def diffrot_velocity(coordinates,omega_eq,omega_pole,R_pole,M): """ Calculate the velocity vector of every surface element. @param coordinates: polar coordinates of stellar surface (phi,theta,radius) make sure the radius is in SI units! @type coordinates: 3xN array @param omega_eq: equatorial angular velocity (as a fraction of the critical one) @type omega_eq: float @param omega_pole: polar angular velocity (as a fraction of the critical one) @type omega_pole: float @param R_pole: polar radius in solar radii @type R_pole: float @param M: stellar mass in solar mass @type M: float @return: velocity vectors of all surface elements @rtype 3xN array """ #-- angular velocity of every surface element Omega_crit = critical_angular_velocity(M,R_pole) phi,theta,radius = coordinates omega_local = diffrot_law(omega_eq,omega_pole,theta)*Omega_crit #-- direction of local angular velocity in Cartesian coordinates (directed in upwards z) omega_local_vec = np.array([np.zeros_like(omega_local),np.zeros_like(omega_local),omega_local]).T x,y,z = vectors.spher2cart_coord(radius,phi,theta) surface_element = np.array([x,y,z]).T velo_local = np.array([np.cross(ielement,iomega_local_vec) for ielement,iomega_local_vec in zip(surface_element,omega_local_vec)]).T return velo_local
def surface_normals(r,phi,theta,grid,gtype='spher'): """ Numerically compute surface normals of a grid (in absence of analytical alternative). Also computes the surface elements, making L{surface_elements} obsolete. """ if gtype=='spher': raise NotImplementedError elif gtype=='delaunay': raise NotImplementedError elif gtype=='triangular': #-- compute the angle between the surface normal and the radius vector x,y,z = vectors.spher2cart_coord(r,phi,theta) centers = np.zeros((len(grid.convex_hull),3)) normals = np.zeros((len(grid.convex_hull),3)) sizes = np.zeros(len(grid.convex_hull)) #vertx,verty,vertz = points.T #-- compute centers,normals and sizes for i,indices in enumerate(grid.convex_hull): #-- center is triangle's barycenter centers[i] = [x[indices].sum()/3,y[indices].sum()/3,z[indices].sum()/3] #-- size is size of triangle a = sqrt((x[indices[0]]-x[indices[1]])**2 + (y[indices[0]]-y[indices[1]])**2 + (z[indices[0]]-z[indices[1]])**2) b = sqrt((x[indices[0]]-x[indices[2]])**2 + (y[indices[0]]-y[indices[2]])**2 + (z[indices[0]]-z[indices[2]])**2) c = sqrt((x[indices[1]]-x[indices[2]])**2 + (y[indices[1]]-y[indices[2]])**2 + (z[indices[1]]-z[indices[2]])**2) s = 0.5*(a+b+c) sizes[i] = sqrt( s*(s-a)*(s-b)*(s-c)) #-- normal is cross product of two sides side1 = [x[indices[1]]-x[indices[0]],y[indices[1]]-y[indices[0]],z[indices[1]]-z[indices[0]]] side2 = [x[indices[2]]-x[indices[0]],y[indices[2]]-y[indices[0]],z[indices[2]]-z[indices[0]]] normals[i] = np.cross(side1,side2) #-- make sure the normal is pointed outwards normal_r,normal_phi,normal_theta = vectors.cart2spher(centers.T,normals.T) normal_r = np.abs(normal_r) centers_sph = vectors.cart2spher_coord(*centers.T) normals = np.array(vectors.spher2cart(centers_sph,(normal_r,normal_phi,normal_theta))) #-- normalise and compute angles normals_T = normals.T normals = normals_T / vectors.norm(normals_T) #cos_gamma = vectors.cos_angle(a,normals) print centers.shape,sizes.shape,normals.shape return centers, sizes, normals#, cos_gamma
(theta + ksi_theta.real),\ (phi + ksi_phi.real),\ (teff + (delta_T*rad_part*teff).real),\ np.log10(gravity+(delta_g*rad_part*gravity).real)+2 #} if __name__ == "__main__": from ivs.roche import local from ivs.coordinates import vectors from enthought.mayavi import mlab from divers import multimedia theta, phi = local.get_grid(50, 25, gtype='triangular') r = np.ones_like(theta) x, y, z = vectors.spher2cart_coord(r, phi, theta) points = np.array([x, y, z]).T grid = Delaunay(points) #keep = phi>pi #theta,phi = theta[keep],phi[keep] l, m = 2, 2 asl = 0.01 for k in [0, 1., 2.]: for l in range(1, 5): for m in range(0, l + 1, 1): mlab.figure(size=(1000, 800)) mlab.gcf().scene.disable_render = True if l == 0 or l == 1: asl = 0.1 else:
def project(star, view_long=(0, 0, 0), view_lat=(pi / 2, 0, 0), photband='OPEN.BOL', only_visible=False, plot_sort=False, scale_factor=1.): """ Project and transform coordinates and vectors to align with the line-of-sight. Parameter C{star} should be a record array containing fields 'teff','gravx', 'gravy','gravz','areas','vx','vy','vz' and either you suply ('r','theta','phi') or ('x','y','z') The XY direction is then the line-of-sight, and the YZ plane is the plane of the sky. An extra column 'projflux' and 'eyeflux' will be added. Projected flux takes care of limb darkening, and projected surface area. Eye flux only takes care of limbdarkening, and should only be used for plotting reasons. view_long[0] of 0 means looking in the XY line, pi means looking in the YX line. view_lat[0] of pi/2 means edge on, 0 or pi is pole-on. This function updates all Cartesian coordinates present in the star, but not the polar coordinates! The projected fluxes are added as a field 'projflux' to the returned record array. If you set 'only_visible' to True, only the information on the visible parts of the star will be contained. If you set 'plot_sort' to True, the arrays will be returned in a sorted order, where the areas at the back come first. This is especially handy for plotting. @parameters star: record array containing all necessary information on the star @type star: numpy record array @parameter view_long: longitude viewing angle (radians) and coordinate zeropoint @type view_long: tuple floats (radians,x,y) @parameter view_lat: inclination viewing angle (radians) and coordinate zeropoint @type view_lat: tuple floats (radians,x,z) @parameter photband: photometric passband @type photband: string @parameter only_visible: flag to return only information on visible surface elements @type only_visible: boolean @parameter plot_sort: flag to sort the surface elements from back to front @type plot_sort: boolean """ myshape = star['gravx'].shape gravx, gravy, gravz = np.array( [star['gravx'].ravel(), star['gravy'].ravel(), star['gravz'].ravel()]) areas = star['areas'].ravel() teff = star['teff'].ravel() vx, vy, vz = star['vx'].ravel(), star['vy'].ravel(), star['vz'].ravel() #-- if 'x' is not in the star's record array, we assume the polar coordinates # are in there and convert them to Cartesian coordinates if not 'x' in star.dtype.names: x, y, z = vectors.spher2cart_coord(star['r'].ravel(), star['phi'].ravel(), star['theta'].ravel()) else: x, y, z = star['x'].ravel(), star['y'].ravel(), star['z'].ravel(), #-- first we rotate in the XY plane (only for surface coordinates is the # coordinate zeropoint important, the rest are vectors!): x, y = vectors.rotate(x, y, view_long[0], x0=view_long[1], y0=view_long[2]) gravx, gravy = vectors.rotate(gravx, gravy, view_long[0]) vx, vy = vectors.rotate(vx, vy, view_long[0]) #-- then we rotate in the YZ plane: if view_lat[0] != pi / 2: rot_i = -(pi / 2 - view_lat[0]) x, z = vectors.rotate(x, z, rot_i) gravx, gravz = vectors.rotate(gravx, gravz, rot_i) vx, vz = vectors.rotate(vx, vz, rot_i) #-- ... and project the fluxes in the line of sight, which is now in the XY # direction: view_vector = np.array([1., 0, 0]) #np.array([-sin(pi/2),0,-cos(pi/2)]) grav_local = np.array([gravx, gravy, gravz]) proj_flux, mus = projected_intensity(teff, grav_local, areas, view_vector, photband=photband) #-- we now construct a copy of the star record array with the changed # coordinates new_star = star.copy() new_star['gravx'], new_star['gravy'], new_star[ 'gravz'] = gravx, gravy, gravz new_star['vx'], new_star['vy'], new_star['vz'] = vx, vy, vz if 'x' in star.dtype.names: new_star['x'], new_star['y'], new_star[ 'z'] = x * scale_factor, y * scale_factor, z * scale_factor else: new_star = pl.mlab.rec_append_fields(new_star, 'x', x * scale_factor) new_star = pl.mlab.rec_append_fields(new_star, 'y', y * scale_factor) new_star = pl.mlab.rec_append_fields(new_star, 'z', z * scale_factor) new_star = pl.mlab.rec_append_fields(new_star, 'projflux', proj_flux) new_star = pl.mlab.rec_append_fields(new_star, 'eyeflux', proj_flux / areas) new_star = pl.mlab.rec_append_fields(new_star, 'mu', mus) #-- clip visible areas and sort in plotting order if necessary if only_visible: new_star = new_star[-np.isnan(new_star['projflux'])] if plot_sort: new_star = new_star[np.argsort(new_star['x'])] return new_star
def surface_elements(radius_and_mygrid, surface_normals_xyz, gtype='spher'): """ Compute surface area of elements in a grid. theta,phi must be generated like mgrid(theta_range,phi_range) usually, the surfnormals are acquired via differentiation of a gravity potential, and is then equal to the *negative* of the local surface gravity. """ (r, mygrid) = radius_and_mygrid (surfnormal_x, surfnormal_y, surfnormal_z) = surface_normals_xyz theta, phi = mygrid[:2] if gtype == 'spher': #-- compute the grid size at each location dtheta = theta[1:] - theta[:-1] dtheta = np.vstack([dtheta, dtheta[-1]]) dphi = phi[:, 1:] - phi[:, :-1] dphi = np.column_stack([dphi, dphi[:, -1]]) #-- compute the angle between the surface normal and the radius vector x, y, z = vectors.spher2cart_coord(r, phi, theta) a = np.array([x, y, z]) b = np.array([surfnormal_x, surfnormal_y, surfnormal_z]) cos_gamma = vectors.cos_angle(a, b) return r**2 * sin(theta) * dtheta * dphi / cos_gamma, cos_gamma elif gtype == 'delaunay': #-- compute the angle between the surface normal and the radius vector x, y, z = vectors.spher2cart_coord(r, phi, theta) a = np.array([x, y, z]) b = np.array([surfnormal_x, surfnormal_y, surfnormal_z]) cos_gamma = vectors.cos_angle(a, b) delaunay_grid = mygrid[2] sizes = np.zeros(len(delaunay_grid.convex_hull)) points = delaunay_grid.points vertx, verty, vertz = points.T #from enthought.mayavi import mlab #mlab.figure() #mlab.triangular_mesh(vertx,verty,vertz,delaunay_grid.convex_hull,scalars=np.ones_like(vertx),colormap='gray',representation='wireframe') #mlab.points3d(x/r,y/r,z/r,scale_factor=0.02) centers = np.zeros((len(delaunay_grid.convex_hull), 3)) for i, indices in enumerate(delaunay_grid.convex_hull): #centers[i] = [vertx[indices].sum()/3,verty[indices].sum()/3,vertz[indices].sum()/3] a = sqrt((vertx[indices[0]] - vertx[indices[1]])**2 + (verty[indices[0]] - verty[indices[1]])**2 + (vertz[indices[0]] - vertz[indices[1]])**2) b = sqrt((vertx[indices[0]] - vertx[indices[2]])**2 + (verty[indices[0]] - verty[indices[2]])**2 + (vertz[indices[0]] - vertz[indices[2]])**2) c = sqrt((vertx[indices[1]] - vertx[indices[2]])**2 + (verty[indices[1]] - verty[indices[2]])**2 + (vertz[indices[1]] - vertz[indices[2]])**2) s = 0.5 * (a + b + c) sizes[i] = sqrt(s * (s - a) * (s - b) * (s - c)) #theta,phi = np.arccos(centers[:,2]),np.arctan2(centers[:,1],centers[:,0])+pi #mlab.points3d(centers[:,0],centers[:,1],centers[:,2],sizes,scale_factor=0.05,scale_mode='none',colormap='RdBu') #mlab.show() #pl.show() return sizes * r**2, cos_gamma
def surface_normals(r, phi, theta, grid, gtype='spher'): """ Numerically compute surface normals of a grid (in absence of analytical alternative). Also computes the surface elements, making L{surface_elements} obsolete. """ if gtype == 'spher': raise NotImplementedError elif gtype == 'delaunay': raise NotImplementedError elif gtype == 'triangular': #-- compute the angle between the surface normal and the radius vector x, y, z = vectors.spher2cart_coord(r, phi, theta) centers = np.zeros((len(grid.convex_hull), 3)) normals = np.zeros((len(grid.convex_hull), 3)) sizes = np.zeros(len(grid.convex_hull)) #vertx,verty,vertz = points.T #-- compute centers,normals and sizes for i, indices in enumerate(grid.convex_hull): #-- center is triangle's barycenter centers[i] = [ x[indices].sum() / 3, y[indices].sum() / 3, z[indices].sum() / 3 ] #-- size is size of triangle a = sqrt((x[indices[0]] - x[indices[1]])**2 + (y[indices[0]] - y[indices[1]])**2 + (z[indices[0]] - z[indices[1]])**2) b = sqrt((x[indices[0]] - x[indices[2]])**2 + (y[indices[0]] - y[indices[2]])**2 + (z[indices[0]] - z[indices[2]])**2) c = sqrt((x[indices[1]] - x[indices[2]])**2 + (y[indices[1]] - y[indices[2]])**2 + (z[indices[1]] - z[indices[2]])**2) s = 0.5 * (a + b + c) sizes[i] = sqrt(s * (s - a) * (s - b) * (s - c)) #-- normal is cross product of two sides side1 = [ x[indices[1]] - x[indices[0]], y[indices[1]] - y[indices[0]], z[indices[1]] - z[indices[0]] ] side2 = [ x[indices[2]] - x[indices[0]], y[indices[2]] - y[indices[0]], z[indices[2]] - z[indices[0]] ] normals[i] = np.cross(side1, side2) #-- make sure the normal is pointed outwards normal_r, normal_phi, normal_theta = vectors.cart2spher( centers.T, normals.T) normal_r = np.abs(normal_r) centers_sph = vectors.cart2spher_coord(*centers.T) normals = np.array( vectors.spher2cart(centers_sph, (normal_r, normal_phi, normal_theta))) #-- normalise and compute angles normals_T = normals.T normals = normals_T / vectors.norm(normals_T) #cos_gamma = vectors.cos_angle(a,normals) print(centers.shape, sizes.shape, normals.shape) return centers, sizes, normals #, cos_gamma
def project(star,view_long=(0,0,0),view_lat=(pi/2,0,0),photband='OPEN.BOL', only_visible=False,plot_sort=False,scale_factor=1.): """ Project and transform coordinates and vectors to align with the line-of-sight. Parameter C{star} should be a record array containing fields 'teff','gravx', 'gravy','gravz','areas','vx','vy','vz' and either you suply ('r','theta','phi') or ('x','y','z') The XY direction is then the line-of-sight, and the YZ plane is the plane of the sky. An extra column 'projflux' and 'eyeflux' will be added. Projected flux takes care of limb darkening, and projected surface area. Eye flux only takes care of limbdarkening, and should only be used for plotting reasons. view_long[0] of 0 means looking in the XY line, pi means looking in the YX line. view_lat[0] of pi/2 means edge on, 0 or pi is pole-on. This function updates all Cartesian coordinates present in the star, but not the polar coordinates! The projected fluxes are added as a field 'projflux' to the returned record array. If you set 'only_visible' to True, only the information on the visible parts of the star will be contained. If you set 'plot_sort' to True, the arrays will be returned in a sorted order, where the areas at the back come first. This is especially handy for plotting. @parameters star: record array containing all necessary information on the star @type star: numpy record array @parameter view_long: longitude viewing angle (radians) and coordinate zeropoint @type view_long: tuple floats (radians,x,y) @parameter view_lat: inclination viewing angle (radians) and coordinate zeropoint @type view_lat: tuple floats (radians,x,z) @parameter photband: photometric passband @type photband: string @parameter only_visible: flag to return only information on visible surface elements @type only_visible: boolean @parameter plot_sort: flag to sort the surface elements from back to front @type plot_sort: boolean """ myshape = star['gravx'].shape gravx,gravy,gravz = np.array([star['gravx'].ravel(),star['gravy'].ravel(),star['gravz'].ravel()]) areas = star['areas'].ravel() teff = star['teff'].ravel() vx,vy,vz = star['vx'].ravel(),star['vy'].ravel(),star['vz'].ravel() #-- if 'x' is not in the star's record array, we assume the polar coordinates # are in there and convert them to Cartesian coordinates if not 'x' in star.dtype.names: x,y,z = vectors.spher2cart_coord(star['r'].ravel(),star['phi'].ravel(),star['theta'].ravel()) else: x,y,z = star['x'].ravel(),star['y'].ravel(),star['z'].ravel(), #-- first we rotate in the XY plane (only for surface coordinates is the # coordinate zeropoint important, the rest are vectors!): x,y = vectors.rotate(x,y,view_long[0],x0=view_long[1],y0=view_long[2]) gravx,gravy = vectors.rotate(gravx,gravy,view_long[0]) vx,vy = vectors.rotate(vx,vy,view_long[0]) #-- then we rotate in the YZ plane: if view_lat[0]!=pi/2: rot_i = -(pi/2 - view_lat[0]) x,z = vectors.rotate(x,z,rot_i) gravx,gravz = vectors.rotate(gravx,gravz,rot_i) vx,vz = vectors.rotate(vx,vz,rot_i) #-- ... and project the fluxes in the line of sight, which is now in the XY # direction: view_vector = np.array([1.,0,0])#np.array([-sin(pi/2),0,-cos(pi/2)]) grav_local = np.array([gravx,gravy,gravz]) proj_flux,mus = projected_intensity(teff,grav_local,areas,view_vector,photband=photband) #-- we now construct a copy of the star record array with the changed # coordinates new_star = star.copy() new_star['gravx'],new_star['gravy'],new_star['gravz'] = gravx,gravy,gravz new_star['vx'],new_star['vy'],new_star['vz'] = vx,vy,vz if 'x' in star.dtype.names: new_star['x'],new_star['y'],new_star['z'] = x*scale_factor,y*scale_factor,z*scale_factor else: new_star = pl.mlab.rec_append_fields(new_star,'x',x*scale_factor) new_star = pl.mlab.rec_append_fields(new_star,'y',y*scale_factor) new_star = pl.mlab.rec_append_fields(new_star,'z',z*scale_factor) new_star = pl.mlab.rec_append_fields(new_star,'projflux',proj_flux) new_star = pl.mlab.rec_append_fields(new_star,'eyeflux',proj_flux/areas) new_star = pl.mlab.rec_append_fields(new_star,'mu',mus) #-- clip visible areas and sort in plotting order if necessary if only_visible: new_star = new_star[-np.isnan(new_star['projflux'])] if plot_sort: new_star = new_star[np.argsort(new_star['x'])] return new_star
theta,phi must be generated like mgrid(theta_range,phi_range) usually, the surfnormals are acquired via differentiation of a gravity potential, and is then equal to the *negative* of the local surface gravity. """ theta,phi = mygrid[:2] if gtype=='spher': #-- compute the grid size at each location dtheta = theta[1:]-theta[:-1] dtheta = np.vstack([dtheta,dtheta[-1]]) dphi = phi[:,1:]-phi[:,:-1] dphi = np.column_stack([dphi,dphi[:,-1]]) #-- compute the angle between the surface normal and the radius vector x,y,z = vectors.spher2cart_coord(r,phi,theta) a = np.array([x,y,z]) b = np.array([surfnormal_x,surfnormal_y,surfnormal_z]) cos_gamma = vectors.cos_angle(a,b) return r**2 * sin(theta) * dtheta * dphi / cos_gamma, cos_gamma elif gtype=='delaunay': #-- compute the angle between the surface normal and the radius vector x,y,z = vectors.spher2cart_coord(r,phi,theta) a = np.array([x,y,z]) b = np.array([surfnormal_x,surfnormal_y,surfnormal_z]) cos_gamma = vectors.cos_angle(a,b)