def _convert_to_numeric(self, first, second, in_units): if in_units: return (first.value_in(in_units), second.value_in(in_units)) elif is_quantity(first) or is_quantity(second): return (to_quantity(first).value_in(to_quantity(second).unit), to_quantity(second).value_in(to_quantity(second).unit)) else: return (first, second)
def _check_comparable(self, first, second): if is_quantity(first) is not is_quantity(second): # One exception: quantity with none_unit CAN be compared with non-quantity: if not to_quantity(first).unit == to_quantity(second).unit: raise TypeError( "Cannot compare quantity: {0} with non-quantity: {1}.". format( *(first, second) if isinstance(first, Quantity) else (second, first)))
def convert_quantity_from_comoving_to_physical(original, redshift, hubble_parameter=1.0): for (exponent, unit) in to_quantity(original).unit.base: if unit is units.m or unit is generic_unit_system.length: return original * (1 / (1.0 + redshift))**exponent return original
def read_inifile_parameters(self, configfile): self._configfile = configfile parser = ConfigParser() parser.optionxform = self._optionxform parser.read(configfile) for section in parser.sections(): group = section for option in parser.options(section): key = (option, group) if key in self._inifile_parameters: ptype = self._inifile_parameters[key]["ptype"] dtype = self._inifile_parameters[key]["dtype"] value = self.interpret_value(parser.get(group, option), dtype=dtype) if is_quantity(self._inifile_parameters[key]["default"]): value = new_quantity( val, to_quantity( self._inifile_parameters[key]["default"]).unit) self._inifile_parameters[key]["value"] = value else: value = self.interpret_value(parser.get(group, option)) self._inifile_parameters[key] = dict( group_name=group, name=option, set_name=group, default=value, value=value, short=option, ptype="ini", dtype="unknown", description="unknown parameter read from %s" % configfile)
def _forward_mapping_nodes_to_nodes(self, source, target, attributes): #create in-memory copies of the grids and a channel to the target in-code grid source_copy, target_copy, channel3 = self._get_grid_copies_and_channel(source.nodes, target.nodes, attributes) #indices for interacting with CDORemapper index_i_src = range(source.elements.size) index_i_dst = range(target.elements.size) for attribute in attributes: #obtain source values and unit values=to_quantity( getattr(source_copy, attribute) ) unit=values.unit values=values.number if len(values.shape) > 1: values = numpy.swapaxes(values, 0, 1) #remap to elements within source grid values = source.map_nodes_to_elements(values) #do the remapping self.cdo_remapper.set_src_grid_values(index_i_src, values.flatten()) self.cdo_remapper.perform_remap() result = self.cdo_remapper.get_dst_grid_values(index_i_dst) #remap to nodes within target grid result = target.map_elements_to_nodes(result) #store result in copy target grid setattr(target_copy, attribute, (result if unit is units.none else (result | unit))) #push in-memory copy target grid to in-code storage target grid channel3.copy_attributes(attributes)
def filter_band_flux( fdata, source, wavelength=None, ): if fdata.__class__.__name__ == "str": fdata = get_filter_data()[fdata] if wavelength is None: wavelength = fdata['wavelength'] throughput = fdata['throughput'] else: xp = fdata['wavelength'] fp = fdata['throughput'] throughput = numpy.interp( wavelength.value_in(units.angstrom), xp=xp.value_in(units.angstrom), fp=fp, left=0., right=0., ) src = throughput * source(wavelength) src = quantities.to_quantity(src) return numpy.trapz( src.number, x=wavelength.number) | (src.unit*wavelength.unit)
def forward_mapping(self, attributes): if attributes is None: attributes=self.source.get_attribute_names_defined_in_store() source=self.source.empty_copy() channel1=self.source.new_channel_to(source) target=self.target.empty_copy() channel2=self.target.new_channel_to(target) channel3=target.new_channel_to(self.target) channel1.copy_attributes(attributes) channel2.copy_attributes(self._axes_names) nodes=self._generate_nodes(source,attributes) xpos=value_in( getattr(target,self._axes_names[0]), self._xpos_unit) ypos=value_in( getattr(target,self._axes_names[1]), self._ypos_unit) for attribute in attributes: values=to_quantity( getattr(nodes,attribute) ) unit=values.unit values=values.number samples=self.sample(values,xpos,ypos) setattr(target, attribute, (samples if unit is units.none else (samples | unit))) channel3.copy_attributes(attributes)
def read_parameters(self, inputfile, add_missing_parameters=False): self._file=inputfile _nml_params = f90nml.read(inputfile) rawvals, comments = self._read_file(inputfile) for key, rawval in rawvals.items(): if key in self._parameters: group_name=self._parameters[key]["group_name"] name=self._parameters[key]["name"] dtype=self._parameters[key]["dtype"] val=self.interpret_value( rawval, dtype=dtype) if is_quantity(self._parameters[key]["default"]): self._parameters[key]["value"]=new_quantity(val, to_quantity(self._parameters[key]["default"]).unit) else: self._parameters[key]["value"]=val else: if not add_missing_parameters: print("'{0}' of group '{1}' not in the parameters list".format(*key)) else: value=rawval description=comments.get(key, "unknown parameter read from {0}".format(inputfile)) self._parameters[key]=dict( group_name=key[1], name=key[0], short_name=key[0], default=value, value=value, short=key[0], ptype=self._ptypes[0], dtype=dtype_str[type(value)], description=description )
def forward_mapping(self, attributes): if attributes is None: attributes = self.source.get_attribute_names_defined_in_store() source = self.source.empty_copy() channel1 = self.source.new_channel_to(source) target = self.target.empty_copy() channel2 = self.target.new_channel_to(target) channel3 = target.new_channel_to(self.target) channel1.copy_attributes(attributes) channel2.copy_attributes(self._axes_names) nodes = self._generate_nodes(source, attributes) xpos = value_in(getattr(target, self._axes_names[0]), self._xpos_unit) ypos = value_in(getattr(target, self._axes_names[1]), self._ypos_unit) for attribute in attributes: values = to_quantity(getattr(nodes, attribute)) unit = values.unit values = values.number samples = self.sample(values, xpos, ypos) setattr(target, attribute, (samples if unit is units.none else (samples | unit))) channel3.copy_attributes(attributes)
def _forward_mapping_elements_to_elements(self, source, target, attributes): #create in-memory copies of the grids and a channel to the target in-code grid source_copy, target_copy, channel3 = self._get_grid_copies_and_channel(source, target, attributes) #indices for interacting with CDORemapper index_i_src = range(source.size) index_i_dst = range(target.size) for attribute in attributes: #obtain source values and unit values=to_quantity( getattr(source_copy, attribute) ) unit=values.unit values=numpy.array(values.number) #do the remapping self.cdo_remapper.set_src_grid_values(index_i_src, values.ravel(order='F')) self.cdo_remapper.perform_remap() result = self.cdo_remapper.get_dst_grid_values(index_i_dst).reshape(target.shape, order='F') #store result in copy target grid setattr(target_copy, attribute, (result if unit is units.none else (result | unit))) #push in-memory copy target grid to in-code storage grid channel3.copy_attributes(attributes)
def write_namelist_parameters(self, outputfile, do_patch=False, nml_file=None): patch = defaultdict(dict) for p in self._namelist_parameters.values(): name = p["name"] group_name = p["group_name"] group = patch[group_name] short = p["short"] parameter_set_name = p.get("set_name", "parameters_" + group_name) parameter_set = getattr(self, parameter_set_name) if getattr(parameter_set, name) is None: # omit if value is None continue if is_quantity(p["default"]): value = to_quantity(getattr(parameter_set, name)).value_in(p["default"].unit) else: value = getattr(parameter_set, name) if isinstance(value, numpy.ndarray): value = list( value) # necessary until f90nml supports numpy arrays group[short] = value if do_patch: f90nml.patch(nml_file or self._nml_file, patch, outputfile) else: f90nml.write(patch, outputfile, force=True)
def read_namelist_parameters(self, inputfile): self._nml_file = inputfile self._nml_params = f90nml.read(inputfile) for group, d in self._nml_params.iteritems(): for short, val in d.iteritems(): key = (short, group.upper()) if key in self._namelist_parameters: group_name = self._namelist_parameters[key]["group_name"] name = self._namelist_parameters[key]["name"] parameter_set_name = self._namelist_parameters[key].get( "set_name", "parameters_" + group_name) parameter_set = getattr(self, parameter_set_name) if is_quantity(self._namelist_parameters[key]["default"]): setattr( parameter_set, name, new_quantity( val, to_quantity(self._namelist_parameters[key] ["default"]).unit)) else: setattr(parameter_set, name, val) else: print "'%s' of group '%s' not in the namelist_parameters" % ( short, group)
def generate_triangulation(self): nodes,elements,boundaries=self.convert_grid_to_nodes_and_elements(self.source, self._axes_names) xpos=to_quantity(getattr(nodes,self._axes_names[0])) ypos=to_quantity(getattr(nodes,self._axes_names[1])) self._xpos_unit=xpos.unit xpos=xpos.number self._ypos_unit=ypos.unit ypos=ypos.number n1=elements.nodes[:,0] n2=elements.nodes[:,1] n3=elements.nodes[:,2] elem=numpy.column_stack((n1,n2,n3)) self._triangulation=tri.Triangulation(xpos,ypos,elem)
def generate_triangulation(self): nodes, elements, boundaries = self.convert_grid_to_nodes_and_elements( self.source, self._axes_names) xpos = to_quantity(getattr(nodes, self._axes_names[0])) ypos = to_quantity(getattr(nodes, self._axes_names[1])) self._xpos_unit = xpos.unit xpos = xpos.number self._ypos_unit = ypos.unit ypos = ypos.number n1 = elements.nodes[:, 0] n2 = elements.nodes[:, 1] n3 = elements.nodes[:, 2] elem = numpy.column_stack((n1, n2, n3)) self._triangulation = tri.Triangulation(xpos, ypos, elem)
def write_parameters(self, outputfile, **options): rawvals=dict() for key, p in self._parameters.items(): name=p["name"] group_name=p["group_name"] short=p["short"] parameter_set_name=p.get("set_name", group_name) parameter_set=getattr(self, self._prefix+parameter_set_name) if is_quantity(p["default"]): value=to_quantity(getattr(parameter_set, name)).value_in(p["default"].unit) else: value=getattr(parameter_set, name) rawvals[key]=self.output_format_value(value) self._write_file(outputfile, rawvals, **options)
def write_inifile_parameters(self, outputfile): parser = ConfigParser() parser.optionxform = self._optionxform for p in self._inifile_parameters.values(): name = p["name"] group_name = p["group_name"] short = p["short"] parameter_set_name = p.get("set_name", group_name) parameter_set = getattr(self, parameter_set_name) if is_quantity(p["default"]): value = to_quantity(getattr(parameter_set, name)).value_in(p["default"].unit) else: value = self.output_format_value(getattr(parameter_set, name)) if not parser.has_section(group_name): parser.add_section(group_name) parser.set(group_name, short, value) f = open(outputfile, "w") parser.write(f) f.close()
def get_orbital_elements_from_arrays( rel_position_raw, rel_velocity_raw, total_masses, G=nbody_system.G): """ Orbital elements from array of relative positions and velocities vectors, based on orbital_elements_from_binary and adapted to work for arrays (each line characterises a two body problem). For circular orbits (eccentricity=0): returns argument of pericenter = 0., true anomaly = 0. For equatorial orbits (inclination=0): longitude of ascending node = 0, argument of pericenter = arctan2(e_y,e_x). :argument rel_position: array of vectors of relative positions of the two-body systems :argument rel_velocity: array of vectors of relative velocities of the two-body systems :argument total_masses: array of total masses for two-body systems :argument G: gravitational constant :output semimajor_axis: array of semi-major axes :output eccentricity: array of eccentricities :output period: array of orbital periods :output inc: array of inclinations [radians] :output long_asc_node: array of longitude of ascending nodes [radians] :output arg_per_mat: array of argument of pericenters [radians] :output true_anomaly: array of true anomalies [radians] """ if len(numpy.shape(rel_position_raw)) == 1: rel_position = numpy.zeros([1, 3]) * rel_position_raw[0] rel_position[0, 0] = rel_position_raw[0] rel_position[0, 1] = rel_position_raw[1] rel_position[0, 2] = rel_position_raw[2] rel_velocity = numpy.zeros([1, 3]) * rel_velocity_raw[0] rel_velocity[0, 0] = rel_velocity_raw[0] rel_velocity[0, 1] = rel_velocity_raw[1] rel_velocity[0, 2] = rel_velocity_raw[2] else: rel_position = rel_position_raw rel_velocity = rel_velocity_raw separation = (rel_position**2).sum(axis=1)**0.5 n_vec = len(rel_position) speed_squared = (rel_velocity**2).sum(axis=1) semimajor_axis = ( G * total_masses * separation / (2. * G * total_masses - separation * speed_squared) ) neg_ecc_arg = ( ( to_quantity(rel_position).cross(rel_velocity)**2 ).sum(axis=-1) / (G * total_masses * semimajor_axis) ) filter_ecc0 = (1. <= neg_ecc_arg) eccentricity = numpy.zeros(separation.shape) eccentricity[~filter_ecc0] = numpy.sqrt(1.0 - neg_ecc_arg[~filter_ecc0]) eccentricity[filter_ecc0] = 0. # angular momentum mom = to_quantity(rel_position).cross(rel_velocity) # inclination inc = arccos(mom[:, 2]/to_quantity(mom).lengths()) # Longitude of ascending nodes, with reference direction along x-axis asc_node_matrix_unit = numpy.zeros(rel_position.shape) z_vectors = numpy.zeros([n_vec, 3]) z_vectors[:, 2] = 1. z_vectors = z_vectors | units.none ascending_node_vectors = z_vectors.cross(mom) filter_non0_incl = ( to_quantity(ascending_node_vectors).lengths().number > 0.) asc_node_matrix_unit[~filter_non0_incl] = numpy.array([1., 0., 0.]) an_vectors_len = to_quantity( ascending_node_vectors[filter_non0_incl]).lengths() asc_node_matrix_unit[filter_non0_incl] = normalize_vector( ascending_node_vectors[filter_non0_incl], an_vectors_len) long_asc_node = arctan2( asc_node_matrix_unit[:, 1], asc_node_matrix_unit[:, 0]) # Argument of periapsis using eccentricity a.k.a. Laplace-Runge-Lenz vector mu = G*total_masses pos_unit_vecs = normalize_vector(rel_position, separation) mom_len = to_quantity(mom).lengths() mom_unit_vecs = normalize_vector(mom, mom_len) e_vecs = ( normalize_vector( to_quantity(rel_velocity).cross(mom), mu) - pos_unit_vecs ) # Argument of pericenter cannot be determined for e = 0, # in this case return 0.0 and 1.0 for the cosines e_vecs_norm = (e_vecs**2).sum(axis=1)**0.5 filter_non0_ecc = (e_vecs_norm > 1.e-15) arg_per_mat = VectorQuantity( array=numpy.zeros(long_asc_node.shape), unit=units.rad) cos_arg_per = numpy.zeros(long_asc_node.shape) arg_per_mat[~filter_non0_ecc] = 0. | units.rad cos_arg_per[~filter_non0_ecc] = 1. e_vecs_unit = numpy.zeros(rel_position.shape) e_vecs_unit[filter_non0_ecc] = normalize_vector( e_vecs[filter_non0_ecc], e_vecs_norm[filter_non0_ecc] ) cos_arg_per[filter_non0_ecc] = ( e_vecs_unit[filter_non0_ecc] * asc_node_matrix_unit[filter_non0_ecc] ).sum(axis=-1) e_cross_an = numpy.zeros(e_vecs_unit.shape) e_cross_an[filter_non0_ecc] = numpy.cross( e_vecs_unit[filter_non0_ecc], asc_node_matrix_unit[filter_non0_ecc] ) e_cross_an_norm = (e_cross_an**2).sum(axis=1)**0.5 filter_non0_e_cross_an = (e_cross_an_norm != 0.) ss = -numpy.sign( ( mom_unit_vecs[filter_non0_e_cross_an] * e_cross_an[filter_non0_e_cross_an] ).sum(axis=-1) ) # note change in size in sin_arg_per and cos_arg_per; they are not used further sin_arg_per = ss*e_cross_an_norm[filter_non0_e_cross_an] cos_arg_per = cos_arg_per[filter_non0_e_cross_an] arg_per_mat[filter_non0_e_cross_an] = arctan2(sin_arg_per, cos_arg_per) # in case longitude of ascending node is 0, omega=arctan2(e_y,e_x) arg_per_mat[~filter_non0_e_cross_an & filter_non0_ecc] = ( arctan2( e_vecs[~filter_non0_e_cross_an & filter_non0_ecc, 1], e_vecs[~filter_non0_e_cross_an & filter_non0_ecc, 0] ) ) filter_negative_zmom = ( ~filter_non0_e_cross_an & filter_non0_ecc & (mom[:, 2] < 0.*mom[0, 0]) ) arg_per_mat[filter_negative_zmom] = ( 2. * numpy.pi - arg_per_mat[filter_negative_zmom] ) # true anomaly cos_true_anomaly = (e_vecs_unit*pos_unit_vecs).sum(axis=-1) e_cross_pos = numpy.cross(e_vecs_unit, pos_unit_vecs) ss2 = numpy.sign((mom_unit_vecs*e_cross_pos).sum(axis=-1)) sin_true_anomaly = ss2*(e_cross_pos**2).sum(axis=1)**0.5 true_anomaly = arctan2(sin_true_anomaly, cos_true_anomaly) return ( semimajor_axis, eccentricity, true_anomaly, inc, long_asc_node, arg_per_mat )
def get_orbital_elements_from_arrays(rel_position_raw, rel_velocity_raw, total_masses, G=nbody_system.G): """ Orbital elements from array of relative positions and velocities vectors, based on orbital_elements_from_binary and adapted to work for arrays (each line characterises a two body problem). For circular orbits (eccentricity=0): returns argument of pericenter = 0., true anomaly = 0. For equatorial orbits (inclination=0): longitude of ascending node = 0, argument of pericenter = arctan2(e_y,e_x). :argument rel_position: array of vectors of relative positions of the two-body systems :argument rel_velocity: array of vectors of relative velocities of the two-body systems :argument total_masses: array of total masses for two-body systems :argument G: gravitational constant :output semimajor_axis: array of semi-major axes :output eccentricity: array of eccentricities :output period: array of orbital periods :output inc: array of inclinations [radians] :output long_asc_node: array of longitude of ascending nodes [radians] :output arg_per_mat: array of argument of pericenters [radians] :output true_anomaly: array of true anomalies [radians] """ if len(numpy.shape(rel_position_raw)) == 1: rel_position = numpy.zeros([1, 3]) * rel_position_raw[0] rel_position[0, 0] = rel_position_raw[0] rel_position[0, 1] = rel_position_raw[1] rel_position[0, 2] = rel_position_raw[2] rel_velocity = numpy.zeros([1, 3]) * rel_velocity_raw[0] rel_velocity[0, 0] = rel_velocity_raw[0] rel_velocity[0, 1] = rel_velocity_raw[1] rel_velocity[0, 2] = rel_velocity_raw[2] else: rel_position = rel_position_raw rel_velocity = rel_velocity_raw separation = (rel_position**2).sum(axis=1)**0.5 n_vec = len(rel_position) speed_squared = (rel_velocity**2).sum(axis=1) semimajor_axis = (G * total_masses * separation / (2. * G * total_masses - separation * speed_squared)) neg_ecc_arg = ( (to_quantity(rel_position).cross(rel_velocity)**2).sum(axis=-1) / (G * total_masses * semimajor_axis)) filter_ecc0 = (1. <= neg_ecc_arg) eccentricity = numpy.zeros(separation.shape) eccentricity[~filter_ecc0] = numpy.sqrt(1.0 - neg_ecc_arg[~filter_ecc0]) eccentricity[filter_ecc0] = 0. # angular momentum mom = to_quantity(rel_position).cross(rel_velocity) # inclination inc = arccos(mom[:, 2] / to_quantity(mom).lengths()) # Longitude of ascending nodes, with reference direction along x-axis asc_node_matrix_unit = numpy.zeros(rel_position.shape) z_vectors = numpy.zeros([n_vec, 3]) z_vectors[:, 2] = 1. z_vectors = z_vectors | units.none ascending_node_vectors = z_vectors.cross(mom) filter_non0_incl = (to_quantity(ascending_node_vectors).lengths().number > 0.) asc_node_matrix_unit[~filter_non0_incl] = numpy.array([1., 0., 0.]) an_vectors_len = to_quantity( ascending_node_vectors[filter_non0_incl]).lengths() asc_node_matrix_unit[filter_non0_incl] = normalize_vector( ascending_node_vectors[filter_non0_incl], an_vectors_len) long_asc_node = arctan2(asc_node_matrix_unit[:, 1], asc_node_matrix_unit[:, 0]) # Argument of periapsis using eccentricity a.k.a. Laplace-Runge-Lenz vector mu = G * total_masses pos_unit_vecs = normalize_vector(rel_position, separation) mom_len = to_quantity(mom).lengths() mom_unit_vecs = normalize_vector(mom, mom_len) e_vecs = (normalize_vector(to_quantity(rel_velocity).cross(mom), mu) - pos_unit_vecs) # Argument of pericenter cannot be determined for e = 0, # in this case return 0.0 and 1.0 for the cosines e_vecs_norm = (e_vecs**2).sum(axis=1)**0.5 filter_non0_ecc = (e_vecs_norm > 1.e-15) arg_per_mat = VectorQuantity(array=numpy.zeros(long_asc_node.shape), unit=units.rad) cos_arg_per = numpy.zeros(long_asc_node.shape) arg_per_mat[~filter_non0_ecc] = 0. | units.rad cos_arg_per[~filter_non0_ecc] = 1. e_vecs_unit = numpy.zeros(rel_position.shape) e_vecs_unit[filter_non0_ecc] = normalize_vector( e_vecs[filter_non0_ecc], e_vecs_norm[filter_non0_ecc]) cos_arg_per[filter_non0_ecc] = (e_vecs_unit[filter_non0_ecc] * asc_node_matrix_unit[filter_non0_ecc]).sum( axis=-1) e_cross_an = numpy.zeros(e_vecs_unit.shape) e_cross_an[filter_non0_ecc] = numpy.cross( e_vecs_unit[filter_non0_ecc], asc_node_matrix_unit[filter_non0_ecc]) e_cross_an_norm = (e_cross_an**2).sum(axis=1)**0.5 filter_non0_e_cross_an = (e_cross_an_norm != 0.) ss = -numpy.sign((mom_unit_vecs[filter_non0_e_cross_an] * e_cross_an[filter_non0_e_cross_an]).sum(axis=-1)) # note change in size in sin_arg_per and cos_arg_per; they are not used further sin_arg_per = ss * e_cross_an_norm[filter_non0_e_cross_an] cos_arg_per = cos_arg_per[filter_non0_e_cross_an] arg_per_mat[filter_non0_e_cross_an] = arctan2(sin_arg_per, cos_arg_per) # in case longitude of ascending node is 0, omega=arctan2(e_y,e_x) arg_per_mat[~filter_non0_e_cross_an & filter_non0_ecc] = (arctan2( e_vecs[~filter_non0_e_cross_an & filter_non0_ecc, 1], e_vecs[~filter_non0_e_cross_an & filter_non0_ecc, 0])) filter_negative_zmom = (~filter_non0_e_cross_an & filter_non0_ecc & (mom[:, 2] < 0. * mom[0, 0])) arg_per_mat[filter_negative_zmom] = (2. * numpy.pi - arg_per_mat[filter_negative_zmom]) # true anomaly cos_true_anomaly = (e_vecs_unit * pos_unit_vecs).sum(axis=-1) e_cross_pos = numpy.cross(e_vecs_unit, pos_unit_vecs) ss2 = numpy.sign((mom_unit_vecs * e_cross_pos).sum(axis=-1)) sin_true_anomaly = ss2 * (e_cross_pos**2).sum(axis=1)**0.5 true_anomaly = arctan2(sin_true_anomaly, cos_true_anomaly) return (semimajor_axis, eccentricity, true_anomaly, inc, long_asc_node, arg_per_mat)
def _check_comparable(self, first, second): if is_quantity(first) is not is_quantity(second): # One exception: quantity with none_unit CAN be compared with non-quantity: if not to_quantity(first).unit == to_quantity(second).unit: raise TypeError("Cannot compare quantity: {0} with non-quantity: {1}.".format(*(first,second) if isinstance(first, Quantity) else (second,first)))
def f(self,index,val): unit=self._input_var_units[var] val=quantities.to_quantity(val).value_in(unit) # todo: select data type return self.set_value_at_indices_float(var,index,val)