def __init__(self, filename, append_to_file=True, open_for_writing=True, copy_history=False): if h5py is None: raise exceptions.AmuseException( "h5py module not available, cannot use hdf5 files") if not append_to_file and open_for_writing and os.path.exists( filename): os.remove(filename) if append_to_file: if open_for_writing: self.hdf5file = h5py.File(filename, 'a') else: if os.access(filename, os.W_OK): self.hdf5file = h5py.File(filename, 'a') else: self.hdf5file = h5py.File(filename, 'r') else: if open_for_writing: self.hdf5file = h5py.File(filename, 'w') else: self.hdf5file = h5py.File(filename, 'r') self.copy_history = copy_history self.mapping_from_groupid_to_set = {}
def select_getters_for(self, attributes): set_of_attributes = set(attributes) # first check for an exact match result = [ getter for getter in self.getters if set(getter.attribute_names) == set_of_attributes ] if result: return result # sort methods on attribute lengths, longest first sorted_getters = sorted(self.getters, key=lambda x: len(x.attribute_names), reverse=True) # next, select the longest fitting method(s), to minize the number of calls for access_method in sorted_getters: if set_of_attributes >= set(access_method.attribute_names): result.append(access_method) set_of_attributes -= set(access_method.attribute_names) # next, select the sortest method(s), to minimize the extra parameters if set_of_attributes: for access_method in reversed(sorted_getters): if set_of_attributes & set(access_method.attribute_names): result.append(access_method) set_of_attributes -= set(access_method.attribute_names) if set_of_attributes: raise exceptions.AmuseException( "Do not have attributes {0}".format(sorted(set_of_attributes))) return result
def reshape(self, shape): if shape == -1 or (len(shape) == 1 and shape[0] == 1): return VectorQuantity([self.number], self.unit) else: raise exceptions.AmuseException( "Cannot reshape a scalar to vector of shape '{0}'".format( shape))
def _get_state_transition_path_to(self, state): all_transitions = self._get_transitions_path_from_to( self._current_state, state) transitions = [] for x in all_transitions: if len(transitions) == 0 or len(x) < len(transitions): transitions = x if len(transitions) == 0: raise Exception( "No transition from current state {0} to {1} possible".format( self._current_state, state)) transitions_with_methods = [ x for x in transitions if not x.method is None ] if not self._do_automatic_state_transitions and len( transitions_with_methods) > 0: lines = [] lines.append( "Interface is not in {0}, should transition from {1} to {0} first.\n" .format(state, self._current_state)) for x in transitions: if x.method is None: lines.append("{0}, automatic".format(x)) else: lines.append("{0}, calling '{1}'".format( x, x.method.function_name)) exception = exceptions.AmuseException('\n'.join(lines)) exception.transitions = transitions raise exception return transitions
def as_vector_with_length(self, length): if len(self) == length: return self.copy() if len(self) == 1: return self.new_from_scalar_quantities(*[self[0]] * length) raise exceptions.AmuseException( "as_vector_with_length only valid for same length or 1")
def amuse_data_location(self): this = os.path.dirname(os.path.abspath(__file__)) # installed result = os.path.abspath( os.path.join(this, "..", "..", "..", "..", "..", "share", "amuse")) if os.path.exists(os.path.join(result, 'build.py')): return result # for some virtualenv setups result = os.path.abspath( os.path.join(this, "..", "..", "..", "..", "..", "..", "share", "amuse")) if os.path.exists(os.path.join(result, 'build.py')): return result # in-place result = os.path.abspath(os.path.join(this, "..", "..", "..")) if os.path.exists(os.path.join(result, 'build.py')): return result raise exceptions.AmuseException( "Could not locate AMUSE root directory! set the AMUSE_DIR variable" )
def asynchronous(self, *list_arguments, **keyword_arguments): if not self.is_async_supported: raise exceptions.AmuseException( "asynchronous call is not supported for this method") object = self.precall() list_arguments, keyword_arguments = self.convert_arguments( list_arguments, keyword_arguments) request = self.method.asynchronous(*list_arguments, **keyword_arguments) def handle_result(function): result = function() result = self.convert_result(result) # currently handled after call (on a wait) # alternatively, this (probably) works for current implemted postcalls # this could be done immediately self.postcall(object) return result request.add_result_handler(handle_result) return request
def densitycentre_coreradius_coredens(particles, unit_converter=None, number_of_neighbours=7, reuse_hop=False, hop=HopContainer()): """ calculate position of the density centre, coreradius and coredensity >>> import numpy >>> from amuse.ic.plummer import new_plummer_sphere >>> numpy.random.seed(1234) >>> particles=new_plummer_sphere(100) >>> pos,coreradius,coredens=particles.densitycentre_coreradius_coredens() >>> print coreradius 0.404120092331 length """ if isinstance(hop, HopContainer): hop.initialize(unit_converter) hop = hop.code try: hop.particles.add_particles(particles) except Exception, ex: hop.stop() raise exceptions.AmuseException( str(ex) + " (note: check whether Hop needs a converter here)")
def combine_bases(self, base1, base2): indexed1 = [None] * 7 for n1, unit1 in base1: indexed1[unit1.index] = (n1, unit1) indexed2 = [None] * 7 for n2, unit2 in base2: indexed2[unit2.index] = (n2, unit2) result = [] for sub1, sub2 in zip(indexed1, indexed2): if not sub1 is None: if not sub2 is None: if sub1[1] == sub2[1]: result.append((sub1[0], sub2[0], sub1[1])) else: raise exceptions.AmuseException( "Cannot combine units from " "different systems: {0} and {1}".format( sub1[1], sub2[1])) else: result.append((sub1[0], 0, sub1[1])) elif not sub2 is None: result.append((0, sub2[0], sub2[1])) return result
def new_from_scalar_quantities(cls, *values): unit=to_quantity(values[0]).unit try: array=[value_in(x,unit) for x in values] except core.IncompatibleUnitsException: raise exceptions.AmuseException("not all values have conforming units") return cls(array, unit)
def _initial_names_for_values(self, possible_values, names_for_values): if names_for_values is None: if possible_values is None: raise exceptions.AmuseException("Must provide a list of values and / or a list of names for each value") else: return [str(x) for x in possible_values] else: return list(names_for_values)
def _initial_list_of_possible_values(self, possible_values, names_for_values): if possible_values is None: if names_for_values is None: raise exceptions.AmuseException("Must provide a list of values and / or a list of names for each value") else: return list(range(len(names_for_values))) else: return list(possible_values)
def __call__(self, string): index = self.names_for_values.index(string) if index > 0: return self.possible_values[index] | self else: raise exceptions.AmuseException( "{0} is not a valid name for {1} enumeration type".format( string, self.name))
def _reindex(self): source_shape = self.source.shape target_shape = self.target.shape if len(source_shape) != len(target_shape): raise exceptions.AmuseException("The source and target grids do not have the same dimensions, cannot use this channel") index = [numpy.s_[0:min(x,y)] for x,y in zip(source_shape, target_shape)] index = tuple(index) self.index = index
def get_parameter(self, name): if not name in self._mapping_from_name_to_definition: raise exceptions.AmuseException("{0!r} not defined as parameter".format(name)) if not name in self._mapping_from_name_to_parameter: definition = self._mapping_from_name_to_definition[name] self._mapping_from_name_to_parameter[name] = Parameter(definition, self) return self._mapping_from_name_to_parameter[name]
def __init__(self, name, symbol, possible_values = None, names_for_values = None): nonnumeric_unit.__init__(self, name, symbol) self.possible_values = self._initial_list_of_possible_values(possible_values, names_for_values) self.names_for_values = self._initial_names_for_values(possible_values, names_for_values) if not len(self.possible_values) == len(self.names_for_values): raise exceptions.AmuseException("Must provide equal lenght list for values({0}) and names({1})".format(len(self.possible_values), len(self.names_for_values))) self.mapping_from_values_to_names = self._initial_mapping_from_values_to_names() self.DEFINED[name] = self
def add_input_parameter(self, parameter): has_default_parameters = any(map(lambda x : x.has_default_value(), self.input_parameters)) if has_default_parameters and not parameter.has_default_value(): raise exceptions.AmuseException("non default argument '{0}' follows default argument".format(parameter.name)) self.input_parameters.append(parameter) parameter.index_in_input = len(self.input_parameters) - 1 parameters = self.dtype_to_input_parameters.get(parameter.datatype, []) parameters.append(parameter) parameter.input_index = len(parameters) - 1 self.dtype_to_input_parameters[parameter.datatype] = parameters
def add_particles_to_store(self, keys, attributes=[], quantities=[]): if len(quantities) != len(attributes): raise exceptions.AmuseException( "you need to provide the same number of quantities as attributes, found {0} attributes and {1} list of values" .format(len(attributes), len(quantities))) if len(quantities) > 0 and len(keys) != len(quantities[0]): raise exceptions.AmuseException( "you need to provide the same number of values as particles, found {0} values and {1} particles" .format(len(quantities[0]), len(keys))) self.__version__ = self.__version__ + 1 self.index_array = numpy.arange(len(self.particle_keys) + len(keys)) if len(self.particle_keys) > 0: previous_length = len(self.particle_keys) self.append_to_storage(keys, attributes, quantities) return self.index_array[previous_length:] else: self.setup_storage(keys, attributes, quantities) return self.index_array
def check_arguments(self, storage, attributes_to_return, *indices): if len(indices[0]) > 1: if self.method_is_legacy and not (self.method.specification.can_handle_array or self.method.specification.must_handle_array): raise Exception( "getter method {0} cannot handle arrays".format(self.method) ) elif self.method_is_code: if not self.method.legacy_specification is None: if not (self.method.legacy_specification.can_handle_array or self.method.legacy_specification.must_handle_array): raise exceptions.AmuseException( "getter method {0} cannot handle arrays".format(self.method) )
def as_quantity_in(self, another_unit): """ Reproduce quantity in another unit. The new unit must have the same basic si quantities. :argument another_unit: unit to convert quantity to :returns: quantity converted to new unit """ if isinstance(another_unit, Quantity): raise exceptions.AmuseException("Cannot expres a unit in a quantity") factor = self.unit.conversion_factor_from(another_unit) return new_quantity(self.number * factor, another_unit)
def select_setters_for(self, attributes): set_of_attributes = set(attributes) result = [] for access_method in self.setters: if set_of_attributes >= set(access_method.attribute_names): result.append(access_method) set_of_attributes -= set(access_method.attribute_names) if set_of_attributes: raise exceptions.AmuseException("Cannot set attributes {0}".format(sorted(set_of_attributes))) return result
def densitycentre_coreradius_coredens(particles, unit_converter=None, number_of_neighbours=7, reuse_hop=False, hop=HopContainer()): """ calculate position of the density centre, coreradius and coredensity >>> import numpy >>> from amuse.ic.plummer import new_plummer_sphere >>> numpy.random.seed(1234) >>> particles=new_plummer_sphere(100) >>> pos,coreradius,coredens=particles.densitycentre_coreradius_coredens() >>> print coreradius 0.404120092331 length """ if isinstance(hop, HopContainer): hop.initialize(unit_converter) hop = hop.code try: hop.particles.add_particles(particles) except Exception as ex: hop.stop() raise exceptions.AmuseException( str(ex) + " (note: check whether Hop needs a converter here)") hop.parameters.density_method = 2 hop.parameters.number_of_neighbors_for_local_density = number_of_neighbours hop.calculate_densities() density = hop.particles.density x = hop.particles.x y = hop.particles.y z = hop.particles.z rho = density.amax() total_density = numpy.sum(density) x_core = numpy.sum(density * x) / total_density y_core = numpy.sum(density * y) / total_density z_core = numpy.sum(density * z) / total_density rc = (density * ((x - x_core)**2 + (y - y_core)**2 + (z - z_core)**2).sqrt()).sum() / total_density if not reuse_hop: hop.stop() return VectorQuantity.new_from_scalar_quantities(x_core, y_core, z_core), rc, rho
def new_particle_with_internal_structure(self, internal_structure, age_tag): if len(internal_structure) > 1: raise exceptions.AmuseException( "Can only add one particle with internal structure at a time.") internal_structure = internal_structure[0] self.new_stellar_model( internal_structure.mass[::-1].value_in(units.MSun), internal_structure.radius[::-1].value_in(units.RSun), internal_structure.rho[::-1].value_in(units.g / units.cm**3), internal_structure.pressure[::-1].value_in(units.barye), internal_structure.X_H[::-1], internal_structure.X_He[::-1], internal_structure.X_C[::-1], internal_structure.X_N[::-1], internal_structure.X_O[::-1], internal_structure.X_Ne[::-1], internal_structure.X_Mg[::-1], internal_structure.X_Si[::-1], internal_structure.X_Fe[::-1]) return self.finalize_stellar_model(age_tag)
def channel_factory(self): if self.channel_type == 'mpi': if MpiChannel.is_supported(): return MpiChannel else: return SocketChannel elif self.channel_type == 'remote': return MultiprocessingMPIChannel elif self.channel_type == 'distributed': return DistributedChannel elif self.channel_type == 'sockets': return SocketChannel elif self.channel_type == 'local': return LocalChannel else: raise exceptions.AmuseException("Cannot create a channel with type {0!r}, type is not supported".format(self.channel_type))
def _add_indices(self, indices): keys = [] for i in indices: if i in self.mapping_from_index_in_the_code_to_particle_key: raise exceptions.AmuseException("adding an index '{0}' that is already managed, bookkeeping is broken".format(i)) newkey = base.UniqueKeyGenerator.next() self.mapping_from_index_in_the_code_to_particle_key[i] = newkey self.mapping_from_particle_key_to_index_in_the_code[newkey] = i keys.append(newkey) if len(self.particle_keys) > 0: self.particle_keys = numpy.concatenate((self.particle_keys, numpy.asarray(list(keys), dtype=self.particle_keys.dtype))) self.code_indices = numpy.concatenate((self.code_indices, numpy.asarray(list(indices), dtype=self.code_indices.dtype))) else: self.particle_keys = numpy.array(keys) self.code_indices = numpy.array(indices)
def as_quantity_in(self, unit): """Express this unit as a quantity in the given unit :argument unit: The unit to express this unit in :result: A Quantity object Examples >>> from amuse.units import units >>> ton = 1000 * units.kg >>> ton.as_quantity_in(units.kg) quantity<1000.0 kg> """ from amuse.units import quantities if isinstance(unit, quantities.Quantity): raise exceptions.AmuseException("Cannot expres a unit in a quantity") else: factor = self.conversion_factor_from(unit) return quantities.new_quantity(factor, unit)
def convert_attributes_and_values_to_list_and_keyword_arguments( self, attributes, values): not_set_marker = object() list_arguments = [not_set_marker] * (len(self.attribute_names)) names_to_index = self.names_to_index for attribute, quantity in zip(attributes, values): if attribute in names_to_index: index = names_to_index[attribute] list_arguments[index] = quantity default_argument_found = False missing_attributes = [] dict_arguments = {} for index, x in enumerate(list_arguments): if x is not_set_marker: name_of_attribute = self.attribute_names[index] if not name_of_attribute in self.optional_attribute_names: missing_attributes.append(name_of_attribute) else: default_argument_found = True elif default_argument_found: name_of_attribute = self.attribute_names[index] if not name_of_attribute in self.optional_attribute_names: raise exceptions.AmuseException( "Optional before required arguments") dict_arguments[name_of_attribute] = x list_arguments[index] = not_set_marker if len(missing_attributes) > 0: if len(missing_attributes) == 1: missing_attributes_string = "{0!r} attribute".format( missing_attributes[0]) else: missing_attributes_string = "{0!r} and {1!r} attributes".format( ", ".join(missing_attributes[:-1]), missing_attributes[-1]) raise exceptions.MissingAttributesAmuseException( missing_attributes, "To add particles to this code you need to specify the {0}". format(missing_attributes_string)) list_arguments = [x for x in list_arguments if not x is not_set_marker] return list_arguments, dict_arguments
def _typecode_to_datatype(typecode): if typecode is None: return None mapping = { 'd':'float64', 'i':'int32', 'f':'float32', 's':'string', 'b':'bool', 'l':'int64', } if typecode in mapping: return mapping[typecode] values = mapping.values() if typecode in values: return typecode raise exceptions.AmuseException("{0} is not a valid typecode".format(typecode))
def virial_radius(particles): """ Returns the virial radius of the particles set. The virial radius is the inverse of the average inverse distance between particles, weighted by their masses. >>> from amuse.datamodel import Particles >>> particles = Particles(2) >>> particles.x = [-1.0, 1.0] | units.m >>> particles.y = [0.0, 0.0] | units.m >>> particles.z = [0.0, 0.0] | units.m >>> particles.mass = [1.0, 1.0] | units.kg >>> particles.virial_radius() quantity<4.0 m> """ if len(particles) < 2: raise exceptions.AmuseException( "Cannot calculate virial radius for a particles set with fewer than 2 particles." ) partial_sum = zero mass = particles.mass x_vector = particles.x y_vector = particles.y z_vector = particles.z for i in range(len(particles) - 1): x = x_vector[i] y = y_vector[i] z = z_vector[i] dx = x - x_vector[i + 1:] dy = y - y_vector[i + 1:] dz = z - z_vector[i + 1:] dr_squared = (dx * dx) + (dy * dy) + (dz * dz) dr = (dr_squared).sqrt() m_m = mass[i] * mass[i + 1:] partial_sum += (m_m / dr).sum() return (mass.sum()**2) / (2 * partial_sum)
def setpos(self): # // Obtain a random position for body b from the King profile # // and return the scaled potential at that location. # // Choose radius randomly from the mass distribution. rno = numpy.random.uniform() i = int(self.NINDX * rno) found_index = False for i1 in range(self.index[i], self.index[i + 1] + 2): #(i1 = self.indx[i]; i1 <= indx[i+1]+1; i1++) if (self.zm[i1] > rno): found_index = True break if (not found_index): raise exceptions.AmuseException("makeking: error in getpos") rfac = (rno - self.zm[i1 - 1]) / (self.zm[i1] - self.zm[i1 - 1]) radius = self.rr[i1 - 1] + rfac * (self.rr[i1] - self.rr[i1 - 1]) potential = self.psi[i1 - 1] + rfac * (self.psi[i1] - self.psi[i1 - 1]) # // Angular position random. theta = numpy.arccos(numpy.random.uniform(-1.0, 1.0)) phi = numpy.random.uniform(0.0, 2.0 * math.pi) return self.coordinates_from_spherical(radius, theta, phi), potential