Source code for pyfr.integrators.dual.controllers
# -*- coding: utf-8 -*-
import math
from pyfr.integrators.dual.base import BaseDualIntegrator
from pyfr.mpiutil import get_comm_rank_root, get_mpi
from pyfr.util import memoize
class BaseDualController(BaseDualIntegrator):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Solution filtering frequency
self._fnsteps = self.cfg.getint('soln-filter', 'nsteps', '0')
# Stats on the most recent step
self.stepinfo = []
def _accept_step(self, dt, idxcurr):
self.tcurr += dt
self.nacptsteps += 1
self.nacptchain += 1
self._idxcurr = idxcurr
# Filter
if self._fnsteps and self.nacptsteps % self._fnsteps == 0:
self.system.filt(idxcurr)
# Invalidate the solution cache
self._curr_soln = None
# Fire off any event handlers
self.completed_step_handlers(self)
[docs]class DualNoneController(BaseDualController):
controller_name = 'none'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
sect = 'solver-time-integrator'
self._maxniters = self.cfg.getint(sect, 'pseudo-niters-max')
self._minniters = self.cfg.getint(sect, 'pseudo-niters-min')
if self._maxniters < self._minniters:
raise ValueError('The maximum number of pseudo-iterations must '
'be greater than or equal to the minimum')
self._pseudo_aresid = self.cfg.getfloat(sect, 'pseudo-aresid')
self._pseudo_rresid = self.cfg.getfloat(sect, 'pseudo-rresid')
[docs] def advance_to(self, t):
if t < self.tcurr:
raise ValueError('Advance time is in the past')
while self.tcurr < t:
for i in range(self._maxniters):
dt = max(min(t - self.tcurr, self._dt), self.dtmin)
dtau = max(min(t - self.tcurr, self._dtau), self.dtaumin)
# Take the step
self._idxcurr, self._idxprev = self.step(self.tcurr, dt, dtau)
# Activate convergence monitoring after pseudo-niters-min
if i >= self._minniters - 1:
# Subtract the current solution from the previous solution
self._add(-1.0/dtau, self._idxprev, 1.0/dtau, self._idxcurr)
# Compute the normalised residual and check for convergence
if self._resid(self._idxprev, self._idxcurr) < 1.0:
break
# Update the dual-time stepping banks (n+1 => n, n => n-1)
self.finalise_step(self._idxcurr)
# We are not adaptive, so accept every step
self._accept_step(dt, self._idxcurr)
[docs] @memoize
def _get_errest_kerns(self):
return self._get_kernels('errest', nargs=3, norm='uniform')
[docs] def _resid(self, x, y):
comm, rank, root = get_comm_rank_root()
# Get an errest kern to compute the square of the maximum residual
errest = self._get_errest_kerns()
# Prepare and run the kernel
self._prepare_reg_banks(x, y, y)
self._queue % errest(self._pseudo_aresid, self._pseudo_rresid)
# Reduce locally (element types) and globally (MPI ranks)
rl = max(errest.retval)
rg = comm.allreduce(rl, op=get_mpi('max'))
# Normalise
return math.sqrt(rg)