class LSRK4TimeStepper(TimeStepper): """A low storage fourth-order Runge-Kutta method See JSH, TW: Nodal Discontinuous Galerkin Methods p.64 or Carpenter, M.H., and Kennedy, C.A., Fourth-order-2N-storage Runge-Kutta schemes, NASA Langley Tech Report TM 109112, 1994 """ _RK4A = [ 0.0, -567301805773 / 1357537059087, -2404267990393 / 2016746695238, -3550918686646 / 2091501179385, -1275806237668 / 842570457699, ] _RK4B = [ 1432997174477 / 9575080441755, 5161836677717 / 13612068292357, 1720146321549 / 2090206949498, 3134564353537 / 4481467310338, 2277821191437 / 14882151754819, ] _RK4C = [ 0.0, 1432997174477 / 9575080441755, 2526269341429 / 6820363962896, 2006345519317 / 3224310063776, 2802321613138 / 2924317926251, #1, ] dt_fudge_factor = 1 adaptive = False def __init__(self, dtype=numpy.float64, rcon=None, vector_primitive_factory=None): if vector_primitive_factory is None: from hedge.vector_primitives import VectorPrimitiveFactory self.vector_primitive_factory = VectorPrimitiveFactory() else: self.vector_primitive_factory = vector_primitive_factory from pytools.log import IntervalTimer, EventCounter timer_factory = IntervalTimer if rcon is not None: timer_factory = rcon.make_timer self.timer = timer_factory("t_rk4", "Time spent doing algebra in RK4") self.flop_counter = EventCounter( "n_flops_rk4", "Floating point operations performed in RK4") from pytools import match_precision self.dtype = numpy.dtype(dtype) self.scalar_dtype = match_precision(numpy.dtype(numpy.float64), self.dtype) self.coeffs = numpy.array([self._RK4A, self._RK4B, self._RK4C], dtype=self.scalar_dtype).T def get_stability_relevant_init_args(self): return () def add_instrumentation(self, logmgr): logmgr.add_quantity(self.timer) logmgr.add_quantity(self.flop_counter) def __call__(self, y, t, dt, rhs): try: self.residual except AttributeError: self.residual = 0 * rhs(t, y) from hedge.tools import count_dofs self.dof_count = count_dofs(self.residual) self.linear_combiner = self.vector_primitive_factory\ .make_linear_combiner(self.dtype, self.scalar_dtype, y, arg_count=2) lc = self.linear_combiner for a, b, c in self.coeffs: this_rhs = rhs(t + c * dt, y) sub_timer = self.timer.start_sub_timer() self.residual = lc((a, self.residual), (dt, this_rhs)) del this_rhs y = lc((1, y), (b, self.residual)) sub_timer.stop().submit() # 5 is the number of flops above, *NOT* the number of stages, # which is already captured in len(self.coeffs) self.flop_counter.add(len(self.coeffs) * self.dof_count * 5) return y
class LSRK4TimeStepper(TimeStepper): """A low storage fourth-order Runge-Kutta method See JSH, TW: Nodal Discontinuous Galerkin Methods p.64 or Carpenter, M.H., and Kennedy, C.A., Fourth-order-2N-storage Runge-Kutta schemes, NASA Langley Tech Report TM 109112, 1994 """ _RK4A = [0.0, -567301805773 /1357537059087, -2404267990393/2016746695238, -3550918686646/2091501179385, -1275806237668/ 842570457699, ] _RK4B = [1432997174477/ 9575080441755, 5161836677717 /13612068292357, 1720146321549 / 2090206949498, 3134564353537 / 4481467310338, 2277821191437 /14882151754819, ] _RK4C = [0.0, 1432997174477/9575080441755, 2526269341429/6820363962896, 2006345519317/3224310063776, 2802321613138/2924317926251, #1, ] dt_fudge_factor = 1 adaptive = False def __init__(self, dtype=numpy.float64, rcon=None, vector_primitive_factory=None): if vector_primitive_factory is None: from hedge.vector_primitives import VectorPrimitiveFactory self.vector_primitive_factory = VectorPrimitiveFactory() else: self.vector_primitive_factory = vector_primitive_factory from pytools.log import IntervalTimer, EventCounter timer_factory = IntervalTimer if rcon is not None: timer_factory = rcon.make_timer self.timer = timer_factory( "t_rk4", "Time spent doing algebra in RK4") self.flop_counter = EventCounter( "n_flops_rk4", "Floating point operations performed in RK4") from pytools import match_precision self.dtype = numpy.dtype(dtype) self.scalar_dtype = match_precision( numpy.dtype(numpy.float64), self.dtype) self.coeffs = numpy.array([self._RK4A, self._RK4B, self._RK4C], dtype=self.scalar_dtype).T def get_stability_relevant_init_args(self): return () def add_instrumentation(self, logmgr): logmgr.add_quantity(self.timer) logmgr.add_quantity(self.flop_counter) def __call__(self, y, t, dt, rhs): try: self.residual except AttributeError: self.residual = 0*rhs(t, y) from hedge.tools import count_dofs self.dof_count = count_dofs(self.residual) self.linear_combiner = self.vector_primitive_factory\ .make_linear_combiner(self.dtype, self.scalar_dtype, y, arg_count=2) lc = self.linear_combiner for a, b, c in self.coeffs: this_rhs = rhs(t + c*dt, y) sub_timer = self.timer.start_sub_timer() self.residual = lc((a, self.residual), (dt, this_rhs)) del this_rhs y = lc((1, y), (b, self.residual)) sub_timer.stop().submit() # 5 is the number of flops above, *NOT* the number of stages, # which is already captured in len(self.coeffs) self.flop_counter.add(len(self.coeffs)*self.dof_count*5) return y
class AdamsBashforthTimeStepper(TimeStepper): dt_fudge_factor = 0.95 def __init__(self, order, startup_stepper=None, dtype=numpy.float64, rcon=None): self.f_history = [] from pytools import match_precision self.dtype = numpy.dtype(dtype) self.scalar_dtype = match_precision( numpy.dtype(numpy.float64), self.dtype) self.coefficients = numpy.asarray(make_ab_coefficients(order), dtype=self.scalar_dtype) if startup_stepper is not None: self.startup_stepper = startup_stepper else: from hedge.timestep.runge_kutta import LSRK4TimeStepper self.startup_stepper = LSRK4TimeStepper(self.dtype) from pytools.log import IntervalTimer, EventCounter timer_factory = IntervalTimer if rcon is not None: timer_factory = rcon.make_timer self.timer = timer_factory( "t_ab", "Time spent doing algebra in Adams-Bashforth") self.flop_counter = EventCounter( "n_flops_ab", "Floating point operations performed in AB") @property def order(self): return len(self.coefficients) def get_stability_relevant_init_args(self): return (self.order,) def add_instrumentation(self, logmgr): logmgr.add_quantity(self.timer) logmgr.add_quantity(self.flop_counter) def __getinitargs__(self): return (self.order, self.startup_stepper) def __call__(self, y, t, dt, rhs): if len(self.f_history) == 0: # insert IC self.f_history.append(rhs(t, y)) from hedge.tools import count_dofs self.dof_count = count_dofs(self.f_history[0]) if len(self.f_history) < len(self.coefficients): ynew = self.startup_stepper(y, t, dt, rhs) if len(self.f_history) == len(self.coefficients) - 1: # here's some memory we won't need any more del self.startup_stepper else: from operator import add sub_timer = self.timer.start_sub_timer() assert len(self.coefficients) == len(self.f_history) ynew = y + dt * reduce(add, (coeff * f for coeff, f in zip(self.coefficients, self.f_history))) self.f_history.pop() sub_timer.stop().submit() self.flop_counter.add((2+2*len(self.coefficients)-1)*self.dof_count) self.f_history.insert(0, rhs(t+dt, ynew)) return ynew
class AdamsBashforthTimeStepper(TimeStepper): dt_fudge_factor = 0.95 def __init__(self, order, startup_stepper=None, dtype=numpy.float64, rcon=None): self.f_history = [] from pytools import match_precision self.dtype = numpy.dtype(dtype) self.scalar_dtype = match_precision(numpy.dtype(numpy.float64), self.dtype) self.coefficients = numpy.asarray(make_ab_coefficients(order), dtype=self.scalar_dtype) if startup_stepper is not None: self.startup_stepper = startup_stepper else: from hedge.timestep.runge_kutta import LSRK4TimeStepper self.startup_stepper = LSRK4TimeStepper(self.dtype) from pytools.log import IntervalTimer, EventCounter timer_factory = IntervalTimer if rcon is not None: timer_factory = rcon.make_timer self.timer = timer_factory( "t_ab", "Time spent doing algebra in Adams-Bashforth") self.flop_counter = EventCounter( "n_flops_ab", "Floating point operations performed in AB") @property def order(self): return len(self.coefficients) def get_stability_relevant_init_args(self): return (self.order, ) def add_instrumentation(self, logmgr): logmgr.add_quantity(self.timer) logmgr.add_quantity(self.flop_counter) def __getinitargs__(self): return (self.order, self.startup_stepper) def __call__(self, y, t, dt, rhs): if len(self.f_history) == 0: # insert IC self.f_history.append(rhs(t, y)) from hedge.tools import count_dofs self.dof_count = count_dofs(self.f_history[0]) if len(self.f_history) < len(self.coefficients): ynew = self.startup_stepper(y, t, dt, rhs) if len(self.f_history) == len(self.coefficients) - 1: # here's some memory we won't need any more del self.startup_stepper else: from operator import add sub_timer = self.timer.start_sub_timer() assert len(self.coefficients) == len(self.f_history) ynew = y + dt * reduce( add, (coeff * f for coeff, f in zip(self.coefficients, self.f_history))) self.f_history.pop() sub_timer.stop().submit() self.flop_counter.add( (2 + 2 * len(self.coefficients) - 1) * self.dof_count) self.f_history.insert(0, rhs(t + dt, ynew)) return ynew