58template <MInt nDim,
class SysEqn>
77 std::vector<BC>* boundaryConditions, SysEqn* sysEqn,
const MPI_Comm comm);
132template <MInt nDim,
class SysEqn>
153template <MInt nDim,
class SysEqn>
155 SurfaceCollector* surfaces_, std::vector<BC>* boundaryConditions, SysEqn* sysEqn,
156 const MPI_Comm comm) {
161 MPI_Comm_rank(mpiComm(), &m_domainId);
162 MPI_Comm_size(mpiComm(), &m_noDomains);
164 m_maxPolyDeg = maxPolyDeg;
166 m_elements = elements_;
167 m_surfaces = surfaces_;
168 m_boundaryConditions = boundaryConditions;
173 checkSpongeBoundaryConditions();
176 initSpongeElements();
186template <MInt nDim,
class SysEqn>
191 const MInt noBcs = m_boundaryConditions->size();
192 const MInt noDomains1 = (domainId() != 0) ? 1 : noDomains();
202 const MInt noBcs1 = (noBcs == 0) ? 1 : noBcs;
204 for(
MInt i = 0; i < noBcs; i++) {
205 bcIds[i] = (*m_boundaryConditions)[i]->id();
209 const MInt noBcsTotal1 = (domainId() != 0) ? 1 : std::accumulate(noBcsPerDomain.begin(), noBcsPerDomain.end(), 0);
215 for(
MInt i = 1; i < noDomains1; i++) {
216 displs[i] = displs[i - 1] + noBcsPerDomain[i - 1];
224 std::set<MInt> bcIdsUnique(bcIdsPerDomain.begin(), bcIdsPerDomain.end());
247 TERMM(1,
"Sponge is activated, but spongeBCs property is not defined.");
252 for(
MInt i = 0; i < noSpongeBcs; i++) {
253 const MInt spongeBcId = Context::getSolverProperty<MInt>(
"spongeBCs", m_solverId, AT_, i);
255 if(domainId() == 0 && bcIdsUnique.count(spongeBcId) == 0) {
256 TERMM(1,
"BC " + std::to_string(spongeBcId) +
" in spongeBCs is not a valid boundary condition id.");
280template <MInt nDim,
class SysEqn>
286 MFloat defaultThickness = -std::numeric_limits<MFloat>::infinity();
299 defaultThickness = Context::getSolverProperty<MFloat>(
"defaultSpongeThickness", m_solverId, AT_, &defaultThickness);
305 std::vector<SpongeLayerType> spongeLayers(noSpongeBcs);
306 for(
MInt i = 0; i < noSpongeBcs; i++) {
308 SpongeLayerType& layer = spongeLayers[i];
311 const MInt spongeBcId = Context::getSolverProperty<MInt>(
"spongeBCs", m_solverId, AT_, i);
313 layer.m_bcId = spongeBcId;
316 const MString propName =
"spongeThickness_" + std::to_string(spongeBcId);
328 layer.m_thickness = Context::getSolverProperty<MFloat>(propName, m_solverId, AT_, &defaultThickness);
330 if(layer.m_thickness < 0.0) {
332 "No valid definition for spongeThickness_" + std::to_string(spongeBcId)
333 +
". Specify positive value or check your default sponge size.");
337 const auto boundaryConditionIt = std::find_if(m_boundaryConditions->begin(),
338 m_boundaryConditions->end(),
339 [spongeBcId](
const BC& bc) { return bc->id() == spongeBcId; });
340 if(boundaryConditionIt == m_boundaryConditions->end()) {
343 TERMM(1,
"Boundary condition id " + std::to_string(spongeBcId) +
" not found");
345 if((*boundaryConditionIt)->count() > 0) {
347 const BC& boundaryCondition = *boundaryConditionIt;
348 initSpongeLayer(layer, boundaryCondition);
351 std::fill_n(layer.m_minCoord.begin(), nDim, std::numeric_limits<MFloat>::max());
352 std::fill_n(layer.m_maxCoord.begin(), nDim, -std::numeric_limits<MFloat>::max());
357 exchangeSpongeLayers(spongeLayers);
360 MBoolScratchSpace spongeElementFlags(m_elements->size(), AT_,
"spongeElementFlags");
361 std::fill(spongeElementFlags.begin(), spongeElementFlags.end(),
false);
365#pragma omp parallel for
367 for(
MInt eId = 0; eId < m_elements->size(); eId++) {
368 const MInt noNodes = m_elements->noNodesXD(eId);
370 const MFloat*
const nodeCoordinates = &m_elements->nodeCoordinates(eId);
372 for(
MInt nodeId = 0; nodeId < noNodes; nodeId++) {
373 const MFloat*
const point = &nodeCoordinates[nodeId * nDim];
376 for(
size_t i = 0; i < spongeLayers.size(); i++) {
378 if(pointInsideSpongeLayer(spongeLayers[i], point, diff)) {
379 spongeElementFlags[eId] =
true;
385 if(spongeElementFlags[eId]) {
392 const MInt spongeElementsCount = std::count(spongeElementFlags.begin(), spongeElementFlags.end(),
true);
393 m_spongeElements.maxPolyDeg(m_maxPolyDeg);
394 m_spongeElements.reset(spongeElementsCount);
397 for(
size_t i = 0; i < spongeElementFlags.size(); i++) {
398 if(spongeElementFlags[i]) {
399 const MInt seId = noSpongeElements();
400 m_spongeElements.append();
401 m_spongeElements.elementId(seId) = i;
407#pragma omp parallel for
409 for(
MInt seId = 0; seId < noSpongeElements(); seId++) {
410 calcSpongeEtaForAllNodes(seId, spongeLayers);
421template <MInt nDim,
class SysEqn>
425 const MInt firstSrfcId = boundaryCondition->begin();
426 const MFloat* srfcCoord = &m_surfaces->coords(firstSrfcId, 0);
429 MInt orientation = m_surfaces->orientation(firstSrfcId);
430 MInt direction = m_surfaces->internalSideId(firstSrfcId);
436 if(spongeLayer.
m_bcId == 200) {
441 if(spongeLayer.
m_bcId == 201) {
446 if(spongeLayer.
m_bcId == 202) {
451 if(spongeLayer.
m_bcId == 203) {
458 spongeLayer.
m_offset = srfcCoord[orientation];
461 std::fill_n(&spongeLayer.
m_minCoord[0], nDim, std::numeric_limits<MFloat>::max());
462 spongeLayer.
m_minCoord[orientation] = srfcCoord[orientation];
463 std::fill_n(&spongeLayer.
m_maxCoord[0], nDim, -std::numeric_limits<MFloat>::max());
464 spongeLayer.
m_maxCoord[orientation] = srfcCoord[orientation];
467 for(
MInt i = boundaryCondition->begin(); i < boundaryCondition->end(); i++) {
468 const MFloat* srfcCenter = &m_surfaces->coords(i, 0);
469 const MInt internalSideId = m_surfaces->internalSideId(i);
472 if(internalSideId == -1) {
475 const MInt eId = m_surfaces->nghbrElementIds(i, internalSideId);
476 const MInt cellId = m_elements->cellId(eId);
477 const MFloat halfCellLength = m_grid->halfCellLength(cellId);
478 for(
MInt j = 0; j < nDim; j++) {
479 if(j != orientation) {
480 spongeLayer.
m_minCoord[j] = std::min(spongeLayer.
m_minCoord[j], srfcCenter[j] - halfCellLength);
481 spongeLayer.
m_maxCoord[j] = std::max(spongeLayer.
m_maxCoord[j], srfcCenter[j] + halfCellLength);
494template <MInt nDim,
class SysEqn>
503 const MInt noSpongeBcs = spongeLayers.size();
507 for(
MInt i = 0; i < noSpongeBcs; i++) {
508 const MInt spongeBcId = spongeLayers[i].m_bcId;
509 whichSpongeLayers(domainId(), i) =
510 std::find_if(m_boundaryConditions->begin(),
511 m_boundaryConditions->end(),
512 [spongeBcId](
const BC& bc) { return bc->id() == spongeBcId && bc->count() > 0; })
513 != m_boundaryConditions->
end();
531 for(
MInt i = 0; i < noDomains(); i++) {
532 for(
MInt j = 0; j < noSpongeBcs; j++) {
534 if(!whichSpongeLayers(i, j)) {
539 for(
MInt k = i + 1; k < noDomains(); k++) {
540 whichSpongeLayers(k, j) =
false;
544 const MInt spongeBcId = spongeLayers[j].m_bcId;
546 *std::find_if(spongeLayers.begin(), spongeLayers.end(),
547 [spongeBcId](
const SpongeLayerType& sl) { return sl.m_bcId == spongeBcId; });
549 "spongeLayer.m_orientation");
551 "spongeLayer.m_offset");
553 mpiComm(), AT_,
"MPI_IN_PLACE",
"spongeLayer.m_minCoord[0]");
555 mpiComm(), AT_,
"MPI_IN_PLACE",
"spongeLayer.m_maxCoord[0]");
568template <MInt nDim,
class SysEqn>
570 const MInt*
const begin = &m_spongeElements.elementId(0);
571 const MInt*
const end = &m_spongeElements.elementId(0) + noSpongeElements();
572 const MInt*
const low = std::lower_bound(begin, end, eId);
575 if(low == end || *low != eId) {
580 return std::distance(begin, low);
592template <MInt nDim,
class SysEqn>
597 const MInt* noNodes1D = &m_elements->noNodes1D(0);
598 const MInt maxDataBlockSize = m_elements->maxNoNodesXD() * SysEqn::noVars();
600 std::vector<MFloat> spongeSources(maxDataBlockSize);
603#pragma omp parallel for firstprivate(spongeSources)
605 for(
MInt seId = 0; seId < noSpongeElements(); seId++) {
606 const MInt eId = m_spongeElements.elementId(seId);
607 const MInt dataBlockSize = m_elements->noNodesXD(eId) * SysEqn::noVars();
608 m_sysEqn->calcSpongeSource(&m_elements->nodeVars(eId),
609 &m_elements->variables(eId),
611 &m_spongeElements.spongeEta(seId),
613 MFloat*
const rhs = &m_elements->rightHandSide(eId);
614 for(
MInt dataId = 0; dataId < dataBlockSize; dataId++) {
615 rhs[dataId] += spongeSources[dataId];
627template <MInt nDim,
class SysEqn>
629 const std::vector<SpongeLayerType>& spongeLayers) {
632 const MInt eId = m_spongeElements.elementId(seId);
633 const MInt noNodes1D = m_elements->noNodes1D(eId);
634 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
636 MFloatTensor nodeCoordinates(&m_elements->nodeCoordinates(eId), noNodes1D, noNodes1D, noNodes1D3, nDim);
638 MFloatTensor sEta(&m_spongeElements.spongeEta(seId), noNodes1D, noNodes1D, noNodes1D3);
639 std::fill_n(&sEta(0, 0, 0), sEta.
size(), 0.0);
641 for(
MInt i = 0; i < noNodes1D; i++) {
642 for(
MInt j = 0; j < noNodes1D; j++) {
643 for(
MInt k = 0; k < noNodes1D3; k++) {
644 for(
size_t s = 0; s < spongeLayers.size(); s++) {
646 if(pointInsideSpongeLayer(spongeLayers[s], &nodeCoordinates(i, j, k, 0), diff)) {
647 const MFloat eta =
POW2(diff / spongeLayers[s].m_thickness);
648 sEta(i, j, k) = std::max(sEta(i, j, k), eta);
664template <MInt nDim,
class SysEqn>
671 return direction * (point[orientation] - spongeLayer.
m_offset);
683template <MInt nDim,
class SysEqn>
697 for(
MInt i = 0; i < nDim; i++) {
699 if(orientation == i) {
static MInt propertyLength(const MString &name, MInt solverId=m_noSolvers)
Returns the number of elements of a property.
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
std::unique_ptr< DgBoundaryCondition< nDim, SysEqn > > ReturnType
Container for sponge elements.
SpongeElementCollector m_spongeElements
MPI_Comm mpiComm() const
Return the MPI communicator used by the corresponding solver.
MInt elementId(const MInt seId) const
std::vector< BC > * m_boundaryConditions
MInt spongeElementId(const MInt eId) const
Return sponge element id for given element id. If none exists, return -1.
void exchangeSpongeLayers(std::vector< SpongeLayerType > &spongeLayers)
Exchange sponge layers between all domains.
maia::dg::collector::ElementCollector< nDim, SysEqn > ElementCollector
MInt domainId() const
Return the domain id of the corresponding solver.
DgSpongeLayer< nDim > SpongeLayerType
void checkSpongeBoundaryConditions() const
Check whether boundary conditions specified to have a sponge exist.
void calcSpongeEtaForAllNodes(const MInt seId, const std::vector< SpongeLayerType > &spongeLayers)
Calculation of SpongeEta for all nodes of one DG-Element.
MBool pointInsideSpongeLayer(const SpongeLayerType &spongeLayer, const MFloat *otherPoint, MFloat &diff) const
Returns true if point is inside sponge layer. Calculates difference between thickness of sponge layer...
ElementCollector * m_elements
void initSpongeLayer(SpongeLayerType &spongeLayer, const BC &boundaryCondition)
Determines boundary plane.
void init(const MInt maxPolyDeg, Grid *grid_, ElementCollector *elements_, SurfaceCollector *surfaces_, std::vector< BC > *boundaryConditions, SysEqn *sysEqn, const MPI_Comm comm)
Sets attributes so that sponge can access necessary components in solver. Checks sponge boundary cond...
typename maia::grid::Proxy< nDim > Grid
maia::dg::collector::SurfaceCollector< nDim, SysEqn > SurfaceCollector
SurfaceCollector * m_surfaces
MFloat distance(const SpongeLayerType &spongeLayer, const MFloat *otherPoint) const
Calculates the distance between a point and a boundary plane. The distance is signed,...
void calcSourceTerms()
Calculates the sponge terms, that can be considered as an addition source terms for each node and add...
DgSponge(const MInt solverId, const MPI_Comm comm)
Constructor accepts solver id and MPI communicator.
MInt noDomains() const
Return the number of domains of the corresponding solver.
MFloat spongeEta(const MInt seId, const MInt pos)
void initSpongeElements()
Initialisation of SpongeLayer. Calculation of spongeEta. Sponge is an additional Sourceoperator: DelL...
MInt noSpongeElements() const
typename DgBoundaryConditionFactory< nDim, SysEqn >::ReturnType BC
This class is a ScratchSpace.
constexpr MInt size() const
Return size (i.e., currently used number of nodes)
Class that represents DG element collector.
Class that represents DG element collector.
MFloat & spongeEta(const MInt id)
Accessor for sponge eta.
MInt & elementId(const MInt id)
Accessor for element id.
Class that represents DG element collector.
size_type size() const
Returns the size of the array as product of all five dimensions (i.e. not the actual array size but t...
constexpr Real POW2(const Real x)
std::basic_string< char > MString
int MPI_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gatherv
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
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
int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gather
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
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Container for attributes characterizing sponge layer.
std::array< MFloat, nDim > m_maxCoord
std::array< MFloat, nDim > m_minCoord