def _get_npts_ncells_nnodes(self, mk): m_inf = self.mesh_inf[mk] # Get the shape and sub division classes shapecls = subclass_where(BaseShape, name=m_inf[0]) subdvcls = subclass_where(BaseShapeSubDiv, name=m_inf[0]) # Number of vis points npts = shapecls.nspts_from_order(self.divisor + 1)*m_inf[1][1] # Number of sub cells and nodes ncells = len(subdvcls.subcells(self.divisor))*m_inf[1][1] nnodes = len(subdvcls.subnodes(self.divisor))*m_inf[1][1] return npts, ncells, nnodes
def __init__(self, args): from frfs.solvers.base import BaseSystem self.outf = args.outf # Load the mesh and solution files self.soln = NativeReader(args.solnf) self.mesh = NativeReader(args.meshf) # Check solution and mesh are compatible if self.mesh['mesh_uuid'] != self.soln['mesh_uuid']: raise RuntimeError('Solution "%s" was not computed on mesh "%s"' % (args.solnf, args.meshf)) # Load the configuration and stats files self.cfg = Inifile(self.soln['config']) self.stats = Inifile(self.soln['stats']) # Data file prefix (defaults to soln for backwards compatibility) self.dataprefix = self.stats.get('data', 'prefix', 'soln') # Get element types and array shapes self.mesh_inf = self.mesh.array_info('spt') self.soln_inf = self.soln.array_info(self.dataprefix) # Dimensions self.ndims = next(iter(self.mesh_inf.values()))[1][2] self.nvars = next(iter(self.soln_inf.values()))[1][1] # System and elements classes self.systemscls = subclass_where( BaseSystem, name=self.cfg.get('solver', 'system') ) self.elementscls = self.systemscls.elementscls
def _pre_proc_fields_grad(self, name, mesh, soln): # Call the reference pre-processor soln = self._pre_proc_fields_ref(name, mesh, soln) # Dimensions nvars, nupts = soln.shape[:2] # Get the shape class basiscls = subclass_where(BaseShape, name=name) # Construct an instance of the relevant elements class eles = self.elementscls(basiscls, mesh, self.cfg) # Get the smats and |J|^-1 to untransform the gradient smat = eles.smat_at_np('upts').transpose(2, 0, 1, 3) rcpdjac = eles.rcpdjac_at_np('upts') # Gradient operator gradop = eles.basis.m4.astype(self.dtype) # Evaluate the transformed gradient of the solution gradsoln = np.dot(gradop, soln.swapaxes(0, 1).reshape(nupts, -1)) gradsoln = gradsoln.reshape(self.ndims, nupts, nvars, -1) # Untransform gradsoln = np.einsum('ijkl,jkml->mikl', smat*rcpdjac, gradsoln, dtype=self.dtype, casting='same_kind') gradsoln = gradsoln.reshape(nvars*self.ndims, nupts, -1) return np.vstack([soln, gradsoln])
def _write_data(self, vtuf, mk, sk): name = self.mesh_inf[mk][0] mesh = self.mesh[mk].astype(self.dtype) soln = self.soln[sk].swapaxes(0, 1).astype(self.dtype) # Dimensions nspts, neles = mesh.shape[:2] # Sub divison points inside of a standard element svpts = self._get_std_ele(name, nspts) nsvpts = len(svpts) # Generate the operator matrices mesh_vtu_op = self._get_mesh_op(name, nspts, svpts) soln_vtu_op = self._get_soln_op(name, nspts, svpts) # Calculate node locations of VTU elements vpts = np.dot(mesh_vtu_op, mesh.reshape(nspts, -1)) vpts = vpts.reshape(nsvpts, -1, self.ndims) # Pre-process the solution soln = self._pre_proc_fields(name, mesh, soln).swapaxes(0, 1) # Interpolate the solution to the vis points vsoln = np.dot(soln_vtu_op, soln.reshape(len(soln), -1)) vsoln = vsoln.reshape(nsvpts, -1, neles).swapaxes(0, 1) # Append dummy z dimension for points in 2D if self.ndims == 2: vpts = np.pad(vpts, [(0, 0), (0, 0), (0, 1)], 'constant') # Write element node locations to file self._write_darray(vpts.swapaxes(0, 1), vtuf, self.dtype) # Perform the sub division subdvcls = subclass_where(BaseShapeSubDiv, name=name) nodes = subdvcls.subnodes(self.divisor) # Prepare VTU cell arrays vtu_con = np.tile(nodes, (neles, 1)) vtu_con += (np.arange(neles)*nsvpts)[:, None] # Generate offset into the connectivity array vtu_off = np.tile(subdvcls.subcelloffs(self.divisor), (neles, 1)) vtu_off += (np.arange(neles)*len(nodes))[:, None] # Tile VTU cell type numbers vtu_typ = np.tile(subdvcls.subcelltypes(self.divisor), neles) # Write VTU node connectivity, connectivity offsets and cell types self._write_darray(vtu_con, vtuf, np.int32) self._write_darray(vtu_off, vtuf, np.int32) self._write_darray(vtu_typ, vtuf, np.uint8) # Process and write out the various fields for arr in self._post_proc_fields(vsoln): self._write_darray(arr.T, vtuf, self.dtype)
def get_integrator(backend, systemcls, rallocs, mesh, initsoln, cfg): form = cfg.get('solver-time-integrator', 'formulation', 'std') if form == 'std': cn = cfg.get('solver-time-integrator', 'controller') sn = cfg.get('solver-time-integrator', 'scheme') cc = subclass_where(BaseStdController, controller_name=cn) sc = subclass_where(BaseStdStepper, stepper_name=sn) bases = [(cn, cc), (sn, sc)] elif form == 'dual': cn = cfg.get('solver-time-integrator', 'controller') pn = cfg.get('solver-time-integrator', 'pseudo-scheme') sn = cfg.get('solver-time-integrator', 'scheme') cc = subclass_where(BaseDualController, controller_name=cn) pc = subclass_where(BaseDualPseudoStepper, pseudo_stepper_name=pn) sc = subclass_where(BaseDualStepper, stepper_name=sn) bases = [(cn, cc), (pn, pc), (sn, sc)] if 'solver-dual-time-integrator-multip' in cfg.sections(): bases.insert(0, ('multip', DualMultiPIntegrator)) else: raise ValueError('Invalid integrator formulation') # Determine the integrator name name = '_'.join([form] + list(bn for bn, bc in bases) + ['integrator']) name = re.sub('(?:^|_|-)([a-z])', lambda m: m.group(1).upper(), name) # Composite the base classes together to form a new type integrator = type(name, tuple(bc for bn, bc in bases), dict(name=name)) # Construct and return an instance of this new integrator class return integrator(backend, systemcls, rallocs, mesh, initsoln, cfg)
def __init__(self, be, lhs, elemap, cfgsect, cfg, **kwargs): super().__init__(be, lhs, elemap, cfgsect, cfg, **kwargs) initcondcls = subclass_where(DGFSInitCondition, model='maxwellian') bc = initcondcls(be, cfg, self._vm, cfgsect) f0 = bc.get_init_vals().reshape(1, self._vm.vsize()) self._d_bnd_f0 = be.const_matrix(f0) unondim = bc.unondim() tplc = {'Ux': unondim[0, 0], 'Uy': unondim[1, 0], 'Uz': unondim[2, 0]} self._tpl_c.update(tplc) # storage self._bcVals_lhs = None # register comm_flux kernel self._be.pointwise.register('frfs.solvers.dgfs.kernels.bccflux') rsolver = self.cfg.get('solver-interfaces', 'riemann-solver') tplargs = dict(ndims=self.ndims, nvars=self.nvars, rsolver=rsolver, c=self._tpl_c, bctype=self.type, vsize=self._vm.vsize(), cw=self._vm.cw()) self.kernels['comm_flux'] = lambda: self._be.kernel( 'bccflux', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, magnl=self._mag_pnorm_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f0, bc_vals=self._bcVals_lhs)
def __init__(self, be, lhs, elemap, cfgsect, cfg, **kwargs): super().__init__(be, lhs, elemap, cfgsect, cfg, **kwargs) initcondcls = subclass_where(DGFSBiInitCondition, model='maxwellian') bc = initcondcls(be, cfg, self._vm, cfgsect) f = bc.get_init_vals() self._d_bnd_f = [0] * self._nspcs for p in range(self._nspcs): self._d_bnd_f[p] = be.const_matrix(f[p].reshape( 1, self._vm.vsize())) # storage self._bcVals_lhs = None # register comm_flux kernel self._be.pointwise.register('frfs.solvers.dgfsbi.kernels.bccflux') rsolver = self.cfg.get('solver-interfaces', 'riemann-solver') tplargs = dict(ndims=self.ndims, nvars=self.nvars, rsolver=rsolver, c=self._tpl_c, bctype=self.type, vsize=self._vm.vsize(), cw=self._vm.cw()) """for p in range(self._nspcs): self.kernels['comm_flux'+str(p+1)] = lambda: self._be.kernel( 'bccflux', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, magnl=self._mag_pnorm_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[p], bc_vals=self._bcVals_lhs ) """ assert self._nspcs == 2, "Valid only for two species!" self.kernels['comm_flux0'] = lambda: self._be.kernel( 'bccflux', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, magnl=self._mag_pnorm_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[0], bc_vals=self._bcVals_lhs) self.kernels['comm_flux1'] = lambda: self._be.kernel( 'bccflux', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, magnl=self._mag_pnorm_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[1], bc_vals=self._bcVals_lhs)
def __init__(self, be, lhs, elemap, cfgsect, cfg, **kwargs): super().__init__(be, lhs, elemap, cfgsect, cfg, **kwargs) initcondcls = subclass_where(DGFSBiInitCondition, model='maxwellian') bc = initcondcls(be, cfg, self._vm, cfgsect, wall=True) f = bc.get_init_vals() self._d_bnd_f = [0 for i in range(self._nspcs)] for p in range(self._nspcs): self._d_bnd_f[p] = be.const_matrix(f[p].reshape( 1, self._vm.vsize())) unondim = bc.unondim() tplc = {'Ux': unondim[0, 0], 'Uy': unondim[1, 0], 'Uz': unondim[2, 0]} self._tpl_c.update(tplc) # register comm_flux kernel self._be.pointwise.register('frfs.solvers.dgfsbi.kernels.bccflux') rsolver = self.cfg.get('solver-interfaces', 'riemann-solver') tplargs = dict(ndims=self.ndims, nvars=self.nvars, rsolver=rsolver, c=self._tpl_c, bctype=self.type, vsize=self._vm.vsize(), bcupdatetype=self.type + '-update', cw=self._vm.cw()) # register update for boundary conditions self._be.pointwise.register('frfs.solvers.dgfsbi.kernels.bccupdate') # storage self._bcVals_lhs = [0 for i in range(self._nspcs)] for p in range(self._nspcs): self._bcVals_lhs[p] = self._mat(lhs, 'get_norm_pnorms_for_inter', initval=p) # there is some ceveat with this approach! # the alternative procedure below works! """ for p in range(self._nspcs): self.kernels['comm_flux'+str(p)] = lambda: self._be.kernel( 'bccflux', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, magnl=self._mag_pnorm_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[p], bc_vals=self._bcVals_lhs[p] ) for p in range(self._nspcs): self.kernels['update_bc'+str(p)] = lambda: self._be.kernel( 'bccupdate', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[p], bc_vals=self._bcVals_lhs[p] ) """ assert self._nspcs == 2, "Valid only for two species!" self.kernels['comm_flux0'] = lambda: self._be.kernel( 'bccflux', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, magnl=self._mag_pnorm_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[0], bc_vals=self._bcVals_lhs[0]) self.kernels['comm_flux1'] = lambda: self._be.kernel( 'bccflux', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, magnl=self._mag_pnorm_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[1], bc_vals=self._bcVals_lhs[1]) self.kernels['update_bc0'] = lambda: self._be.kernel( 'bccupdate', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[0], bc_vals=self._bcVals_lhs[0]) self.kernels['update_bc1'] = lambda: self._be.kernel( 'bccupdate', tplargs, dims=[self.ninterfpts], ul=self._scal_lhs, nl=self._norm_pnorm_lhs, ploc=self._ploc, cvx=self._vm.d_cvx(), cvy=self._vm.d_cvy(), cvz=self._vm.d_cvz(), bnd_f0=self._d_bnd_f[1], bc_vals=self._bcVals_lhs[1])
def _get_shape(self, name, nspts): shapecls = subclass_where(BaseShape, name=name) return shapecls(nspts, self.cfg)
def get_reader_by_name(name, *args, **kwargs): return subclass_where(BaseReader, name=name)(*args, **kwargs)
def get_polybasis(name, order, pts=[]): return subclass_where(BasePolyBasis, name=name)(order, pts)
def get_plugin(name, *args, **kwargs): return subclass_where(BasePlugin, name=name)(*args, **kwargs)
def get_solver(backend, rallocs, mesh, initsoln, cfg): systemcls = subclass_where(BaseSystem, name=cfg.get('solver', 'system')) # Combine with an integrator to yield the solver return get_integrator(backend, systemcls, rallocs, mesh, initsoln, cfg)
def get_backend(name, cfg): return subclass_where(BaseBackend, name=name.lower())(cfg)
def get_writer_by_name(name, *args, **kwargs): return subclass_where(BaseWriter, name=name)(*args, **kwargs)
def __init__(self, backend, rallocs, mesh, initsoln, nreg, cfg): if(not backend.name=='cuda'): raise ValueError("CUDA backend supported!") # load the velocity mesh self.vm = self.velocitymeshcls(backend, cfg, self._nspcs) cv = self.vm.cv() vsize = self.vm.vsize() # need to define the expressions # the prefix "f_" should be same as in elementcls distvar # size of distvar should be equal to NvBatchSize for ivar in range(self.vm.NvBatchSize()): cfg.set('soln-ics', 'f_' + str(ivar), '0.') # now, we can initialize things super().__init__(backend, rallocs, mesh, initsoln, nreg, cfg, vm=self.vm) print('Finished initializing the BaseSystem') # define the time-step minjac = 100.0 for t, ele in self.ele_map.items(): djac = ele.djac_at_np('upts') minjac = np.min([minjac, np.min(djac)]) advmax = self.vm.L() unitCFLdt = np.array([np.sqrt(minjac)/advmax/self.ndims]) gunitCFLdt = np.zeros(1) # MPI info comm, rank, root = get_comm_rank_root() # Reduce and, if we are the root rank, output if rank != root: comm.Reduce(unitCFLdt, gunitCFLdt, op=get_mpi('min'), root=root) else: comm.Reduce(unitCFLdt, gunitCFLdt, op=get_mpi('min'), root=root) print("Time-step for unit CFL:", gunitCFLdt) print("The actual time-step will depend on DG order CFL") # load the scattering model smn = cfg.get('scattering-model', 'type') scatteringcls = subclass_where(DGFSBiScatteringModel, scattering_model=smn) self.sm = scatteringcls(backend, self.cfg, self.vm) # Allocate and bank the storage required by the time integrator #eles_scal_upts_full = proxylist(self.ele_banks) eles_scal_upts_inb_full = proxylist(self.ele_banks) spcs_eles_scal_upts_full = [list(self.ele_banks) for spcs in range(self._nspcs)] if initsoln: #raise ValueError("Not implemented") # Load the config and stats files from the solution solncfg = Inifile(initsoln['config']) solnsts = Inifile(initsoln['stats']) # Get the names of the conserved variables (fields) solnfields = solnsts.get('data', 'fields', '') # see dgfsdistwriterbi.py plugin currfields = [] fields = ['f_'+str(i) for i in range(vsize)] lf = len(fields) for p in range(self._nspcs): currfields.extend(fields) for ivar in range(-1,-lf-1,-1): currfields[ivar] += ':'+str(p+1) currfields = ','.join(currfields) # Ensure they match up if solnfields and solnfields != currfields: raise RuntimeError('Invalid solution for system') # Ensure the solnfields are not empty if not solnfields: raise RuntimeError('Invalid solution for system') nreg0 = nreg//self._nspcs assert nreg==nreg0*self._nspcs, "Should be multiple of nspcs" # Process the solution for t, (k, ele) in enumerate(self.ele_map.items()): soln = initsoln['soln_%s_p%d' % (k, rallocs.prank)] #ele.set_ics_from_soln(soln, solncfg) # Recreate the existing solution basis solnb = ele.basis.__class__(None, solncfg) # Form the interpolation operator interp = solnb.ubasis.nodal_basis_at(ele.basis.upts) # Apply and reshape data = np.dot(interp, soln.reshape(solnb.nupts, -1)) data = data.reshape(ele.nupts, self._nspcs*vsize, ele.neles) for p in range(self._nspcs): spcs_eles_scal_upts_full[p][t] = data[:, p*vsize:(p+1)*vsize, :] else: # load the initial condition model icn = cfg.get('soln-ics', 'type') initcondcls = subclass_where(DGFSBiInitCondition, model=icn) ic = initcondcls(backend, cfg, self.vm, 'soln-ics') #initvals = ic.get_init_vals() nreg0 = nreg//self._nspcs assert nreg==nreg0*self._nspcs, "Should be multiple of nspcs" # loop over the sub-domains in the full mixed domain for p in range(self._nspcs): for t, ele in enumerate(self.ele_map.values()): spcs_eles_scal_upts_full[p][t] = np.empty( (ele.nupts, vsize, ele.neles)) ic.apply_init_vals(p, spcs_eles_scal_upts_full[p][t], ele) # Convert from primitive to conservative form if needed nreg0 = nreg//self._nspcs assert nreg==nreg0*self._nspcs, "Should be multiple of nspcs" for t in range(len(eles_scal_upts_inb_full)): scal_upts_full = [] for p in range(self._nspcs): if p==0: scal_upts_full = [ backend.matrix(spcs_eles_scal_upts_full[p][t].shape, spcs_eles_scal_upts_full[p][t], tags={'align'}) for i in range(nreg0)] else: scal_upts_full.extend([ backend.matrix(spcs_eles_scal_upts_full[p][t].shape, spcs_eles_scal_upts_full[p][t], tags={'align'}) for i in range(nreg0)]) eles_scal_upts_inb_full[t] = backend.matrix_bank(scal_upts_full) #eles_scal_upts_outb_full[t] = backend.matrix_bank(scal_upts_full) self.eles_scal_upts_inb_full = eles_scal_upts_inb_full del spcs_eles_scal_upts_full
def get_rank_allocation(mesh, cfg): name = cfg.get('backend', 'rank-allocator', 'linear') return subclass_where(BaseRankAllocator, name=name)(mesh, cfg)
def get_partitioner(name, *args, **kwargs): return subclass_where(BasePartitioner, name=name)(*args, **kwargs)