def test_empty_texts(): assert str(Elem(content=Text(''))) == '<div></div>' assert str(Elem(content=[Text(''), Text('')])) == '<div></div>' assert str( Elem(content=[Text('foo'), Text(''), Elem()])) == '<div>\n foo\ \n <div></div>\n</div>' print('Elem with empty texts : OK.')
def test_embedding(): assert (str(Elem(content=Elem(content=Elem(content=Elem())))) == """<div> <div> <div> <div></div> </div> </div> </div>""") print('Element embedding : OK.')
def __init__(self, mat_cls, mesh_cls, prob_dict): # equation name self._name = 'nda' # mesh data self._mesh = mesh_cls self._cell_length = mesh_cls.cell_length() # quantities of interest self._keff = 1.0 self._keff_prev = 1.0 # preassembly-interpolation data self._elem = Elem(self._cell_length) # material ids and group info self._mids = mat_cls.get('ids') self._n_grp = mat_cls.get('n_grps') self._g_thr = mat_cls.get('g_thermal') # mesh self._mesh = msh_cls # problem type self._is_eigen = prob_dict['is_eigen_problem'] self._do_ua = prob_dict['do_ua'] # linear algebra objects self._sys_mats = {} self._sys_rhses = { k: np.ones(self._n_dof) for k in xrange(self._n_tot) } self._fixed_rhses = { k: np.zeros(self._n_dof) for k in xrange(self._n_tot) } self._sflxes = {k: np.ones(self._n_dof) for k in xrange(self._n_grp)} # linear solver objects self._lu = {} # total number of components: keep consistency with HO self._n_tot = self._n_grp # all material self._dcoefs = mat_cls.get('diff_coef') self._sigts = mat_cls.get('sig_t') self._sigses = mat_cls.get('sig_s') self._sigrs = mat_cls.get('sig_r') self._fiss_xsecs = mat_cls.get('chi_nu_sig_f') # derived material properties self._sigrs_ua = mat_cls.get('sig_r_ua') self._dcoefs_ua = mat_cls.get('diff_coef_ua') # fission source self._global_fiss_src = self._calculate_fiss_src() self._global_fiss_src_prev = self._global_fiss_src # assistance object self._local_dof_pairs = pd(xrange(4), xrange(4))
def last_test(): assert (str( Elem(tag='html', content=[ Elem(tag='head', content=Elem(tag='title', content=Text('"Hello ground!"'))), Elem(tag='body', content=[ Elem(tag='h1', content=Text('"Oh no, not again!"')), Elem(tag='img', attr={'src': "http://i.imgur.com/pfp3T.jpg"}, tag_type='simple') ]) ])) == """<html> <head> <title> "Hello ground!" </title> </head> <body> <h1> "Oh no, not again!" </h1> <img src="http://i.imgur.com/pfp3T.jpg" /> </body> </html>""") print('Last Test : OK.')
def last_test(): print( str( Elem(tag='html', content=[ Elem(tag='head', content=Elem(tag='title', content=Text('"Hello ground!"'))), Elem(tag='body', content=[ Elem(tag='h1', content=Text('"Oh no, not again!"')), Elem( tag='img', attr={'src': "http://i.imgur.com/pfp3T.jpg"}, tag_type='simple') ]) ]))) # == '''<html> # <head> # <title> # "Hello ground!" # </title> # </head> # <body> # <h1> # "Oh no, not again!" # </h1> # <img src="http://i.imgur.com/pfp3T.jpg"/> # </body> # </html>''' # ) print('Last Test : OK.')
def test_elem_basics(): # Default behaviour : assert str(Elem()) == '<div></div>' # Arguments order : assert str(Elem('div', {}, None, 'double')) == '<div></div>' # Argument names : assert str(Elem(tag='body', attr={}, content=Elem(), tag_type='double')) == '<body>\n <div></div>\n</body>' # With elem as content : assert str(Elem(content=Elem())) == '<div>\n <div></div>\n</div>' # With list as content : assert str(Elem(content=[Text('foo'), Text('bar'), Elem()])) == '<div>\n foo\n bar\n \ <div></div>\n</div>' print('Basic Elem behaviour : OK.')
def __init__(self, n: int, view: 'View'): self.view = view sorted_array = [] for i in range(1, n + 1): sorted_array.append(i) self.array = [] for i in range(0, n): rand_elem = random.choice(sorted_array) sorted_array.remove(rand_elem) self.array.append(Elem(rand_elem, self)) self.high_lighted1 = -1 self.high_lighted2 = -1 self.comparisons = 0 self.mutations = 0
def test_errors(): # Type error if the content isn't made of Text or Elem. try: Elem(content=1) except Exception as e: assert type(e) == Elem.ValidationError # The right way : assert str(Elem(content=Text(1))) == '<div>\n 1\n</div>' # Type error if the elements of the list aren't Text or Elem instances. try: Elem(content=['foo', Elem(), 1]) except Exception as e: assert type(e) == Elem.ValidationError # The right way : assert (str( Elem(content=[Text('foo'), Elem(), Text(1)])) == '<div>\n foo\n <div></div>\n 1\n</div>') # Same with add_method() try: elem = Elem() elem.add_content(1) raise (Exception("incorrect behaviour.")) except Exception as e: assert isinstance(e, Elem.ValidationError) # Or with lists : try: elem = Elem() elem.add_content([ 1, ]) raise (Exception('incorrect behaviour')) except Exception as e: assert isinstance(e, Elem.ValidationError) # str can't be used : try: elem = Elem() elem.add_content([ '', ]) raise (Exception("incorrect behaviour.")) except Exception as e: assert isinstance(e, Elem.ValidationError) try: elem = Elem(content='') raise (Exception("incorrect behaviour.")) except Exception as e: assert isinstance(e, Elem.ValidationError) print('Error cases : OK.')
def __init__(self, content=None, attr={}): Elem.__init__(self, tag="ul", attr=attr, content=content, tag_type='double')
def __init__(self, content=None, attr={}): Elem.__init__(self, tag="img", attr=attr, content=content, tag_type='simple')
class NDA(object): def __init__(self, mat_cls, mesh_cls, prob_dict): # equation name self._name = 'nda' # mesh data self._mesh = mesh_cls self._cell_length = mesh_cls.cell_length() # quantities of interest self._keff = 1.0 self._keff_prev = 1.0 # preassembly-interpolation data self._elem = Elem(self._cell_length) # material ids and group info self._mids = mat_cls.get('ids') self._n_grp = mat_cls.get('n_grps') self._g_thr = mat_cls.get('g_thermal') # mesh self._mesh = msh_cls # problem type self._is_eigen = prob_dict['is_eigen_problem'] self._do_ua = prob_dict['do_ua'] # linear algebra objects self._sys_mats = {} self._sys_rhses = { k: np.ones(self._n_dof) for k in xrange(self._n_tot) } self._fixed_rhses = { k: np.zeros(self._n_dof) for k in xrange(self._n_tot) } self._sflxes = {k: np.ones(self._n_dof) for k in xrange(self._n_grp)} # linear solver objects self._lu = {} # total number of components: keep consistency with HO self._n_tot = self._n_grp # all material self._dcoefs = mat_cls.get('diff_coef') self._sigts = mat_cls.get('sig_t') self._sigses = mat_cls.get('sig_s') self._sigrs = mat_cls.get('sig_r') self._fiss_xsecs = mat_cls.get('chi_nu_sig_f') # derived material properties self._sigrs_ua = mat_cls.get('sig_r_ua') self._dcoefs_ua = mat_cls.get('diff_coef_ua') # fission source self._global_fiss_src = self._calculate_fiss_src() self._global_fiss_src_prev = self._global_fiss_src # assistance object self._local_dof_pairs = pd(xrange(4), xrange(4)) def name(self): return self._name def assemble_bilinear_forms(self, ho_cls=None, correction=False): '''@brief A function used to assemble bilinear forms of NDA for current iterations @param correction A boolean used to determine if correction terms are assembled. By default, it's not. In this case, the bilinear form is typical diffusion ''' # TODO: Boundary is assumed to be reflective so kappa will not be handled streaming, mass = self._elem.streaming(), self._elem.mass() if correction: assert ho_cls is not None, 'ho_cls has to be filled in for NDA correction' # basic diffusion Elementary matrices diff_mats = {} # Elementary correction matrices corx, cory, sigt, dcoef = self._elem.corx(), self._elem.cory(), 0, 0 for g in xrange(self._n_grp): self._sys_mats[g] = sps.lil_matrix( (self._mesh.n_node(), self._mesh.n_node())) for mid in self._mids: sigt, sigr, dcoef = self._sigts[mid][g], self._sigrs[mid][ g], self._dcoefs[mid][g] diff_mats[(g, mid)] = (dcoef * streaming + sigr * mass) # preassembled matrices for upscattering acceleration if self._do_ua: self._sys_mats['ua'] = sps.lil_matrix( (self._mesh.n_node(), self._mesh.n_node())) for mid in self._mids: dcoef_ua, sigr_ua = self._dcoefs_ua[mid], self._sigrs_ua[mid] # basic elementary diffusion matrices for upscattering acceleration diff_mats[('ua', mid)] = (dcoef_ua * streaming + sigr_ua * mass) # loop over cells for assembly for cell in self._mesh.cells(): # get global dof index and mat id idx, mid = cell.id(), cell.global_idx() # corrections for all groups in current cell and ua corr_vecs = {} if correction: corr_vecs = ho_cls.calculate_nda_cell_correction(mat_id=mid, idx=idx) for g in xrange(self._n_grp): # if correction is asked cor_mat = np.zeros((4, 4)) if correction: # calculate NDA correction in HO class corr_vecs[g] = ho_cls.calculate_nda_cell_correction( g=g, mat_id=mid, idx=idx) # TODO: fixed the "9" for i in xrange(9): # x-component cor_mat += corr_vecs['x_comp'][g][i] * corx[i] # y-component cor_mat += corr_vecs['x_comp'][g][i] * cory[i] diff_mats[(g, mid)] += cor_mat # assemble global system for ci, cj in self._local_dof_pairs: self._sys_mats[g][idx[ci], idx[cj]] += diff_mats[(g, mid)][ci, cj] # if we do upscattering acceleration if self._do_ua: # assemble global system of ua matrix without correction for ci, cj in self._local_dof_pairs: self._sys_mats['ua'][idx[ci], idx[cj]] += diff_mats[('ua', mid)][ci, cj] # correction matrix for upscattering acceleration cor_mat_ua = np.zeros((4, 4)) if correction: for i in xrange(len(corr_vecs[0])): cor_mat_ua += (corr_vecs['x_ua'][i] * corx[i] + corr_vecs['y_ua'][i] * cory[i]) diff_mats[('ua', mid)] += cor_mat_ua[ci, cj] # mapping UA matrix to global for ci, cj in self._local_dof_pairs: self._sys_mats['ua'][idx[ci], idx[cj]] += diff_mats[('ua', mid)][ci, cj] # Transform system matrices to CSC format for g in xrange(self._n_grp): self._sys_mats[g] = sps.csc_matrix(self._sys_mats[g]) if self._do_ua: self._sys_mats['ua'] = sps.csc_matrix(self._sys_mats['ua']) def assemble_fixed_linear_forms(self, sflxes_prev=None): '''@brief function used to assemble linear form for fixed source or fission source ''' # scale the fission xsec by keff scaled_fiss_xsec = {k: v / self._keff for k, v in self._fiss_xsecs} for g in xrange(self._n_grp): fixed_rhses[g] = np.array(self._mesh.n_node()) for cell in self._mesh.cells(): idx, mid, fiss_src = cell.global_idx(), cell.id(), np.zeros(4) for gi in filter(lambda: scaled_fiss_xsec[mid][g, x] > 1.0e-14, xrange(self._n_grp)): sflx_vtx = self._sflxes[g][idx] if not sflxes_prev else \ sflxes_prev[g][idx] fiss_src += scaled_fiss_xsec[mid][g, gi] * np.dot( mass, sflx_vtx) self._fixed_rhses[g][idx] += fiss_src def _assemble_group_linear_forms(self, g): '''@brief A function used to assemble linear form for upscattering acceleration ''' # NOTE: due to pass-by-reference feature in Python, we have to make # deep copy of fixed rhs instead of using "=" np.copyto(self._sys_rhses[g], self._fixed_rhses[g]) # get mass matrix mass = self._elem.mass() for cell in mesh.cells: idx, mid = cell.global_idx(), cell.id() sigs = self._sigses[mid][g, :] scat_src = np.zeros(4) for gi in filter(lambda x: sigs[x] > 1.0e-14 and x != g, xrange(self._n_grp)): sflx_vtx = self._sflxes[gi][idx] scat_src += sigs[gi] * np.dot(mass, sflx_vtx) self._sys_rhses[g][idx] += scat_src def _assemble_ua_linear_form(self, sflxes_old): '''@brief A function used to assemble linear form for upscattering acceleration ''' assert len(sflxes_old)==self._n_grp, \ 'old scalar fluxes should have the same number of groups as current scalar fluxes' mass = self._elem.mass() self._sys_rhses['ua'] *= 0.0 for cell in self._mesh.cells(): idx, mid, scat_src_ua = cell.global_idx(), cell.id(), np.zeros(4) for g in xrange(self._g_thr, self._n_grp - 1): for gi in xrange(g + 1, self._n_grp): sigs = self._sigses[mid][g, gi] if sigs > 1.0e-14: dsflx_vtx = self._sflxes[gi][idx] - sflxes_old[g][idx] scat_src_ua += sigs * np.dot(mass, dsflx_vtx) self._sys_rhses['ua'][idx] += scat_src_ua def solve_in_group(self, g): assert 0 <= g < self._n_grp, 'Group index out of range' self._assemble_group_linear_forms(g) if g not in self._lu: # factorize it if not yet self._lu[g] = sla.splu(self._sys_mats[g]) # direct solve self._sflxes[g] = self._lu[g].solve(self._sys_rhses[g]) #NOTE: this function has to be removed if abstract class is implemented def calculate_keff(self): assert not self._is_eigen, 'only be called in eigenvalue problems' # update the previous fission source and previous keff self._global_fiss_src_prev, self._keff_prev = self._global_fiss_src, self._keff # calculate the new fission source self._calculate_fiss_src() # calculate the new keff self._keff = self._keff_prev * self._global_fiss_src / self._global_fiss_src_prev return self._keff #NOTE: this function has to be removed if abstract class is implemented def calculate_sflx_diff(self, sflxes_old, g): '''@brief function used to generate ho scalar flux for Group g using angular fluxes @param sflx_old Scalar flux from previous generation @param g The group index @return double The relative difference between new and old scalar flux ''' # return the l1 norm relative difference return norm( (self._sflxes[g] - sflxes_old[g]), 1) / norm(self._sflxes[g], 1) #NOTE: this function has to be removed if abstract class is implemented def update_sflxes(self, sflxes_old, g): '''@brief A function used to update scalar flux for group g @param sflxes_old A dictionary @param g Group index ''' np.copyto(sflxes_old[g], self._sflxes[g]) def update_ua(self): '''@brief A function used to update the scalar fluxes after upscattering acceleration ''' for g in xrange(self.g_thr, self._n_grp): self._sflxes[g] += self._sflxes['ua'] def clear_factorization(self): '''@brief A function used to clear all the factorizations after NDA is dictionaries for current iteration Every outer iterations, NDA equations are modified so previous factorizations are no longer suitable and must be cleared and redone. ''' self._lu.clear() def solve_ua(self): # assemble ua self._assemble_ua_linear_form() if 'ua' not in self._lu: # factorize it if not yet self._lu['ua'] = sla.splu(self._sys_mats['ua']) # direct solve self._sflxes['ua'] = self._lu['ua'].solve(self._sys_rhses['ua']) def get_sflxes(self, g): '''@brief Function called outside to retrieve the scalar flux value for Group g @param g Target group number ''' return self._sflxes[g] def get_sflx_vtx(self, g, idx): return self._sflxes[g][idx] def get_keff(self): '''@brief A function used to retrieve keff @return keff calculated in SAAF class ''' return self._keff def do_ua(self): return self._do_ua def n_dof(self): return self._mesh.n_node() def n_grp(self): return self._n_grp
class SAAF(object): def __init__(self, mat_cls, mesh_cls, prob_dict): # name of the Equation self._name = 'saaf' # mesh data self._mesh = mesh_cls self._cell_length = mesh_cls.cell_length() # quantities of interest self._keff = 1.0 self._keff_prev = 1.0 # preassembly-interpolation data self._elem = Elem(self._cell_length) # material data self._n_grp = mat_cls.get('n_grps') self._g_thr = mat_cls.get('g_thermal') self._sigts = mat_cls.get('sig_t') self._isigts = mat_cls.get('inv_sig_t') self._fiss_xsecs = mat_cls.get_per_str('chi_nu_sig_f') self._nu_sigfs = mat_cls.get('nu_sig_f') self._sigses = mat_cls.get_per_str('sig_s') self._dcoefs = mat_cls.get('diff_coef') self._mids = mat_cls.ids() # derived material data self._ksi_ua = mat_cls.get('ksi_ua') # problem type: is problem eigenvalue problem # aq data in forms of dictionary self._aq = AQ(prob_dict['sn_order']).get_aq_data() self._n_dir = self._aq['n_dir'] # total number of components in HO self._n_tot = self._n_grp * self._n_dir # get a component indexing mapping self._comp = dict() # component to group map self._comp_grp = dict() # component to direction map self._comp_dir = dict() self._generate_component_map() # local vectors self._rhs_mats = dict() self._preassembly_rhs() # related to global matrices and vectors self._n_dof = mesh_cls.n_node() self._sys_mats = {} # be very careful about the following self._sys_rhses = { k: np.ones(self._n_dof) for k in xrange(self._n_tot) } self._fixed_rhses = { k: np.zeros(self._n_dof) for k in xrange(self._n_tot) } self._aflxes = {k: np.ones(self._n_dof) for k in xrange(self._n_tot)} # scalar flux for current calculation self._sflxes = {k: np.ones(self._n_dof) for k in xrange(self._n_grp)} # linear solver objects self._lu = {} # source iteration tol self._tol = 1.0e-7 # fission source self._global_fiss_src = self._calculate_fiss_src() self._global_fiss_src_prev = self._global_fiss_src # assistance: self._local_dof_pairs = pd(xrange(4), xrange(4)) def _generate_component_map(self): '''@brief Internal function used to generate mappings between component, group and directions ''' ct = 0 for g in xrange(self._n_grp): for d in xrange(self._n_dir): self._comp[(g, d)] = ct self._comp_grp[ct] = g self._comp_dir[ct] = d ct += 1 def _preassembly_rhs(self): for mid in self._mids: sigts, isigts = self._sigts[mid], self._isigts[mid] for g in xrange(self._n_grp): for d in xrange(self._n_dir): ox, oy = self._aq['omega'][d] # streaming part of rhs rhs_mat = (ox * self._elem.dxvu() + oy * self._elem.dyvu()) * isigts[g] # mass part of rhs rhs_mat += sigts[g] * self._elem.mass() self._rhs_mats[mid] = {(g, d): rhs_mat} def name(self): return self._name def assemble_bilinear_forms(self): '''@brief Function used to assemble bilinear forms @param correction Boolean to determine if correction is needed. Only useful in NDA class ''' # retrieve all the material properties for i in xrange(self._n_tot): # get the group and direction indices g, d = self._comp_grp[i], self._comp_dir[i] # get omega_i * omega_j combinations oxox, oxoy, oyoy = self._aq['dir_prods'][d].values() # dict containing lhs local matrices for all materials for component i lhs_mats = dict() for mid in self._mids: sigt, isigt = self._sigts[mid][g], self._isigts[mid][g] # streaming lhs matx = isigt * (oxox * self._elem.dxdx() + oxoy * (self._elem.dxdy() + self._elem.dydx()) + oyoy * self._elem.dydy()) # collision matrix matx += sigt * self._elem.mass() lhs_mats[mid] = matx # loop over cells for assembly # sys_mat: temp variable for system matrix for one component sys_mat = sps.lil_matrix( (self._mesh.n_node(), self._mesh.n_node())) for cell in self._mesh.cells(): # retrieving global indices and material id per cell idx, mid = cell.global_idx(), cell.get('id') # mapping local matrices to global for ci, cj in self._local_dof_pairs: sys_mat[idx[ci], idx[cj]] += lhs_mats[mid][ci][cj] # boundary part if cell.bounds(): # loop over for bd in cell.bounds().keys(): if self._aq['bd_angle'][(bd, d)] > 0: #outgoing boundary assembly: retrieving omega*n and boundary mass matrices odn, bd_mass = self._aq['bd_angle'][( bd, d)], self._elem.bdmt()[bd] # mapping local vertices to global for ci, cj in self._local_dof_pairs: if bd_mass[ci][cj] > 1.0e-14: sys_mat[idx[ci], idx[cj]] += odn * bd_mass[ci][cj] # transform lil_matrix to csc_matrix for efficient computation self._sys_mats[i] = sps.csc_matrix(sys_mat) def assemble_fixed_linear_forms(self, sflxes_prev=None, nda_cls=None): '''@brief a function used to assemble fixed source or fission source on the rhs for all components Generate fission source. If nda_cls is not None, sflxes_prev is ignored ''' if not nda_cls: assert sflxes_prev is not None, 'scalar flux must be provided' # get properties per str scaled by keff for cp in xrange(self._n_tot): # re-init fixed rhs. This must be done at the beginning of calling this function self._fixed_rhses[cp] = np.array(self._n_dof) # get group and direction indices g, d = self._comp_grp[cp], self._comp_dir[cp] for cell in self._mesh.cells(): idx, mid = cell.global_idx(), cell.get('id') fiss_src, fiss_xsec = np.zeros(4), self._fiss_xsecs[mid][g] # get fission source contribution from ingroups for gi in filter(lambda j: fiss_xsec[j] > 1.0e-14, xrange(self._n_grp)): sflx_vtx = sflxes_prev[gi][idx] if not nda_cls else \ nda_cls.get_sflx_vtx(gi, idx) fiss_src += fiss_xsec[gi] * np.dot( self._rhs_mats[mid][(g, d)], sflx_vtx) self._fixed_rhses[cp][idx] += fiss_src def _assemble_group_linear_forms(self, g, nda_cls=None): '''@brief Function used to assemble linear forms for Group g if NDA is used, nda_cls must be filled in. This function will not be called from outside. It will rather be called in solve_in_group or solve_all_groups ''' assert 0 <= g < self._n_grp, 'Group index out of range' if nda_cls: assert nda_cls.name( ) == 'nda', 'Correct NDA class must be filled in' for d in xrange(self._n_dir): cp = self._comp[(g, d)] # get fixed/fission source # NOTE: due to pass-by-reference feature in Python, we have to make # deep copy of fixed rhs instead of using "=" np.copyto(self._sys_rhses[cp], self._fixed_rhses[cp]) # go through all cells for cell in self._mesh.cells(): # get global dof indices and material ids idx, mid = cell.global_idx(), cell.get('id') # get scattering matrix for current cell sigs = self._sigses[mid] # calculate local scattering source scat_bd_src = np.zeros(4) for gi in filter(lambda x: sigs[g][x] > 1.0e-14, xrange(self._n_grp)): # retrieve scalar flux at vertices sflx_vtx = self._sflxes[gi][idx] if not nda_cls \ else nda_cls.get_sflx_vtx(gi, idx) # calculate scattering source scat_bd_src += sigs[g, gi] * np.dot( self._rhs_mats[mid][(g, d)], sflx_vtx) # if it's boundary if cell.bounds(): for bd, tp in cell.bounds().items(): # incident boundary with reflective setting if tp == 'refl' and self._aq['bd_angle'][(bd, d)] < 0.0: r_dir = self._aq['refl_dir'][(bd, d)] odn = abs(self._aq['bd_angle'][(bd, d)]) bd_mass = self._elem.bdmt()[bd] bd_aflx = self._aflxes[self._comp(g, r_dir)][idx] scat_bd_src += odn * np.dot(bd_mass, bd_aflx) self._sys_rhses[cp][idx] += scat_bd_src def _assemble_linear_forms(self, nda_cls): '''@brief A function call to assemble linear forms for all components once This function is to be called along with NDA providing keff and fluxes ''' assert nda_cls is not None and nda_cls.name( ) == 'nda', 'NDA has to be passed in to call' # NOTE: this is not the most efficient way as there is no need to separating # the assembly process here self.assemble_fixed_linear_forms(sflxes_prev=None, nda_cls=nda_cls) for g in xrange(self._n_grp): self._assemble_group_linear_forms(g=g, nda_cls=nda_cls) def solve_all_groups(self, nda_cls): '''@brief A function call to solve all components once This function is to be called along with NDA providing rhs ''' self._assemble_linear_forms(nda_cls=nda_cls) for i in xrange(self._n_tot): if i not in self._lu: # factorization self._lu[i] = sla.splu(self._sys_mats[comp[(g, d)]]) # direct solve for angular fluxes self._aflxes[i] = self._lu[i].solve(self._sys_rhses[i]) def solve_in_group(self, g): '''@brief Called to solve direction by direction inside Group g @param g Group index ''' assert 0 <= g < self._n_grp, 'Group index out of range' # Source iteration e, sflx_ig_prev = 1.0, np.ones(self._n_dof) while e > self._tol: # assemble group rhses self._assemble_group_linear_forms(g) # copy scalar flux np.copyto(sflx_ig_prev, self._sflxes[g]) self._sflxes[g] *= 0 for d in xrange(self._n_dir): # if not factorized, factorize the the HO matrices cp = self._comp[(g, d)] if cp not in self._lu: self._lu[cp] = sla.splu(self._sys_mats[cp]) # solve direction d self._aflxes[cp] = self._lu[cp].solve(self._sys_rhses[cp]) self._sflxes[g] += self._aq['wt'][d] * self._aflxes[cp] # calculate difference for SI convergence e = norm(sflx_old_ig - self._sflxes[g], 1) / norm( self._sflxes[g], 1) #NOTE: this function has to be removed if abstract class is implemented def update_sflxes(self, sflxes_old, g): '''@brief A function used to update scalar flux for group g @param sflxes_old A dictionary @param g Group index ''' np.copyto(sflxes_old[g], self._sflxes[g]) def calculate_keff(self): assert not self._is_eigen, 'only be called in eigenvalue problems' # update the previous fission source and previous keff self._global_fiss_src_prev, self._keff_prev = self._global_fiss_src, self._keff # calculate the new fission source self._global_fiss_src = self._calculate_fiss_src() # calculate the new keff self._keff = self._keff_prev * self._global_fiss_src / self._global_fiss_src_prev return self._keff def _calculate_fiss_src(self): # loop over cells and groups and calculate nu_sig_f*phi # NOTE: the following calculation is using mid-point rule for integration # It will suffice only for constant,RT1 and bilinear finite elements. global_fiss_src = 0 for cell in self._mesh.cells(): idx, mid = cell.global_idx(), cell.get('id') nusigf = self._nu_sigfs[mid] for g in filter(lambda x: nusigf[x] > 1.0e-14, xrange(self._n_grp)): sflx_vtx = sum(self._sflxes[g][idx]) global_fiss_src += nusigf[g] * sflx_vtx return global_fiss_src def calculate_sflx_diff(self, sflxes_old, g): '''@brief function used to generate ho scalar flux for Group g using angular fluxes @param sflx_old Scalar flux from previous generation @param g The group index @return double The relative difference between new and old scalar flux ''' # return the l1 norm relative difference return norm( (self._sflxes[g] - sflxes_old[g]), 1) / norm(self._sflxes[g], 1) def calculate_nda_cell_correction(self, mat_id, idx, do_ua=False): # TODO: address the "9" corrs = { 'x_comp': np.zeros((self._n_grp, 9)), 'y_comp': np.zeros((self._n_grp, 9)) } for g in xrange(self._n_grp): dcoef = self._dcoefs[mat_id][g] isgit = self._isigts[mat_id][g] # retrive grad_aflx for all directions at quadrature points grad_aflxes_qp = { d: self._elem.get_grad_at_qps(self._aflxes[self._comp(g, d)][idx]) for d in self._n_dir } sflxes_qp = self._elem.get_sol_at_qps(self._sflxes[g][idx]) grad_sflx_qp = self._elem.get_grad_at_qps(self._sflxes[g][idx]) # calculate correction for x and y components corx, cory = np.zeros(len(sflxes_qp)), np.zeros(len(sflxes_qp)) for i in len(sflxes_qp): # transport current tc = np.zeros(2) for d in xrange(self._n_dir): # NOTE: 'wt_tensor' is equal to w*OmegaOmega, a 2x2 matrix tc += np.dot(self._aq['wt_tensor'][d], grad_aflxes_qp[d][i]) # minus diffusion current mdc = dcoef * grad_sflx_qp # corrections corx[i], cory[i] = (isgit * tc + mdc) / sflxes_qp[i] # wrap corrections to corrs corrs['x_comp'][g], corrs['y_comp'][g] = corx, cory # do upscattering acceleration if do_ua: corrs['x_ua'] = np.dot(self._ksi_ua[mat_id], corrs['x_comp'][self._g_thr:, ]) corrs['y_ua'] = np.dot(self._ksi_ua[mat_id], corrs['y_comp'][self._g_thr:, ]) return corrs def get_sflxes(self, g): '''@brief Function called outside to retrieve the scalar flux value for Group g @param g Target group number ''' return self._sflxes[g] def get_keff(self): '''@brief A function used to retrieve keff @return keff calculated in SAAF class ''' return self._keff def n_dof(self): return self._mesh.n_node() def n_grp(self): return self._n_grp
def __init__(self, mat_cls, mesh_cls, prob_dict): # name of the Equation self._name = 'saaf' # mesh data self._mesh = mesh_cls self._cell_length = mesh_cls.cell_length() # quantities of interest self._keff = 1.0 self._keff_prev = 1.0 # preassembly-interpolation data self._elem = Elem(self._cell_length) # material data self._n_grp = mat_cls.get('n_grps') self._g_thr = mat_cls.get('g_thermal') self._sigts = mat_cls.get('sig_t') self._isigts = mat_cls.get('inv_sig_t') self._fiss_xsecs = mat_cls.get_per_str('chi_nu_sig_f') self._nu_sigfs = mat_cls.get('nu_sig_f') self._sigses = mat_cls.get_per_str('sig_s') self._dcoefs = mat_cls.get('diff_coef') self._mids = mat_cls.ids() # derived material data self._ksi_ua = mat_cls.get('ksi_ua') # problem type: is problem eigenvalue problem # aq data in forms of dictionary self._aq = AQ(prob_dict['sn_order']).get_aq_data() self._n_dir = self._aq['n_dir'] # total number of components in HO self._n_tot = self._n_grp * self._n_dir # get a component indexing mapping self._comp = dict() # component to group map self._comp_grp = dict() # component to direction map self._comp_dir = dict() self._generate_component_map() # local vectors self._rhs_mats = dict() self._preassembly_rhs() # related to global matrices and vectors self._n_dof = mesh_cls.n_node() self._sys_mats = {} # be very careful about the following self._sys_rhses = { k: np.ones(self._n_dof) for k in xrange(self._n_tot) } self._fixed_rhses = { k: np.zeros(self._n_dof) for k in xrange(self._n_tot) } self._aflxes = {k: np.ones(self._n_dof) for k in xrange(self._n_tot)} # scalar flux for current calculation self._sflxes = {k: np.ones(self._n_dof) for k in xrange(self._n_grp)} # linear solver objects self._lu = {} # source iteration tol self._tol = 1.0e-7 # fission source self._global_fiss_src = self._calculate_fiss_src() self._global_fiss_src_prev = self._global_fiss_src # assistance: self._local_dof_pairs = pd(xrange(4), xrange(4))
def __init__(self, content=None, attr={}): Elem.__init__(self, tag="meta", attr=attr, content=content, tag_type='one')