def __init__(self, file_address=None): # set file address (using a setter method) [self._file_directory, self._file_name] = ['', ''] self.file_address = file_address self.s = bp.Species() self.t = bp.Grid() self.t.ndim = 1 self.p = bp.Grid() self.geometry = bp.Geometry() self.sv = bp.SVGrid() self.coll = bp.Collisions() self.scheme = bp.Scheme() self.output_parameters = np.array([['Mass', 'Momentum_X'], ['Momentum_X', 'Momentum_Flow_X'], ['Energy', 'Energy_Flow_X']]) self.check_integrity(complete_check=False) return
def load(file_address): """Set up and return a :class:`Simulation` instance based on the parameters in the given HDF5 group. Parameters ---------- file_address : :obj:`str`, optional The full path to the simulation (hdf5) file. Returns ------- self : :class:`Simulation` """ assert isinstance(file_address, str) assert os.path.exists(file_address) # Open HDF5 file file = h5py.File(file_address, mode='r') assert file.attrs["class"] == "Simulation" self = Simulation(file_address) key = "Species" self.s = bp.Species.load(file[key]) key = "Time_Grid" self.t = bp.Grid.load(file[key]) # Todo this should (needs to) be unnecessary self.t.ndim = 1 key = "Position_Grid" self.p = bp.Grid().load(file[key]) key = "Geometry" self.geometry = bp.Geometry.load(file[key]) key = "Velocity_Grids" self.sv = bp.SVGrid.load(file[key]) key = "Collisions" self.coll = bp.Collisions.load(file[key]) key = "Scheme" self.scheme = bp.Scheme.load(file[key]) key = "Computation/Output_Parameters" shape = file[key].attrs["shape"] self.output_parameters = file[key][()].reshape(shape) file.close() self.check_integrity(complete_check=False) return self
def setup_position_grid(self, grid_dimension, grid_shape, grid_spacing): """Set up :attr:`p` and adjust :attr:`geometry` to the new shape. See :class:`Grid() <Grid>` Parameters ---------- grid_dimension : :obj:`int` grid_shape : :obj:`tuple` [:obj:`int`] grid_spacing : :obj:`float` """ self.p = bp.Grid(ndim=grid_dimension, shape=grid_shape, physical_spacing=grid_spacing) # Update shape of initialization_array self.geometry.shape = self.p.shape return
def setup_time_grid(self, max_time, number_time_steps, calculations_per_time_step=1): """Set up :attr:`t`. Calculate step size and call :class:`Grid() <Grid>`. Parameters ---------- max_time : :obj:`float` number_time_steps : :obj:`int` calculations_per_time_step : :obj:`int` """ step_size = max_time / (number_time_steps - 1) self.t = bp.Grid(ndim=1, shape=(number_time_steps, ), physical_spacing=step_size, spacing=calculations_per_time_step) return
def setup(self): """Construct the attributes :attr:`Grid.iMG`, :attr:`Grid.index_range`, :attr:`Grid.vGrids`.""" # Basic asserts : is everything configured and correct? self.check_integrity(False) assert self.is_configured number_of_grids = len(self.shapes) self.index_range = np.zeros((number_of_grids, 2), dtype=int) self.vGrids = np.empty(number_of_grids, dtype='object') # set up sub grids, one by one for i in range(number_of_grids): # Todo the physical spacing is only a dummy so far new_grid = bp.Grid(ndim=self.ndim, shape=self.shapes[i], physical_spacing=1.0, spacing=self.spacings[i], is_centered=True) self.vGrids[i] = new_grid self.index_range[i, 1] = self.index_range[i, 0] + new_grid.size if i + 1 < number_of_grids: self.index_range[i + 1, 0] = self.index_range[i, 1] # Sub grids only have a view on the data # The actual data are stored in the multi grid self.iMG = np.zeros((self.index_range[-1, 1], self.ndim), dtype=int) for (idx_G, G) in enumerate(self.vGrids): [beg, end] = self.index_range[idx_G] self.iMG[beg:end, :] = G.iG[...] G.iG = self.iMG[beg:end] # Todo find more elegant way for this self.delta = self.maximum_velocity / np.max(self.iMG) for G in self.vGrids: G.delta = self.delta return
def setup(self, scheme, svgrid, species): """Generates the :attr:`relations` and :attr:`weights`. Parameters ---------- scheme : :class:`Scheme` svgrid : :class:`SVGrid` species : :class:`Species` """ assert isinstance(scheme, bp.Scheme) assert isinstance(svgrid, bp.SVGrid) assert isinstance(species, bp.Species) print('Generating Collision Array...') time_beg = time() # collect collisions in the following lists relations = [] weights = [] """The velocities are named in the following way: 1. v* and w* are velocities of the first/second specimen, respectively 2. v0 or w0 denotes the velocity before the collision v1 or w1 denotes the velocity after the collision """ # choose function for local collisions if scheme.Collisions_Generation == 'UniformComplete': coll_func = Collisions.complete elif scheme.Collisions_Generation == 'Convergent': coll_func = Collisions.convergent else: raise NotImplementedError('Unsupported Selection Scheme: ' '{}'.format( scheme.Collisions_Generation)) grids = np.empty((4, ), dtype=object) # use larger grids to shift within equivalence classes extended_grids = np.empty((4, ), dtype=object) # Todo rename into species, after Model update species_idx = np.zeros(4, dtype=int) masses = np.zeros(4, dtype=int) # Iterate over Specimen pairs for (idx_v, grid_v) in enumerate(svgrid.vGrids): grids[0:2] = grid_v extended_shape = (2 * grids[0].shape[0] - grids[0].shape[0] % 2, 2 * grids[0].shape[0] - grids[0].shape[0] % 2) extended_grids[0:2] = bp.Grid(grids[0].ndim, extended_shape, grids[0].physical_spacing, grids[0].spacing, grids[0].is_centered) species_idx[0:2] = idx_v for (idx_w, grid_w) in enumerate(svgrid.vGrids): grids[2:4] = grid_w extended_shape = (2 * grids[2].shape[0] - grids[2].shape[0] % 2, 2 * grids[2].shape[0] - grids[2].shape[0] % 2) extended_grids[2:4] = bp.Grid(grids[2].ndim, extended_shape, grids[2].physical_spacing, grids[2].spacing, grids[2].is_centered) species_idx[2:4] = idx_w masses[:] = species.mass[species_idx] collision_rate = species.collision_rates[idx_v, idx_w] index_offset = np.array(svgrid.index_range[species_idx, 0]) # Todo may be bad for differing weights # skip already computed combinations if idx_w < idx_v: continue # group grid[0] points by distance to grid[2] for equivalence_class in grids[2].group(grids[0].iG).values(): # only generate colliding velocities(colvels) # for a representative v0 of its group, v0_repr = equivalence_class[0] [repr_colvels, extended_weights] = coll_func(extended_grids, masses, v0_repr, collision_rate) # Get relations for other class elements by shifting for v0 in equivalence_class: # shift extended colvels new_colvels = repr_colvels + (v0 - v0_repr) # get indices new_rels = np.zeros(new_colvels.shape[0:2], dtype=int) for i in range(4): new_rels[:, i] = grids[i].get_idx(new_colvels[:, i, :]) new_rels += index_offset # remove out-of-bounds or useless collisions choice = np.where( # must be in the grid np.all(new_rels >= index_offset, axis=1) # must be effective & (new_rels[..., 0] != new_rels[..., 3]) & (new_rels[..., 0] != new_rels[..., 1])) # Add chosen Relations/Weights to the list assert np.array_equal(new_colvels[choice], svgrid.iMG[new_rels[choice]]) relations.extend(new_rels[choice]) weights.extend(extended_weights[choice]) # relations += new_rels # weights += new_weights self.relations = np.array(relations, dtype=int) self.weights = np.array(weights, dtype=float) # remove redundant collisions self.filter() # sort collisions for better comparability self.sort() time_end = time() print('Time taken = {t} seconds\n' 'Total Number of Collisions = {n}\n' ''.format(t=round(time_end - time_beg, 3), n=self.size)) self.check_integrity() return
def __init__(self, file_address, s=None, t=None, p=None, sv=None, coll=None, geometry=None, scheme=None, output_parameters=None): super().__init__(file_address) if s is None: s = bp.Species() s.add(mass=2, collision_rate=np.array([50], dtype=float)) s.add(mass=3, collision_rate=np.array([50, 50], dtype=float)) else: assert isinstance(s, bp.Species) self.s = s if t is None: t = bp.Grid(ndim=1, shape=(5, ), physical_spacing=0.01, spacing=3) self.t = t if p is None: p = bp.Grid(ndim=1, shape=(6, ), spacing=1, physical_spacing=0.5) self.p = p if sv is None: spacings = bp.SVGrid.generate_spacings(s.mass) shapes = [(int(2 * m + 1), int(2 * m + 1)) for m in s.mass] sv = bp.SVGrid( ndim=2, maximum_velocity=1.5, shapes=shapes, spacings=spacings, ) self.sv = sv if geometry is None: left_rho = 2 * np.ones(s.size) right_rho = np.ones(s.size) initial_drift = np.zeros((s.size, sv.ndim)) initial_temp = np.ones(s.size) rules = [ bp.ConstantPointRule(initial_rho=left_rho, initial_drift=initial_drift, initial_temp=initial_temp, affected_points=[0], velocity_grids=sv, species=s), bp.InnerPointRule(initial_rho=left_rho, initial_drift=initial_drift, initial_temp=initial_temp, affected_points=np.arange(1, p.size // 2), velocity_grids=sv, species=s), bp.InnerPointRule(initial_rho=right_rho, initial_drift=initial_drift, initial_temp=initial_temp, affected_points=np.arange( p.size // 2, p.size - 1), velocity_grids=sv, species=s), bp.BoundaryPointRule( initial_rho=right_rho, initial_drift=initial_drift, initial_temp=initial_temp, affected_points=[p.size - 1], velocity_grids=sv, reflection_rate_inverse=np.full(s.size, 0.25, dtype=float), reflection_rate_elastic=np.full(s.size, 0.25, dtype=float), reflection_rate_thermal=np.full(s.size, 0.25, dtype=float), absorption_rate=np.full(s.size, 0.25, dtype=float), surface_normal=np.array([1, 0], dtype=int), species=s) ] geometry = bp.Geometry(shape=p.shape, rules=rules) self.geometry = geometry if scheme is None: scheme = bp.Scheme(OperatorSplitting="FirstOrder", Transport="FiniteDifferences_FirstOrder", Transport_VelocityOffset=np.array([-0.2, 0.0]), Collisions_Generation="UniformComplete", Collisions_Computation="EulerScheme") self.scheme = scheme if output_parameters is None: output_parameters = np.array([['Mass', 'Momentum_X'], ['Momentum_X', 'Momentum_Flow_X'], ['Energy', 'Energy_Flow_X']]) self.output_parameters = output_parameters if coll is None: coll = bp.Collisions() coll.setup(scheme=self.scheme, svgrid=self.sv, species=self.s) self.coll = coll return