MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
DgCartesianSolver< nDim, SysEqn > Class Template Reference

#include <dgcartesiansolver.h>

Inheritance diagram for DgCartesianSolver< nDim, SysEqn >:
[legend]
Collaboration diagram for DgCartesianSolver< nDim, SysEqn >:
[legend]

Classes

struct  CellData
 

Public Types

using Geom = Geometry< nDim >
 
using CartesianSolver = typename maia::CartesianSolver< nDim, DgCartesianSolver >
 
using Grid = typename CartesianSolver::Grid
 
using GridProxy = typename CartesianSolver::GridProxy
 
using Cell = typename maia::grid::tree::Tree< nDim >::Cell
 
- Public Types inherited from maia::CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >
using Grid = CartesianGrid< nDim >
 
using GridProxy = typename maia::grid::Proxy< nDim >
 
using Geom = Geometry< nDim >
 
using TreeProxy = maia::grid::tree::TreeProxy< nDim >
 
using Cell = maia::grid::tree::Cell
 

Public Member Functions

 DgCartesianSolver (const MInt solverId, GridProxy &gridProxy_, Geometry< nDim > &geometry_, const MPI_Comm comm)
 Constructor of the DG solver reads properties and allocates solver resources (as far as they are known at instantiation time). More...
 
 ~DgCartesianSolver () override
 Frees resources that were allocated in the constructor and that are not automatically released when the member variables are destroyed. More...
 
void run ()
 Main method to run this solver. More...
 
MInt getCurrentTimeStep () const override
 
void forceTimeStep (const MFloat dt)
 Force time step externally. More...
 
MFloat time () const override
 Return the time. More...
 
MInt noVariables () const override
 Return the number of variables. More...
 
void loadSampleVariables (MInt timeStep)
 
void getSampleVariables (MInt cellId, const MFloat *&vars)
 
void getSampleVariables (const MInt cellId, std::vector< MFloat > &)
 
void calculateHeatRelease ()
 
void getHeatRelease (MFloat *&heatRelease)
 
constexpr const Geomgeometry () const
 Access the solver's geometry. More...
 
const MFloata_coordinate (const MInt cellId, const MInt dim) const
 
MInt a_noCells () const
 
MInt a_hasNeighbor (const MInt cellId, const MInt dir) const
 
MInt a_level (const MInt) const
 
void initSolver () override
 Initialize the solver. More...
 
void finalizeInitSolver () override
 Finalization of the solver initialization. More...
 
void cleanUp () override
 Clean up after a simulation run. More...
 
void preTimeStep () override
 Perform pre-time-step operations, e.g. set new dt if required. More...
 
MBool solutionStep () override
 Perform one Runge-Kutta step/stage. More...
 
void postTimeStep ()
 Perform post-time-step operations, e.g. advance time, error analysis. More...
 
MBool solverConverged ()
 
void saveSolverSolution (const MBool forceOutput, const MBool finalTimeStep) override
 Save the solver solution, i.e. write solution files and sampling/slice output. More...
 
void writeRestartFile (const MBool writeRestart, const MBool writeBackup, const MString gridFileName, MInt *recalcIdTree) override
 Write a restart file. More...
 
MBool prepareRestart (MBool, MBool &) override
 Return true if the solver wants to write a restart file. More...
 
virtual void reIntAfterRestart (MBool)
 
void resizeGridMap ()
 Swap the given cells. More...
 
void swapProxy (const MInt cellId0, const MInt cellId1)
 Swap the given cells. More...
 
void prepareAdaptation () override
 prepare adaptation for split adaptation before the adaptation loop More...
 
void setSensors (std::vector< std::vector< MFloat > > &NotUsed(sensors), std::vector< MFloat > &NotUsed(sensorWeight), std::vector< std::bitset< 64 > > &NotUsed(sensorCellFlag), std::vector< MInt > &NotUsed(sensorSolverId)) override
 
void postAdaptation () override
 post adaptation for split adaptation within the adaptation loop More...
 
void finalizeAdaptation () override
 finalize adaptation for split sadptation after the adaptation loop More...
 
MBool step (const MFloat externalDt=-std::numeric_limits< MFloat >::infinity(), const MBool substep=false)
 Advance the solution by one time step. More...
 
MFloat calcTimeStep ()
 Calculate the next time step. More...
 
MInt getCellIdByIndex (const MInt index)
 Return cell id belonging to an element id/index. More...
 
MInt getIdAtPoint (const MFloat *point, const MBool globalUnique=false)
 Return the element id containing a given point. More...
 
void calcSamplingVarAtPoint (const MFloat *point, const MInt elementId, const MInt sampleVarId, MFloat *state, const MBool interpolate) override
 Calculate the state vector at a given point and for the specified sampling variable. More...
 
void getSolverSamplingProperties (std::vector< MInt > &samplingVarIds, std::vector< MInt > &noSamplingVars, std::vector< std::vector< MString > > &samplingVarNames, const MString featureName="") override
 Return sampling properties for the DG solver. More...
 
virtual void initSolverSamplingVariables (const std::vector< MInt > &NotUsed(varIds), const std::vector< MInt > &NotUsed(noSamplingVars))
 
virtual void initInterpolationForCell (const MInt NotUsed(cellId))
 
virtual void calcSamplingVariables (const std::vector< MInt > &NotUsed(varIds), const MBool NotUsed(exchange))
 
MInt noInternalCells () const override
 Return the number of internal cells within this solver. More...
 
void resetSolver () override
 Reset solver (for load balancing) More...
 
void setCellWeights (MFloat *solverCellWeight) override
 Set cell weights with constant weighting factor weightPerNode. More...
 
MInt noLoadTypes () const override
 Return the number of DG load types. More...
 
void getDefaultWeights (MFloat *weights, std::vector< MString > &names) const
 Return the default weights for all load quantities. More...
 
void getLoadQuantities (MInt *const loadQuantities) const override
 Return the cumulative load quantities on this domain. More...
 
MFloat getCellLoad (const MInt cellId, const MFloat *const weights) const override
 Return the load of a single cell (given computational weights). More...
 
void balance (const MInt *const NotUsed(noCellsToReceiveByDomain), const MInt *const NotUsed(noCellsToSendByDomain), const MInt *const NotUsed(targetDomainsByCell), const MInt NotUsed(oldNoCells)) override
 Perform load balancing. More...
 
MBool hasSplitBalancing () const override
 Return if load balancing for solver is split into multiple methods or implemented in balance() More...
 
void balancePre () override
 Reinitialize solver prior to setting solution data in DLB. More...
 
void balancePost () override
 Reinitialize solver after setting solution data. More...
 
void finalizeBalance () override
 
void localToGlobalIds () override
 Change local into global ids. More...
 
void globalToLocalIds () override
 Change global into local ids. More...
 
MInt noCellDataDlb () const override
 Methods to inquire solver data information. More...
 
MInt cellDataTypeDlb (const MInt dataId) const override
 Get data type of cell data. More...
 
MInt cellDataSizeDlb (const MInt dataId, const MInt cellId) override
 Return data size of cell data. More...
 
template<typename dataType >
void getCellDataDlb_ (const MInt dataId, const MInt oldNoCells, const MInt *const bufferIdToCellId, dataType *const data)
 
void getCellDataDlb (const MInt dataId, const MInt oldNoCells, const MInt *const bufferIdToCellId, MInt *const data) override
 
void getCellDataDlb (const MInt dataId, const MInt oldNoCells, const MInt *const bufferIdToCellId, MFloat *const data) override
 
template<typename dataType >
void setCellDataDlb_ (const MInt dataId, const dataType *const data)
 
void setCellDataDlb (const MInt dataId, const MInt *const data) override
 
void setCellDataDlb (const MInt dataId, const MFloat *const data) override
 
void getGlobalSolverVars (std::vector< MFloat > &NotUsed(globalFloatVars), std::vector< MInt > &NotUsed(globalIntVars)) override
 Get global solver variables that need to be communicated for DLB (same on each domain) More...
 
void setGlobalSolverVars (std::vector< MFloat > &NotUsed(globalFloatVars), std::vector< MInt > &NotUsed(globalIdVars)) override
 Set global solver variables for DLB (same on each domain) More...
 
MInt noSolverTimers (const MBool allTimings) override
 
void getSolverTimings (std::vector< std::pair< MString, MFloat > > &solverTimings, const MBool allTimings) override
 Get solver timings. More...
 
void getDomainDecompositionInformation (std::vector< std::pair< MString, MInt > > &domainInfo) override
 Return decomposition information, i.e. number of local elements,... More...
 
template<typename DataType >
void getCellDataDlb_ (const MInt dataId, const MInt oldNoCells, const MInt *const bufferIdToCellId, DataType *const data)
 Get solver cell (element) data for load balancing. More...
 
template<typename DataType >
void setCellDataDlb_ (const MInt dataId, const DataType *const data)
 Set solver cell (element) data. More...
 
- Public Member Functions inherited from maia::CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >
 CartesianSolver (const MInt solverId, GridProxy &gridProxy_, const MPI_Comm comm, const MBool checkActive=false)
 
MInt minLevel () const
 Read-only accessors for grid data. More...
 
MInt maxLevel () const
 
MInt maxNoGridCells () const
 
MInt maxRefinementLevel () const
 
MInt maxUniformRefinementLevel () const
 
MInt noNeighborDomains () const
 
MInt neighborDomain (const MInt id) const
 
MLong domainOffset (const MInt id) const
 
MInt noHaloLayers () const
 
MInt noHaloCells (const MInt domainId) const
 
MInt haloCellId (const MInt domainId, const MInt cellId) const
 
MInt noWindowCells (const MInt domainId) const
 
MInt windowCellId (const MInt domainId, const MInt cellId) const
 
MString gridInputFileName () const
 
MFloat reductionFactor () const
 
MFloat centerOfGravity (const MInt dir) const
 
MInt neighborList (const MInt cellId, const MInt dir) const
 
const MLonglocalPartitionCellGlobalIds (const MInt cellId) const
 
MLong localPartitionCellOffsets (const MInt index) const
 
MInt noMinCells () const
 
MInt minCell (const MInt id) const
 
const MInthaloCell (const MInt domainId, const MInt cellId) const
 
const MIntwindowCell (const MInt domainId, const MInt cellId) const
 
MBool isActive () const override
 
constexpr GridProxygrid () const
 
GridProxygrid ()
 
virtual void sensorDerivative (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorDivergence (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorTotalPressure (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorEntropyGrad (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorEntropyQuot (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorVorticity (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorInterface (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
void sensorLimit (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt, std::function< MFloat(MInt)>, const MFloat, const MInt *, const MBool, const MBool allowCoarsening=true)
 simple sensor to apply a limit for a value More...
 
void sensorSmooth (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 sensor to smooth level jumps NOTE: only refines additional cells to ensure a smooth level transition this requires that all other sensors are frozen i.e. no refine/coarse sensors set! More...
 
void sensorBand (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 This sensor generates a max refinement band around the cells with max refinement level. In order for it to work, the property addedAdaptationSteps has to be equal to /maxRefinementLevel() - minLevel()/. This sensor also ensures a smooth transition between levels. Do not use together with sensorSmooth. More...
 
virtual void sensorMeanStress (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorParticle (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorSpecies (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
virtual void sensorPatch (std::vector< std::vector< MFloat > > &sensor, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen)
 
virtual void sensorCutOff (std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
void saveSensorData (const std::vector< std::vector< MFloat > > &sensors, const MInt &level, const MString &gridFileName, const MInt *const recalcIds) override
 Saves all sensor values for debug/tunig purposes. More...
 
void assertValidGridCellId (const MInt) const
 
MLong c_parentId (const MInt cellId) const
 Returns the grid parent id of the cell cellId. More...
 
MLong c_neighborId (const MInt cellId, const MInt dir) const
 Returns the grid neighbor id of the grid cell cellId dir. More...
 
MInt c_noCells () const
 
MInt c_level (const MInt cellId) const
 
MLong c_globalGridId (const MInt cellId)
 
void exchangeData (T *data, const MInt dataBlockSize=1)
 Exchange memory in 'data' assuming a solver size of 'dataBlockSize' per cell. More...
 
void exchangeLeafData (std::function< T &(MInt, MInt)> data, const MInt noDat=1)
 Blocking exchange memory in 'data' assuming a solver size of 'dataBlockSize' per cell NOTE: exchange is only performed on leaf-cells and leaf-NeighborDomains Assumes, that updateLeafCellExchange has been called in the proxy previously! More...
 
void exchangeSparseLeafValues (G getData, S setData, const MInt dataSize, M cellMapping)
 Exchange of sparse data structures on max Level. More...
 
void exchangeAzimuthalPer (T *data, MInt dataBlockSize=1, MInt firstBlock=0)
 Exchange of sparse data structures on max Level. More...
 
void collectVariables (T *variablesIn, ScratchSpace< T > &variablesOut, const std::vector< MString > &variablesNameIn, std::vector< MString > &variablesNameOut, const MInt noVars, const MInt noCells, const MBool reverseOrder=false)
 generalised helper function for writing restart files! This is necessary for example if the minLevel shall be raised at the new restart! More...
 
void collectVariables (T **variablesIn, ScratchSpace< T > &variablesOut, const std::vector< MString > &variablesNameIn, std::vector< MString > &variablesNameOut, const MInt noVars, const MInt noCells)
 generalised helper function for writing restart files! This is necessary for example if the minLevel shall be raised at the new restart! More...
 
void saveGridFlowVars (const MChar *fileName, const MChar *gridFileName, const MInt noTotalCells, const MInt noInternal, MFloatScratchSpace &dbVariables, std::vector< MString > &dbVariablesName, MInt noDbVars, MIntScratchSpace &idVariables, std::vector< MString > &idVariablesName, MInt noIdVars, MFloatScratchSpace &dbParameters, std::vector< MString > &dbParametersName, MIntScratchSpace &idParameters, std::vector< MString > &idParametersName, MInt *recalcIds, MFloat time)
 This function writes the parallel Netcdf cartesian grid cell based solution/restart file currently used in PostData, LPT and LS solvers! More...
 
void collectParameters (T, ScratchSpace< T > &, const MChar *, std::vector< MString > &)
 This function collects a single parameters for the massivley parallel IO functions. More...
 
void calcRecalcCellIdsSolver (const MInt *const recalcIdsTree, MInt &noCells, MInt &noInternalCellIds, std::vector< MInt > &recalcCellIdsSolver, std::vector< MInt > &reorderedCellIds)
 Derive recalc cell ids of the solver and reordered cell ids. More...
 
- Public Member Functions inherited from Solver
MString getIdentifier (const MBool useSolverId=false, const MString preString="", const MString postString="_")
 
virtual ~Solver ()=default
 
virtual MInt noInternalCells () const =0
 Return the number of internal cells within this solver. More...
 
virtual MFloat time () const =0
 Return the time. More...
 
virtual MInt noVariables () const
 Return the number of variables. More...
 
virtual void getDimensionalizationParams (std::vector< std::pair< MFloat, MString > > &) const
 Return the dimensionalization parameters of this solver. More...
 
void updateDomainInfo (const MInt domainId, const MInt noDomains, const MPI_Comm mpiComm, const MString &loc)
 Set new domain information. More...
 
virtual MFloata_slope (const MInt, MInt const, const MInt)
 
virtual MBool a_isBndryCell (const MInt) const
 
virtual MFloata_FcellVolume (MInt)
 
virtual MInt getCurrentTimeStep () const
 
virtual void accessSampleVariables (MInt, MFloat *&)
 
virtual void getSampleVariableNames (std::vector< MString > &NotUsed(varNames))
 
virtual MBool a_isBndryGhostCell (MInt) const
 
virtual void saveCoarseSolution ()
 
virtual void getSolverSamplingProperties (std::vector< MInt > &NotUsed(samplingVarIds), std::vector< MInt > &NotUsed(noSamplingVars), std::vector< std::vector< MString > > &NotUsed(samplingVarNames), const MString NotUsed(featureName)="")
 
virtual void initSolverSamplingVariables (const std::vector< MInt > &NotUsed(varIds), const std::vector< MInt > &NotUsed(noSamplingVars))
 
virtual void calcSamplingVariables (const std::vector< MInt > &NotUsed(varIds), const MBool NotUsed(exchange))
 
virtual void calcSamplingVarAtPoint (const MFloat *NotUsed(point), const MInt NotUsed(id), const MInt NotUsed(sampleVarId), MFloat *NotUsed(state), const MBool NotUsed(interpolate)=false)
 
virtual void balance (const MInt *const NotUsed(noCellsToReceiveByDomain), const MInt *const NotUsed(noCellsToSendByDomain), const MInt *const NotUsed(targetDomainsByCell), const MInt NotUsed(oldNoCells))
 Perform load balancing. More...
 
virtual MBool hasSplitBalancing () const
 Return if load balancing for solver is split into multiple methods or implemented in balance() More...
 
virtual void balancePre ()
 
virtual void balancePost ()
 
virtual void finalizeBalance ()
 
virtual void resetSolver ()
 Reset the solver/solver for load balancing. More...
 
virtual void cancelMpiRequests ()
 Cancel open mpi (receive) requests in the solver (e.g. due to interleaved execution) More...
 
virtual void setCellWeights (MFloat *)
 Set cell weights. More...
 
virtual MInt noLoadTypes () const
 
virtual void getDefaultWeights (MFloat *NotUsed(weights), std::vector< MString > &NotUsed(names)) const
 
virtual void getLoadQuantities (MInt *const NotUsed(loadQuantities)) const
 
virtual MFloat getCellLoad (const MInt NotUsed(cellId), const MFloat *const NotUsed(weights)) const
 
virtual void limitWeights (MFloat *NotUsed(weights))
 
virtual void localToGlobalIds ()
 
virtual void globalToLocalIds ()
 
virtual MInt noCellDataDlb () const
 Methods to inquire solver data information. More...
 
virtual MInt cellDataTypeDlb (const MInt NotUsed(dataId)) const
 
virtual MInt cellDataSizeDlb (const MInt NotUsed(dataId), const MInt NotUsed(cellId))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MInt *const NotUsed(data))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MLong *const NotUsed(data))
 
virtual void getCellDataDlb (const MInt NotUsed(dataId), const MInt NotUsed(oldNoCells), const MInt *const NotUsed(bufferIdToCellId), MFloat *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MInt *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MLong *const NotUsed(data))
 
virtual void setCellDataDlb (const MInt NotUsed(dataId), const MFloat *const NotUsed(data))
 
virtual void getGlobalSolverVars (std::vector< MFloat > &NotUsed(globalFloatVars), std::vector< MInt > &NotUsed(globalIntVars))
 
virtual void setGlobalSolverVars (std::vector< MFloat > &NotUsed(globalFloatVars), std::vector< MInt > &NotUsed(globalIdVars))
 
void enableDlbTimers ()
 
void reEnableDlbTimers ()
 
void disableDlbTimers ()
 
MBool dlbTimersEnabled ()
 
void startLoadTimer (const MString name)
 
void stopLoadTimer (const MString &name)
 
void stopIdleTimer (const MString &name)
 
void startIdleTimer (const MString &name)
 
MBool isLoadTimerRunning ()
 
virtual MInt noSolverTimers (const MBool NotUsed(allTimings))
 
virtual void getSolverTimings (std::vector< std::pair< MString, MFloat > > &NotUsed(solverTimings), const MBool NotUsed(allTimings))
 
virtual void getDomainDecompositionInformation (std::vector< std::pair< MString, MInt > > &NotUsed(domainInfo))
 
void setDlbTimer (const MInt timerId)
 
virtual void prepareAdaptation (std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &)
 
virtual void reinitAfterAdaptation ()
 
virtual void prepareAdaptation ()
 prepare adaptation for split adaptation before the adaptation loop More...
 
virtual void setSensors (std::vector< std::vector< MFloat > > &, std::vector< MFloat > &, std::vector< std::bitset< 64 > > &, std::vector< MInt > &)
 set solver sensors for split adaptation within the adaptation loop More...
 
virtual void saveSensorData (const std::vector< std::vector< MFloat > > &, const MInt &, const MString &, const MInt *const)
 
virtual void postAdaptation ()
 post adaptation for split adaptation within the adaptation loop More...
 
virtual void finalizeAdaptation ()
 finalize adaptation for split sadptation after the adaptation loop More...
 
virtual void refineCell (const MInt)
 Refine the given cell. More...
 
virtual void removeChilds (const MInt)
 Coarsen the given cell. More...
 
virtual void removeCell (const MInt)
 Remove the given cell. More...
 
virtual void swapCells (const MInt, const MInt)
 Swap the given cells. More...
 
virtual void swapProxy (const MInt, const MInt)
 Swap the given cells. More...
 
virtual MInt cellOutside (const MFloat *, const MInt, const MInt)
 Check whether cell is outside the fluid domain. More...
 
virtual void resizeGridMap ()
 Swap the given cells. More...
 
virtual MBool prepareRestart (MBool, MBool &)
 Prepare the solvers for a grid-restart. More...
 
virtual void reIntAfterRestart (MBool)
 
MPI_Comm mpiComm () const
 Return the MPI communicator used by this solver. More...
 
virtual MInt domainId () const
 Return the domainId (rank) More...
 
virtual MInt noDomains () const
 
virtual MBool isActive () const
 
void setSolverStatus (const MBool status)
 
MBool getSolverStatus ()
 Get the solver status indicating if the solver is currently active in the execution recipe. More...
 
MString testcaseDir () const
 Return the testcase directory. More...
 
MString outputDir () const
 Return the directory for output files. More...
 
MString restartDir () const
 Return the directory for restart files. More...
 
MString solverMethod () const
 Return the solverMethod of this solver. More...
 
MString solverType () const
 Return the solverType of this solver. More...
 
MInt restartInterval () const
 Return the restart interval of this solver. More...
 
MInt restartTimeStep () const
 Return the restart interval of this solver. More...
 
MInt solverId () const
 Return the solverId. More...
 
MBool restartFile ()
 
MInt readSolverSamplingVarNames (std::vector< MString > &varNames, const MString featureName="") const
 Read sampling variables names, store in vector and return the number of sampling variables. More...
 
virtual MBool hasRestartTimeStep () const
 
virtual MBool forceAdaptation ()
 
virtual void preTimeStep ()=0
 
virtual void postTimeStep ()=0
 
virtual void initSolver ()=0
 
virtual void finalizeInitSolver ()=0
 
virtual void saveSolverSolution (const MBool NotUsed(forceOutput)=false, const MBool NotUsed(finalTimeStep)=false)=0
 
virtual void cleanUp ()=0
 
virtual MBool solutionStep ()
 
virtual void preSolutionStep (MInt)
 
virtual MBool postSolutionStep ()
 
virtual MBool solverConverged ()
 
virtual void getInterpolatedVariables (MInt, const MFloat *, MFloat *)
 
virtual void loadRestartFile ()
 
virtual MInt determineRestartTimeStep () const
 
virtual void writeRestartFile (MBool)
 
virtual void writeRestartFile (const MBool, const MBool, const MString, MInt *)
 
virtual void setTimeStep ()
 
virtual void implicitTimeStep ()
 
virtual void prepareNextTimeStep ()
 

Private Types

using ElementCollector = maia::dg::collector::ElementCollector< nDim, SysEqn >
 
using HElementCollector = maia::dg::collector::HElementCollector< nDim, SysEqn >
 
using SurfaceCollector = maia::dg::collector::SurfaceCollector< nDim, SysEqn >
 
using Timers = maia::dg::Timers_
 
using BC = typename DgBoundaryConditionFactory< nDim, SysEqn >::ReturnType
 

Private Member Functions

Geomgeometry ()
 Access the solver's geometry (non-const version) More...
 
void initDgCartesianSolver ()
 Initializes basic properties of the solver. More...
 
void initTimers ()
 Initialize all solver-wide timers and start the solver timer. More...
 
void setNumericalProperties ()
 Reads properties associated with the numerical method. More...
 
void setInputOutputProperties ()
 
void allocateAndInitSolverMemory ()
 Allocates main memory resources. More...
 
void initGridMap ()
 Determine grid-to-grid mapping. More...
 
void loadGridMap (const MString &gridMapFileName)
 Load previously created grid map. More...
 
void checkGridMap (const MString &donorGridFileName)
 Perform some sanity checks on loaded grid map. More...
 
void initElements ()
 Initialize all elements by iterating over all cells and creating an element for each internal leaf cell. More...
 
MBool needElementForCell (const MInt cellId)
 Return true if element is needed for cell, false otherwise. More...
 
MInt calculateNeededNoSurfaces ()
 Determine the number of surfaces that need to be created on this domain. More...
 
MBool pointIsInside (const MFloat *const coordinates)
 Check if point is inside the computational domain. More...
 
void createElement (const MInt cellId)
 Create element for cell with id cellId. More...
 
void initPolynomialDegree ()
 Calculate and set initial polynomial degree and number of nodes in all elements. More...
 
void initInterpolation ()
 Calculates necessary coefficients for interpolation and stores them once for the whole solver. More...
 
void initNodeCoordinates ()
 Calculates the coordinates of the integration nodes within each element. More...
 
void initJacobian ()
 Calculates the inverse Jacobian for each element. More...
 
void checkCellProperties ()
 Check all relevant bit properties in the cells. More...
 
std::array< MInt, 2 *nDim > getBoundaryConditionIds (const MInt cellId)
 Determine if element is boundary is cut by geometry elements and return corresponding boundary condition ids. More...
 
void initSurfaces ()
 Create for all elements and directions surfaces if necessary. More...
 
MInt initBoundarySurface (const MInt elementId, const MInt dir)
 Check if the surface of the element in the given direction is a boundary surface. If it is init, a boundary surface. More...
 
MInt initInnerSurface (const MInt elementId, const MInt dir)
 Check if the surface of the element in the given direction is an inner surface without h/p-refinement. If it is, init an inner surface. More...
 
MInt initMpiSurface (const MInt elementId, const MInt dir)
 Check if the surface of the element in the given direction is a MPI surface. If it is, init a MPI surface. More...
 
MBool hasSurface (const MInt elementId, const MInt dir)
 Check if a surface exists for the element in the given direction. More...
 
MInt createSurface (const MInt elementId, const MInt dir, MInt nghbrId=-1)
 
void calcSurfaceNodeCoordinates (const MInt surfaceId)
 
void calcElementNodeCoordinates (const MInt elementId)
 Calculates the coordinates of the integration nodes within the element. More...
 
void initMpiExchange ()
 
void updateNodeVariables ()
 Update all node variables at the surfaces. More...
 
void extendNodeVariables ()
 Extends nodeVars from given planes to given directions. More...
 
void extendNodeVariablesSingleDirection (const MInt extendDir, const MFloat extendOffset, const MFloat extendLimit)
 Set nodeVars upstream of given plane to values of elements in plane. More...
 
void updateNodeVariablesSingleElement (const MInt elementId, const MInt extendDir, MIntTensor hForwardSurfaceId, MIntTensor hReverseSurfaceId, std::vector< MBool > &cellHasUpdatedMeans, std::vector< MInt > &SurfaceWantsToMPISend, MBool &noMoreUpdates)
 Sets nodeVars of an element to values on the surface opposite to extendDir. More...
 
void initSimulationStatistics ()
 
void initSolverObjects ()
 Initializes the solver. This must be called before using any of the discretization methods, and should be followed (after the simulation run) by a call to cleanUp(). More...
 
void initData ()
 Initialize solver data, i.e. set initial conditions or load restart file. More...
 
void initMainLoop ()
 Perform all operations that prepare the execution of the main loop. More...
 
MInt getLevelByElementId (const MInt elementId)
 
MInt getLevelOfDirectNeighborCell (const MInt cellId, const MInt dir)
 
MBool hasNeighborCell (const MInt elementId, const MInt dir)
 
MBool isMpiSurface (const MInt id) const
 Return true if a surface is a MPI surface. More...
 
void updateWeightsAndWorkloads ()
 
void savePartitionCellWorkloads ()
 
void writeEOC ()
 
MInt getHElementId (const MInt elementId) const
 Return h-element id of a given element (if it exists). More...
 
void finalizeMpiExchange ()
 
virtual void initialCondition ()
 Set the initial condition in all elements. More...
 
void outputInitSummary ()
 Print initialization summary to user and m_log. More...
 
void saveSolutionFile ()
 Saves all available data to disk. More...
 
void saveSolutionFile (const MString &suffix)
 Saves all available data to disk. More...
 
virtual void saveRestartFile ()
 Saves a file to disk with all information that is necessary to restart the calculations from here. More...
 
void loadRestartFile () override
 Load restart file with all information that is necessary to restart the calculations from here. More...
 
void saveNodalData (const MString &fileNameBase, const MInt noVars, const std::vector< MString > &varNames, const MFloat *const data) const
 Save nodal data to file. More...
 
void saveNodeVarsFile ()
 Save node variables to file. More...
 
void loadNodeVarsFile ()
 Load node variables from file. More...
 
MString getRestartFileName (const MInt timeStep, const MInt useNonSpecifiedRestartFile)
 Return name of a restart file for the given time step. More...
 
BC make_bc (MInt bcId)
 
void calcDgTimeDerivative (const MFloat t, const MFloat tStage)
 Main routine to calculate the discontinuous Galerkin time derivative. After this method was called, m_rightHandSide contains the time derivative of the conservative variables at the integration points. More...
 
void prolongToSurfaces ()
 Extrapolate the solution from inside the elements to the surfaces. More...
 
void prolongToSurfaces (const MInt begin, const MInt end)
 Extrapolate the solution in the given range of elements from the elements to the surfaces. More...
 
void applyForwardProjection ()
 
void calcVolumeIntegral ()
 Calculate the volume integral for all elements and update m_rightHandSide. More...
 
template<class F >
void calcVolumeIntegral (const MInt noElements, ElementCollector &elem, F &fluxFct)
 Calculate the volume integral for all elements and update m_rightHandSide. More...
 
void calcBoundarySurfaceFlux (MFloat t)
 Calculate the numerical flux on the boundary surfaces and update m_flux. More...
 
void calcInnerSurfaceFlux ()
 Calculate the numerical flux on the internal surfaces and update m_flux. More...
 
void calcMpiSurfaceFlux ()
 Calculate the numerical flux on the MPI surfaces and update m_flux. More...
 
template<class F >
void calcRegularSurfaceFlux (const MInt begin, const MInt end, SurfaceCollector &surf, F &riemannFct)
 Calculate the numerical flux for a regular (i.e. inner or MPI) surface. More...
 
void calcSurfaceIntegral ()
 Calculate the surface integral for all faces of element and update dU/dt. More...
 
void calcSurfaceIntegral (const MInt begin, const MInt end, ElementCollector &elem, SurfaceCollector &surf, HElementCollector &helem, const MInt noHElements)
 Calculate the surface integral for all faces of each element and update dU/dt. More...
 
void applySurfaceIntegral (MFloat *rhs, const MInt polyDeg, const MInt noNodes1D, const MInt srfcId, const MInt side, const MFloat *flux, SurfaceCollector &surf)
 Calculate the surface integral for a face of an element and update dU/dt. More...
 
void applyJacobian ()
 Adds the negative of the inverse Jacobian to the time derivative. More...
 
void applyJacobian (const MInt noElements, ElementCollector &elem)
 Adds the negative of the inverse Jacobian to the time derivative. More...
 
void calcSourceTerms (MFloat t)
 Calculates the source terms for each node and adds them to the time derivative of the conservative variables. More...
 
template<class F >
void calcSourceTerms (MFloat t, const MInt noElements, ElementCollector &elem, F &sourceFct)
 Calculates the source terms for each node and adds them to the time derivative of the conservative variables. More...
 
void applyExternalSourceTerms (const MFloat time)
 Add the external coupling source terms to the right hand side. More...
 
MBool isMpiRoot () const
 Return true if this is the root rank of the solver MPI communicator. More...
 
MBool hasMpiExchange () const
 
void startMpiSurfaceExchange ()
 Start sending the window-side data and start receiving the halo-side data for all MPI surfaces. More...
 
void finishMpiSurfaceExchange ()
 Finish sending the window-side data and finish receiving the halo-side data for all MPI surfaces. More...
 
void cancelMpiRequests () override
 Cancel open MPI (receive) requests. More...
 
void timeStepRk (const MFloat t, const MFloat dt, const MInt substep=-1)
 Time integration using the five-stage fourth-order low-storage Runge-Kutta scheme as described in the book by Hesthaven and Warburton (2008), p. 64, Eqn. 3.5. More...
 
void subTimeStepRk (const MFloat dt, const MInt stage, const MInt totalSize, const MFloat *const rhs, MFloat *const variables, MFloat *const timeIntStorage)
 Perform one Runge-Kutta substep on the given elements. More...
 
void analyzeTimeStep (MFloat t, MFloat runTimeRelative, MFloat runTimeTotal, MInt timeStep, MFloat dt)
 Calculates and prints the L^2 and L^inf errors (using calcErrorNorms()) for the current time. More...
 
void calcErrorNorms (const MFloat t, std::vector< MFloat > &L2Error, std::vector< MFloat > &LInfError, std::vector< MFloat > &L2ErrLocal, std::vector< MFloat > &LInfErrLocal)
 Calculate the L^2 and L^infinity error norms at a given time. The error is calculated in comparison to the initial condition. More...
 
virtual void resetRHS ()
 Reset the time derivative of the conservative variables to zero. More...
 
void resetExternalSources ()
 
void resetBuffer (const MInt totalSize, MFloat *const buffer)
 Reset the given buffer to zero. More...
 
MInt getElementIdAtPoint (const MFloat *point, MBool globalUnique=false)
 returns the elementId of a element containing a given point More...
 
MBool calcStateAtPoint (const MFloat *point, MFloat *state)
 returns the cellId of a cell containing a given point More...
 
void calcStateAtPoint (const MFloat *point, const MInt elementId, MFloat *state)
 Calculate the node variables at a given point in an element. More...
 
void calcStateAtPoint (const MFloat *point, const MInt elementId, const MInt noVars, const MFloat *const u, MFloat *state)
 Calculates the state vector at a given Point. More...
 
DgSponge< nDim, SysEqn > & sponge ()
 
MBool useSponge () const
 
void initMortarProjections ()
 Calculate all necessary mortar projection matrices. More...
 
void initPrefinement ()
 Set polynomial degree for static p-refinement case. More...
 
template<MBool forward, MInt noVars>
void calcMortarProjectionH (const MInt srfcId, const MInt dir, MFloat *source, MFloat *destination, ElementCollector &elem, SurfaceCollector &surf)
 Calculate the h-refinement mortar projection. More...
 
template<MBool forward, MInt noVars>
void calcMortarProjectionP (const MInt srfcId, const MInt dir, MFloat *source, MFloat *destination, ElementCollector &elem, SurfaceCollector &surf)
 Calculate the p-refinement mortar projection. More...
 
template<MBool forward, MInt noVars>
void calcMortarProjection (const MInt srfcId, const MInt dir, MFloat *source, MFloat *destination, ElementCollector &elem, SurfaceCollector &surf)
 
template<MBool forward>
MFloatmortarP (const MInt sourcePolyDeg, const MInt targetPolyDeg)
 
template<MBool forward>
MFloatmortarH (const MInt polyDeg, const MInt position)
 
void exchangeMpiSurfacePolyDeg ()
 
void adaptiveRefinement (const MInt timeStep)
 Apply adaptive refinement (right now: only p-refinement) More...
 
void calcErrorEstimate (std::vector< MFloat > &errorEstimate)
 Calculate error estimate for adaptive hp-refinement. More...
 
void interpolateElement (const MInt elementId, const MInt newPolyDeg)
 Interpolate an element to a different polynomial degree. More...
 
MBool hasAdaptivePref () const
 Return true if adaptive hp-refinement is activated. More...
 
MBool needHElementForCell (const MInt cellId)
 Return true if h-element is needed for cell, false otherwise. More...
 
void createHElement (const MInt cellId)
 Create h-element for cell with id cellId. More...
 
void initHElements ()
 Initialize all helements by iterating over all cells and creating an element for each coarse cell in a h-refined grid. More...
 
MInt createHMPISurfaces (const MInt elementId, const MInt dir)
 
MBool hasPref () const
 Return true if p-refinement is set. More...
 
MBool isAdaptationTimeStep (const MInt timeStep) const
 Return if the given timestep is an adaptation timestep. More...
 
MInt noDgCartesianSolverCellData () const
 
MInt noBcSolverCellData () const
 

Private Attributes

Geomm_geometry
 Reference to geometry object. More...
 
MBool m_weightDgRbcElements = false
 
MInt m_loadBalancingReinitStage = -1
 
MInt m_timeStep = -1
 
MInt m_timeSteps = -1
 
MBool m_firstTimeStep = false
 
MInt m_calcTimeStepInterval = -1
 
MInt m_rkStage = -1
 
MInt m_noRkStages = -1
 
std::vector< MFloatm_timeIntegrationCoefficientsA {}
 
std::vector< MFloatm_timeIntegrationCoefficientsB {}
 
std::vector< MFloatm_timeIntegrationCoefficientsC {}
 
MBool m_mpiRecvRequestsOpen = false
 
MBool m_mpiSendRequestsOpen = false
 
MBool m_sbpMode = false
 
MString m_sbpOperator = ""
 
MInt m_initPolyDeg = -1
 
MInt m_minPolyDeg = -1
 
MInt m_maxPolyDeg = -1
 
MInt m_initNoNodes1D = -1
 
MInt m_minNoNodes1D = -1
 
MInt m_maxNoNodes1D = -1
 
MInt m_dgIntegrationMethod = -1
 
MInt m_dgTimeIntegrationScheme = -1
 
MInt m_dgPolynomialType = -1
 
MFloat m_startTime = 0.0
 
MFloat m_finalTime = 0.0
 
MBool m_finalTimeStep = false
 
MFloat m_cfl = 1.0
 
std::vector< std::vector< DgInterpolation > > m_interpolation {}
 
MFloat m_globalVolume = -1.0
 
MFloat m_localVolume = -1.0
 
MBool m_calcErrorNorms = true
 
MInt m_analysisInterval = -1
 
MInt m_noAnalysisNodes = -1
 
MInt m_polyDegAnalysis = -1
 
MInt m_noErrorDigits = -1
 
DgInterpolation m_interpAnalysis {}
 
MFloatTensor m_wVolumeAnalysis {}
 
std::vector< std::vector< MFloatTensor > > m_vdmAnalysis {}
 
MInt m_noExchangeNghbrDomains = -1
 
std::vector< MIntm_exchangeNghbrDomains {}
 
std::vector< std::vector< MInt > > m_mpiSurfaces {}
 
std::vector< std::vector< MInt > > m_mpiRecvSurfaces {}
 
std::vector< std::vector< MFloat > > m_sendBuffers {}
 
std::vector< std::vector< MFloat > > m_recvBuffers {}
 
std::vector< MPI_Datatype > m_sendTypes {}
 
std::vector< MPI_Datatype > m_recvTypes {}
 
std::vector< MPI_Request > m_sendRequests {}
 
std::vector< MPI_Request > m_recvRequests {}
 
MBool m_alwaysSaveFinalSolution = true
 
MBool m_alwaysSaveFinalRestart = true
 
MBool m_saveNodeVariablesToSolutionFile = false
 
MBool m_writeTimeDerivative = false
 
MBool m_writeSpongeEta = false
 
MInt m_noMinutesEndAutoSave = 0
 
MInt m_endAutoSaveCheckInterval = 0
 
MBool m_updateCellWeights = false
 
MFloat m_weightPerNode = 1.0
 
MFloat m_weightPerElement = 0.0
 
MFloat m_weightPerCell = 0.0
 
MBool m_restoreDefaultWeights = false
 
MBool m_writeInitialSolution = true
 
MBool m_writeNodeVarsFile = true
 
PointData< nDim, DgCartesianSolver< nDim, SysEqn > > m_pointData {*this}
 
SurfaceData< nDim, DgCartesianSolver< nDim, SysEqn > > m_surfaceData {*this}
 
VolumeData< nDim, DgCartesianSolver< nDim, SysEqn > > m_volumeData {*this}
 
DgSlices< nDim, SysEqn > m_slice {*this}
 
std::vector< maia::dg::GridMapOffsetm_gridMapOffsets {}
 
MInt m_maxNoGridMapOffsets = -1
 
DgSponge< nDim, SysEqn > m_sponge {-1, MPI_COMM_NULL}
 
MBool m_useSponge = false
 
MInt m_pref = -1
 
MInt m_adaptivePref = -1
 
MFloat m_adaptiveThreshold = -1
 
MInt m_adaptiveInterval = -1
 
std::vector< MFloat * > m_projectionMatrixPointersH {}
 
std::vector< MFloatm_projectionMatricesH {}
 
std::vector< MFloat * > m_projectionMatrixPointersP {}
 
std::vector< MFloatm_projectionMatricesP {}
 
HElementCollector m_helements
 
std::vector< std::array< MFloat, 2 *nDim > > m_prefPatchesCoords {}
 
std::vector< MFloatm_prefPatchesPolyDeg {}
 
std::vector< MStringm_prefPatchesOperators {}
 
std::vector< MIntm_prefPatchesNoNodes1D {}
 
GeometryIntersection< nDim > * m_geometryIntersection = nullptr
 
SysEqn m_sysEqn
 
DgBoundaryConditionFactory< nDim, SysEqn > m_boundaryConditionFactory {*this}
 
std::vector< BCm_boundaryConditions {}
 
MBool m_useCutOffBoundaries = false
 
std::array< MInt, 2 *nDim > m_cutOffBoundaryConditionIds {}
 
std::array< MInt, 2 *nDim > m_noCutOffBoundarySurfaces {}
 
MBool m_useSourceRampUp = false
 
MFloat m_sourceRampUpTime = 0.0
 
MInt m_maxNoSurfaces = -1
 
MInt m_internalDataSize = -1
 
MInt m_noTotalNodesXD = -1
 
ElementCollector m_elements
 
SurfaceCollector m_surfaces
 
MInt m_noBoundarySurfaces = -1
 
MInt m_noInnerSurfaces = -1
 
MInt m_noMpiSurfaces = -1
 
MInt m_innerSurfacesOffset = -1
 
MInt m_mpiSurfacesOffset = -1
 
MFloat m_time = 0.0
 
MFloat m_dt = -1.0
 
MFloat m_externalDt = -1.0
 
MInt m_statLocalMinPolyDeg = -1
 
MInt m_statLocalMaxPolyDeg = -1
 
MInt m_statLocalMinLevel = -1
 
MInt m_statLocalMaxLevel = -1
 
MInt m_statLocalNoCells = -1
 
MInt m_statLocalNoInternalCells = -1
 
MInt m_statLocalNoHaloCells = -1
 
MInt m_statLocalMaxNoCells = -1
 
MInt m_statLocalNoElements = -1
 
MInt m_statLocalNoHElements = -1
 
MInt m_statLocalNoSurfaces = -1
 
MInt m_statLocalNoBoundarySurfaces = -1
 
MInt m_statLocalNoInnerSurfaces = -1
 
MInt m_statLocalNoMpiSurfaces = -1
 
MInt m_statLocalMaxNoSurfaces = -1
 
MInt m_statLocalNoActiveCells = -1
 
MInt m_statLocalNoActiveDOFs = -1
 
std::vector< MIntm_statLocalNoActiveDOFsPolyDeg {}
 
MInt m_statLocalPolyDegSum = -1
 
MInt m_statLocalNoHrefSurfs = -1
 
MInt m_statLocalNoPrefSurfs = -1
 
MInt m_statGlobalMinPolyDeg = -1
 
MInt m_statGlobalMaxPolyDeg = -1
 
MInt m_statGlobalMinLevel = -1
 
MInt m_statGlobalMaxLevel = -1
 
MLong m_statGlobalNoCells = -1
 
MLong m_statGlobalNoInternalCells = -1
 
MLong m_statGlobalNoHaloCells = -1
 
MLong m_statGlobalMaxNoCells = -1
 
MLong m_statGlobalNoElements = -1
 
MLong m_statGlobalNoSurfaces = -1
 
MLong m_statGlobalNoBoundarySurfaces = -1
 
MLong m_statGlobalNoInnerSurfaces = -1
 
MLong m_statGlobalNoMpiSurfaces = -1
 
MLong m_statGlobalMaxNoSurfaces = -1
 
MLong m_statGlobalNoActiveCells = -1
 
MLong m_statGlobalNoActiveDOFs = -1
 
MInt m_statGlobalPolyDegSum = -1
 
MLong m_statGlobalNoHrefSurfs = -1
 
MLong m_statGlobalNoPrefSurfs = -1
 
MLong m_statGlobalNoHElements = -1
 
std::array< MLong, 6 > m_statGlobalNoCutOffBoundarySurfaces {}
 
MInt m_timerGroup = -1
 
std::array< MInt, Timers::_countm_timers {}
 
MBool m_isInitTimers = false
 
MBool m_isInitSolver = false
 
MBool m_isInitData = false
 
MBool m_isInitMainLoop = false
 
MBool m_isInitMpiExchange = false
 
MInt m_noAnalyzeTimeSteps = -1
 
MFloat m_analyzeTimeStart = 0.0
 
MFloat m_loopTimeStart = 0.0
 
std::time_t m_endAutoSaveTime = -1
 
MBool m_endAutoSaveWritten = false
 
MFloat m_outputTime = 0.0
 

Static Private Attributes

static const std::array< MInt, CellData::counts_cellDataTypeDlb = {{MINT, MINT, MINT, MFLOAT, MFLOAT}}
 

Friends

class DgBoundaryCondition< nDim, SysEqn >
 
template<MInt nDim_, class CouplingX >
class CouplingDgApe
 
class DgCcAcousticPerturb< nDim, SysEqn >
 
class CouplingDg< nDim, SysEqn >
 
class DgSlices< nDim, SysEqn >
 
class maia::CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >
 
template<MInt nDim_, class ppType >
class PostProcessing
 

Additional Inherited Members

- Public Attributes inherited from Solver
std::set< MIntm_freeIndices
 
MBool m_singleAdaptation = false
 
MBool m_splitAdaptation = true
 
MBool m_saveSensorData = false
 
- Protected Types inherited from maia::CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >
using fun = void(CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >::*)(std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt)
 
- Protected Member Functions inherited from maia::CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >
void identifyBoundaryCells (MBool *const isInterface, const std::vector< MInt > &bndCndIds=std::vector< MInt >())
 
void identifyBoundaryCells ()
 
MBool cellIsOnGeometry (MInt cellId, Geometry< nDim > *geom)
 checks whether a cell lies on a certain geometry copied the essential part from identifyBoundaryCells More...
 
void setBoundaryDistance (const MBool *const interfaceCell, const MFloat *const outerBandWidth, MFloatScratchSpace &distance)
 transverses over all neighboring cells for a specified length More...
 
void markSurrndCells (MIntScratchSpace &inList, const MInt bandWidth, const MInt level, const MBool refineDiagonals=true)
 
void receiveWindowTriangles ()
 Receives triangles from neighbors contained in their window cells and inserts them locally. More...
 
void compactCells ()
 Removes all holes in the cell collector and moves halo cells to the back of the collector. More...
 
MInt createCellId (const MInt gridCellId)
 
void removeCellId (const MInt cellId)
 
MInt inCell (const MInt cellId, MFloat *point, MFloat fac=F1)
 
MInt setUpInterpolationStencil (const MInt cellId, MInt *, const MFloat *, std::function< MBool(MInt, MInt)>, MBool allowIncompleteStencil)
 
MFloat interpolateFieldData (MInt *, MFloat *, MInt varId, std::function< MFloat(MInt, MInt)> scalarField, std::function< MFloat(MInt, MInt)> coordinate)
 
MFloat leastSquaresInterpolation (MInt *, MFloat *, MInt varId, std::function< MFloat(MInt, MInt)> scalarField, std::function< MFloat(MInt, MInt)> coordinate)
 
void checkNoHaloLayers ()
 check that each solver has the required number of haloLayers for leaf cells!!! TODO labels:toenhance under production, needs to be cleaned up! More...
 
void mapInterpolationCells (std::map< MInt, MInt > &cellMap)
 
void setHaloCellsOnInactiveRanks ()
 
void patchRefinement (std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen)
 
void reOrderCellIds (std::vector< MInt > &reOrderedCells)
 reOrder cellIds before writing the restart file! This is necessary for example if the minLevel shall be raised at the new restart! More...
 
void recomputeGlobalIds (std::vector< MInt > &, std::vector< MLong > &)
 reOrder cellIds before writing the restart file! This is necessary for example if the minLevel shall be raised at the new restart! More...
 
void extractPointIdsFromGrid (Collector< PointBasedCell< nDim > > *&, Collector< CartesianGridPoint< nDim > > *&, const MBool, const std::map< MInt, MInt > &, MInt levelThreshold=999999, MFloat *bBox=nullptr, MBool levelSetMb=false) const
 Creates a list of unique corner points for all cells using a hash map levelThreshold optionally specifies the maximum cell level to be extracted bBox optionally specifies a bounding to box to which the extracted domain shall be truncated. More...
 
- Protected Member Functions inherited from Solver
 Solver (const MInt solverId, const MPI_Comm comm, const MBool isActive=true)
 
MFloat returnLoadRecord () const
 
MFloat returnIdleRecord () const
 
- Protected Attributes inherited from maia::CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >
MIntm_rfnBandWidth
 
MInt m_noSensors
 
MInt m_adaptationInterval
 
MInt m_adaptationStep
 
std::vector< MIntm_maxSensorRefinementLevel
 
std::vector< MFloatm_sensorWeight
 
std::vector< MFloatm_sensorDerivativeVariables
 
MBool m_adaptation
 
MBool m_adapts
 
MInt m_noInitialSensors
 
MBool m_resTriggeredAdapt
 
MInt m_noSmoothingLayers
 
MInt m_sensorBandAdditionalLayers
 
MBool m_sensorInterface
 
MBool m_sensorParticle
 
std::vector< MStringm_sensorType
 
MIntm_recalcIds
 
std::vector< funm_sensorFnPtr
 
MInt m_maxNoSets
 
std::vector< MFloatm_azimuthalCartRecCoord
 
const MInt m_revDir [6]
 
const MInt m_noDirs
 
- Protected Attributes inherited from Solver
MFloat m_Re {}
 the Reynolds number More...
 
MFloat m_Ma {}
 the Mach number More...
 
MInt m_solutionInterval
 The number of timesteps before writing the next solution file. More...
 
MInt m_solutionOffset {}
 
std::set< MIntm_solutionTimeSteps
 
MInt m_restartInterval
 The number of timesteps before writing the next restart file. More...
 
MInt m_restartTimeStep
 
MInt m_restartOffset
 
MString m_solutionOutput
 
MBool m_useNonSpecifiedRestartFile = false
 
MBool m_initFromRestartFile
 
MInt m_residualInterval
 The number of timesteps before writing the next residual. More...
 
const MInt m_solverId
 a unique solver identifier More...
 
MFloatm_outerBandWidth = nullptr
 
MFloatm_innerBandWidth = nullptr
 
MIntm_bandWidth = nullptr
 
MBool m_restart = false
 
MBool m_restartFile = false
 

Detailed Description

template<MInt nDim, class SysEqn>
class DgCartesianSolver< nDim, SysEqn >

Definition at line 44 of file dgcartesiansolver.h.

Member Typedef Documentation

◆ BC

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::BC = typename DgBoundaryConditionFactory<nDim, SysEqn>::ReturnType
private

Definition at line 61 of file dgcartesiansolver.h.

◆ CartesianSolver

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::CartesianSolver = typename maia::CartesianSolver<nDim, DgCartesianSolver>

Definition at line 65 of file dgcartesiansolver.h.

◆ Cell

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::Cell = typename maia::grid::tree::Tree<nDim>::Cell

Definition at line 93 of file dgcartesiansolver.h.

◆ ElementCollector

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::ElementCollector = maia::dg::collector::ElementCollector<nDim, SysEqn>
private

Definition at line 57 of file dgcartesiansolver.h.

◆ Geom

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::Geom = Geometry<nDim>

Definition at line 64 of file dgcartesiansolver.h.

◆ Grid

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::Grid = typename CartesianSolver::Grid

Definition at line 66 of file dgcartesiansolver.h.

◆ GridProxy

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::GridProxy = typename CartesianSolver::GridProxy

Definition at line 67 of file dgcartesiansolver.h.

◆ HElementCollector

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::HElementCollector = maia::dg::collector::HElementCollector<nDim, SysEqn>
private

Definition at line 58 of file dgcartesiansolver.h.

◆ SurfaceCollector

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::SurfaceCollector = maia::dg::collector::SurfaceCollector<nDim, SysEqn>
private

Definition at line 59 of file dgcartesiansolver.h.

◆ Timers

template<MInt nDim, class SysEqn >
using DgCartesianSolver< nDim, SysEqn >::Timers = maia::dg::Timers_
private

Definition at line 60 of file dgcartesiansolver.h.

Constructor & Destructor Documentation

◆ DgCartesianSolver()

template<MInt nDim, class SysEqn >
DgCartesianSolver< nDim, SysEqn >::DgCartesianSolver ( const MInt  solverId,
GridProxy gridProxy_,
Geometry< nDim > &  geometry_,
const MPI_Comm  comm 
)
Author
Michael Schlottke
Date
October 2012

The constructor does NOT prepare the solver for starting a simulation, however. You need to call initSolverObjects() to set up all necessary methods/data structures when you want to run a simulation.

Definition at line 51 of file dgcartesiansolver.cpp.

53 : maia::CartesianSolver<nDim, DgCartesianSolver<nDim, SysEqn>>(solverId_, gridProxy_, comm, true),
54 m_geometry(geometry_),
55 m_sponge(solverId_, comm),
56 m_sysEqn(solverId_) {
57 TRACE();
58
59 // Store currently used memory
60 const MLong previouslyAllocated = allocatedBytes();
61
62 // Initialize all solver-wide timers
63 initTimers();
64
65 // Initialize basic properties
67
68 // Input/output
70
71 // Numerical method
73
74 // Allocate general DG solver memory
76
77 // Initialize boundary condition factory
79
80 if(gridProxy_.isActive()) {
81 // Print information on used memory
82 printAllocatedMemory(previouslyAllocated, "DgCartesianSolver (solverId = " + to_string(m_solverId) + ")",
83 mpiComm());
84 }
85
86 RECORD_TIMER_STOP(m_timers[Timers::Constructor]);
87}
MLong allocatedBytes()
Return the number of allocated bytes.
Definition: alloc.cpp:121
DgBoundaryConditionFactory< nDim, SysEqn > m_boundaryConditionFactory
void initTimers()
Initialize all solver-wide timers and start the solver timer.
void initDgCartesianSolver()
Initializes basic properties of the solver.
std::array< MInt, Timers::_count > m_timers
Geom & m_geometry
Reference to geometry object.
void allocateAndInitSolverMemory()
Allocates main memory resources.
void setNumericalProperties()
Reads properties associated with the numerical method.
DgSponge< nDim, SysEqn > m_sponge
MPI_Comm mpiComm() const
Return the MPI communicator used by this solver.
Definition: solver.h:380
const MInt m_solverId
a unique solver identifier
Definition: solver.h:90
MBool isActive() const override
void printAllocatedMemory(const MLong oldAllocatedBytes, const MString &solverName, const MPI_Comm comm)
Prints currently allocated memory.
int64_t MLong
Definition: maiatypes.h:64
static void init(FactoryType &factory)

◆ ~DgCartesianSolver()

template<MInt nDim, class SysEqn >
DgCartesianSolver< nDim, SysEqn >::~DgCartesianSolver
override
Author
Michael Schlottke
Date
October 2012

Definition at line 98 of file dgcartesiansolver.cpp.

98 {
99 TRACE();
100 RECORD_TIMER_START(m_timers[Timers::Destructor]);
101 RECORD_TIMER_STOP(m_timers[Timers::Destructor]);
102 RECORD_TIMER_STOP(m_timers[Timers::SolverType]);
103}

Member Function Documentation

◆ a_coordinate()

template<MInt nDim, class SysEqn >
const MFloat & DgCartesianSolver< nDim, SysEqn >::a_coordinate ( const MInt  cellId,
const MInt  dim 
) const
inline

Definition at line 139 of file dgcartesiansolver.h.

139{ return grid().tree().coordinate(cellId, dim); }

◆ a_hasNeighbor()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::a_hasNeighbor ( const MInt  cellId,
const MInt  dir 
) const
inline

Definition at line 141 of file dgcartesiansolver.h.

141{ return grid().tree().hasNeighbor(cellId, dir); }

◆ a_level()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::a_level ( const  MInt) const
inline

Definition at line 142 of file dgcartesiansolver.h.

142{ TERMM(1, "Make this function return something meaningful in future!"); }

◆ a_noCells()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::a_noCells ( ) const
inline

Definition at line 140 of file dgcartesiansolver.h.

140{ TERMM(1, "Make this function return something meaningful in future!"); }

◆ adaptiveRefinement()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::adaptiveRefinement ( const MInt  timeStep)
private
Author
Sven Berger
Date
Februar 2015
Parameters
[in]timeStepTimestep at which adaptive refinement has been called

Note: Further information can be found in: Chapter 4 of "Implementation and validation of an adaptive hp-refinement method for the discontinuous Galerkin spectral element method. Master thesis, Sven Berger, RWTH Aachen University, 2014".

Adaptive refinement method 1 Refine cells for x>0 +1 in each adaptive refinement step

Adaptive refinement method 2 Sets the error relative to the maximum error

Properties: The property adaptiveThreshold determines the error threshold relative to the max. error. E.g.:

*smaller value -> more elements are set to a higher polynomial degree

*larger value -> a smaller number of elements is set to each higher polynomial degree

Note: Further information can be found in: Chapter 4 of "Implementation and validation of an adaptive hp-refinement method for the discontinuous Galerkin spectral element method. Master thesis, Sven Berger, RWTH Aachen University, 2014".

Definition at line 8838 of file dgcartesiansolver.cpp.

8838 {
8839 TRACE();
8840 RECORD_TIMER_START(m_timers[Timers::AdaptiveRefinement]);
8841
8842 // Empty set to hold surface ids of refined elements
8843 set<MInt> adaptedSrfcs;
8844
8845 // Vector to hold error estimate
8846 const MInt noElements = m_elements.size();
8847 vector<MFloat> errorEstimate(noElements, 0.0);
8848
8849 // Update the error estimate of the elements
8850 calcErrorEstimate(errorEstimate);
8851
8852 // Determine maximum error on local domain
8853 MFloat localErrorEstimate = *max_element(errorEstimate.begin(), errorEstimate.end());
8854 MFloat buffer = -1.0;
8855
8856 // exchange local max. error estimate to obtain global max. error
8857 if(noDomains() > 1) {
8858 MPI_Allreduce(&localErrorEstimate, &buffer, 1, maia::type_traits<MFloat>::mpiType(), MPI_MAX, mpiComm(), AT_,
8859 "localErrorEstimate", "buffer");
8860 }
8861
8862 const MFloat maxErrorEstimate = (buffer > localErrorEstimate) ? buffer : localErrorEstimate;
8863
8864#ifdef _OPENMP
8865#pragma omp parallel for
8866#endif
8867 // Determine which elments need to be refined
8868 for(MInt elementId = 0; elementId < noElements; elementId++) {
8869 const MInt cellId = m_elements.cellId(elementId);
8870 const MFloat error = errorEstimate[elementId];
8871
8872 // Initialize adapted polynomial degree to current value
8873 MInt adaptedPolyDeg = m_elements.polyDeg(elementId);
8874
8880 if(grid().tree().coordinate(cellId, 0) > 0) {
8881 adaptedPolyDeg += 1;
8882 }
8883 }
8884
8905 // Determine relative error threshold
8906 MFloat lvlThreshold = maxErrorEstimate * m_adaptiveThreshold;
8907
8908 // Iterate over all possible polynomial degrees (e.g. between minPolyDeg
8909 // and maxPolyDeg)
8910 for(MInt refLvl = m_maxPolyDeg; refLvl > m_minPolyDeg; refLvl--) {
8911 // If error is below current threshold, set new polynomialDegree
8912 if(error > lvlThreshold || refLvl == m_minPolyDeg) {
8913 adaptedPolyDeg = refLvl;
8914 break;
8915 }
8916 // Decrease threshold
8917 lvlThreshold *= m_adaptiveThreshold;
8918 }
8919 } else {
8920 TERMM(1, "Invalid adaptive refinement case.");
8921 }
8922
8923 // Skip elements for which no refinement is necessary
8924 if(adaptedPolyDeg == m_elements.polyDeg(elementId)) {
8925 continue;
8926 }
8927
8928 // Do not allow elements to be refined over m_maxPolyDeg
8929 if(adaptedPolyDeg > m_maxPolyDeg) {
8930 m_log << "WARNING: Element polynomial degree would exceed maximum "
8931 "polynomial degree."
8932 << endl;
8933 cout << "WARNING: Element polynomial degree would exceed maximum "
8934 "polynomial degree."
8935 << endl;
8936 adaptedPolyDeg = m_maxPolyDeg;
8937 }
8938
8939 // Do not allow elements to be coarsed lower than m_minPolyDeg
8940 if(adaptedPolyDeg < m_minPolyDeg) {
8941 m_log << "WARNING: Element polynomial degree would be coarsed below "
8942 "minimum polynomial degree."
8943 << endl;
8944 cout << "WARNING: Element polynomial degree would be coarsed below "
8945 "minimum polynomial degree."
8946 << endl;
8947 adaptedPolyDeg = m_minPolyDeg;
8948 }
8949
8950 // Interpolate element to degree specified by adaptedPolyDeg
8951 interpolateElement(elementId, adaptedPolyDeg);
8952 }
8953
8954 const MInt begin = 0;
8955 const MInt end = m_surfaces.size();
8956
8957 // Adapt all surfaces to the new polynomial degree
8958 MInt noAdaptedSrfcs = 0;
8959#ifdef _OPENMP
8960#pragma omp parallel for reduction(+ : noAdaptedSrfcs)
8961#endif
8962 for(MInt srfcId = begin; srfcId < end; srfcId++) {
8963 const MInt srfcPolyDeg = m_surfaces.polyDeg(srfcId);
8964 const MInt internalSide = m_surfaces.internalSideId(srfcId);
8965 const MInt elementIdL = m_surfaces.nghbrElementIds(srfcId, (internalSide == -1) ? 0 : internalSide);
8966 const MInt elementIdR = m_surfaces.nghbrElementIds(srfcId, (internalSide == -1) ? 1 : internalSide);
8967 const MInt polyDegL = m_elements.polyDeg(elementIdL);
8968 const MInt polyDegR = m_elements.polyDeg(elementIdR);
8969 const MInt noNodes1DL = m_elements.noNodes1D(elementIdL);
8970 const MInt noNodes1DR = m_elements.noNodes1D(elementIdR);
8971
8972 // If the maximum polynomial degree of the adjacent elements has changed,
8973 // update polynomial degree and re-calculate surface node coordinates
8974 if(max(polyDegL, polyDegR) != srfcPolyDeg) {
8975 m_surfaces.polyDeg(srfcId) = max(polyDegL, polyDegR);
8976 m_surfaces.noNodes1D(srfcId) = max(noNodes1DL, noNodes1DR);
8978 noAdaptedSrfcs++;
8979 }
8980 }
8981
8982 // Update MPI surface polynomial degree
8983 if(hasMpiExchange()) {
8985 }
8986
8987 // Recalculate values that depend on element polynomial degree
8988 m_noTotalNodesXD = 0;
8989 for(MInt i = 0; i < m_elements.size(); i++) {
8990 const MInt noNodesXD = m_elements.noNodesXD(i);
8991 m_noTotalNodesXD += noNodesXD;
8992 }
8993
8994 cout << "Grid has been refined at timestep " << timeStep << " (adapted surfaces: " << noAdaptedSrfcs << " )" << endl;
8995 m_log << "Grid has been refined at timestep " << timeStep << " (adapted surfaces: " << noAdaptedSrfcs << " )" << endl;
8996
8997 RECORD_TIMER_STOP(m_timers[Timers::AdaptiveRefinement]);
8998}
MBool hasMpiExchange() const
SurfaceCollector m_surfaces
void calcErrorEstimate(std::vector< MFloat > &errorEstimate)
Calculate error estimate for adaptive hp-refinement.
void interpolateElement(const MInt elementId, const MInt newPolyDeg)
Interpolate an element to a different polynomial degree.
ElementCollector m_elements
void calcSurfaceNodeCoordinates(const MInt surfaceId)
virtual MInt noDomains() const
Definition: solver.h:387
constexpr MInt size() const
Return size (i.e., currently used number of nodes)
Definition: container.h:89
MInt & polyDeg(const MInt id)
Accessor for polynomial degree.
MInt noNodesXD(const MInt id) const
Accessor for number of nodes XD (const version).
MInt & cellId(const MInt id)
Accessor for cell id.
MInt noNodes1D(const MInt id) const
Accessor for number of nodes 1D (const version).
MInt & internalSideId(const MInt srfcId)
Accessor for internal side id.
MInt & noNodes1D(const MInt srfcId)
Accessor for number of nodes 1D.
MInt & nghbrElementIds(const MInt srfcId, const MInt side)
Accessor for neighbor element ids.
MInt & polyDeg(const MInt srfcId)
Accessor for polynomial degree.
@ DG_ADAPTIVE_GRADIENT
Definition: enums.h:336
@ DG_ADAPTIVE_TEST
Definition: enums.h:336
InfoOutFile m_log
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
void const MInt cellId
Definition: collector.h:239

◆ allocateAndInitSolverMemory()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::allocateAndInitSolverMemory
private
Author
Michael Schlottke
Date
October 2012

Some of the container sizes depend directly on the number of leaf cells, others are controlled by a property.

Definition at line 1125 of file dgcartesiansolver.cpp.

1125 {
1126 TRACE();
1127
1128 // Count leaf cells to determine number of elements
1129 MInt noElements = 0;
1130 for(MInt cellId = 0; cellId < grid().noInternalCells(); cellId++) {
1131 // Check if element needs to be created
1132 if(needElementForCell(cellId)) {
1133 noElements++;
1134 }
1135 }
1136
1137 // Determine and set max. number of surfaces if not specified in properties
1138 if(m_maxNoSurfaces == -1) {
1139 // TODO labels:DG in some cases with partition level shift the calculated number was too small!
1141 m_log << "Max. no surfaces was not specified in the properties file (or "
1142 "set to -1). It was therefore calculated automatically for the "
1143 "current domain: "
1144 << m_maxNoSurfaces << endl;
1145 }
1146
1147 if(isActive()) {
1148 MInt maxNoElements = noElements;
1149 MPI_Allreduce(MPI_IN_PLACE, &maxNoElements, 1, type_traits<MInt>::mpiType(), MPI_MAX, mpiComm(), AT_,
1150 "MPI_IN_PLACE", "maxNoElements");
1151 MInt minNoElements = noElements;
1152 MPI_Allreduce(MPI_IN_PLACE, &minNoElements, 1, type_traits<MInt>::mpiType(), MPI_MIN, mpiComm(), AT_,
1153 "MPI_IN_PLACE", "minNoElements");
1154 MInt maxNoSurfaces = m_maxNoSurfaces;
1155 MPI_Allreduce(MPI_IN_PLACE, &maxNoSurfaces, 1, type_traits<MInt>::mpiType(), MPI_MAX, mpiComm(), AT_,
1156 "MPI_IN_PLACE", "maxNoSurfaces");
1157
1158 stringstream message;
1159 message << "Solver #" << solverId() << " - maximum number of DG elements among ranks: " << maxNoElements
1160 << std::endl;
1161 message << "Solver #" << solverId() << " - minimum number of DG elements among ranks: " << minNoElements
1162 << std::endl;
1163 message << "Solver #" << solverId() << " - maximum number of DG surfaces among ranks: " << maxNoSurfaces
1164 << std::endl;
1165 m_log << message.str();
1166 cerr0 << message.str();
1167 }
1168
1169 // Elements (allocated with maximum polynomial degree to support p-ref.)
1172 m_elements.noNodeVars(SysEqn::noNodeVars());
1173 m_elements.reset(noElements);
1174
1175 // Surfaces (allocated with maximum polynomial degree to support p-ref.)
1178 m_surfaces.noNodeVars(SysEqn::noNodeVars());
1180
1181 // Count coarse elements that smaller elements and need an h-element
1182 MInt noHElements = 0;
1183 for(MInt cellId = 0; cellId < grid().noCells(); cellId++) {
1184 if(needHElementForCell(cellId)) {
1185 noHElements++;
1186 }
1187 }
1188
1189 // H-elements
1190 m_helements.reset(noHElements);
1191}
MBool needHElementForCell(const MInt cellId)
Return true if h-element is needed for cell, false otherwise.
MInt calculateNeededNoSurfaces()
Determine the number of surfaces that need to be created on this domain.
MBool needElementForCell(const MInt cellId)
Return true if element is needed for cell, false otherwise.
HElementCollector m_helements
MInt solverId() const
Return the solverId.
Definition: solver.h:425
MInt maxNoNodes1D() const
Return maximum number of nodes 1D.
MInt maxPolyDeg() const
Return maximum polynomial degree.
void reset()
Reset tree, re-create data structures with given capacity, and set size to zero.
void reset()
Reset HElementCollector, re-create data structures.
MInt maxNoNodes1D() const
Return maximum number of nodes 1D.
MInt maxPolyDeg() const
Return maximum polynomial degree.
void reset()
Reset SurfaceCollector, re-create data structures.
const MString const MString & message
Definition: functions.h:37
std::ostream cerr0

◆ analyzeTimeStep()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::analyzeTimeStep ( MFloat  t,
MFloat  runTimeRelative,
MFloat  runTimeTotal,
MInt  timeStep,
MFloat  dt 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-05-01
Parameters
[in]tTime at which to analyze the solution.

Definition at line 7781 of file dgcartesiansolver.cpp.

7782 {
7783 TRACE();
7784 RECORD_TIMER_START(m_timers[Timers::Accumulated]);
7785 RECORD_TIMER_START(m_timers[Timers::AnalyzeTimeStep]);
7786 // Calculate error norms only if enabled in properties
7787 vector<MFloat> L2Error(m_sysEqn.noVars());
7788 vector<MFloat> LInfError(m_sysEqn.noVars());
7789 vector<MFloat> L2ErrLocal(m_sysEqn.noVars());
7790 vector<MFloat> LInfErrLocal(m_sysEqn.noVars());
7791 if(m_calcErrorNorms) {
7792 calcErrorNorms(t, L2Error, LInfError, L2ErrLocal, LInfErrLocal);
7793 // If any of the error measures are NaN, write a solution file before the
7794 // simulation is aborted
7795 if(any_of(L2Error.begin(), L2Error.end(), [](const MFloat e) { return std::isnan(e); })
7796 || any_of(LInfError.begin(), LInfError.end(), [](const MFloat e) { return std::isnan(e); })) {
7797 saveSolutionFile("nan_" + to_string(timeStep));
7798 }
7799
7800 // Check error norms for NaN and abort if found
7801 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
7802 if(std::isnan(L2ErrLocal[i])) {
7803 TERMM(1, "L^2 error for variable '" + m_sysEqn.consVarNames(i) + "' is NaN at time step " + to_string(timeStep)
7804 + " on global domain " + to_string(globalDomainId()));
7805 }
7806 if(std::isnan(LInfErrLocal[i])) {
7807 TERMM(1, "L^inf error for variable '" + m_sysEqn.consVarNames(i) + "' is NaN at time step "
7808 + to_string(timeStep) + " on global domain " + to_string(globalDomainId()));
7809 }
7810 }
7811 }
7812
7813 const MInt precision = m_noErrorDigits;
7814 const MInt fieldwith = precision + 6;
7815
7816 if(isMpiRoot()) {
7817 stringstream log;
7818
7819 log << endl;
7820 log << "----------------------------------------"
7821 << "----------------------------------------" << endl;
7822 log << " Solver " << solverId() << " running '" << m_sysEqn.sysEqnName() << "' with N = " << m_initPolyDeg
7823 << " and maxLevel = " << grid().maxLevel() << endl;
7824 log << "----------------------------------------"
7825 << "----------------------------------------" << endl;
7826 log << " No. timesteps: " << timeStep << endl;
7827 log << " dt: " << scientific << dt << endl;
7828 log << " Run time: " << runTimeTotal << " s" << endl;
7829 log << " Time/DOF/step: " << runTimeRelative << " s" << endl;
7830
7831 if(m_calcErrorNorms) {
7832 streamsize ss = log.precision();
7833 log << setprecision(precision);
7834 log << " Variable: ";
7835 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
7836 log << " " << left << setw(fieldwith) << setfill(' ') << m_sysEqn.consVarNames(i);
7837 }
7838 log << right << endl;
7839 log << " L^2 error: ";
7840 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
7841 log << " " << L2Error[i];
7842 }
7843 log << endl;
7844 log << " L^inf error: ";
7845 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
7846 log << " " << LInfError[i];
7847 }
7848 log << endl;
7849 log << setprecision(ss);
7850 }
7851
7852 log << "----------------------------------------"
7853 << "----------------------------------------" << endl;
7854 log << " Simulation time: " << t << endl;
7855 log << "----------------------------------------"
7856 << "----------------------------------------" << endl;
7857
7858 m_log << log.str() << endl;
7859 cout << log.str() << endl;
7860
7861 // Determine if this is the last time step and reset time step if necessary
7862 MBool finalTimeStep = false;
7863 if(m_finalTime - m_time - m_dt < 1.0E-10) {
7864 finalTimeStep = true;
7865 } else if(m_timeStep == m_timeSteps) {
7866 finalTimeStep = true;
7867 }
7868
7869 if(m_calcErrorNorms && isMpiRoot() && finalTimeStep) {
7870 std::ofstream eocStream;
7871 eocStream.open("EOCout.csv");
7872 eocStream << m_statGlobalNoActiveDOFs << "," << L2Error[0] << "," << LInfError[0];
7873 eocStream.close();
7874
7875 std::ofstream perfStream;
7876 perfStream.open("TimerOut.csv");
7877 perfStream << m_statGlobalNoActiveCells << "," << m_timeStep << "," << runTimeTotal << "," << runTimeRelative;
7878 perfStream.close();
7879 }
7880 }
7881
7882 // write local errors
7883 if(m_calcErrorNorms) {
7884 stringstream logLocal;
7885 logLocal << setprecision(precision) << scientific;
7886 logLocal << endl << " Variable: ";
7887 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
7888 logLocal << " " << left << setw(fieldwith) << setfill(' ') << m_sysEqn.consVarNames(i);
7889 }
7890 logLocal << right << endl;
7891 logLocal << " Local L^2 error: ";
7892 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
7893 logLocal << " " << L2ErrLocal[i];
7894 }
7895 logLocal << endl;
7896 logLocal << " Local L^inf error:";
7897 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
7898 logLocal << " " << LInfErrLocal[i];
7899 }
7900 logLocal << endl;
7901
7902 m_log << logLocal.str() << endl;
7903 }
7904
7905 RECORD_TIMER_STOP(m_timers[Timers::AnalyzeTimeStep]);
7906 RECORD_TIMER_STOP(m_timers[Timers::Accumulated]);
7907}
void calcErrorNorms(const MFloat t, std::vector< MFloat > &L2Error, std::vector< MFloat > &LInfError, std::vector< MFloat > &L2ErrLocal, std::vector< MFloat > &LInfErrLocal)
Calculate the L^2 and L^infinity error norms at a given time. The error is calculated in comparison t...
MBool isMpiRoot() const
Return true if this is the root rank of the solver MPI communicator.
void saveSolutionFile()
Saves all available data to disk.
void open(const MString &filename, const MString &projectName, MInt fileType=0, MPI_Comm mpiComm=MPI_COMM_WORLD, MBool rootOnlyHardwired=false)
Opens a file by passing the parameters to InfoOut_<xyz>FileBuffer::open(...).
Definition: infoout.cpp:975
MInt globalDomainId()
Return global domain id.
bool MBool
Definition: maiatypes.h:58

◆ applyExternalSourceTerms()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::applyExternalSourceTerms ( const MFloat  time)
private

Definition at line 7332 of file dgcartesiansolver.cpp.

7332 {
7333 TRACE();
7334 RECORD_TIMER_START(m_timers[Timers::ExternalSources]);
7335
7336 const MInt* noNodes1D = &m_elements.noNodes1D(0);
7337
7338 // Source term ramp up factor (linear in time)
7339 const MFloat rampUpFactor =
7341
7342#ifdef _OPENMP
7343#pragma omp parallel for
7344#endif
7345 for(MInt elementId = 0; elementId < m_elements.size(); elementId++) {
7346 const MInt dataBlockSize = ipow(noNodes1D[elementId], nDim) * SysEqn::noVars();
7347 MFloat* const rhs = &m_elements.rightHandSide(elementId);
7348 const MFloat* const sources = &m_elements.externalSource(elementId);
7349
7350 for(MInt dataId = 0; dataId < dataBlockSize; dataId++) {
7351 rhs[dataId] += rampUpFactor * sources[dataId];
7352 }
7353 }
7354
7355 RECORD_TIMER_STOP(m_timers[Timers::ExternalSources]);
7356}
MFloat time() const override
Return the time.
MFloat & externalSource(const MInt id)
Accessor for external source terms.
MFloat & rightHandSide(const MInt id)
Accessor for right hand side.
MInt ipow(MInt base, MInt exp)
Integer exponent function for non-negative exponents.
Definition: functions.h:317
T linear(const T a, const T b, const T x)
Linear slope filter.
Definition: filter.h:83

◆ applyForwardProjection()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::applyForwardProjection
private

Apply forward mortar projections (hp-refinement).

Author
Sven Berger, Michael Schlottke
Date
2015-03-02

This method does two things: first, all missing results from the prolong step are copied to the remaining surfaces for h-refined faces. Then, both h- and p-refinement mortar projections are first applied to h-refined surfaces and then p-refinement mortar projections are applied to purely p-refined surfaces.

Definition at line 6805 of file dgcartesiansolver.cpp.

6805 {
6806 TRACE();
6807 RECORD_TIMER_START(m_timers[Timers::ForwardProjection]);
6808
6809 // IMPORTANT:
6810 // If anything in this method is changed, please check if
6811 // updateNodeVariables() needs to be changed as well, since it contains more
6812 // or less the same code.
6813
6814 const MInt* surfaceIds = &m_elements.surfaceIds(0, 0);
6815 const MInt noVars = SysEqn::noVars();
6816 const MInt maxNoNodes1D = m_maxNoNodes1D;
6817 const MInt maxNoNodes1D3 = (nDim == 3) ? maxNoNodes1D : 1;
6818 const MInt noHElements = m_helements.size();
6819 const MInt noDirs = 2 * nDim;
6820 const MInt noSurfs = 2 * (nDim - 1);
6821
6823 // Copy prolong results to h-refined surfaces (the prolong step stored its
6824 // results only in the first refined surface)
6826 if(noHElements > 0) {
6827#ifdef _OPENMP
6828#pragma omp parallel for
6829#endif
6830 for(MInt hElementId = 0; hElementId < noHElements; hElementId++) {
6831 const MInt coarseElementId = m_helements.elementId(hElementId);
6832 for(MInt dir = 0; dir < noDirs; dir++) {
6833 const MInt coarseSrfcId = m_elements.surfaceIds(coarseElementId, dir);
6834 for(MInt pos = 0; pos < noSurfs; pos++) {
6835 const MInt hSrfcId = m_helements.hrefSurfaceIds(hElementId, dir, pos);
6836 const MInt side = 1 - dir % 2;
6837
6838 // Skip if this surface does not exist
6839 if(hSrfcId == -1) {
6840 continue;
6841 }
6842
6843 // Copy values of prolong step to all remaining refined surfaces
6844 if(coarseSrfcId != hSrfcId) {
6845 const MInt noNodes1D = m_elements.noNodes1D(coarseElementId);
6846 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
6847 const MInt size = noNodes1D * noNodes1D3 * SysEqn::noVars();
6848
6849 // Copy values from prolong step to surface
6850 copy_n(&m_surfaces.variables(coarseSrfcId, side), size, &m_surfaces.variables(hSrfcId, side));
6851 }
6852 }
6853 }
6854 }
6855 }
6856
6858 // Apply mortar projection
6860 const MInt noElements = m_elements.size();
6861 MFloatTensor projected(maxNoNodes1D, maxNoNodes1D3, noVars);
6862
6863 // Apply projection to h- (and possibly p-)refined surfaces
6864 if(noHElements > 0) {
6865#ifdef _OPENMP
6866#pragma omp parallel for firstprivate(projected)
6867#endif
6868 for(MInt hElementId = 0; hElementId < noHElements; hElementId++) {
6869 for(MInt dir = 0; dir < noDirs; dir++) {
6870 for(MInt pos = 0; pos < noSurfs; pos++) {
6871 const MInt hSrfcId = m_helements.hrefSurfaceIds(hElementId, dir, pos);
6872 const MInt side = 1 - dir % 2;
6873
6874 // Skip if this surface does not exist
6875 if(hSrfcId == -1) {
6876 continue;
6877 }
6878
6879 const MInt surfaceNoNodes1D = m_surfaces.noNodes1D(hSrfcId);
6880 const MInt surfaceNoNodes1D3 = (nDim == 3) ? surfaceNoNodes1D : 1;
6881 const MInt size = surfaceNoNodes1D * surfaceNoNodes1D3 * noVars;
6882
6883 // Project the coarse side to the surface
6884 calcMortarProjection<dg::mortar::forward, SysEqn::noVars()>(
6885 hSrfcId, dir, &m_surfaces.variables(hSrfcId, side), &projected[0], m_elements, m_surfaces);
6886
6887 // Copy results of projection back to surface
6888 copy_n(&projected[0], size, &m_surfaces.variables(hSrfcId, side));
6889 }
6890 }
6891 }
6892 }
6893
6894 // Apply projection to pure p-refined surfaces
6895#ifdef _OPENMP
6896#pragma omp parallel for firstprivate(projected)
6897#endif
6898 for(MInt elementId = 0; elementId < noElements; elementId++) {
6899 const MInt surfaceIdOffset = elementId * 2 * nDim;
6900
6901 for(MInt dir = 0; dir < 2 * nDim; dir++) {
6902 // Define auxiliary variables for better readability
6903 const MInt srfcId = surfaceIds[surfaceIdOffset + dir];
6904
6905 // Skip boundary surfaces as they are *always* conforming
6906 if(srfcId < m_innerSurfacesOffset) {
6907 continue;
6908 }
6909
6910 const MInt surfacePolyDeg = m_surfaces.polyDeg(srfcId);
6911 const MInt elementPolyDeg = m_elements.polyDeg(elementId);
6912 const MInt side = 1 - dir % 2;
6913 const MInt surfaceNoNodes1D = m_surfaces.noNodes1D(srfcId);
6914 const MInt surfaceNoNodes1D3 = (nDim == 3) ? surfaceNoNodes1D : 1;
6915 const MInt size = surfaceNoNodes1D * surfaceNoNodes1D3 * noVars;
6916
6917 // Skip h-refined surfaces since they have been already projected
6918 if(m_surfaces.fineCellId(srfcId) != -1 && m_surfaces.fineCellId(srfcId) != m_elements.cellId(elementId)) {
6919 continue;
6920 }
6921
6922 // Calculate forward projection for lower polyDeg elements
6923 if(surfacePolyDeg > elementPolyDeg) {
6924 // Calculate forward projection
6925 calcMortarProjection<dg::mortar::forward, SysEqn::noVars()>(srfcId, dir, &m_surfaces.variables(srfcId, side),
6926 &projected[0], m_elements, m_surfaces);
6927
6928 // Copy results of projection back to surface
6929 copy_n(&projected[0], size, &m_surfaces.variables(srfcId, side));
6930 }
6931 }
6932 }
6933
6934 RECORD_TIMER_STOP(m_timers[Timers::ForwardProjection]);
6935}
MInt & surfaceIds(const MInt id, const MInt dir)
Accessor for surface ids.
MInt & hrefSurfaceIds(const MInt id, const MInt dir, const MInt pos)
Accessor for h-refined surface ids.
MInt & elementId(const MInt id)
Accessor for element id.
MInt & fineCellId(const MInt srfcId)
Accessor for fine cell id.
MFloat & variables(const MInt srfcId, const MInt side)
Accessor for variables.

◆ applyJacobian() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::applyJacobian
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-12-13

Definition at line 7274 of file dgcartesiansolver.cpp.

7274 {
7275 TRACE();
7276 RECORD_TIMER_START(m_timers[Timers::Jacobian]);
7277
7279
7280 RECORD_TIMER_STOP(m_timers[Timers::Jacobian]);
7281}
void applyJacobian()
Adds the negative of the inverse Jacobian to the time derivative.

◆ applyJacobian() [2/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::applyJacobian ( const MInt  noElements,
ElementCollector elem 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-12-23
Parameters
[in]noElementsNumber of elements.
[in]elemPointer to elements.

Definition at line 7294 of file dgcartesiansolver.cpp.

7294 {
7295 TRACE();
7296
7297 MFloat* const invJacobians = &elem.invJacobian(0);
7298
7299#ifdef _OPENMP
7300#pragma omp parallel for
7301#endif
7302 for(MInt elementId = 0; elementId < noElements; elementId++) {
7303 const MInt dataBlockSize = elem.noNodesXD(elementId) * SysEqn::noVars();
7304 const MFloat invJacobian = invJacobians[elementId];
7305
7306 MFloat* const rhs = &elem.rightHandSide(elementId);
7307 for(MInt dataId = 0; dataId < dataBlockSize; dataId++) {
7308 rhs[dataId] *= -invJacobian;
7309 }
7310 }
7311}

◆ applySurfaceIntegral()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::applySurfaceIntegral ( MFloat rhs,
const MInt  polyDeg,
const MInt  noNodes1D,
const MInt  srfcId,
const MInt  side,
const MFloat flux,
SurfaceCollector surf 
)
private
Author
Michael Schlottke, Sven Berger
Date
March 2015
Parameters
[in]rhsTime derivatives of element variables where the surface integral is added to. \parma[in] polyDeg Polynomial degree of element.
[in]srfcIdSurface id from which the flux is to be used.
[in]sidePosition of element with respect to the surface. A value of zero means the element is in the -ve coordinate direction with respect to the surface, a value of one means the element is in the +ve direction.
[in]fluxThe surface flux.
[in]surfPointer to surfaces.

Definition at line 7169 of file dgcartesiansolver.cpp.

7171 {
7172 // TRACE();
7173 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
7174 const MInt noVars = SysEqn::noVars();
7175 const MInt srfcNodes1D = surf.noNodes1D(srfcId);
7176 const MInt srfcNodes1D3 = (nDim == 3) ? srfcNodes1D : 1;
7177
7178 const MFloatTensor f(const_cast<MFloat*>(flux), srfcNodes1D, srfcNodes1D3, noVars);
7179
7180 // Calculate surface integral
7181 MFloatTensor ut(rhs, noNodes1D, noNodes1D, noNodes1D3, noVars);
7182 const MInt dirId = surf.orientation(srfcId);
7183 const MInt index = (side == 0) ? (noNodes1D - 1) : 0;
7184 const MInt sign = (side == 0) ? 1 : -1;
7185 const DgInterpolation& interp = m_interpolation[polyDeg][noNodes1D];
7186
7187
7189 // Use different loops depending on the surface orientation
7190 switch(dirId) {
7191 case 0:
7192 for(MInt i = 0; i < noNodes1D; i++) {
7193 for(MInt j = 0; j < noNodes1D; j++) {
7194 for(MInt k = 0; k < noNodes1D3; k++) {
7195 for(MInt n = 0; n < noVars; n++) {
7196 ut(i, j, k, n) += sign * f(j, k, n) * interp.m_LhatFace[1 - side][i];
7197 }
7198 }
7199 }
7200 }
7201 break;
7202
7203 case 1:
7204 for(MInt i = 0; i < noNodes1D; i++) {
7205 for(MInt j = 0; j < noNodes1D; j++) {
7206 for(MInt k = 0; k < noNodes1D3; k++) {
7207 for(MInt n = 0; n < noVars; n++) {
7208 ut(i, j, k, n) += sign * f(i, k, n) * interp.m_LhatFace[1 - side][j];
7209 }
7210 }
7211 }
7212 }
7213 break;
7214
7215 case 2:
7216 for(MInt i = 0; i < noNodes1D; i++) {
7217 for(MInt j = 0; j < noNodes1D; j++) {
7218 for(MInt k = 0; k < noNodes1D3; k++) {
7219 for(MInt n = 0; n < noVars; n++) {
7220 ut(i, j, k, n) += sign * f(i, j, n) * interp.m_LhatFace[1 - side][k];
7221 }
7222 }
7223 }
7224 }
7225 break;
7226 default:
7227 mTerm(1, AT_, "Bad direction id");
7228 }
7230 // Use different loops depending on the surface orientation
7231 switch(dirId) {
7232 case 0:
7233 for(MInt j = 0; j < noNodes1D; j++) {
7234 for(MInt k = 0; k < noNodes1D3; k++) {
7235 for(MInt n = 0; n < noVars; n++) {
7236 ut(index, j, k, n) += sign * f(j, k, n) * interp.m_LhatFace[1 - side][index];
7237 }
7238 }
7239 }
7240 break;
7241
7242 case 1:
7243 for(MInt i = 0; i < noNodes1D; i++) {
7244 for(MInt k = 0; k < noNodes1D3; k++) {
7245 for(MInt n = 0; n < noVars; n++) {
7246 ut(i, index, k, n) += sign * f(i, k, n) * interp.m_LhatFace[1 - side][index];
7247 }
7248 }
7249 }
7250 break;
7251
7252 case 2:
7253 for(MInt i = 0; i < noNodes1D; i++) {
7254 for(MInt j = 0; j < noNodes1D3; j++) {
7255 for(MInt n = 0; n < noVars; n++) {
7256 ut(i, j, index, n) += sign * f(i, j, n) * interp.m_LhatFace[1 - side][index];
7257 }
7258 }
7259 }
7260 break;
7261
7262 default:
7263 mTerm(1, AT_, "Bad direction id");
7264 }
7265 }
7266}
std::vector< std::vector< DgInterpolation > > m_interpolation
Class stores precalculated values for interpolation & integration on the reference interval [-1,...
MFloatVector m_LhatFace[2]
@ DG_INTEGRATE_GAUSS
Definition: enums.h:313
@ DG_INTEGRATE_GAUSS_LOBATTO
Definition: enums.h:313
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
IdType index(const FloatType *const x, const IdType level)
Return Hilbert index for given location and level in 2D or 3D.
Definition: hilbert.h:165

◆ balance()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::balance ( const MInt *const   NotUsednoCellsToReceiveByDomain,
const MInt *const   NotUsednoCellsToSendByDomain,
const MInt *const   NotUsedtargetDomainsByCell,
const MInt   NotUsedoldNoCells 
)
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 403 of file dgcartesiansolver.h.

406 {
407 TERMM(1, "Use split balancing methods for DG solver instead of balance().");
408 };

◆ balancePost()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::balancePost
overridevirtual
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

Reimplemented from Solver.

Definition at line 9696 of file dgcartesiansolver.cpp.

9696 {
9697 TRACE();
9698
9699 // Nothing to do if solver is not active
9700 if(!isActive()) {
9701 return;
9702 }
9703
9704 // Set reinitialization stage
9706
9707 RECORD_TIMER_START(m_timers[Timers::RunInit]);
9708 RECORD_TIMER_START(m_timers[Timers::InitSolverObjects]);
9709
9711
9712 // Set new internal data size
9713 m_internalDataSize = m_elements.size() * pow(m_maxNoNodes1D, nDim) * SysEqn::noVars();
9714
9715 // Calculate new total number of nodes
9716 m_noTotalNodesXD = 0;
9717 for(MInt i = 0; i < m_elements.size(); i++) {
9718 const MInt noNodesXD = m_elements.noNodesXD(i);
9719 m_noTotalNodesXD += noNodesXD;
9720 }
9721
9723
9724 initJacobian();
9725
9727
9728 // Prevent the RBC from overwriting its solution
9729 m_restart = true;
9730
9731 initSurfaces();
9732
9733 if(noDomains() > 1) {
9735 }
9736
9737 if(useSponge()) {
9738 m_log << "Reinitializing sponge... ";
9740 m_log << "done" << endl;
9741 }
9742
9743 if(noDomains() > 1 && hasPref()) {
9745 }
9746
9748
9749 // @ansgar TODO labels:DG,PP wont work, no cleanup, save data prior to DLB? also the point ordering in the
9750 // output file might change
9751 m_pointData.init();
9754
9755 m_slice.init();
9756
9758 TERMM(1, "DLB for point/surface/volumeData not supported yet");
9759 }
9760
9762
9763 // From initData()
9764 // Reset current Runge Kutta stage
9765 m_rkStage = 0;
9766
9767 // Update all node variables, if they are used
9768 if(SysEqn::noNodeVars() > 0) {
9770 extendNodeVariables(); // @ansgar TODO labels:DG,totest,toremove check if needed!
9771 }
9772
9773 m_isInitSolver = true;
9774 m_isInitData = true;
9775 // TODO labels:DG endAutoSaveTime
9776 m_isInitMainLoop = true;
9777
9778 // outputInitSummary();
9779 RECORD_TIMER_STOP(m_timers[Timers::InitSolverObjects]);
9780 RECORD_TIMER_STOP(m_timers[Timers::RunInit]);
9781
9782 // Set reinitialization stage
9784}
void checkCellProperties()
Check all relevant bit properties in the cells.
MBool useSponge() const
void initSurfaces()
Create for all elements and directions surfaces if necessary.
void initJacobian()
Calculates the inverse Jacobian for each element.
std::vector< BC > m_boundaryConditions
void initMortarProjections()
Calculate all necessary mortar projection matrices.
void extendNodeVariables()
Extends nodeVars from given planes to given directions.
void initNodeCoordinates()
Calculates the coordinates of the integration nodes within each element.
void initInterpolation()
Calculates necessary coefficients for interpolation and stores them once for the whole solver.
DgSponge< nDim, SysEqn > & sponge()
PointData< nDim, DgCartesianSolver< nDim, SysEqn > > m_pointData
MBool hasPref() const
Return true if p-refinement is set.
SurfaceData< nDim, DgCartesianSolver< nDim, SysEqn > > m_surfaceData
DgSlices< nDim, SysEqn > m_slice
void updateNodeVariables()
Update all node variables at the surfaces.
VolumeData< nDim, DgCartesianSolver< nDim, SysEqn > > m_volumeData
MBool enabled() const
Definition: samplingdata.h:42
MBool m_restart
Definition: solver.h:97

◆ balancePre()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::balancePre
overridevirtual
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

Reimplemented from Solver.

Definition at line 9648 of file dgcartesiansolver.cpp.

9648 {
9649 TRACE();
9650
9651 // Set reinitialization stage
9653
9654 // Store currently used memory
9655 const MLong previouslyAllocated = allocatedBytes();
9656
9657 // Set to prevent initialization (e.g. due to coupling) that overwrites redistributed data
9658 m_restart = true;
9659
9660 // Update the grid proxy for this solver
9661 grid().update();
9662
9663 // Just reset parallelization information if solver is not active and cleanup containers
9664 if(!isActive()) {
9665 updateDomainInfo(-1, -1, MPI_COMM_NULL, AT_);
9666 m_elements.reset(0);
9667 m_helements.reset(0);
9668 m_surfaces.reset(0);
9669 return;
9670 }
9671
9672 // Set new domain info for solver
9674
9676
9677 // Print information on used memory
9678 printAllocatedMemory(previouslyAllocated, "DgCartesianSolver (solverId = " + to_string(m_solverId) + ")", mpiComm());
9679
9680 RECORD_TIMER_START(m_timers[Timers::RunInit]);
9681 RECORD_TIMER_START(m_timers[Timers::InitSolverObjects]);
9682 // Initialization from initSolver()
9683 initGridMap();
9684 initElements();
9685 initHElements();
9686 // Note: Polynomial degree is communicated and set from gridcontroller
9687 RECORD_TIMER_STOP(m_timers[Timers::InitSolverObjects]);
9688 RECORD_TIMER_STOP(m_timers[Timers::RunInit]);
9689}
void initElements()
Initialize all elements by iterating over all cells and creating an element for each internal leaf ce...
void initGridMap()
Determine grid-to-grid mapping.
void initHElements()
Initialize all helements by iterating over all cells and creating an element for each coarse cell in ...
virtual MInt domainId() const
Return the domainId (rank)
Definition: solver.h:383
void updateDomainInfo(const MInt domainId, const MInt noDomains, const MPI_Comm mpiComm, const MString &loc)
Set new domain information.
Definition: solver.h:135

◆ calcBoundarySurfaceFlux()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcBoundarySurfaceFlux ( MFloat  t)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-04-18
Parameters
[in]tTime at which the boundary conditions should be set (necessary for time-dependent b.c.'s).

Definition at line 6965 of file dgcartesiansolver.cpp.

6965 {
6966 TRACE();
6967 RECORD_TIMER_START(m_timers[Timers::Flux]);
6968 RECORD_TIMER_START(m_timers[Timers::FluxBndry]);
6969
6970 for(auto&& bc : m_boundaryConditions) {
6971 bc->apply(t);
6972 }
6973
6974 RECORD_TIMER_STOP(m_timers[Timers::FluxBndry]);
6975 RECORD_TIMER_STOP(m_timers[Timers::Flux]);
6976}

◆ calcDgTimeDerivative()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcDgTimeDerivative ( const MFloat  t,
const MFloat  tStage 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-04-18
Parameters
[in]tPhysical time at which the time derivative is calculated.
[in]tStagePseudo time of the Runge-Kutta stage (needed for time-dependent source terms).

Definition at line 6647 of file dgcartesiansolver.cpp.

6647 {
6648 TRACE();
6649 RECORD_TIMER_START(m_timers[Timers::TimeDeriv]);
6650
6651 // Reset the time derivative to zero
6652 resetRHS();
6653
6654 // Calculate solution on all surfaces and start exchange of surface data
6655 // In split MPI mode most of the time this was already done at the end of
6656 // timeStepRk(). If there are no open MPI requests it needs to be done here.
6658 // Extrapolate the solution vector U from the element volume to all surfaces
6660
6661 // Apply forward mortar projection to h- and/or p-refined surfaces
6663
6664 // Start exchanging surface data
6666 }
6667
6668 // Calculate the volume integral and update dU/dt
6670
6671 // Calculate the fluxes on the internal surfaces
6673
6674 // Exclude communication from domain load and add to idle time
6675 // Finish exchanging surface data
6677
6678 // Calculate the fluxes on the boundary surfaces
6679 // Note: this was previously called after calcVolumeIntegral(). It was moved
6680 // in order to make the radiation boundary conditions work in parallel without
6681 // any additional MPI communication.
6683
6684 // Calculate the fluxes on the MPI surfaces
6686
6687 // Calculate the integrals for all surfaces and update dU/dt
6689
6690 // Apply Jacobian to dU/dt
6691 applyJacobian();
6692
6693 // Calculate source terms and add them to dU/dt
6694 calcSourceTerms(tStage);
6695
6696 // Add external (coupling) source terms
6698
6699 // Calculate sponge terms and add them to dU/dt
6700 if(useSponge()) {
6701 RECORD_TIMER_START(m_timers[Timers::Sponge]);
6702 sponge().calcSourceTerms();
6703 RECORD_TIMER_STOP(m_timers[Timers::Sponge]);
6704 }
6705
6706 RECORD_TIMER_STOP(m_timers[Timers::TimeDeriv]);
6707}
void prolongToSurfaces()
Extrapolate the solution from inside the elements to the surfaces.
void calcSurfaceIntegral()
Calculate the surface integral for all faces of element and update dU/dt.
void calcInnerSurfaceFlux()
Calculate the numerical flux on the internal surfaces and update m_flux.
void applyExternalSourceTerms(const MFloat time)
Add the external coupling source terms to the right hand side.
void calcMpiSurfaceFlux()
Calculate the numerical flux on the MPI surfaces and update m_flux.
void calcSourceTerms(MFloat t)
Calculates the source terms for each node and adds them to the time derivative of the conservative va...
void calcVolumeIntegral()
Calculate the volume integral for all elements and update m_rightHandSide.
void calcBoundarySurfaceFlux(MFloat t)
Calculate the numerical flux on the boundary surfaces and update m_flux.
void finishMpiSurfaceExchange()
Finish sending the window-side data and finish receiving the halo-side data for all MPI surfaces.
void startMpiSurfaceExchange()
Start sending the window-side data and start receiving the halo-side data for all MPI surfaces.
virtual void resetRHS()
Reset the time derivative of the conservative variables to zero.
MBool g_splitMpiComm

◆ calcElementNodeCoordinates()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcElementNodeCoordinates ( const MInt  elementId)
private
Author
Sven Berger
Date
Februar 2015

Definition at line 2799 of file dgcartesiansolver.cpp.

2799 {
2800 // Create a shallow tensor for the node coordinates
2801 const MInt cellId = m_elements.cellId(elementId);
2802 const MInt lvl = grid().tree().level(cellId);
2803 const MInt polyDeg = m_elements.polyDeg(elementId);
2804 const MInt noNodes1D = m_elements.noNodes1D(elementId);
2805 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
2806 MFloatTensor nodeCoordinates(&m_elements.nodeCoordinates(elementId), noNodes1D, noNodes1D, noNodes1D3, nDim);
2807
2808 // Iterate over all nodes and set the coordinates
2809 for(MInt i = 0; i < noNodes1D; i++) {
2810 for(MInt j = 0; j < noNodes1D; j++) {
2811 for(MInt k = 0; k < noNodes1D3; k++) {
2812 // Node coordinates = cell center
2813 // + 1/2 cell length * normalized ([-1,1]) node coordinate
2814 nodeCoordinates(i, j, k, 0) =
2815 grid().tree().coordinate(cellId, 0)
2816 + F1B2 * grid().cellLengthAtLevel(lvl) * m_interpolation[polyDeg][noNodes1D].m_nodes[i];
2817 nodeCoordinates(i, j, k, 1) =
2818 grid().tree().coordinate(cellId, 1)
2819 + F1B2 * grid().cellLengthAtLevel(lvl) * m_interpolation[polyDeg][noNodes1D].m_nodes[j];
2820 IF_CONSTEXPR(nDim == 3) {
2821 nodeCoordinates(i, j, k, 2) =
2822 grid().tree().coordinate(cellId, 2)
2823 + F1B2 * grid().cellLengthAtLevel(lvl) * m_interpolation[polyDeg][noNodes1D].m_nodes[k];
2824 }
2825 }
2826 }
2827 }
2828}
MFloat & nodeCoordinates(const MInt id)
Accessor for node coordinates.

◆ calcErrorEstimate()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcErrorEstimate ( std::vector< MFloat > &  errorEstimate)
private
Author
Sven Berger
Date
Februar 2015
Parameters
[out]errorEstimateReference to a vector of size noElements to store the calculated error.

Definition at line 9009 of file dgcartesiansolver.cpp.

9009 {
9010 TRACE();
9011
9013 // Calculate the gradient over all surfaces to determine the maximum
9014 // gradient for each element
9015 const MInt begin = m_innerSurfacesOffset;
9016 const MInt end = m_surfaces.size();
9017 const MInt noVars = SysEqn::noVars();
9018 const MInt noElements = m_elements.size();
9019
9020 MFloatScratchSpace error(m_surfaces.size(), FUN_, "Error estimate");
9021 fill_n(&error[0], m_surfaces.size(), 0.0);
9022
9023// Loop over all surfaces, calculate error estimates, and update elements
9024#ifdef _OPENMP
9025#pragma omp parallel for
9026#endif
9027 for(MInt srfcId = begin; srfcId < end; srfcId++) {
9028 const MInt noNodes1D = m_surfaces.noNodes1D(srfcId);
9029 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
9030 const MFloat* stateL = &m_surfaces.variables(srfcId, 0);
9031 const MFloat* stateR = &m_surfaces.variables(srfcId, 1);
9032
9033
9034 const MFloatTensor uL(const_cast<MFloat*>(stateL), noNodes1D, noNodes1D3, noVars);
9035 const MFloatTensor uR(const_cast<MFloat*>(stateR), noNodes1D, noNodes1D3, noVars);
9036
9037 // Calculate error estimate as difference between left and right state
9038 for(MInt i = 0; i < noNodes1D; i++) {
9039 for(MInt j = 0; j < noNodes1D3; j++) {
9040 for(MInt var = 0; var < noVars; var++) {
9041 error[srfcId] += fabs(uL(i, j, var) - uR(i, j, var));
9042 }
9043 }
9044 }
9045
9046 // Normalize by number of nodes on surface
9047 error[srfcId] = error[srfcId] / (noNodes1D * noNodes1D3);
9048 }
9049
9050#ifdef _OPENMP
9051#pragma omp parallel for
9052#endif
9053 // sum element error contributions
9054 for(MInt elementId = 0; elementId < noElements; elementId++) {
9055 const MInt noSrfcs = 2 * nDim;
9056 for(MInt i = 0; i < noSrfcs; i++) {
9057 const MInt srfcId = m_elements.surfaceIds(elementId, i);
9058 errorEstimate[elementId] += error[srfcId];
9059 }
9060 }
9061 }
9062}
This class is a ScratchSpace.
Definition: scratch.h:758

◆ calcErrorNorms()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcErrorNorms ( const MFloat  t,
std::vector< MFloat > &  L2Error,
std::vector< MFloat > &  LInfError,
std::vector< MFloat > &  L2ErrLocal,
std::vector< MFloat > &  LInfErrLocal 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-05-01
Parameters
[in]tPhysical time at which to calculate the error norms.
[out]L2ErrorStorage for the L^2 error (one value/variable).
[out]LInfErrorStorage for the L^infinity error (one value/variable).
[out]L2ErrLocalStorage for the local L^2 error (one value/variable).
[out]LInfErrLocalStorage for the local L^infinity error (one value/variable).

Definition at line 7925 of file dgcartesiansolver.cpp.

7929 {
7930 TRACE();
7931 const MInt noVars = m_sysEqn.noVars();
7932 L2Error.assign(noVars, F0);
7933 LInfError.assign(noVars, F0);
7934 L2ErrLocal.assign(noVars, F0);
7935 LInfErrLocal.assign(noVars, F0);
7936
7937 // Allocate space for temporary values
7938 MFloatScratchSpace uExact(noVars, FUN_, "uExact");
7939 const MInt noNodesAnalysis1D = m_noAnalysisNodes;
7940 const MInt noNodesAnalysis1D3 = (nDim == 3) ? noNodesAnalysis1D : 1;
7941 MFloatTensor u(noNodesAnalysis1D, noNodesAnalysis1D, noNodesAnalysis1D3, noVars);
7942 MFloatTensor x(noNodesAnalysis1D, noNodesAnalysis1D, noNodesAnalysis1D3, nDim);
7943 // Set node vars to minimum 1 to avoid errors in Tensor
7944 // TODO labels:DG Check if this is really sensible
7945 MFloatTensor nodeVars(noNodesAnalysis1D, noNodesAnalysis1D, noNodesAnalysis1D3, max(SysEqn::noNodeVars(), 1));
7946
7947 // Loop over internal elements and calculate local errors
7948 const MInt noElements = m_elements.size();
7949 for(MInt elementId = 0; elementId < noElements; elementId++) {
7950 // Interpolate solution from regular nodes to analysis nodes
7951 const MInt polyDegElement = m_elements.polyDeg(elementId);
7952 const MInt noNodesElement = m_elements.noNodes1D(elementId);
7953 auto vdm = m_vdmAnalysis[polyDegElement][noNodesElement];
7954 dg::interpolation::interpolateNodes<nDim>(&m_elements.variables(elementId), &vdm[0], noNodesElement,
7955 m_noAnalysisNodes, noVars, &u[0]);
7956
7957 // Interpolation node locations from regular nodes to analysis nodes
7958 dg::interpolation::interpolateNodes<nDim>(&m_elements.nodeCoordinates(elementId), &vdm[0], noNodesElement,
7959 m_noAnalysisNodes, nDim, &x[0]);
7960
7961 // Calculate error norms
7962 const MFloat jacobian = pow(F1 / m_elements.invJacobian(elementId), nDim);
7963 for(MInt i = 0; i < noNodesAnalysis1D; i++) {
7964 for(MInt j = 0; j < noNodesAnalysis1D; j++) {
7965 for(MInt k = 0; k < noNodesAnalysis1D3; k++) {
7966 // TODO labels:DG Check if we need to initialize coupling quantities here as
7967 // well (instead of just interpolating)
7968 m_sysEqn.calcInitialCondition(t, &x(i, j, k, 0), &nodeVars(i, j, k, 0), &uExact[0]);
7969 for(MInt v = 0; v < noVars; v++) {
7970 const MFloat diff = uExact[v] - u(i, j, k, v);
7971 L2ErrLocal[v] += pow(diff, F2) * m_wVolumeAnalysis(i, j, k) * jacobian;
7972 LInfErrLocal[v] = max(LInfErrLocal[v], fabs(diff));
7973 }
7974 }
7975 }
7976 }
7977 }
7978
7979 // Calculate global errors
7980 RECORD_TIMER_START(m_timers[Timers::MPI]);
7981 RECORD_TIMER_START(m_timers[Timers::MPIComm]);
7982 MPI_Allreduce(&L2ErrLocal[0], &L2Error[0], noVars, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "L2ErrLocal[0]",
7983 "L2Error[0]");
7984 MPI_Allreduce(&LInfErrLocal[0], &LInfError[0], noVars, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "LInfErrLocal[0]",
7985 "LInfError[0]");
7986 RECORD_TIMER_STOP(m_timers[Timers::MPIComm]);
7987 RECORD_TIMER_STOP(m_timers[Timers::MPI]);
7988
7989 // Finalize L^2 error calculation
7990 for(MInt v = 0; v < noVars; v++) {
7991 L2ErrLocal[v] = sqrt(L2ErrLocal[v] / m_localVolume);
7992 L2Error[v] = sqrt(L2Error[v] / m_globalVolume);
7993 }
7994}
std::vector< std::vector< MFloatTensor > > m_vdmAnalysis
MFloatTensor m_wVolumeAnalysis
MFloat & invJacobian(const MInt id)
Accessor for inverse jacobian.
MFloat & variables(const MInt id, const MInt pos)
Accessor for variables.

◆ calcInnerSurfaceFlux()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcInnerSurfaceFlux
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-07-24

Definition at line 6987 of file dgcartesiansolver.cpp.

6987 {
6988 TRACE();
6989 RECORD_TIMER_START(m_timers[Timers::Flux]);
6990 RECORD_TIMER_START(m_timers[Timers::FluxInner]);
6991
6992 const MInt begin = m_innerSurfacesOffset;
6995
6996 RECORD_TIMER_STOP(m_timers[Timers::FluxInner]);
6997 RECORD_TIMER_STOP(m_timers[Timers::Flux]);
6998}
void calcRegularSurfaceFlux(const MInt begin, const MInt end, SurfaceCollector &surf, F &riemannFct)
Calculate the numerical flux for a regular (i.e. inner or MPI) surface.

◆ calcMortarProjection()

template<MInt nDim, class SysEqn >
template<MBool forward, MInt noVars>
void DgCartesianSolver< nDim, SysEqn >::calcMortarProjection ( const MInt  srfcId,
const MInt  dir,
MFloat source,
MFloat destination,
ElementCollector elem,
SurfaceCollector surf 
)
private

Calculate the forward/reverse mortar projection.

Author
Sven Berger
Date
November 2014
Template Parameters
forwardTrue calculates the forward, false the reverse projection.
Parameters
[in]srfcIdSurface ID of the surface to be projected.
[in]dirDirection of the projection.
[in]sourcePointer to the values to be projected.
[out]destinationPointer to the destination of the result.
[in]elemPointer to elements.
[in]surfPointer to surfaces.

Definition at line 8498 of file dgcartesiansolver.cpp.

8503 {
8504 calcMortarProjectionH<forward, noVars>(srfcId, dir, source, destination, elem, surf);
8505 calcMortarProjectionP<forward, noVars>(srfcId, dir, source, destination, elem, surf);
8506}

◆ calcMortarProjectionH()

template<MInt nDim, class SysEqn >
template<MBool forward, MInt noVars>
void DgCartesianSolver< nDim, SysEqn >::calcMortarProjectionH ( const MInt  srfcId,
const MInt  dir,
MFloat source,
MFloat destination,
ElementCollector elem,
SurfaceCollector surf 
)
private
Author
Sven Berger
Date
March 2014
Parameters
[in]srfcIdSurface ID of the surface to be projected.
[in]dirDirection of the projection.
[in]sourcePointer to the values to be projected.
[out]destinationPointer to the destination of the result.
[in]elemPointer to elements.
[in]surfPointer to surfaces.

See also Chapter 3 in Sven Berger: Implementation and validation of an adaptive hp-refinement method for the discontinuous Galerkin spectral element method. Master thesis, RWTH Aachen University, 2014.

Definition at line 8618 of file dgcartesiansolver.cpp.

8623 {
8624 // TRACE(); //causes a huge performance hit
8625
8626 // Skip if this is not an h-refined surface
8627 const MInt side = 1 - dir % 2;
8628 const MInt elementId = surf.nghbrElementIds(srfcId, side);
8629 if(surf.fineCellId(srfcId) == -1 || surf.fineCellId(srfcId) == elem.cellId(elementId)) {
8630 return;
8631 }
8632
8633 // Determine polynomial degree(s) and number of nodes
8634 const MInt elementPolyDeg = elem.polyDeg(elementId);
8635 const MInt surfacePolyDeg = surf.polyDeg(srfcId);
8636 const MInt elementNoNodes1D = elem.noNodes1D(elementId);
8637 const MInt surfaceNoNodes1D = surf.noNodes1D(srfcId);
8638 const MInt noNodes1D = forward ? elementNoNodes1D : surfaceNoNodes1D;
8639 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
8640
8641 // Select source/destination storage
8642 MFloatTensor src(source, noNodes1D, noNodes1D3, noVars);
8643 MFloatTensor dest(destination, noNodes1D, noNodes1D3, noVars);
8644
8645 // Reset destination matrix to 0
8646 dest.set(0.0);
8647
8648 // Select correct projection matrix for h-refinement
8649 const MInt cellIdR = elem.cellId(elementId);
8650 const MInt cellIdL = surf.fineCellId(srfcId);
8651 const MInt orientation = surf.orientation(srfcId);
8652
8653 // Select projection matrix
8654 const MInt dirA = (orientation == 0) ? 1 : 0;
8655 const MInt positionA = (grid().tree().coordinate(cellIdR, dirA) < grid().tree().coordinate(cellIdL, dirA))
8658
8659 const MFloatMatrix pA(mortarH<forward>(noNodes1D, positionA), noNodes1D, noNodes1D);
8660
8661 // Apply projection
8662 IF_CONSTEXPR(nDim == 2) {
8663 // 2D version
8664 for(MInt i = 0; i < noNodes1D; i++) {
8665 for(MInt j = 0; j < noNodes1D; j++) {
8666 for(MInt var = 0; var < noVars; var++) {
8667 dest(i, 0, var) += src(j, 0, var) * pA(i, j);
8668 }
8669 }
8670 }
8671 }
8672 else {
8673 // 3D version
8674 // Select additional projection matrix
8675 const MInt dirB = (orientation == 2) ? 1 : 2;
8676 const MInt positionB = (grid().tree().coordinate(cellIdL, dirB) < grid().tree().coordinate(cellIdR, dirB))
8679
8680 const MFloatMatrix pB(mortarH<forward>(noNodes1D, positionB), noNodes1D, noNodes1D);
8681
8682 for(MInt i = 0; i < noNodes1D; i++) {
8683 for(MInt j = 0; j < noNodes1D; j++) {
8684 for(MInt k = 0; k < noNodes1D; k++) {
8685 for(MInt l = 0; l < noNodes1D; l++) {
8686 for(MInt var = 0; var < noVars; var++) {
8687 dest(i, j, var) += src(k, l, var) * pA(i, k) * pB(j, l);
8688 }
8689 }
8690 }
8691 }
8692 }
8693 }
8694
8695 // Copy results to source if p-projection is necessary
8696 // TODO labels:DG Move this p-refinement code out of a h-refinement method
8697 if(elementPolyDeg != surfacePolyDeg) {
8698 const MInt size = src.dim0() * src.dim1() * src.dim2();
8699 copy_n(&dest[0], size, &src[0]);
8700 }
8701}

◆ calcMortarProjectionP()

template<MInt nDim, class SysEqn >
template<MBool forward, MInt noVars>
void DgCartesianSolver< nDim, SysEqn >::calcMortarProjectionP ( const MInt  srfcId,
const MInt  dir,
MFloat source,
MFloat destination,
ElementCollector elem,
SurfaceCollector surf 
)
private
Author
Sven Berger
Date
March 2014
Parameters
[in]srfcIdSurface ID of the surface to be projected.
[in]dirDirection of the projection.
[in]sourcePointer to the values to be projected.
[out]destinationPointer to the destination of the result.
[in]elemPointer to elements.
[in]surfPointer to surfaces.

See also Chapter 3 in Sven Berger: Implementation and validation of an adaptive hp-refinement method for the discontinuous Galerkin spectral element method. Master thesis, RWTH Aachen University, 2014.

Definition at line 8527 of file dgcartesiansolver.cpp.

8532 {
8533 // TRACE();
8534
8535 // Skip if this is not a p-refined surface
8536 const MInt side = 1 - dir % 2;
8537 const MInt elementId = surf.nghbrElementIds(srfcId, side);
8538 const MInt elementPolyDeg = elem.polyDeg(elementId);
8539 const MInt surfacePolyDeg = surf.polyDeg(srfcId);
8540 if(elementPolyDeg == surfacePolyDeg) {
8541 return;
8542 }
8543
8544 // Calculate auxiliary variables for better readability
8545 const MInt surfaceNodes1D = surf.noNodes1D(srfcId);
8546 const MInt surfaceNodes1D3 = (nDim == 3) ? surfaceNodes1D : 1;
8547 const MInt elementNodes1D = elem.noNodes1D(elementId);
8548 const MInt elementNodes1D3 = (nDim == 3) ? elementNodes1D : 1;
8549
8550 MFloatTensor src;
8551 MFloatTensor dest;
8552
8553 if(forward) {
8554 src = MFloatTensor(source, elementNodes1D, elementNodes1D3, noVars);
8555 dest = MFloatTensor(destination, surfaceNodes1D, surfaceNodes1D3, noVars);
8556 } else {
8557 src = MFloatTensor(source, surfaceNodes1D, surfaceNodes1D3, noVars);
8558 dest = MFloatTensor(destination, surfaceNodes1D, surfaceNodes1D3, noVars);
8559 }
8560
8561 // Reset destination matrix to 0
8562 dest.set(0.0);
8563
8564 // Determine matrix sizes
8565 const MInt size0 = forward ? surfaceNodes1D : elementNodes1D;
8566 const MInt size1 = forward ? elementNodes1D : surfaceNodes1D;
8567
8568 // Select projection matrix
8569 MFloatMatrix p(mortarP<forward>(elementPolyDeg, surfacePolyDeg), size0, size1);
8570
8571
8572 // Apply projection
8573 IF_CONSTEXPR(nDim == 2) {
8574 // 2D version
8575 for(MInt i = 0; i < size0; i++) {
8576 for(MInt j = 0; j < size1; j++) {
8577 for(MInt var = 0; var < noVars; var++) {
8578 dest(i, 0, var) += src(j, 0, var) * p(i, j);
8579 }
8580 }
8581 }
8582 }
8583 else {
8584 // 3D version
8585 for(MInt i = 0; i < size0; i++) {
8586 for(MInt s = 0; s < size0; s++) {
8587 for(MInt j = 0; j < size1; j++) {
8588 for(MInt k = 0; k < size1; k++) {
8589 for(MInt var = 0; var < noVars; var++) {
8590 dest(i, s, var) += src(j, k, var) * p(i, j) * p(s, k);
8591 }
8592 }
8593 }
8594 }
8595 }
8596 }
8597}
void set(const T &value)
Initializes tensor to constant value.
Definition: tensor.h:271
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.
maia::tensor::Tensor< MFloat > MFloatTensor
Definition: tensor.h:1101

◆ calcMpiSurfaceFlux()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcMpiSurfaceFlux
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-07-24

Definition at line 7009 of file dgcartesiansolver.cpp.

7009 {
7010 TRACE();
7011 RECORD_TIMER_START(m_timers[Timers::Flux]);
7012 RECORD_TIMER_START(m_timers[Timers::FluxMPI]);
7013
7014 const MInt begin = m_mpiSurfacesOffset;
7017
7018 RECORD_TIMER_STOP(m_timers[Timers::FluxMPI]);
7019 RECORD_TIMER_STOP(m_timers[Timers::Flux]);
7020}

◆ calcRegularSurfaceFlux()

template<MInt nDim, class SysEqn >
template<class F >
void DgCartesianSolver< nDim, SysEqn >::calcRegularSurfaceFlux ( const MInt  begin,
const MInt  end,
SurfaceCollector surf,
F &  riemannFct 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-04-18
Parameters
[in]beginIndex of the first surface to consider.
[in]endIndex+1 of the last surface to consider.
[in]surfPointer to surfaces.
[in]riemannFctObject which provides the calcRiemann() function used to compute the numerical flux.

Definition at line 970 of file dgcartesiansolver.h.

973 {
974 TRACE();
975
976#ifdef _OPENMP
977#pragma omp parallel for
978#endif
979 // Loop over all surfaces, calculate the numerical flux
980 for(MInt srfcId = begin; srfcId < end; srfcId++) {
981 MFloat* flux = &surf.flux(srfcId);
982 MFloat* nodeVarsL = &surf.nodeVars(srfcId, 0);
983 MFloat* nodeVarsR = &surf.nodeVars(srfcId, 1);
984 MFloat* stateL = &surf.variables(srfcId, 0);
985 MFloat* stateR = &surf.variables(srfcId, 1);
986 const MInt noNodes1D = surf.noNodes1D(srfcId);
987 const MInt dirId = surf.orientation(srfcId);
988
989 riemannFct.calcRiemann(nodeVarsL, nodeVarsR, stateL, stateR, noNodes1D, dirId, flux);
990 }
991}

◆ calcSamplingVarAtPoint()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcSamplingVarAtPoint ( const MFloat point,
const MInt  elementId,
const MInt  sampleVarId,
MFloat state,
const MBool  interpolate 
)
override

Definition at line 8288 of file dgcartesiansolver.cpp.

8290 {
8291 switch(sampleVarId) {
8292 case DG_VARS: {
8293 // Evaluate solution state
8294 calcStateAtPoint(point, elementId, state);
8295 break;
8296 }
8297 case DG_NODEVARS: {
8298 // Evaluate node variables
8299 calcStateAtPoint(point, elementId, SysEqn::noNodeVars(), &m_elements.nodeVars(elementId), state);
8300 break;
8301 }
8302 case DG_SOURCETERMS: {
8303 // Evaluate external source terms
8304 calcStateAtPoint(point, elementId, SysEqn::noVars(), &m_elements.externalSource(elementId), state);
8305 break;
8306 }
8307 default: {
8308 TERMM(1, "sampling variable not supported");
8309 }
8310 }
8311}
MBool calcStateAtPoint(const MFloat *point, MFloat *state)
returns the cellId of a cell containing a given point
MFloat & nodeVars(const MInt id)
Accessor for node variables.
@ DG_SOURCETERMS
Definition: enums.h:385
@ DG_VARS
Definition: enums.h:385
@ DG_NODEVARS
Definition: enums.h:385

◆ calcSamplingVariables()

template<MInt nDim, class SysEqn >
virtual void DgCartesianSolver< nDim, SysEqn >::calcSamplingVariables ( const std::vector< MInt > &  NotUsedvarIds,
const MBool   NotUsedexchange 
)
inlinevirtual

Reimplemented from Solver.

Definition at line 329 of file dgcartesiansolver.h.

329{};

◆ calcSourceTerms() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcSourceTerms ( MFloat  t)
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-12-13

Definition at line 7320 of file dgcartesiansolver.cpp.

7320 {
7321 TRACE();
7322 RECORD_TIMER_START(m_timers[Timers::Sources]);
7323
7325
7326 RECORD_TIMER_STOP(m_timers[Timers::Sources]);
7327}

◆ calcSourceTerms() [2/2]

template<MInt nDim, class SysEqn >
template<class F >
void DgCartesianSolver< nDim, SysEqn >::calcSourceTerms ( MFloat  t,
const MInt  noElements,
ElementCollector elem,
F &  sourceFct 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-12-23
Parameters
[in]tCurrent time.
[in]noElementsNumber of elements.
[in]elemPointer to elements.
[in]sourceFctObject which provides the calcSource() function used to calculate the source terms.

Definition at line 1009 of file dgcartesiansolver.h.

1012 {
1013 TRACE();
1014
1015 const MInt* const noNodes1D = &elem.noNodes1D(0);
1016
1017 const MInt maxDataBlockSize = ipow(m_maxNoNodes1D, nDim) * SysEqn::noVars();
1018 std::vector<MFloat> sources(maxDataBlockSize);
1019
1020#ifdef _OPENMP
1021#pragma omp parallel for firstprivate(sources)
1022#endif
1023 for(MInt elementId = 0; elementId < noElements; elementId++) {
1024 const MInt noNodesXD = elem.noNodesXD(elementId);
1025 const MInt dataBlockSize = noNodesXD * SysEqn::noVars();
1026 sourceFct.calcSource(&elem.nodeVars(elementId), &elem.variables(elementId), noNodes1D[elementId], t,
1027 &elem.nodeCoordinates(elementId), &sources[0]);
1028
1029 MFloat* const rhs = &elem.rightHandSide(elementId);
1030 for(MInt dataId = 0; dataId < dataBlockSize; dataId++) {
1031 rhs[dataId] += sources[dataId];
1032 }
1033 }
1034}

◆ calcStateAtPoint() [1/3]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcStateAtPoint ( const MFloat point,
const MInt  elementId,
const MInt  noVars,
const MFloat *const  u,
MFloat state 
)
private
Author
Vitali Pauz v.pau.nosp@m.z@ai.nosp@m.a.rwt.nosp@m.h-aa.nosp@m.chen..nosp@m.de
Date
24.01.2014
Parameters
[in]pointEvaluation point.
[in]elementIdElement ID of the evaluation point.
[in]noVarsNumber of variables of given element data field.
[in]uElement data field to evaluate.
[out]stateState vector at a given point.

state should have the dimension 'noVars'.

Definition at line 8171 of file dgcartesiansolver.cpp.

8172 {
8173 TRACE();
8174
8175 const MInt cellId = m_elements.cellId(elementId);
8176 const MInt polyDeg = m_elements.polyDeg(elementId);
8177 const MInt noNodes1D = m_elements.noNodes1D(elementId);
8178 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
8179 const DgInterpolation& interp = m_interpolation[polyDeg][noNodes1D];
8180
8181 const MFloat cellLength = grid().cellLengthAtCell(cellId);
8182
8183 // Vector saves the point with coordinates on the interval [17,1]
8184 MFloat pointOnUnitInt[nDim];
8185
8186 const MFloatTensor U(const_cast<MFloat*>(u), noNodes1D, noNodes1D, noNodes1D3, noVars);
8187
8188 // Because Lagrangefunctions are only defined on the interval [-1,1]
8189 // the coordinates are transformed to the interval.
8190 for(MInt n = 0; n < nDim; n++) {
8191 pointOnUnitInt[n] = F2 * (point[n] - grid().tree().coordinate(cellId, n)) / cellLength;
8192 }
8193
8194 if(m_sbpMode) {
8195 IF_CONSTEXPR(nDim == 2) {
8196 dg::interpolation::calcBilinearInterpolation(pointOnUnitInt, &interp.m_nodes[0], noNodes1D, noVars, u, state);
8197 }
8198 else {
8199 dg::interpolation::calcTrilinearInterpolation(pointOnUnitInt, &interp.m_nodes[0], noNodes1D, noVars, u, state);
8200 }
8201 } else {
8202 /*
8203 * Transform the coordinates of the Point to the intervall [-1,1]:
8204 * P(x,y,z) --> P(xi, eta, mu)
8205 *
8206 * To calculate the state Q at a Point P we use the interpolation formula:
8207 * Q(x,y,z) = Q(x(xi), y(eta), z(mu))
8208 * = \Sum_{i,j,k}^{N} q_{ijk} * l_i(xi) * l_j(eta) * l_k(mu)
8209 **/
8210
8211 MFloatVector lagrangePoly[nDim];
8212 for(MInt n = 0; n < nDim; n++) {
8213 lagrangePoly[n].resize(noNodes1D);
8214 fill_n(&lagrangePoly[n][0], noNodes1D, F0);
8215 }
8216
8217 for(MInt n = 0; n < nDim; n++) {
8218 dg::interpolation::calcLagrangeInterpolatingPolynomials(pointOnUnitInt[n], polyDeg, &interp.m_nodes[0],
8219 &interp.m_wBary[0], &lagrangePoly[n][0]);
8220 }
8221
8222 fill_n(state, noVars, 0.0);
8223
8224 IF_CONSTEXPR(nDim == 2) {
8225 for(MInt i = 0; i < noNodes1D; i++) {
8226 for(MInt j = 0; j < noNodes1D; j++) {
8227 for(MInt k = 0; k < noNodes1D3; k++) {
8228 for(MInt v = 0; v < noVars; v++) {
8229 state[v] += U(i, j, k, v) * lagrangePoly[0][i] * lagrangePoly[1][j];
8230 }
8231 }
8232 }
8233 }
8234 }
8235 else { // nDim == 3
8236 for(MInt i = 0; i < noNodes1D; i++) {
8237 for(MInt j = 0; j < noNodes1D; j++) {
8238 for(MInt k = 0; k < noNodes1D3; k++) {
8239 for(MInt v = 0; v < noVars; v++) {
8240 state[v] += U(i, j, k, v) * lagrangePoly[0][i] * lagrangePoly[1][j] * lagrangePoly[2][k];
8241 }
8242 }
8243 }
8244 }
8245 }
8246 }
8247}
size_type resize(size_type n0, size_type n1=1, size_type n2=1, size_type n3=1, size_type n4=1)
Deletes the old data structure and creates a new one with the requested dimensions.
Definition: tensor.h:230
void calcTrilinearInterpolation(MFloat *point, const MFloat *nodes, const MInt noNodes, const MInt noVars, const MFloat *u, MFloat *const out)
Calculates trilinear interpolation at given point (3D)
void calcLagrangeInterpolatingPolynomials(const MFloat x, const MInt polyDeg, const MFloat *nodes, const MFloat *wBary, MFloat *polynomials)
Calculates the values of the Lagrangian polynomials l_j for a given point x in [-1,...
void calcBilinearInterpolation(MFloat *point, const MFloat *nodes, const MInt noNodes, const MInt noVars, const MFloat *u, MFloat *const out)
Calculates bilinear interpolation at given point (2D)

◆ calcStateAtPoint() [2/3]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcStateAtPoint ( const MFloat point,
const MInt  elementId,
MFloat state 
)
private

Calculate the state variables at a given point in an element

Definition at line 8279 of file dgcartesiansolver.cpp.

8281 {
8282 calcStateAtPoint(point, elementId, SysEqn::noVars(), &m_elements.variables(elementId), state);
8283}

◆ calcStateAtPoint() [3/3]

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::calcStateAtPoint ( const MFloat point,
MFloat state 
)
private
Author
Vitali Pauz v.pau.nosp@m.z@ai.nosp@m.a.rwt.nosp@m.h-aa.nosp@m.chen..nosp@m.de
Date
24.01.2014
Parameters
[in]pointEvaluation point.
[out]returnscellId.

Calculates the state vector at a given Point.

Author
Fabian Klemp f.kle.nosp@m.mp@a.nosp@m.ia.rw.nosp@m.th-a.nosp@m.achen.nosp@m..de
Date
2016-07-22
Parameters
[in]pointEvaluation point.
[out]stateState vector at a given point.

state should have the dimension SysEqn::noVars();

Definition at line 8143 of file dgcartesiansolver.cpp.

8143 {
8144 TRACE();
8145 const MInt elementId = getElementIdAtPoint(point);
8146
8147 if(elementId == -1) {
8148 return false;
8149 }
8150
8151 calcStateAtPoint(point, elementId, state);
8152
8153 return true;
8154}
MInt getElementIdAtPoint(const MFloat *point, MBool globalUnique=false)
returns the elementId of a element containing a given point

◆ calcSurfaceIntegral() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcSurfaceIntegral
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2014-02-07

Definition at line 7029 of file dgcartesiansolver.cpp.

7029 {
7030 TRACE();
7031 RECORD_TIMER_START(m_timers[Timers::SurfInt]);
7032
7034
7035 RECORD_TIMER_STOP(m_timers[Timers::SurfInt]);
7036}

◆ calcSurfaceIntegral() [2/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcSurfaceIntegral ( const MInt  begin,
const MInt  end,
ElementCollector elem,
SurfaceCollector surf,
HElementCollector helem,
const MInt  noHElements 
)
private
Author
Michael Schlottke, Sven Berger
Date
2014-02-07
Parameters
[in]beginIndex of the first element to consider.
[in]endIndex+1 of the last element to consider.
[in]elemPointer to elements.
[in]surfPointer to surfaces.
[in]helemPointer to h-elements.
[in]noHElementsNumber of h-elements.
  1. Calculate surface integral for all surfaces except for the coarse element side of h-refined surfaces.
  2. Calculate surface integral for h-refined surfaces.

Definition at line 7051 of file dgcartesiansolver.cpp.

7056 {
7057 TRACE();
7058
7059 const MInt noVars = SysEqn::noVars();
7060 const MInt* surfaceIds = &elem.surfaceIds(0, 0);
7061
7066
7067#ifdef _OPENMP
7068#pragma omp parallel for
7069#endif
7070 // Loop over all elements and calculate surface integrals
7071 for(MInt elementId = begin; elementId < end; elementId++) {
7072 const MInt surfaceIdOffset = elementId * 2 * nDim;
7073
7074 for(MInt dir = 0; dir < 2 * nDim; dir++) {
7075 // Calculate auxiliary variables for better readability
7076 const MInt srfcId = surfaceIds[surfaceIdOffset + dir];
7077 const MInt srfcPolyDeg = surf.polyDeg(srfcId);
7078 const MInt srfcNodes1D = surf.noNodes1D(srfcId);
7079 const MInt srfcNodes1D3 = (nDim == 3) ? srfcNodes1D : 1;
7080 const MInt polyDeg = elem.polyDeg(elementId);
7081 const MInt noNodes1D = elem.noNodes1D(elementId);
7082 MFloatTensor f(&surf.flux(srfcId), srfcNodes1D, srfcNodes1D3, noVars);
7083
7084 const MInt side = 1 - dir % 2;
7085
7086 // Skip coarse surfaces they need to be handled separately
7087 if(surf.fineCellId(srfcId) != -1 && surf.fineCellId(srfcId) != elem.cellId(elementId)) {
7088 continue;
7089 }
7090
7091 // Pure p-refinement case (srfcPolyDeg is never small than polyDeg)
7092 if(srfcPolyDeg > polyDeg) {
7093 MFloatTensor fp(srfcNodes1D, srfcNodes1D3, noVars);
7094
7095 // Calculate reverse projection
7096 calcMortarProjection<dg::mortar::reverse, SysEqn::noVars()>(srfcId, dir, &f[0], &fp[0], elem, surf);
7097
7098 // Use projected flux for integration
7099 applySurfaceIntegral(&elem.rightHandSide(elementId), polyDeg, noNodes1D, srfcId, side, &fp[0], surf);
7100
7101 } else {
7102 // Use original flux for integration
7103 applySurfaceIntegral(&elem.rightHandSide(elementId), polyDeg, noNodes1D, srfcId, side, &f[0], surf);
7104 }
7105 }
7106 }
7107
7111 if(noHElements > 0) {
7112 const MInt noDirs = 2 * nDim;
7113 const MInt noSurfs = 2 * (nDim - 1);
7114
7115#ifdef _OPENMP
7116#pragma omp parallel for
7117#endif
7118 for(MInt hElementId = 0; hElementId < noHElements; hElementId++) {
7119 const MInt coarseElementId = helem.elementId(hElementId);
7120 const MInt polyDeg = elem.polyDeg(coarseElementId);
7121 const MInt noNodes1D = elem.noNodes1D(coarseElementId);
7122
7123 for(MInt dir = 0; dir < noDirs; dir++) {
7124 const MInt coarseSrfcId = elem.surfaceIds(coarseElementId, dir);
7125
7126 for(MInt pos = 0; pos < noSurfs; pos++) {
7127 const MInt hSrfcId = helem.hrefSurfaceIds(hElementId, dir, pos);
7128 const MInt side = 1 - dir % 2;
7129
7130 // Skip if this surface does not exist
7131 if(hSrfcId == -1) {
7132 continue;
7133 }
7134
7135 const MInt srfcNodes1D = surf.noNodes1D(hSrfcId);
7136 const MInt srfcNodes1D3 = (nDim == 3) ? srfcNodes1D : 1;
7137 MFloatTensor f(&surf.flux(hSrfcId), srfcNodes1D, srfcNodes1D3, noVars);
7138 MFloatTensor fp(srfcNodes1D, srfcNodes1D3, noVars);
7139
7140 // Calculate reverse projection
7141 calcMortarProjection<dg::mortar::reverse, SysEqn::noVars()>(hSrfcId, dir, &f[0], &fp[0], elem, surf);
7142
7143 // Use projected flux for integration
7144 applySurfaceIntegral(&elem.rightHandSide(coarseElementId), polyDeg, noNodes1D, coarseSrfcId, side, &fp[0],
7145 surf);
7146 }
7147 }
7148 }
7149 }
7150}
void applySurfaceIntegral(MFloat *rhs, const MInt polyDeg, const MInt noNodes1D, const MInt srfcId, const MInt side, const MFloat *flux, SurfaceCollector &surf)
Calculate the surface integral for a face of an element and update dU/dt.

◆ calcSurfaceNodeCoordinates()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcSurfaceNodeCoordinates ( const MInt  surfaceId)
private

Definition at line 3905 of file dgcartesiansolver.cpp.

3905 {
3906 const MInt internalSide = (m_surfaces.internalSideId(srfcId) <= 0) ? 0 : 1;
3907 const MInt elementId = m_surfaces.nghbrElementIds(srfcId, internalSide);
3908 const MInt cellId = m_elements.cellId(elementId);
3909
3910 // Compute surface node coordinates
3911 const MInt polyDeg = m_surfaces.polyDeg(srfcId);
3912 const MInt noNodes1D = m_surfaces.noNodes1D(srfcId);
3913 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
3914 const MFloat length = grid().cellLengthAtCell(cellId);
3915 MFloatTensor nodeCoordinates(&m_surfaces.nodeCoords(srfcId), noNodes1D, noNodes1D3, nDim);
3916
3917 // Iterate over all nodes and set the coordinates
3918 // Node coordinates = surface center
3919 // + (1/2 element length * normalized ([-1,1]) node coordinate)
3920 switch(m_surfaces.orientation(srfcId)) {
3921 case 0: // x-direction
3922 for(MInt j = 0; j < noNodes1D; j++) {
3923 for(MInt k = 0; k < noNodes1D3; k++) {
3924 nodeCoordinates(j, k, 0) = m_surfaces.coords(srfcId, 0);
3925 nodeCoordinates(j, k, 1) =
3926 m_surfaces.coords(srfcId, 1) + F1B2 * length * m_interpolation[polyDeg][noNodes1D].m_nodes[j];
3927 IF_CONSTEXPR(nDim == 3) {
3928 nodeCoordinates(j, k, 2) =
3929 m_surfaces.coords(srfcId, 2) + F1B2 * length * m_interpolation[polyDeg][noNodes1D].m_nodes[k];
3930 }
3931 }
3932 }
3933 break;
3934
3935 case 1: // y-direction
3936 for(MInt i = 0; i < noNodes1D; i++) {
3937 for(MInt k = 0; k < noNodes1D3; k++) {
3938 nodeCoordinates(i, k, 0) =
3939 m_surfaces.coords(srfcId, 0) + F1B2 * length * m_interpolation[polyDeg][noNodes1D].m_nodes[i];
3940 nodeCoordinates(i, k, 1) = m_surfaces.coords(srfcId, 1);
3941 IF_CONSTEXPR(nDim == 3) {
3942 nodeCoordinates(i, k, 2) =
3943 m_surfaces.coords(srfcId, 2) + F1B2 * length * m_interpolation[polyDeg][noNodes1D].m_nodes[k];
3944 }
3945 }
3946 }
3947 break;
3948
3949 case 2: // z-direction
3950 for(MInt i = 0; i < noNodes1D; i++) {
3951 for(MInt j = 0; j < noNodes1D3; j++) {
3952 nodeCoordinates(i, j, 0) =
3953 m_surfaces.coords(srfcId, 0) + F1B2 * length * m_interpolation[polyDeg][noNodes1D].m_nodes[i];
3954 nodeCoordinates(i, j, 1) =
3955 m_surfaces.coords(srfcId, 1) + F1B2 * length * m_interpolation[polyDeg][noNodes1D].m_nodes[j];
3956 IF_CONSTEXPR(nDim == 3) { nodeCoordinates(i, j, 2) = m_surfaces.coords(srfcId, 2); }
3957 }
3958 }
3959 break;
3960
3961 default:
3962 mTerm(1, AT_, "Bad orientation");
3963 }
3964}
MFloat & nodeCoords(const MInt srfcId)
Accessor for node coordinates.
MInt & orientation(const MInt srfcId)
Accessor for orientation.
MFloat & coords(const MInt srfcId, const MInt dir)
Accessor for coordinates.

◆ calcTimeStep()

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::calcTimeStep
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-04-26
Returns
The new time step size.

Definition at line 7587 of file dgcartesiansolver.cpp.

7587 {
7588 TRACE();
7589 RECORD_TIMER_START(m_timers[Timers::CalcTimeStep]);
7590
7591 MFloat minDt = numeric_limits<MFloat>::infinity();
7592
7593 // First check if external coupling overrides the time step calculation
7594 const MBool forcedTimeStep = (m_externalDt > 0.0);
7595
7596 // Time step calculation (if forced to check that the external dt is small enough)
7597 {
7598 // Calculate time step from system of equations class
7599 const MInt noElements = m_elements.size();
7600 const MInt* noNodes1D = &m_elements.noNodes1D(0);
7601 const MFloat* invJacobians = &m_elements.invJacobian(0);
7602
7603#ifdef _OPENMP
7604#pragma omp parallel for reduction(min : minDt)
7605#endif
7606 for(MInt elementId = 0; elementId < noElements; elementId++) {
7607 MFloat ts = m_sysEqn.getTimeStep(&m_elements.nodeVars(elementId), &m_elements.variables(elementId),
7608 noNodes1D[elementId], invJacobians[elementId], m_sbpMode);
7609 minDt = min(minDt, ts);
7610 }
7611 }
7612
7613 if(forcedTimeStep) {
7614 if(m_externalDt > minDt) {
7615 cerr << " WARNING: external dt larger than computed time step size on global domain " << globalDomainId() << "("
7616 << m_externalDt << " > " << minDt << ")" << std::endl;
7617 }
7618 // Calculate global minimum computed time step
7619 MPI_Allreduce(MPI_IN_PLACE, &minDt, 1, type_traits<MFloat>::mpiType(), MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
7620 "minDt");
7621 m_log << "DG-Solver #" << solverId() << " using external time step size: " << m_externalDt
7622 << " (computed global minimum: " << minDt << ")" << std::endl;
7623 minDt = m_externalDt;
7624 }
7625
7626 // Check for NaN in time step
7627 if(std::isnan(minDt)) {
7628 TERMM(1,
7629 "Time step is NaN at time step " + to_string(m_timeStep) + " on global domain "
7630 + to_string(globalDomainId()));
7631 }
7632
7633 // Check negative time step
7634 if(minDt < 0.0) {
7635 TERMM(1,
7636 "Time step is less than zero at time step " + to_string(m_timeStep) + " on global domain "
7637 + to_string(globalDomainId()));
7638 }
7639
7640 // Check ridiculuously small time step that indicates *most probably* an error
7641 // Note: the threshold here was arbitrarily chosen, but seemed "low enough"
7642 if(minDt < 1.0e-100) {
7643 TERMM(1,
7644 "Time step is less than 1.0e-100 at time step " + to_string(m_timeStep) + " on global domain "
7645 + to_string(globalDomainId()));
7646 }
7647
7648 // Calculate global minimum time step
7649 MPI_Allreduce(MPI_IN_PLACE, &minDt, 1, type_traits<MFloat>::mpiType(), MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
7650 "minDt");
7651
7652 RECORD_TIMER_STOP(m_timers[Timers::CalcTimeStep]);
7653
7654 return minDt;
7655}

◆ calculateHeatRelease()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calculateHeatRelease ( )
inline

Definition at line 123 of file dgcartesiansolver.h.

123{ std::cerr << "calculateHeatRelease DgCartesianSolver " << std::endl; }

◆ calculateNeededNoSurfaces()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::calculateNeededNoSurfaces
private
Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-11-27
Returns
The number of needed DG surfaces.

Definition at line 2398 of file dgcartesiansolver.cpp.

2398 {
2399 TRACE();
2400
2401 // Loop over all internal cells
2402 MInt noSurfaces = 0;
2403 for(MInt cellId = 0; cellId < grid().noInternalCells(); cellId++) {
2404 // Skip cell if it is not a leaf cell (i.e. if it has child cells)
2405 if(grid().tree().hasChildren(cellId)) {
2406 continue;
2407 }
2408
2409 // Loop over all directions to check if surfaces need to be created
2410 for(MInt dir = 0; dir < 2 * nDim; dir++) {
2411 if(!grid().tree().hasNeighbor(cellId, dir)) {
2412 // If it does not have a neighbor, cell is boundary cell or neighbor is
2413 // coarse, thus one surface is needed
2414 noSurfaces++;
2415 } else {
2416 // Otherwise check if surface needs to be created
2417 const MInt neighborId = grid().tree().neighbor(cellId, dir);
2418 const MBool neighborIsHalo = (neighborId >= grid().noInternalCells());
2419
2420 if(grid().tree().hasChildren(neighborId)) {
2421 // Neighbor is refined
2422 if(neighborIsHalo) {
2423 // Only create surface towards refined cells if neighbor is halo
2424 // cell (in this case 2 ^ (nDim - 1) surfaces are needed). This
2425 // slightly overestimates the actual number of needed surfaces in
2426 // case no all refined cells exist
2427 noSurfaces += IPOW2(nDim - 1);
2428 }
2429 } else {
2430 // Neighbor is at same level
2431 if(dir % 2 == 1 || neighborIsHalo) {
2432 // Count surfaces only in positive direction or if neighbor is halo
2433 // cell
2434 noSurfaces++;
2435 }
2436 }
2437 }
2438 }
2439 }
2440
2441 return noSurfaces;
2442}
constexpr MLong IPOW2(MInt x)

◆ calcVolumeIntegral() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::calcVolumeIntegral
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-12-13

Definition at line 6944 of file dgcartesiansolver.cpp.

6944 {
6945 TRACE();
6946 RECORD_TIMER_START(m_timers[Timers::VolInt]);
6947
6949
6950 RECORD_TIMER_STOP(m_timers[Timers::VolInt]);
6951}

◆ calcVolumeIntegral() [2/2]

template<MInt nDim, class SysEqn >
template<class F >
void DgCartesianSolver< nDim, SysEqn >::calcVolumeIntegral ( const MInt  noElements,
ElementCollector elem,
F &  fluxFct 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-04-18
Parameters
[in]noElementsNumber of elements.
[in]elemPointer to elements.
[in]fluxFctObject which provides the calcFlux() function used to compute the physical flux.

Definition at line 894 of file dgcartesiansolver.h.

894 {
895 TRACE();
896
897 const MInt noVars = SysEqn::noVars();
898 const MInt* const polyDegs = &elem.polyDeg(0);
899 const MInt* const noNodes = &elem.noNodes1D(0);
900
901 // Create temporary storage for flux values
902 const MInt maxNoNodesXD = elem.maxNoNodesXD();
903 std::vector<MFloat> flux(maxNoNodesXD * noVars * nDim);
904
905#ifdef _OPENMP
906#pragma omp parallel for firstprivate(flux)
907#endif
908 for(MInt elementId = 0; elementId < noElements; elementId++) {
909 const MInt polyDeg = polyDegs[elementId];
910 const MInt noNodes1D = noNodes[elementId];
911 const MFloat* const dhat = &m_interpolation[polyDeg][noNodes1D].m_Dhat[0];
912 MFloat* const ut = &elem.rightHandSide(elementId);
913 MInt index = 0;
914
915 // Calculate flux
916 fluxFct.calcFlux(&elem.nodeVars(elementId), &elem.variables(elementId), noNodes1D, &flux[0]);
917
918 IF_CONSTEXPR(nDim == 2) {
919 // Copy flux to time derivative
920 MFloatTensor f(&flux[0], noNodes1D, noNodes1D, nDim, noVars);
921 for(MInt i = 0; i < noNodes1D; i++) {
922 for(MInt j = 0; j < noNodes1D; j++) {
923 for(MInt n = 0; n < noVars; n++) {
924 // auto df = 0.0;
925 for(MInt l = 0; l < noNodes1D; l++) {
926 ut[index] += dhat[i * noNodes1D + l] * f(l, j, 0, n) + dhat[j * noNodes1D + l] * f(i, l, 1, n);
927 }
928 index++;
929 }
930 }
931 }
932 }
933 else IF_CONSTEXPR(nDim == 3) {
934 // Copy flux to time derivative
935 MFloatTensor f(&flux[0], noNodes1D, noNodes1D, noNodes1D, nDim, noVars);
936
937 for(MInt i = 0; i < noNodes1D; i++) {
938 for(MInt j = 0; j < noNodes1D; j++) {
939 for(MInt k = 0; k < noNodes1D; k++) {
940 for(MInt n = 0; n < noVars; n++) {
941 for(MInt l = 0; l < noNodes1D; l++) {
942 ut[index] += dhat[i * noNodes1D + l] * f(l, j, k, 0, n) + dhat[j * noNodes1D + l] * f(i, l, k, 1, n)
943 + dhat[k * noNodes1D + l] * f(i, j, l, 2, n);
944 }
945 index++;
946 }
947 }
948 }
949 }
950 }
951 }
952}

◆ cancelMpiRequests()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::cancelMpiRequests
overrideprivatevirtual
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2018-10-17

Cancel opened receive request that do not have a matching send initiated yet. Note: canceling send requests might cause MPI errors depending on the MPI implementation.

Reimplemented from Solver.

Definition at line 4418 of file dgcartesiansolver.cpp.

4418 {
4419 TRACE();
4420
4421 // Complete already started communication in split-MPI mode
4423 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
4424 RECORD_TIMER_START(m_timers[Timers::RungeKuttaStep]);
4425 RECORD_TIMER_START(m_timers[Timers::TimeDeriv]);
4427 RECORD_TIMER_STOP(m_timers[Timers::TimeDeriv]);
4428 RECORD_TIMER_STOP(m_timers[Timers::RungeKuttaStep]);
4429 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
4430
4431 // Wait for send requests to finish
4432 MPI_Waitall(m_noExchangeNghbrDomains, &m_sendRequests[0], MPI_STATUSES_IGNORE, AT_);
4433 m_mpiSendRequestsOpen = false;
4434 }
4435
4436 // Cancel opened receive requests
4438 std::vector<MBool> waitForCancel(m_noExchangeNghbrDomains, false);
4439 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4440 if(m_recvRequests[i] != MPI_REQUEST_NULL) {
4441 MPI_Cancel(&m_recvRequests[i], AT_);
4442 waitForCancel[i] = true;
4443 }
4444 }
4445 // Wait for all requests until they are canceled
4446 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4447 if(waitForCancel[i]) {
4448 MPI_Wait(&m_recvRequests[i], MPI_STATUS_IGNORE, AT_);
4449 }
4450 }
4451 m_mpiRecvRequestsOpen = false;
4452 }
4453}
std::vector< MPI_Request > m_recvRequests
std::vector< MPI_Request > m_sendRequests
int MPI_Cancel(MPI_Request *request, const MString &name)
same as MPI_cancel
int MPI_Wait(MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Wait
int MPI_Waitall(int count, MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Waitall

◆ cellDataSizeDlb()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::cellDataSizeDlb ( const MInt  dataId,
const MInt  gridCellId 
)
override
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Parameters
[in]dataIdData id of requested cell data.
[in]gridCellIdRequested grid cell id.
Returns
Data size of requested cell data for given cell.

Definition at line 9584 of file dgcartesiansolver.cpp.

9584 {
9585 TRACE();
9586
9587 // Inactive ranks do not have any data to communicate
9588 if(!isActive()) {
9589 return 0;
9590 }
9591
9592 // Convert to solver cell id and check
9593 const MInt cellId = grid().tree().grid2solver(gridCellId);
9594 if(cellId < 0) {
9595 return 0;
9596 }
9597
9598 MInt dataSize = 0;
9599
9600 if(dataId > -1 && dataId < noDgCartesianSolverCellData()) {
9601 // DG solver cell data
9602 const MInt elementId = m_elements.getElementByCellId(cellId);
9603
9604 if(elementId != -1) {
9605 const MInt noNodesXD = m_elements.noNodesXD(elementId);
9606 switch(dataId) {
9609 dataSize = 1;
9610 break;
9612 dataSize = 1;
9613 break;
9615 dataSize = noNodesXD * SysEqn::noVars();
9616 break;
9618 dataSize = noNodesXD * SysEqn::noNodeVars();
9619 break;
9620 default:
9621 TERMM(1, "Unknown data id. (" + to_string(dataId) + ")");
9622 break;
9623 }
9624 }
9625 } else if(dataId >= noDgCartesianSolverCellData() && dataId < noCellDataDlb()) {
9626 // Boundary condition cell data
9628 for(auto&& bc : m_boundaryConditions) {
9629 const MInt bcNoCellData = bc->noCellDataDlb();
9630 if(dataId >= offset && dataId < offset + bcNoCellData) {
9631 dataSize = bc->cellDataSizeDlb(dataId - offset, cellId);
9632 break;
9633 }
9634 offset += bcNoCellData;
9635 }
9636 } else {
9637 TERMM(1, "The requested dataId is not valid.");
9638 }
9639
9640 return dataSize;
9641}
MInt noDgCartesianSolverCellData() const
MInt noCellDataDlb() const override
Methods to inquire solver data information.
MInt getElementByCellId(const MInt cellId) const
Return element id for a given cell id (or -1 if not found).
static constexpr const MInt ELEM_NO_NODES_1D
static constexpr const MInt ELEM_CELL_ID
static constexpr const MInt ELEM_NODE_VARS
static constexpr const MInt ELEM_VARIABLES
static constexpr const MInt ELEM_POLY_DEG

◆ cellDataTypeDlb()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::cellDataTypeDlb ( const MInt  dataId) const
override
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Parameters
[in]dataIdData id of requested cell data.
Returns
Data type of cell data.

Definition at line 9544 of file dgcartesiansolver.cpp.

9544 {
9545 TRACE();
9546
9547 if(!isActive()) {
9548 TERMM(1, "Error: cellDataTypeDlb() might give wrong results on inactive ranks.");
9549 return -1;
9550 }
9551
9552 MInt dataType = -1;
9553 if(dataId > -1 && dataId < noDgCartesianSolverCellData()) {
9554 // DG solver cell data
9555 dataType = s_cellDataTypeDlb[dataId];
9556 } else if(dataId >= noDgCartesianSolverCellData() && dataId < noCellDataDlb()) {
9557 // Boundary condition cell data
9559 for(auto&& bc : m_boundaryConditions) {
9560 const MInt bcNoCellData = bc->noCellDataDlb();
9561 if(dataId >= offset && dataId < offset + bcNoCellData) {
9562 dataType = bc->cellDataTypeDlb(dataId - offset);
9563 break;
9564 }
9565 offset += bcNoCellData;
9566 }
9567 } else {
9568 TERMM(1, "The requested dataId is not valid: " + to_string(dataId) + " (" + to_string(noDgCartesianSolverCellData())
9569 + ", " + to_string(noCellDataDlb()) + ")");
9570 }
9571
9572 return dataType;
9573}
static const std::array< MInt, CellData::count > s_cellDataTypeDlb

◆ checkCellProperties()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::checkCellProperties
private
Author
Michael Schlottke-Lakemper
Date
November 2017

Definition at line 2870 of file dgcartesiansolver.cpp.

2870 {
2871 TRACE();
2872
2873 m_log << "Initializing cell properties... ";
2874
2875 const MInt noCells = grid().noCells();
2876
2877 // Make sure that all cells that are not internal cells are marked as halo, as this is an
2878 // implicit assumption used throughout the solver
2879 for(MInt c = grid().noInternalCells(); c < noCells; c++) {
2880 if(!grid().tree().hasProperty(c, Cell::IsHalo)) {
2881 TERMM(1, "Cell " + to_string(c) + " should be marked as a halo cell");
2882 }
2883 }
2884
2885 m_log << "done" << endl;
2886}
MInt noInternalCells() const override
Return the number of internal cells within this solver.

◆ checkGridMap()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::checkGridMap ( const MString donorGridFileName)
private
Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-11-04
Parameters
[in]donorGridFileNameName of donor grid file.

Note: tests should be sorted by increasing test time, i.e. simpler tests should go first.

Definition at line 2157 of file dgcartesiansolver.cpp.

2157 {
2158 TRACE();
2159
2160 //------------------------------
2161 //------------------------------
2162 //------------------------------
2163 if(domainId() == 0) {
2164 cerr << "Warning: DgCartesianSolver::checkGridMap deactivated! (fix coordinate comparison)" << endl;
2165 }
2166 return;
2167 //------------------------------
2168 //------------------------------
2169 //------------------------------
2170
2171 m_log << "Checking grip map for donor grid " << donorGridFileName << "...";
2172 const MFloat startTime = wallTime();
2173
2174 // Determine the local number of donor cells and the maximum number of donor
2175 // cells across all grid map offsets on this domain
2176 MInt noDonorCellsLocal = 0;
2177 MInt gridMapMaxNoDonorCells = 0;
2178 for(auto&& offset : m_gridMapOffsets) {
2179 noDonorCellsLocal += offset.m_noDonorCells;
2180 gridMapMaxNoDonorCells = max(gridMapMaxNoDonorCells, offset.m_noDonorCells);
2181 }
2182
2183
2185 // Check 1: total number of donor cells matches number of cells in grid file
2187 using namespace maia::parallel_io;
2188 ParallelIo file(donorGridFileName, PIO_READ, mpiComm());
2189 MInt noDonorCellsFile;
2190 // file.readScalar(&noDonorCellsFile, "noCells");
2191 file.getAttribute(&noDonorCellsFile, "noCells");
2192 MInt noDonorCellsGlobal;
2193 MPI_Allreduce(&noDonorCellsLocal, &noDonorCellsGlobal, 1, type_traits<MInt>::mpiType(), MPI_SUM, mpiComm(), AT_,
2194 "noDonorCellsLocal", "noDonorCellsGlobal");
2195 if(noDonorCellsFile != noDonorCellsGlobal) {
2196 TERMM(1, "Number of mapped donor cells does not match number of cells in "
2197 "donor grid file: mapped: "
2198 + to_string(noDonorCellsGlobal) + "; grid: " + to_string(noDonorCellsFile));
2199 }
2200
2201
2203 // Check 2: coordinates of donor cells match those of target cells
2205 // Define epsilon according to CartesianGrid constructor
2206 const MFloat eps = 1.0 / FPOW2(30) * grid().lengthLevel0();
2207
2208 // Successively read coordinates of donor grid and check them against target
2209 // grid coordinates
2210 MFloatScratchSpace coordinates(max(gridMapMaxNoDonorCells, 1), AT_, "coordinates");
2211 const array<MString, 3> dirs = {{"x", "y", "z"}};
2212 for(MInt offsetId = 0; offsetId < m_maxNoGridMapOffsets; offsetId++) {
2213 // Store whether this is a valid iteration or if this is just done to make
2214 // sure that reading from the grid file in parallel works correctly
2215 const MBool valid = (static_cast<size_t>(offsetId) < m_gridMapOffsets.size());
2216
2217 // Set offset dependent on whether this is a valid iteration
2218 const MInt noDonorCells = valid ? m_gridMapOffsets[offsetId].m_noDonorCells : 0;
2219 const MInt firstDonorGlobalId = valid ? m_gridMapOffsets[offsetId].m_firstDonorGlobalId : 0;
2220 file.setOffset(noDonorCells, firstDonorGlobalId);
2221
2222 // Read and compare coordinates
2223 for(MInt dir = 0; dir < nDim; dir++) {
2224 // Read from file
2225 file.readArray(&coordinates[0], "coordinates_" + to_string(dir));
2226
2227 // Skip comparison if not a valid iteration
2228 if(!valid) {
2229 continue;
2230 }
2231
2232 const MInt noTargetCells = m_gridMapOffsets[offsetId].m_noTargetCells;
2233 MInt donorCellId = 0;
2234 // Initialize donorLength to bogus value s.t. it always triggers an abort
2235 // if this value is (erroneously) used before a valid length is set
2236 MFloat donorLength = -numeric_limits<MFloat>::infinity();
2237
2238 // Compare coordinates
2239 for(MInt i = 0; i < noTargetCells; i++) {
2240 const MInt cellId = m_gridMapOffsets[offsetId].m_firstTargetCellId + i;
2241 const MFloat targetCoordinate = grid().tree().coordinate(cellId, dir);
2242
2243 // Check if this element belongs to a one-to-many mapping
2244 if(m_gridMapOffsets[offsetId].m_noOffspring[i] == -1) {
2245 const MFloat lastDonorCoordinate = coordinates[donorCellId - 1];
2246 // Check if target cell is contained in the donor cell, which is the
2247 // same as the last considered and matching donor cell, for which the
2248 // cell length is stored in 'donorLength'.
2249 if(targetCoordinate < lastDonorCoordinate - 0.5 * donorLength
2250 || targetCoordinate > lastDonorCoordinate + 0.5 * donorLength) {
2251 TERMM(1, "Target cell of one-to-many mapping not contained in "
2252 "donor cell.");
2253 }
2254 // Continue with next target cell
2255 continue;
2256 }
2257
2258 // Compare coordinates of matching target and donor cell
2259 const MFloat donorCoordinate = coordinates[donorCellId];
2260 if(!approx(targetCoordinate, donorCoordinate, eps)) {
2261 const MInt globalId = grid().tree().globalId(cellId);
2262 TERMM(1, dirs[dir] + "-coordinates for target cell " + to_string(cellId) + " (globalId: "
2263 + to_string(globalId) + ") and donor cell " + to_string(firstDonorGlobalId + donorCellId)
2264 + " do not match: target: " + to_string(targetCoordinate)
2265 + "; donor: " + to_string(donorCoordinate));
2266 }
2267 donorCellId++;
2268
2269 const MFloat targetLength = grid().cellLengthAtCell(cellId);
2270 // Store cell length of matching donor cell for one-to-many check
2271 donorLength = targetLength;
2272
2273 // Check if donor offspring cells are contained in target cell
2274 for(MInt offspringId = 0; offspringId < m_gridMapOffsets[offsetId].m_noOffspring[i]; offspringId++) {
2275 const MFloat offspringCoordinate = coordinates[donorCellId + offspringId];
2276 if(offspringCoordinate < targetCoordinate - 0.5 * targetLength
2277 || offspringCoordinate > targetCoordinate + 0.5 * targetLength) {
2278 TERMM(1, "Donor offspring not contained in target cell.");
2279 }
2280 }
2281 // Increase by the number of donor child cells for this target cell
2282 donorCellId += m_gridMapOffsets[offsetId].m_noOffspring[i];
2283 }
2284 }
2285 }
2286
2287 // Show duration to allow estimate about how costly this check was
2288 m_log << "OK (duration: " << (wallTime() - startTime) << " s)" << endl;
2289}
std::vector< maia::dg::GridMapOffset > m_gridMapOffsets
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
MFloat wallTime()
Definition: functions.h:80
constexpr MFloat FPOW2(MInt x)
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292

◆ cleanUp()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::cleanUp
overridevirtual
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-07-31

Clean up only stuff that cannot (or maybe is not) properly handled in the destructor of the solver. So e.g. do not clean up every single std::vector that was used as a member variable, but free file resources, free MPI resources, destroy manually allocated memory etc.

Implements Solver.

Definition at line 4384 of file dgcartesiansolver.cpp.

4384 {
4385 TRACE();
4386
4387 // Nothing to do if solver is not active
4388 if(!isActive()) {
4389 RECORD_TIMER_STOP(m_timers[Timers::Run]);
4390 return;
4391 }
4392
4393 RECORD_TIMER_START(m_timers[Timers::CleanUp]);
4394
4395 // Abort if solver not initialized
4396 if(!m_isInitSolver) {
4397 TERMM(1, "Solver was not initialized.");
4398 }
4399
4400 // Free persistent MPI requests
4401 if(hasMpiExchange()) {
4403 }
4404
4405 RECORD_TIMER_STOP(m_timers[Timers::CleanUp]);
4406 RECORD_TIMER_STOP(m_timers[Timers::Run]);
4407}

◆ createElement()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::createElement ( const MInt  cellId)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2014-02-21
Parameters
[in]cellIdCell id of cell for which element should be created.

Definition at line 2500 of file dgcartesiansolver.cpp.

2500 {
2501 // TRACE();
2502
2503 // Determine element id and create element in collector
2504 const MInt elementId = m_elements.size();
2506
2507 // Set cell id for forward references to cells
2508 m_elements.cellId(elementId) = cellId;
2509
2510 // Reset surface ids
2511 for(MInt dir = 0; dir < 2 * nDim; dir++) {
2512 m_elements.surfaceIds(elementId, dir) = -1;
2513 }
2514}
void append(const MInt count)
Append nodes to end of tree.
Definition: container.h:223

◆ createHElement()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::createHElement ( const MInt  cellId)
private
Author
Sven Berger
Date
March 2015
Parameters
[in]cellIdCell id of cell for which h-element should be created.

Definition at line 2523 of file dgcartesiansolver.cpp.

2523 {
2524 // TRACE();
2525
2526 // Determine h-element id and create h-element in collector
2527 const MInt hElementId = m_helements.size();
2529
2530 // Set elementId so that it can be used in loops over the h-element collector
2531 m_helements.elementId(hElementId) = m_elements.getElementByCellId(cellId);
2532
2533 // Reset h-refined surface ids
2534 for(MInt dir = 0; dir < 2 * nDim; dir++) {
2535 for(MInt pos = 0; pos < 2 * (nDim - 1); pos++) {
2536 m_helements.hrefSurfaceIds(hElementId, dir, pos) = -1;
2537 }
2538 }
2539}

◆ createHMPISurfaces()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::createHMPISurfaces ( const MInt  elementId,
const MInt  dir 
)
private

Definition at line 3644 of file dgcartesiansolver.cpp.

3644 {
3645 // TRACE();
3646
3647 // Determine neighbor element
3648 const MInt cellId = m_elements.cellId(elementId);
3649
3650 // Get neighbor cells from child level
3651 vector<MInt> nghbrIds;
3652 const MInt parentNghbrId = grid().tree().neighbor(cellId, dir);
3653
3654 // Arrays give child id of child level neighbors for a neighbor cell in a
3655 // given direction
3656 static constexpr MInt dirNghbrs[6][4] = {
3657 {1, 3, 5, 7}, // -x direction
3658 {0, 2, 4, 6}, // +x direction
3659 {2, 3, 6, 7}, // -y direction
3660 {0, 1, 4, 5}, // +y direction
3661 {4, 5, 6, 7}, // -z direction
3662 {0, 1, 2, 3} // +z direction
3663 };
3664
3665 MInt noNonHaloChilds = 0;
3666 // Store every existing child level neighbor element
3667 for(MInt i = 0; i < 2 * (nDim - 1); i++) {
3668 if(grid().tree().hasChild(parentNghbrId, dirNghbrs[dir][i])) {
3669 // Check if child is an internal cell (partition level shift), skip
3670 const MInt childId = grid().tree().child(parentNghbrId, dirNghbrs[dir][i]);
3671 if(!grid().tree().hasProperty(childId, Cell::IsHalo)) {
3672 ASSERT(grid().tree().hasProperty(parentNghbrId, Cell::IsPartLvlAncestor),
3673 "this case is only valid with a neighboring partition level ancestor cell");
3674 noNonHaloChilds++;
3675 continue;
3676 }
3677 nghbrIds.push_back(grid().tree().child(parentNghbrId, dirNghbrs[dir][i]));
3678 }
3679 }
3680
3681 // Partition level shift: only neighboring non-halo childs, nothing to do
3682 if(noNonHaloChilds == 2 * (nDim - 1)) {
3683 return -1;
3684 }
3685
3686 if(nghbrIds.empty()) {
3687 stringstream errorMessage;
3688 errorMessage << "Error: child cells of neighboring halo cell not found. "
3689 "Try setting 'newCreateWindowCellsF = 0'."
3690 << endl;
3691 TERMM(1, errorMessage.str());
3692 }
3693
3694 // Create a surface for each child level neighbor element
3695 MInt firstSurfaceId = -1;
3696 for(const auto& nghbrId : nghbrIds) {
3697 // First, create normal surface
3698 const MInt srfcId = createSurface(elementId, dir, nghbrId);
3699
3700 // Store first created surface for the return value
3701 if(firstSurfaceId == -1) {
3702 firstSurfaceId = srfcId;
3703 }
3704
3705 // Then, add surface id of new surface to corresponding h-element
3706 for(MInt hElementId = 0; hElementId < m_helements.size(); hElementId++) {
3707 // Find h-element of the current element
3708 if(m_helements.elementId(hElementId) == elementId) {
3709 // Add surface id at first unused location
3710 for(MInt hSurfId = 0; hSurfId < 2 * (nDim - 1); hSurfId++) {
3711 if(m_helements.hrefSurfaceIds(hElementId, dir, hSurfId) == -1) {
3712 m_helements.hrefSurfaceIds(hElementId, dir, hSurfId) = srfcId;
3713 break;
3714 }
3715 }
3716 break;
3717 }
3718 }
3719
3720 // Set h-refinement specific variables
3721 m_surfaces.fineCellId(srfcId) = nghbrId;
3722
3723 // Increase counter
3725 }
3726
3727 return firstSurfaceId;
3728}
MInt createSurface(const MInt elementId, const MInt dir, MInt nghbrId=-1)

◆ createSurface()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::createSurface ( const MInt  elementId,
const MInt  dir,
MInt  nghbrId = -1 
)
private

Definition at line 3750 of file dgcartesiansolver.cpp.

3750 {
3751 // TRACE();
3752
3753 // Determine neighbor element
3754 const MInt cellId = m_elements.cellId(elementId);
3755 const MInt parentId = grid().tree().parent(cellId);
3756
3757 // Get neighbor from current or parent cell (or leave id as -1 if no neighbor
3758 // found)
3759 if(nghbrId == -1) {
3760 nghbrId = grid().tree().neighbor(cellId, dir);
3761 if(nghbrId == -1 && parentId > -1 && grid().tree().hasNeighbor(parentId, dir)) {
3762 nghbrId = grid().tree().neighbor(parentId, dir);
3763 }
3764 }
3765 const MInt nghbrElementId = m_elements.getElementByCellId(nghbrId);
3766
3767 // Determine new surface id and create the surface in collector
3768 const MInt srfcId = m_surfaces.size();
3770
3771 // Calculate opposite direction
3772 const MInt oppositeDir = 2 * (dir / 2) + 1 - (dir % 2);
3773
3774 // Calculate and set the surface orientation (0: x, 1: y, 2: z)
3775 const MInt orientation = dir / 2;
3776 m_surfaces.orientation(srfcId) = orientation;
3777
3778 // Calculate and set the neighboring element ids (element in -ve direction is
3779 // first)
3780 const MInt nghbrSideId = dir % 2;
3781 const MInt elementSideId = (nghbrSideId + 1) % 2;
3782 m_surfaces.nghbrElementIds(srfcId, nghbrSideId) = nghbrElementId;
3783 m_surfaces.nghbrElementIds(srfcId, elementSideId) = elementId;
3784
3785 // Set surfaceId for element
3786 m_elements.surfaceIds(elementId, dir) = srfcId;
3787
3788 // Set the surfaceId for the neighbor element if it is not already set
3789 if(nghbrElementId > -1 && m_elements.surfaceIds(nghbrElementId, oppositeDir) == -1) {
3790 m_elements.surfaceIds(nghbrElementId, oppositeDir) = srfcId;
3791 }
3792
3793 // Get levels of element and neighbor element (if existing)
3794 const MInt level = getLevelByElementId(elementId);
3795 MInt nghbrLvl = -1;
3796 if(nghbrElementId > -1) {
3797 nghbrLvl = getLevelByElementId(nghbrElementId);
3798 }
3799
3800 // Reset fine cell id
3801 m_surfaces.fineCellId(srfcId) = -1;
3802
3803 // Set h-elements if a neighbor with a lower level exists
3804 if(nghbrLvl != -1 && level > nghbrLvl) {
3805 // Iterate over h-elements
3806 for(MInt hElementId = 0; hElementId < m_helements.size(); hElementId++) {
3807 // Find h-element for neighbor element
3808 if(m_helements.elementId(hElementId) == nghbrElementId) {
3809 m_surfaces.fineCellId(srfcId) = cellId;
3810 // Add surface id at first unused location
3811 for(MInt hSurfId = 0; hSurfId < 2 * (nDim - 1); hSurfId++) {
3812 if(m_helements.hrefSurfaceIds(hElementId, oppositeDir, hSurfId) == -1) {
3813 m_helements.hrefSurfaceIds(hElementId, oppositeDir, hSurfId) = srfcId;
3814 break;
3815 }
3816 }
3817 break;
3818 }
3819 }
3820 }
3821
3822 // Set polynomial degree to maximum of both elements' polynomial degrees
3823 // Set number of nodes 1D to maximum of both elements' number of nodes 1D
3824 if(nghbrElementId > -1) {
3825 m_surfaces.polyDeg(srfcId) = max(m_elements.polyDeg(elementId), m_elements.polyDeg(nghbrElementId));
3826 m_surfaces.noNodes1D(srfcId) = max(m_elements.noNodes1D(elementId), m_elements.noNodes1D(nghbrElementId));
3827 } else {
3828 m_surfaces.polyDeg(srfcId) = m_elements.polyDeg(elementId);
3829 m_surfaces.noNodes1D(srfcId) = m_elements.noNodes1D(elementId);
3830 }
3831
3832
3833 // Reset level in case there is a neighbor cell
3834 if(nghbrId > -1) {
3835 nghbrLvl = grid().tree().level(nghbrId);
3836 }
3837
3838 // Compute surface coordinates by using the higher level cell
3839 if(level > nghbrLvl) {
3840 const MFloat cellLength = grid().cellLengthAtCell(cellId);
3841 m_surfaces.coords(srfcId, orientation) =
3842 grid().tree().coordinate(cellId, orientation) + (static_cast<MFloat>(nghbrSideId) - F1B2) * cellLength;
3843 for(MInt i = 0; i < nDim; i++) {
3844 if(i != orientation) {
3845 m_surfaces.coords(srfcId, i) = grid().tree().coordinate(cellId, i);
3846 }
3847 }
3848 } else {
3849 const MFloat cellLength = grid().cellLengthAtCell(nghbrId);
3850 m_surfaces.coords(srfcId, orientation) =
3851 grid().tree().coordinate(nghbrId, orientation) + (static_cast<MFloat>(1 - nghbrSideId) - F1B2) * cellLength;
3852 for(MInt i = 0; i < nDim; i++) {
3853 if(i != orientation) {
3854 m_surfaces.coords(srfcId, i) = grid().tree().coordinate(nghbrId, i);
3855 }
3856 }
3857 }
3858
3859 // Set internal side id
3860 const MInt elementIdL = m_surfaces.nghbrElementIds(srfcId, 0);
3861 const MInt elementIdR = m_surfaces.nghbrElementIds(srfcId, 1);
3862 // If a valid nghbrCell exists only one side -> mark this side
3863 // otherwise keep -1
3864 m_surfaces.internalSideId(srfcId) = -1;
3865 if(elementIdL == -1) {
3866 m_surfaces.internalSideId(srfcId) = 1;
3867 }
3868 if(elementIdR == -1) {
3869 m_surfaces.internalSideId(srfcId) = 0;
3870 }
3871
3872 // Calculate node coordinates
3874
3875 // Determine & set global surface id
3876 const MLong globalCellId = grid().tree().globalId(m_elements.cellId(elementId));
3877 if(nghbrId == -1 || nghbrLvl == -1) {
3878 // If no neighbor cell exists, take the global id from the cell
3879 m_surfaces.globalId(srfcId) = 2 * nDim * globalCellId + dir;
3880 } else {
3881 // If neighbor cell exists, take the higher level cell or if both have the
3882 // same level take the cell with the lower global cell id
3883 const MLong globalNghbrId = grid().tree().globalId(nghbrId);
3884 if(level > nghbrLvl || (globalCellId < globalNghbrId && level == nghbrLvl)) {
3885 m_surfaces.globalId(srfcId) = 2 * nDim * globalCellId + dir;
3886 } else {
3887 m_surfaces.globalId(srfcId) = 2 * nDim * globalNghbrId + oppositeDir;
3888 }
3889 }
3890
3891 return srfcId;
3892}
MInt getLevelByElementId(const MInt elementId)
MLong & globalId(const MInt srfcId)
Accessor for global id.

◆ exchangeMpiSurfacePolyDeg()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::exchangeMpiSurfacePolyDeg
private

Exchange polynomial degrees for MPI surfaces (necessary for adaptive p-refinement)

Author
Sven Berger
Date
Februar 2015

Definition at line 8767 of file dgcartesiansolver.cpp.

8767 {
8768 TRACE();
8769
8770 m_log << "Exchanging polynomial degrees of MPI surfaces... ";
8771
8772 // Create communication buffers
8773 vector<vector<MInt>> sendBuffer(m_noExchangeNghbrDomains);
8774 vector<vector<MInt>> recvBuffer(m_noExchangeNghbrDomains);
8775 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
8776 sendBuffer[i].resize(m_mpiSurfaces[i].size());
8777 recvBuffer[i].resize(m_mpiSurfaces[i].size());
8778 }
8779
8780 // Exchange data with each neighbor exchange domain
8781 vector<MPI_Request> recvRequests(m_noExchangeNghbrDomains, MPI_REQUEST_NULL);
8782 vector<MPI_Request> sendRequests(m_noExchangeNghbrDomains, MPI_REQUEST_NULL);
8783 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
8784 // Copy data from surfaces to send buffer
8785 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
8786 sendBuffer[i][j] = m_surfaces.polyDeg(m_mpiSurfaces[i][j]);
8787 }
8788
8789 // Begin MPI exchange
8791 m_exchangeNghbrDomains[i], mpiComm(), &recvRequests[i], AT_, "recvBuffer[i][0]");
8793 domainId(), mpiComm(), &sendRequests[i], AT_, "sendBuffer[i][0]");
8794 }
8795
8796 // Wait for MPI exchange to complete
8797 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
8798 MPI_Wait(&sendRequests[i], MPI_STATUS_IGNORE, AT_);
8799 MPI_Wait(&recvRequests[i], MPI_STATUS_IGNORE, AT_);
8800 }
8801
8802 // Copy data from receive buffer to surfaces
8803 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
8804 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
8805 const MInt srfcId = m_mpiSurfaces[i][j];
8806 const MInt currentPolyDeg = m_surfaces.polyDeg(srfcId);
8807 const MInt receivedPolyDeg = recvBuffer[i][j];
8808
8809 // If new polynomial degree is lower than current polynomial degree,
8810 // change surface polynomial degree and recalculate node coordinates
8811 if(currentPolyDeg < receivedPolyDeg) {
8812 m_surfaces.polyDeg(srfcId) = receivedPolyDeg;
8813 m_surfaces.noNodes1D(srfcId) = receivedPolyDeg + 1;
8814 // Recompute surface node coordinates
8816 }
8817 }
8818 }
8819
8820 m_log << "done" << endl;
8821}
std::vector< std::vector< MInt > > m_mpiSurfaces
std::vector< MInt > m_exchangeNghbrDomains
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Isend
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Irecv

◆ extendNodeVariables()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::extendNodeVariables
private
Author
Patrick Antony (patrick) patri.nosp@m.ck@a.nosp@m.ia.rw.nosp@m.th-a.nosp@m.achen.nosp@m..de
Date
2019-09-18

This method checks if the meanExtension feature has been activated properly in the properties file and triggers the extension for each specified direction/plane-pair.

This method must be called once after updateNodeVars and will call updateNodeVars itself again.

Definition at line 4845 of file dgcartesiansolver.cpp.

4845 {
4846 // check if this feature is activated properly in the .toml file
4847 MBool nodeVarsExtension = false;
4848 if(Context::propertyExists("nodeVarsExtension", m_solverId)) {
4849 nodeVarsExtension = Context::getSolverProperty<MBool>("nodeVarsExtension", m_solverId, AT_, &nodeVarsExtension);
4850 } else {
4851 const MBool extensionSetImplicit = Context::propertyExists("meanExtendDirections", m_solverId)
4852 || Context::propertyExists("meanExtendOffsets", m_solverId)
4853 || Context::propertyExists("meanExtendLimits", m_solverId);
4854 nodeVarsExtension = extensionSetImplicit;
4855 }
4856
4857 // return if neither flag(explicit) nor parameters(implicit) are set
4858 if(!nodeVarsExtension) {
4859 return;
4860 }
4861
4862 // read in directions and offsets (which specify planes)
4863 const MInt noExtendDirs = Context::propertyLength("meanExtendDirections", m_solverId);
4864 const MInt noExtendOffsets = Context::propertyLength("meanExtendOffsets", m_solverId);
4865 const MInt noExtendLimits = Context::propertyLength("meanExtendLimits", m_solverId);
4866 if(noExtendOffsets != noExtendDirs || noExtendLimits != noExtendDirs) {
4867 TERMM(1, "ERROR: # of specified directions (" + to_string(noExtendDirs) + "), # of offsets ("
4868 + to_string(noExtendOffsets) + "), and # of limits (" + to_string(noExtendLimits) + ") do not match!");
4869 }
4870
4871 std::vector<MInt> meanExtendDirections(noExtendDirs);
4872 std::vector<MFloat> meanExtendOffsets(noExtendDirs);
4873 std::vector<MFloat> meanExtendLimits(noExtendDirs);
4874
4875 for(MInt i = 0; i < noExtendDirs; i++) {
4876 meanExtendDirections[i] = Context::getSolverProperty<MInt>("meanExtendDirections", m_solverId, AT_, i);
4877 meanExtendOffsets[i] = Context::getSolverProperty<MFloat>("meanExtendOffsets", m_solverId, AT_, i);
4878 meanExtendLimits[i] = Context::getSolverProperty<MFloat>("meanExtendLimits", m_solverId, AT_, i);
4879 }
4880
4881 // trigger extension for each direction/offset-pair
4882 for(MInt i = 0; i < noExtendDirs; i++) {
4883 if(meanExtendDirections[i] >= 0 && meanExtendDirections[i] < 2 * nDim) {
4884 extendNodeVariablesSingleDirection(meanExtendDirections[i], meanExtendOffsets[i], meanExtendLimits[i]);
4885 }
4886 }
4887}
static MInt propertyLength(const MString &name, MInt solverId=m_noSolvers)
Returns the number of elements of a property.
Definition: context.cpp:538
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
void extendNodeVariablesSingleDirection(const MInt extendDir, const MFloat extendOffset, const MFloat extendLimit)
Set nodeVars upstream of given plane to values of elements in plane.

◆ extendNodeVariablesSingleDirection()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::extendNodeVariablesSingleDirection ( const MInt  extendDir,
const MFloat  extendOffset,
const MFloat  extendLimit 
)
private
Author
Patrick Antony (patrick) patri.nosp@m.ck@a.nosp@m.ia.rw.nosp@m.th-a.nosp@m.achen.nosp@m..de
Date
2019-04-29

This method executes the following steps until it hits the domain border:

  • extend nodeVars values in given direction orthogonal to given plane –update nodeVars in elements and surfaces along the direction -if a domain boundary is updated, updated surfaces are communicated and the updated values are propagated on the next domain until no domain sends updated values or updates its own elements. afterwards updateNodeVars is called to update nodeVars on surfaces orthogonal to the extend direction.

Definition at line 4904 of file dgcartesiansolver.cpp.

4906 {
4907 m_log << "Propagating mean values in direction " << extendDir << " from offset " << extendOffset << "..."
4908 << std::endl;
4909 // set up and pre-compute grid and extension variables
4910 const MInt noElements = m_elements.size();
4911 const MInt* const noNodes1D = &m_elements.noNodes1D(0);
4912 const MInt extendSide = extendDir % 2;
4913 const MInt extendDimension = (extendDir - extendSide) / 2;
4914 const MInt donorDir = 2 * extendDimension + (1 - extendSide);
4915 const MInt noHElements = m_helements.size();
4916 const MInt noSurfs = 2 * (nDim - 1);
4917
4918 // precompute map from surfaceId to surfaceId of h-refined child surfaces
4919 // for the surface, which is shared between the coarse element and one of the fine elements,
4920 // this gives for every position the surface of the child surface of that position. for child
4921 // surfaces, it gives number of surfaces+1, because they should not acces anything surface
4922 // related. for unrefined surfaces, all entries are -1
4923 // surfIdForward has the recv side's surfaces, because forward mortar projection is used there
4924 // to
4925 // get from coarse(1 element) to fine (multiple child elements)
4926 // surfIdReverse has the donor side's surfaces, because reverse mortar projection is used there
4927 // to
4928 // get from fine (multiple child elements) to coarse(1 element)
4929 MIntTensor hForwardSurfaceId(m_surfaces.size(), noSurfs);
4930 MIntTensor hReverseSurfaceId(m_surfaces.size(), noSurfs);
4931 hForwardSurfaceId.set(-1);
4932 hReverseSurfaceId.set(-1);
4933 for(MInt hElemId = 0; hElemId < noHElements; hElemId++) {
4934 const MInt elemId = m_helements.elementId(hElemId);
4935 // get global surface id for this surface
4936 const MInt surfIdForward = m_elements.surfaceIds(elemId, extendDir);
4937 const MInt surfIdReverse = m_elements.surfaceIds(elemId, donorDir);
4938 for(MInt pos = 0; pos < noSurfs; pos++) {
4939 hForwardSurfaceId(surfIdForward, pos) = m_helements.hrefSurfaceIds(hElemId, extendDir, pos);
4940 const MInt hReverseSurfaceIdFine = m_helements.hrefSurfaceIds(hElemId, donorDir, pos);
4941 hReverseSurfaceId(surfIdReverse, pos) = hReverseSurfaceIdFine;
4942 // this prevents access on a valid surface, but marks children surfs as refined
4943 if(hReverseSurfaceId(surfIdReverse, pos) != surfIdReverse && hReverseSurfaceIdFine > 0) {
4944 hReverseSurfaceId(hReverseSurfaceIdFine, 0) = m_surfaces.size() + 1;
4945 }
4946 }
4947 }
4948 // this is needed for hrefinement on mpisurfaces; for the lack of booltensor, these are ints
4949 MIntTensor surfaceHasRecvd(m_surfaces.size());
4950 surfaceHasRecvd.set(0.0);
4951 // mark those elements as updated, which are on the plane specified by the offset
4952 std::vector<MBool> elementUpdated(noElements, false);
4953 std::vector<MBool> elementOutsideLimit(noElements, false);
4954 std::vector<MInt> mpiSurfaceSendSize(m_surfaces.size(), 0);
4955 for(MInt elemId = 0; elemId < noElements; elemId++) {
4956 // assume here: all elements have either only old nodeVars or only new nodeVars
4957 const MFloat pSideCoordinate =
4958 m_surfaces.coords(m_elements.surfaceIds(elemId, extendDimension * 2 + 1), extendDimension);
4959 const MFloat mSideCoordinate =
4960 m_surfaces.coords(m_elements.surfaceIds(elemId, extendDimension * 2), extendDimension);
4961 elementUpdated[elemId] = (pSideCoordinate >= extendOffset && mSideCoordinate <= extendOffset);
4962 // mark elements that are outside the extend limit coordinates
4963 if((!extendSide && pSideCoordinate <= extendLimit && mSideCoordinate <= extendLimit)
4964 || (extendSide && pSideCoordinate >= extendLimit && mSideCoordinate >= extendLimit)) {
4965 elementOutsideLimit[elemId] = true;
4966 }
4967 // mark mpi surfaces with initially updated NodeVars as ready to send data to neighbor domain
4968 if(elementUpdated[elemId]) {
4969 const MInt sId = m_elements.surfaceIds(elemId, extendDir);
4970 if(sId >= m_mpiSurfacesOffset) {
4971 const MInt buffSize = ipow(noNodes1D[elemId], nDim - 1) * SysEqn::noNodeVars();
4972 mpiSurfaceSendSize[sId] = buffSize;
4973 if(hForwardSurfaceId(sId, 0) > -1) {
4974 for(MInt pos = 0; pos < noSurfs; pos++) {
4975 const MInt hElemId = m_surfaces.nghbrElementIds(sId, extendSide);
4976 mpiSurfaceSendSize[m_elements.surfaceIds(hElemId, extendDir)] = buffSize;
4977 }
4978 }
4979 }
4980 }
4981 }
4982
4983 for(MInt extendIterator = 0; extendIterator < 4 * noDomains() + 1; extendIterator++) {
4984 if(extendIterator == 4 * noDomains()) {
4985 // terminate because strict upper bound for number if iterations is reached
4986 for(MInt elemId = 0; elemId < noElements; elemId++) {
4987 if(elementUpdated[elemId] == 0) {
4988 m_log << "r" << domainId() << " e" << elemId << " not updated" << std::endl;
4989 }
4990 }
4991 TERMM(1, "Maximum amount of extension iterations reached.");
4992 }
4993 for(MInt elementCounter = 0; elementCounter < noElements; elementCounter++) {
4994 MBool noMoreUpdates = true;
4995 for(MInt elemId = 0; elemId < noElements; elemId++) {
4996 // update neighbor element in extend direction, skipping elements that
4997 // have no neighbor in extend direction to update
4998 const MInt srfcId = m_elements.surfaceIds(elemId, extendDir);
4999 if(srfcId < m_innerSurfacesOffset) {
5000 continue;
5001 }
5002 if(srfcId < m_mpiSurfacesOffset) {
5003 const MInt updateeElementId = m_surfaces.nghbrElementIds(srfcId, extendSide);
5004 if(elementUpdated[elemId] && !(elementUpdated[updateeElementId])
5005 && !(elementOutsideLimit[updateeElementId])) {
5006 updateNodeVariablesSingleElement(updateeElementId, extendDir, hForwardSurfaceId, hReverseSurfaceId,
5007 elementUpdated, mpiSurfaceSendSize, noMoreUpdates);
5008 noMoreUpdates = false;
5009 }
5010 }
5011 }
5012 if(noMoreUpdates) {
5013 break;
5014 }
5015 }
5016
5017 // MPI communication of surfaces updated in this iteration:
5018 MInt extendDomainId;
5019 MPI_Comm_rank(mpiComm(), &extendDomainId);
5020 // exchange information about whether any domain has updated nodeVars to communicate
5021 MInt thisRankIsDone = 1;
5022 for(MInt a = 0; a < m_surfaces.size(); a++) {
5023 if(mpiSurfaceSendSize[a] > 0) {
5024 thisRankIsDone = 0;
5025 }
5026 }
5027 MInt allRanksAreDone;
5028 MPI_Allreduce(&thisRankIsDone, &allRanksAreDone, 1, MPI_INT, MPI_MIN, mpiComm(), AT_, "thisRankIsDone",
5029 "allRanksAreDone");
5030 if(allRanksAreDone) {
5031 break;
5032 }
5033
5034 // exchange information on how much data to recv from each neighbor domain
5035 // allocate send and recv metadata buffer and fill send metadata buffer
5036 std::vector<std::vector<MInt>> nghbrSendSizes(m_noExchangeNghbrDomains);
5037 std::vector<std::vector<MInt>> nghbrRecvSizes(m_noExchangeNghbrDomains);
5038
5039 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
5040 nghbrSendSizes[i].resize(m_mpiSurfaces[i].size());
5041 nghbrRecvSizes[i].resize(m_mpiSurfaces[i].size());
5042 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
5043 nghbrSendSizes[i][j] = mpiSurfaceSendSize[m_mpiSurfaces[i][j]];
5044 mpiSurfaceSendSize[m_mpiSurfaces[i][j]] = 0;
5045 }
5046 }
5047
5048 // Exchange metadata buffers.
5049 std::vector<MPI_Request> metaDataRecvRequests(m_noExchangeNghbrDomains);
5050 std::vector<MPI_Request> metaDataSendRequests(m_noExchangeNghbrDomains);
5051 for(MInt nghbrIndex = 0; nghbrIndex < m_noExchangeNghbrDomains; nghbrIndex++) {
5052 MPI_Irecv(&nghbrRecvSizes[nghbrIndex][0], nghbrRecvSizes[nghbrIndex].size(), type_traits<MInt>::mpiType(),
5053 m_exchangeNghbrDomains[nghbrIndex], 0, mpiComm(), &metaDataRecvRequests[nghbrIndex], AT_,
5054 "nghbrRecvSizes[nghbrIndex][0]");
5055 MPI_Isend(&nghbrSendSizes[nghbrIndex][0], nghbrSendSizes[nghbrIndex].size(), type_traits<MInt>::mpiType(),
5056 m_exchangeNghbrDomains[nghbrIndex], 0, mpiComm(), &metaDataSendRequests[nghbrIndex], AT_,
5057 "nghbrSendSizes[nghbrIndex][0]");
5058 }
5059 MPI_Waitall(m_noExchangeNghbrDomains, &metaDataRecvRequests[0], MPI_STATUS_IGNORE, AT_);
5060
5061 // Exchange actual nodevars to neighbordomains.
5062 // Set up buffers.
5063 vector<vector<MFloat>> nodeVarsSendBuffers(m_noExchangeNghbrDomains);
5064 vector<vector<MFloat>> nodeVarsRecvBuffers(m_noExchangeNghbrDomains);
5065 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
5066 const MInt sendSize = accumulate(nghbrSendSizes[i].begin(), nghbrSendSizes[i].end(), 0);
5067 const MInt recvSize = accumulate(nghbrRecvSizes[i].begin(), nghbrRecvSizes[i].end(), 0);
5068 nodeVarsSendBuffers[i].resize(sendSize);
5069 nodeVarsRecvBuffers[i].resize(recvSize);
5070
5071 // Fill sendbuffer.
5072 MInt size = 0;
5073 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
5074 if(nghbrSendSizes[i][j] < 1) {
5075 continue;
5076 }
5077 const MInt srfcId = m_mpiSurfaces[i][j];
5078 // The side of the surface from which the nodevars are copied should
5079 // not matter, as both sides have to contain updated nodeVars in an
5080 // appropriate basis.
5081 const MFloat* data = &m_surfaces.nodeVars(srfcId, 1 - extendSide);
5082 copy(data, data + nghbrSendSizes[i][j], &nodeVarsSendBuffers[i][size]);
5083 size += nghbrSendSizes[i][j];
5084 }
5085 ASSERT(size == static_cast<MInt>(nodeVarsSendBuffers[i].size()), "Data size does not match buffer size.");
5086 }
5087 std::vector<MPI_Request> nodeVarsRecvRequests(m_noExchangeNghbrDomains);
5088 std::vector<MPI_Request> nodeVarsSendRequests(m_noExchangeNghbrDomains);
5089
5090 // Mpi-exchange buffer.
5091 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
5092 if(nodeVarsRecvBuffers[i].size() > 0) {
5093 MPI_Irecv(&nodeVarsRecvBuffers[i][0], nodeVarsRecvBuffers[i].size(), type_traits<MFloat>::mpiType(),
5094 m_exchangeNghbrDomains[i], m_exchangeNghbrDomains[i], mpiComm(), &nodeVarsRecvRequests[i], AT_,
5095 "nodeVarsRecvBuffers[i][0]");
5096 } else {
5097 nodeVarsRecvRequests[i] = MPI_REQUEST_NULL;
5098 }
5099 if(nodeVarsSendBuffers[i].size() > 0) {
5100 MPI_Isend(&nodeVarsSendBuffers[i][0], nodeVarsSendBuffers[i].size(), type_traits<MFloat>::mpiType(),
5101 m_exchangeNghbrDomains[i], domainId(), mpiComm(), &nodeVarsSendRequests[i], AT_,
5102 "nodeVarsSendBuffers[i][0]");
5103 } else {
5104 nodeVarsSendRequests[i] = MPI_REQUEST_NULL;
5105 }
5106 }
5107 // Since the send buffer will not get modified after this point, this wait
5108 // can be moved to a later point, it is posted here for readability only.
5109 MPI_Waitall(m_noExchangeNghbrDomains, &nodeVarsSendRequests[0], MPI_STATUSES_IGNORE, AT_);
5110
5111 // This wait can not be posted later than here, since the recvbuffer is
5112 // read after this!
5113 MPI_Waitall(m_noExchangeNghbrDomains, &nodeVarsRecvRequests[0], MPI_STATUSES_IGNORE, AT_);
5114 // Unpack recvbuffers into surfaces and trigger updates on element(s) at surfaces.
5115 for(MInt nghbrIndex = 0; nghbrIndex < m_noExchangeNghbrDomains; nghbrIndex++) {
5116 // Unpack recvbuffer.
5117 MInt size = 0;
5118 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[nghbrIndex].size(); j++) {
5119 if(nghbrRecvSizes[nghbrIndex][j] < 1) {
5120 continue;
5121 }
5122 const MInt srfcId = m_mpiSurfaces[nghbrIndex][j];
5123 surfaceHasRecvd[srfcId] = 1.0;
5124 // Copy nodeVars data.
5125 copy_n(&nodeVarsRecvBuffers[nghbrIndex][size],
5126 nghbrRecvSizes[nghbrIndex][j],
5127 &m_surfaces.nodeVars(srfcId, 1 - extendSide));
5128 copy_n(&nodeVarsRecvBuffers[nghbrIndex][size],
5129 nghbrRecvSizes[nghbrIndex][j],
5130 &m_surfaces.nodeVars(srfcId, extendSide));
5131 // Set up update.
5132 const MInt recvElementId = m_surfaces.nghbrElementIds(srfcId, extendSide);
5133 // Coarse cells with fine neighbors on a different domain
5134 //("reverse h-Refined") update only if all child surfaces have received
5135 // updated nodeVars.
5136 MBool srfcIsReverseHrefTemp = false;
5137 for(MInt pos = 0; pos < noSurfs; pos++) {
5138 if(hReverseSurfaceId(srfcId, pos) > -1) {
5139 srfcIsReverseHrefTemp = true;
5140 }
5141 }
5142 const MBool srfcIsReverseHref = srfcIsReverseHrefTemp;
5143 MBool allSurfsReady = true;
5144 if(srfcIsReverseHref) {
5145 const MInt mainSurfId = m_elements.surfaceIds(recvElementId, donorDir);
5146 for(MInt pos = 0; pos < noSurfs; pos++) {
5147 if(surfaceHasRecvd[hReverseSurfaceId(mainSurfId, pos)] < 1) {
5148 allSurfsReady = false;
5149 }
5150 }
5151 }
5152 if(allSurfsReady) {
5153 MBool dummy; // this is not used here
5154 const MInt updateeElementId = m_surfaces.nghbrElementIds(srfcId, extendSide);
5155 // skip elements outside the extend limit coordinates
5156 if(!elementOutsideLimit[updateeElementId]) {
5157 updateNodeVariablesSingleElement(recvElementId, extendDir, hForwardSurfaceId, hReverseSurfaceId,
5158 elementUpdated, mpiSurfaceSendSize, dummy);
5159 elementUpdated[recvElementId] = true;
5160 }
5161 }
5162 size += nghbrRecvSizes[nghbrIndex][j];
5163 }
5164 ASSERT(size == static_cast<MInt>(nodeVarsRecvBuffers[nghbrIndex].size()),
5165 "Data size does not match buffer size.");
5166 }
5167 // The sendSurfaceBufferSize might be modified in the next iteration,
5168 // so we have to wait for this request no later than here.
5169 MPI_Waitall(m_noExchangeNghbrDomains, &metaDataSendRequests[0], MPI_STATUS_IGNORE, AT_);
5170 }
5171 m_log << "done" << std::endl;
5173}
void updateNodeVariablesSingleElement(const MInt elementId, const MInt extendDir, MIntTensor hForwardSurfaceId, MIntTensor hReverseSurfaceId, std::vector< MBool > &cellHasUpdatedMeans, std::vector< MInt > &SurfaceWantsToMPISend, MBool &noMoreUpdates)
Sets nodeVars of an element to values on the surface opposite to extendDir.
MFloat & nodeVars(const MInt srfcId, const MInt side)
Accessor for node variables.
Definition: contexttypes.h:19

◆ finalizeAdaptation()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::finalizeAdaptation ( )
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 298 of file dgcartesiansolver.h.

298 {
299 // TODO labels:DG,GRID check this, previously in reinitAfterAdaptation()
300 grid().updateOther();
302 };

◆ finalizeBalance()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::finalizeBalance ( )
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 413 of file dgcartesiansolver.h.

413{};

◆ finalizeInitSolver()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::finalizeInitSolver
overridevirtual

Implements Solver.

Definition at line 1874 of file dgcartesiansolver.cpp.

1874 {
1875 TRACE();
1876
1877 // Nothing to be done if solver is not active
1878 if(!isActive()) return;
1879
1880 RECORD_TIMER_START(m_timers[Timers::RunInit]);
1881 // Perform remaining steps needed before main loop execution
1882 initMainLoop();
1883 RECORD_TIMER_STOP(m_timers[Timers::RunInit]);
1884}
void initMainLoop()
Perform all operations that prepare the execution of the main loop.

◆ finalizeMpiExchange()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::finalizeMpiExchange
private

Definition at line 4464 of file dgcartesiansolver.cpp.

4464 {
4465 TRACE();
4466
4467 if(m_noExchangeNghbrDomains > 0) {
4468 // Wait for open send requests to finish
4470 MPI_Waitall(m_noExchangeNghbrDomains, &m_sendRequests[0], MPI_STATUSES_IGNORE, AT_);
4471 }
4472
4473 // Cancel and free requests if they are non-null
4474 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4475 if(m_sendRequests[i] != MPI_REQUEST_NULL) {
4476 // Note: canceling send requests might cause MPI errors depending on the MPI
4477 // implementation https://github.com/mpi-forum/mpi-forum-historic/issues/479
4478 /* MPI_Cancel(&m_sendRequests[i], AT_); */
4480 }
4481
4482 if(m_recvRequests[i] != MPI_REQUEST_NULL) {
4483 // Cancel opened receive request that do not have a matching send initiated yet
4485 MPI_Cancel(&m_recvRequests[i], AT_);
4486 }
4488 }
4489 }
4490 }
4491
4492 m_mpiSendRequestsOpen = false;
4493 m_mpiRecvRequestsOpen = false;
4494
4495#ifdef DG_USE_MPI_DERIVED_TYPES
4496 // Free derived data types
4497 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4498 MPI_Type_free(&m_sendTypes[i], AT_);
4499 MPI_Type_free(&m_recvTypes[i], AT_);
4500 }
4501#endif
4502}
std::vector< MPI_Datatype > m_recvTypes
std::vector< MPI_Datatype > m_sendTypes
int MPI_Type_free(MPI_Datatype *datatype, const MString &name)
same as MPI_Type_free
int MPI_Request_free(MPI_Request *request, const MString &name)
same as MPI_Request_free

◆ finishMpiSurfaceExchange()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::finishMpiSurfaceExchange
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-07-24

Definition at line 7469 of file dgcartesiansolver.cpp.

7469 {
7470 TRACE();
7471 RECORD_TIMER_START(m_timers[Timers::SurfExchange]);
7472 RECORD_TIMER_START(m_timers[Timers::Accumulated]);
7473 RECORD_TIMER_START(m_timers[Timers::MPI]);
7474
7475 // IMPORTANT:
7476 // If anything in this method is changed, please check if
7477 // updateNodeVariables() needs to be changed as well, since it contains more
7478 // or less the same code.
7479
7481 TERMM(1, "MPI requests are not open: receive=" + std::to_string(m_mpiRecvRequestsOpen)
7482 + ", send=" + std::to_string(m_mpiSendRequestsOpen));
7483 }
7484
7485#ifdef DG_USE_MPI_WAITSOME
7486 TERMM(1, "This code is untested and will not work with p-refinement.");
7487
7488 // Init status array and counter
7489 vector<MInt> indices(m_noExchangeNghbrDomains);
7490 MInt noFinished;
7491
7492 // Start with receiving data and unpack the buffers as they are filled
7493 // with incoming data
7494 RECORD_TIMER_START(m_timers[Timers::MPIWait]);
7495 RECORD_TIMER_START(m_timers[Timers::SurfExchangeWait]);
7496 RECORD_TIMER_START(m_timers[Timers::SEWaitRecv]);
7497 MPI_Waitsome(m_noExchangeNghbrDomains, &m_recvRequests[0], &noFinished, &indices[0], MPI_STATUSES_IGNORE, AT_);
7498 while(noFinished != MPI_UNDEFINED) {
7499 for(MInt i = 0; i < noFinished; i++) {
7500 const MInt index = indices[i];
7501 MInt size = 0;
7502 for(size_t j = 0; j < m_mpiSurfaces[index].size(); j++) {
7503 const MInt srfcId = m_mpiSurfaces[index][j];
7504 const MInt noNodes1D = m_surfaces.noNodes1D(srfcId);
7505 const MInt noNodesXD = ipow(noNodes1D, nDim - 1);
7506 const MInt sideId = 1 - m_surfaces.internalSideId(srfcId);
7507
7508 MFloat* data = m_surfaces.variables(srfcId, sideId);
7509 const MInt dataBlockSize = noNodesXD * SysEqn::noVars();
7510 copy_n(&m_recvBuffers[index][size], dataBlockSize, data);
7511 size += dataBlockSize;
7512 }
7513 ASSERT(size == static_cast<MInt>(m_recvBuffers[index].size()), "Data size does not match buffer size.");
7514 }
7515
7516 // Wait for next batch
7517 MPI_Waitsome(m_noExchangeNghbrDomains, &m_recvRequests[0], &noFinished, &indices[0], MPI_STATUSES_IGNORE, AT_);
7518 }
7519 RECORD_TIMER_STOP(m_timers[Timers::SEWaitRecv]);
7520 RECORD_TIMER_STOP(m_timers[Timers::SurfExchangeWait]);
7521 RECORD_TIMER_STOP(m_timers[Timers::MPIWait]);
7522#else
7523
7524 // Finish receiving
7525 RECORD_TIMER_START(m_timers[Timers::MPIWait]);
7526 RECORD_TIMER_START(m_timers[Timers::SurfExchangeWait]);
7527 RECORD_TIMER_START(m_timers[Timers::SEWaitRecv]);
7528 if(m_noExchangeNghbrDomains > 0) {
7529 MPI_Waitall(m_noExchangeNghbrDomains, &m_recvRequests[0], MPI_STATUSES_IGNORE, AT_);
7530 }
7531 RECORD_TIMER_STOP(m_timers[Timers::SEWaitRecv]);
7532 RECORD_TIMER_STOP(m_timers[Timers::SurfExchangeWait]);
7533 RECORD_TIMER_STOP(m_timers[Timers::MPIWait]);
7534
7535 // Unpack receive buffers
7536#ifdef DG_USE_MPI_BUFFERS
7537 RECORD_TIMER_START(m_timers[Timers::MPICopy]);
7538 RECORD_TIMER_START(m_timers[Timers::SurfExchangeCopy]);
7539 RECORD_TIMER_START(m_timers[Timers::SECopyRecv]);
7540
7541 // Use max. polynomial degree to account for p-refined surfaces
7542 const MInt dataBlockSize = ipow(m_maxNoNodes1D, nDim - 1) * SysEqn::noVars();
7543
7544 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
7545 MInt size = 0;
7546 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
7547 // Here the surface id from m_mpiRecvSurfaces is used to handle the case of communication
7548 // of a domain with itself due to periodically connected boundaries
7549 const MInt srfcId = m_mpiRecvSurfaces[i][j];
7550
7551
7552 // Use max. polynomial degree to account for p-refined surfaces
7553 const MInt sideId = 1 - m_surfaces.internalSideId(srfcId);
7554 MFloat* data = &m_surfaces.variables(srfcId, sideId);
7555 copy_n(&m_recvBuffers[i][size], dataBlockSize, data);
7556 size += dataBlockSize;
7557 }
7558 ASSERT(size == static_cast<MInt>(m_recvBuffers[i].size()), "Data size does not match buffer size.");
7559 }
7560 RECORD_TIMER_STOP(m_timers[Timers::SECopyRecv]);
7561 RECORD_TIMER_STOP(m_timers[Timers::SurfExchangeCopy]);
7562 RECORD_TIMER_STOP(m_timers[Timers::MPICopy]);
7563#endif // DG_USE_MPI_BUFFERS
7564#endif // DG_USE_MPI_WAITSOME
7565
7566 m_mpiRecvRequestsOpen = false;
7567
7568 // Start new receive requests
7569 if(m_noExchangeNghbrDomains > 0) {
7571 m_mpiRecvRequestsOpen = true;
7572 }
7573
7574 RECORD_TIMER_STOP(m_timers[Timers::MPI]);
7575 RECORD_TIMER_STOP(m_timers[Timers::Accumulated]);
7576 RECORD_TIMER_STOP(m_timers[Timers::SurfExchange]);
7577}
std::vector< std::vector< MFloat > > m_recvBuffers
std::vector< std::vector< MInt > > m_mpiRecvSurfaces
int MPI_Waitsome(int incount, MPI_Request array_of_requests[], int *outcount, int array_of_indices[], MPI_Status array_of_statuses[], const MString &name)
same as MPI_Waitsome
int MPI_Startall(int count, MPI_Request array_of_requests[], const MString &name)
same as MPI_Startall
void indices(const MInt i, const MInt n, MInt *const ids)
Calculate the 2D/3D indices for a given scalar id for accessing a field of n^nDim points.

◆ forceTimeStep()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::forceTimeStep ( const MFloat  dt)
inline

Definition at line 102 of file dgcartesiansolver.h.

102 {
103 m_externalDt = dt;
104 if(m_restart) {
105 // m_dt is only updated via calcTimeStep(), not necessarily at a restart
107 }
108 }

◆ geometry() [1/2]

template<MInt nDim, class SysEqn >
Geom & DgCartesianSolver< nDim, SysEqn >::geometry ( )
inlineprivate

Definition at line 135 of file dgcartesiansolver.h.

135{ return m_geometry; }

◆ geometry() [2/2]

template<MInt nDim, class SysEqn >
constexpr const Geom & DgCartesianSolver< nDim, SysEqn >::geometry ( ) const
inlineconstexpr

Definition at line 129 of file dgcartesiansolver.h.

129{ return m_geometry; }

◆ getBoundaryConditionIds()

template<MInt nDim, class SysEqn >
array< MInt, 2 *nDim > DgCartesianSolver< nDim, SysEqn >::getBoundaryConditionIds ( const MInt  cellId)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2014
Parameters
[in]elementIdId of element for which to return boundary condition ids.
Returns
An array of length 2*nDim with the boundary condition id for each element face (or -1 if the element face is not at a physical boundary).

Definition at line 3395 of file dgcartesiansolver.cpp.

3395 {
3396 TRACE();
3397
3398 // Set target region to be the minimum and maximum cell coordinates, i.e. of
3399 // the 4 (2D) or 6 (3D) vertices
3400 array<MFloat, 2 * nDim> targetRegion;
3401 for(MInt dir = 0; dir < nDim; dir++) {
3402 targetRegion[dir] = grid().tree().coordinate(cellId, dir) - 0.5 * grid().cellLengthAtCell(cellId);
3403 targetRegion[dir + nDim] = grid().tree().coordinate(cellId, dir) + 0.5 * grid().cellLengthAtCell(cellId);
3404 }
3405
3406 // Get cell coordinates and half length
3407 const MFloat cellHalfLength = 0.5 * grid().cellLengthAtCell(cellId);
3408 array<MFloat, nDim> coordinates;
3409 for(MInt i = 0; i < nDim; i++) {
3410 coordinates[i] = grid().tree().coordinate(cellId, i);
3411 }
3412
3413 // Check if there are elements in the cell
3414 const MBool hasElement = needElementForCell(cellId);
3415
3416 // Get list of intersecting elements
3417 std::vector<MInt> nodeList;
3418 geometry().getIntersectionElements(&targetRegion[0], nodeList, cellHalfLength, &coordinates[0]);
3419
3420 array<MInt, 2 * nDim> bcIds;
3421 bcIds.fill(-1);
3422
3423 // Process each geometric element ('node')
3424 static constexpr MFloat standardBasis[MAX_SPACE_DIMENSIONS][MAX_SPACE_DIMENSIONS] = {
3425 {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
3426 for(MInt n = 0; n < (signed)nodeList.size(); n++) {
3427 // Obtain element normal
3428 const GeometryElement<nDim>& elem = geometry().elements[nodeList[n]];
3429 // Obtain geometry vertices
3430 array<MFloat, nDim * nDim> geometryPoints;
3431 elem.getVertices(&geometryPoints[0]);
3432
3433 // Obtain normal
3434 array<MFloat, nDim> normal;
3435 elem.calcNormal(&geometryPoints[0], &normal[0]);
3436
3437 // Check orientation of element normal (axis aligned)
3438 MInt orientation = -1;
3439 for(MInt d = 0; d < nDim; d++) {
3440 const MFloat dot = inner_product(&normal[0], &normal[nDim], standardBasis[d], 0.0);
3441 if(approx(std::fabs(dot), 1.0, MFloatEps)) {
3442 orientation = d;
3443 break;
3444 }
3445 }
3446
3447 // Set boundary id
3448 if(orientation != -1) {
3449 // ... for axis-aligned cases
3450
3451 // Find closest cell face (i.e. determine +ve or -ve placement w.r.t. to the
3452 // cell center)
3453 array<MFloat, nDim> centroid;
3454 elem.calcCentroid(&geometryPoints[0], &centroid[0]);
3455 const MFloat pos = grid().tree().coordinate(cellId, orientation) + 0.5 * grid().cellLengthAtCell(cellId);
3456 const MFloat neg = grid().tree().coordinate(cellId, orientation) - 0.5 * grid().cellLengthAtCell(cellId);
3457 const MInt direction = (std::fabs(neg - centroid[orientation]) < std::fabs(pos - centroid[orientation]))
3458 ? 2 * orientation
3459 : 2 * orientation + 1;
3460
3461 // Abort if boundary condition id for this direction was already set to a
3462 // different value
3463 if(bcIds[direction] > -1 && bcIds[direction] != elem.m_bndCndId) {
3464 stringstream ss;
3465 ss << "Bad cell: " << cellId << ". Cell has two different boundary condition ids (" << bcIds[direction] << ", "
3466 << elem.m_bndCndId << ") in direction " << direction << ". This feature is not yet implemented." << endl;
3467 TERMM(1, ss.str());
3468 }
3469
3470 // Set boundary id
3471 bcIds[direction] = elem.m_bndCndId;
3472
3473 } else {
3474 // ... for non axis-aligned cases
3475
3476 {
3477 // TODO labels:DG,GEOM,toenhance Needs to be adapted for cases where the outer boundary is non axis-aligned
3478 //
3479 // /DESCRIPTION/
3480 //
3481 // Currently, the excerpt of code below only works for the cases where the
3482 // INNER boundary only is non axis-aligned, e.g., an airfoil (2D), or a wing (3D)
3483 // inside the domain. The outer boundary HAS to be axis aligned, e.g., has to be
3484 // a square (2D) or cube (3D). This happens due to the following condition:
3485 //
3486 // direction = (normal[i] < 0) ? 2 * i : 2 * i + 1;
3487 //
3488 // That condition is only capable of assigning the correct direction for INNER
3489 // boundaries with the normal vector pointing outwards the geometry, i.e., pointing
3490 // inside the domain (for outer boundaries this just need to be flipped in order to
3491 // work). However, we currently can't find a proper way to to differentiate if a geometry
3492 // element belongs to the inner or outer boundary.
3493 //
3494 // /POSSIBLE FIX/
3495 //
3496 // A simplistic way of dealing with this issue can be by creating different
3497 // boundary condition IDs for inner and outer boundaries. Then, the code below
3498 // can be modified to check if the current geometry element has a m_bndCndId
3499 // that corresponds to a inner or outer boundary and assign the direction correctly.
3500 // (Remember to also change the geometry.toml files accordingly)
3501 //
3502 for(MInt i = 0; i < nDim; i++) {
3503 if(!approx(normal[i], 0.0, MFloatEps)) {
3504 MInt direction = (normal[i] < 0) ? 2 * i : 2 * i + 1;
3505 // If elements exist in the cell, use the opposite normal direction of geometry face
3506 if(hasElement) {
3507 direction = 2 * (direction / 2) + 1 - (direction % 2);
3508 }
3509
3510 // Abort if h-ref is used along a non axis-aligned boundary
3511 // First check if a neighbor on same level can theoretically exists -> if not a coarser nghbr might exists
3512 array<MFloat, nDim> nghbrCellCoord;
3513 for(MInt d = 0; d < nDim; ++d) {
3514 nghbrCellCoord[d] = grid().tree().coordinate(cellId, d);
3515 }
3516 nghbrCellCoord[i] += (2 * (direction % 2) - 1) * grid().cellLengthAtCell(cellId);
3517 const MBool nghbrIsInside = geometry().pointIsInside2(&nghbrCellCoord[0]);
3518 if((!nghbrIsInside && grid().tree().level(cellId) != getLevelOfDirectNeighborCell(cellId, direction))
3519 || (grid().tree().level(cellId) < getLevelOfDirectNeighborCell(cellId, direction))) {
3520 stringstream ss;
3521 ss << "Bad cell: " << cellId << ". There is h-refinement being used along a non axis-aligned surface in "
3522 << "direction " << direction << ". This feature is not yet implemented." << endl;
3523 TERMM(1, ss.str());
3524 }
3525
3526 // Abort if boundary condition id for this direction was already set to a
3527 // different value
3528 if(bcIds[direction] > -1 && bcIds[direction] != elem.m_bndCndId) {
3529 stringstream ss;
3530 ss << "Bad cell: " << cellId << ". Cell has two different boundary condition ids (" << bcIds[direction]
3531 << ", " << elem.m_bndCndId << ") in direction " << direction
3532 << ". This feature is not yet implemented." << endl;
3533 TERMM(1, ss.str());
3534 }
3535
3536 // Set boundary id
3537 bcIds[direction] = elem.m_bndCndId;
3538 }
3539 }
3540 }
3541
3542 // Candidates for geometry intersection
3543 std::vector<CutCandidate<nDim>> cutCandidates(1);
3544 // Assign cellId as the only candidate
3545 cutCandidates[0].cellId = cellId;
3546
3548
3549 const MInt noCutPoints = cutCandidates[0].noCutPoints;
3550
3551 // Set target points according to the number of cut points and dimensions (2D or 3D)
3552 vector<MFloat> targetPoints(noCutPoints * nDim);
3553 for(MInt cutPoint = 0; cutPoint < noCutPoints; cutPoint++) {
3554 for(MInt i = 0; i < nDim; i++) {
3555 targetPoints[(cutPoint * nDim) + i] = cutCandidates[0].cutPoints[cutPoint][i];
3556 }
3557 }
3558
3559 // Recalculate the normal for cutPoints
3560 elem.calcNormal(&targetPoints[0], &normal[0]);
3561
3562 // Check the new orientation for non-axis aligned cases
3563 orientation = 0;
3564 MFloat maxNormal = fabs(normal[0]);
3565 for(MInt d = 0; d < nDim; d++) {
3566 if(fabs(normal[d]) > maxNormal) {
3567 orientation = d;
3568 maxNormal = fabs(normal[d]);
3569 }
3570 }
3571
3572 {
3573 // Set boundary ids for faces that are not intersected by geometry
3574 // Find closest cell face (i.e. determine +ve or -ve placement w.r.t. to the cell center)
3575 array<MFloat, nDim> centroid;
3576 elem.calcCentroid(&targetPoints[0], &centroid[0]);
3577 const MFloat pos = grid().tree().coordinate(cellId, orientation) + 0.5 * grid().cellLengthAtCell(cellId);
3578 const MFloat neg = grid().tree().coordinate(cellId, orientation) - 0.5 * grid().cellLengthAtCell(cellId);
3579 MInt direction = (std::fabs(neg - centroid[orientation]) < std::fabs(pos - centroid[orientation]))
3580 ? 2 * orientation
3581 : 2 * orientation + 1;
3582
3583 // Needed when a geometry vertice is inside the cell and the wrong direction is assigned.
3584 // Mirror direction assignment if:
3585 // 1. No elements exist in the cell AND no neighbor exists in the specified direction OR
3586 // 2. Element exists in the cell AND neighbor exists in the speficied direction
3587 if((!hasElement && !grid().tree().hasNeighbor(cellId, direction))
3588 || (hasElement && grid().tree().hasNeighbor(cellId, direction))) {
3589 direction = 2 * (direction / 2) + 1 - (direction % 2);
3590 }
3591 // Abort if h-ref is used along a non axis-aligned boundary
3592 // First check if a neighbor on same level can theoretically exists -> if not a coarser nghbr might exists
3593 array<MFloat, nDim> nghbrCellCoord;
3594 for(MInt d = 0; d < nDim; ++d) {
3595 nghbrCellCoord[d] = grid().tree().coordinate(cellId, d);
3596 }
3597 nghbrCellCoord[orientation] += (2 * (direction % 2) - 1) * grid().cellLengthAtCell(cellId);
3598 const MBool nghbrIsInside = geometry().pointIsInside2(&nghbrCellCoord[0]);
3599 if((!nghbrIsInside && grid().tree().level(cellId) != getLevelOfDirectNeighborCell(cellId, direction))
3600 || (grid().tree().level(cellId) < getLevelOfDirectNeighborCell(cellId, direction))) {
3601 stringstream ss;
3602 ss << "Bad cell: " << cellId << ". There is h-refinement being used along a non axis-aligned surface "
3603 << "in direction " << direction << ". This feature is not yet implemented." << endl;
3604 TERMM(1, ss.str());
3605 }
3606 // Abort if boundary condition id for this direction was already set to a
3607 // different value
3608 if(bcIds[direction] > -1 && bcIds[direction] != elem.m_bndCndId) {
3609 stringstream ss;
3610 ss << "Bad cell: " << cellId << ". Cell has two different boundary condition ids (" << bcIds[direction]
3611 << ", " << elem.m_bndCndId << ") in direction " << direction << ". This feature is not yet implemented."
3612 << endl;
3613 TERMM(1, ss.str());
3614 }
3615
3616 // Set boundary id
3617 bcIds[direction] = elem.m_bndCndId;
3618 }
3619 }
3620 }
3621
3622 return bcIds;
3623}
MInt getLevelOfDirectNeighborCell(const MInt cellId, const MInt dir)
GeometryIntersection< nDim > * m_geometryIntersection
constexpr const Geom & geometry() const
Access the solver's geometry.
void calcNormal(const MFloat *const vertices, MFloat *normal) const
Calculates the normal vector from the geometry element vertices.
void calcCentroid(const MFloat *const vertices, MFloat *centroid) const
Calculate the centroid of the geometry element vertices.
void getVertices(MFloat *vertices) const
Return the vertices of the geometry element.
MBool pointIsInside2(const MFloat *const coordinates, MInt *numcutsperdir=nullptr)
Determines if a point is in or outside the geometry.
Definition: geometry.cpp:213
element< nDim > * elements
Definition: geometry.h:215
virtual MInt getIntersectionElements(MFloat *, std::vector< MInt > &)
Definition: geometry.h:63
void computeCutPointsFromSTL(std::vector< CutCandidate< nDim > > &candidates)
computes cut points where candidate intersects with the geometry note: can not handle bndryRefinement...

◆ getCellDataDlb() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getCellDataDlb ( const MInt  dataId,
const MInt  oldNoCells,
const MInt *const  bufferIdToCellId,
MFloat *const  data 
)
inlineoverride

Definition at line 435 of file dgcartesiansolver.h.

436 {
437 getCellDataDlb_(dataId, oldNoCells, bufferIdToCellId, data);
438 };
void getCellDataDlb_(const MInt dataId, const MInt oldNoCells, const MInt *const bufferIdToCellId, dataType *const data)

◆ getCellDataDlb() [2/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getCellDataDlb ( const MInt  dataId,
const MInt  oldNoCells,
const MInt *const  bufferIdToCellId,
MInt *const  data 
)
inlineoverride

Definition at line 431 of file dgcartesiansolver.h.

432 {
433 getCellDataDlb_(dataId, oldNoCells, bufferIdToCellId, data);
434 };

◆ getCellDataDlb_() [1/2]

template<MInt nDim, class SysEqn >
template<typename dataType >
void DgCartesianSolver< nDim, SysEqn >::getCellDataDlb_ ( const MInt  dataId,
const MInt  oldNoCells,
const MInt *const  bufferIdToCellId,
dataType *const  data 
)

◆ getCellDataDlb_() [2/2]

template<MInt nDim, class SysEqn >
template<typename DataType >
void DgCartesianSolver< nDim, SysEqn >::getCellDataDlb_ ( const MInt  dataId,
const MInt  oldNoCells,
const MInt *const  bufferIdToCellId,
DataType *const  data 
)
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

This method returns the requested data for all elements, e.g. the polynomial degree or the variables of all elements.

Parameters
[in]dataIdRequested data id.
[in]oldNoCellsCurrent (old) number of cells before load balancing.
[in]bufferIdToCellIdMapping from buffer location to corresponding cell id.
[out]dataPointer to storage for requested data.

Definition at line 1050 of file dgcartesiansolver.h.

1053 {
1054 TRACE();
1055
1056 // Check for unsorted cells, not supported yet, data needs to be resorted into buffers
1057 MInt prevCellId = -1;
1058 for(MInt i = 0; i < oldNoCells; i++) {
1059 const MInt mapping = bufferIdToCellId[i];
1060 if(mapping != -1) {
1061 if(mapping <= prevCellId) {
1062 TERMM(1, "Error: assembling data buffers for unsorted cells not supported yet in DG solver.");
1063 }
1064 prevCellId = mapping;
1065 }
1066 }
1067
1068 const MInt noElements = m_elements.size();
1069
1070 if(dataId > -1 && dataId < noDgCartesianSolverCellData()) {
1071 // DG solver cell data
1072 switch(dataId) {
1074 std::copy_n(&m_elements.cellId(0), noElements, data);
1075 break;
1077 std::copy_n(&m_elements.polyDeg(0), noElements, data);
1078 break;
1080 std::copy_n(&m_elements.noNodes1D(0), noElements, data);
1081 break;
1083 MInt dataOffset = 0;
1084 // Store all element variables in the data buffer
1085 for(MInt elementId = 0; elementId < noElements; elementId++) {
1086 const MInt noNodesXD = m_elements.noNodesXD(elementId);
1087 const MInt dataSize = noNodesXD * SysEqn::noVars();
1088 std::copy_n(&m_elements.variables(elementId), dataSize, &data[dataOffset]);
1089 dataOffset += dataSize;
1090 }
1091 break;
1092 }
1094 MInt dataOffset = 0;
1095 // Store all element node variables in the data buffer
1096 for(MInt elementId = 0; elementId < noElements; elementId++) {
1097 const MInt noNodesXD = m_elements.noNodesXD(elementId);
1098 const MInt dataSize = noNodesXD * SysEqn::noNodeVars();
1099 std::copy_n(&m_elements.nodeVars(elementId), dataSize, &data[dataOffset]);
1100 dataOffset += dataSize;
1101 }
1102 break;
1103 }
1104 default:
1105 TERMM(1, "Unknown data id (" + std::to_string(dataId) + ").");
1106 break;
1107 }
1108 } else if(dataId >= noDgCartesianSolverCellData() && dataId < noCellDataDlb()) {
1109 // Boundary condition cell data
1111 for(auto&& bc : m_boundaryConditions) {
1112 const MInt bcNoCellData = bc->noCellDataDlb();
1113 if(dataId >= offset && dataId < offset + bcNoCellData) {
1114 bc->getCellDataDlb(dataId - offset, data);
1115 break;
1116 }
1117 offset += bcNoCellData;
1118 }
1119 } else {
1120 // TODO labels:DG support exchange of CC mean vars data -> needs to be performed via gridcontroller!
1121 TERMM(1, "Invalid dataId (" + std::to_string(dataId) + ").");
1122 }
1123}

◆ getCellIdByIndex()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::getCellIdByIndex ( const MInt  index)
inline
  • Functions for postprocessing/sampling *

Definition at line 312 of file dgcartesiansolver.h.

312{ return m_elements.cellId(index); }

◆ getCellLoad()

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::getCellLoad ( const MInt  gridCellId,
const MFloat *const  weights 
) const
override
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Parameters
[in]cellIdRequested grid cell id.
[in]weightsComputational weights for different simulation components.
Returns
Cell load.

Definition at line 9431 of file dgcartesiansolver.cpp.

9431 {
9432 TRACE();
9433 ASSERT(isActive(), "solver is not active");
9434
9435 // Convert to solver cell id and check
9436 const MInt cellId = grid().tree().grid2solver(gridCellId);
9437 if(cellId < 0) {
9438 return 0;
9439 }
9440
9441 if(cellId < 0 || cellId >= grid().noInternalCells()) {
9442 TERMM(1, "The given cell id is invalid.");
9443 }
9444
9445 const MInt elementId = m_elements.getElementByCellId(cellId);
9446
9447 // Default cell load
9448 MFloat cellLoad = 0.0;
9449
9450 // Add load if there is an element
9451 if(elementId != -1) {
9452 const MInt polyDeg = m_elements.polyDeg(elementId);
9453 const MInt noNodesXD = m_elements.noNodesXD(elementId);
9454 // Weight the number of nodes and add a constant weight for each element
9455 // Note: m_weightPerElement should only be != 0 when getCellLoad is called from setCellWeights!
9456 cellLoad = m_weightPerElement + noNodesXD * weights[polyDeg - m_minPolyDeg];
9457
9458 // Add weight for boundary condition element
9460 for(auto&& bc : m_boundaryConditions) {
9461 if(bc->hasBcElement(elementId)) {
9462 cellLoad += noNodesXD * weights[m_maxPolyDeg - m_minPolyDeg + 1];
9463 }
9464 }
9465 }
9466 }
9467
9468 return cellLoad;
9469}

◆ getCurrentTimeStep()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::getCurrentTimeStep ( ) const
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 100 of file dgcartesiansolver.h.

100{ return m_timeStep; }

◆ getDefaultWeights()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getDefaultWeights ( MFloat weights,
std::vector< MString > &  names 
) const

Definition at line 9368 of file dgcartesiansolver.cpp.

9368 {
9369 TRACE();
9370
9371 const MInt noPolyDegs = m_maxPolyDeg - m_minPolyDeg + 1;
9372 for(MInt i = 0; i < noPolyDegs; i++) {
9373 weights[i] = 0.2;
9374 names[i] = "dg_node_p" + std::to_string(m_minPolyDeg + i);
9375 }
9376
9378 weights[noPolyDegs] = 0.5;
9379 names[noPolyDegs] = "dg_node_rbc";
9380 }
9381}

◆ getDomainDecompositionInformation()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getDomainDecompositionInformation ( std::vector< std::pair< MString, MInt > > &  domainInfo)
override

Definition at line 9884 of file dgcartesiansolver.cpp.

9885 {
9886 TRACE();
9887
9888 const MString namePrefix = "b" + std::to_string(solverId()) + "_";
9889
9890 // Number of DG elements
9891 const MInt noElements = m_elements.size();
9892 domainInfo.emplace_back(namePrefix + "noDgElements", noElements);
9893
9894 // Number of additional boundary condition elements
9895 MInt noBcElements = 0;
9896 for(auto&& bc : m_boundaryConditions) {
9897 for(MInt elementId = 0; elementId < noElements; elementId++) {
9898 if(bc->hasBcElement(elementId)) {
9899 noBcElements++;
9900 }
9901 }
9902 }
9903 domainInfo.emplace_back(namePrefix + "noDgBcElements", noBcElements);
9904}
std::basic_string< char > MString
Definition: maiatypes.h:55

◆ getElementIdAtPoint()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::getElementIdAtPoint ( const MFloat point,
MBool  globalUnique = false 
)
private
Author
Vitali Pauz v.pau.nosp@m.z@ai.nosp@m.a.rwt.nosp@m.h-aa.nosp@m.chen..nosp@m.de
Date
24.01.2014 (update 01.08.17)
Parameters
[in]pointEvaluation point.
[in]globalUniqueSpecify if a point should be globally unique (i.e. only appears once).
[out]returnselementId.

If the parameter "globalUnique" is set to true it is assured that every point is globally associated to only one element. This allows to avoid problems for points located on a domain boundary that should only appear on a single domain, e.g. when writing point data. By default globalUnique is set to false.

Definition at line 8061 of file dgcartesiansolver.cpp.

8061 {
8062 TRACE();
8063
8064 MInt foundElementId = -1;
8065 const MInt noElements = m_elements.size();
8066
8067 for(MInt elementId = 0; elementId < noElements; elementId++) {
8068 const MInt cellId = m_elements.cellId(elementId);
8069 const MFloat cellLength = grid().cellLengthAtCell(cellId);
8070 MBool pointInCell = true;
8071 MBool takeCell = true;
8072
8073 for(MInt i = 0; i < nDim; i++) {
8074 if(!(fabs(grid().tree().coordinate(cellId, i) - point[i]) <= cellLength * 0.5)) {
8075 pointInCell = false;
8076 }
8077 }
8078
8079 // Set globalUnique to true in order to avoid that points located on domain boundaries are
8080 // found multiple times (i.e. on different domains). This ensures that each point is globally
8081 // unique
8082 if(pointInCell && globalUnique) {
8083 for(MInt dimId = 0; dimId < nDim; dimId++) {
8084 const MFloat distance = grid().tree().coordinate(cellId, dimId) - point[dimId];
8085 // Check if the point is located on a cell edge
8086 if(approx(fabs(distance), cellLength * 0.5, MFloatEps)) {
8087 // Check the relative position of the point with respect to the cell center
8088 if(distance > 0.0) {
8089 // Point is on surface in negative coordinate direction, thus neighborDir is either
8090 // equal to 0, 2, or 4
8091 const MInt neighborDir = 2 * dimId;
8092 const MInt surfaceId = m_elements.surfaceIds(elementId, neighborDir);
8093 // Check for a MPI surface, if this is the case the unique point belongs to the
8094 // neighboring element on another domain
8095 if(isMpiSurface(surfaceId)) {
8096 takeCell = false;
8097 }
8098 }
8099 }
8100 }
8101 }
8102
8103 if(pointInCell && takeCell) {
8104 foundElementId = elementId;
8105 break;
8106 }
8107 }
8108
8109 return foundElementId;
8110}
MBool isMpiSurface(const MInt id) const
Return true if a surface is a MPI surface.
MFloat distance(const MFloat *a, const MFloat *b)
Definition: maiamath.h:249

◆ getGlobalSolverVars()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getGlobalSolverVars ( std::vector< MFloat > &  NotUsedglobalFloatVars,
std::vector< MInt > &  NotUsedglobalIntVars 
)
overridevirtual

Reimplemented from Solver.

Definition at line 9789 of file dgcartesiansolver.cpp.

9790 {
9791 TRACE();
9792
9793 globalFloatVars.push_back(m_time);
9794 globalFloatVars.push_back(m_dt);
9795
9796 globalIntVars.push_back(m_timeStep);
9797 globalIntVars.push_back(m_firstTimeStep);
9798 globalIntVars.push_back(m_noAnalyzeTimeSteps);
9799}

◆ getHeatRelease()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getHeatRelease ( MFloat *&  heatRelease)
inline

Definition at line 124 of file dgcartesiansolver.h.

124 {
125 std::cerr << "getHeatRelease DgCartesianSolver " << heatRelease << std::endl;
126 }

◆ getHElementId()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::getHElementId ( const MInt  elementId) const
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-03-06
Parameters
[in]elementIdElement id to check.

Definition at line 9298 of file dgcartesiansolver.cpp.

9298 {
9299 TRACE();
9300
9301 MInt hElementId = -1;
9302
9303 const MInt noHElements = m_helements.size();
9304 for(MInt hId = 0; hId < noHElements; hId++) {
9305 if(m_helements.elementId(hId) == elementId) {
9306 hElementId = hId;
9307 break;
9308 }
9309 }
9310
9311 return hElementId;
9312}

◆ getIdAtPoint()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::getIdAtPoint ( const MFloat point,
const MBool  globalUnique = false 
)
inline

Definition at line 315 of file dgcartesiansolver.h.

315 {
316 return getElementIdAtPoint(point, globalUnique);
317 }

◆ getLevelByElementId()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::getLevelByElementId ( const MInt  elementId)
private

Get h-refinement (cell) level of element.

Author
Sven Berger
Date
Februar 2015
Parameters
[in]elementIdId of the element for which level is requested.
Returns
The level of the corresponding cell.

Definition at line 9159 of file dgcartesiansolver.cpp.

9159 {
9160 // TRACE();
9161 ASSERT(elementId >= 0, "Invalid elementId");
9162
9163 const MInt cellId = m_elements.cellId(elementId);
9164 const MInt level = grid().tree().level(cellId);
9165
9166 return level;
9167}

◆ getLevelOfDirectNeighborCell()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::getLevelOfDirectNeighborCell ( const MInt  cellId,
const MInt  dir 
)
private

Get h-refinement (cell) level of neighbor element.

Author
Sven Berger
Date
Februar 2015
Parameters
[in]elementIdElement for which neighbor level is requested.
[in]dirDirection of neighbor element (-x,+x,-y,... = 0,1,2,...).
Returns
Level of the neighbor element or -1 if neighbor does not exist. Get h-refinement (cell) level of neighbor cell.
Author
Sven Berger, Rodrigo Miguez
Date
Februar 2015, October 2019
Parameters
[in]cellIdfor which neighbor level is requested.
[in]dirDirection of neighbor cell (-x,+x,-y,... = 0,1,2,...).
Returns
Level of the neighbor element or -1 if neighbor does not exist.

This method is smart and does not just return -1 if there is no same-level neighbor, but also checks if there are refined (smaller) or coarsened (larger) neighbor element(s).

Definition at line 9205 of file dgcartesiansolver.cpp.

9205 {
9206 // TRACE();
9207
9208 const MInt nghbrCellId = grid().tree().neighbor(cellId, dir);
9209 const MInt cellLvl = grid().tree().level(cellId);
9210
9211 // Check for finer nghbr. The finer nghbr must be directly adjacent to current cell.
9212 if(nghbrCellId > 0 && grid().tree().hasChildren(nghbrCellId)) {
9213 TERMM(1, "The following is not yet tested! If it works, delete this TERMM!");
9214 for(MInt child = 0; child < IPOW2(nDim); child++) {
9215 if(!(childCodePro[dir] & (1 << child))) continue;
9216 if(grid().tree().child(nghbrCellId, child) > -1) return cellLvl + 1;
9217 }
9218 }
9219
9220 // If neigbor cell does not exist on current level, check parent level
9221 if(nghbrCellId < 0 && grid().tree().hasParent(cellId)) {
9222 if(grid().tree().neighbor(grid().tree().parent(cellId), dir)) {
9223 return cellLvl - 1;
9224 }
9225 }
9226
9227 return nghbrCellId < 0 ? -1 : cellLvl;
9228}

◆ getLoadQuantities()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getLoadQuantities ( MInt *const  loadQuantities) const
override
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Parameters
[out]loadQuantitiesStorage for load quantities.

Definition at line 9390 of file dgcartesiansolver.cpp.

9390 {
9391 TRACE();
9392
9393 // Reset
9394 std::fill_n(&loadQuantities[0], noLoadTypes(), 0);
9395
9396 // Nothing to do if solver is not active
9397 if(!isActive()) {
9398 return;
9399 }
9400
9401 const MInt noPolyDegs = m_maxPolyDeg - m_minPolyDeg + 1;
9402
9403 if(noPolyDegs > 1) {
9404 // Total DOFs of different polynomial degrees
9405 for(MInt i = 0; i < noPolyDegs; i++) {
9406 loadQuantities[i] = m_statLocalNoActiveDOFsPolyDeg[i];
9407 }
9408 } else {
9409 // Only one polynomial degree
9410 loadQuantities[0] = m_statLocalNoActiveDOFs;
9411 }
9412
9413 // Add number of boundary condition element nodes
9415 loadQuantities[noPolyDegs] = 0;
9416 for(auto&& bc : m_boundaryConditions) {
9417 loadQuantities[noPolyDegs] += bc->getLocalNoNodes();
9418 }
9419 }
9420}
std::vector< MInt > m_statLocalNoActiveDOFsPolyDeg
MInt noLoadTypes() const override
Return the number of DG load types.

◆ getRestartFileName()

template<MInt nDim, class SysEqn >
MString DgCartesianSolver< nDim, SysEqn >::getRestartFileName ( const MInt  timeStep,
const MInt  useNonSpecifiedRestartFile 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-09-22
Parameters
[in]timeStepTime step to calculate the name for.
[in]useNonSpecifiedRestartFileIf true, return restart file name without time step code.
Returns
Name of the restart file.

Definition at line 6610 of file dgcartesiansolver.cpp.

6611 {
6612 TRACE();
6613
6614 stringstream ss;
6615 if(useNonSpecifiedRestartFile) {
6616 ss << restartDir() << "restart_" << getIdentifier(g_multiSolverGrid, "b", "") << ParallelIo::fileExt();
6617 } else {
6618 ss << restartDir() << "restart_" << getIdentifier(g_multiSolverGrid, "b") << setw(8) << setfill('0') << timeStep
6619 << ParallelIo::fileExt();
6620 }
6621 const MString fileName = ss.str();
6622
6623 return fileName;
6624}
MString getIdentifier(const MBool useSolverId=false, const MString preString="", const MString postString="_")
Definition: solver.cpp:188
MString restartDir() const
Return the directory for restart files.
Definition: solver.h:410
MBool g_multiSolverGrid

◆ getSampleVariables() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getSampleVariables ( const MInt  cellId,
std::vector< MFloat > &   
)
inline

Definition at line 120 of file dgcartesiansolver.h.

120 {
121 std::cerr << "getSampleVariables DgCartesianSolver " << cellId << std::endl;
122 };

◆ getSampleVariables() [2/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getSampleVariables ( MInt  cellId,
const MFloat *&  vars 
)
inline

Definition at line 117 of file dgcartesiansolver.h.

117 {
118 std::cerr << "getSampleVariables DgCartesianSolver " << cellId << " " << vars << std::endl;
119 };

◆ getSolverSamplingProperties()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getSolverSamplingProperties ( std::vector< MInt > &  samplingVarIds,
std::vector< MInt > &  noSamplingVars,
std::vector< std::vector< MString > > &  samplingVarNames,
const MString  featureName = "" 
)
override

Definition at line 9909 of file dgcartesiansolver.cpp.

9912 {
9913 TRACE();
9914
9915 // Read sampling variable names (for a specific feature)
9916 std::vector<MString> varNamesList;
9917 MInt noSampleVars = readSolverSamplingVarNames(varNamesList, featureName);
9918
9919 // Set default sampling variables if none specified
9920 if(noSampleVars == 0) {
9921 varNamesList.push_back("DG_VARS");
9922 noSampleVars = 1;
9923 }
9924
9925 for(MInt i = 0; i < noSampleVars; i++) {
9926 const MInt samplingVar = string2enum(varNamesList[i]);
9927 std::vector<MString> varNames;
9928
9929 auto samplingVarIt = std::find(samplingVarIds.begin(), samplingVarIds.end(), samplingVar);
9930 if(samplingVarIt != samplingVarIds.end()) {
9931 TERMM(1, "Sampling variable '" + varNamesList[i] + "' already specified.");
9932 }
9933
9934 switch(samplingVar) {
9935 case DG_VARS: {
9936 const MInt noVars = SysEqn::noVars();
9937
9938 samplingVarIds.push_back(DG_VARS);
9939 noSamplingVars.push_back(noVars);
9940
9941 varNames.resize(noVars);
9942 for(MInt varId = 0; varId < noVars; varId++) {
9943 // TODO labels:DG needs to be fixed if conservative and primitive variables are different
9944 varNames[varId] = SysEqn::consVarNames(varId);
9945 }
9946
9947 samplingVarNames.push_back(varNames);
9948 break;
9949 }
9950 case DG_NODEVARS: {
9951 const MInt noVars = SysEqn::noNodeVars();
9952
9953 samplingVarIds.push_back(DG_NODEVARS);
9954 noSamplingVars.push_back(noVars);
9955
9956 varNames.resize(noVars);
9957 for(MInt varId = 0; varId < noVars; varId++) {
9958 varNames[varId] = SysEqn::nodeVarNames(varId);
9959 }
9960 samplingVarNames.push_back(varNames);
9961 break;
9962 }
9963 case DG_SOURCETERMS: {
9964 const MInt noVars = SysEqn::noVars();
9965
9966 samplingVarIds.push_back(DG_SOURCETERMS);
9967 noSamplingVars.push_back(noVars);
9968
9969 varNames.resize(noVars);
9970 for(MInt varId = 0; varId < noVars; varId++) {
9971 varNames[varId] = "source_" + SysEqn::consVarNames(varId);
9972 }
9973 samplingVarNames.push_back(varNames);
9974 break;
9975 }
9976 default: {
9977 TERMM(1, "Unknown sampling variable: " + varNamesList[i]);
9978 break;
9979 }
9980 }
9981 }
9982}
MInt readSolverSamplingVarNames(std::vector< MString > &varNames, const MString featureName="") const
Read sampling variables names, store in vector and return the number of sampling variables.
Definition: solver.cpp:167
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20

◆ getSolverTimings()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::getSolverTimings ( std::vector< std::pair< MString, MFloat > > &  solverTimings,
const MBool  allTimings 
)
override

Definition at line 9819 of file dgcartesiansolver.cpp.

9820 {
9821 TRACE();
9822 const MString namePrefix = "b" + std::to_string(solverId()) + "_";
9823
9824 const MFloat load = returnLoadRecord();
9825 const MFloat idle = returnIdleRecord();
9826
9827 solverTimings.emplace_back(namePrefix + "loadDgCartesianSolver", load);
9828 solverTimings.emplace_back(namePrefix + "idleDgCartesianSolver", idle);
9829
9830#ifdef MAIA_TIMER_FUNCTION
9831 solverTimings.emplace_back(namePrefix + "timeStepRk", RETURN_TIMER_TIME(m_timers[Timers::RungeKuttaStep]));
9832
9833 if(allTimings) {
9834 // Full set of timings
9835 solverTimings.emplace_back(namePrefix + "calcDgTimeDerivative", RETURN_TIMER_TIME(m_timers[Timers::TimeDeriv]));
9836
9837 solverTimings.emplace_back(namePrefix + "resetRHS", RETURN_TIMER_TIME(m_timers[Timers::ResetRHS]));
9838 solverTimings.emplace_back(namePrefix + "prolong_to_surfaces", RETURN_TIMER_TIME(m_timers[Timers::Prolong]));
9839 solverTimings.emplace_back(namePrefix + "forward_projection",
9840 RETURN_TIMER_TIME(m_timers[Timers::ForwardProjection]));
9841
9842 solverTimings.emplace_back(namePrefix + "MPI_surface_exchange", RETURN_TIMER_TIME(m_timers[Timers::SurfExchange]));
9843 solverTimings.emplace_back(namePrefix + "communication", RETURN_TIMER_TIME(m_timers[Timers::SurfExchangeComm]));
9844 solverTimings.emplace_back(namePrefix + "copy_operations", RETURN_TIMER_TIME(m_timers[Timers::SurfExchangeCopy]));
9845 solverTimings.emplace_back(namePrefix + "waiting", RETURN_TIMER_TIME(m_timers[Timers::SurfExchangeWait]));
9846 solverTimings.emplace_back(namePrefix + "waiting_send", RETURN_TIMER_TIME(m_timers[Timers::SEWaitSend]));
9847 solverTimings.emplace_back(namePrefix + "waiting_recv", RETURN_TIMER_TIME(m_timers[Timers::SEWaitRecv]));
9848
9849 solverTimings.emplace_back(namePrefix + "calcVolumeIntegral", RETURN_TIMER_TIME(m_timers[Timers::VolInt]));
9850
9851 solverTimings.emplace_back(namePrefix + "flux_calculation", RETURN_TIMER_TIME(m_timers[Timers::Flux]));
9852 solverTimings.emplace_back(namePrefix + "calcBoundarySurfaceFlux", RETURN_TIMER_TIME(m_timers[Timers::FluxBndry]));
9853 solverTimings.emplace_back(namePrefix + "calcInnerSurfaceFlux", RETURN_TIMER_TIME(m_timers[Timers::FluxInner]));
9854 solverTimings.emplace_back(namePrefix + "calcMpiSurfaceFlux", RETURN_TIMER_TIME(m_timers[Timers::FluxMPI]));
9855
9856 solverTimings.emplace_back(namePrefix + "surface_integrals", RETURN_TIMER_TIME(m_timers[Timers::SurfInt]));
9857 solverTimings.emplace_back(namePrefix + "applyJacobian", RETURN_TIMER_TIME(m_timers[Timers::Jacobian]));
9858 solverTimings.emplace_back(namePrefix + "calcSourceTerms", RETURN_TIMER_TIME(m_timers[Timers::Sources]));
9859 solverTimings.emplace_back(namePrefix + "resetExtSources",
9860 RETURN_TIMER_TIME(m_timers[Timers::ResetExternalSources]));
9861 solverTimings.emplace_back(namePrefix + "applyExternalSources",
9862 RETURN_TIMER_TIME(m_timers[Timers::ExternalSources]));
9863 solverTimings.emplace_back(namePrefix + "calcSpongeTerms", RETURN_TIMER_TIME(m_timers[Timers::Sponge]));
9864
9865 solverTimings.emplace_back(namePrefix + "time_integration", RETURN_TIMER_TIME(m_timers[Timers::TimeInt]));
9866
9867 solverTimings.emplace_back(namePrefix + "IO", RETURN_TIMER_TIME(m_timers[Timers::MainLoopIO]));
9868 solverTimings.emplace_back(namePrefix + "solution_analysis", RETURN_TIMER_TIME(m_timers[Timers::Analysis]));
9869 solverTimings.emplace_back(namePrefix + "adaptive_refinement",
9870 RETURN_TIMER_TIME(m_timers[Timers::AdaptiveRefinement]));
9871 } else {
9872 // Reduced/essential set of timings
9873 // MPI exchange
9874 solverTimings.emplace_back(namePrefix + "MPI_surface_exchange", RETURN_TIMER_TIME(m_timers[Timers::SurfExchange]));
9875 // Boundary conditions
9876 solverTimings.emplace_back(namePrefix + "calcBoundarySurfaceFlux", RETURN_TIMER_TIME(m_timers[Timers::FluxBndry]));
9877 }
9878#endif
9879}
MFloat returnIdleRecord() const
Definition: solver.h:486
MFloat returnLoadRecord() const
Definition: solver.h:485

◆ globalToLocalIds()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::globalToLocalIds
overridevirtual
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

Reimplemented from Solver.

Definition at line 9519 of file dgcartesiansolver.cpp.

9519 {
9520 TRACE();
9521
9522 // Nothing to do if solver is not active
9523 if(!isActive()) {
9524 return;
9525 }
9526
9527 const MInt domainOffset = grid().domainOffset(domainId());
9528 const MInt noElements = m_elements.size();
9529 // Change global cell ids to local cell ids
9530 for(MInt elementId = 0; elementId < noElements; elementId++) {
9531 const MInt localCellId = m_elements.cellId(elementId) - domainOffset;
9532 m_elements.cellId(elementId) = localCellId;
9533 }
9534}

◆ hasAdaptivePref()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::hasAdaptivePref
private
Author
Sven Berger

Definition at line 9235 of file dgcartesiansolver.cpp.

9235 {
9236 TRACE();
9237
9238 return (m_adaptivePref > 0 && hasPref());
9239}

◆ hasMpiExchange()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::hasMpiExchange
private

Definition at line 3972 of file dgcartesiansolver.cpp.

3972 {
3973 TRACE();
3974
3975 // If InitMpiExchange has not been performed yet: Initialize it, if the grid has neighbor
3976 // domains. Else if InitMpiExchange has been performed: m_noExchangeNghbrDomains describes
3977 // number of neighbor domains, with which actually data has to be exchanged. Look also in
3978 // initMpiExchange().
3979 const MBool neighbors = m_isInitMpiExchange ? m_noExchangeNghbrDomains > 0 : grid().noNeighborDomains() > 0;
3980
3981 // Return true if executed on more than one domain *or* if there exist neighbor domains (the
3982 // latter may occur in case of periodicity)
3983 return (noDomains() > 1 || neighbors);
3984}

◆ hasNeighborCell()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::hasNeighborCell ( const MInt  elementId,
const MInt  dir 
)
private

Check if an element has a neighbor cell in the given direction.

Author
Sven Berger
Date
Februar 2015
Parameters
[in]elementIdElement for which neighbor level is requested.
[in]dirDirection of neighbor element (-x,+x,-y,... = 0,1,2,...).
Returns
If an cell exists in given direction.

This method is smart and does not just return false if there is no same-level neighbor, but also checks if there are refined (smaller) or coarsened (larger) neighbor element(s).

Definition at line 9136 of file dgcartesiansolver.cpp.

9136 {
9137 // TRACE();
9138
9139 const MInt cellId = m_elements.cellId(elementId);
9140 MInt nghbrCellId = grid().tree().neighbor(cellId, dir);
9141
9142 // If neigbor cell does not exist on current level, check parent level
9143 if(nghbrCellId < 0 && grid().tree().hasParent(cellId)) {
9144 nghbrCellId = grid().tree().neighbor(grid().tree().parent(cellId), dir);
9145 }
9146
9147 return nghbrCellId >= 0;
9148}

◆ hasPref()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::hasPref
private
Author
Bjoern Peeters

Definition at line 9245 of file dgcartesiansolver.cpp.

9245 {
9246 TRACE();
9247
9248 return (m_pref == 1 && m_minPolyDeg != m_maxPolyDeg);
9249}

◆ hasSplitBalancing()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::hasSplitBalancing ( ) const
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 410 of file dgcartesiansolver.h.

410{ return 1; }

◆ hasSurface()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::hasSurface ( const MInt  elementId,
const MInt  dir 
)
private
Author
Sven Berger
Date
November 2014
Parameters
[in]elementIdId of element to check.
[in]dirDirection element-> surface (0..5 -> -x,+x,-y,+y,-z,+z)
Returns
True if surface exists, false otherwise.

Definition at line 3236 of file dgcartesiansolver.cpp.

3236 {
3237 TRACE();
3238 return m_elements.surfaceIds(elementId, dir) > -1;
3239}

◆ initBoundarySurface()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::initBoundarySurface ( const MInt  elementId,
const MInt  dir 
)
private
Author
Sven Berger
Date
Februar 2014
Parameters
[in]elementIdId of element to check.
[in]dirDirection element->surface (0..5 -> -x,+x,-y,+y,-z,+z)

Definition at line 3251 of file dgcartesiansolver.cpp.

3251 {
3252 TRACE();
3253
3254 const MInt surfaceId = createSurface(elementId, dir);
3256
3257 return surfaceId;
3258}

◆ initData()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initData
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-10-19

Definition at line 1255 of file dgcartesiansolver.cpp.

1255 {
1256 TRACE();
1257 RECORD_TIMER_START(m_timers[Timers::InitData]);
1258
1259 // Abort if solver not initialized
1260 if(!m_isInitSolver) {
1261 TERMM(1, "Solver was not initialized.");
1262 }
1263
1264 if(m_restart) {
1265 m_log << "Restart is enabled." << endl;
1266
1267 // Load restart file
1269
1270 // Load node variable file
1271 if(SysEqn::noNodeVars() > 0 && !SysEqn::hasTimeDependentNodeVars()) {
1273 }
1274 } else {
1275 // Apply the initial conditions
1277
1278 // Reset global time step and simulation time
1279 m_timeStep = 0;
1281 m_firstTimeStep = true;
1282 }
1283
1284 // Reset current Runge Kutta stage
1285 m_rkStage = 0;
1286
1287 // Update all node variables, if they are used
1288 if(SysEqn::noNodeVars() > 0) {
1290 // TODO labels:DG,toenhance not required at a restart when loading nodevars, but could be used to overwrite saved
1291 // node vars/change extension
1293 }
1294
1295 // Set status to initialized
1296 m_isInitData = true;
1297
1298 RECORD_TIMER_STOP(m_timers[Timers::InitData]);
1299}
void loadNodeVarsFile()
Load node variables from file.
void loadRestartFile() override
Load restart file with all information that is necessary to restart the calculations from here.
virtual void initialCondition()
Set the initial condition in all elements.

◆ initDgCartesianSolver()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initDgCartesianSolver
private
Author
Michael Schlottke
Date
October 2012

Definition at line 200 of file dgcartesiansolver.cpp.

◆ initElements()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initElements
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2014-02-13

Definition at line 2298 of file dgcartesiansolver.cpp.

2298 {
2299 TRACE();
2300
2301 m_log << "Initializing elements... ";
2302 for(MInt cellId = 0; cellId < grid().noInternalCells(); cellId++) {
2303 // Check if element needs to be created
2304 if(needElementForCell(cellId)) {
2305 createElement(cellId);
2306 }
2307 }
2308 m_log << "done" << endl;
2309}
void createElement(const MInt cellId)
Create element for cell with id cellId.

◆ initGridMap()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initGridMap
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2014-11-29

Definition at line 1977 of file dgcartesiansolver.cpp.

◆ initHElements()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initHElements
private
Author
Sven Berger
Date
March 2015

Definition at line 2317 of file dgcartesiansolver.cpp.

2317 {
2318 TRACE();
2319
2320 m_log << "Initializing h-refined elements... ";
2321
2322 for(MInt cellId = 0; cellId < grid().noInternalCells(); cellId++) {
2323 // Check if h-element needs to be created
2324 if(needHElementForCell(cellId)) {
2325 createHElement(cellId);
2326 }
2327 }
2328
2329 m_log << "done" << endl;
2330}
void createHElement(const MInt cellId)
Create h-element for cell with id cellId.

◆ initialCondition()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initialCondition
privatevirtual
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-12-03

Definition at line 4512 of file dgcartesiansolver.cpp.

4512 {
4513 TRACE();
4514 RECORD_TIMER_START(m_timers[Timers::InitialCondition]);
4515
4516 m_log << "Applying initial conditions... ";
4517
4518 const MFloat time = m_startTime;
4519
4520 // First apply initial conditions from coupling
4521 // Note: changed with unified run loop, if you need to overwrite an initial condition set by the
4522 // coupling initialCondition() needs to be called again from the coupler!
4523
4524 // Iterate over all elements
4525 const MInt noElements = m_elements.size();
4526 for(MInt elementId = 0; elementId < noElements; elementId++) {
4527 const MInt noNodes1D = m_elements.noNodes1D(elementId);
4528 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
4529 // Set node vars to minimum 1 to avoid errors in Tensor
4530 // TODO labels:DG,totest Check if this is really sensible
4531 MFloatTensor nodeVars(&m_elements.nodeVars(elementId), noNodes1D, noNodes1D, noNodes1D3,
4532 max(SysEqn::noNodeVars(), 1));
4533 MFloatTensor u(&m_elements.variables(elementId), noNodes1D, noNodes1D, noNodes1D3, SysEqn::noVars());
4534 MFloatTensor x(&m_elements.nodeCoordinates(elementId), noNodes1D, noNodes1D, noNodes1D3, nDim);
4535 // Loop over all nodes and apply initial condition at all integration points
4536 for(MInt i = 0; i < noNodes1D; i++) {
4537 for(MInt j = 0; j < noNodes1D; j++) {
4538 for(MInt k = 0; k < noNodes1D3; k++) {
4539 // Apply initial condition
4540 m_sysEqn.calcInitialCondition(time, &x(i, j, k, 0), &nodeVars(i, j, k, 0), &u(i, j, k, 0));
4541 }
4542 }
4543 }
4544 }
4545
4546 m_log << "done" << endl;
4547
4548 RECORD_TIMER_STOP(m_timers[Timers::InitialCondition]);
4549}

◆ initInnerSurface()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::initInnerSurface ( const MInt  elementId,
const MInt  dir 
)
private
Author
Sven Berger
Date
Februar 2014
Parameters
[in]elementIdId of element to check.
[in]dirDirection element->surface (0..5 -> -x,+x,-y,+y,-z,+z)

If the neighboring cell/element is h-refined with respect to the current (coarse) cell/element, no surfaces are created. Surfaces are always created from the refined to the coarses elements, and there is one surface per refined element (i.e. in 2D there will be at most 2 surfaces for each fine-coarse interface, and in 3D there will be at most 5 surfaces). This is different form initMpiSurface, where surfaces are created from the point of view of the coarse element as well.

Definition at line 3279 of file dgcartesiansolver.cpp.

3279 {
3280 TRACE();
3281
3282 MInt cellId = m_elements.cellId(elementId);
3283
3284 // No surface if there is no neighbor cell on current and parent level
3285 if(!grid().tree().hasNeighbor(cellId, dir)) {
3286 const MInt parentId = grid().tree().parent(cellId);
3287 if(parentId > -1 && grid().tree().hasNeighbor(parentId, dir)) {
3288 // If parent cell exists and it has neighbor in correct direction, use
3289 // parent to determine neighbor cell
3290 cellId = parentId;
3291 } else {
3292 // Otherwise there is no neighbor in the specified direction, so quit
3293 // without creating a surface
3294 return -1;
3295 }
3296 }
3297
3298 const MInt nghbrId = grid().tree().neighbor(cellId, dir);
3299
3300 // If child exists skip since surfaces are created on highest level
3301 if(grid().tree().hasChildren(nghbrId)) {
3302 return -1;
3303 }
3304
3305 // No surface if neighbor is a halo cell
3306 if(grid().tree().hasProperty(nghbrId, Cell::IsHalo)) {
3307 return -1;
3308 }
3309
3310 // No surface if there is no neighbor element
3311 const MInt nghbrElementId = m_elements.getElementByCellId(nghbrId);
3312 if(nghbrElementId == -1) {
3313 return -1;
3314 }
3315
3316 // Create surface
3317 const MInt surfaceId = createSurface(elementId, dir);
3319
3320 return surfaceId;
3321}

◆ initInterpolation()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initInterpolation
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-11-13

Definition at line 2649 of file dgcartesiansolver.cpp.

2649 {
2650 TRACE();
2651
2652 m_log << "Initializing interpolation data... ";
2653
2654 // Interpolation
2655 m_interpolation.clear();
2656 m_interpolation.resize(m_maxPolyDeg + 1);
2657 for(MInt polyDeg = m_minPolyDeg; polyDeg <= m_maxPolyDeg; polyDeg++) {
2658 m_interpolation[polyDeg].clear();
2659 m_interpolation[polyDeg].resize(m_maxNoNodes1D + 1);
2660 }
2661
2662 // Convert integers to enums
2663 auto polyType = static_cast<DgPolynomialType>(m_dgPolynomialType);
2664 auto intMethod = static_cast<DgIntegrationMethod>(m_dgIntegrationMethod);
2665
2666 // Create DgInterpolation object for each possible occurring polynomial
2667 // degree AND number of nodes (trivial for DG, necessary for SBP)
2668
2669 for(MInt i = m_minPolyDeg; i <= m_maxPolyDeg; i++) {
2670 MInt prefIndex = -1;
2671 for(std::vector<MFloat>::size_type j = 0; j < m_prefPatchesPolyDeg.size(); j++) {
2672 if(i == (MInt)m_prefPatchesPolyDeg[j]) {
2673 prefIndex = j;
2674 break;
2675 }
2676 }
2677
2678 MString refOperator = m_sbpOperator;
2679 MInt refNoNodes1D = m_sbpMode ? m_initNoNodes1D : (i + 1);
2680 if(prefIndex != -1) {
2681 refOperator = m_prefPatchesOperators[prefIndex];
2682 refNoNodes1D = m_prefPatchesNoNodes1D[prefIndex];
2683 }
2684 m_interpolation[i][refNoNodes1D].init(i, polyType, refNoNodes1D, intMethod, m_sbpMode, refOperator);
2685 }
2686
2687 // Local and global volume
2688 // Calculate the local and global volume for use in error normalizations
2689 m_globalVolume = F0;
2690 m_localVolume = F0;
2691 for(MInt elementId = 0; elementId < m_elements.size(); elementId++) {
2692 const MInt cellId = m_elements.cellId(elementId);
2693 m_localVolume += pow(grid().cellLengthAtCell(cellId), nDim);
2694 }
2695
2696 RECORD_TIMER_START(m_timers[Timers::Accumulated]);
2697 RECORD_TIMER_START(m_timers[Timers::MPI]);
2698 RECORD_TIMER_START(m_timers[Timers::MPIComm]);
2699 MPI_Allreduce(&m_localVolume, &m_globalVolume, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "m_localVolume",
2700 "m_globalVolume");
2701 RECORD_TIMER_STOP(m_timers[Timers::MPIComm]);
2702 RECORD_TIMER_STOP(m_timers[Timers::MPI]);
2703 RECORD_TIMER_STOP(m_timers[Timers::Accumulated]);
2704
2705 // Init interpolation for error analysis
2706 if(m_calcErrorNorms) {
2707 // Init interpolation object for error analysis
2709
2710 // Create volume weights for error analysis
2711 const MInt noNodesAnalysis1D = m_noAnalysisNodes;
2712 const MInt noNodesAnalysis1D3 = (nDim == 3) ? noNodesAnalysis1D : 1;
2713 m_wVolumeAnalysis.resize(noNodesAnalysis1D, noNodesAnalysis1D, noNodesAnalysis1D3);
2714 const MFloatVector& wInt = m_interpAnalysis.m_wInt;
2715 for(MInt i = 0; i < noNodesAnalysis1D; i++) {
2716 for(MInt j = 0; j < noNodesAnalysis1D; j++) {
2717 for(MInt k = 0; k < noNodesAnalysis1D3; k++) {
2718 m_wVolumeAnalysis(i, j, k) = wInt[i] * wInt[j] * (nDim == 3 ? wInt[k] : F1);
2719 }
2720 }
2721 }
2722
2723 // Create analysis Vandermonde matrices to interpolate the solution from the
2724 // calculation nodes to the analysis nodes
2725 m_vdmAnalysis.clear();
2726 m_vdmAnalysis.resize(m_maxPolyDeg + 1);
2727 for(MInt polyDeg = m_minPolyDeg; polyDeg <= m_maxPolyDeg; polyDeg++) {
2728 m_vdmAnalysis[polyDeg].clear();
2729 m_vdmAnalysis[polyDeg].resize(m_maxNoNodes1D + 1);
2730 }
2731
2732
2733 // Create matrices
2734 for(MInt polyDeg = m_minPolyDeg; polyDeg <= m_maxPolyDeg; polyDeg++) {
2735 if(m_sbpMode) {
2736 for(MInt noNodes1D = m_minNoNodes1D; noNodes1D <= m_maxNoNodes1D; noNodes1D++) {
2737 m_vdmAnalysis[polyDeg][noNodes1D].resize(m_noAnalysisNodes, noNodes1D);
2738 const DgInterpolation& interp = m_interpolation[polyDeg][noNodes1D];
2739 ASSERT(noNodes1D == m_noAnalysisNodes,
2740 "For now SBP Error Analysis only supports direct evaluation at regular nodes "
2741 "without interpolation...(noNodes1D = "
2742 + to_string(noNodes1D) + ", noAnalysisNodes = " + to_string(m_noAnalysisNodes) + ")");
2743
2745 &interp.m_nodes[0],
2748 &m_vdmAnalysis[polyDeg][noNodes1D][0]);
2749 }
2750 } else {
2751 const MInt noNodes1D = polyDeg + 1;
2752 m_vdmAnalysis[polyDeg][noNodes1D].resize(m_noAnalysisNodes, noNodes1D);
2753 const DgInterpolation& interp = m_interpolation[polyDeg][noNodes1D];
2755 &interp.m_nodes[0],
2758 &interp.m_wBary[0],
2759 &m_vdmAnalysis[polyDeg][noNodes1D][0]);
2760 }
2761 }
2762 }
2763
2764 m_log << "done" << endl;
2765}
std::vector< MFloat > m_prefPatchesPolyDeg
DgInterpolation m_interpAnalysis
std::vector< MString > m_prefPatchesOperators
std::vector< MInt > m_prefPatchesNoNodes1D
void init(const MInt polyDeg, const DgPolynomialType polyType, const MInt noNodes, const DgIntegrationMethod intMethod, const MBool sbpMode, const MString sbpOperator)
Sets the member variables and calls the appropriate functions to calculate the nodes and weights etc.
DgPolynomialType
Definition: enums.h:310
DgIntegrationMethod
Definition: enums.h:313
void calcPolynomialInterpolationMatrix(MInt noNodesIn, const T nodesIn, MInt noNodesOut, const U nodesOut, const V wBary, W vandermonde)
Calculate the polynomial interpolation matrix (Vandermonde) to interpolate from one set of nodes to a...
void calcLinearInterpolationMatrix(const MInt noNodesIn, const T nodesIn, const MInt noNodesOut, const U nodesOut, V vandermonde)
Calculates the linear interpolation matrix (Vandermonde) to interpolate from one set of nodes to anot...

◆ initInterpolationForCell()

template<MInt nDim, class SysEqn >
virtual void DgCartesianSolver< nDim, SysEqn >::initInterpolationForCell ( const MInt   NotUsedcellId)
inlinevirtual

Definition at line 328 of file dgcartesiansolver.h.

328{};

◆ initJacobian()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initJacobian
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-12-23

The Jacobian describes the mapping of the arbitarily-sized (but squared or cubic) elements to the reference element [-1,1] x [-1,1] x [-1,1]. For regular elements it is always (element length)/2. However, since we only ever need the inverse Jacobian, the inverse is saved, i.e. 2/(element length), to make the code more efficient.

Definition at line 2845 of file dgcartesiansolver.cpp.

2845 {
2846 TRACE();
2847
2848 m_log << "Initializing inverse Jacobian determinant... ";
2849
2850 const MInt noElements = m_elements.size();
2851 MFloat* invJacobians = &m_elements.invJacobian(0);
2852
2853 for(MInt i = 0; i < noElements; i++) {
2854 const MInt cellId = m_elements.cellId(i);
2855 invJacobians[i] = F2 / grid().cellLengthAtCell(cellId);
2856 }
2857
2858 m_log << "done" << endl;
2859}

◆ initMainLoop()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initMainLoop
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-10-19

Definition at line 1307 of file dgcartesiansolver.cpp.

1307 {
1308 TRACE();
1309 RECORD_TIMER_START(m_timers[Timers::InitMainLoop]);
1310
1311 // Abort if data not initialized
1312 if(!m_isInitData) {
1313 TERMM(1, "Solver data was not initialized.");
1314 }
1315
1316 if(!m_restart) {
1317 // Save initial state before entering main loop
1320 }
1321
1322 // Save node variables for restarting if they are constant in time
1323 if(SysEqn::noNodeVars() > 0 && !SysEqn::hasTimeDependentNodeVars()) {
1326 }
1327 }
1328
1329 // Save initial sampling data before entering main loop
1330 m_pointData.save(false);
1331 m_surfaceData.save(false);
1332 m_volumeData.save(false);
1333
1334 // Save inital slice data before entering main loop
1335 m_slice.save(false);
1336 }
1337
1338 // Init end auto save
1339 m_endAutoSaveTime = -1;
1340 m_endAutoSaveWritten = false;
1341 const char* envJobEndTime = getenv("MAIA_JOB_END_TIME");
1342
1343 if(envJobEndTime) {
1344 // Check if env variable only contains digits
1345 const MString jobEndTime(envJobEndTime);
1346 MBool onlyDigits = true;
1347 for(auto&& character : jobEndTime) {
1348 if(!isdigit(character)) {
1349 m_log << "Warning: the environment variable MAIA_JOB_END_TIME "
1350 "included non-digit characters.\n"
1351 << "Saving a restart file before the compute job ends is NOT "
1352 "active."
1353 << endl;
1354 onlyDigits = false;
1355 break;
1356 }
1357 }
1358 // Only activate if MAIA_JOB_END_TIME is a proper integer
1359 if(onlyDigits) {
1360 m_endAutoSaveTime = stoi(jobEndTime);
1362 m_log << "Activated automatic restart file writing at " << ctime(&m_endAutoSaveTime)
1363 << " (in Unix time: " << m_endAutoSaveTime << ")." << endl;
1364 }
1365 }
1366
1367 // Output initialization summary
1369
1370 // Init main loop
1371 analyzeTimeStep(m_time, F0, F0, m_timeStep, F0);
1372
1373 // Init timing for run time statistics
1376 m_outputTime = 0.0;
1378
1379 // Set status to initialized
1380 m_isInitMainLoop = true;
1381
1382 RECORD_TIMER_STOP(m_timers[Timers::InitMainLoop]);
1383
1384 // If multiphysics-optimized parallelization is used, prolong and start
1385 // tranmitting
1386 if(g_splitMpiComm) {
1387 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
1388 RECORD_TIMER_START(m_timers[Timers::RungeKuttaStep]);
1389 RECORD_TIMER_START(m_timers[Timers::TimeDeriv]);
1393 RECORD_TIMER_STOP(m_timers[Timers::TimeDeriv]);
1394 RECORD_TIMER_STOP(m_timers[Timers::RungeKuttaStep]);
1395 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
1396 }
1397}
void saveNodeVarsFile()
Save node variables to file.
void analyzeTimeStep(MFloat t, MFloat runTimeRelative, MFloat runTimeTotal, MInt timeStep, MFloat dt)
Calculates and prints the L^2 and L^inf errors (using calcErrorNorms()) for the current time.
std::time_t m_endAutoSaveTime
void outputInitSummary()
Print initialization summary to user and m_log.
void save(MBool finalTimestep)
Definition: samplingdata.h:832

◆ initMortarProjections()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initMortarProjections
private
Author
Sven Berger
Date
Januar 2014

Note: If the way how memory is allocated for the matrices is changed here, there is a good chance that they have to be changed in mortarH() and/or mortarP() as well. Note: Projections have been taken from: Kopriva, D. A.; Woodruff, S. L. & Hussaini, M.: Computation of electromagnetic scattering with a non-conforming discontinuous spectral element method, Int. Journal for Numerical Methods in Engineering, 2002, 53, 105-222. Note: Further information can be found in: Sven Berger: Implementation and validation of an adaptive hp-refinement method for the discontinuous Galerkin spectral element method. Master thesis, RWTH Aachen University, 2014.

Definition at line 8332 of file dgcartesiansolver.cpp.

8332 {
8333 TRACE();
8334 RECORD_TIMER_START(m_timers[Timers::InitMortarProjection]);
8335
8336 m_log << "Initializing mortar projections... ";
8337
8338 using namespace dg::interpolation;
8339
8340 // Init h-refinement mortar projection matrices
8341 // All four matrices for a particular polynomial degree are stored
8342 // coonsecutively. A second data structure with pointers stores the location
8343 // for each matrix.
8344
8345 m_projectionMatricesH.clear();
8347 // Allocate storage for all h-refinement projection matrices
8348 MInt sizeH = 0;
8349 for(MInt noNodes1D = m_minNoNodes1D; noNodes1D <= m_maxNoNodes1D; noNodes1D++) {
8350 sizeH += 4 * noNodes1D * noNodes1D;
8351 }
8352 m_projectionMatricesH.resize(sizeH);
8353
8354 // Store pointers to matrices
8356 MInt offset = 0;
8357 for(MInt noNodes1D = m_minNoNodes1D; noNodes1D <= m_maxNoNodes1D; noNodes1D++) {
8358 for(MInt p = 0; p < 4; p++) {
8359 m_projectionMatrixPointersH[4 * noNodes1D + p] = &m_projectionMatricesH[offset];
8360 offset += noNodes1D * noNodes1D;
8361 }
8362 }
8363
8364 // Calculate matrices
8365 if(m_sbpMode) {
8366 for(MInt noNodes1D = m_minNoNodes1D; noNodes1D <= m_maxNoNodes1D; noNodes1D++) {
8367 using namespace sbp::mortar;
8368 // Calculate fwd,bwd x lwr,upr projections matrices (all at onces)
8369 calcMortarProjectionMatrixHSBP(m_initPolyDeg, m_sbpOperator, mortarH<dg::mortar::forward>(noNodes1D, lower),
8370 mortarH<dg::mortar::forward>(noNodes1D, upper),
8371 mortarH<dg::mortar::reverse>(noNodes1D, lower),
8372 mortarH<dg::mortar::reverse>(noNodes1D, upper));
8373 }
8374 } else {
8375 for(MInt polyDeg = m_minPolyDeg; polyDeg <= m_maxPolyDeg; polyDeg++) {
8376 const MInt noNodes1D = polyDeg + 1;
8377 const DgInterpolation& interp = m_interpolation[polyDeg][noNodes1D];
8378 const MFloat* const nodes = &interp.m_nodes[0];
8379 const MFloat* const wBary = &interp.m_wBary[0];
8380 using namespace dg::mortar;
8381
8382 // Calculate first forward projection matrix
8384 mortarH<dg::mortar::forward>(noNodes1D, dg::mortar::lower));
8385
8386 // Calculate second forward projection matrix
8388 mortarH<dg::mortar::forward>(noNodes1D, dg::mortar::upper));
8389
8390 // Calculate first reverse projection matrix
8392 mortarH<dg::mortar::reverse>(noNodes1D, dg::mortar::lower));
8393
8394 // Calculate second reverse projection matrix
8396 mortarH<dg::mortar::reverse>(noNodes1D, dg::mortar::upper));
8397 }
8398 }
8399
8400 // Init p-refinement mortar projection matrices
8401 // The forward/reverse matrices for a particular polyDegHi/polyDegLo
8402 // combination are stored consecutively. A second data structure stores
8403 // pointers to the beginning of each matrix.
8404
8405 m_projectionMatricesP.clear();
8407 // Allocate storage for all p-refinement projection matrices
8408 MInt sizeP = 0;
8409 for(MInt polyDegHi = m_minPolyDeg; polyDegHi <= m_maxPolyDeg; polyDegHi++) {
8410 for(MInt polyDegLo = m_minPolyDeg; polyDegLo < polyDegHi; polyDegLo++) {
8411 sizeP += 2 * (polyDegHi + 1) * (polyDegLo + 1);
8412 }
8413 }
8414 m_projectionMatricesP.resize(sizeP);
8415
8416 // Store pointers to matrices
8418 sizeP = 0;
8419 for(MInt polyDegHi = m_minPolyDeg; polyDegHi <= m_maxPolyDeg; polyDegHi++) {
8420 for(MInt polyDegLo = m_minPolyDeg; polyDegLo < polyDegHi; polyDegLo++) {
8421 for(MInt p = 0; p < 2; p++) {
8422 const MInt idx = 2 * (polyDegHi * (polyDegHi - 1) / 2 + polyDegLo) + p;
8424 sizeP += (polyDegHi + 1) * (polyDegLo + 1);
8425 }
8426 }
8427 }
8428
8429 // Calculate matrices
8430 if(m_sbpMode) {
8431 // Read SBP Projection Matrices
8432 for(MInt polyDegHi = m_minPolyDeg; polyDegHi <= m_maxPolyDeg; polyDegHi++) {
8433 for(MInt polyDegLo = m_minPolyDeg; polyDegLo < polyDegHi; polyDegLo++) {
8434 auto operatorLo = m_sbpOperator;
8435 auto operatorHi = m_sbpOperator;
8436
8437 for(MUint j = 0; j < m_prefPatchesPolyDeg.size(); j++) {
8438 if(polyDegLo == (MInt)m_prefPatchesPolyDeg[j]) {
8439 operatorLo = m_prefPatchesOperators[j];
8440 }
8441 if(polyDegHi == (MInt)m_prefPatchesPolyDeg[j]) {
8442 operatorHi = m_prefPatchesOperators[j];
8443 }
8444 }
8445
8446 sbp::mortar::calcMortarProjectionMatrixPSBP(operatorLo, operatorHi, polyDegLo, polyDegHi,
8447 mortarP<dg::mortar::forward>(polyDegLo, polyDegHi),
8448 mortarP<dg::mortar::reverse>(polyDegLo, polyDegHi));
8449 }
8450 }
8451
8452 } else {
8453 // Calculate DG Projection Matrices by using Lagrange interpolation
8454 for(MInt polyDegHi = m_minPolyDeg; polyDegHi <= m_maxPolyDeg; polyDegHi++) {
8455 const MInt noNodes1DHi = polyDegHi + 1;
8456 const DgInterpolation& interpHi = m_interpolation[polyDegHi][noNodes1DHi];
8457 for(MInt polyDegLo = m_minPolyDeg; polyDegLo < polyDegHi; polyDegLo++) {
8458 const MInt noNodes1DLo = polyDegLo + 1;
8459 const DgInterpolation& interpLo = m_interpolation[polyDegLo][noNodes1DLo];
8460
8461 const MFloat* const nodesHi = &interpHi.m_nodes[0];
8462 const MFloat* const wBaryHi = &interpHi.m_wBary[0];
8463 const MFloat* const nodesLo = &interpLo.m_nodes[0];
8464 const MFloat* const wBaryLo = &interpLo.m_wBary[0];
8465
8466 // Calculate forward projection matrix from lower to higher polynomial
8467 // degree
8468 dg::mortar::calcMortarProjectionMatrixP(polyDegLo, nodesLo, wBaryLo, polyDegHi, nodesHi,
8469 mortarP<dg::mortar::forward>(polyDegLo, polyDegHi));
8470
8471 // Calculate reverse projection matrix from higher to lower polynomial
8472 // degree
8473 dg::mortar::calcMortarProjectionMatrixP(polyDegHi, nodesHi, wBaryHi, polyDegLo, nodesLo,
8474 mortarP<dg::mortar::reverse>(polyDegLo, polyDegHi));
8475 }
8476 }
8477 }
8478 m_log << "done" << endl;
8479
8480 RECORD_TIMER_STOP(m_timers[Timers::InitMortarProjection]);
8481}
std::vector< MFloat > m_projectionMatricesH
std::vector< MFloat * > m_projectionMatrixPointersH
std::vector< MFloat * > m_projectionMatrixPointersP
std::vector< MFloat > m_projectionMatricesP
uint32_t MUint
Definition: maiatypes.h:63
void calcMortarProjectionMatrixHReverse(const MInt polyDeg, const MFloat *const nodes, const MFloat *const wBary, const MInt position, MFloat *const matrix)
void calcMortarProjectionMatrixHForward(const MInt polyDeg, const MFloat *const nodes, const MFloat *const wBary, const MInt position, MFloat *const matrix)
void calcMortarProjectionMatrixP(const MInt sourcePolyDeg, const MFloat *const sourceNodes, const MFloat *const sourceBaryWeights, const MInt targetPolyDeg, const MFloat *const targetNodes, MFloat *const matrix)
void calcMortarProjectionMatrixHSBP(const MInt noNodes, const MString sbpOperator, MFloat *const forwardLower, MFloat *const forwardUpper, MFloat *const backwardLower, MFloat *const backwardUpper)
Reads and constructs h-refinement projection operator.
void calcMortarProjectionMatrixPSBP(const MString sourceOp, const MString targetOp, const MInt sourceNoNodes, const MInt targetNoNodes, MFloat *const f, MFloat *const b)
Reads projection coefficients and stores them.

◆ initMpiExchange()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initMpiExchange
private

Definition at line 3996 of file dgcartesiansolver.cpp.

3996 {
3997 TRACE();
3998
3999 m_log << "Initialize MPI exchange... ";
4000
4001 // Create map domain ids to exchange neighbor domain ids
4002 map<MInt, MInt> exchangeNghbrDomainMap;
4003
4004 // Reset number of exchange neighbor domains (i.e. domains with which actual
4005 // data needs to be exchanged, as opposed to neighbor domains, with which just
4006 // halo/window cells are shared).
4008
4009 // Initialize resize containers to max. number of exchange domains
4012
4013 // Fill MPI surfaces container with surfaces that need to be exchanged with
4014 // the respective domain
4015 const MInt begin = m_mpiSurfacesOffset;
4017 for(MInt srfcId = begin; srfcId < end; srfcId++) {
4018 const MInt internalSideId = m_surfaces.internalSideId(srfcId);
4019 const MInt elementId = m_surfaces.nghbrElementIds(srfcId, internalSideId);
4020 const MInt internalCellId = m_elements.cellId(elementId);
4021 const MInt nghbrCellDir = 2 * m_surfaces.orientation(srfcId) + 1 - internalSideId;
4022
4023 // Get halo cell
4024 MInt haloCellId = grid().tree().neighbor(internalCellId, nghbrCellDir);
4025 if(haloCellId == -1) {
4026 // If halo cell does not exist, get parent-level cell
4027 haloCellId = grid().tree().neighbor(grid().tree().parent(internalCellId), nghbrCellDir);
4028 }
4029
4030 // Get child-level halo cells if halo cell has children
4031 if(grid().tree().hasChildren(haloCellId)) {
4033 }
4034
4035 // Determine domain id
4036 MInt exchangeNghbrDomainId = -1;
4037 for(MInt i = 0; i < noDomains() + 1; i++) {
4038 if(grid().domainOffset(i) > grid().tree().globalId(haloCellId)) {
4039 exchangeNghbrDomainId = i - 1;
4040 break;
4041 }
4042 }
4043 ASSERT(exchangeNghbrDomainId > -1, "Could not find domain id!");
4044
4045 // Add new exchange neighbor domain if not yet existing
4046 if(exchangeNghbrDomainMap.count(exchangeNghbrDomainId) == 0) {
4047 m_exchangeNghbrDomains[m_noExchangeNghbrDomains] = exchangeNghbrDomainId;
4048 exchangeNghbrDomainMap[exchangeNghbrDomainId] = m_noExchangeNghbrDomains;
4050 }
4051
4052 // Add surface to container
4053 m_mpiSurfaces[exchangeNghbrDomainMap[exchangeNghbrDomainId]].push_back(srfcId);
4054 }
4055
4056 // Reset size of containers to actual size
4059
4060 // Sort the MPI surfaces container according to the global surface id
4061 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4062 sort(m_mpiSurfaces[i].begin(), m_mpiSurfaces[i].end(),
4063 [this](const MInt a, const MInt b) { return (m_surfaces.globalId(a) < m_surfaces.globalId(b)); });
4064 }
4065
4066 // Build a container for receiving periodic interfaces
4069
4070 // Modification for periodic boundary conditions. This is required since in case of periodic
4071 // boundary conditions with periodicity on the same MPI rank, two surfaces exist with the same
4072 // global surface id.
4073 if(grid().periodicCartesianDir(0) || grid().periodicCartesianDir(1)
4074 || (nDim == 3 && grid().periodicCartesianDir(2))) {
4075 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4076 // If a global surface id exists twice within one domain, change its order for receiving
4077 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size() - 1; j++) {
4079 swap(m_mpiRecvSurfaces[i][j], m_mpiRecvSurfaces[i][j + 1]);
4080 }
4081 }
4082 }
4083 }
4084
4085
4086 // TODO labels:DG,toremove Remove this debugging output once multi-solver simulations are properly tested
4087 // TODO labels:DG add test to check if mpi surfaces match on exchange domains!
4088 // stringstream ss;
4089 // ss << solverId() << " " << domainId() << " " << m_noExchangeNghbrDomains << " exchange neighb:";
4090 // for (MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4091 // ss << " " << m_exchangeNghbrDomains[i];
4092 //}
4093 // ss << endl;
4094 // for (MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4095 // ss << solverId() << " " << domainId() << " " << m_mpiSurfaces[i].size()
4096 // << " MPI surfaces for domain " << m_exchangeNghbrDomains[i] << ":";
4097 // for (MInt j = 0; j < static_cast<MInt>(m_mpiSurfaces[i].size()); j++) {
4098 // ss << " " << m_surfaces.globalId(m_mpiSurfaces[i][j]);
4099 // }
4100 // ss << endl;
4101 //}
4102 // ss << endl;
4103 // cout << ss.str() << endl;
4104 // m_log << ss.str() << endl;
4105
4106 // IMPORTANT:
4107 // If anything in the following loops is changed, please check if
4108 // updateNodeVariables() needs to be changed as well, since it contains more
4109 // or less the same code.
4110
4111#ifdef DG_USE_MPI_BUFFERS
4112 // Resize send/receive buffers
4115 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4116 MInt size = 0;
4117 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
4118 // Use max. noNodes to account for p-refined surfaces
4119 const MInt noNodes1D = m_maxNoNodes1D;
4120 const MInt noNodesXD = ipow(noNodes1D, nDim - 1);
4121 const MInt dataBlockSize = noNodesXD * SysEqn::noVars();
4122 size += dataBlockSize;
4123 }
4124
4125 m_sendBuffers[i].resize(size);
4126 m_recvBuffers[i].resize(size);
4127 }
4128#endif
4129#ifdef DG_USE_MPI_DERIVED_TYPES
4130#error Does not work anymore - need to fix for p-refinement!
4131 // Create and commit MPI derived datatypes for send/recv operations
4134 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4135 // Note: This method uses non-MAIA types for interfacing with an external
4136 // library
4137 // Count specifies the number of solvers in the derived data type
4138 const MInt count = m_mpiSurfaces[i].size();
4139
4140 // If count is zero, skip this domain (since there is no data to exchange)
4141 // and send the data type to a null type. This is used later to determine
4142 // that no data needs to be exchanged.
4143 if(count == 0) {
4144 m_sendTypes[i] = MPI_DATATYPE_NULL;
4145 m_recvTypes[i] = MPI_DATATYPE_NULL;
4146 continue;
4147 }
4148
4149 vector<MInt> lengths(count);
4150 vector<MPI_Aint> displacementsSend(count);
4151 vector<MPI_Aint> displacementsRecv(count);
4152
4153 // Fill lengths and displacements vectors
4154 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
4155 const MInt srfcId = m_mpiSurfaces[i][j];
4156 // Set solver length
4157 const MInt noNodes1D = m_surfaces.noNodes1D(srfcId);
4158 const MInt noNodesXD = ipow(noNodes1D, nDim - 1);
4159 const MInt dataBlockSize = noNodesXD * SysEqn::noVars();
4160 lengths[j] = dataBlockSize;
4161
4162 // Set displacements
4163 const MInt internalSideId = m_surfaces.internalSideId(srfcId);
4164 MPI_Get_address(m_surfaces.variables(srfcId, internalSideId), &displacementsSend[j], AT_);
4165 MPI_Get_address(m_surfaces.variables(srfcId, 1 - internalSideId), &displacementsRecv[j], AT_);
4166 }
4167
4168 // Create MPI data types (hindexed since we're using absolute addresses for
4169 // the displacement)
4170 MPI_Type_create_hindexed(count, &lengths[0], &displacementsSend[0], type_traits<MFloat>::mpiType(), &m_sendTypes[i],
4171 AT_);
4172 MPI_Type_create_hindexed(count, &lengths[0], &displacementsRecv[0], type_traits<MFloat>::mpiType(), &m_recvTypes[i],
4173 AT_);
4174
4175 // Commit data types
4176 MPI_Type_commit(&m_sendTypes[i], AT_);
4177 MPI_Type_commit(&m_recvTypes[i], AT_);
4178 }
4179#endif
4180
4181 // Create persistent requests
4184 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4185#ifdef DG_USE_MPI_BUFFERS
4187 m_exchangeNghbrDomains[i], domainId(), mpiComm(), &m_sendRequests[i], AT_, "m_sendBuffers[i][0]");
4190 "m_recvBuffers[i][0]");
4191#endif
4192#ifdef DG_USE_MPI_DERIVED_TYPES
4194 AT_, "MPI_BOTTOM");
4196 &m_recvRequests[i], AT_, "MPI_BOTTOM");
4197#endif
4198 }
4199
4200 m_isInitMpiExchange = true;
4201 m_log << "done" << endl;
4202}
std::vector< std::vector< MFloat > > m_sendBuffers
MInt haloCellId(const MInt domainId, const MInt cellId) const
int MPI_Send_init(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Send_init
int MPI_Type_commit(MPI_Datatype *datatype, const MString &name)
same as MPI_Type_commit
int MPI_Recv_init(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Recv_init
int MPI_Type_create_hindexed(int count, const int array_of_solverlengths[], const MPI_Aint array_of_displacements[], MPI_Datatype oldtype, MPI_Datatype *newtype, const MString &name)
same as MPI_Type_create_hindexed
int MPI_Get_address(const void *location, MPI_Aint *address, const MString &name)
same as MPI_Get_address
void swap(Tensor< TT > &a, Tensor< TT > &b)
Non-member swap exchanges the contents of two Tensors.
Definition: tensor.h:752

◆ initMpiSurface()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::initMpiSurface ( const MInt  elementId,
const MInt  dir 
)
private
Author
Sven Berger
Date
Februar 2014
Parameters
[in]elementIdId of element to check.
[in]dirDirection element->surface (0..5 -> -x,+x,-y,+y,-z,+z)

If the corresponding halo cell is refined in comparison to the current cell, two surfaces are created. This is different to initInnterSurface, where surfaces are always created from the fine elements, never from the coarse element.

Definition at line 3338 of file dgcartesiansolver.cpp.

3338 {
3339 TRACE();
3340
3341 MInt cellId = m_elements.cellId(elementId);
3342
3343 // No surface if there is no neighbor cell on current and parent level
3344 if(!grid().tree().hasNeighbor(cellId, dir)) {
3345 const MInt parentId = grid().tree().parent(cellId);
3346 if(parentId > -1 && grid().tree().hasNeighbor(parentId, dir)) {
3347 // If parent cell exists and it has neighbor in correct direction, use
3348 // parent to determine neighbor cell
3349 cellId = parentId;
3350 } else {
3351 // Otherwise there is no neighbor in the specified direction, so quit
3352 // without creating a surface
3353 return -1;
3354 }
3355 }
3356
3357 const MInt nghbrId = grid().tree().neighbor(cellId, dir);
3358
3359 // Surface only with halo cells as neighbor OR
3360 // (in case of partition level shifts) if the neighbor has children (createHMPISurfaces will
3361 // handle/check such cases)
3362 if(!grid().tree().hasProperty(nghbrId, Cell::IsHalo) && !grid().tree().hasChildren(nghbrId)) {
3363 return -1;
3364 }
3365
3366 MInt surfaceId = -1;
3367
3368 // If child exists create multiple MPI surfaces
3369 if(grid().tree().hasChildren(nghbrId)) {
3370 // Create multiple surfaces
3371 surfaceId = createHMPISurfaces(elementId, dir);
3372 } else {
3373 // Create surface
3374 surfaceId = createSurface(elementId, dir);
3376 }
3377
3378 return surfaceId;
3379}
MInt createHMPISurfaces(const MInt elementId, const MInt dir)

◆ initNodeCoordinates()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initNodeCoordinates
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-11-28

Definition at line 2775 of file dgcartesiansolver.cpp.

2775 {
2776 TRACE();
2777
2778 m_log << "Initializing node coordinates... ";
2779
2780 const MInt noElements = m_elements.size();
2781
2782 // Iterate over all elements and calculate the integration node coordinates
2783 for(MInt elementId = 0; elementId < noElements; elementId++) {
2784 calcElementNodeCoordinates(elementId);
2785 }
2786
2787 m_log << "done" << endl;
2788}
void calcElementNodeCoordinates(const MInt elementId)
Calculates the coordinates of the integration nodes within the element.

◆ initPolynomialDegree()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initPolynomialDegree
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-12-03

Definition at line 2549 of file dgcartesiansolver.cpp.

2549 {
2550 TRACE();
2551
2552 m_log << "Initializing polynomial degree and number of nodes in the elements... ";
2553
2554 if(!hasPref()) {
2557 } else {
2558 // If p-refinement is used, select method based on property settings
2560 }
2561
2562 // Once the polynomial degree is set, calculate the total data size and number
2563 // of nodes on this domain.
2564 // The internal data size counts the total number of MFloats allocated for
2565 // the conservative variables
2566 m_internalDataSize = m_elements.size() * m_elements.maxNoNodesXD() * SysEqn::noVars();
2567
2568 // The total number of nodes counts the number of nodes that are in use, i.e.
2569 // not counting unused but allocated nodes for elements with a polynomial
2570 // degree less than the maximum
2571 m_noTotalNodesXD = 0;
2572 for(MInt i = 0; i < m_elements.size(); i++) {
2574 }
2575
2576 m_log << "done" << endl;
2577}
void initPrefinement()
Set polynomial degree for static p-refinement case.
MInt maxNoNodesXD() const
Return maximum number of nodes XD.

◆ initPrefinement()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initPrefinement
private
Author
Sven Berger, Bjoern Peeters
Date
November 2014, November 2015

Definition at line 2585 of file dgcartesiansolver.cpp.

2585 {
2586 TRACE();
2587
2588 m_log << "Static p-refinement is enabled." << endl;
2589
2590 MIntScratchSpace changed(m_elements.size(), AT_, "changed");
2591 fill(changed.begin(), changed.end(), 0);
2592 const MInt noElements = m_elements.size();
2593
2594 for(MInt elementId = 0; elementId < noElements; elementId++) {
2595 const MInt cellId = m_elements.cellId(elementId);
2596
2597 // Static p-refinement is done through patches that specify a region and a
2598 // polynomial degree. Elements that are in two or more patches get the
2599 // polynomial degree of the last matching patch.
2600
2601 // Initialize polynomial degree with initPolyDeg, which is used if no
2602 // matching patch is found
2603 MInt elemPolyDeg = m_initPolyDeg;
2604 MInt elemNoNodes1D = m_initNoNodes1D;
2605
2606 // Iterate over all defined patches to check if they contain the current
2607 // cell
2608 for(std::vector<MFloat>::size_type patchId = 0; patchId < m_prefPatchesPolyDeg.size(); patchId++) {
2609 MBool inPatch = true;
2610
2611 for(MInt i = 0; i < nDim; i++) {
2612 const MFloat cellCoord = grid().tree().coordinate(cellId, i);
2613
2614 if(cellCoord < m_prefPatchesCoords[patchId][i]) {
2615 inPatch = false;
2616 }
2617 if(cellCoord > m_prefPatchesCoords[patchId][i + nDim]) {
2618 inPatch = false;
2619 }
2620 }
2621
2622 // Set the new polynomial degree if the element lies inside the patch
2623 if(inPatch) {
2624 elemPolyDeg = m_prefPatchesPolyDeg[patchId];
2625 elemNoNodes1D = m_prefPatchesNoNodes1D[patchId];
2626
2627 changed[elementId]++;
2628 }
2629 }
2630 m_elements.polyDeg(elementId) = elemPolyDeg;
2631 m_elements.noNodes1D(elementId) = elemNoNodes1D;
2632 }
2633
2634 m_log << "p-refinement"
2635 << " changed the polynomial degree "
2636 << "on " << count_if(changed.begin(), changed.end(), [](MInt i) { return i > 0; }) << " elements in total for "
2637 << accumulate(changed.begin(), changed.end(), 0) << " times." << endl;
2638}
std::vector< std::array< MFloat, 2 *nDim > > m_prefPatchesCoords

◆ initSimulationStatistics()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initSimulationStatistics
private

Definition at line 4215 of file dgcartesiansolver.cpp.

4215 {
4216 TRACE();
4217
4218 m_log << "Initializing simulation statistics... ";
4219
4220 // Set or determine local statistics
4221
4222 // Minimum & maximum grid refinement level
4223 m_statLocalMinLevel = grid().minLevel();
4224 m_statLocalMaxLevel = grid().maxLevel();
4225
4226 // Total cell counts
4227 m_statLocalNoCells = grid().noCells();
4228 m_statLocalNoInternalCells = grid().noInternalCells();
4229 m_statLocalNoHaloCells = grid().noCells() - grid().noInternalCells();
4230 m_statLocalMaxNoCells = grid().raw().treeb().capacity();
4231
4232 // Total element counts
4235
4236 // Total surface counts
4242
4243 // Active cell/DOF count
4246 accumulate(&m_elements.noNodes1D(0), &m_elements.noNodes1D(0) + m_elements.size(), 0,
4247 [](const MInt result, const MInt noNodes1D) { return result + ipow(noNodes1D, nDim); });
4248
4249 // Count active DOF per polynomial degree (if there are multiple polyDegs)
4250 const MInt noPolyDegs = m_maxPolyDeg - m_minPolyDeg + 1;
4251 if(noPolyDegs > 1) {
4252 m_statLocalNoActiveDOFsPolyDeg.assign(noPolyDegs, 0);
4253 const MInt noElements = m_elements.size();
4254 for(MInt elementId = 0; elementId < noElements; elementId++) {
4255 const MInt polyDeg = m_elements.polyDeg(elementId);
4256 const MInt noDOFs = m_elements.noNodesXD(elementId);
4257 m_statLocalNoActiveDOFsPolyDeg[polyDeg - m_minPolyDeg] += noDOFs;
4258 }
4259 }
4260
4261
4262 // Minimum & maximum polynomial degrees
4265
4266 // Form sum of polynomial degress for average calculation
4268
4269 // Number of h- and p-refined surfaces
4271 [](const MInt id) { return id != -1; });
4273 // Only counted for inner surfaces
4274 // TODO labels:DG Also count for MPI surfaces
4275 for(MInt srfcId = m_innerSurfacesOffset; srfcId < m_innerSurfacesOffset + m_noInnerSurfaces; srfcId++) {
4276 const MInt elementIdL = m_surfaces.nghbrElementIds(srfcId, 0);
4277 const MInt elementIdR = m_surfaces.nghbrElementIds(srfcId, 1);
4278 if(m_elements.polyDeg(elementIdL) != m_elements.polyDeg(elementIdR)) {
4280 }
4281 }
4282
4283 // Determine global statistics
4284
4285 // Pack buffer
4286 MLong buffer[26];
4287 // Min
4288 buffer[0] = m_statLocalMinLevel;
4289 buffer[1] = m_statLocalMinPolyDeg;
4290 // Max
4291 buffer[2] = m_statLocalMaxLevel;
4292 buffer[3] = m_statLocalMaxPolyDeg;
4293 // Sum
4294 buffer[4] = m_statLocalNoCells;
4295 buffer[5] = m_statLocalNoInternalCells;
4296 buffer[6] = m_statLocalNoHaloCells;
4297 buffer[7] = m_statLocalMaxNoCells;
4298 buffer[8] = m_statLocalNoElements;
4299 buffer[9] = m_statLocalNoSurfaces;
4300 buffer[10] = m_statLocalNoBoundarySurfaces;
4301 buffer[11] = m_statLocalNoInnerSurfaces;
4302 buffer[12] = m_statLocalNoMpiSurfaces;
4303 buffer[13] = m_statLocalMaxNoSurfaces;
4304 buffer[14] = m_statLocalNoActiveCells;
4305 buffer[15] = m_statLocalNoActiveDOFs;
4306 buffer[16] = m_statLocalPolyDegSum;
4307 buffer[17] = m_statLocalNoHrefSurfs;
4308 buffer[18] = m_statLocalNoPrefSurfs;
4309 buffer[19] = m_statLocalNoHElements;
4310 buffer[20] = m_noCutOffBoundarySurfaces[0];
4311 buffer[21] = m_noCutOffBoundarySurfaces[1];
4312 buffer[22] = m_noCutOffBoundarySurfaces[2];
4313 buffer[23] = m_noCutOffBoundarySurfaces[3];
4314 IF_CONSTEXPR(nDim == 3) {
4315 buffer[24] = m_noCutOffBoundarySurfaces[4];
4316 buffer[25] = m_noCutOffBoundarySurfaces[5];
4317 }
4318 else {
4319 buffer[24] = 0;
4320 buffer[25] = 0;
4321 }
4322
4323 RECORD_TIMER_START(m_timers[Timers::Accumulated]);
4324 RECORD_TIMER_START(m_timers[Timers::MPI]);
4325 RECORD_TIMER_START(m_timers[Timers::MPIComm]);
4326
4327 // Exchange statistics
4328 // Operation: min
4329 MPI_Allreduce(MPI_IN_PLACE, &buffer[0], 2, MPI_INT, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "buffer[0]");
4330 // Operation: max
4331 MPI_Allreduce(MPI_IN_PLACE, &buffer[2], 2, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "buffer[2]");
4332 // Operation: sum
4333 MPI_Allreduce(MPI_IN_PLACE, &buffer[4], 22, maia::type_traits<MLong>::mpiType(), MPI_SUM, mpiComm(), AT_,
4334 "MPI_IN_PLACE", "buffer[4]");
4335
4336 RECORD_TIMER_STOP(m_timers[Timers::MPIComm]);
4337 RECORD_TIMER_STOP(m_timers[Timers::MPI]);
4338 RECORD_TIMER_STOP(m_timers[Timers::Accumulated]);
4339
4340 // Unpack buffer
4341 m_statGlobalMinLevel = buffer[0];
4342 m_statGlobalMinPolyDeg = buffer[1];
4343 m_statGlobalMaxLevel = buffer[2];
4344 m_statGlobalMaxPolyDeg = buffer[3];
4345 m_statGlobalNoCells = buffer[4];
4346 m_statGlobalNoInternalCells = buffer[5];
4347 m_statGlobalNoHaloCells = buffer[6];
4348 m_statGlobalMaxNoCells = buffer[7];
4349 m_statGlobalNoElements = buffer[8];
4350 m_statGlobalNoSurfaces = buffer[9];
4351 m_statGlobalNoBoundarySurfaces = buffer[10];
4352 m_statGlobalNoInnerSurfaces = buffer[11];
4353 m_statGlobalNoMpiSurfaces = buffer[12];
4354 m_statGlobalMaxNoSurfaces = buffer[13];
4355 m_statGlobalNoActiveCells = buffer[14];
4356 m_statGlobalNoActiveDOFs = buffer[15];
4357 m_statGlobalPolyDegSum = buffer[16];
4358 m_statGlobalNoHrefSurfs = buffer[17];
4359 m_statGlobalNoPrefSurfs = buffer[18];
4360 m_statGlobalNoHElements = buffer[19];
4367
4368 m_log << "done" << endl;
4369}
MLong m_statGlobalNoBoundarySurfaces
std::array< MLong, 6 > m_statGlobalNoCutOffBoundarySurfaces
std::array< MInt, 2 *nDim > m_noCutOffBoundarySurfaces

◆ initSolver()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initSolver
overridevirtual

Implements Solver.

Definition at line 1845 of file dgcartesiansolver.cpp.

1845 {
1846 TRACE();
1847 RECORD_TIMER_START(m_timers[Timers::Run]);
1848
1849 // Nothing to be done if solver is not active
1850 if(!isActive()) {
1851 // TODO labels:DG inactive ranks need to call createGridSlice as well
1852 TERMM_IF_COND(m_slice.enabled(), "Fixme: DG slices with inactive ranks not supported.");
1853 return;
1854 }
1855
1856 RECORD_TIMER_START(m_timers[Timers::RunInit]);
1857
1858 // Set polynomial degree, init interpolation, create surfaces etc.
1860
1861 // Apply initial conditions or load restart file
1862 initData();
1863
1864 // Note: moved to finalizeInitSolver, coupler need to be initialized first
1865 // Perform remaining steps needed before main loop execution
1866 // initMainLoop();
1867
1868 RECORD_TIMER_STOP(m_timers[Timers::RunInit]);
1869}
void initData()
Initialize solver data, i.e. set initial conditions or load restart file.
void initSolverObjects()
Initializes the solver. This must be called before using any of the discretization methods,...

◆ initSolverObjects()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initSolverObjects
private
Author
Michael Schlottke
Date
October 2012

Definition at line 1895 of file dgcartesiansolver.cpp.

1895 {
1896 TRACE();
1897 RECORD_TIMER_START(m_timers[Timers::InitSolverObjects]);
1898
1899 // NOTE: if anything is added/changed here, make the same changes in balancePre()/balancePost()
1900
1901 // Init grid-to-grid map
1902 initGridMap();
1903
1904 // Init elements
1905 initElements();
1906
1907 // Init h-elements
1908 initHElements();
1909
1910 // Set the polynomial degree in the elements
1912
1913 // Calculate all necessary interpolation values
1915
1916 // Calculate the coordinates of the integration nodes in the elements
1918
1919 // Calculate the inverse Jacobian for the mapping to the reference element
1920 initJacobian();
1921
1922 // Check cell properties
1924
1925 // Create all surfaces (except between internal cells and halo cells)
1926 initSurfaces();
1927
1928 // Initialize all necessary routines & data arrays for MPI communication
1929 if(hasMpiExchange()) {
1931 }
1932
1933 // Check whether sponge is activated
1934 if(useSponge()) {
1935 m_log << "Initializing sponge... ";
1937 m_log << "done" << endl;
1938 }
1939
1940 // For all halo cells send a list of polynomial degrees to neighboring domain
1941 // (p-refinement)
1942 if(hasMpiExchange() && hasPref()) {
1944 }
1945
1946 // Calculate all necessary mortar projections
1948
1949 // Load points at which the states should be written out
1950 m_pointData.init();
1951 // Load surface points on which the states should be written out
1953 // Load volume points on which the states should be written out
1955
1956 // Load coordinates of slice intercept
1957 m_slice.init();
1958
1959 // Initialize statistics about the simulation itself and write it to m_log
1961
1962 // Set status to initialized
1963 m_isInitSolver = true;
1964
1965 RECORD_TIMER_STOP(m_timers[Timers::InitSolverObjects]);
1966}
void initPolynomialDegree()
Calculate and set initial polynomial degree and number of nodes in all elements.

◆ initSolverSamplingVariables()

template<MInt nDim, class SysEqn >
virtual void DgCartesianSolver< nDim, SysEqn >::initSolverSamplingVariables ( const std::vector< MInt > &  NotUsedvarIds,
const std::vector< MInt > &  NotUsednoSamplingVars 
)
inlinevirtual

Reimplemented from Solver.

Definition at line 326 of file dgcartesiansolver.h.

327 {};

◆ initSurfaces()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initSurfaces
private
Author
Sven Berger
Date
Februar 2014

Definition at line 2893 of file dgcartesiansolver.cpp.

2893 {
2894 TRACE();
2895
2896 const MInt noElements = m_elements.size();
2897 const MInt noDirs = 2 * nDim;
2898 const MInt* const cellIds = &m_elements.cellId(0);
2899
2901 // 1) Create boundary surfaces
2903 m_log << "Creating boundary surfaces... ";
2904 // m_boundarySurfacesOffset = m_surfaces.size();
2906
2907 // Identify all interface cells, i.e., cells that are intersected by at least one geometry
2908 // element
2909 MBoolScratchSpace isInterface(grid().tree().size(), AT_, "isInterface");
2910 this->identifyBoundaryCells(&isInterface[0]);
2911
2912 // Delete m_geometryIntersection if already allocated
2915 }
2916 // Initialize geometry intersection object
2918
2919 // Loop over all elements and all directions and check if boundary
2920 // surfaces have to be created and which boundary condition ids are present
2921 MIntScratchSpace bcIds(noElements, noDirs, AT_, "bcIds");
2922 fill(bcIds.begin(), bcIds.end(), -1);
2923 for(MInt elementId = 0; elementId < noElements; elementId++) {
2924 // Skip elements that are not at an interface
2925 const MInt cellId = cellIds[elementId];
2926 if(!isInterface[cellId]) {
2927 continue;
2928 }
2929
2930 // Get boundary condition ids and save them to scratch
2931 array<MInt, 2 * nDim> ids = getBoundaryConditionIds(cellId);
2932
2933 // Check for neighboring elements and prevent creating a boundary surface
2934 for(MInt dir = 0; dir < noDirs; dir++) {
2935 const MInt nId = grid().tree().neighbor(cellId, dir);
2936 if(ids[dir] > -1 && nId > -1 && needElementForCell(nId)) {
2937 ids[dir] = -1;
2938 }
2939 }
2940
2941 copy(ids.begin(), ids.end(), &bcIds(elementId, 0));
2942 }
2943
2944 // Find additional boundary conditions for boundary elements that are not
2945 // intersected by geometry but that do not have a neighbor. This is mainly
2946 // necessary to support concave domains and situations where the intersected
2947 // cell does not have an element because the cell center is outside of the
2948 // domain.
2949 for(MInt elementId = 0; elementId < noElements; elementId++) {
2950 const MInt cellId = cellIds[elementId];
2951 for(MInt dir = 0; dir < noDirs; dir++) {
2952 // Skip if element already has boundary condition for this direction
2953 if(bcIds(elementId, dir) > -1) {
2954 continue;
2955 }
2956
2957 // Skip if no neighbor cell exists
2958 if(!grid().tree().hasNeighbor(cellId, dir)) {
2959 continue;
2960 }
2961
2962 // Skip if neighbor is not an interface cell
2963 const MInt neighborCellId = grid().tree().neighbor(cellId, dir);
2964 if(!isInterface[neighborCellId]) {
2965 continue;
2966 }
2967
2968 // Skip if neighbor element exists
2969 if(needElementForCell(neighborCellId)) {
2970 continue;
2971 }
2972
2973 // Get boundary condition ids for neighbor
2974 auto ids = getBoundaryConditionIds(neighborCellId);
2975
2976 // Check if neighbor cell has boundary condition in the direction of
2977 // current element and if yes, save it for current element
2978 const MInt oppositeDir = 2 * (dir / 2) + 1 - (dir % 2);
2979 if(ids[oppositeDir] > -1) {
2980 bcIds(elementId, dir) = ids[oppositeDir];
2981 }
2982 }
2983 }
2984
2985 // Find cut-off boundaries, i.e., cells that do not have a neighbor while at
2986 // the same time not being intersected by geometry
2988 // Reset cut-off boundary counter
2990
2991 // Find and mark cut-off boundaries
2992 for(MInt elementId = 0; elementId < noElements; elementId++) {
2993 const MInt cellId = cellIds[elementId];
2994 for(MInt dir = 0; dir < noDirs; dir++) {
2995 // Skip if no cut-off boundary condition is specified for this direction
2996 if(m_cutOffBoundaryConditionIds[dir] < 0) {
2997 continue;
2998 }
2999
3000 // Skip if element already has boundary condition for this direction
3001 if(bcIds(elementId, dir) > -1) {
3002 continue;
3003 }
3004
3005 // Skip if neighbor cell exists
3006 if(grid().tree().hasNeighbor(cellId, dir)) {
3007 continue;
3008 }
3009
3010 // Skip if neighbor of parent cell exists (will be handled by normal
3011 // h-refinement)
3012 if(grid().tree().parent(cellId) > -1 && grid().tree().hasNeighbor(grid().tree().parent(cellId), dir)) {
3013 continue;
3014 }
3015
3016 // Set boundary condition id to cut-off boundary condition id
3017 bcIds(elementId, dir) = m_cutOffBoundaryConditionIds[dir];
3018
3019 // Count number of cut-off surfaces
3021 }
3022 }
3023 }
3024
3025 // Obtain list of unique boundary condition ids
3026 set<MInt> localUniqueBcIds(bcIds.begin(), bcIds.end());
3027
3028 // Remove -1 (represents faces without a boundary condition id)
3029 localUniqueBcIds.erase(-1);
3030
3031 // Exchange all local unique boundary conditions ids and determine all global
3032 // unique boundary condition ids. Each rank will create all boundary
3033 // conditions such that a global communication is possible for e.g.
3034 // reading/writing boundary condition restart data.
3035
3036 // Local number of unique boundary condition ids
3037 MInt noBcIds = localUniqueBcIds.size();
3038
3039 // Counts and offsets for Allgatherv
3040 ScratchSpace<MInt> countsBcIds(noDomains(), FUN_, "countsBcIds");
3041 ScratchSpace<MInt> offsetsBcIds(noDomains(), FUN_, "offsetsBcIds");
3042
3043 // Gather the number of unique boundary condition ids on each domain
3044 MPI_Allgather(&noBcIds, 1, MPI_INT, &countsBcIds[0], 1, MPI_INT, mpiComm(), AT_, "noBcIds", "countsBcIds[0]");
3045
3046 // Compute offsets
3047 offsetsBcIds[0] = 0;
3048 for(MInt dId = 1; dId < noDomains(); dId++) {
3049 offsetsBcIds[dId] = offsetsBcIds[dId - 1] + countsBcIds[dId - 1];
3050 }
3051
3052 // Send buffer
3053 // Avoid dereferencing a zero length array
3054 ScratchSpace<MInt> localBcIds(max(noBcIds, 1), AT_, "localBcIds");
3055 std::copy(localUniqueBcIds.begin(), localUniqueBcIds.end(), &localBcIds[0]);
3056
3057 // Receive buffer
3058 const MInt totalNoBcIds = offsetsBcIds[noDomains() - 1] + countsBcIds[noDomains() - 1];
3059 ScratchSpace<MInt> globalBcIds(totalNoBcIds, FUN_, "globalBcIds");
3060
3061 // Gather and distribute all boundary condition ids from all domains
3062 MPI_Allgatherv(&localBcIds[0], noBcIds, MPI_INT, &globalBcIds[0], &countsBcIds[0], &offsetsBcIds[0], MPI_INT,
3063 mpiComm(), AT_, "localBcIds[0]", "globalBcIds[0]");
3064
3065 // Obtain list of global unique boundary condition ids
3066 set<MInt> uniqueBcIds(globalBcIds.begin(), globalBcIds.end());
3067
3068 // Loop over all boundary conditions and create surfaces, then the boundary
3069 // condition object (so that the result is sorted by bcId)
3070 std::vector<MInt> boundaryConditionIds;
3071 std::vector<std::pair<MInt, MInt>> bcIntervals;
3072 for(const auto& boundaryConditionId : uniqueBcIds) {
3073 const MInt begin = m_noBoundarySurfaces;
3074
3075 for(MInt elementId = 0; elementId < noElements; elementId++) {
3076 for(MInt dir = 0; dir < noDirs; dir++) {
3077 // Skip direction if boundary condition id does not match
3078 if(boundaryConditionId != bcIds(elementId, dir)) {
3079 continue;
3080 }
3081 if(hasSurface(elementId, dir)) {
3082 continue;
3083 }
3084
3085 // Skip if boundary surface creation if periodic connectivity is given in this direction
3086 // Determine periodic direction pDir(+x,+y,+z) based on dir(+-x,+-y,+-z)
3087 // --> pDir = (MInt) dir/2
3088 if(grid().periodicCartesianDir(dir / 2) != 0) {
3089 // Add additional check to avoid unintentional errors (i.e., users must set a periodic
3090 // direction *and* use bcId=0 on all relevant boundaries)
3091 if(boundaryConditionId != 0) {
3092 TERMM(1,
3093 "If you use periodic BCs, you must set the BC id of corresponding boundaries "
3094 "to zero.");
3095 }
3096 continue;
3097 }
3098
3099 initBoundarySurface(elementId, dir);
3100 }
3101 }
3102 const MInt end = m_noBoundarySurfaces;
3103
3104 // Store boundary condition id and the corresponding surface interval
3105 // Boundary conditions are created & initialized after all remaining
3106 // surfaces are created
3107 boundaryConditionIds.push_back(boundaryConditionId);
3108 bcIntervals.emplace_back(begin, end);
3109 }
3110
3111 m_log << "done" << endl;
3112
3114 // 2) Create inner surfaces
3116 m_log << "creating inner surfaces... ";
3117
3120
3121 for(MInt elementId = 0; elementId < noElements; elementId++) {
3122 for(MInt dir = 0; dir < noDirs; dir++) {
3123 if(hasSurface(elementId, dir)) {
3124 continue;
3125 }
3126 initInnerSurface(elementId, dir);
3127 }
3128 }
3129
3130 m_log << "done" << endl;
3131
3133 // 3) Create MPI surfaces
3135 m_log << "creating MPI surfaces... ";
3136
3138 m_noMpiSurfaces = 0;
3139
3140 if(hasMpiExchange()) {
3141 for(MInt elementId = 0; elementId < noElements; elementId++) {
3142 for(MInt dir = 0; dir < noDirs; dir++) {
3143 const MInt cellId = m_elements.cellId(elementId);
3144 const MInt nghbrId = grid().tree().neighbor(cellId, dir);
3145 MBool partLvlAncestorNghbr = false;
3146
3147 // In case of partition level shifts there can be elements at level jumps that have both
3148 // internal and halo cells as neighbors on the higher level. Check if the neighbor cell is a
3149 // candidate for such a case
3150 if(nghbrId > -1 && grid().tree().hasProperty(nghbrId, Cell::IsPartLvlAncestor)
3151 && grid().tree().hasChildren(nghbrId)) {
3152 // Check all childs of the neighbor for a cell and continue process with initMpiSurface()
3153 // below to create any missing h-mpi surfaces (and skip internal childs of the neighbor)
3154 for(MInt child = 0; child < IPOW2(nDim); child++) {
3155 const MInt childId = grid().tree().child(nghbrId, child);
3156 if(childId > -1 && grid().tree().hasProperty(childId, Cell::IsHalo)) {
3157 partLvlAncestorNghbr = true;
3158 }
3159 }
3160 }
3161
3162 if(hasSurface(elementId, dir) && !partLvlAncestorNghbr) {
3163 continue;
3164 }
3165 initMpiSurface(elementId, dir);
3166 }
3167 }
3168 }
3169
3170 m_log << "done" << endl;
3171
3172 // Reset previous boundary condition objects
3173 m_boundaryConditions.clear();
3174
3175 // Create & initialize boundary condition
3176 m_log << "creating and initializing boundary conditions... ";
3177 for(MUint bcId = 0; bcId < boundaryConditionIds.size(); bcId++) {
3178 m_boundaryConditions.emplace_back(make_bc(boundaryConditionIds[bcId]));
3179
3180 const MInt begin = bcIntervals[bcId].first;
3181 const MInt end = bcIntervals[bcId].second;
3182 m_boundaryConditions[bcId]->init(begin, end);
3183 }
3184 m_log << "done" << endl;
3185
3186 // Sanity check: all elements should have surfaces in each direction
3187 m_log << "Sanity check: all elements must have surfaces in each "
3188 "direction... ";
3189 MInt missing = 0;
3190 for(MInt elementId = 0; elementId < noElements; elementId++) {
3191 for(MInt dir = 0; dir < noDirs; dir++) {
3192 if(!hasSurface(elementId, dir)) {
3193 // Write surface information to log
3194 m_log << "\nmissing surface for element " << elementId << " in direction " << dir << " (coordinates: ";
3195 const MInt cellId = m_elements.cellId(elementId);
3196 for(MInt i = 0; i < nDim; i++) {
3197 m_log << grid().tree().coordinate(cellId, i) << " ";
3198 }
3199 m_log << ")" << std::endl;
3200 m_log.flush();
3201
3202 // Count number of missing surfaces for abort message
3203 missing++;
3204 }
3205 }
3206 }
3207
3208 // Abort if there are missing surfaces
3209 if(missing) {
3210 TERMM(1, "There are " + to_string(missing)
3211 + " surfaces missing (check m_log for more details). Did "
3212 "you maybe forget to specify cut-off boundary conditions?");
3213 } else {
3214 m_log << "done" << endl;
3215 }
3216
3217 // Ensure that there are no boundary surfaces if all directions are periodic
3218 if(grid().periodicCartesianDir(0) && grid().periodicCartesianDir(1) && (nDim == 2 || grid().periodicCartesianDir(2))
3219 && m_noBoundarySurfaces > 0) {
3220 TERMM(1, "There are boundary surfaces although every direction has a periodic boundaries. "
3221 "Please check what is wrong here.\n");
3222 }
3223}
std::array< MInt, 2 *nDim > getBoundaryConditionIds(const MInt cellId)
Determine if element is boundary is cut by geometry elements and return corresponding boundary condit...
MInt initMpiSurface(const MInt elementId, const MInt dir)
Check if the surface of the element in the given direction is a MPI surface. If it is,...
MInt initInnerSurface(const MInt elementId, const MInt dir)
Check if the surface of the element in the given direction is an inner surface without h/p-refinement...
MBool hasSurface(const MInt elementId, const MInt dir)
Check if a surface exists for the element in the given direction.
std::array< MInt, 2 *nDim > m_cutOffBoundaryConditionIds
MInt initBoundarySurface(const MInt elementId, const MInt dir)
Check if the surface of the element in the given direction is a boundary surface. If it is init,...
int MPI_Allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgatherv
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather

◆ initTimers()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::initTimers
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-07-24

Definition at line 113 of file dgcartesiansolver.cpp.

113 {
114 TRACE();
115
116 // Invalidate timer ids
117 std::fill(m_timers.begin(), m_timers.end(), -1);
118
119 // Create timer group & timer for solver, and start the timer
120 NEW_TIMER_GROUP_NOCREATE(m_timerGroup, "DgCartesianSolver (solverId = " + to_string(m_solverId) + ")");
121 NEW_TIMER_NOCREATE(m_timers[Timers::SolverType], "total object lifetime", m_timerGroup);
122 RECORD_TIMER_START(m_timers[Timers::SolverType]);
123
124 // Create & start constructor timer
125 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Constructor], "Constructor", m_timers[Timers::SolverType]);
126 RECORD_TIMER_START(m_timers[Timers::Constructor]);
127
128 // Create regular solver-wide timers
129 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Run], "run", m_timers[Timers::SolverType]);
130 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::RunInit], "run initialization", m_timers[Timers::Run]);
131 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitSolverObjects], "initialize solver infrastructure",
133 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitMortarProjection], "initMortarProjection",
135 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitData], "initialize solver data", m_timers[Timers::RunInit]);
136 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitialCondition], "initialCondition", m_timers[Timers::InitData]);
137 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitMainLoop], "initialize main loop", m_timers[Timers::RunInit]);
138 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MainLoop], "main loop", m_timers[Timers::Run]);
139 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcTimeStep], "calcTimeStep", m_timers[Timers::MainLoop]);
140 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ResetExternalSources], "resetExternalSources", m_timers[Timers::MainLoop]);
141 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::RungeKuttaStep], "timeStepRk", m_timers[Timers::MainLoop]);
142 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::TimeDeriv], "calcDgTimeDerivative", m_timers[Timers::RungeKuttaStep]);
143 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ResetRHS], "resetRHS", m_timers[Timers::TimeDeriv]);
144 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Prolong], "prolong to surfaces", m_timers[Timers::TimeDeriv]);
145 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ForwardProjection], "forward projection", m_timers[Timers::TimeDeriv]);
146 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfExchange], "MPI surface exchange", m_timers[Timers::TimeDeriv]);
147 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfExchangeComm], "communication", m_timers[Timers::SurfExchange]);
148 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SECommSend], "send", m_timers[Timers::SurfExchangeComm]);
149 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SECommRecv], "recv", m_timers[Timers::SurfExchangeComm]);
150 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfExchangeCopy], "copy operations", m_timers[Timers::SurfExchange]);
151 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SECopySend], "send", m_timers[Timers::SurfExchangeCopy]);
152 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SECopyRecv], "recv", m_timers[Timers::SurfExchangeCopy]);
153 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfExchangeWait], "waiting", m_timers[Timers::SurfExchange]);
154 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SEWaitSend], "send", m_timers[Timers::SurfExchangeWait]);
155 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SEWaitRecv], "recv", m_timers[Timers::SurfExchangeWait]);
156 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::VolInt], "calcVolumeIntegral", m_timers[Timers::TimeDeriv]);
157 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Flux], "flux calculation", m_timers[Timers::TimeDeriv]);
158 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::FluxBndry], "calcBoundarySurfaceFlux", m_timers[Timers::Flux]);
159 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::FluxInner], "calcInnerSurfaceFlux", m_timers[Timers::Flux]);
160 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::FluxMPI], "calcMpiSurfaceFlux", m_timers[Timers::Flux]);
161 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfInt], "surface integrals", m_timers[Timers::TimeDeriv]);
162 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Jacobian], "applyJacobian", m_timers[Timers::TimeDeriv]);
163 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Sources], "calcSourceTerms", m_timers[Timers::TimeDeriv]);
164 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ExternalSources], "applyExternalSourceTerms", m_timers[Timers::TimeDeriv]);
165 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Sponge], "calcSpongeTerms", m_timers[Timers::TimeDeriv]);
166 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::TimeInt], "time integration", m_timers[Timers::RungeKuttaStep]);
167 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MainLoopIO], "I/O", m_timers[Timers::MainLoop]);
168 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Analysis], "solution analysis", m_timers[Timers::MainLoop]);
169 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CleanUp], "cleanUp", m_timers[Timers::Run]);
170 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Destructor], "Destructor", m_timers[Timers::SolverType]);
171 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::AdaptiveRefinement], "adaptive refinement", m_timers[Timers::MainLoop]);
172
173 // Create accumulated timers that monitor selected subsystems
174 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Accumulated], "selected accumulated timers", m_timers[Timers::SolverType]);
175 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::IO], "IO", m_timers[Timers::Accumulated]);
176 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveSolutionFile], "saveSolutionFile", m_timers[Timers::IO]);
177 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveRestartFile], "saveRestartFile", m_timers[Timers::IO]);
178 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::AnalyzeTimeStep], "analyzeTimeStep", m_timers[Timers::Accumulated]);
179 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MPI], "MPI", m_timers[Timers::Accumulated]);
180 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MPIComm], "communication", m_timers[Timers::MPI]);
181 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MPICopy], "copy operations", m_timers[Timers::MPI]);
182 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MPIWait], "waiting", m_timers[Timers::MPI]);
183
184 // Set status to initialized
185 m_isInitTimers = true;
186}

◆ interpolateElement()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::interpolateElement ( const MInt  elementId,
const MInt  adaptedPolyDeg 
)
private
Author
Sven Berger
Date
Februar 2015
Parameters
[in]elementIdElementId of the element to be interpolated to a new polynomial degree.
[in]adaptedPolyDegNew polynomial degree of the element.

Definition at line 9075 of file dgcartesiansolver.cpp.

9075 {
9076 TRACE();
9077
9078 // Interpolate element data to new integration nodes at new polynomial degree
9079 // in temporary storage, then copy result to destination location
9080 // (do not use Scratch space to remain thread-safe!)
9081 const MInt adaptedNodes1D = adaptedPolyDeg + 1;
9082 const MInt adaptedNodes1D3 = (nDim == 3) ? adaptedNodes1D : 1;
9083 const MInt noVars = SysEqn::noVars();
9084 const MInt elemPolyDeg = m_elements.polyDeg(elementId);
9085 const MInt elemNodes1D = m_elements.noNodes1D(elementId);
9086 const MInt size = adaptedNodes1D * adaptedNodes1D * adaptedNodes1D3 * noVars;
9087 vector<MFloat> buffer(size);
9088 using namespace dg::interpolation;
9089
9090 // Variables
9091 if(elemPolyDeg < adaptedPolyDeg) {
9092 interpolateNodes<nDim>(&m_elements.variables(elementId), mortarP<dg::mortar::forward>(elemPolyDeg, adaptedPolyDeg),
9093 elemNodes1D, adaptedNodes1D, noVars, &buffer[0]);
9094 copy(buffer.begin(), buffer.end(), &m_elements.variables(elementId));
9095
9096 // Time Integration Storage
9097 interpolateNodes<nDim>(&m_elements.timeIntStorage(elementId),
9098 mortarP<dg::mortar::forward>(elemPolyDeg, adaptedPolyDeg), elemNodes1D, adaptedNodes1D,
9099 noVars, &buffer[0]);
9100 copy(buffer.begin(), buffer.end(), &m_elements.timeIntStorage(elementId));
9101 } else {
9102 interpolateNodes<nDim>(&m_elements.variables(elementId), mortarP<dg::mortar::reverse>(adaptedPolyDeg, elemPolyDeg),
9103 elemNodes1D, adaptedNodes1D, noVars, &buffer[0]);
9104 copy(buffer.begin(), buffer.end(), &m_elements.variables(elementId));
9105
9106 // Time Integration Storage
9107 interpolateNodes<nDim>(&m_elements.timeIntStorage(elementId),
9108 mortarP<dg::mortar::reverse>(adaptedPolyDeg, elemPolyDeg), elemNodes1D, adaptedNodes1D,
9109 noVars, &buffer[0]);
9110 copy(buffer.begin(), buffer.end(), &m_elements.timeIntStorage(elementId));
9111 }
9112
9113 // Update polynomial degree
9114 m_elements.polyDeg(elementId) = adaptedPolyDeg;
9115 m_elements.noNodes1D(elementId) = adaptedNodes1D;
9116
9117 // Recalculate node coordinates of the element
9118 calcElementNodeCoordinates(elementId);
9119}
MFloat & timeIntStorage(const MInt id)
Accessor for storage variables.

◆ isAdaptationTimeStep()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::isAdaptationTimeStep ( const MInt  timeStep) const
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-11-10
Parameters
[in]timeStepTime step to check if it is an adaptation time step.

Definition at line 9259 of file dgcartesiansolver.cpp.

9259 {
9260 TRACE();
9261
9262 // Check if adaptive p-refinement is enabled: The adaptation is done once
9263 // after the first time step (i.e. before the second time step), and then
9264 // before each adaptation interval
9265 return (hasAdaptivePref() && (timeStep == 2 || timeStep % m_adaptiveInterval == 0));
9266}
MBool hasAdaptivePref() const
Return true if adaptive hp-refinement is activated.

◆ isMpiRoot()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::isMpiRoot
inlineprivate
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-01-13
Returns
True if the rank is zero in the solver MPI communicator.

Definition at line 7366 of file dgcartesiansolver.cpp.

7366 {
7367 return (domainId() == 0);
7368}

◆ isMpiSurface()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::isMpiSurface ( const MInt  id) const
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-01-01
Parameters
[in]idSurface id to check.

Definition at line 9276 of file dgcartesiansolver.cpp.

9276 {
9277 TRACE();
9278
9279 const MInt begin = m_mpiSurfacesOffset;
9281 MBool isMpiSrfc = false;
9282
9283 if(begin <= id && id < end) {
9284 isMpiSrfc = true;
9285 }
9286
9287 return isMpiSrfc;
9288}

◆ loadGridMap()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::loadGridMap ( const MString gridMapFileName)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-03-17
Parameters
[in]gridMapFileNameFile name of grid map.

Definition at line 2064 of file dgcartesiansolver.cpp.

2064 {
2065 TRACE();
2066
2067 m_log << "Loading grip map from " << gridMapFileName << "..." << endl;
2068
2069 // Read grid map
2070 const MInt noCells = grid().noInternalCells();
2071 MIntScratchSpace gridMap(noCells, AT_, "gridMap");
2072 MIntScratchSpace gridMapNoOffspring(noCells, AT_, "gridMapNoOffspring");
2073 using namespace parallel_io;
2074 ParallelIo gridMapFile(gridMapFileName, PIO_READ, mpiComm());
2075 gridMapFile.setOffset(noCells, grid().domainOffset(domainId()));
2076 gridMapFile.readArray(&gridMap[0], "cellIds");
2077 gridMapFile.readArray(&gridMapNoOffspring[0], "noOffspring");
2078
2079 // Temporary storage for the number of offspring cells mapped to target cells
2080 MIntScratchSpace noOffspring(noCells, AT_, "noOffspring");
2081
2082 // Clear previous grid map offsets
2083 m_gridMapOffsets.clear();
2084
2085 // Determine grid map offsets
2086 for(MInt cellId = 0; cellId < noCells; cellId++) {
2087 // Skip if mapped donor cell id is -1, i.e., if there is no donor cell
2088 if(gridMap[cellId] == -1) {
2089 continue;
2090 }
2091
2092 // Store first local target cell id and first mapped donor cell global id
2093 const MInt firstTargetCellId = cellId;
2094 const MInt firstDonorGlobalId = gridMap[cellId];
2095
2096 // Store the number of donor offspring cells for the first considered target
2097 // cell
2098 noOffspring[0] = gridMapNoOffspring[cellId];
2099
2100 // Find consecutive mapped ids (account for child cells on the donor grid),
2101 // i.e., consecutive cells on the target grid that have one or more donor
2102 // cells
2103 MInt noDonorCells = 1 + gridMapNoOffspring[cellId];
2104 while(cellId + 1 < noCells) {
2105 if(gridMap[cellId + 1] == firstDonorGlobalId + noDonorCells) {
2106 // If next mapped target cell id is contiguous, increase donor size and
2107 // proceed with next
2108 cellId++;
2109 noDonorCells += 1 + gridMapNoOffspring[cellId];
2110 noOffspring[cellId - firstTargetCellId] = gridMapNoOffspring[cellId];
2111 } else if(gridMap[cellId + 1] == firstDonorGlobalId + noDonorCells - 1) {
2112 // One-to-many mapping: the next target cell is also mapped to the
2113 // previous donor cell.
2114 cellId++;
2115 // Set number of offspring to -1 to indicate one-to-many mapping
2116 noOffspring[cellId - firstTargetCellId] = -1;
2117 } else {
2118 // Otherwise exit while loop
2119 break;
2120 }
2121 }
2122
2123 // Determine number of contiguous mapped target cells
2124 const MInt noTargetCells = cellId - firstTargetCellId + 1;
2125
2126 // Create & store grid map offset
2127 m_gridMapOffsets.push_back({firstTargetCellId, noTargetCells, firstDonorGlobalId, noDonorCells,
2128 std::vector<MInt>(noOffspring.begin(), noOffspring.end())});
2129 }
2130
2131 m_log << "Found " << m_gridMapOffsets.size() << " contiguous mapped region(s):" << endl;
2132 for(size_t i = 0; i < m_gridMapOffsets.size(); i++) {
2133 const auto& o = m_gridMapOffsets[i];
2134 m_log << "- offset: " << i << "; firstTargetCellId: " << o.m_firstTargetCellId
2135 << "; globalId: " << grid().tree().globalId(o.m_firstTargetCellId) << "; noDonorCells: " << o.m_noDonorCells
2136 << "; noTargetCells: " << o.m_noTargetCells << "; firstDonorGlobalId: " << o.m_firstDonorGlobalId << endl;
2137 }
2138
2139 // Determine maximum amount of offsets across all domains
2141 MPI_Allreduce(MPI_IN_PLACE, &m_maxNoGridMapOffsets, 1, type_traits<MInt>::mpiType(), MPI_MAX, mpiComm(), AT_,
2142 "MPI_IN_PLACE", "m_maxNoGridMapOffsets");
2143 m_log << "Maximum number of grid map offsets on all domains: " << m_maxNoGridMapOffsets << endl;
2144}

◆ loadNodeVarsFile()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::loadNodeVarsFile
private
Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-07-26

This is mainly used to restart from a previously stored file if the node variables are constant in time.

Definition at line 6532 of file dgcartesiansolver.cpp.

6532 {
6533 TRACE();
6534 CHECK_TIMERS_IO();
6535
6536 m_log << "Loading nodevars file... ";
6537
6538 // Add solver number in case of multisolver execution
6539 stringstream ss;
6540 ss << restartDir() << "nodevars" << getIdentifier(g_multiSolverGrid, "_b", "") << ParallelIo::fileExt();
6541
6542 // Create big data object to load data from disk
6543 using namespace parallel_io;
6544 ParallelIo parallelIo(ss.str(), PIO_READ, mpiComm());
6545
6546 // Determine data offset for each element in output buffer
6547 const MInt noElements = m_elements.size();
6548 MIntScratchSpace elementOffset(noElements, AT_, "elementOffset");
6549 for(MInt cellId = 0, offset = 0, elementId = 0; elementId < noElements; cellId++) {
6550 // If cellId is not the one of the current element (i.e. the current cell
6551 // does not have an element), add the default offset (based on initPolyDeg)
6552 if(cellId != m_elements.cellId(elementId)) {
6553 offset += ipow(m_initNoNodes1D, nDim);
6554 continue;
6555 }
6556
6557 // Otherwise use current offset for the current element
6558 elementOffset[elementId] = offset;
6559
6560 // Increase offset based on element polynomial degree
6561 const MInt noNodesXD = m_elements.noNodesXD(elementId);
6562 offset += noNodesXD;
6563
6564 // Set number of nodes to use later and proceed with next element
6565 elementId++;
6566 }
6567
6568 // Set data offsets and array sizes
6569 // Determine local data array size
6570 // array size = #nodes of elements + (#cells - #elements) * default cell size
6571 // (cells without elements use polyDeg = initPolyDeg)
6572 const MInt localNoNodes = m_noTotalNodesXD + (grid().noInternalCells() - noElements) * ipow(m_initNoNodes1D, nDim);
6573
6574 // Determine offset and global number of nodes
6575 ParallelIo::size_type nodesOffset, globalNoNodes;
6576 ParallelIo::calcOffset(localNoNodes, &nodesOffset, &globalNoNodes, mpiComm());
6577
6578 // Load data from disk
6579 parallelIo.setOffset(localNoNodes, nodesOffset);
6580 for(MInt i = 0; i < m_sysEqn.noNodeVars(); i++) {
6581 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
6582 const MString name = "variables" + to_string(i);
6583 parallelIo.readArray(&buffer[0], name);
6584 for(MInt e = 0; e < noElements; e++) {
6585 const MFloat* const b = &buffer[elementOffset[e]];
6586 MFloat* const v = &m_elements.nodeVars(e) + i;
6587 const MInt noNodesXD = m_elements.noNodesXD(e);
6588 for(MInt n = 0; n < noNodesXD; n++) {
6589 v[n * m_sysEqn.noNodeVars()] = b[n];
6590 }
6591 }
6592 }
6593
6594 m_log << "done" << endl;
6595}

◆ loadRestartFile()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::loadRestartFile
overrideprivatevirtual
Author
Michael Schlottke, Sven Berger
Date
2013-09-23

Reimplemented from Solver.

Definition at line 6173 of file dgcartesiansolver.cpp.

6173 {
6174 TRACE();
6175
6176 m_log << "Loading restart file... ";
6177
6178 // Determine file name and grid file name
6180
6181 // Create big data object to load data from disk
6182 using namespace parallel_io;
6183 ParallelIo parallelIo(fileName, PIO_READ, mpiComm());
6184
6185 // Get attributes
6186 MString gridFileName;
6187 parallelIo.getAttribute(&gridFileName, "gridFile");
6188
6189 // Get time variables
6190 parallelIo.readScalar(&m_timeStep, "timeStep");
6191 parallelIo.readScalar(&m_time, "time");
6192 parallelIo.readScalar(&m_dt, "dt");
6193
6194 // Load polynomial degrees
6195 MIntScratchSpace polyDegs(grid().noInternalCells(), AT_, "buffer");
6196 if(!parallelIo.hasDataset("polyDegs", 1)) {
6197 TERMM(1, "ERROR: restart file is not valid (missing polynomial degree data).");
6198 }
6199 parallelIo.setOffset(grid().noInternalCells(), grid().domainOffset(domainId()));
6200 parallelIo.readArray(&polyDegs[0], "polyDegs");
6201
6202 // update elements
6203 const MInt noElements = m_elements.size();
6204 m_noTotalNodesXD = 0;
6205 for(MInt elementId = 0; elementId < noElements; elementId++) {
6206 const MInt cellId = m_elements.cellId(elementId);
6207 const MInt polyDeg = polyDegs[cellId];
6208 const MInt noNodes1D = polyDeg + 1;
6209 const MInt noNodesXD = ipow(polyDeg + 1, nDim);
6210 m_elements.polyDeg(elementId) = polyDeg;
6211 m_elements.noNodes1D(elementId) = noNodes1D;
6212 m_noTotalNodesXD += noNodesXD;
6213 }
6214
6215 // Determine data offset for each element in output buffer
6216 MIntScratchSpace elementOffset(noElements, AT_, "elementOffset");
6217 for(MInt cellId = 0, offset = 0, elementId = 0; elementId < noElements; cellId++) {
6218 // If cellId is not the one of the current element (i.e. the current cell
6219 // does not have an element), add the default offset (based on initPolyDeg)
6220 if(cellId != m_elements.cellId(elementId)) {
6221 offset += ipow(m_initNoNodes1D, nDim);
6222 continue;
6223 }
6224
6225 // Otherwise use current offset for the current element
6226 elementOffset[elementId] = offset;
6227
6228 // Increase offset based on element polynomial degree
6229 const MInt noNodesXD = m_elements.noNodesXD(elementId);
6230 offset += noNodesXD;
6231
6232 // Set number of nodes to use later and proceed with next element
6233 elementId++;
6234 }
6235
6236 // Set data offsets and array sizes
6237 // Determine local data array size
6238 // array size = #nodes of elements + (#cells - #elements) * default cell size
6239 // (cells without elements use polyDeg = initPolyDeg)
6240 const MInt localNoNodes = m_noTotalNodesXD + (grid().noInternalCells() - noElements) * ipow(m_initNoNodes1D, nDim);
6241
6242 // Determine offset and global number of nodes
6243 ParallelIo::size_type nodesOffset, globalNoNodes;
6244 ParallelIo::calcOffset(localNoNodes, &nodesOffset, &globalNoNodes, mpiComm());
6245
6246 // Load data from disk
6247 parallelIo.setOffset(localNoNodes, nodesOffset);
6248 MInt varId = 0;
6249
6250 // Solution
6251 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
6252 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
6253 const MString name = "variables" + to_string(varId++);
6254 parallelIo.readArray(&buffer[0], name);
6255 for(MInt e = 0; e < noElements; e++) {
6256 const MFloat* const b = &buffer[elementOffset[e]];
6257 MFloat* const v = &m_elements.variables(e) + i;
6258 const MInt noNodesXD = m_elements.noNodesXD(e);
6259 for(MInt n = 0; n < noNodesXD; n++) {
6260 v[n * m_sysEqn.noVars()] = b[n];
6261 }
6262 }
6263 }
6264
6265 // Node variables
6266 if(SysEqn::hasTimeDependentNodeVars()) {
6267 for(MInt i = 0; i < m_sysEqn.noNodeVars(); i++) {
6268 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
6269 const MString name = "variables" + to_string(varId++);
6270 parallelIo.readArray(&buffer[0], name);
6271 for(MInt e = 0; e < noElements; e++) {
6272 const MFloat* const b = &buffer[elementOffset[e]];
6273 MFloat* const v = &m_elements.nodeVars(e) + i;
6274 const MInt noNodesXD = m_elements.noNodesXD(e);
6275 for(MInt n = 0; n < noNodesXD; n++) {
6276 v[n * m_sysEqn.noNodeVars()] = b[n];
6277 }
6278 }
6279 }
6280 }
6281
6282 // Note: keep this, might be useful as a reference sometime
6283 // Coupling variables
6284 // if (hasCoupling()) {
6285 // for (auto& cc : m_couplingConditions) {
6286 // for (MInt i = 0; i < cc->noRestartVars(); i++) {
6287 // // Load data into local buffer
6288 // MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
6289 // const MString name = "variables" + to_string(varId++);
6290 // parallelIo.readArray(&buffer[0], name);
6291 //
6292 // // Re-arrange data in buffer to make it "gap-less", i.e. for each
6293 // // element the data is adjacent to the neighboring elements
6294 // MInt offset = 0;
6295 // for (MInt e = 0; e < noElements; e++) {
6296 // // Create pointers to data
6297 // const MFloat* const b = &buffer[elementOffset[e]];
6298 // MFloat* const v = &buffer[offset];
6299 //
6300 // // Update offset
6301 // const MInt noNodesXD = m_elements.noNodesXD(e);
6302 // offset += noNodesXD;
6303 //
6304 // // No copy operation needed if pointers are equal
6305 // if (b == v) {
6306 // continue;
6307 // }
6308 //
6309 // // Copy (move) data
6310 // copy(b, b + noNodesXD, v);
6311 // }
6312 //
6313 // // Store restart variable in coupling class
6314 // cc->setRestartVariable(i, &buffer[0]);
6315 // }
6316 // }
6317 //}
6318
6319 // Boundary conditions
6320 for(auto&& bc : m_boundaryConditions) {
6321 const MInt bcNoVars = bc->noRestartVars();
6322 if(bcNoVars > 0) {
6323 const MInt bcLocalNoNodes = bc->getLocalNoNodes();
6324 ParallelIo::size_type bcNodesOffset, bcGlobalNoNodes;
6325 ParallelIo::calcOffset(bcLocalNoNodes, &bcNodesOffset, &bcGlobalNoNodes, mpiComm());
6326 parallelIo.setOffset(bcLocalNoNodes, bcNodesOffset);
6327 for(MInt i = 0; i < bcNoVars; i++) {
6328 // Avoid dereferencing a zero length array
6329 MFloatScratchSpace buffer(max(bcLocalNoNodes, 1), AT_, "buffer");
6330 const MString name = "variables" + to_string(varId++);
6331 parallelIo.readArray(&buffer[0], name);
6332
6333 // Store restart variable in boundary condition
6334 bc->setRestartVariable(i, &buffer[0]);
6335 }
6336 }
6337 }
6338
6339 m_log << "done" << endl;
6340}
MString getRestartFileName(const MInt timeStep, const MInt useNonSpecifiedRestartFile)
Return name of a restart file for the given time step.
MInt m_restartTimeStep
Definition: solver.h:80
MBool m_useNonSpecifiedRestartFile
Definition: solver.h:83

◆ loadSampleVariables()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::loadSampleVariables ( MInt  timeStep)
inline

Definition at line 114 of file dgcartesiansolver.h.

114 {
115 std::cerr << "loadSampleVariables DgCartesianSolver " << timeStep << std::endl;
116 };

◆ localToGlobalIds()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::localToGlobalIds
overridevirtual
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

Reimplemented from Solver.

Definition at line 9497 of file dgcartesiansolver.cpp.

9497 {
9498 TRACE();
9499
9500 // Nothing to do if solver is not active
9501 if(!isActive()) {
9502 return;
9503 }
9504
9505 const MInt domainOffset = grid().domainOffset(domainId());
9506 const MInt noElements = m_elements.size();
9507 // Store the global cell id in all elements
9508 for(MInt elementId = 0; elementId < noElements; elementId++) {
9509 const MInt globalCellId = m_elements.cellId(elementId) + domainOffset;
9510 m_elements.cellId(elementId) = globalCellId;
9511 }
9512}

◆ make_bc()

template<MInt nDim, class SysEqn >
DgCartesianSolver< nDim, SysEqn >::BC DgCartesianSolver< nDim, SysEqn >::make_bc ( MInt  bcId)
private

Definition at line 6628 of file dgcartesiansolver.cpp.

6628 {
6629 TRACE();
6630
6631 BC bc = m_boundaryConditionFactory.create(bcId);
6632
6633 return bc;
6634}
typename DgBoundaryConditionFactory< nDim, SysEqn >::ReturnType BC

◆ mortarH()

template<MInt nDim, class SysEqn >
template<MBool forward>
MFloat * DgCartesianSolver< nDim, SysEqn >::mortarH ( const MInt  noNodes1D,
const MInt  position 
)
private

Returns the forward/reverse projection matrix for h-refinement.

Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-03-03
Template Parameters
forwardTrue returns the forward, false the reverse projection matrix.
Parameters
[in]polyDegPolynomial degree of projection.
[in]positionRelative position of smaller element (0 means lower element, 1 means upper element; for more info see comment on calcMortarProjectionMatrix...H{A,B})
Returns
Pointer to projection matrix.

Definition at line 8749 of file dgcartesiansolver.cpp.

8749 {
8750 // Sanity check
8751 ASSERT(position == 0 || position == 1, "position must be `0` or `1` (=" + to_string(position) + ")");
8752
8753 // Calculate matrix index relative from polynomial degree and position
8754 const MInt index = 4 * noNodes1D + 2 * (1 - forward) + position;
8755
8756 // Return pointer to first element in projection matrix
8758}

◆ mortarP()

template<MInt nDim, class SysEqn >
template<MBool forward>
MFloat * DgCartesianSolver< nDim, SysEqn >::mortarP ( const MInt  sourcePolyDeg,
const MInt  targetPolyDeg 
)
private

Returns the forward/reverse projection matrix for p-refinement.

Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-03-03
Template Parameters
forwardTrue returns the forward, false the reverse projection matrix.
Parameters
[in]sourcePolyDegPolynomial degree of projection source.
[in]targetPolyDegPolynomial degree of projection target.
Returns
Pointer to projection matrix.

Note: the source polynomial degree must always be lower than the target polynomial degree.

Definition at line 8720 of file dgcartesiansolver.cpp.

8720 {
8721 // Sanity check
8722 ASSERT(sourcePolyDeg < targetPolyDeg,
8723 "source polynomial degree (= " + to_string(sourcePolyDeg)
8724 + ") must be lower than target polynomial degree (= " + to_string(targetPolyDeg) + ")");
8725
8726 // Calculate matrix index from polyomial degrees
8727 const MInt index = 2 * (targetPolyDeg * (targetPolyDeg - 1) / 2 + sourcePolyDeg) + (1 - forward);
8728
8729 // Return pointer to first element in projection matrix
8731}

◆ needElementForCell()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::needElementForCell ( const MInt  cellId)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2014-02-21
Parameters
[in]cellIdId of cell that should be checked.
Returns
True if element is needed, false otherwise.

Definition at line 2342 of file dgcartesiansolver.cpp.

2342 {
2343 // TRACE();
2344
2345 MBool needElement = true;
2346
2347 // Do not create element if...
2348 // ... cell has child cells or
2349 if(grid().tree().hasChildren(cellId)
2350 // ... cell center is outside the geometry
2351 || !pointIsInside(&grid().tree().coordinate(cellId, 0))) {
2352 needElement = false;
2353 }
2354 return needElement;
2355}
MBool pointIsInside(const MFloat *const coordinates)
Check if point is inside the computational domain.

◆ needHElementForCell()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::needHElementForCell ( const MInt  cellId)
private
Author
Sven Berger
Date
March 2015
Parameters
[in]cellIdId of cell that should be checked.
Returns
True if h-element is needed, false otherwise.

Definition at line 2367 of file dgcartesiansolver.cpp.

2367 {
2368 // TRACE();
2369
2370 // Only leaf cells have elements
2371 if(grid().tree().hasChildren(cellId)) {
2372 return false;
2373 }
2374
2375 // Check neighbors in every direction. If neighbor has children, then neighbor
2376 // is h-refined and coarse element requires an h-element
2377 for(MInt dir = 0; dir < 2 * nDim; dir++) {
2378 if(grid().tree().hasNeighbor(cellId, dir)) {
2379 const MInt neighborId = grid().tree().neighbor(cellId, dir);
2380 if(grid().tree().hasChildren(neighborId)) {
2381 return true;
2382 }
2383 }
2384 }
2385
2386 return false;
2387}

◆ noBcSolverCellData()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::noBcSolverCellData ( ) const
inlineprivate

Definition at line 468 of file dgcartesiansolver.h.

468 {
469 MInt count = 0;
470 for(auto&& bc : m_boundaryConditions) {
471 count += bc->noCellDataDlb();
472 }
473 return count;
474 };

◆ noCellDataDlb()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::noCellDataDlb ( ) const
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 419 of file dgcartesiansolver.h.

419 {
420 if(grid().isActive()) {
422 } else {
423 return 0;
424 }
425 };
MInt noBcSolverCellData() const

◆ noDgCartesianSolverCellData()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::noDgCartesianSolverCellData ( ) const
inlineprivate

Definition at line 467 of file dgcartesiansolver.h.

467{ return CellData::count; };
static constexpr const MInt count

◆ noInternalCells()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::noInternalCells ( ) const
inlineoverridevirtual

Implements Solver.

Definition at line 356 of file dgcartesiansolver.h.

356{ return grid().noInternalCells(); }

◆ noLoadTypes()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::noLoadTypes
overridevirtual
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

Reimplemented from Solver.

Definition at line 9349 of file dgcartesiansolver.cpp.

9349 {
9350 TRACE();
9351
9352 MInt totalNoDgLT = 0;
9353 // Add a load type for each polynomial degree (even if there might be no element with this
9354 // polyomial degree)
9355 totalNoDgLT += m_maxPolyDeg - m_minPolyDeg + 1;
9356
9357 // Add load type for boundary condition elements (assumes only one polynomial degree)
9359 totalNoDgLT += 1;
9360 }
9361
9362 return totalNoDgLT;
9363}

◆ noSolverTimers()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::noSolverTimers ( const MBool  allTimings)
inlineoverride

Definition at line 449 of file dgcartesiansolver.h.

449 {
450#ifdef MAIA_TIMER_FUNCTION
451 if(allTimings) {
452 return 28;
453 } else {
454 return 5;
455 }
456#else
457 return 2;
458#endif
459 }

◆ noVariables()

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::noVariables ( ) const
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 112 of file dgcartesiansolver.h.

112{ return SysEqn::noVars(); }

◆ outputInitSummary()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::outputInitSummary
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-07-29

Definition at line 5460 of file dgcartesiansolver.cpp.

5460 {
5461 TRACE();
5462
5463 // Get proper names from numeric properties
5464 const MString polynomialType = "Legendre";
5465 const MString integrationMethod = (m_dgIntegrationMethod == 0) ? "Gauss" : "Gauss-Lobatto";
5466
5467 using namespace maia::logtable;
5468
5469 // INIT SUMMARY FRAME
5470 Frame summary(" SOLVER " + std::to_string(solverId()) + " INITIALIZATION SUMMARY AT TIME STEP "
5471 + std::to_string(m_timeStep));
5472
5473 // PROBLEM SUMMARY GROUP
5474 Group& problem = summary.addGroup(" PROBLEM SUMMARY");
5475 problem.addData("System of equations", m_sysEqn.sysEqnName());
5476 problem.addData("Number of dimensions", nDim);
5477 Data& vars = problem.addData("Number of variables", m_sysEqn.noVars());
5478 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
5479 if(i == 0) {
5480 vars.addData("Conservative variable name(s)", m_sysEqn.consVarNames(i));
5481 } else {
5482 vars.addData("", m_sysEqn.consVarNames(i));
5483 }
5484 }
5485 problem.addData("Restart", m_restart);
5486 if(m_restart) {
5487 problem.addData("Initial condition", getRestartFileName(m_timeStep, m_useNonSpecifiedRestartFile));
5488 } else {
5489 problem.addData("Initial condition", m_sysEqn.m_initialCondition);
5490 }
5491 problem.addData("Start time (non-dimensionalized)", m_time);
5492 problem.addData("Final time (non-dimensionalized)", m_finalTime);
5493 problem.addData("CFL", m_sysEqn.cfl());
5494 problem.addData("Recalculation interval for time step", m_calcTimeStepInterval);
5495 problem.addData("Time step", m_timeStep);
5496 problem.addData("Maximum number of time steps", m_timeSteps);
5497
5498 // DISCRETIZATION SUMMARY GROUP
5499 Group& discret = summary.addGroup("DISCRETIZATION SUMMARY");
5500 discret.addData("Initial polynomial degree", m_initPolyDeg);
5501 discret.addData("Minimum polynomial degree (limit)", m_minPolyDeg);
5502 discret.addData("Maximum polynomial degree (limit)", m_maxPolyDeg);
5503 discret.addData("Polynomial type", polynomialType);
5504 discret.addData("Integration method", integrationMethod);
5505 MString timeIntegrationScheme;
5508 default:
5509 timeIntegrationScheme = "Carpenter 4/5";
5510 break;
5511 }
5513 timeIntegrationScheme = "Toulorge C 4/8";
5514 break;
5515 }
5517 timeIntegrationScheme = "Niegemann 4/14";
5518 break;
5519 }
5521 timeIntegrationScheme = "Niegemann 4/13";
5522 break;
5523 }
5525 timeIntegrationScheme = "Toulorge C 3/7";
5526 break;
5527 }
5529 timeIntegrationScheme = "Toulorge F 4/8";
5530 break;
5531 }
5532 }
5533 discret.addData("Time integration scheme", timeIntegrationScheme);
5534
5535 // PARALLELIZATION SUMMARY
5536 Group& parallel = summary.addGroup("PARALLELIZATION SUMMARY");
5537 parallel.addData("Domain id", domainId());
5538 parallel.addData("Number of neighbor domains", grid().noNeighborDomains());
5539 parallel.addData("Number of exchange neighbor domains", m_noExchangeNghbrDomains);
5540 parallel.addData("Total number of domains", noDomains());
5541
5542 // GRID SUMMARY LOCAL
5543 Group& gridLocal = summary.addGroup("GRID SUMMARY (LOCAL)");
5544 gridLocal.addData("Minimum used polynomial degree", m_statLocalMinPolyDeg);
5545 gridLocal.addData("Maximum used polynomial degree", m_statLocalMaxPolyDeg);
5546 gridLocal.addData("Average used polynomial degree", 1.0 * m_statLocalPolyDegSum / m_statLocalNoActiveCells);
5547 gridLocal.addBlank();
5548 gridLocal.addData("Minimum grid level", m_statLocalMinLevel);
5549 gridLocal.addData("Maximum grid level", m_statLocalMaxLevel);
5550 gridLocal.addBlank();
5551 Data& noCellsLocal = gridLocal.addData("Number of cells", m_statLocalNoCells);
5552 noCellsLocal.addData("internal cells", m_statLocalNoInternalCells);
5553 noCellsLocal.addData("halo cells", m_statLocalNoHaloCells);
5554 gridLocal.addData("Number of active cells", m_statLocalNoActiveCells);
5555 gridLocal.addData("Number of active DOFs", m_statLocalNoActiveDOFs);
5556 // Number of active DOFs per polynomial degree
5557 const MInt noPolyDegs = m_maxPolyDeg - m_minPolyDeg + 1;
5558 if(noPolyDegs > 1) {
5559 for(MInt i = 0; i < noPolyDegs; i++) {
5560 MString name = "Number of active DOFs polyDeg=" + std::to_string(m_minPolyDeg + i);
5561 gridLocal.addData(name, m_statLocalNoActiveDOFsPolyDeg[i]);
5562 }
5563 }
5564 gridLocal.addData("Max. number of cells (collector size)", m_statLocalMaxNoCells);
5565 gridLocal.addData("Memory utilization", 100.0 * m_statLocalNoCells / m_statLocalMaxNoCells);
5566 gridLocal.addBlank();
5567 gridLocal.addData("Number of elements", m_statLocalNoElements);
5568 gridLocal.addData("Number of helements", m_statLocalNoHElements);
5569 gridLocal.addBlank();
5570 Data& surfaces = gridLocal.addData("Number of surfaces", m_statLocalNoSurfaces);
5571 surfaces.addData("boundary surfaces", m_statLocalNoBoundarySurfaces);
5572 surfaces.addData("inner surfaces", m_statLocalNoInnerSurfaces);
5573 surfaces.addData("MPI surfaces", m_statLocalNoMpiSurfaces);
5574 gridLocal.addData("Max. number of surfaces (collector size)", m_statLocalMaxNoSurfaces);
5575 gridLocal.addData("Memory utilization", 100.0 * m_statLocalNoSurfaces / m_statLocalMaxNoSurfaces);
5576
5577 // GRID SUMMARY (GLOBAL)
5578 Group& gridGlobal = summary.addGroup("GRID SUMMARY (GLOBAL)");
5579 gridGlobal.addData("Minimum used polynomial degree", m_statGlobalMinPolyDeg);
5580 gridGlobal.addData("Maximum used polynomial degree", m_statGlobalMaxPolyDeg);
5581 gridGlobal.addData("Average used polynomial degree", 1.0 * m_statGlobalPolyDegSum / m_statGlobalNoActiveCells);
5582 gridGlobal.addBlank();
5583 gridGlobal.addData("Minimum grid level", m_statGlobalMinLevel);
5584 gridGlobal.addData("Maximum grid level", m_statGlobalMaxLevel);
5585 gridGlobal.addBlank();
5586 Data& noCellsGlbl = gridGlobal.addData("Number of cells", m_statGlobalNoCells);
5587 noCellsGlbl.addData("internal cells", m_statGlobalNoInternalCells);
5588 noCellsGlbl.addData("halo cells", m_statGlobalNoHaloCells);
5589 gridGlobal.addData("Number of active cells", m_statGlobalNoActiveCells);
5590 gridGlobal.addData("Number of active DOFs", m_statGlobalNoActiveDOFs);
5591 gridGlobal.addData("Max. number of cells (collector size)", m_statGlobalMaxNoCells);
5592 gridGlobal.addData("Memory utilization", 100.0 * m_statGlobalNoCells / m_statGlobalMaxNoCells);
5593 gridGlobal.addBlank();
5594 gridGlobal.addData("Number of elements", m_statGlobalNoElements);
5595 gridGlobal.addData("Number of helements", m_statGlobalNoHElements);
5596 gridGlobal.addBlank();
5597 Data& surfacesGlobal = gridGlobal.addData("Number of surfaces", m_statGlobalNoSurfaces);
5598 surfacesGlobal.addData("boundary surfaces", m_statGlobalNoBoundarySurfaces);
5599 surfacesGlobal.addData("inner surfaces", m_statGlobalNoInnerSurfaces);
5600 surfacesGlobal.addData("MPI surfaces", m_statGlobalNoMpiSurfaces);
5601 surfacesGlobal.addData("Surfaces marked for p-ref", m_statGlobalNoPrefSurfs);
5602 surfacesGlobal.addData("Surfaces marked for h-ref", m_statGlobalNoHrefSurfs);
5603 gridGlobal.addData("Max. number of surfaces (collector size)", m_statGlobalMaxNoSurfaces);
5604 gridGlobal.addData("Memory utilization", 100.0 * m_statGlobalNoSurfaces / m_statGlobalMaxNoSurfaces);
5605
5606 // BOUNDARY CONDITION SUMMARY
5607 Group& boundary = summary.addGroup("BOUNDARY CONDITIONS");
5608 for(auto&& bc : m_boundaryConditions) {
5609 boundary.addData(bc->name(), bc->id());
5610 }
5611
5612 // CUT-OFF BOUNDARY SUMMARY
5613 Group& cutOffBoundary = summary.addGroup("CUT-OFF BOUNDARY CONDITIONS");
5614 cutOffBoundary.addData("Enabled?", m_useCutOffBoundaries);
5616 std::array<MString, 6> dirs = {{"-x", "+x", "-y", "+y", "-z", "+z"}};
5617 for(MInt i = 0; i < 2 * nDim; i++) {
5618 const MString bc = dirs[i] + " (bcId: " + to_string(m_cutOffBoundaryConditionIds[i]) + ")";
5619 cutOffBoundary.addData(bc, m_statGlobalNoCutOffBoundarySurfaces[i]);
5620 }
5621 }
5622
5623 // SBP SUMMARY
5624 Group& sbp = summary.addGroup("SBP MODE");
5625 sbp.addData("Enabled?", m_sbpMode);
5626 sbp.addData("Operator", m_sbpOperator);
5627
5628 std::string s = summary.buildString();
5629
5630 // Print output to terminal only on root domain, print output to m_log on
5631 // all domains
5632 if(isMpiRoot()) {
5633 cout << s << std::endl;
5634 }
5635 m_log << s << endl;
5636}
@ DG_TIMEINTEGRATION_CARPENTER_4_5
Definition: enums.h:321
@ DG_TIMEINTEGRATION_TOULORGEC_3_7
Definition: enums.h:325
@ DG_TIMEINTEGRATION_TOULORGEC_4_8
Definition: enums.h:322
@ DG_TIMEINTEGRATION_TOULORGEF_4_8
Definition: enums.h:326
@ DG_TIMEINTEGRATION_NIEGEMANN_4_13
Definition: enums.h:324
@ DG_TIMEINTEGRATION_NIEGEMANN_4_14
Definition: enums.h:323
MString buildString(const int shift=0) final
Definition: logtable.h:56
Data & addData(const std::string &title_, T data_)
Definition: logtable.h:75
Data & addData(const std::string &title_, T data_)
Definition: logtable.h:111

◆ pointIsInside()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::pointIsInside ( const MFloat *const  coordinates)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-04-23
Parameters
[in]coordinatesThe coordinates of the point to check.
Returns
If the point is inside the computational domain (i.e. not inside "non-fluid" areas), return true. Return false otherwise.

FIXME labels:DG This has been shamelessly copied from GridgenPar. This should be implemented in the grid or geometry classes and used from there. However, currently CartesianGrid has a mess of pointIsInside methods and it is not clear which one to use.

Definition at line 2460 of file dgcartesiansolver.cpp.

2460 {
2461 // TRACE();
2462
2463 // Get bounding box of grid
2464 const MFloat* const box = geometry().boundingBox();
2465
2466 // Shoot rays in each direction
2467 MBool isInside = true;
2468 for(MInt dir = 0; dir < nDim; dir++) {
2469 // Cast ray from the point in question in the -ve 'dir'-direction
2470 array<MFloat, 2 * nDim> target;
2471 for(MInt i = 0; i < nDim; i++) {
2472 target[i] = coordinates[i];
2473 target[i + nDim] = coordinates[i];
2474 }
2475 // This line ensures that the second point is well outside the bounding box
2476 target[dir] = box[dir] - (target[dir] - box[dir]);
2477
2478 // Get list of intersecting geometry elements
2479 std::vector<MInt> nodeList;
2480 geometry().getLineIntersectionElements(&target[0], nodeList);
2481
2482 // Point is inside iff the number of cuts is uneven
2483 if(nodeList.size() % 2 == 0) {
2484 isInside = false;
2485 break;
2486 }
2487 }
2488
2489 return isInside;
2490}
const MFloat * boundingBox() const
Definition: geometry.h:50
virtual MInt getLineIntersectionElements(MFloat *, std::vector< MInt > &)
Definition: geometry.h:73

◆ postAdaptation()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::postAdaptation ( )
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 297 of file dgcartesiansolver.h.

297{};

◆ postTimeStep()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::postTimeStep
virtual

Implements Solver.

Definition at line 1679 of file dgcartesiansolver.cpp.

1679 {
1680 TRACE();
1681 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
1682
1683 // Time step completed
1684 // Update physical time and counters
1685 m_time += m_dt;
1687
1688 // Analyze error norms and print info to user
1690 RECORD_TIMER_START(m_timers[Timers::Analysis]);
1691
1692 const MFloat timeDiff = wallTime() - m_analyzeTimeStart - m_outputTime;
1693 const MFloat runTimeRelative = timeDiff * noDomains() / m_noAnalyzeTimeSteps / m_statGlobalNoActiveDOFs;
1694 const MFloat runTimeTotal = wallTime() - m_loopTimeStart;
1695
1696 analyzeTimeStep(m_time, runTimeRelative, runTimeTotal, m_timeStep, m_dt);
1697 if(m_finalTimeStep && isMpiRoot()) {
1698 cout << endl;
1699 cout << "----------------------------------------"
1700 << "----------------------------------------" << endl;
1701 cout << " MAIA finished. Final time: " << m_time << " Time steps: " << m_timeStep << endl;
1702 cout << "----------------------------------------"
1703 << "----------------------------------------" << endl;
1704 }
1705
1706 // Reset time + counters
1708 m_outputTime = 0.0;
1710
1711 RECORD_TIMER_STOP(m_timers[Timers::Analysis]);
1712 }
1713 // TODO labels:DG,toremove moved to run_unified() but no output of sim-time/dt
1714 /* } else if (m_aliveInterval > 0 && m_timeStep % m_aliveInterval == 0 && isMpiRoot()) { */
1715 /* // Calculate total run time for printing */
1716 /* const MFloat runTimeTotal = wallTime() - m_loopTimeStart; */
1717
1718 /* // Print out processing information to user */
1719 /* printf("#t/s: %8d | dt: %.4e | Sim. time: %.4e | Run time: %.4e s\n", m_timeStep, m_dt,
1720 * m_time, */
1721 /* runTimeTotal); */
1722 /* } */
1723
1724 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
1725}

◆ prepareAdaptation()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::prepareAdaptation ( )
inlineoverridevirtual

Reimplemented from Solver.

Definition at line 292 of file dgcartesiansolver.h.

292{};

◆ prepareRestart()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::prepareRestart ( MBool  ,
MBool  
)
overridevirtual

Reimplemented from Solver.

Definition at line 1730 of file dgcartesiansolver.cpp.

1730 {
1731 TRACE();
1732
1733 if(!isActive()) return false;
1734
1736 return true;
1737 }
1738
1739 return writeRestart;
1740}
MInt m_restartInterval
The number of timesteps before writing the next restart file.
Definition: solver.h:79

◆ preTimeStep()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::preTimeStep
overridevirtual

Implements Solver.

Definition at line 1608 of file dgcartesiansolver.cpp.

1608 {
1609 TRACE();
1610 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
1611
1612 // Abort if main loop not initialized
1613 if(!m_isInitMainLoop) {
1614 TERMM(1, "Main loop was not initialized.");
1615 }
1616
1617 // Check that this is the first Runge-Kutta stage, i.e. start of new timestep
1618 if(m_rkStage != 0) {
1619 TERMM(1,
1620 "preTimeStep should only be called at the start of a new timestep: rkStage = " + std::to_string(m_rkStage));
1621 }
1622
1623 // Increment time step
1624 m_timeStep++;
1625 ASSERT(m_timeStep == globalTimeStep, "Error: time step inconsistent.");
1626
1627 // Calculate time step (or use external dt) at first time step or for correct modulo
1629 m_dt = calcTimeStep();
1630 m_firstTimeStep = false;
1631 }
1632
1633 // Perform adaptive refinement if needed
1635 // Cancel open MPI (receive) requests
1637
1639 }
1640
1641 // Determine if this is the last time step and reset time step size if necessary
1642 m_finalTimeStep = false;
1643 if(m_finalTime - m_time - m_dt < 1.0E-10) {
1644 m_finalTimeStep = true;
1646 } else if(g_multiSolverGrid && m_timeStep == std::max(m_restartTimeStep, 0) + m_timeSteps) {
1647 m_finalTimeStep = true;
1648 } else if(!g_multiSolverGrid && m_timeStep == m_timeSteps) {
1649 // TODO labels:DG change default time step behaviour of DG solver?
1650 m_finalTimeStep = true;
1651 }
1652
1653 // Reset external (coupling) sources at beginning of a new time step
1655
1656 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
1657}
MFloat calcTimeStep()
Calculate the next time step.
void adaptiveRefinement(const MInt timeStep)
Apply adaptive refinement (right now: only p-refinement)
void cancelMpiRequests() override
Cancel open MPI (receive) requests.
MBool isAdaptationTimeStep(const MInt timeStep) const
Return if the given timestep is an adaptation timestep.
MInt globalTimeStep

◆ prolongToSurfaces() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::prolongToSurfaces
private
Author
Sven Berger
Date
November 2014

Definition at line 6714 of file dgcartesiansolver.cpp.

6714 {
6715 TRACE();
6716 RECORD_TIMER_START(m_timers[Timers::Prolong]);
6717
6719
6720 RECORD_TIMER_STOP(m_timers[Timers::Prolong]);
6721}

◆ prolongToSurfaces() [2/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::prolongToSurfaces ( const MInt  begin,
const MInt  end 
)
private
Author
Sven Berger
Date
November 2014
Parameters
[in]beginIndex of the first element to consider.
[in]endIndex+1 of the last element to consider.

Definition at line 6733 of file dgcartesiansolver.cpp.

6733 {
6734 TRACE();
6735
6736 const MInt* polyDegs = &m_elements.polyDeg(0);
6737 const MInt* noNodes = &m_elements.noNodes1D(0);
6738 const MInt* surfaceIds = &m_elements.surfaceIds(0, 0);
6739
6740 using namespace dg::interpolation;
6741
6742 // IMPORTANT:
6743 // If anything in this method is changed, please check if
6744 // updateNodeVariables() needs to be changed as well, since it contains more
6745 // or less the same code.
6746
6748#ifdef _OPENMP
6749#pragma omp parallel for
6750#endif
6751 // Loop over all elements in given range
6752 for(MInt elementId = begin; elementId < end; elementId++) {
6753 const MInt surfaceIdOffset = elementId * 2 * nDim;
6754 const MInt polyDeg = polyDegs[elementId];
6755 const MInt noNodes1D = noNodes[elementId];
6756 const DgInterpolation& interp = m_interpolation[polyDeg][noNodes1D];
6757
6758 // Extrapolate the solution to each surface on the faces
6759 for(MInt dir = 0; dir < 2 * nDim; dir++) {
6760 const MInt srfcId = surfaceIds[surfaceIdOffset + dir];
6761 const MInt side = 1 - dir % 2;
6762
6763 MFloat* src = &m_elements.variables(elementId);
6764 MFloat* dest = &m_surfaces.variables(srfcId, side);
6765
6766 prolongToFaceGauss<nDim, SysEqn::noVars()>(src, dir, noNodes1D, &interp.m_LFace[0][0], &interp.m_LFace[1][0],
6767 dest);
6768 }
6769 }
6771#ifdef _OPENMP
6772#pragma omp parallel for
6773#endif
6774 // Loop over all elements in given range
6775 for(MInt elementId = begin; elementId < end; elementId++) {
6776 const MInt surfaceIdOffset = elementId * 2 * nDim;
6777 const MInt noNodes1D = noNodes[elementId];
6778
6779 // Extrapolate the solution to each surface on the faces
6780 for(MInt dir = 0; dir < 2 * nDim; dir++) {
6781 const MInt srfcId = surfaceIds[surfaceIdOffset + dir];
6782 const MInt side = 1 - dir % 2;
6783
6784 MFloat* src = &m_elements.variables(elementId);
6785 MFloat* dest = &m_surfaces.variables(srfcId, side);
6786
6787 prolongToFaceGaussLobatto<nDim, SysEqn::noVars()>(src, dir, noNodes1D, dest);
6788 }
6789 }
6790 }
6791}

◆ reIntAfterRestart()

template<MInt nDim, class SysEqn >
virtual void DgCartesianSolver< nDim, SysEqn >::reIntAfterRestart ( MBool  )
inlinevirtual

Reimplemented from Solver.

Definition at line 282 of file dgcartesiansolver.h.

282{};

◆ resetBuffer()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::resetBuffer ( const MInt  totalSize,
MFloat *const  buffer 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-12-23
Parameters
[in]totalSizeTotal data size.
[in]bufferPointer to data buffer to be reset.

Definition at line 8033 of file dgcartesiansolver.cpp.

8033 {
8034 TRACE();
8035
8036#ifdef _OPENMP
8037#pragma omp parallel for
8038#endif
8039 for(MInt i = 0; i < totalSize; i++) {
8040 buffer[i] = 0.0;
8041 }
8042}

◆ resetExternalSources()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::resetExternalSources
private

Definition at line 8013 of file dgcartesiansolver.cpp.

8013 {
8014 TRACE();
8015 RECORD_TIMER_START(m_timers[Timers::ResetExternalSources]);
8016
8018
8019 RECORD_TIMER_STOP(m_timers[Timers::ResetExternalSources]);
8020}
void resetBuffer(const MInt totalSize, MFloat *const buffer)
Reset the given buffer to zero.

◆ resetRHS()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::resetRHS
privatevirtual
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-12-13

Definition at line 8002 of file dgcartesiansolver.cpp.

8002 {
8003 TRACE();
8004 RECORD_TIMER_START(m_timers[Timers::ResetRHS]);
8005
8007
8008 RECORD_TIMER_STOP(m_timers[Timers::ResetRHS]);
8009}

◆ resetSolver()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::resetSolver
overridevirtual
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

Reimplemented from Solver.

Definition at line 9319 of file dgcartesiansolver.cpp.

9319 {
9320 TRACE();
9321
9323
9324 // Set to -1 such that the new size is calculated in allocateAndInitSolverMemory
9325 m_maxNoSurfaces = -1;
9326
9327 // Cleanup communication memory
9328 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
9329 m_mpiSurfaces[i].clear();
9330 m_sendBuffers[i].clear();
9331 m_recvBuffers[i].clear();
9332 }
9333 m_mpiSurfaces.clear();
9334 m_sendBuffers.clear();
9335 m_recvBuffers.clear();
9336 m_exchangeNghbrDomains.clear();
9337 m_sendRequests.clear();
9338 m_recvRequests.clear();
9340
9341 m_isInitSolver = false;
9342}

◆ resizeGridMap()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::resizeGridMap ( )
inlinevirtual

Reimplemented from Solver.

Definition at line 286 of file dgcartesiansolver.h.

286 {
287 // Note: resize with current tree size since the number of cells should not change
288 grid().resizeGridMap(grid().tree().size());
289 }

◆ run()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::run
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-04-26

After creation of a solver instance, this should be the only method that needs to be called from outside.

In the future, when we have "true" multi solver support, this needs to be rewritten properly, but for now this is where the magic takes place.

Definition at line 1220 of file dgcartesiansolver.cpp.

1220 {
1221 TRACE();
1222
1223 RECORD_TIMER_START(m_timers[Timers::Run]);
1224 RECORD_TIMER_START(m_timers[Timers::RunInit]);
1225
1226 // Set polynomial degree, init interpolation, create surfaces etc.
1228
1229 // Apply initial conditions or load restart file
1230 initData();
1231
1232 // Perform remaining steps needed before main loop execution
1233 initMainLoop();
1234
1235 RECORD_TIMER_STOP(m_timers[Timers::RunInit]);
1236
1237 // Run main loop
1238 MBool finalTimeStep = false;
1239 while(!finalTimeStep) {
1240 finalTimeStep = step();
1241 }
1242
1243 // Clean up after the simulation is done
1244 cleanUp();
1245
1246 RECORD_TIMER_STOP(m_timers[Timers::Run]);
1247}
void cleanUp() override
Clean up after a simulation run.
MBool step(const MFloat externalDt=-std::numeric_limits< MFloat >::infinity(), const MBool substep=false)
Advance the solution by one time step.

◆ saveNodalData()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::saveNodalData ( const MString fileNameBase,
const MInt  noVars,
const std::vector< MString > &  varNames,
const MFloat *const  data 
) const
private
Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-07-26
Parameters
[in]fileNameBaseBase name of file (i.e., without directory or file extension) to write noda data to.
[in]noVarsNumber of variables to save to file.
[in]varNamesList of variable names.
[in]dataNodal data to save.

This function allows to save nodal data to a file. The data needs to be stored with a data solver size per element of the (maximum number of nodes) x (number of variables), i.e, it has to have the same structure as the m_variables field in m_elements. If noVars > 1, it is expected that the variables are stored in an array-of-structs layout, i.e., var0 var1 var2 var0 var1 var2 var0 ...

Definition at line 6361 of file dgcartesiansolver.cpp.

6364 {
6365 TRACE();
6366 CHECK_TIMERS_IO();
6367
6368 // Sanity check
6369 if(noVars < 1) {
6370 TERMM(1, "noVars must by >= 1");
6371 }
6372
6373 // Determine data offset for each element in output buffer
6374 const MInt noElements = m_elements.size();
6375 MIntScratchSpace elementOffset(noElements, AT_, "elementOffset");
6376 MIntScratchSpace elementNodes(noElements, AT_, "elementNodes");
6377 for(MInt cellId = 0, offset = 0, elementId = 0; elementId < noElements; cellId++) {
6378 // If cellId is not the one of the current element (i.e. the current cell
6379 // does not have an element), add the default offset (based on initPolyDeg)
6380 if(cellId != m_elements.cellId(elementId)) {
6381 offset += ipow(m_initNoNodes1D, nDim);
6382 continue;
6383 }
6384
6385 // Otherwise use current offset for the current element
6386 elementOffset[elementId] = offset;
6387
6388 // Increase offset based on element polynomial degree
6389 const MInt noNodesXD = m_elements.noNodesXD(elementId);
6390 offset += noNodesXD;
6391
6392 // Set number of nodes to use later and proceed with next element
6393 elementNodes[elementId] = noNodesXD;
6394 elementId++;
6395 }
6396
6397 // Determine local data array size
6398 // array size = #nodes of elements + (#cells - #elements) * default cell size
6399 // (cells without elements use polyDeg = initPolyDeg)
6400 const MInt localNoNodes = m_noTotalNodesXD + (grid().noInternalCells() - noElements) * ipow(m_initNoNodes1D, nDim);
6401
6402 // Create data out object to save data to disk
6403 const MString fileName = outputDir() + fileNameBase + ParallelIo::fileExt();
6404 using namespace parallel_io;
6405 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
6406
6407 // Set attributes
6408 parallelIo.setAttribute(grid().gridInputFileName(), "gridFile");
6409 parallelIo.setAttribute("DG", "solverType");
6410 if(m_sbpMode) {
6411 parallelIo.setAttribute((MInt)m_sbpMode, "sbpMode");
6412 }
6413 // @ansgar TODO labels:DG,toenhance change this in the future to always write the solver id, this will change a lot
6414 // of reference files, e.g., the nodevars
6415 if(grid().raw().treeb().noSolvers() > 1) {
6416 parallelIo.setAttribute(solverId(), "solverId");
6417 }
6418
6419 // Determine offset and global number of nodes
6420 ParallelIo::size_type nodesOffset, globalNoNodes;
6421 ParallelIo::calcOffset(localNoNodes, &nodesOffset, &globalNoNodes, mpiComm());
6422
6423 // Define arrays in file
6424 // Polyomial degree
6425 parallelIo.defineArray(PIO_UCHAR, "polyDegs", grid().domainOffset(noDomains()));
6426 // Number of nodes in SBP mode
6427 if(m_sbpMode) {
6428 parallelIo.defineArray(PIO_UCHAR, "noNodes1D", grid().domainOffset(noDomains()));
6429 }
6430
6431 // Get information about integration method and polynomial type
6432 MString dgIntegrationMethod = m_sbpMode ? "DG_INTEGRATE_GAUSS_LOBATTO" : "DG_INTEGRATE_GAUS";
6433 dgIntegrationMethod =
6434 Context::getSolverProperty<MString>("dgIntegrationMethod", m_solverId, AT_, &dgIntegrationMethod);
6435 MString dgPolynomialType = "DG_POLY_LEGENDRE";
6436 dgPolynomialType = Context::getSolverProperty<MString>("dgPolynomialType", m_solverId, AT_, &dgPolynomialType);
6437
6438 // Add integration method & polynomial type to grid file as attributes
6439 parallelIo.setAttribute(dgIntegrationMethod, "dgIntegrationMethod", "polyDegs");
6440 parallelIo.setAttribute(dgPolynomialType, "dgPolynomialType", "polyDegs");
6441
6442 // Add arrays to file
6443 for(MInt i = 0; i < noVars; i++) {
6444 const MString name = "variables" + to_string(i);
6445 parallelIo.defineArray(PIO_FLOAT, name, globalNoNodes);
6446 parallelIo.setAttribute(varNames[i], "name", name);
6447 }
6448
6449 const MInt maxNoNodesXD = ipow(m_maxNoNodes1D, nDim);
6450 const MInt elementDataSize = noVars * maxNoNodesXD;
6451
6452 // Write data to disk
6453 // Create scratch space with polynomial degree and write it to file
6454 parallelIo.setOffset(grid().noInternalCells(), grid().domainOffset(domainId()));
6455 MUcharScratchSpace polyDegs(grid().noInternalCells(), FUN_, "polyDegs");
6456 fill_n(&polyDegs[0], grid().noInternalCells(), m_initPolyDeg);
6457 for(MInt elementId = 0; elementId < noElements; elementId++) {
6458 const MInt cellId = m_elements.cellId(elementId);
6459 polyDegs.p[cellId] = m_elements.polyDeg(elementId);
6460 }
6461 parallelIo.writeArray(polyDegs.begin(), "polyDegs");
6462
6463 // Create scratch space with noNodes and write it to file
6464 if(m_sbpMode) {
6465 parallelIo.setOffset(grid().noInternalCells(), grid().domainOffset(domainId()));
6466 MUcharScratchSpace noNodes1D(grid().noInternalCells(), FUN_, "noNodes1D");
6467 fill_n(&noNodes1D[0], grid().noInternalCells(), m_initNoNodes1D);
6468 for(MInt elementId = 0; elementId < noElements; elementId++) {
6469 const MInt cellId = m_elements.cellId(elementId);
6470 noNodes1D.p[cellId] = m_elements.noNodes1D(elementId);
6471 }
6472 parallelIo.writeArray(noNodes1D.begin(), "noNodes1D");
6473 }
6474
6475 parallelIo.setOffset(localNoNodes, nodesOffset);
6476 for(MInt i = 0; i < noVars; i++) {
6477 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
6478 fill(buffer.begin(), buffer.end(), 0.0);
6479 for(MInt e = 0; e < noElements; e++) {
6480 MFloat* const b = &buffer[elementOffset[e]];
6481 const MInt dataOffset = e * elementDataSize + i;
6482 const MFloat* const v = &data[dataOffset];
6483 for(MInt n = 0; n < elementNodes[e]; n++) {
6484 b[n] = v[n * noVars];
6485 }
6486 }
6487 const MString name = "variables" + to_string(i);
6488 parallelIo.writeArray(&buffer[0], name);
6489 }
6490}
MString outputDir() const
Return the directory for output files.
Definition: solver.h:407
MInt noSolvers
Definition: maiatypes.h:73

◆ saveNodeVarsFile()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::saveNodeVarsFile
private
Author
Michael Schlottke-Lakemper (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-07-26

This is mainly used as a restart file if the node variables are constant in time.

Definition at line 6501 of file dgcartesiansolver.cpp.

6501 {
6502 TRACE();
6503 CHECK_TIMERS_IO();
6504
6505 m_log << "Saving file with node variable data for restarting... ";
6506
6507 // Add solver number in case of multisolver execution
6508 stringstream ss;
6509 ss << "nodevars" << getIdentifier(g_multiSolverGrid, "_b", "");
6510
6511 // Assemble node variable names
6512 vector<MString> nodeVarNames(SysEqn::noNodeVars());
6513 for(MInt nodeVar = 0; nodeVar < SysEqn::noNodeVars(); nodeVar++) {
6514 nodeVarNames[nodeVar] = m_sysEqn.nodeVarNames(nodeVar);
6515 }
6516
6517 // Save node variables
6518 saveNodalData(ss.str(), SysEqn::noNodeVars(), nodeVarNames, &m_elements.nodeVars(0));
6519
6520 m_log << "done" << endl;
6521}
void saveNodalData(const MString &fileNameBase, const MInt noVars, const std::vector< MString > &varNames, const MFloat *const data) const
Save nodal data to file.

◆ savePartitionCellWorkloads()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::savePartitionCellWorkloads ( )
private

◆ saveRestartFile()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::saveRestartFile
privatevirtual
Author
Michael Schlottke, Sven Berger
Date
2012-12-22

Definition at line 5893 of file dgcartesiansolver.cpp.

5893 {
5894 TRACE();
5895 RECORD_TIMER_START(m_timers[Timers::Accumulated]);
5896 RECORD_TIMER_START(m_timers[Timers::IO]);
5897 RECORD_TIMER_START(m_timers[Timers::SaveRestartFile]);
5898
5899 // Determine file name and grid file name
5901
5902 stringstream ss;
5903 ss << "restart_" << getIdentifier(g_multiSolverGrid, "b") << setw(8) << setfill('0') << m_timeStep;
5904 const MString suffix = ss.str();
5905
5906 // Determine data offset for each element in output buffer
5907 const MInt noElements = m_elements.size();
5908 MIntScratchSpace elementOffset(noElements, AT_, "elementOffset");
5909 MIntScratchSpace elementNodes(noElements, AT_, "elementNodes");
5910 for(MInt cellId = 0, offset = 0, elementId = 0; elementId < noElements; cellId++) {
5911 // If cellId is not the one of the current element (i.e. the current cell
5912 // does not have an element), add the default offset (based on initPolyDeg)
5913 if(cellId != m_elements.cellId(elementId)) {
5914 offset += ipow(m_initNoNodes1D, nDim);
5915 continue;
5916 }
5917
5918 // Otherwise use current offset for the current element
5919 elementOffset[elementId] = offset;
5920
5921 // Increase offset based on element polynomial degree
5922 const MInt noNodesXD = m_elements.noNodesXD(elementId);
5923 offset += noNodesXD;
5924
5925 // Set number of nodes to use later and proceed with next element
5926 elementNodes[elementId] = noNodesXD;
5927 elementId++;
5928 }
5929
5930 // Determine local data array size
5931 // array size = #nodes of elements + (#cells - #elements) * default cell size
5932 // (cells without elements use polyDeg = initPolyDeg)
5933 const MInt localNoNodes = m_noTotalNodesXD + (grid().noInternalCells() - noElements) * ipow(m_initNoNodes1D, nDim);
5934
5935 // Create data out object to save data to disk
5936 using namespace parallel_io;
5937 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
5938
5939 // Set attributes
5940 // If adaptive refinement is active set to correct adapted grid file name
5941 if(hasAdaptivePref()) {
5942 parallelIo.setAttribute(suffix + grid().gridInputFileName(), "gridFile");
5943 } else {
5944 parallelIo.setAttribute(grid().gridInputFileName(), "gridFile");
5945 }
5946 parallelIo.setAttribute("DG", "solverType");
5947 if(m_sbpMode) {
5948 parallelIo.setAttribute((MInt)m_sbpMode, "sbpMode");
5949 }
5950 parallelIo.setAttribute(solverId(), "solverId");
5951
5952 // Set time variables
5953 parallelIo.defineScalar(PIO_INT, "timeStep");
5954 parallelIo.defineScalar(PIO_FLOAT, "time");
5955 parallelIo.defineScalar(PIO_FLOAT, "dt");
5956
5957 // Determine offset and global number of nodes
5958 ParallelIo::size_type nodesOffset, globalNoNodes;
5959 ParallelIo::calcOffset(localNoNodes, &nodesOffset, &globalNoNodes, mpiComm());
5960
5961 // Define arrays in file
5962 // Polynomial degree
5963 parallelIo.defineArray(PIO_UCHAR, "polyDegs", grid().domainOffset(noDomains()));
5964 // Number of nodes in SBP mode
5965 if(m_sbpMode) {
5966 parallelIo.defineArray(PIO_UCHAR, "noNodes1D", grid().domainOffset(noDomains()));
5967 }
5968
5969 // Get information about integration method and polynomial type
5970 MString dgIntegrationMethod = m_sbpMode ? "DG_INTEGRATE_GAUSS_LOBATTO" : "DG_INTEGRATE_GAUSS";
5971 dgIntegrationMethod =
5972 Context::getSolverProperty<MString>("dgIntegrationMethod", m_solverId, AT_, &dgIntegrationMethod);
5973 MString dgPolynomialType = "DG_POLY_LEGENDRE";
5974 dgPolynomialType = Context::getSolverProperty<MString>("dgPolynomialType", m_solverId, AT_, &dgPolynomialType);
5975 // Add integration method & polynomial type to restart file as attributes
5976 parallelIo.setAttribute(dgIntegrationMethod, "dgIntegrationMethod", "polyDegs");
5977 parallelIo.setAttribute(dgPolynomialType, "dgPolynomialType", "polyDegs");
5978
5979 // Set counter to get correct variable names
5980 MInt varId = 0;
5981
5982 // Solution
5983 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
5984 const MString name = "variables" + to_string(varId++);
5985 parallelIo.defineArray(PIO_FLOAT, name, globalNoNodes);
5986 parallelIo.setAttribute(m_sysEqn.consVarNames(i), "name", name);
5987 }
5988
5989 // Node variables
5990 if(SysEqn::hasTimeDependentNodeVars()) {
5991 for(MInt i = 0; i < SysEqn::noNodeVars(); i++) {
5992 const MString name = "variables" + to_string(varId++);
5993 parallelIo.defineArray(PIO_FLOAT, name, globalNoNodes);
5994 parallelIo.setAttribute(m_sysEqn.nodeVarNames(i), "name", name);
5995 }
5996 }
5997
5998 // Note: kept here to have a template for writing a data array that is only defined for all
5999 // elements but should be filled and written on a cell basis for visualization
6000 // Coupling variables
6001 // if (hasCoupling()) {
6002 // for (auto& cc : m_couplingConditions) {
6003 // for (MInt i = 0; i < cc->noRestartVars(); i++) {
6004 // const MString name = "variables" + to_string(varId++);
6005 // parallelIo.defineArray(PIO_FLOAT, name, globalNoNodes);
6006 // parallelIo.setAttribute(cc->restartVarName(i), "name", name);
6007 // parallelIo.setAttribute("couplingCondition", "type", name);
6008 // parallelIo.setAttribute(cc->name(), "ccName", name);
6009 // parallelIo.setAttribute(cc->id(), "ccId", name);
6010 // }
6011 // }
6012 //}
6013
6014 // Boundary conditions
6015 MInt bcId = 0;
6016 const MInt noBcIds = m_boundaryConditions.size();
6017 std::vector<ParallelIo::size_type> bcNodesOffset(noBcIds, 0), bcLocalNoNodes(noBcIds, 0), bcGlobalNoNodes(noBcIds, 0);
6018
6019 for(auto&& bc : m_boundaryConditions) {
6020 const MInt bcNoVars = bc->noRestartVars();
6021 if(bcNoVars > 0) {
6022 bcLocalNoNodes[bcId] = bc->getLocalNoNodes();
6023 ParallelIo::calcOffset(bcLocalNoNodes[bcId], &bcNodesOffset[bcId], &bcGlobalNoNodes[bcId], mpiComm());
6024 for(MInt i = 0; i < bcNoVars; i++) {
6025 const MString name = "variables" + to_string(varId++);
6026 parallelIo.defineArray(PIO_FLOAT, name, bcGlobalNoNodes[bcId]);
6027 parallelIo.setAttribute(bc->restartVarName(i), "name", name);
6028 }
6029 }
6030 bcId++;
6031 }
6032
6033 // Write data to disk
6034
6035 // Write time variables to file
6036 parallelIo.writeScalar(m_timeStep, "timeStep");
6037 parallelIo.writeScalar(m_time, "time");
6038 parallelIo.writeScalar(m_dt, "dt");
6039
6040 // Create scratch space with polynomial degree and write it to file
6041 parallelIo.setOffset(grid().noInternalCells(), grid().domainOffset(domainId()));
6042 MUcharScratchSpace polyDegs(grid().noInternalCells(), FUN_, "polyDegs");
6043 fill_n(&polyDegs[0], grid().noInternalCells(), m_initPolyDeg);
6044 for(MInt elementId = 0; elementId < noElements; elementId++) {
6045 const MInt cellId = m_elements.cellId(elementId);
6046 polyDegs.p[cellId] = m_elements.polyDeg(elementId);
6047 }
6048 parallelIo.writeArray(polyDegs.begin(), "polyDegs");
6049
6050 // Create scratch space with noNodes and write it to file
6051 if(m_sbpMode) {
6052 parallelIo.setOffset(grid().noInternalCells(), grid().domainOffset(domainId()));
6053 MUcharScratchSpace noNodes1D(grid().noInternalCells(), FUN_, "noNodes1D");
6054 fill_n(&noNodes1D[0], grid().noInternalCells(), m_initNoNodes1D);
6055 for(MInt elementId = 0; elementId < noElements; elementId++) {
6056 const MInt cellId = m_elements.cellId(elementId);
6057 noNodes1D.p[cellId] = m_elements.noNodes1D(elementId);
6058 }
6059 parallelIo.writeArray(noNodes1D.begin(), "noNodes1D");
6060 }
6061
6062 varId = 0;
6063 parallelIo.setOffset(localNoNodes, nodesOffset);
6064
6065 // Solution
6066 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
6067 // Solution
6068 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
6069 fill(buffer.begin(), buffer.end(), 0.0);
6070 for(MInt e = 0; e < noElements; e++) {
6071 MFloat* const b = &buffer[elementOffset[e]];
6072 const MFloat* const v = &m_elements.variables(e) + i;
6073 for(MInt n = 0; n < elementNodes[e]; n++) {
6074 b[n] = v[n * m_sysEqn.noVars()];
6075 }
6076 }
6077 const MString name = "variables" + to_string(varId++);
6078 parallelIo.writeArray(&buffer[0], name);
6079 }
6080
6081 // Node variables
6082 if(SysEqn::hasTimeDependentNodeVars()) {
6083 for(MInt i = 0; i < SysEqn::noNodeVars(); i++) {
6084 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
6085 fill(buffer.begin(), buffer.end(), 0.0);
6086 for(MInt e = 0; e < noElements; e++) {
6087 MFloat* const b = &buffer[elementOffset[e]];
6088 const MFloat* const v = &m_elements.nodeVars(e) + i;
6089 for(MInt n = 0; n < elementNodes[e]; n++) {
6090 b[n] = v[n * SysEqn::noNodeVars()];
6091 }
6092 }
6093 const MString name = "variables" + to_string(varId++);
6094 parallelIo.writeArray(&buffer[0], name);
6095 }
6096 }
6097
6098 // Note: keep this, see comment above at definition of coupling variables
6099 // Coupling variables
6100 // if (hasCoupling()) {
6101 // for (auto& cc : m_couplingConditions) {
6102 // for (MInt i = 0; i < cc->noRestartVars(); i++) {
6103 // // Load restart variable from coupling class
6104 // MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
6105 // cc->getRestartVariable(i, &buffer[0]);
6106 //
6107 // // Re-arrange data in buffer to add gaps for each cell without element
6108 // MInt offset = m_noTotalNodesXD;
6109 // for (MInt e = noElements - 1; e >= 0; e--) {
6110 // // Update offset
6111 // const MInt noNodesXD = m_elements.noNodesXD(e);
6112 // offset -= noNodesXD;
6113 //
6114 // // Create pointers to data
6115 // MFloat* const source = &buffer[offset];
6116 // MFloat* const destination = &buffer[elementOffset[e]];
6117 //
6118 // // No copy operation needed if pointers are equal
6119 // if (destination == source) {
6120 // continue;
6121 // }
6122 //
6123 // // Copy (move) data
6124 // copy_backward(source, source + noNodesXD, destination + noNodesXD);
6125 //
6126 // // Fill up original storage location with zeros
6127 // // The min(...) expression makes sure that
6128 // // - if the original and the final storage location overlap, only the
6129 // // values that are not in the final storage location are reset
6130 // // - if the original and the final storage location DO NOT overlap,
6131 // // - the entire original region is reset with zeros
6132 // fill_n(source, min(static_cast<MLong>(noNodesXD), destination - source), 0.0);
6133 // }
6134 //
6135 // // Write data from buffer to file
6136 // const MString name = "variables" + to_string(varId++);
6137 // parallelIo.writeArray(&buffer[0], name);
6138 // }
6139 // }
6140 //}
6141
6142 // Boundary conditions
6143 bcId = 0;
6144 for(auto&& bc : m_boundaryConditions) {
6145 parallelIo.setOffset(bcLocalNoNodes[bcId], bcNodesOffset[bcId]);
6146 for(MInt i = 0; i < bc->noRestartVars(); i++) {
6147 // Avoid dereferencing a zero length array
6148 MFloatScratchSpace buffer(max(bcLocalNoNodes[bcId], 1l), AT_, "buffer");
6149 fill(buffer.begin(), buffer.end(), 0.0);
6150
6151 // Get boundary condition restart variable
6152 bc->getRestartVariable(i, &buffer[0]);
6153 const MString name = "variables" + to_string(varId++);
6154 parallelIo.writeArray(&buffer[0], name);
6155 }
6156 bcId++;
6157 }
6158
6159 RECORD_TIMER_STOP(m_timers[Timers::SaveRestartFile]);
6160 RECORD_TIMER_STOP(m_timers[Timers::IO]);
6161 RECORD_TIMER_STOP(m_timers[Timers::Accumulated]);
6162}

◆ saveSolutionFile() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::saveSolutionFile
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-12-22

Calls saveSolutionFile(const MString& suffix) with the current m_timeStep as the suffix.

Definition at line 5649 of file dgcartesiansolver.cpp.

5649 {
5650 TRACE();
5651
5652 stringstream ss;
5653 ss << setw(8) << setfill('0') << m_timeStep;
5654 saveSolutionFile(ss.str());
5655}

◆ saveSolutionFile() [2/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::saveSolutionFile ( const MString suffix)
private
Author
Michael Schlottke, Sven Berger
Date
2013-04-19
Parameters
[in]suffixThe suffix that should be appended to the generic output name (e.g. the current time step).

Definition at line 5668 of file dgcartesiansolver.cpp.

5668 {
5669 TRACE();
5670 RECORD_TIMER_START(m_timers[Timers::Accumulated]);
5671 RECORD_TIMER_START(m_timers[Timers::IO]);
5672 RECORD_TIMER_START(m_timers[Timers::SaveSolutionFile]);
5673
5674 m_log << "Saving solution file ... ";
5675
5676 // Create ParallelIo instance
5677 using namespace parallel_io;
5678 const MString fileName =
5679 outputDir() + "solution_" + getIdentifier(g_multiSolverGrid, "b") + suffix + ParallelIo::fileExt();
5680 const MInt noElements = m_elements.size();
5681 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
5682
5683 // If adaptive refinement is active set to correct adapted grid file name
5684 if(hasAdaptivePref()) {
5685 parallelIo.setAttribute(suffix + grid().gridInputFileName(), "gridFile");
5686 } else {
5687 parallelIo.setAttribute(grid().gridInputFileName(), "gridFile");
5688 }
5689
5690 // for g_multiSolverGrids we need the solverId in the file
5691 parallelIo.setAttribute(solverId(), "solverId");
5692
5693 // Determine data offset for each element in output buffer
5694 MIntScratchSpace elementOffset(noElements, AT_, "elementOffset");
5695 MIntScratchSpace elementNodes(noElements, AT_, "elementNodes");
5696 for(MInt cellId = 0, offset = 0, elementId = 0; elementId < noElements; cellId++) {
5697 // If cellId is not the one of the current element (i.e. the current cell
5698 // does not have an element), add the default offset (based on initPolyDeg)
5699 if(cellId != m_elements.cellId(elementId)) {
5700 offset += ipow(m_initNoNodes1D, nDim);
5701 continue;
5702 }
5703
5704 // Otherwise use current offset for the current element
5705 elementOffset[elementId] = offset;
5706
5707 // Increase offset based on element polynomial degree
5708 const MInt noNodesXD = m_elements.noNodesXD(elementId);
5709 offset += noNodesXD;
5710
5711 // Set number of nodes to use later and proceed with next element
5712 elementNodes[elementId] = noNodesXD;
5713 elementId++;
5714 }
5715
5716 // Determine local data array size
5717 // array size = #nodes of elements + (#cells - #elements) * default cell size
5718 // (cells without elements use polyDeg = initPolyDeg)
5719 const MInt localNoNodes = m_noTotalNodesXD + (grid().noInternalCells() - noElements) * ipow(m_initNoNodes1D, nDim);
5720
5721 // Determine offset and global number of nodes
5722 ParallelIo::size_type nodesOffset, globalNoNodes;
5723 ParallelIo::calcOffset(localNoNodes, &nodesOffset, &globalNoNodes, mpiComm());
5724
5725 // Grid file name and solver type
5726 parallelIo.setAttribute("DG", "solverType");
5727 if(m_sbpMode) {
5728 parallelIo.setAttribute((MInt)m_sbpMode, "sbpMode");
5729 }
5730 parallelIo.setAttribute(m_timeStep, "timeStep");
5731 parallelIo.setAttribute(m_time, "time");
5732
5733 // Define arrays in file
5734 // Polyomial degree
5735 parallelIo.defineArray(PIO_UCHAR, "polyDegs", grid().domainOffset(noDomains()));
5736 // Number of nodes in SBP mode
5737 if(m_sbpMode) {
5738 parallelIo.defineArray(PIO_UCHAR, "noNodes1D", grid().domainOffset(noDomains()));
5739 }
5740
5741
5742 // Get information about integration method and polynomial type
5743 MString dgIntegrationMethod = m_sbpMode ? "DG_INTEGRATE_GAUSS_LOBATTO" : "DG_INTEGRATE_GAUSS";
5744 dgIntegrationMethod =
5745 Context::getSolverProperty<MString>("dgIntegrationMethod", m_solverId, AT_, &dgIntegrationMethod);
5746 MString dgPolynomialType = "DG_POLY_LEGENDRE";
5747 dgPolynomialType = Context::getSolverProperty<MString>("dgPolynomialType", m_solverId, AT_, &dgPolynomialType);
5748
5749 // Add integration method & polynomial type to grid file as attributes
5750 parallelIo.setAttribute(dgIntegrationMethod, "dgIntegrationMethod", "polyDegs");
5751 parallelIo.setAttribute(dgPolynomialType, "dgPolynomialType", "polyDegs");
5752
5753 // Set counter to get correct variable names
5754 MInt varId = 0;
5755
5756 // Solution
5757 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
5758 const MString name = "variables" + to_string(varId++);
5759 parallelIo.defineArray(PIO_FLOAT, name, globalNoNodes);
5760 parallelIo.setAttribute(m_sysEqn.consVarNames(i), "name", name);
5761 }
5762
5763 // Node variables
5765 for(MInt i = 0; i < SysEqn::noNodeVars(); i++) {
5766 const MString name = "variables" + to_string(varId++);
5767 parallelIo.defineArray(PIO_FLOAT, name, globalNoNodes);
5768 parallelIo.setAttribute(m_sysEqn.nodeVarNames(i), "name", name);
5769 }
5770 }
5771
5772 // Time derivative
5774 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
5775 const MString name = "variables" + to_string(varId++);
5776 parallelIo.defineArray(PIO_FLOAT, name, globalNoNodes);
5777 parallelIo.setAttribute(m_sysEqn.consVarNames(i) + "_tDeriv", "name", name);
5778 }
5779 }
5780
5781 if(useSponge() && m_writeSpongeEta > 0) {
5782 const MString name = "variables" + to_string(varId);
5783 parallelIo.defineArray(PIO_FLOAT, name, globalNoNodes);
5784 parallelIo.setAttribute("spongeEta", "name", name);
5785 }
5786
5787 // Write data to disk
5788 // Create scratch space with polynomial degree and write it to file
5789 parallelIo.setOffset(grid().noInternalCells(), grid().domainOffset(domainId()));
5790 MUcharScratchSpace polyDegs(grid().noInternalCells(), FUN_, "polyDegs");
5791 fill_n(&polyDegs[0], grid().noInternalCells(), m_initPolyDeg);
5792 for(MInt elementId = 0; elementId < noElements; elementId++) {
5793 const MInt cellId = m_elements.cellId(elementId);
5794 polyDegs.p[cellId] = m_elements.polyDeg(elementId);
5795 }
5796 parallelIo.writeArray(polyDegs.begin(), "polyDegs");
5797
5798 // Create scratch space with noNodes and write it to file
5799 if(m_sbpMode) {
5800 parallelIo.setOffset(grid().noInternalCells(), grid().domainOffset(domainId()));
5801 MUcharScratchSpace noNodes1D(grid().noInternalCells(), FUN_, "noNodes1D");
5802 fill_n(&noNodes1D[0], grid().noInternalCells(), m_initNoNodes1D);
5803 for(MInt elementId = 0; elementId < noElements; elementId++) {
5804 const MInt cellId = m_elements.cellId(elementId);
5805 noNodes1D.p[cellId] = m_elements.noNodes1D(elementId);
5806 }
5807 parallelIo.writeArray(noNodes1D.begin(), "noNodes1D");
5808 }
5809
5810 varId = 0;
5811 parallelIo.setOffset(localNoNodes, nodesOffset);
5812
5813 // Solution
5814 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
5815 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
5816 fill(buffer.begin(), buffer.end(), 0.0);
5817 for(MInt e = 0; e < noElements; e++) {
5818 MFloat* const b = &buffer[elementOffset[e]];
5819 const MFloat* const v = &m_elements.variables(e) + i;
5820 for(MInt n = 0; n < elementNodes[e]; n++) {
5821 b[n] = v[n * m_sysEqn.noVars()];
5822 }
5823 }
5824 const MString name = "variables" + to_string(varId++);
5825 parallelIo.writeArray(&buffer[0], name);
5826 }
5827
5828 // Node variables
5830 for(MInt i = 0; i < SysEqn::noNodeVars(); i++) {
5831 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
5832 fill(buffer.begin(), buffer.end(), 0.0);
5833 for(MInt e = 0; e < noElements; e++) {
5834 MFloat* const b = &buffer[elementOffset[e]];
5835 const MFloat* const v = &m_elements.nodeVars(e) + i;
5836 for(MInt n = 0; n < elementNodes[e]; n++) {
5837 b[n] = v[n * SysEqn::noNodeVars()];
5838 }
5839 }
5840 const MString name = "variables" + to_string(varId++);
5841 parallelIo.writeArray(&buffer[0], name);
5842 }
5843 }
5844
5845 // Time derivative
5847 for(MInt i = 0; i < m_sysEqn.noVars(); i++) {
5848 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
5849 fill(buffer.begin(), buffer.end(), 0.0);
5850 for(MInt e = 0; e < noElements; e++) {
5851 MFloat* const b = &buffer[elementOffset[e]];
5852 const MFloat* const r = &m_elements.rightHandSide(e) + i;
5853 for(MInt n = 0; n < elementNodes[e]; n++) {
5854 b[n] = r[n * m_sysEqn.noVars()];
5855 }
5856 }
5857 const MString name = "variables" + to_string(varId++);
5858 parallelIo.writeArray(&buffer[0], name);
5859 }
5860 }
5861
5862 // SpongeEta
5863 if(useSponge() && m_writeSpongeEta > 0) {
5864 const MInt noSpongeElements = sponge().noSpongeElements();
5865 MFloatScratchSpace buffer(localNoNodes, AT_, "buffer");
5866 fill(buffer.begin(), buffer.end(), 0.0);
5867 for(MInt e = 0; e < noSpongeElements; e++) {
5868 MInt elementId = sponge().elementId(e);
5869 MFloat* const b = &buffer[elementOffset[elementId]];
5870 for(MInt n = 0; n < elementNodes[elementId]; n++) {
5871 b[n] = sponge().spongeEta(e, n);
5872 }
5873 }
5874 const MString name = "variables" + to_string(varId);
5875 parallelIo.writeArray(&buffer[0], name);
5876 }
5877 m_log << "done" << endl;
5878
5879 RECORD_TIMER_STOP(m_timers[Timers::SaveSolutionFile]);
5880 RECORD_TIMER_STOP(m_timers[Timers::IO]);
5881 RECORD_TIMER_STOP(m_timers[Timers::Accumulated]);
5882}
MBool m_saveNodeVariablesToSolutionFile

◆ saveSolverSolution()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::saveSolverSolution ( const MBool  forceOutput,
const MBool  finalTimeStep 
)
override

Definition at line 1814 of file dgcartesiansolver.cpp.

1814 {
1815 TRACE();
1816 CHECK_TIMERS_IO();
1817 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
1818 RECORD_TIMER_START(m_timers[Timers::MainLoopIO]);
1819
1820 // Write out solution in intervals, at the final time step, or if forced
1822 || ((m_finalTimeStep || finalTimeStep) && m_alwaysSaveFinalSolution) || forceOutput) {
1823 const MFloat tOutputStart = wallTime();
1825 const MFloat tOutputEnd = wallTime();
1826
1827 // Update output time so that inner loop does not consider it
1828 m_outputTime += tOutputEnd - tOutputStart;
1829 }
1830
1831 // Produce sampling data output
1832 m_pointData.save(finalTimeStep);
1833 m_surfaceData.save(finalTimeStep);
1834 m_volumeData.save(finalTimeStep);
1835 // Produce slice data output
1836 m_slice.save(finalTimeStep);
1837
1838 RECORD_TIMER_STOP(m_timers[Timers::MainLoopIO]);
1839 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
1840}
MInt m_solutionInterval
The number of timesteps before writing the next solution file.
Definition: solver.h:74

◆ setCellDataDlb() [1/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::setCellDataDlb ( const MInt  dataId,
const MFloat *const  data 
)
inlineoverride

Definition at line 442 of file dgcartesiansolver.h.

442{ setCellDataDlb_(dataId, data); };
void setCellDataDlb_(const MInt dataId, const dataType *const data)

◆ setCellDataDlb() [2/2]

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::setCellDataDlb ( const MInt  dataId,
const MInt *const  data 
)
inlineoverride

Definition at line 441 of file dgcartesiansolver.h.

441{ setCellDataDlb_(dataId, data); };

◆ setCellDataDlb_() [1/2]

template<MInt nDim, class SysEqn >
template<typename dataType >
void DgCartesianSolver< nDim, SysEqn >::setCellDataDlb_ ( const MInt  dataId,
const dataType *const  data 
)

◆ setCellDataDlb_() [2/2]

template<MInt nDim, class SysEqn >
template<typename DataType >
void DgCartesianSolver< nDim, SysEqn >::setCellDataDlb_ ( const MInt  dataId,
const DataType *const  data 
)
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de

This method sets the given data for all elements, e.g. the polynomial degree or the variables of all elements.

Parameters
[in]dataIdRequested data id.
[in]dataPointer to storage of data.

Definition at line 1137 of file dgcartesiansolver.h.

1137 {
1138 TRACE();
1139
1140 // Nothing to do if solver is not active
1141 if(!grid().isActive()) {
1142 return;
1143 }
1144
1145 const MInt noElements = m_elements.size();
1146
1147 if(dataId > -1 && dataId < noDgCartesianSolverCellData()) {
1148 // Skip if this is the wrong reinitialization stage
1150 return;
1151 }
1152
1153 // DG solver cell data
1154 switch(dataId) {
1156 std::copy_n(data, noElements, &m_elements.cellId(0));
1157 break;
1159 std::copy_n(data, noElements, &m_elements.polyDeg(0));
1160 break;
1162 std::copy_n(data, noElements, &m_elements.noNodes1D(0));
1163 break;
1165 MInt dataOffset = 0;
1166 for(MInt elementId = 0; elementId < noElements; elementId++) {
1167 // NOTE: assumes polynomial degree is already set!
1168 const MInt noNodesXD = m_elements.noNodesXD(elementId);
1169 const MInt dataSize = noNodesXD * SysEqn::noVars();
1170 std::copy_n(&data[dataOffset], dataSize, &m_elements.variables(elementId));
1171 dataOffset += dataSize;
1172 }
1173 break;
1174 }
1176 MInt dataOffset = 0;
1177 for(MInt elementId = 0; elementId < noElements; elementId++) {
1178 // NOTE: assumes polynomial degree is already set!
1179 const MInt noNodesXD = m_elements.noNodesXD(elementId);
1180 const MInt dataSize = noNodesXD * SysEqn::noNodeVars();
1181 std::copy_n(&data[dataOffset], dataSize, &m_elements.nodeVars(elementId));
1182 dataOffset += dataSize;
1183 }
1184 break;
1185 }
1186 default:
1187 TERMM(1, "Unknown data id.");
1188 break;
1189 }
1190 } else if(dataId >= noDgCartesianSolverCellData() && dataId < noCellDataDlb()) {
1191 // Note: this should happen after boundary conditions are created, skip if
1192 // this is the wrong reinitialization stage
1194 return;
1195 }
1196
1197 // Boundary condition cell data
1199 for(auto&& bc : m_boundaryConditions) {
1200 const MInt bcNoCellData = bc->noCellDataDlb();
1201 if(dataId >= offset && dataId < offset + bcNoCellData) {
1202 bc->setCellDataDlb(dataId - offset, data);
1203 break;
1204 }
1205 offset += bcNoCellData;
1206 }
1207 } else {
1208 // TODO labels:DG support exchange of CC mean vars data -> needs to be performed via gridcontroller!
1209 // Note: when setting the data for the first time the boundary conditions are not created yet
1210 // and the total cell data count does not match
1212 TERMM(1, "Invalid dataId: " + std::to_string(dataId));
1213 }
1214 }
1215}

◆ setCellWeights()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::setCellWeights ( MFloat solverCellWeight)
overridevirtual

Reimplemented from Solver.

Definition at line 9474 of file dgcartesiansolver.cpp.

9474 {
9475 TRACE();
9476 ASSERT(isActive(), "solver is not active");
9477
9478 const MInt noCells = grid().noInternalCells();
9479 const MInt noCellsGrid = grid().raw().treeb().size();
9480 const MInt noWeights = noLoadTypes();
9481 const MInt offset = solverId() * noCellsGrid;
9482
9483 std::vector<MFloat> weights(noWeights);
9484 std::fill(weights.begin(), weights.end(), m_weightPerNode);
9485
9486 for(MInt cellId = 0; cellId < noCells; cellId++) {
9487 const MInt gridCellId = grid().tree().solver2grid(cellId);
9488 solverCellWeight[offset + gridCellId] = getCellLoad(gridCellId, &weights[0]);
9489 }
9490}
MFloat getCellLoad(const MInt cellId, const MFloat *const weights) const override
Return the load of a single cell (given computational weights).

◆ setGlobalSolverVars()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::setGlobalSolverVars ( std::vector< MFloat > &  NotUsedglobalFloatVars,
std::vector< MInt > &  NotUsedglobalIdVars 
)
overridevirtual

Reimplemented from Solver.

Definition at line 9804 of file dgcartesiansolver.cpp.

9805 {
9806 TRACE();
9807
9808 m_time = globalFloatVars[0];
9809 m_dt = globalFloatVars[1];
9810
9811 m_timeStep = globalIntVars[0];
9812 m_firstTimeStep = globalIntVars[1];
9813 m_noAnalyzeTimeSteps = globalIntVars[2];
9814}

◆ setInputOutputProperties()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::setInputOutputProperties
private

Reads properties associated with input/output.

Author
Michael Schlottke
Date
October 2012

Definition at line 246 of file dgcartesiansolver.cpp.

◆ setNumericalProperties()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::setNumericalProperties
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2012-11-13

Definition at line 529 of file dgcartesiansolver.cpp.

◆ setSensors()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::setSensors ( std::vector< std::vector< MFloat > > &  NotUsedsensors,
std::vector< MFloat > &  NotUsedsensorWeight,
std::vector< std::bitset< 64 > > &  NotUsedsensorCellFlag,
std::vector< MInt > &  NotUsedsensorSolverId 
)
inlineoverride

Definition at line 293 of file dgcartesiansolver.h.

296 {};

◆ solutionStep()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::solutionStep
overridevirtual

Reimplemented from Solver.

Definition at line 1662 of file dgcartesiansolver.cpp.

1662 {
1663 TRACE();
1664 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
1665
1666 // Perform just a single Runge-Kutta step/stage
1668 // Update current Runge-Kutta stage
1670
1671 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
1672 // Return if time step is completed
1673 return (m_rkStage == 0);
1674}
void timeStepRk(const MFloat t, const MFloat dt, const MInt substep=-1)
Time integration using the five-stage fourth-order low-storage Runge-Kutta scheme as described in the...

◆ solverConverged()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::solverConverged ( )
inlinevirtual

Reimplemented from Solver.

Definition at line 276 of file dgcartesiansolver.h.

276{ return m_finalTimeStep; };

◆ sponge()

template<MInt nDim, class SysEqn >
DgSponge< nDim, SysEqn > & DgCartesianSolver< nDim, SysEqn >::sponge ( )
inlineprivate

Definition at line 360 of file dgcartesiansolver.h.

360{ return m_sponge; }

◆ startMpiSurfaceExchange()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::startMpiSurfaceExchange
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-07-24

Definition at line 7379 of file dgcartesiansolver.cpp.

7379 {
7380 TRACE();
7381
7382 // IMPORTANT:
7383 // If anything in this method is changed, please check if
7384 // updateNodeVariables() needs to be changed as well, since it contains more
7385 // or less the same code.
7386
7387 RECORD_TIMER_START(m_timers[Timers::SurfExchange]);
7388 RECORD_TIMER_START(m_timers[Timers::Accumulated]);
7389 RECORD_TIMER_START(m_timers[Timers::MPI]);
7390
7391 // Start receiving
7392 RECORD_TIMER_START(m_timers[Timers::MPIComm]);
7393 RECORD_TIMER_START(m_timers[Timers::SurfExchangeComm]);
7394 RECORD_TIMER_START(m_timers[Timers::SECommRecv]);
7397 m_mpiRecvRequestsOpen = true;
7398 }
7399 RECORD_TIMER_STOP(m_timers[Timers::SECommRecv]);
7400 RECORD_TIMER_STOP(m_timers[Timers::SurfExchangeComm]);
7401 RECORD_TIMER_STOP(m_timers[Timers::MPIComm]);
7402
7403 // Finish previous sending
7404 RECORD_TIMER_START(m_timers[Timers::MPIWait]);
7405 RECORD_TIMER_START(m_timers[Timers::SurfExchangeWait]);
7406 RECORD_TIMER_START(m_timers[Timers::SEWaitSend]);
7408 MPI_Waitall(m_noExchangeNghbrDomains, &m_sendRequests[0], MPI_STATUSES_IGNORE, AT_);
7409 m_mpiSendRequestsOpen = false;
7410 }
7411 RECORD_TIMER_STOP(m_timers[Timers::SEWaitSend]);
7412 RECORD_TIMER_STOP(m_timers[Timers::SurfExchangeWait]);
7413 RECORD_TIMER_STOP(m_timers[Timers::MPIWait]);
7414
7415 // Pack send buffers
7416#ifdef DG_USE_MPI_BUFFERS
7417 RECORD_TIMER_START(m_timers[Timers::MPICopy]);
7418 RECORD_TIMER_START(m_timers[Timers::SurfExchangeCopy]);
7419 RECORD_TIMER_START(m_timers[Timers::SECopySend]);
7420
7421 // Use max. polynomial degree to account for p-refined surfaces
7422 const MInt dataBlockSize = ipow(m_maxNoNodes1D, nDim - 1) * SysEqn::noVars();
7423
7424 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
7425 MInt size = 0;
7426 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
7427 const MInt srfcId = m_mpiSurfaces[i][j];
7428 const MInt sideId = m_surfaces.internalSideId(srfcId);
7429
7430 // Copy state data
7431 const MFloat* data = &m_surfaces.variables(srfcId, sideId);
7432 copy(data, data + dataBlockSize, &m_sendBuffers[i][size]);
7433 size += dataBlockSize;
7434 }
7435 ASSERT(size == static_cast<MInt>(m_sendBuffers[i].size()), "Data size does not match buffer size.");
7436 }
7437 RECORD_TIMER_STOP(m_timers[Timers::SECopySend]);
7438 RECORD_TIMER_STOP(m_timers[Timers::SurfExchangeCopy]);
7439 RECORD_TIMER_STOP(m_timers[Timers::MPICopy]);
7440#endif
7441
7442 // Start sending
7443 RECORD_TIMER_START(m_timers[Timers::MPIComm]);
7444 RECORD_TIMER_START(m_timers[Timers::SurfExchangeComm]);
7445 RECORD_TIMER_START(m_timers[Timers::SECommSend]);
7446 if(m_noExchangeNghbrDomains > 0) {
7448 }
7449 RECORD_TIMER_STOP(m_timers[Timers::SECommSend]);
7450 RECORD_TIMER_STOP(m_timers[Timers::SurfExchangeComm]);
7451 RECORD_TIMER_STOP(m_timers[Timers::MPIComm]);
7452
7453 m_mpiSendRequestsOpen = true;
7454
7455 RECORD_TIMER_STOP(m_timers[Timers::MPI]);
7456 RECORD_TIMER_STOP(m_timers[Timers::Accumulated]);
7457 RECORD_TIMER_STOP(m_timers[Timers::SurfExchange]);
7458}

◆ step()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::step ( const MFloat  externalDt = -std::numeric_limits<MFloat>::infinity(),
const MBool  substep = false 
)
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-10-19
Parameters
[in]externalDtExternal time step size to use for current time step.
[in]substepIndicator if only a single Runge-Kutta substep/stage should be performed.
Returns
True if this is the last time step, i.e. if the main loop should be terminated.

NOTE: can be removed once the transition to the unified run loop is finished

Definition at line 1416 of file dgcartesiansolver.cpp.

1416 {
1417 TRACE();
1418 TERMM(1, "deprecated");
1419
1420 // Abort if main loop not initialized
1421 if(!m_isInitMainLoop) {
1422 TERMM(1, "Main loop was not initialized.");
1423 }
1424
1425 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
1426
1427 startLoadTimer(AT_);
1428
1429 // Check if this is the first Runge-Kutta stage, i.e. start of new timestep
1430 if(m_rkStage == 0) {
1431 // Increment time step
1432 m_timeStep++;
1433
1434 // Calculate time step if it is not already set
1435 if(externalDt < 0.0) {
1436 // Calculate time step at first time step or for correct modulo
1438 m_dt = calcTimeStep();
1439 m_firstTimeStep = false;
1440 }
1441 } else {
1442 m_dt = externalDt;
1443 }
1444
1445 // Perform adaptive refinement if needed
1447 // Cancel open MPI (receive) requests
1450 }
1451 }
1452
1453 // Determine if this is the last time step and reset time step if necessary
1454 MBool finalTimeStep = false;
1455 if(m_finalTime - m_time - m_dt < 1.0E-10) {
1456 finalTimeStep = true;
1458 } else if(m_timeStep == m_timeSteps) {
1459 finalTimeStep = true;
1460 } else if(m_timeStep == std::max(m_restartTimeStep, 0) + m_timeSteps) {
1461 // TODO labels:DG @ansgar_unified for coupled combustion case, step() should not be used anymore by other
1462 // run loops!
1463 finalTimeStep = true;
1464 }
1465
1466 if(!substep) {
1467 // Run Runge-Kutta step
1469 // Reset current Runge-Kutta stage
1470 m_rkStage = 0;
1471 } else {
1472 // Perform just a single Runge-Kutta stage
1474 // Update current Runge-Kutta stage
1476 }
1477
1478 stopLoadTimer(AT_);
1479
1480 // Check if time step is completed and return if not
1481 if(m_rkStage != 0) {
1482 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
1483 return finalTimeStep;
1484 }
1485
1487
1488 // Time step completed
1489 // Update physical time and counters
1490 m_time += m_dt;
1492
1493 // Write out solution in intervals
1494 if((m_solutionInterval > 0 && m_timeStep % m_solutionInterval == 0) || (finalTimeStep && m_alwaysSaveFinalSolution)) {
1495 RECORD_TIMER_START(m_timers[Timers::MainLoopIO]);
1496
1497 const MFloat tOutputStart = wallTime();
1499 const MFloat tOutputEnd = wallTime();
1500
1501 // Update output time so that inner loop does not consider it
1502 m_outputTime += tOutputEnd - tOutputStart;
1503
1504 RECORD_TIMER_STOP(m_timers[Timers::MainLoopIO]);
1505 }
1506
1507 // Write out restart file in intervals
1508 if((m_restartInterval > 0 && m_timeStep % m_restartInterval == 0) || (finalTimeStep && m_alwaysSaveFinalRestart)) {
1509 RECORD_TIMER_START(m_timers[Timers::MainLoopIO]);
1510
1511 const MFloat tOutputStart = wallTime();
1513 const MFloat tOutputEnd = wallTime();
1514
1515 // Update output time so that inner loop does not consider it
1516 m_outputTime += tOutputEnd - tOutputStart;
1517
1518 RECORD_TIMER_STOP(m_timers[Timers::MainLoopIO]);
1519 }
1520
1521 // Check regularly if job is about to end
1523 // synchronize ranks (prevent deadlocks)
1524 MBool writeEndAutoSave = false;
1525 if(isMpiRoot()
1527 <= chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count()) {
1528 writeEndAutoSave = true;
1529 }
1530 MPI_Bcast(&writeEndAutoSave, 1, MPI_C_BOOL, 0, mpiComm(), AT_, "writeEndAutoSave");
1531 // Write out restart file if job is about to end
1532 if(writeEndAutoSave) {
1533 RECORD_TIMER_START(m_timers[Timers::MainLoopIO]);
1534
1535 const MFloat tOutputStart = wallTime();
1537 time_t now =
1538 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
1539 m_log << "Finished end auto save at " << std::ctime(&now) << " (in Unix time: " << now << ")." << endl;
1540 time_t jobEndTime = m_endAutoSaveTime + m_noMinutesEndAutoSave * 60;
1541 m_log << "Job will end at " << std::ctime(&jobEndTime) << " (in Unix time: " << jobEndTime << ")." << endl;
1542
1543 m_endAutoSaveWritten = true;
1544
1545 const MFloat tOutputEnd = wallTime();
1546
1547 // Update output time so that inner loop does not consider it
1548 m_outputTime += tOutputEnd - tOutputStart;
1549
1550 RECORD_TIMER_STOP(m_timers[Timers::MainLoopIO]);
1551 }
1552 }
1553
1554 RECORD_TIMER_START(m_timers[Timers::MainLoopIO]);
1555 // Produce sampling data output
1556 m_pointData.save(finalTimeStep);
1557 m_surfaceData.save(finalTimeStep);
1558 m_volumeData.save(finalTimeStep);
1559 // Produce slice data output
1560 m_slice.save(finalTimeStep);
1561 RECORD_TIMER_STOP(m_timers[Timers::MainLoopIO]);
1562
1563 // Analyze error norms and print info to user
1564 if((m_analysisInterval > 0 && m_timeStep % m_analysisInterval == 0) || (finalTimeStep)) {
1565 RECORD_TIMER_START(m_timers[Timers::Analysis]);
1566
1567 const MFloat timeDiff = wallTime() - m_analyzeTimeStart - m_outputTime;
1568 const MFloat runTimeRelative = timeDiff * noDomains() / m_noAnalyzeTimeSteps / m_statGlobalNoActiveDOFs;
1569 const MFloat runTimeTotal = wallTime() - m_loopTimeStart;
1570
1571 analyzeTimeStep(m_time, runTimeRelative, runTimeTotal, m_timeStep, m_dt);
1572 if(finalTimeStep && isMpiRoot()) {
1573 cout << endl;
1574 cout << "----------------------------------------"
1575 << "----------------------------------------" << endl;
1576 cout << " MAIA finished. Final time: " << m_time << " Time steps: " << m_timeStep << endl;
1577 cout << "----------------------------------------"
1578 << "----------------------------------------" << endl;
1579 }
1580
1581 // Reset time + counters
1583 m_outputTime = 0.0;
1585
1586 RECORD_TIMER_STOP(m_timers[Timers::Analysis]);
1587 }
1588 /* } else if (m_aliveInterval > 0 && m_timeStep % m_aliveInterval == 0 && isMpiRoot()) { */
1589 /* // Calculate total run time for printing */
1590 /* const MFloat runTimeTotal = wallTime() - m_loopTimeStart; */
1591
1592 /* // Print out processing information to user */
1593 /* printf("#t/s: %8d | dt: %.4e | Sim. time: %.4e | Run time: %.4e s\n", m_timeStep, m_dt,
1594 * m_time, */
1595 /* runTimeTotal); */
1596 /* } */
1597
1598 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
1599
1601
1602 return finalTimeStep;
1603}
virtual void saveRestartFile()
Saves a file to disk with all information that is necessary to restart the calculations from here.
void startLoadTimer(const MString name)
Definition: solver.h:293
void enableDlbTimers()
Definition: solver.h:283
void stopLoadTimer(const MString &name)
Definition: solver.h:295
void disableDlbTimers()
Definition: solver.h:289
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Bcast

◆ subTimeStepRk()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::subTimeStepRk ( const MFloat  dt,
const MInt  stage,
const MInt  totalSize,
const MFloat *const  rhs,
MFloat *const  variables,
MFloat *const  timeIntStorage 
)
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-12-13
Parameters
[in]dtCurrent time step size.
[in]stageRunge-Kutta stage to perform.
[in]totalSizeTotal data length.
[in]rhsPointer to right hand side, i.e. time derivative.
[in]variablesPointer to variables.
[in]timeIntStoragePointer to time integration storage.

Definition at line 7733 of file dgcartesiansolver.cpp.

7738 {
7739 TRACE();
7740
7741 // Get pointers for a more concise code
7742 MFloat* const p = variables;
7743 MFloat* const k = timeIntStorage;
7744
7745 // Calculate auxiliary variables to save on operations
7746 MFloat bDt = -1.0;
7747 bDt = m_timeIntegrationCoefficientsB[stage] * dt;
7748
7749 // Stage 0
7750 if(stage == 0) {
7751#ifdef _OPENMP
7752#pragma omp parallel for
7753#endif
7754 for(MInt i = 0; i < totalSize; i++) {
7755 k[i] = rhs[i];
7756 p[i] += k[i] * bDt;
7757 }
7758 } else {
7759 // Stage 1-End
7760#ifdef _OPENMP
7761#pragma omp parallel for
7762#endif
7763 for(MInt i = 0; i < totalSize; i++) {
7764 k[i] = rhs[i] - k[i] * m_timeIntegrationCoefficientsA[stage];
7765 p[i] += k[i] * bDt;
7766 }
7767 }
7768}
std::vector< MFloat > m_timeIntegrationCoefficientsB
std::vector< MFloat > m_timeIntegrationCoefficientsA

◆ swapProxy()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::swapProxy ( const MInt  MInt,
const MInt  MInt 
)
inlinevirtual

Reimplemented from Solver.

Definition at line 290 of file dgcartesiansolver.h.

290{ grid().swapGridIds(cellId0, cellId1); }

◆ time()

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::time ( ) const
inlineoverridevirtual

Implements Solver.

Definition at line 111 of file dgcartesiansolver.h.

111{ return m_time; }

◆ timeStepRk()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::timeStepRk ( const MFloat  t,
const MFloat  dt,
const MInt  substep = -1 
)
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2013-04-26
Parameters
[in]tCurrent physical time (needed for boundary conditions etc.).
[in]dtCurrent time step size.
[in]substepPerform only the specified Runge-Kutta substep/stage.

The 'substep' option allows to perform only a single Runge-Kutta substep, which is necessary for interleaving the Runge-Kutta stages in a coupled simulation to avoid idle time. By default the complete timestep is performed.

Definition at line 7675 of file dgcartesiansolver.cpp.

7675 {
7676 TRACE();
7677
7678 RECORD_TIMER_START(m_timers[Timers::RungeKuttaStep]);
7679
7680 // Save total data length
7681 const MInt totalSize = m_internalDataSize;
7682
7683 // General Runge-Kutta time step calculation
7684 for(MInt s = 0; s < m_noRkStages; s++) {
7685 // Perform only the given single Runge-Kutta substep if specified
7686 if(substep != -1 && s != substep) {
7687 continue;
7688 }
7689
7691
7692 RECORD_TIMER_START(m_timers[Timers::TimeInt]);
7693 subTimeStepRk(dt, s, totalSize, &m_elements.rightHandSide(0), &m_elements.variables(0),
7695 RECORD_TIMER_STOP(m_timers[Timers::TimeInt]);
7696
7697
7698 // Determine if this is the final Runge-Kutta stage before an adaptation
7699 // time step (error estimates are calculated with the current solution on
7700 // all surfaces, so prevent overwriting the surface states if split MPI
7701 // communication is active)
7702 const MBool lastRkStage = (s == (m_noRkStages - 1));
7703 const MBool adaptationTimeStep = (lastRkStage && isAdaptationTimeStep(m_timeStep + 1));
7704
7705 // If multiphysics-optimized parallelization is used, prolong and start
7706 // tranmitting
7707 if(g_splitMpiComm && !adaptationTimeStep) {
7708 RECORD_TIMER_START(m_timers[Timers::TimeDeriv]);
7712 RECORD_TIMER_STOP(m_timers[Timers::TimeDeriv]);
7713 }
7714 }
7715
7716
7717 RECORD_TIMER_STOP(m_timers[Timers::RungeKuttaStep]);
7718}
void calcDgTimeDerivative(const MFloat t, const MFloat tStage)
Main routine to calculate the discontinuous Galerkin time derivative. After this method was called,...
void subTimeStepRk(const MFloat dt, const MInt stage, const MInt totalSize, const MFloat *const rhs, MFloat *const variables, MFloat *const timeIntStorage)
Perform one Runge-Kutta substep on the given elements.
std::vector< MFloat > m_timeIntegrationCoefficientsC

◆ updateNodeVariables()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::updateNodeVariables
private
Author
Michael Schlottke (mic) mic@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2015-09-24

This method executes the following three steps:

  • prolong all node variables from the elements to the surfaces
  • apply the forward projection algorithm to the node variables
  • exchange the node variable information for MPI surfaces

This method only needs to be called once after a change to the node variables.

Definition at line 4565 of file dgcartesiansolver.cpp.

4565 {
4566 TRACE();
4567
4568 m_log << "Update node variable data on surfaces... ";
4569
4570 const MInt* const polyDegs = &m_elements.polyDeg(0);
4571 const MInt* const noNodes = &m_elements.noNodes1D(0);
4572 const MInt* const surfaceIds = &m_elements.surfaceIds(0, 0);
4573 const MInt noElements = m_elements.size();
4574
4576 // Prolong to surfaces
4578
4579 // IMPORTANT:
4580 // If anything in this part of the method is changed, please check if
4581 // prolongToSurfaces() needs to be changed as well, since it contains more
4582 // or less the same code.
4583 using namespace dg::interpolation;
4584
4586#ifdef _OPENMP
4587#pragma omp parallel for
4588#endif
4589 // Loop over all elements in given range
4590 for(MInt elementId = 0; elementId < noElements; elementId++) {
4591 const MInt surfaceIdOffset = elementId * 2 * nDim;
4592 const MInt polyDeg = polyDegs[elementId];
4593 const MInt noNodes1D = noNodes[elementId];
4594 const DgInterpolation& interp = m_interpolation[polyDeg][noNodes1D];
4595
4596 // Extrapolate the solution to each surface on the faces
4597 for(MInt dir = 0; dir < 2 * nDim; dir++) {
4598 const MInt srfcId = surfaceIds[surfaceIdOffset + dir];
4599 const MInt side = 1 - dir % 2;
4600
4601 MFloat* src = &m_elements.nodeVars(elementId);
4602 MFloat* dest = &m_surfaces.nodeVars(srfcId, side);
4603 prolongToFaceGauss<nDim, SysEqn::noNodeVars()>(src, dir, noNodes1D, &interp.m_LFace[0][0],
4604 &interp.m_LFace[1][0], dest);
4605 }
4606 }
4608#ifdef _OPENMP
4609#pragma omp parallel for
4610#endif
4611 // Loop over all elements in given range
4612 for(MInt elementId = 0; elementId < noElements; elementId++) {
4613 const MInt surfaceIdOffset = elementId * 2 * nDim;
4614 const MInt noNodes1D = noNodes[elementId];
4615
4616 // Extrapolate the solution to each surface on the faces
4617 for(MInt dir = 0; dir < 2 * nDim; dir++) {
4618 const MInt srfcId = surfaceIds[surfaceIdOffset + dir];
4619 const MInt side = 1 - dir % 2;
4620
4621 MFloat* src = &m_elements.nodeVars(elementId);
4622 MFloat* dest = &m_surfaces.nodeVars(srfcId, side);
4623 prolongToFaceGaussLobatto<nDim, SysEqn::noNodeVars()>(src, dir, noNodes1D, dest);
4624 }
4625 }
4626 }
4627
4629 // Forward projection for hp-refined surfaces
4631
4632 // IMPORTANT:
4633 // If anything in this part of the method is changed, please check if
4634 // applyForwardProjection() needs to be changed as well, since it contains
4635 // more or less the same code.
4636
4637 const MInt noVars = SysEqn::noNodeVars();
4638 const MInt maxNoNodes1D = m_maxNoNodes1D;
4639 const MInt maxNoNodes1D3 = (nDim == 3) ? maxNoNodes1D : 1;
4640 const MInt noHElements = m_helements.size();
4641 const MInt noDirs = 2 * nDim;
4642 const MInt noSurfs = 2 * (nDim - 1);
4643
4644 // Copy prolong results to h-refined surfaces (the prolong step stored its
4645 // results only in the first refined surface)
4646 if(noHElements > 0) {
4647#ifdef _OPENMP
4648#pragma omp parallel for
4649#endif
4650 for(MInt hElementId = 0; hElementId < noHElements; hElementId++) {
4651 const MInt coarseElementId = m_helements.elementId(hElementId);
4652 for(MInt dir = 0; dir < noDirs; dir++) {
4653 const MInt coarseSrfcId = m_elements.surfaceIds(coarseElementId, dir);
4654 for(MInt pos = 0; pos < noSurfs; pos++) {
4655 const MInt hSrfcId = m_helements.hrefSurfaceIds(hElementId, dir, pos);
4656 const MInt side = 1 - dir % 2;
4657
4658 // Skip if this surface does not exist
4659 if(hSrfcId == -1) {
4660 continue;
4661 }
4662
4663 // Copy values of prolong step to all remaining refined surfaces
4664 if(coarseSrfcId != hSrfcId) {
4665 const MInt noNodes1D = noNodes[coarseElementId];
4666 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
4667 const MInt noNodesXD = noNodes1D * noNodes1D3;
4668
4669 // Copy nodeVars from prolong step to surface
4670 copy_n(&m_surfaces.nodeVars(coarseSrfcId, side),
4671 noNodesXD * SysEqn::noNodeVars(),
4672 &m_surfaces.nodeVars(hSrfcId, side));
4673 }
4674 }
4675 }
4676 }
4677 }
4678
4679 // Apply mortar projection
4680 MFloatTensor projected(maxNoNodes1D, maxNoNodes1D3, noVars);
4681
4682 // Apply projection to h- (and possibly p-)refined surfaces
4683 if(noHElements > 0) {
4684#ifdef _OPENMP
4685#pragma omp parallel for firstprivate(projected)
4686#endif
4687 for(MInt hElementId = 0; hElementId < noHElements; hElementId++) {
4688 for(MInt dir = 0; dir < noDirs; dir++) {
4689 for(MInt pos = 0; pos < noSurfs; pos++) {
4690 const MInt hSrfcId = m_helements.hrefSurfaceIds(hElementId, dir, pos);
4691 const MInt side = 1 - dir % 2;
4692
4693 // Skip if this surface does not exist
4694 if(hSrfcId == -1) {
4695 continue;
4696 }
4697
4698 const MInt surfaceNoNodes1D = m_surfaces.noNodes1D(hSrfcId);
4699 const MInt surfaceNoNodes1D3 = (nDim == 3) ? surfaceNoNodes1D : 1;
4700 const MInt size = surfaceNoNodes1D * surfaceNoNodes1D3 * noVars;
4701
4702 // Project the coarse side to the surface
4703 calcMortarProjection<dg::mortar::forward, SysEqn::noNodeVars()>(
4704 hSrfcId, dir, &m_surfaces.nodeVars(hSrfcId, side), &projected[0], m_elements, m_surfaces);
4705
4706 // Copy results of projection back to surface
4707 copy_n(&projected[0], size, &m_surfaces.nodeVars(hSrfcId, side));
4708 }
4709 }
4710 }
4711 }
4712
4713 // Apply projection to pure p-refined surfaces
4714#ifdef _OPENMP
4715#pragma omp parallel for firstprivate(projected)
4716#endif
4717 for(MInt elementId = 0; elementId < noElements; elementId++) {
4718 const MInt surfaceIdOffset = elementId * 2 * nDim;
4719
4720 for(MInt dir = 0; dir < 2 * nDim; dir++) {
4721 // Define auxiliary variables for better readability
4722 const MInt srfcId = surfaceIds[surfaceIdOffset + dir];
4723
4724 // Skip boundary surfaces as they are *always* conforming
4725 if(srfcId < m_innerSurfacesOffset) {
4726 continue;
4727 }
4728
4729 const MInt surfacePolyDeg = m_surfaces.polyDeg(srfcId);
4730 const MInt elementPolyDeg = m_elements.polyDeg(elementId);
4731 const MInt side = 1 - dir % 2;
4732 const MInt surfaceNoNodes1D = m_surfaces.noNodes1D(srfcId);
4733 const MInt surfaceNoNodes1D3 = (nDim == 3) ? surfaceNoNodes1D : 1;
4734 const MInt size = surfaceNoNodes1D * surfaceNoNodes1D3 * noVars;
4735
4736 // Skip h-refined surfaces since they have been already projected
4737 if(m_surfaces.fineCellId(srfcId) != -1 && m_surfaces.fineCellId(srfcId) != m_elements.cellId(elementId)) {
4738 continue;
4739 }
4740
4741 // Calculate forward projection for lower polyDeg elements
4742 if(surfacePolyDeg > elementPolyDeg) {
4743 // Calculate forward projection
4744 calcMortarProjection<dg::mortar::forward, SysEqn::noNodeVars()>(srfcId, dir, &m_surfaces.nodeVars(srfcId, side),
4745 &projected[0], m_elements, m_surfaces);
4746
4747 // Copy results of projection back to surface
4748 copy_n(&projected[0], size, &m_surfaces.nodeVars(srfcId, side));
4749 }
4750 }
4751 }
4752
4754 // MPI exchange
4756
4757 // Exit here if there is nothing to communicate
4758 if(!hasMpiExchange()) {
4759 return;
4760 }
4761
4762 // IMPORTANT:
4763 // If anything in this part of the method is changed, please check if
4764 // initMpiExchange()/startMpiSurfaceExchange()/finishMpiSurfaceExchange()
4765 // needs to be changed as well, since they contain more or less the same code.
4766
4767 // Set up buffers and requests
4768 vector<vector<MFloat>> sendBuffers(m_noExchangeNghbrDomains);
4769 vector<vector<MFloat>> recvBuffers(m_noExchangeNghbrDomains);
4770 const MInt dataBlockSize = ipow(m_maxNoNodes1D, nDim - 1) * SysEqn::noNodeVars();
4771 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4772 const MInt size = m_mpiSurfaces[i].size() * dataBlockSize;
4773 sendBuffers[i].resize(size);
4774 recvBuffers[i].resize(size);
4775 }
4776 ScratchSpace<MPI_Request> sendRequests(m_noExchangeNghbrDomains, AT_, "sendRequests");
4777 fill(sendRequests.begin(), sendRequests.end(), MPI_REQUEST_NULL);
4778 ScratchSpace<MPI_Request> recvRequests(m_noExchangeNghbrDomains, AT_, "recvRequests");
4779 fill(recvRequests.begin(), recvRequests.end(), MPI_REQUEST_NULL);
4780
4781 // Start receiving
4782 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4783 MPI_Irecv(&recvBuffers[i][0], recvBuffers[i].size(), type_traits<MFloat>::mpiType(), m_exchangeNghbrDomains[i],
4784 m_exchangeNghbrDomains[i], mpiComm(), &recvRequests[i], AT_, "recvBuffers[i][0]");
4785 }
4786
4787 // Fill send buffers
4788 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4789 MInt size = 0;
4790 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
4791 const MInt srfcId = m_mpiSurfaces[i][j];
4792 const MInt sideId = m_surfaces.internalSideId(srfcId);
4793
4794 // Copy nodeVars data
4795 const MFloat* data = &m_surfaces.nodeVars(srfcId, sideId);
4796 copy_n(data, dataBlockSize, &sendBuffers[i][size]);
4797 size += dataBlockSize;
4798 }
4799 ASSERT(size == static_cast<MInt>(sendBuffers[i].size()), "Data size does not match buffer size.");
4800 }
4801
4802 // Start sending
4803 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4804 MPI_Isend(&sendBuffers[i][0], sendBuffers[i].size(), type_traits<MFloat>::mpiType(), m_exchangeNghbrDomains[i],
4805 domainId(), mpiComm(), &sendRequests[i], AT_, "sendBuffers[i][0]");
4806 }
4807
4808 // Finish receiving
4809 MPI_Waitall(m_noExchangeNghbrDomains, &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
4810
4811 // Unpack receive buffers
4812 for(MInt i = 0; i < m_noExchangeNghbrDomains; i++) {
4813 MInt size = 0;
4814 for(vector<MInt>::size_type j = 0; j < m_mpiSurfaces[i].size(); j++) {
4815 const MInt srfcId = m_mpiSurfaces[i][j];
4816 const MInt sideId = 1 - m_surfaces.internalSideId(srfcId);
4817
4818 // Copy nodeVars data
4819 MFloat* data = &m_surfaces.nodeVars(srfcId, sideId);
4820 std::copy_n(&recvBuffers[i][size], dataBlockSize, data);
4821 size += dataBlockSize;
4822 }
4823 ASSERT(size == static_cast<MInt>(recvBuffers[i].size()), "Data size does not match buffer size.");
4824 }
4825
4826 // Finish sending
4827 MPI_Waitall(m_noExchangeNghbrDomains, &sendRequests[0], MPI_STATUSES_IGNORE, AT_);
4828
4829 m_log << "done" << endl;
4830}

◆ updateNodeVariablesSingleElement()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::updateNodeVariablesSingleElement ( const MInt  elementId,
const MInt  extendDir,
MIntTensor  hForwardSurfaceId,
MIntTensor  hReverseSurfaceId,
std::vector< MBool > &  elementUpdated,
std::vector< MInt > &  mpiSurfaceSendSize,
MBool noMoreUpdates 
)
private
Author
Patrick Antony (patrick) patri.nosp@m.ck@a.nosp@m.ia.rw.nosp@m.th-a.nosp@m.achen.nosp@m..de
Date
2019-04-29

This method sets the nodeVars of an element to values on the surface opposite to extendDir. It then updates the nodeVars on the surface in extendDir of the element, and notes the surfaces buffer size if it is on a domain boundary. If the element is h-refined, it also calls itself for the child elements.

Definition at line 5186 of file dgcartesiansolver.cpp.

5192 {
5193 // Precompute variables.
5194 const MInt* const noNodes1D = &m_elements.noNodes1D(0);
5195 const MInt* const surfaceNoNodes1D = &m_surfaces.noNodes1D(0);
5196 const MInt extendSide = extendDir % 2;
5197 const MInt extendDimension = (extendDir - extendSide) / 2;
5198 const MInt donorDir = 2 * extendDimension + (1 - extendSide);
5199 const MInt noVars = max(SysEqn::noNodeVars(), 1);
5200 const MInt noSurfs = 2 * (nDim - 1);
5201 const MInt maxNoNodes1D = noNodes1D[elementId];
5202 const MInt maxNoNodes1D3 = (nDim == 3) ? maxNoNodes1D : 1;
5203 MInt extendDomainId;
5204 MPI_Comm_rank(mpiComm(), &extendDomainId);
5205 // Set up Ids and data tensors.
5206 const MInt donorSrfcId = m_elements.surfaceIds(elementId, donorDir);
5207 const MInt recvSrfcId = m_elements.surfaceIds(elementId, extendDir);
5208 MFloatTensor nodeVars(&m_elements.nodeVars(elementId), maxNoNodes1D, maxNoNodes1D, maxNoNodes1D3, noVars);
5209 const MInt noNodesSecondSurfDim = extendDimension == 2 ? maxNoNodes1D : maxNoNodes1D3;
5210 MFloatTensor elemNodeVarsSlice(maxNoNodes1D, noNodesSecondSurfDim, noVars);
5211 /* const MFloatTensor donorNodeVars(&m_surfaces.nodeVars(donorSrfcId, 1 - extendSide), */
5212 /* maxNoNodes1D, noNodesSecondSurfDim, noVars); */
5213 MFloatTensor recvSurfaceNodeVarsMSide(&m_surfaces.nodeVars(recvSrfcId, extendSide), maxNoNodes1D,
5214 noNodesSecondSurfDim, noVars);
5215 MFloatTensor recvSurfaceNodeVarsPSide(&m_surfaces.nodeVars(recvSrfcId, 1 - extendSide), maxNoNodes1D,
5216 noNodesSecondSurfDim, noVars);
5217
5218 // Update receiver cell and its receiver side surface.
5219 const MBool pRefinedDonorSide = m_surfaces.polyDeg(donorSrfcId) > m_elements.polyDeg(elementId);
5220 const MBool pRefinedRecvSide = m_surfaces.polyDeg(recvSrfcId) > m_elements.polyDeg(elementId);
5221 const MBool srfcIsForwardHref = hForwardSurfaceId(donorSrfcId, 0) > -1;
5222
5223 // Get default node variables for those variables that are not extended
5224 MFloatScratchSpace defaultNodeVars(SysEqn::noNodeVars(), AT_, "defaultNodeVars");
5225 m_sysEqn.getDefaultNodeVars(defaultNodeVars.getPointer());
5226 // Store if variables needs to be extended
5227 MBoolScratchSpace extendNodeVar(SysEqn::noNodeVars(), AT_, "extendNodeVars");
5228 for(MInt iVars = 0; iVars < noVars; iVars++) {
5229 extendNodeVar[iVars] = m_sysEqn.extendNodeVar(iVars);
5230 }
5231
5232 // This abuses the fact that the coarse elements surface and the main position's fine surface
5233 // share the srfcID
5234 MBool srfcIsReverseHrefTemp = false;
5235 for(MInt pos = 0; pos < noSurfs; pos++) {
5236 if(hReverseSurfaceId(donorSrfcId, pos) > -1) {
5237 srfcIsReverseHrefTemp = true;
5238 }
5239 }
5240 const MBool srfcIsReverseHref = srfcIsReverseHrefTemp;
5241 MBool srfcIsMainPosTemp = false;
5242 for(MInt pos = 0; pos < noSurfs; pos++) {
5243 if(hReverseSurfaceId(donorSrfcId, pos) == donorSrfcId) {
5244 srfcIsMainPosTemp = true;
5245 }
5246 }
5247 const MBool srfcIsMainPos = srfcIsMainPosTemp;
5248 if(srfcIsForwardHref) { // One donor element, multiple recv/updatee elements
5249 // Call update for children, then proceed to update self.
5250 for(MInt pos = 1; pos < noSurfs; pos++) {
5251 const MInt hSrfcId = hForwardSurfaceId(donorSrfcId, pos);
5252 const MInt hElemId = m_surfaces.nghbrElementIds(hSrfcId, extendSide);
5253 updateNodeVariablesSingleElement(hElemId, extendDir, hForwardSurfaceId, hReverseSurfaceId, elementUpdated,
5254 mpiSurfaceSendSize, noMoreUpdates);
5255 }
5256 }
5257 // h(p) is excluded here, because h already includes p refinement(if necessary)
5258 if(!srfcIsReverseHref) { // one donor/one recv
5259 // project/copy from donorVars(fine surface) to element(coarse).
5260 if(pRefinedDonorSide) { // p projection required
5261 const MInt maxNoNodes1DFine = surfaceNoNodes1D[donorSrfcId];
5262 const MInt maxNoNodes1D3Fine = nDim == 3 ? maxNoNodes1DFine : 1;
5263 const MInt noNodesSecondSurfDimFine = extendDimension == 2 ? maxNoNodes1DFine : maxNoNodes1D3Fine;
5264 // P-ref mortar projection projects onto same size buffers (high degree),
5265 // even though lower p'nomial degree has fewer dofs.
5266 MFloatTensor projectedRight(maxNoNodes1DFine, noNodesSecondSurfDimFine, noVars);
5267 calcMortarProjection<dg::mortar::reverse, SysEqn::noNodeVars()>(donorSrfcId, donorDir,
5268 &m_surfaces.nodeVars(donorSrfcId, 1 - extendSide),
5269 &projectedRight[0], m_elements, m_surfaces);
5270 for(MInt a = 0; a < maxNoNodes1D; ++a) {
5271 for(MInt b = 0; b < maxNoNodes1D3; ++b) {
5272 for(MInt iVars = 0; iVars < noVars; iVars++) {
5273 elemNodeVarsSlice(a, b, iVars) = projectedRight(a, b, iVars);
5274 }
5275 }
5276 }
5277 } else { // no p projection required
5278 copy_n(&m_surfaces.nodeVars(donorSrfcId, 1 - extendSide),
5279 maxNoNodes1D * noNodesSecondSurfDim * noVars,
5280 &elemNodeVarsSlice[0]);
5281 }
5282 // copy nodeVars to element
5283 for(MInt a = 0; a < maxNoNodes1D; ++a) {
5284 for(MInt b = 0; b < maxNoNodes1D; ++b) {
5285 for(MInt c = 0; c < maxNoNodes1D3; ++c) {
5286 // determine which iterators are need for the surface-like elemNodeVarsSlice
5287 const MInt iNodes2D = extendDimension == 0 ? b : a;
5288 const MInt iNodes3D = extendDimension == 2 ? b : c;
5289 for(MInt iVars = 0; iVars < noVars; iVars++) {
5290 nodeVars(a, b, c, iVars) =
5291 (extendNodeVar[iVars]) ? elemNodeVarsSlice(iNodes2D, iNodes3D, iVars) : defaultNodeVars(iVars);
5292 }
5293 }
5294 }
5295 }
5296 // Mark element as updated.
5297 elementUpdated[elementId] = true;
5298 noMoreUpdates = false;
5299 // Copy from elem(coarse) and map to recvSurf(fine)
5300 if(pRefinedRecvSide) {
5301 // Set up projection to next surface.
5302 // Skip h-refined surfaces, as they will be handled separately.
5303 if(hForwardSurfaceId(recvSrfcId, 0) <= 0) {
5304 const MInt maxNoNodes1DSurf = surfaceNoNodes1D[recvSrfcId];
5305 const MInt maxNoNodes1D3Surf = nDim == 3 ? maxNoNodes1DSurf : 1;
5306 const MInt noNodesSecondRefSurfDim = extendDimension == 2 ? maxNoNodes1DSurf : maxNoNodes1D3Surf;
5307 MFloatTensor projected(maxNoNodes1DSurf, noNodesSecondRefSurfDim, noVars);
5308 // Project data to next surface.
5309 calcMortarProjection<dg::mortar::forward, SysEqn::noNodeVars()>(
5310 recvSrfcId, extendDir, &m_surfaces.nodeVars(donorSrfcId, 1 - extendSide), &projected[0], m_elements,
5311 m_surfaces);
5312 // Update next surface(both sides).
5313 copy_n(&projected[0],
5314 maxNoNodes1DSurf * noNodesSecondRefSurfDim * noVars,
5315 &m_surfaces.nodeVars(recvSrfcId, extendSide));
5316 copy_n(&projected[0],
5317 maxNoNodes1DSurf * noNodesSecondRefSurfDim * noVars,
5318 &m_surfaces.nodeVars(recvSrfcId, 1 - extendSide));
5319 // Mark recv surface for mpi exchange if on domain border.
5320 if(recvSrfcId >= m_mpiSurfacesOffset) {
5321 mpiSurfaceSendSize[recvSrfcId] = maxNoNodes1DSurf * maxNoNodes1D3Surf * SysEqn::noNodeVars();
5322 }
5323 }
5324 } else { // no projection needed, just copy to both sides of recv surface
5325 copy_n(&elemNodeVarsSlice[0], maxNoNodes1D * noNodesSecondSurfDim * noVars, &recvSurfaceNodeVarsMSide[0]);
5326 copy_n(&elemNodeVarsSlice[0], maxNoNodes1D * noNodesSecondSurfDim * noVars, &recvSurfaceNodeVarsPSide[0]);
5327 // Mark recv surface for mpi exchange if on domain border.
5328 if(recvSrfcId >= m_mpiSurfacesOffset) {
5329 mpiSurfaceSendSize[recvSrfcId] = maxNoNodes1D * maxNoNodes1D3 * SysEqn::noNodeVars();
5330 }
5331 }
5332 }
5333 if(srfcIsReverseHref && srfcIsMainPos) { // multiple donors, one receive element
5334 // Check if all four pos have updated means.
5335 MBool allDonorsHaveUpdatedMeans = true;
5336 for(MInt pos = 0; pos < noSurfs; pos++) {
5337 const MInt hElemId = m_surfaces.nghbrElementIds(hReverseSurfaceId(donorSrfcId, pos), 1 - extendSide);
5338 // This case happens if href happens across domain boundaries and is handled outside of this
5339 // function.
5340 if(hElemId < 0) {
5341 allDonorsHaveUpdatedMeans = true;
5342 continue;
5343 }
5344 if(elementUpdated[hElemId] == false) {
5345 allDonorsHaveUpdatedMeans = false;
5346 elementUpdated[elementId] = false;
5347 noMoreUpdates = false;
5348 }
5349 }
5350 // Only when all donor surfaces are updated, the recv element assembles its nodevars.
5351 if(allDonorsHaveUpdatedMeans) {
5352 const MInt maxNoNodes1DSurf = surfaceNoNodes1D[donorSrfcId];
5353 const MInt maxNoNodes1D3Surf = nDim == 3 ? maxNoNodes1DSurf : 1;
5354 const MInt noNodesSecondRefSurfDim = extendDimension == 2 ? maxNoNodes1DSurf : maxNoNodes1D3Surf;
5355 const MInt coarseNextSrfcId = m_elements.surfaceIds(elementId, extendDir);
5356 // mark refined cell as updated with hElemId
5357 elementUpdated[elementId] = true;
5358 // mark recv surface for mpi exchange if on domain border
5359 if(coarseNextSrfcId >= m_mpiSurfacesOffset) {
5360 mpiSurfaceSendSize[coarseNextSrfcId] = maxNoNodes1D * maxNoNodes1D3 * SysEqn::noNodeVars();
5361 }
5362 noMoreUpdates = false;
5363 MFloatTensor projectedSum(maxNoNodes1DSurf, noNodesSecondRefSurfDim, noVars);
5364 projectedSum.set(0.0);
5365 for(MInt pos = 0; pos < noSurfs; pos++) {
5366 const MInt hSrfId = hReverseSurfaceId(donorSrfcId, pos);
5367 MFloatTensor projected(maxNoNodes1DSurf, noNodesSecondRefSurfDim, noVars);
5368 projected.set(0.0);
5369 calcMortarProjection<dg::mortar::reverse, SysEqn::noNodeVars()>(
5370 hSrfId, donorDir, &m_surfaces.nodeVars(hSrfId, 1 - extendSide), &projected[0], m_elements, m_surfaces);
5371 for(MInt i = 0; i < maxNoNodes1D; i++) {
5372 for(MInt j = 0; j < noNodesSecondSurfDim; j++) {
5373 for(MInt k = 0; k < noVars; k++) {
5374 projectedSum(i, j, k) += projected(i, j, k);
5375 }
5376 }
5377 }
5378 }
5379 // Copy projected values to element.
5380 // This loop structure is suboptimal regarding memory acces, but easier to read.
5381 // If better performance is desired here, consider using separate loops for each possible
5382 // direction.
5383 MFloatTensor hNodeVarsLeft(&m_elements.nodeVars(elementId), maxNoNodes1D, maxNoNodes1D, maxNoNodes1D3, noVars);
5384 MFloatTensor hNodeVarsLeftSurf1(&m_surfaces.nodeVars(coarseNextSrfcId, extendSide), maxNoNodes1D,
5385 noNodesSecondSurfDim, noVars);
5386 MFloatTensor hNodeVarsLeftSurf2(&m_surfaces.nodeVars(coarseNextSrfcId, 1 - extendSide), maxNoNodes1D,
5387 noNodesSecondSurfDim, noVars);
5388 for(MInt a = 0; a < maxNoNodes1D; ++a) {
5389 for(MInt b = 0; b < maxNoNodes1D; ++b) {
5390 for(MInt c = 0; c < maxNoNodes1D3; ++c) {
5391 const MInt iNodes2D = extendDimension == 0 ? b : a;
5392 const MInt iNodes3D = extendDimension == 2 ? b : c;
5393 for(MInt iVars = 0; iVars < noVars; iVars++) {
5394 if(extendNodeVar[iVars]) {
5395 hNodeVarsLeft(a, b, c, iVars) = projectedSum(iNodes2D, iNodes3D, iVars);
5396 elemNodeVarsSlice(iNodes2D, iNodes3D, iVars) = projectedSum(iNodes2D, iNodes3D, iVars);
5397 hNodeVarsLeftSurf1(iNodes2D, iNodes3D, iVars) = projectedSum(iNodes2D, iNodes3D, iVars);
5398 hNodeVarsLeftSurf2(iNodes2D, iNodes3D, iVars) = projectedSum(iNodes2D, iNodes3D, iVars);
5399 } else {
5400 hNodeVarsLeft(a, b, c, iVars) = defaultNodeVars(iVars);
5401 elemNodeVarsSlice(iNodes2D, iNodes3D, iVars) = defaultNodeVars(iVars);
5402 hNodeVarsLeftSurf1(iNodes2D, iNodes3D, iVars) = defaultNodeVars(iVars);
5403 hNodeVarsLeftSurf2(iNodes2D, iNodes3D, iVars) = defaultNodeVars(iVars);
5404 }
5405 }
5406 }
5407 }
5408 }
5409 elementUpdated[elementId] = true;
5410 noMoreUpdates = false;
5411 }
5412 }
5413 // If the receiver surface is h(p)-refined(because the element after the receive element is),
5414 // copy the updated nodeVars to all child surfaces and project.
5415 // This guarantees that the next element can use these as is.
5416 if(hForwardSurfaceId(recvSrfcId, 0) > 0) {
5417 const MInt maxNoNodes1DFine = surfaceNoNodes1D[recvSrfcId];
5418 const MInt maxNoNodes1D3Fine = nDim == 3 ? maxNoNodes1DFine : 1;
5419 const MInt noNodesSecondFineSurfDim = extendDimension == 2 ? maxNoNodes1DFine : maxNoNodes1D3Fine;
5420 for(MInt pos = 0; pos < noSurfs; pos++) {
5421 const MInt hSrfId = hForwardSurfaceId(recvSrfcId, pos);
5422 copy_n(&elemNodeVarsSlice(0, 0, 0),
5423 maxNoNodes1D * noNodesSecondSurfDim * noVars,
5424 &m_surfaces.nodeVars(hSrfId, 1 - extendSide));
5425 }
5426 for(MInt pos = 0; pos < noSurfs; pos++) {
5427 const MInt hSrfId = hForwardSurfaceId(recvSrfcId, pos);
5428 MFloatTensor projected(maxNoNodes1DFine, noNodesSecondFineSurfDim, noVars);
5429 projected.set(0.0);
5430 calcMortarProjection<dg::mortar::forward, SysEqn::noNodeVars()>(
5431 hSrfId, extendDir, &m_surfaces.nodeVars(hSrfId, 1 - extendSide), &projected[0], m_elements, m_surfaces);
5432 MFloatTensor nodeVarsNextSrfPSide(&m_surfaces.nodeVars(hSrfId, extendSide), maxNoNodes1DFine,
5433 noNodesSecondFineSurfDim, noVars);
5434 MFloatTensor nodeVarsNextSrfMSide(&m_surfaces.nodeVars(hSrfId, 1 - extendSide), maxNoNodes1DFine,
5435 noNodesSecondFineSurfDim, noVars);
5436 for(MInt iNodes2D = 0; iNodes2D < maxNoNodes1DFine; iNodes2D++) {
5437 for(MInt iNodes3D = 0; iNodes3D < noNodesSecondFineSurfDim; iNodes3D++) {
5438 for(MInt iVars = 0; iVars < noVars; iVars++) {
5439 nodeVarsNextSrfPSide(iNodes2D, iNodes3D, iVars) = projected(iNodes2D, iNodes3D, iVars);
5440 nodeVarsNextSrfMSide(iNodes2D, iNodes3D, iVars) = projected(iNodes2D, iNodes3D, iVars);
5441 }
5442 }
5443 }
5444 // Mark next left surface of child element for mpi exchange if on domain border.
5445 if(recvSrfcId >= m_mpiSurfacesOffset) {
5446 mpiSurfaceSendSize[hSrfId] = maxNoNodes1DFine * maxNoNodes1D3Fine * noVars;
5447 }
5448 }
5449 }
5450}

◆ updateWeightsAndWorkloads()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::updateWeightsAndWorkloads ( )
private

◆ useSponge()

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::useSponge ( ) const
inlineprivate

Definition at line 361 of file dgcartesiansolver.h.

361{ return m_useSponge; }

◆ writeEOC()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::writeEOC
private

Definition at line 1194 of file dgcartesiansolver.cpp.

1194 {
1195 vector<MFloat> L2Error(m_sysEqn.noVars());
1196 vector<MFloat> LInfError(m_sysEqn.noVars());
1197 vector<MFloat> L2ErrLocal(m_sysEqn.noVars());
1198 vector<MFloat> LInfErrLocal(m_sysEqn.noVars());
1199 calcErrorNorms(m_finalTime, L2Error, LInfError, L2ErrLocal, LInfErrLocal);
1200
1201 cout << "WRITE EOC" << endl;
1202 // Write output for EOC analysis
1203 if(m_calcErrorNorms && isMpiRoot()) {
1204 }
1205}

◆ writeRestartFile()

template<MInt nDim, class SysEqn >
void DgCartesianSolver< nDim, SysEqn >::writeRestartFile ( const MBool  writeRestart,
const MBool  writeBackup,
const MString  gridFileName,
MInt recalcIdTree 
)
overridevirtual

Reimplemented from Solver.

Definition at line 1745 of file dgcartesiansolver.cpp.

1748 {
1749 TRACE();
1750 CHECK_TIMERS_IO();
1751 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
1752
1753 // Write out restart file
1754 if(writeRestart) {
1755 RECORD_TIMER_START(m_timers[Timers::MainLoopIO]);
1756
1757 const MFloat tOutputStart = wallTime();
1759 const MFloat tOutputEnd = wallTime();
1760
1761 // Update output time so that inner loop does not consider it
1762 m_outputTime += tOutputEnd - tOutputStart;
1763
1764 RECORD_TIMER_STOP(m_timers[Timers::MainLoopIO]);
1765 }
1766
1767 // TODO labels:DG integrate this in the unified run loop/gridcontroller for all solvers!
1768 /* // Check regularly if job is about to end */
1769 /* if (m_endAutoSaveTime != -1 && !m_endAutoSaveWritten */
1770 /* && m_timeStep % m_endAutoSaveCheckInterval == 0) { */
1771 /* // synchronize ranks (prevent deadlocks) */
1772 /* MBool writeEndAutoSave = false; */
1773 /* if (isMpiRoot() */
1774 /* && m_endAutoSaveTime */
1775 /* <= chrono::duration_cast<chrono::seconds>( */
1776 /* chrono::system_clock::now().time_since_epoch()) */
1777 /* .count()) { */
1778 /* writeEndAutoSave = true; */
1779 /* } */
1780 /* MPI_Bcast(&writeEndAutoSave, 1, MPI_C_BOOL, 0, mpiComm(), AT_, "writeEndAutoSave" ); */
1781 /* // Write out restart file if job is about to end */
1782 /* if (writeEndAutoSave) { */
1783 /* RECORD_TIMER_START(m_timers[Timers::MainLoopIO]); */
1784
1785 /* const MFloat tOutputStart = wallTime(); */
1786 /* saveRestartFile(); */
1787 /* time_t now = std::chrono::duration_cast<std::chrono::seconds>( */
1788 /* std::chrono::system_clock::now().time_since_epoch()) */
1789 /* .count(); */
1790 /* m_log << "Finished end auto save at " << std::ctime(&now) */
1791 /* << " (in Unix time: " << now << ")." << endl; */
1792 /* time_t jobEndTime = m_endAutoSaveTime + m_noMinutesEndAutoSave * 60; */
1793 /* m_log << "Job will end at " << std::ctime(&jobEndTime) */
1794 /* << " (in Unix time: " << jobEndTime << ")." << endl; */
1795
1796 /* m_endAutoSaveWritten = true; */
1797
1798 /* const MFloat tOutputEnd = wallTime(); */
1799
1800 /* // Update output time so that inner loop does not consider it */
1801 /* m_outputTime += tOutputEnd - tOutputStart; */
1802
1803 /* RECORD_TIMER_STOP(m_timers[Timers::MainLoopIO]); */
1804 /* } */
1805 /* } */
1806 /* } */
1807
1808 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
1809}

Friends And Related Function Documentation

◆ CouplingDg< nDim, SysEqn >

template<MInt nDim, class SysEqn >
friend class CouplingDg< nDim, SysEqn >
friend

Definition at line 47 of file dgcartesiansolver.h.

◆ CouplingDgApe

template<MInt nDim, class SysEqn >
template<MInt nDim_, class CouplingX >
friend class CouplingDgApe
friend

Definition at line 47 of file dgcartesiansolver.h.

◆ DgBoundaryCondition< nDim, SysEqn >

template<MInt nDim, class SysEqn >
friend class DgBoundaryCondition< nDim, SysEqn >
friend

Definition at line 1137 of file dgcartesiansolver.h.

◆ DgCcAcousticPerturb< nDim, SysEqn >

template<MInt nDim, class SysEqn >
friend class DgCcAcousticPerturb< nDim, SysEqn >
friend

Definition at line 47 of file dgcartesiansolver.h.

◆ DgSlices< nDim, SysEqn >

template<MInt nDim, class SysEqn >
friend class DgSlices< nDim, SysEqn >
friend

Definition at line 47 of file dgcartesiansolver.h.

◆ maia::CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >

template<MInt nDim, class SysEqn >
friend class maia::CartesianSolver< nDim, DgCartesianSolver< nDim, SysEqn > >
friend

Definition at line 47 of file dgcartesiansolver.h.

◆ PostProcessing

template<MInt nDim, class SysEqn >
template<MInt nDim_, class ppType >
friend class PostProcessing
friend

Definition at line 53 of file dgcartesiansolver.h.

Member Data Documentation

◆ m_adaptiveInterval

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_adaptiveInterval = -1
private

Definition at line 664 of file dgcartesiansolver.h.

◆ m_adaptivePref

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_adaptivePref = -1
private

Definition at line 660 of file dgcartesiansolver.h.

◆ m_adaptiveThreshold

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_adaptiveThreshold = -1
private

Definition at line 662 of file dgcartesiansolver.h.

◆ m_alwaysSaveFinalRestart

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_alwaysSaveFinalRestart = true
private

Definition at line 611 of file dgcartesiansolver.h.

◆ m_alwaysSaveFinalSolution

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_alwaysSaveFinalSolution = true
private

Definition at line 609 of file dgcartesiansolver.h.

◆ m_analysisInterval

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_analysisInterval = -1
private

Definition at line 566 of file dgcartesiansolver.h.

◆ m_analyzeTimeStart

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_analyzeTimeStart = 0.0
private

Definition at line 838 of file dgcartesiansolver.h.

◆ m_boundaryConditionFactory

template<MInt nDim, class SysEqn >
DgBoundaryConditionFactory<nDim, SysEqn> DgCartesianSolver< nDim, SysEqn >::m_boundaryConditionFactory {*this}
private

Definition at line 686 of file dgcartesiansolver.h.

◆ m_boundaryConditions

template<MInt nDim, class SysEqn >
std::vector<BC> DgCartesianSolver< nDim, SysEqn >::m_boundaryConditions {}
private

Definition at line 688 of file dgcartesiansolver.h.

◆ m_calcErrorNorms

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_calcErrorNorms = true
private

Definition at line 562 of file dgcartesiansolver.h.

◆ m_calcTimeStepInterval

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_calcTimeStepInterval = -1
private

Definition at line 507 of file dgcartesiansolver.h.

◆ m_cfl

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_cfl = 1.0
private

Definition at line 552 of file dgcartesiansolver.h.

◆ m_cutOffBoundaryConditionIds

template<MInt nDim, class SysEqn >
std::array<MInt, 2 * nDim> DgCartesianSolver< nDim, SysEqn >::m_cutOffBoundaryConditionIds {}
private

Definition at line 692 of file dgcartesiansolver.h.

◆ m_dgIntegrationMethod

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_dgIntegrationMethod = -1
private

Definition at line 540 of file dgcartesiansolver.h.

◆ m_dgPolynomialType

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_dgPolynomialType = -1
private

Definition at line 544 of file dgcartesiansolver.h.

◆ m_dgTimeIntegrationScheme

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_dgTimeIntegrationScheme = -1
private

Definition at line 542 of file dgcartesiansolver.h.

◆ m_dt

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_dt = -1.0
private

Definition at line 733 of file dgcartesiansolver.h.

◆ m_elements

template<MInt nDim, class SysEqn >
ElementCollector DgCartesianSolver< nDim, SysEqn >::m_elements
private

Definition at line 711 of file dgcartesiansolver.h.

◆ m_endAutoSaveCheckInterval

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_endAutoSaveCheckInterval = 0
private

Definition at line 621 of file dgcartesiansolver.h.

◆ m_endAutoSaveTime

template<MInt nDim, class SysEqn >
std::time_t DgCartesianSolver< nDim, SysEqn >::m_endAutoSaveTime = -1
private

Definition at line 840 of file dgcartesiansolver.h.

◆ m_endAutoSaveWritten

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_endAutoSaveWritten = false
private

Definition at line 841 of file dgcartesiansolver.h.

◆ m_exchangeNghbrDomains

template<MInt nDim, class SysEqn >
std::vector<MInt> DgCartesianSolver< nDim, SysEqn >::m_exchangeNghbrDomains {}
private

Definition at line 585 of file dgcartesiansolver.h.

◆ m_externalDt

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_externalDt = -1.0
private

Definition at line 735 of file dgcartesiansolver.h.

◆ m_finalTime

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_finalTime = 0.0
private

Definition at line 548 of file dgcartesiansolver.h.

◆ m_finalTimeStep

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_finalTimeStep = false
private

Definition at line 550 of file dgcartesiansolver.h.

◆ m_firstTimeStep

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_firstTimeStep = false
private

Definition at line 505 of file dgcartesiansolver.h.

◆ m_geometry

template<MInt nDim, class SysEqn >
Geom& DgCartesianSolver< nDim, SysEqn >::m_geometry
private

Definition at line 132 of file dgcartesiansolver.h.

◆ m_geometryIntersection

template<MInt nDim, class SysEqn >
GeometryIntersection<nDim>* DgCartesianSolver< nDim, SysEqn >::m_geometryIntersection = nullptr
private

Definition at line 680 of file dgcartesiansolver.h.

◆ m_globalVolume

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_globalVolume = -1.0
private

Definition at line 558 of file dgcartesiansolver.h.

◆ m_gridMapOffsets

template<MInt nDim, class SysEqn >
std::vector<maia::dg::GridMapOffset> DgCartesianSolver< nDim, SysEqn >::m_gridMapOffsets {}
private

Definition at line 648 of file dgcartesiansolver.h.

◆ m_helements

template<MInt nDim, class SysEqn >
HElementCollector DgCartesianSolver< nDim, SysEqn >::m_helements
private

Definition at line 671 of file dgcartesiansolver.h.

◆ m_initNoNodes1D

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_initNoNodes1D = -1
private

Definition at line 534 of file dgcartesiansolver.h.

◆ m_initPolyDeg

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_initPolyDeg = -1
private

Definition at line 528 of file dgcartesiansolver.h.

◆ m_innerSurfacesOffset

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_innerSurfacesOffset = -1
private

Definition at line 725 of file dgcartesiansolver.h.

◆ m_internalDataSize

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_internalDataSize = -1
private

Definition at line 705 of file dgcartesiansolver.h.

◆ m_interpAnalysis

template<MInt nDim, class SysEqn >
DgInterpolation DgCartesianSolver< nDim, SysEqn >::m_interpAnalysis {}
private

Definition at line 574 of file dgcartesiansolver.h.

◆ m_interpolation

template<MInt nDim, class SysEqn >
std::vector<std::vector<DgInterpolation> > DgCartesianSolver< nDim, SysEqn >::m_interpolation {}
private

Definition at line 556 of file dgcartesiansolver.h.

◆ m_isInitData

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_isInitData = false
private

Definition at line 832 of file dgcartesiansolver.h.

◆ m_isInitMainLoop

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_isInitMainLoop = false
private

Definition at line 833 of file dgcartesiansolver.h.

◆ m_isInitMpiExchange

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_isInitMpiExchange = false
private

Definition at line 834 of file dgcartesiansolver.h.

◆ m_isInitSolver

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_isInitSolver = false
private

Definition at line 831 of file dgcartesiansolver.h.

◆ m_isInitTimers

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_isInitTimers = false
private

Definition at line 830 of file dgcartesiansolver.h.

◆ m_loadBalancingReinitStage

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_loadBalancingReinitStage = -1
private

Definition at line 477 of file dgcartesiansolver.h.

◆ m_localVolume

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_localVolume = -1.0
private

Definition at line 560 of file dgcartesiansolver.h.

◆ m_loopTimeStart

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_loopTimeStart = 0.0
private

Definition at line 839 of file dgcartesiansolver.h.

◆ m_maxNoGridMapOffsets

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_maxNoGridMapOffsets = -1
private

Definition at line 650 of file dgcartesiansolver.h.

◆ m_maxNoNodes1D

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_maxNoNodes1D = -1
private

Definition at line 538 of file dgcartesiansolver.h.

◆ m_maxNoSurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_maxNoSurfaces = -1
private

Definition at line 703 of file dgcartesiansolver.h.

◆ m_maxPolyDeg

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_maxPolyDeg = -1
private

Definition at line 532 of file dgcartesiansolver.h.

◆ m_minNoNodes1D

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_minNoNodes1D = -1
private

Definition at line 536 of file dgcartesiansolver.h.

◆ m_minPolyDeg

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_minPolyDeg = -1
private

Definition at line 530 of file dgcartesiansolver.h.

◆ m_mpiRecvRequestsOpen

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_mpiRecvRequestsOpen = false
private

Definition at line 519 of file dgcartesiansolver.h.

◆ m_mpiRecvSurfaces

template<MInt nDim, class SysEqn >
std::vector<std::vector<MInt> > DgCartesianSolver< nDim, SysEqn >::m_mpiRecvSurfaces {}
private

Definition at line 590 of file dgcartesiansolver.h.

◆ m_mpiSendRequestsOpen

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_mpiSendRequestsOpen = false
private

Definition at line 520 of file dgcartesiansolver.h.

◆ m_mpiSurfaces

template<MInt nDim, class SysEqn >
std::vector<std::vector<MInt> > DgCartesianSolver< nDim, SysEqn >::m_mpiSurfaces {}
private

Definition at line 587 of file dgcartesiansolver.h.

◆ m_mpiSurfacesOffset

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_mpiSurfacesOffset = -1
private

Definition at line 727 of file dgcartesiansolver.h.

◆ m_noAnalysisNodes

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noAnalysisNodes = -1
private

Definition at line 568 of file dgcartesiansolver.h.

◆ m_noAnalyzeTimeSteps

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noAnalyzeTimeSteps = -1
private

Definition at line 837 of file dgcartesiansolver.h.

◆ m_noBoundarySurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noBoundarySurfaces = -1
private

Definition at line 717 of file dgcartesiansolver.h.

◆ m_noCutOffBoundarySurfaces

template<MInt nDim, class SysEqn >
std::array<MInt, 2 * nDim> DgCartesianSolver< nDim, SysEqn >::m_noCutOffBoundarySurfaces {}
private

Definition at line 694 of file dgcartesiansolver.h.

◆ m_noErrorDigits

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noErrorDigits = -1
private

Definition at line 572 of file dgcartesiansolver.h.

◆ m_noExchangeNghbrDomains

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noExchangeNghbrDomains = -1
private

Definition at line 583 of file dgcartesiansolver.h.

◆ m_noInnerSurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noInnerSurfaces = -1
private

Definition at line 719 of file dgcartesiansolver.h.

◆ m_noMinutesEndAutoSave

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noMinutesEndAutoSave = 0
private

Definition at line 619 of file dgcartesiansolver.h.

◆ m_noMpiSurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noMpiSurfaces = -1
private

Definition at line 721 of file dgcartesiansolver.h.

◆ m_noRkStages

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noRkStages = -1
private

Definition at line 511 of file dgcartesiansolver.h.

◆ m_noTotalNodesXD

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_noTotalNodesXD = -1
private

Definition at line 707 of file dgcartesiansolver.h.

◆ m_outputTime

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_outputTime = 0.0
private

Definition at line 842 of file dgcartesiansolver.h.

◆ m_pointData

template<MInt nDim, class SysEqn >
PointData<nDim, DgCartesianSolver<nDim, SysEqn> > DgCartesianSolver< nDim, SysEqn >::m_pointData {*this}
private

Definition at line 638 of file dgcartesiansolver.h.

◆ m_polyDegAnalysis

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_polyDegAnalysis = -1
private

Definition at line 570 of file dgcartesiansolver.h.

◆ m_pref

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_pref = -1
private

Definition at line 658 of file dgcartesiansolver.h.

◆ m_prefPatchesCoords

template<MInt nDim, class SysEqn >
std::vector<std::array<MFloat, 2 * nDim> > DgCartesianSolver< nDim, SysEqn >::m_prefPatchesCoords {}
private

Definition at line 674 of file dgcartesiansolver.h.

◆ m_prefPatchesNoNodes1D

template<MInt nDim, class SysEqn >
std::vector<MInt> DgCartesianSolver< nDim, SysEqn >::m_prefPatchesNoNodes1D {}
private

Definition at line 677 of file dgcartesiansolver.h.

◆ m_prefPatchesOperators

template<MInt nDim, class SysEqn >
std::vector<MString> DgCartesianSolver< nDim, SysEqn >::m_prefPatchesOperators {}
private

Definition at line 676 of file dgcartesiansolver.h.

◆ m_prefPatchesPolyDeg

template<MInt nDim, class SysEqn >
std::vector<MFloat> DgCartesianSolver< nDim, SysEqn >::m_prefPatchesPolyDeg {}
private

Definition at line 675 of file dgcartesiansolver.h.

◆ m_projectionMatricesH

template<MInt nDim, class SysEqn >
std::vector<MFloat> DgCartesianSolver< nDim, SysEqn >::m_projectionMatricesH {}
private

Definition at line 667 of file dgcartesiansolver.h.

◆ m_projectionMatricesP

template<MInt nDim, class SysEqn >
std::vector<MFloat> DgCartesianSolver< nDim, SysEqn >::m_projectionMatricesP {}
private

Definition at line 669 of file dgcartesiansolver.h.

◆ m_projectionMatrixPointersH

template<MInt nDim, class SysEqn >
std::vector<MFloat*> DgCartesianSolver< nDim, SysEqn >::m_projectionMatrixPointersH {}
private

Definition at line 666 of file dgcartesiansolver.h.

◆ m_projectionMatrixPointersP

template<MInt nDim, class SysEqn >
std::vector<MFloat*> DgCartesianSolver< nDim, SysEqn >::m_projectionMatrixPointersP {}
private

Definition at line 668 of file dgcartesiansolver.h.

◆ m_recvBuffers

template<MInt nDim, class SysEqn >
std::vector<std::vector<MFloat> > DgCartesianSolver< nDim, SysEqn >::m_recvBuffers {}
private

Definition at line 595 of file dgcartesiansolver.h.

◆ m_recvRequests

template<MInt nDim, class SysEqn >
std::vector<MPI_Request> DgCartesianSolver< nDim, SysEqn >::m_recvRequests {}
private

Definition at line 606 of file dgcartesiansolver.h.

◆ m_recvTypes

template<MInt nDim, class SysEqn >
std::vector<MPI_Datatype> DgCartesianSolver< nDim, SysEqn >::m_recvTypes {}
private

Definition at line 601 of file dgcartesiansolver.h.

◆ m_restoreDefaultWeights

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_restoreDefaultWeights = false
private

Definition at line 631 of file dgcartesiansolver.h.

◆ m_rkStage

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_rkStage = -1
private

Definition at line 509 of file dgcartesiansolver.h.

◆ m_saveNodeVariablesToSolutionFile

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_saveNodeVariablesToSolutionFile = false
private

Definition at line 613 of file dgcartesiansolver.h.

◆ m_sbpMode

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_sbpMode = false
private

Definition at line 524 of file dgcartesiansolver.h.

◆ m_sbpOperator

template<MInt nDim, class SysEqn >
MString DgCartesianSolver< nDim, SysEqn >::m_sbpOperator = ""
private

Definition at line 526 of file dgcartesiansolver.h.

◆ m_sendBuffers

template<MInt nDim, class SysEqn >
std::vector<std::vector<MFloat> > DgCartesianSolver< nDim, SysEqn >::m_sendBuffers {}
private

Definition at line 593 of file dgcartesiansolver.h.

◆ m_sendRequests

template<MInt nDim, class SysEqn >
std::vector<MPI_Request> DgCartesianSolver< nDim, SysEqn >::m_sendRequests {}
private

Definition at line 604 of file dgcartesiansolver.h.

◆ m_sendTypes

template<MInt nDim, class SysEqn >
std::vector<MPI_Datatype> DgCartesianSolver< nDim, SysEqn >::m_sendTypes {}
private

Definition at line 599 of file dgcartesiansolver.h.

◆ m_slice

template<MInt nDim, class SysEqn >
DgSlices<nDim, SysEqn> DgCartesianSolver< nDim, SysEqn >::m_slice {*this}
private

Definition at line 644 of file dgcartesiansolver.h.

◆ m_sourceRampUpTime

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_sourceRampUpTime = 0.0
private

Definition at line 699 of file dgcartesiansolver.h.

◆ m_sponge

template<MInt nDim, class SysEqn >
DgSponge<nDim, SysEqn> DgCartesianSolver< nDim, SysEqn >::m_sponge {-1, MPI_COMM_NULL}
private

Definition at line 653 of file dgcartesiansolver.h.

◆ m_startTime

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_startTime = 0.0
private

Definition at line 546 of file dgcartesiansolver.h.

◆ m_statGlobalMaxLevel

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statGlobalMaxLevel = -1
private

Definition at line 787 of file dgcartesiansolver.h.

◆ m_statGlobalMaxNoCells

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalMaxNoCells = -1
private

Definition at line 795 of file dgcartesiansolver.h.

◆ m_statGlobalMaxNoSurfaces

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalMaxNoSurfaces = -1
private

Definition at line 807 of file dgcartesiansolver.h.

◆ m_statGlobalMaxPolyDeg

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statGlobalMaxPolyDeg = -1
private

Definition at line 783 of file dgcartesiansolver.h.

◆ m_statGlobalMinLevel

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statGlobalMinLevel = -1
private

Definition at line 785 of file dgcartesiansolver.h.

◆ m_statGlobalMinPolyDeg

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statGlobalMinPolyDeg = -1
private

Definition at line 781 of file dgcartesiansolver.h.

◆ m_statGlobalNoActiveCells

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoActiveCells = -1
private

Definition at line 809 of file dgcartesiansolver.h.

◆ m_statGlobalNoActiveDOFs

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoActiveDOFs = -1
private

Definition at line 811 of file dgcartesiansolver.h.

◆ m_statGlobalNoBoundarySurfaces

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoBoundarySurfaces = -1
private

Definition at line 801 of file dgcartesiansolver.h.

◆ m_statGlobalNoCells

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoCells = -1
private

Definition at line 789 of file dgcartesiansolver.h.

◆ m_statGlobalNoCutOffBoundarySurfaces

template<MInt nDim, class SysEqn >
std::array<MLong, 6> DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoCutOffBoundarySurfaces {}
private

Definition at line 821 of file dgcartesiansolver.h.

◆ m_statGlobalNoElements

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoElements = -1
private

Definition at line 797 of file dgcartesiansolver.h.

◆ m_statGlobalNoHaloCells

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoHaloCells = -1
private

Definition at line 793 of file dgcartesiansolver.h.

◆ m_statGlobalNoHElements

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoHElements = -1
private

Definition at line 819 of file dgcartesiansolver.h.

◆ m_statGlobalNoHrefSurfs

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoHrefSurfs = -1
private

Definition at line 815 of file dgcartesiansolver.h.

◆ m_statGlobalNoInnerSurfaces

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoInnerSurfaces = -1
private

Definition at line 803 of file dgcartesiansolver.h.

◆ m_statGlobalNoInternalCells

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoInternalCells = -1
private

Definition at line 791 of file dgcartesiansolver.h.

◆ m_statGlobalNoMpiSurfaces

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoMpiSurfaces = -1
private

Definition at line 805 of file dgcartesiansolver.h.

◆ m_statGlobalNoPrefSurfs

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoPrefSurfs = -1
private

Definition at line 817 of file dgcartesiansolver.h.

◆ m_statGlobalNoSurfaces

template<MInt nDim, class SysEqn >
MLong DgCartesianSolver< nDim, SysEqn >::m_statGlobalNoSurfaces = -1
private

Definition at line 799 of file dgcartesiansolver.h.

◆ m_statGlobalPolyDegSum

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statGlobalPolyDegSum = -1
private

Definition at line 813 of file dgcartesiansolver.h.

◆ m_statLocalMaxLevel

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalMaxLevel = -1
private

Definition at line 745 of file dgcartesiansolver.h.

◆ m_statLocalMaxNoCells

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalMaxNoCells = -1
private

Definition at line 753 of file dgcartesiansolver.h.

◆ m_statLocalMaxNoSurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalMaxNoSurfaces = -1
private

Definition at line 767 of file dgcartesiansolver.h.

◆ m_statLocalMaxPolyDeg

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalMaxPolyDeg = -1
private

Definition at line 741 of file dgcartesiansolver.h.

◆ m_statLocalMinLevel

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalMinLevel = -1
private

Definition at line 743 of file dgcartesiansolver.h.

◆ m_statLocalMinPolyDeg

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalMinPolyDeg = -1
private

Definition at line 739 of file dgcartesiansolver.h.

◆ m_statLocalNoActiveCells

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoActiveCells = -1
private

Definition at line 769 of file dgcartesiansolver.h.

◆ m_statLocalNoActiveDOFs

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoActiveDOFs = -1
private

Definition at line 771 of file dgcartesiansolver.h.

◆ m_statLocalNoActiveDOFsPolyDeg

template<MInt nDim, class SysEqn >
std::vector<MInt> DgCartesianSolver< nDim, SysEqn >::m_statLocalNoActiveDOFsPolyDeg {}
private

Definition at line 773 of file dgcartesiansolver.h.

◆ m_statLocalNoBoundarySurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoBoundarySurfaces = -1
private

Definition at line 761 of file dgcartesiansolver.h.

◆ m_statLocalNoCells

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoCells = -1
private

Definition at line 747 of file dgcartesiansolver.h.

◆ m_statLocalNoElements

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoElements = -1
private

Definition at line 755 of file dgcartesiansolver.h.

◆ m_statLocalNoHaloCells

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoHaloCells = -1
private

Definition at line 751 of file dgcartesiansolver.h.

◆ m_statLocalNoHElements

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoHElements = -1
private

Definition at line 757 of file dgcartesiansolver.h.

◆ m_statLocalNoHrefSurfs

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoHrefSurfs = -1
private

Definition at line 777 of file dgcartesiansolver.h.

◆ m_statLocalNoInnerSurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoInnerSurfaces = -1
private

Definition at line 763 of file dgcartesiansolver.h.

◆ m_statLocalNoInternalCells

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoInternalCells = -1
private

Definition at line 749 of file dgcartesiansolver.h.

◆ m_statLocalNoMpiSurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoMpiSurfaces = -1
private

Definition at line 765 of file dgcartesiansolver.h.

◆ m_statLocalNoPrefSurfs

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoPrefSurfs = -1
private

Definition at line 779 of file dgcartesiansolver.h.

◆ m_statLocalNoSurfaces

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalNoSurfaces = -1
private

Definition at line 759 of file dgcartesiansolver.h.

◆ m_statLocalPolyDegSum

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_statLocalPolyDegSum = -1
private

Definition at line 775 of file dgcartesiansolver.h.

◆ m_surfaceData

template<MInt nDim, class SysEqn >
SurfaceData<nDim, DgCartesianSolver<nDim, SysEqn> > DgCartesianSolver< nDim, SysEqn >::m_surfaceData {*this}
private

Definition at line 640 of file dgcartesiansolver.h.

◆ m_surfaces

template<MInt nDim, class SysEqn >
SurfaceCollector DgCartesianSolver< nDim, SysEqn >::m_surfaces
private

Definition at line 715 of file dgcartesiansolver.h.

◆ m_sysEqn

template<MInt nDim, class SysEqn >
SysEqn DgCartesianSolver< nDim, SysEqn >::m_sysEqn
private

Definition at line 684 of file dgcartesiansolver.h.

◆ m_time

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_time = 0.0
private

Definition at line 731 of file dgcartesiansolver.h.

◆ m_timeIntegrationCoefficientsA

template<MInt nDim, class SysEqn >
std::vector<MFloat> DgCartesianSolver< nDim, SysEqn >::m_timeIntegrationCoefficientsA {}
private

Definition at line 513 of file dgcartesiansolver.h.

◆ m_timeIntegrationCoefficientsB

template<MInt nDim, class SysEqn >
std::vector<MFloat> DgCartesianSolver< nDim, SysEqn >::m_timeIntegrationCoefficientsB {}
private

Definition at line 515 of file dgcartesiansolver.h.

◆ m_timeIntegrationCoefficientsC

template<MInt nDim, class SysEqn >
std::vector<MFloat> DgCartesianSolver< nDim, SysEqn >::m_timeIntegrationCoefficientsC {}
private

Definition at line 517 of file dgcartesiansolver.h.

◆ m_timerGroup

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_timerGroup = -1
private

Definition at line 825 of file dgcartesiansolver.h.

◆ m_timers

template<MInt nDim, class SysEqn >
std::array<MInt, Timers::_count> DgCartesianSolver< nDim, SysEqn >::m_timers {}
private

Definition at line 827 of file dgcartesiansolver.h.

◆ m_timeStep

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_timeStep = -1
private

Definition at line 501 of file dgcartesiansolver.h.

◆ m_timeSteps

template<MInt nDim, class SysEqn >
MInt DgCartesianSolver< nDim, SysEqn >::m_timeSteps = -1
private

Definition at line 503 of file dgcartesiansolver.h.

◆ m_updateCellWeights

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_updateCellWeights = false
private

Definition at line 623 of file dgcartesiansolver.h.

◆ m_useCutOffBoundaries

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_useCutOffBoundaries = false
private

Definition at line 690 of file dgcartesiansolver.h.

◆ m_useSourceRampUp

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_useSourceRampUp = false
private

Definition at line 697 of file dgcartesiansolver.h.

◆ m_useSponge

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_useSponge = false
private

Definition at line 654 of file dgcartesiansolver.h.

◆ m_vdmAnalysis

template<MInt nDim, class SysEqn >
std::vector<std::vector<MFloatTensor> > DgCartesianSolver< nDim, SysEqn >::m_vdmAnalysis {}
private

Definition at line 579 of file dgcartesiansolver.h.

◆ m_volumeData

template<MInt nDim, class SysEqn >
VolumeData<nDim, DgCartesianSolver<nDim, SysEqn> > DgCartesianSolver< nDim, SysEqn >::m_volumeData {*this}
private

Definition at line 642 of file dgcartesiansolver.h.

◆ m_weightDgRbcElements

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_weightDgRbcElements = false
private

Definition at line 465 of file dgcartesiansolver.h.

◆ m_weightPerCell

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_weightPerCell = 0.0
private

Definition at line 629 of file dgcartesiansolver.h.

◆ m_weightPerElement

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_weightPerElement = 0.0
private

Definition at line 627 of file dgcartesiansolver.h.

◆ m_weightPerNode

template<MInt nDim, class SysEqn >
MFloat DgCartesianSolver< nDim, SysEqn >::m_weightPerNode = 1.0
private

Definition at line 625 of file dgcartesiansolver.h.

◆ m_writeInitialSolution

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_writeInitialSolution = true
private

Definition at line 633 of file dgcartesiansolver.h.

◆ m_writeNodeVarsFile

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_writeNodeVarsFile = true
private

Definition at line 635 of file dgcartesiansolver.h.

◆ m_writeSpongeEta

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_writeSpongeEta = false
private

Definition at line 617 of file dgcartesiansolver.h.

◆ m_writeTimeDerivative

template<MInt nDim, class SysEqn >
MBool DgCartesianSolver< nDim, SysEqn >::m_writeTimeDerivative = false
private

Definition at line 615 of file dgcartesiansolver.h.

◆ m_wVolumeAnalysis

template<MInt nDim, class SysEqn >
MFloatTensor DgCartesianSolver< nDim, SysEqn >::m_wVolumeAnalysis {}
private

Definition at line 576 of file dgcartesiansolver.h.

◆ s_cellDataTypeDlb

template<MInt nDim, class SysEqn >
const std::array< MInt, DgCartesianSolver< nDim, SysEqn >::CellData::count > DgCartesianSolver< nDim, SysEqn >::s_cellDataTypeDlb = {{MINT, MINT, MINT, MFLOAT, MFLOAT}}
staticprivate

Definition at line 481 of file dgcartesiansolver.h.


The documentation for this class was generated from the following files: