def __init__(self, backend, systemcls, rallocs, mesh, initsoln, cfg, tcoeffs, dt): self.backend = backend sect = 'solver-time-integrator' mgsect = 'solver-dual-time-integrator-multip' # Get the solver order and set the initial multigrid level self._order = self.level = order = cfg.getint('solver', 'order') # Get the multigrid cycle self.cycle, self.csteps = zip(*cfg.getliteral(mgsect, 'cycle')) self.levels = sorted(set(self.cycle), reverse=True) if max(self.cycle) > self._order: raise ValueError('The multigrid level orders cannot exceed ' 'the solution order') if any(abs(i - j) > 1 for i, j in zip(self.cycle, self.cycle[1:])): raise ValueError('The orders of consecutive multigrid levels can ' 'only change by one') if self.cycle[0] != self._order or self.cycle[-1] != self._order: raise ValueError('The multigrid cycle needs to start end with the ' 'highest (solution) order ') # Initialise the number of cycles self.npmgcycles = 0 # Multigrid pseudo-time steps dtau = cfg.getfloat(sect, 'pseudo-dt') self.dtauf = cfg.getfloat(mgsect, 'pseudo-dt-fact', 1.0) self._maxniters = cfg.getint(sect, 'pseudo-niters-max', 0) self._minniters = cfg.getint(sect, 'pseudo-niters-min', 0) # Get the multigrid pseudostepper and pseudocontroller classes pn = cfg.get(sect, 'pseudo-scheme') cn = cfg.get(sect, 'pseudo-controller') cc = subclass_where(BaseDualPseudoController, pseudo_controller_name=cn) cc_none = subclass_where(BaseDualPseudoController, pseudo_controller_name='none') # Construct a pseudo-integrator for each level from pyfr.integrators.dual.pseudo import get_pseudo_stepper_cls self.pintgs = {} for l in self.levels: pc = get_pseudo_stepper_cls(pn, l) if l == order: bases = [cc, pc] mcfg = cfg else: bases = [cc_none, pc] mcfg = Inifile(cfg.tostr()) mcfg.set('solver', 'order', l) mcfg.set(sect, 'pseudo-dt', dtau * self.dtauf**(order - l)) for s in cfg.sections(): m = re.match(f'solver-(.*)-mg-p{l}$', s) if m: mcfg.rename_section(s, f'solver-{m.group(1)}') # A class that bypasses pseudo-controller methods within a cycle class lpsint(*bases): name = 'MultiPPseudoIntegrator' + str(l) aux_nregs = 2 if l != self._order else 0 @property def _aux_regidx(iself): if iself.aux_nregs != 0: return iself._regidx[-2:] @property def ntotiters(iself): return self.npmgcycles def convmon(iself, *args, **kwargs): pass def finalise_pseudo_advance(iself, *args, **kwargs): pass def _rhs_with_dts(iself, t, uin, fout): # Compute -∇·f iself.system.rhs(t, uin, fout) # Coefficients for the physical stepper svals = [sc / iself._dt for sc in iself._stepper_coeffs] # Physical stepper source addition -∇·f - dQ/dt axnpby = iself._get_axnpby_kerns(len(svals) + 1, subdims=iself._subdims) iself._prepare_reg_banks(fout, iself._idxcurr, *iself._stepper_regidx) iself._queue.enqueue_and_run(axnpby, 1, *svals) # Multigrid r addition if iself._aux_regidx: axnpby = iself._get_axnpby_kerns(2) iself._prepare_reg_banks(fout, iself._aux_regidx[0]) iself._queue.enqueue_and_run(axnpby, 1, -1) self.pintgs[l] = lpsint(backend, systemcls, rallocs, mesh, initsoln, mcfg, tcoeffs, dt) # Get the highest p system from plugins self.system = self.pintgs[self._order].system # Get the convergence monitoring method self.mg_convmon = cc.convmon # Initialise the restriction and prolongation matrices self._init_proj_mats() # Delete remaining elements maps from multigrid systems for l in self.levels[1:]: del self.pintgs[l].system.ele_map
def __init__(self, backend, systemcls, rallocs, mesh, initsoln, cfg, stp_nregs, stg_nregs, dt): self.backend = backend sect = 'solver-time-integrator' mgsect = 'solver-dual-time-integrator-multip' # Get the solver order and set the initial multigrid level self._order = self.level = order = cfg.getint('solver', 'order') # Get the multigrid cycle self.cycle, self.csteps = zip(*cfg.getliteral(mgsect, 'cycle')) self.levels = sorted(set(self.cycle), reverse=True) if max(self.cycle) > self._order: raise ValueError('The multigrid level orders cannot exceed ' 'the solution order') if any(abs(i - j) > 1 for i, j in zip(self.cycle, self.cycle[1:])): raise ValueError('The orders of consecutive multigrid levels can ' 'only change by one') if self.cycle[0] != self._order or self.cycle[-1] != self._order: raise ValueError('The multigrid cycle needs to start end with the ' 'highest (solution) order ') # Initialise the number of cycles self.npmgcycles = 0 # Multigrid pseudo-time steps dtau = cfg.getfloat(sect, 'pseudo-dt') self.dtauf = cfg.getfloat(mgsect, 'pseudo-dt-fact', 1.0) self._maxniters = cfg.getint(sect, 'pseudo-niters-max', 0) self._minniters = cfg.getint(sect, 'pseudo-niters-min', 0) # Get the multigrid pseudostepper and pseudocontroller classes pn = cfg.get(sect, 'pseudo-scheme') cn = cfg.get(sect, 'pseudo-controller') cc = subclass_where(BaseDualPseudoController, pseudo_controller_name=cn) cc_none = subclass_where(BaseDualPseudoController, pseudo_controller_name='none') # Construct a pseudo-integrator for each level from pyfr.integrators.dual.pseudo import get_pseudo_stepper_cls self.pintgs = {} for l in self.levels: pc = get_pseudo_stepper_cls(pn, l) if l == order: bases = [cc, pc] mcfg = cfg else: bases = [cc_none, pc] mcfg = Inifile(cfg.tostr()) mcfg.set('solver', 'order', l) mcfg.set(sect, 'pseudo-dt', dtau * self.dtauf**(order - l)) for s in cfg.sections(): if (m := re.match(f'solver-(.*)-mg-p{l}$', s)): mcfg.rename_section(s, f'solver-{m.group(1)}') # A class that bypasses pseudo-controller methods within a cycle class lpsint(*bases): name = 'MultiPPseudoIntegrator' + str(l) aux_nregs = 2 if l != self._order else 0 stepper_nregs = stp_nregs if l == self._order else 0 stage_nregs = stg_nregs if l == self._order else 0 @property def _aux_regidx(iself): if iself.aux_nregs != 0: return iself._regidx[-2:] @property def ntotiters(iself): return self.npmgcycles def convmon(iself, *args, **kwargs): pass def _rhs_with_dts(iself, t, uin, fout, mg_add=True): # Compute -∇·f iself.system.rhs(t, uin, fout) if iself.stage_nregs > 1: iself._add(0, self._stage_regidx[iself.currstg], 1, fout) # Registers vals = iself.stepper_coeffs[:2] + [1] regs = [fout, iself._idxcurr, iself._source_regidx] # Physical stepper source addition -∇·f - dQ/dt iself._addv(vals, regs, subdims=iself._subdims) # Multigrid r addition if mg_add and iself._aux_regidx: iself._add(1, fout, -1, iself._aux_regidx[0]) self.pintgs[l] = lpsint(backend, systemcls, rallocs, mesh, initsoln, mcfg, stp_nregs, stg_nregs, dt)