Source code for pyro.compressible_sdc.simulation

"""The routines that implement the 4th-order compressible scheme,
using SDC time integration

"""

from pyro import compressible_fv4
from pyro.mesh import fv, patch
from pyro.util import msg


[docs] class Simulation(compressible_fv4.Simulation): """Drive the 4th-order compressible solver with SDC time integration""" def __init__(self, solver_name, problem_name, problem_func, rp, *, problem_finalize_func=None, problem_source_func=None, timers=None, data_class=fv.FV2d): super().__init__(solver_name, problem_name, problem_func, rp, problem_finalize_func=problem_finalize_func, problem_source_func=problem_source_func, timers=timers, data_class=data_class) self.n_nodes = 3 # Gauss-Lobotto temporal nodes self.n_iter = 4 # 4 SDC iterations for 4th order
[docs] def sdc_integral(self, m_start, m_end, As): """Compute the integral over the sources from m to m+1 with a Simpson's rule""" integral = self.cc_data.grid.scratch_array(nvar=self.ivars.nvar) if m_start == 0 and m_end == 1: for n in range(self.ivars.nvar): integral.v(n=n)[:, :] = self.dt/24.0 * (5.0*As[0].v(n=n) + 8.0*As[1].v(n=n) - As[2].v(n=n)) elif m_start == 1 and m_end == 2: for n in range(self.ivars.nvar): integral.v(n=n)[:, :] = self.dt/24.0 * (-As[0].v(n=n) + 8.0*As[1].v(n=n) + 5.0*As[2].v(n=n)) else: msg.fail("invalid quadrature range") return integral
[docs] def evolve(self): """ Evolve the equations of compressible hydrodynamics through a timestep dt. """ tm_evolve = self.tc.timer("evolve") tm_evolve.begin() myd = self.cc_data # we need the solution at 3 time points and at the old and # current iteration (except for m = 0 -- that doesn't change). # This copy will initialize the the solution at all time nodes # with the current (old) solution. U_kold = [] U_kold.append(patch.cell_center_data_clone(self.cc_data)) U_kold.append(patch.cell_center_data_clone(self.cc_data)) U_kold.append(patch.cell_center_data_clone(self.cc_data)) U_knew = [] U_knew.append(U_kold[0]) U_knew.append(patch.cell_center_data_clone(self.cc_data)) U_knew.append(patch.cell_center_data_clone(self.cc_data)) # we need the advective term at all time nodes at the old # iteration -- we'll compute this for the initial state # now A_kold = [] A_kold.append(self.substep(U_kold[0])) A_kold.append(A_kold[-1].copy()) A_kold.append(A_kold[-1].copy()) A_knew = [] for adv in A_kold: A_knew.append(adv.copy()) # loop over iterations for _ in range(self.n_iter): # loop over the time nodes and update for m in range(self.n_nodes): # update m to m+1 for knew # compute A(U_m^{k+1}) # note: for m = 0, the advective term doesn't change if m > 0: A_knew[m] = self.substep(U_knew[m]) # only do an update if we are not at the last node if m < self.n_nodes-1: # compute the integral over A at the old iteration integral = self.sdc_integral(m, m+1, A_kold) # and the final update for n in range(self.ivars.nvar): U_knew[m+1].data.v(n=n)[:, :] = U_knew[m].data.v(n=n) + \ 0.5*self.dt * (A_knew[m].v(n=n) - A_kold[m].v(n=n)) + integral.v(n=n) # fill ghost cells U_knew[m+1].fill_BC_all() # store the current iteration as the old iteration # node m = 0 data doesn't change for m in range(1, self.n_nodes): U_kold[m].data[:, :, :] = U_knew[m].data[:, :, :] A_kold[m][:, :, :] = A_knew[m][:, :, :] # store the new solution self.cc_data.data[:, :, :] = U_knew[-1].data[:, :, :] if self.particles is not None: self.particles.update_particles(self.dt) # increment the time myd.t += self.dt self.n += 1 tm_evolve.end()