Loading [MathJax]/extensions/tex2jax.js
MAIA bb96820c
Multiphysics at AIA
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
fvcartesianbndrycndxd.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
8
9#include <cmath>
10#include <cstring>
11#include <fstream>
12#include <iomanip>
13#include <iostream>
14#include <iterator>
15#include <stack>
16#include "COMM/mpioverride.h"
19#include "IO/context.h"
20#include "IO/parallelio.h"
21#include "MEMORY/list.h"
22#include "UTIL/hilbert.h"
24#include "fvcartesiansolverxd.h"
25#include "fvstg.h"
26#include "fvstructuredsolver.h"
27#include "property.h"
28
29using namespace std;
30using namespace maia::parallel_io;
31
32
33template <MInt nDim, class SysEqn>
35 : m_sysEqn(&solver->m_sysEqn),
36 m_cells(solver->m_cells),
37 m_surfaces(solver->m_surfaces),
38 m_solverId(solver->m_solverId),
39 CV(solver->CV),
40 FV(solver->FV),
41 PV(solver->PV),
42 AV(solver->AV),
43 m_minLevel(solver->minLevel()),
44 m_maxLevel(solver->maxLevel()),
45 m_createSpongeBoundary(solver->m_createSpongeBoundary),
46 m_cellsInsideSpongeLayer(solver->m_cellsInsideSpongeLayer),
47 m_noCellsInsideSpongeLayer(solver->m_noCellsInsideSpongeLayer),
48 m_spongeBndryCndIds(solver->m_spongeBndryCndIds),
49 m_spongeFactor(solver->m_spongeFactor),
50 m_spongeDirections(solver->m_spongeDirections),
51 m_sigmaSpongeBndryId(solver->m_sigmaSpongeBndryId),
52 m_sigmaEndSpongeBndryId(solver->m_sigmaEndSpongeBndryId),
53 m_spongeLayerThickness(solver->m_spongeLayerThickness),
54 m_spongeLayerLayout(solver->m_spongeLayerLayout),
55 m_spongeTimeDep(solver->m_spongeTimeDep),
56 m_spongeStartIteration(solver->m_spongeStartIteration),
57 m_spongeEndIteration(solver->m_spongeEndIteration),
58 m_spongeTimeDependent(solver->m_spongeTimeDependent),
59 m_noSpongeBndryCndIds(solver->m_noSpongeBndryCndIds),
60 m_noMaxSpongeBndryCells(solver->m_noMaxSpongeBndryCells),
61 m_spongeBeta(solver->m_spongeBeta),
62 m_spongeCoord(solver->m_spongeCoord),
63 m_radiusFlameTube(solver->m_radiusFlameTube),
64 m_radiusVelFlameTube(solver->m_radiusVelFlameTube),
65 m_shearLayerThickness(solver->m_shearLayerThickness),
66 m_jetHeight(solver->m_jetHeight),
67 m_primaryJetRadius(solver->m_primaryJetRadius),
68 m_secondaryJetRadius(solver->m_secondaryJetRadius),
69 m_targetVelocityFactor(solver->m_targetVelocityFactor),
70 m_momentumThickness(solver->m_momentumThickness),
71 m_shearLayerStrength(solver->m_shearLayerStrength),
72 m_Ma(solver->m_Ma),
73 m_noSpecies(solver->m_noSpecies),
74 m_noRansEquations(solver->m_noRansEquations),
75 m_combustion(solver->m_combustion),
76 m_isEEGas(solver->m_isEEGas) {
77 TRACE();
78
79 const MLong oldAllocatedBytes = allocatedBytes();
80
81 m_solver = solver;
82 m_inflowTemperatureRatio = m_solver->m_inflowTemperatureRatio;
83
84 // TODO labels:FV,COMM this is a workaround, needs fixing! initBndryCommunications() is called multiple times for
85 // adaptation
86 m_comm_bc_init = 0;
87 m_comm_bcCo_init = 0;
88
89 m_noDirs = 2 * nDim;
90
91 m_noEdges = 2;
92 for(MInt i = 1; i < nDim; i++) {
93 m_noEdges *= (i + 1);
94 }
95 m_noLevelSetsUsedForMb = 1;
96 m_complexBoundaryMB = false;
97 m_cellCoordinatesCorrected = false;
98
99 if(m_solver->m_levelSetMb) {
109 m_complexBoundaryMB =
110 Context::getSolverProperty<MBool>("complexBoundaryForMb", m_solverId, AT_, &m_complexBoundaryMB);
111 if(m_complexBoundaryMB)
112 m_noLevelSetsUsedForMb =
113 Context::getSolverProperty<MInt>("maxNoLevelSets", m_solverId, AT_, &m_noLevelSetsUsedForMb);
114 }
115
116
117 m_gridCutTest = "SAT";
118 m_gridCutTest = Context::getSolverProperty<MString>("gridCutTest", m_solverId, AT_, &m_gridCutTest);
119
130 m_Bc3011WallTemperature = sysEqn().temperature_IR(m_Ma);
131 m_Bc3011WallTemperature =
132 Context::getSolverProperty<MFloat>("Bc3011WallTemperature", m_solverId, AT_, &m_Bc3011WallTemperature);
133
134 m_besselModes = 0;
135
136 // small cell treatment
137 m_createBoundaryAtCutoff = false;
138 m_volumeLimitWall = F1B2;
139 m_volumeLimitOther = F1B4;
140
152 m_sigmaNonRefl = F1;
153 m_sigmaNonRefl = Context::getSolverProperty<MFloat>("sigmaNonRefl", m_solverId, AT_, &m_sigmaNonRefl);
154
166 m_sigmaNonReflInflow = F1;
167 m_sigmaNonReflInflow =
168 Context::getSolverProperty<MFloat>("sigmaNonReflInflow", m_solverId, AT_, &m_sigmaNonReflInflow);
180 m_createBoundaryAtCutoff =
181 Context::getSolverProperty<MBool>("createBoundaryAtCutoff", m_solverId, AT_, &m_createBoundaryAtCutoff);
182 m_volumeLimitOther = Context::getSolverProperty<MFloat>("volumeLimitOther", m_solverId, AT_, &m_volumeLimitOther);
183
195 m_volumeLimitWall = Context::getSolverProperty<MFloat>("volumeLimitWall", m_solverId, AT_, &m_volumeLimitWall);
206 m_smallCellRHSCorrection = false;
207 m_smallCellRHSCorrection =
208 Context::getSolverProperty<MBool>("smallCellRHSCorrection", m_solverId, AT_, &m_smallCellRHSCorrection);
210 if(m_createBoundaryAtCutoff) {
211 m_changeAdiabBCToTemp = false;
212 m_changeAdiabBCToTemp =
213 Context::getSolverProperty<MBool>("changeAdiabBCToTemp", m_solverId, AT_, &m_changeAdiabBCToTemp);
214 }
215
230 m_multipleGhostCells = 0;
231 m_multipleGhostCells = Context::getSolverProperty<MInt>("multipleGhostCells", m_solverId, AT_, &m_multipleGhostCells);
232
233 m_ipVariableIterative = 0;
234 m_noImagePointIterations = 0;
235 m_surfaceGhostCell = 0;
236 m_outputIGPoints = 0;
237
238 if(m_multipleGhostCells != 0) {
253 m_ipVariableIterative =
254 Context::getSolverProperty<MInt>("ipVariableIterative", m_solverId, AT_, &m_ipVariableIterative);
255 if(m_ipVariableIterative != 0) {
265 m_noImagePointIterations = 10;
266 m_noImagePointIterations =
267 Context::getSolverProperty<MInt>("noImagePointIterations", m_solverId, AT_, &m_noImagePointIterations);
281 m_surfaceGhostCell = Context::getSolverProperty<MInt>("surfaceGhostCell", m_solverId, AT_, &m_surfaceGhostCell);
282
293 m_outputIGPoints = Context::getSolverProperty<MBool>("outputIGPoints", m_solverId, AT_, &m_outputIGPoints);
294 }
295
306 m_maxNoBndryCells = Context::getSolverProperty<MInt>("maxNoBndryCells", m_solverId, AT_);
307
308 if(m_multipleGhostCells || m_solver->m_useCreateCutFaceMGC || (m_complexBoundaryMB && m_noLevelSetsUsedForMb == 1))
309 mAlloc(m_bndryCells, m_maxNoBndryCells, nDim, m_noSpecies, m_noRansEquations, 3, 0, "m_bndryCells_3",
310 AT_); // each boundary cell may have 3 surfaces
311 else if(m_complexBoundaryMB)
312 mAlloc(m_bndryCells, m_maxNoBndryCells, nDim, m_noSpecies, m_noRansEquations, 12, 0, "m_bndryCells_12",
313 AT_); // each boundary cell may have 12 surfaces
314 else
315 mAlloc(m_bndryCells, m_maxNoBndryCells, nDim, m_noSpecies, m_noRansEquations, 1, 0, "m_bndryCells_1",
316 AT_); // each boundary cell may only have one surface!
317
318 // make sure that m_boundarySurfaces is intialized correctly!
319 m_bndryCell = m_bndryCells->a;
320 solver->m_bndryCells = m_bndryCells; // RUDIE particle code
321
322 mAlloc(m_smallBndryCells, m_maxNoBndryCells, "m_smallBndryCells", -1, AT_);
323 mAlloc(m_sortedBndryCells, m_maxNoBndryCells, "m_sortedBndryCells", -1, AT_);
324 mAlloc(m_sortedSpongeBndryCells, mMax(1, m_noMaxSpongeBndryCells), "m_sortedSpongeBndryCells", -1, AT_);
325 mAlloc(m_boundarySurfaces, nDim * m_maxNoBndryCells * FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces,
326 "m_boundarySurfaces", -1, AT_);
327 if(m_multipleGhostCells || m_solver->m_useCreateCutFaceMGC) {
328 mAlloc(m_bndryNghbrs, m_maxNoBndryCells * m_noDirs * 2, "m_bndryNghbrs", -1, AT_);
329 }
330
331
342 m_maxNoBndryCndIds = Context::getSolverProperty<MInt>("maxNoBndryCndIds", m_solverId, AT_);
343
344 m_cellMerging = false;
353 m_cellMerging = Context::getSolverProperty<MBool>("cellMerging", m_solverId, AT_, &m_cellMerging);
354
355 m_secondOrderRec = true;
363 m_secondOrderRec = Context::getSolverProperty<MBool>("secondOrderRec", m_solverId, AT_, &m_secondOrderRec);
364
372 m_noFluxRedistributionLayers = 2;
373 m_noFluxRedistributionLayers =
374 Context::getSolverProperty<MInt>("noFluxRedistributionLayers", m_solverId, AT_, &m_noFluxRedistributionLayers);
375 if(noDomains() > 1 && !m_cellMerging && (m_noFluxRedistributionLayers > m_solver->noHaloLayers())) {
376 cerr << "Warning: noHalo layers smaller than flux redistribution layers!" << endl;
377 }
378 m_nearBoundaryWindowCells = nullptr;
379 m_nearBoundaryHaloCells = nullptr;
380 if(!m_cellMerging) {
381 if(m_solver->noNeighborDomains() > 0) {
382 mAlloc(m_nearBoundaryWindowCells, m_solver->noNeighborDomains(), "m_nearBoundaryWindowCells", AT_);
383 mAlloc(m_nearBoundaryHaloCells, m_solver->noNeighborDomains(), "m_nearBoundaryHaloCells", AT_);
384 }
385 }
386
387 // reconstruction
388 mAlloc(m_reconstructionNghbrs, m_maxNoBndryCells, m_cells.noRecNghbrs(), "m_reconstructionNghbrs", -1, AT_);
389 mAlloc(m_reconstructionConstants, m_maxNoBndryCells, nDim * m_cells.noRecNghbrs(), "m_reconstructionConstants_BND",
390 F0, AT_);
391
392 // initialize
393 m_noBndryCndIds = 0;
394 m_noCutOffBndryCndIds = 0;
395
396 bndryCndHandlerVariables = 0;
397 bndryCndHandlerCutOffVariables = 0;
398 bndryCndHandlerCutOffInit = 0;
399 bndryCndHandlerSpongeVariables = 0;
400 // nonReflectingBoundaryCondition = 0;
401 nonReflectingCutOffBoundaryCondition = 0;
402 nonReflectingBoundaryConditionAfterTreatmentCutOff = 0;
403 bndryCndHandlerSlopesInviscid = 0;
404 bndryCndHandlerCutOffSlopesInviscid = 0;
405 bndryViscousSlopes = 0;
406 bndryCutOffViscousSlopes = 0;
407 bndryCndHandlerNeumann = 0;
408 bndryCndHandlerInit = 0;
409
410 /*
411 m_bndryCndIds = new MInt[ m_maxNoBndryCndIds ];
412 m_cutOffBndryCndIds = new MInt[ m_maxNoBndryCndIds ];
413 for(MInt i = 0; i < m_maxNoBndryCndIds; i++){
414 m_bndryCndIds[ i ] = 0;
415 m_cutOffBndryCndIds[ i ] = 0;
416 }
417 m_bndryCndCells = new MInt[ m_maxNoBndryCndIds+1 ];
418 m_spongeBndryCells = new MInt[ m_maxNoBndryCndIds+1 ];
419 for(MInt i = 0; i < m_maxNoBndryCndIds+1; i++){
420 m_bndryCndCells[ i ] = 0;
421 m_spongeBndryCells[ i ] = 0;
422 }
423 */
424 mAlloc(m_bndryCndIds, m_maxNoBndryCndIds, "m_bndryCndIds", 0, AT_);
425 mAlloc(m_cutOffBndryCndIds, m_maxNoBndryCndIds, "m_cutOffBndryCndIds", 0, AT_);
426 mAlloc(m_bndryCndCells, m_maxNoBndryCndIds + 1, "m_bndryCndCells", 0, AT_);
427 mAlloc(m_spongeBndryCells, m_maxNoBndryCndIds + 1, "m_spongeBndryCells", 0, AT_);
428
437 m_jetInletTurbulence = false;
438 m_jetInletTurbulence =
439 Context::getSolverProperty<MBool>("jetInletTurbulence", m_solverId, AT_, &m_jetInletTurbulence);
440
441 m_cutCandidates.clear();
442 m_geometryIntersection = new GeometryIntersection<nDim>(&m_solver->grid(), m_solver->m_geometry);
443
444 printAllocatedMemory(oldAllocatedBytes, "FvBndryCndXD", solver->globalMpiComm());
445}
446
447
448template <MInt nDim, class SysEqn>
450 TRACE();
451
452 // Clean up allocated memory
453 mDeallocate(m_bndryCells);
454 mDeallocate(m_smallBndryCells);
455 mDeallocate(m_sortedBndryCells);
456 mDeallocate(m_sortedSpongeBndryCells);
457 mDeallocate(m_boundarySurfaces);
458 mDeallocate(m_bndryNghbrs);
459 mDeallocate(m_nearBoundaryWindowCells);
460 mDeallocate(m_nearBoundaryHaloCells);
461 mDeallocate(m_reconstructionNghbrs);
462 mDeallocate(m_reconstructionConstants);
463 mDeallocate(m_bndryCndIds);
464 mDeallocate(m_cutOffBndryCndIds);
465 mDeallocate(m_bndryCndCells);
466 mDeallocate(m_spongeBndryCells);
467}
468
469
470//----------------------------------------------------------------------------
471
472
473template <MInt nDim, class SysEqn>
475 TRACE();
476
477 MInt bc;
478 MInt size;
479 MInt noBndryCells = m_bndryCells->size();
480 MBool append = false;
481 //---
482
483 m_bndryCndCells[m_noBndryCndIds] = noBndryCells;
484 m_sortedBndryCells->setSize(0);
485 size = 0;
486 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
487 m_bndryCndCells[bcId] = size;
488 bc = m_bndryCndIds[bcId];
489 for(MInt id = 0; id < noBndryCells; id++) {
490 append = false;
491 for(MInt srfc = 0; srfc < m_bndryCells->a[id].m_noSrfcs; srfc++) {
492 if(m_bndryCells->a[id].m_srfcs[srfc]->m_bndryCndId == bc) {
493 append = true;
494 break;
495 }
496 }
497 if(append) {
498 m_sortedBndryCells->append();
499 m_sortedBndryCells->a[size] = id;
500 size++;
501 }
502 // //Debug
503 // MInt cellId = m_bndryCells->a[ m_sortedBndryCells->a[ bcId ] ].m_cellId;
504 // std::cout << "createSortedBndryCellList CellTemp: " << m_solver->a_pvariable(cellId,PV->P) <<
505 // std::endl;
506 }
507 }
508 m_bndryCndCells[m_noBndryCndIds] = size;
509}
511
512//-----------------------------------------------------------------------------
513
514
515// resets the cell center coordinates of boundary cells to the grid cell position
516template <MInt nDim, class SysEqn>
518 TRACE();
519
520 MInt noCells = m_bndryCells->size();
521 //---
522
523 for(MInt id = 0; id < noCells; id++) {
524 for(MInt i = 0; i < nDim; i++) {
525 m_solver->a_coordinate(m_bndryCells->a[id].m_cellId, i) += m_bndryCells->a[id].m_coordinates[i];
526 }
527 }
528 ASSERT(!m_cellCoordinatesCorrected, "Irregular sequence of cell-coordinate correction!");
529 m_cellCoordinatesCorrected = true;
530}
531
532
533//-----------------------------------------------------------------------------
534
535
536// resets the cell center coordinates of boundary cells to the boundary cell position
537template <MInt nDim, class SysEqn>
539 TRACE();
540
541 MInt smallCell = 0;
542 MInt masterId;
543 MInt noCells = m_bndryCells->size();
544 MInt noSmallCells = m_smallBndryCells->size();
545 //---
546
547 for(MInt id = 0; id < noCells; id++) {
548 for(MInt i = 0; i < nDim; i++) {
549 m_solver->a_coordinate(m_bndryCells->a[id].m_cellId, i) -= m_bndryCells->a[id].m_coordinates[i];
550 }
551 }
552 // recorrect all coordinates of internal master cells
553 for(MInt smallId = 0; smallId < noSmallCells; smallId++) {
554 smallCell = m_smallBndryCells->a[smallId];
555 masterId = m_bndryCells->a[smallCell].m_linkedCellId;
556 if(m_solver->a_bndryId(masterId) == -1) {
557 for(MInt i = 0; i < nDim; i++) {
558 m_solver->a_coordinate(masterId, i) = m_bndryCells->a[smallCell].m_masterCoordinates[i];
559 }
560 }
561 }
562 ASSERT(m_cellCoordinatesCorrected, "Irregular sequence of cell-coordinate correction!");
563 m_cellCoordinatesCorrected = false;
564}
565
566// resets the cell center coordinates of boundary cells to the grid cell position
567template <MInt nDim, class SysEqn>
569 TRACE();
570
571 const MInt noCells = m_bndryCells->size();
572 const MInt noSmallCells = m_smallBndryCells->size();
573 //---
575 for(MInt id = 0; id < noCells; id++) {
576 for(MInt i = 0; i < nDim; i++) {
577 m_solver->a_coordinate(m_bndryCells->a[id].m_cellId, i) += m_bndryCells->a[id].m_coordinates[i];
578 }
580 // rerecorrect all coordinates of internal master cells
581 for(MInt smallId = 0; smallId < noSmallCells; smallId++) {
582 const MInt smallCell = m_smallBndryCells->a[smallId];
583 const MInt smallCellId = m_bndryCells->a[smallCell].m_cellId;
584 const MInt masterId = m_bndryCells->a[smallCell].m_linkedCellId;
585 if(m_solver->a_bndryId(masterId) == -1) {
586 for(MInt i = 0; i < nDim; i++) {
587 m_solver->a_coordinate(masterId, i) = m_solver->a_coordinate(smallCellId, i);
588 }
590 }
591 ASSERT(!m_cellCoordinatesCorrected, "Irregular sequence of cell-coordinate correction!");
592 m_cellCoordinatesCorrected = true;
593}
596// ------------------------------------------------------------------------
597
598
605template <MInt nDim, class SysEqn>
607 TRACE();
608
609 // initialize all cells as internal cells
610 for(MInt id = 0; id < m_solver->a_noCells(); id++) {
611 m_solver->a_bndryId(id) = -1;
612 }
614 // correct the entries of boundary cells
615 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
616 m_solver->a_bndryId(m_bndryCells->a[bndryId].m_cellId) = bndryId;
620
621//-----------------------------------------------------------------------------------------
622
623
624template <MInt nDim, class SysEqn>
626 TRACE();
627 m_solver->m_associatedInternalCells.clear();
628 m_solver->m_totalnoghostcells = 0;
629 //---
631 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
632 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
633 // append a cell to the cell-collectors only!
634 m_cells.append();
635 m_solver->m_totalnoghostcells++;
636 const MInt ghostCellId = m_solver->a_noCells() - 1;
637 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId = ghostCellId;
638
639#ifdef mirroredGhostCell
640 // calculate the global coordinates of the ghost point as a mirror image of
641 // the center of gravity of the concerning boundary cell to the body surface
642 // compute the connection vector between the center of the gravity of the
643 // boundary cell and the center of the body surface
644 for(MInt i = 0; i < nDim; i++) {
645 connectionVctr[i] = m_solver->a_coordinate(m_bndryCells->a[bndryId].m_cellId, i)
646 - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i];
649 // to compute the distance, project the connection vector into the normal
650 // vector by using a scalar product
651 distance = F0;
652 for(MInt i = 0; i < nDim; i++) {
653 distance += connectionVctr[i] * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
655 distance = fabs(distance);
657 // the ghost coordinates are found if the double distance is added to the
658 // center of gravity of the boundary cell in negative direction of the
659 // normal vector of the body surface
660 for(MInt i = 0; i < nDim; i++) {
661 m_solver->a_coordinate(ghostCellId, i) =
662 m_solver->a_coordinate(m_bndryCells->a[bndryId].m_cellId, i)
663 - 2.0 * distance * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
664 }
665#else
666 // compute the ghost cell coordinates (new version)
667 for(MInt i = 0; i < nDim; i++) {
668 m_solver->a_coordinate(ghostCellId, i) = F2 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]
669 - m_solver->a_coordinate(m_bndryCells->a[bndryId].m_cellId, i);
671#endif
672
673 if(!m_cellMerging) {
674 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
675 const MFloat cellHalfLength = F1B2 * m_solver->c_cellLengthAtCell(cellId);
676 MFloat dn = F0;
677 for(MInt i = 0; i < nDim; i++) {
678 dn += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
679 * (m_solver->a_coordinate(cellId, i) - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]);
680 }
681 for(MInt i = 0; i < nDim; i++) {
682 // m_solver->a_coordinate( ghostCellId , i ) = m_solver->a_coordinate( cellId , i ) - ( dn + cellHalfLength
683 // ) * m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_normalVector[ i ]; use mirrored coords if dn > dx/2:
684 m_solver->a_coordinate(ghostCellId, i) =
685 m_solver->a_coordinate(cellId, i)
686 - mMax(F2 * dn, dn + cellHalfLength) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
688 }
689
690 m_solver->a_noReconstructionNeighbors(ghostCellId) = 0;
691 m_solver->a_level(ghostCellId) = m_solver->a_level(m_bndryCells->a[bndryId].m_cellId);
692
693 // grid-cell properties:
694 /* m_solver->c_globalId(ghostCellId) = -1;
695
696 // set all possible child ids of the newly created cell to -1
697 for( MInt ccId = 0; ccId < IPOW2(nDim); ccId++)
698 m_solver->c_childId( ghostCellId , ccId ) = -1;
699
700 m_solver->c_parentId(ghostCellId) = -1;
701 */
702 // set pointer to cellId
703 m_solver->m_associatedInternalCells.push_back(m_bndryCells->a[bndryId].m_cellId);
704
705 // mark a ghost cell in m_bndryCellIds and the cell collector
706 m_solver->a_bndryId(ghostCellId) = -2;
707 m_solver->a_isBndryGhostCell(ghostCellId) = true;
708
709 ASSERT(m_solver->a_level(ghostCellId) == m_solver->a_level(m_solver->getAssociatedInternalCell(ghostCellId)), "");
711 }
712}
713
714
715//-----------------------------------------------------------------------------------------
716
717
728template <MInt nDim, class SysEqn>
730 TRACE();
731
732 MFloat dist = F0;
733 ofstream ofl;
734 ofstream ofl2;
735 if(m_outputIGPoints) {
736 const MChar* filename = "imagePoints_";
737 stringstream filename2;
738 filename2 << filename << domainId() << ".vtk";
739 ofl.open((filename2.str()).c_str(), ofstream::trunc);
740 const MChar* filename3 = "ghostPoints";
741 stringstream filename4;
742 filename4 << filename3 << domainId() << ".vtk";
743 ofl2.open((filename4.str()).c_str(), ofstream::trunc);
744 }
745
746 MInt noImagePoints = 0;
747 //---
748
749 m_solver->m_associatedInternalCells.clear();
750 m_solver->m_totalnoghostcells = 0;
751
752 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
753 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
754 // append a cell to the fv-cell-collectors
755 m_cells.append();
756 m_solver->m_totalnoghostcells++;
757
758 // initialize m_bndryCellIds
759 m_solver->a_bndryId(m_solver->a_noCells() - 1) = -2;
760
761 const MInt ghostCellId = m_solver->a_noCells() - 1;
762
763 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId = ghostCellId;
764
765
766 if(m_solver->a_hasProperty(m_bndryCells->a[bndryId].m_cellId, SolverCell::IsOnCurrentMGLevel)) {
767 // if(m_solver->a_hasProperty(m_bndryCells->a[ bndryId ].m_cellId, SolverCell::IsActive))
768 MInt gridcellId = m_bndryCells->a[bndryId].m_cellId;
769 if(m_solver->a_hasProperty(gridcellId, SolverCell::IsSplitClone)) {
770 gridcellId = m_solver->m_splitChildToSplitCell.find(gridcellId)->second;
771 }
772 if(m_solver->c_noChildren(gridcellId) == 0) noImagePoints++;
773 }
775 // compute geometric data of the ghost cell
777 // compute ImagePoint coordinates
778 dist = F0;
779 for(MInt i = 0; i < nDim; i++) {
780 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[i] =
781 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i];
782 m_solver->a_coordinate(ghostCellId, i) = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i];
784 dist += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
785 * (m_solver->a_coordinate(m_bndryCells->a[bndryId].m_cellId, i)
786 - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]);
787 }
788 dist = fabs(dist);
789 if(m_surfaceGhostCell != 0) {
790 for(MInt i = 0; i < nDim; i++) {
791 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[i] +=
792 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i] * dist;
794 } else {
795 for(MInt i = 0; i < nDim; i++) {
796 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[i] +=
797 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i] * dist;
798 m_solver->a_coordinate(ghostCellId, i) -= m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i] * dist;
799 }
801
802 // init Ghost cell properties
803 m_solver->a_noReconstructionNeighbors(ghostCellId) = 0;
804 m_solver->a_level(ghostCellId) = m_solver->a_level(m_bndryCells->a[bndryId].m_cellId);
806 // set pointer to cellId
807 m_solver->m_associatedInternalCells.push_back(m_bndryCells->a[bndryId].m_cellId);
808 m_solver->a_isBndryGhostCell(ghostCellId) = true;
809 }
811
812 // if required write out image and ghost points to a .vtk data file
813 if(m_outputIGPoints) {
814 if(ofl && ofl2) {
815 ofl.setf(ios::fixed);
816 ofl.precision(7);
817 ofl2.setf(ios::fixed);
818 ofl2.precision(7);
819
820 ofl << "# vtk DataFile Version 3.0" << endl
821 << "MAIAD imagePoints file" << endl
822 << "ASCII" << endl
823 << "DATASET POLYDATA" << endl
824 << "POINTS " << noImagePoints << " float" << endl;
826 ofl2 << "# vtk DataFile Version 3.0" << endl
827 << "MAIAD ghostPoints file" << endl
828 << "ASCII" << endl
829 << "DATASET POLYDATA" << endl
830 << "POINTS " << noImagePoints << " float" << endl;
832 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
833 if(!m_solver->a_hasProperty(m_bndryCells->a[bndryId].m_cellId, SolverCell::IsOnCurrentMGLevel)) continue;
834 // if(!m_solver->a_hasProperty(m_bndryCells->a[ bndryId ].m_cellId, SolverCell::IsActive))
835 // continue;
836 if(m_solver->c_noChildren(m_bndryCells->a[bndryId].m_cellId) > 0) continue;
837 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
838 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
839 for(MInt i = 0; i < 3; i++) {
840 ofl << m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[i] << " ";
841 ofl2 << m_solver->a_coordinate(ghostCellId, i) << " ";
842 }
843 ofl << endl;
844 ofl2 << endl;
845 }
846 }
847
848 ofl << "VERTICES " << noImagePoints << " " << noImagePoints * 2 << endl;
849 ofl2 << "VERTICES " << noImagePoints << " " << noImagePoints * 2 << endl;
850 for(MInt i = 0; i < noImagePoints; i++) {
851 ofl << "1 " << i << endl;
852 ofl2 << "1 " << i << endl;
856 ofl.close();
857 ofl2.close();
858 }
859}
860
861
862//-----------------------------------------------------------------------------------------
865/*template <MInt nDim, class SysEqn>
866void FvBndryCndXD<nDim,SysEqn>::correctGhostCells()
867{
868 TRACE();
869
870 MInt cellId,ghostCellId;
871 MInt direction,spaceId=0,sideId;
872 const MInt noCells = m_bndryCells->size();
873 MFloat dist;
874 //---
875 // Warning: produces slightly non symmetric field
876 for( MInt bc=0; bc<noCells; bc++ ) {
877 if( m_bndryCells->a[ bc ].m_srfcs[0]->m_bndryCndId == 3904 ) {
878 cellId = m_bndryCells->a[ bc ].m_cellId;
879 for( MInt i=0; i<nDim; i++ ) {
880 m_solver->a_coordinate( cellId , i ) -= m_bndryCells->a[ bc ].m_coordinates[ i ];
881 m_bndryCells->a[ bc ].m_coordinates[ i ] = F0;
882 }
883 dist = m_solver->c_cellLengthAtCell(cellId);
884 ghostCellId = m_bndryCells->a[ bc ].m_srfcVariables[0]->m_ghostCellId;
885 for( MInt d=0; d<m_noDirs; d++ ) {
886 if( m_solver->a_hasNeighbor( cellId , d) > 0 )
887 continue;
888 direction = d;
889 spaceId = direction / 2;
890 sideId = direction % 2;
891 dist *= (MFloat)( 2*sideId - 1 );
892 break;
893 }
894 for( MInt i=0; i<nDim; i++ )
895 if( i != spaceId )
896 m_solver->a_coordinate( ghostCellId , i ) = m_solver->a_coordinate( cellId , i );
897 else
898 m_solver->a_coordinate( ghostCellId , i ) = m_solver->a_coordinate( cellId , i ) + dist;
899 }
900 }
901}*/
902
903
904//-----------------------------------------------------------------------------------------
905
906
907template <MInt nDim, class SysEqn>
909 // TRACE();
910
911 MFloat distance = 0;
912 //---
913
914 for(MInt i = 0; i < nDim; i++) {
915 x[i] = m_solver->a_coordinate(m_bndryCells->a[bndryId].m_cellId, i)
916 - m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i];
917 }
918
919 for(MInt i = 0; i < nDim; i++) {
920 distance += x[i] * m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i];
921 }
922 distance = fabs(distance);
923 for(MInt i = 0; i < nDim; i++) {
924 x[i] = m_solver->a_coordinate(m_bndryCells->a[bndryId].m_cellId, i)
925 - F2 * distance * m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i];
926 }
927}
928
929//-----------------------------------------------------------------------------------------
930
931
932template <MInt nDim, class SysEqn>
934 // TRACE();
935
936 MFloat distance = 0;
937 //---
938
939 for(MInt i = 0; i < nDim; i++) {
940 x[i] = m_solver->a_coordinate(m_bndryCells->a[bndryId].m_cellId, i)
941 - m_bndryCells->a[bndryId].m_srfcs[srfcId]->m_coordinates[i];
942 }
943
944 for(MInt i = 0; i < nDim; i++) {
945 distance += x[i] * m_bndryCells->a[bndryId].m_srfcs[srfcId]->m_normalVector[i];
946 }
947 distance = fabs(distance);
948 for(MInt i = 0; i < nDim; i++) {
949 x[i] = m_solver->a_coordinate(m_bndryCells->a[bndryId].m_cellId, i)
950 - F2 * distance * m_bndryCells->a[bndryId].m_srfcs[srfcId]->m_normalVector[i];
951 }
952}
953
954
955//-----------------------------------------------------------------------------------------
956
957
962template <MInt nDim, class SysEqn>
964 TRACE();
965
966 MBool cellOk = false;
967 MInt cellId, ghostCellId;
968 MInt noCells = m_bndryCells->size();
969 MInt srfcId = 0;
970 MFloat epsilon = pow(10.0, -13.0);
971 //---
972
973 m_noBoundarySurfaces = 0;
974
975 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
976 cellOk = false;
977
978 for(MInt srfc = 0; srfc < FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces; srfc++) {
979 for(MInt i = 0; i < nDim; i++)
980 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = -1;
981 }
982
983 // do not consider grid halo cells; only those which have a non-halo cell as master
984 // do not consider small cells with a boundary cell as master
985 if(m_solver->a_isHalo(m_bndryCells->a[bndryId].m_cellId)) {
986 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) {
987 if(m_solver->a_bndryId(m_bndryCells->a[bndryId].m_linkedCellId) == -1
988 && !m_solver->a_isHalo(m_bndryCells->a[bndryId].m_linkedCellId))
989 cellOk = true;
990 }
991 } else {
992 if(m_bndryCells->a[bndryId].m_linkedCellId == -1) {
993 cellOk = true;
994 } else {
995 if(m_solver->a_bndryId(m_bndryCells->a[bndryId].m_linkedCellId) == -1) {
996 cellOk = true;
997 }
998 }
999 }
1000
1001 if(cellOk) {
1002 ASSERT(m_bndryCells->a[bndryId].m_noSrfcs == 1, "noSrfc: " << m_bndryCells->a[bndryId].m_noSrfcs
1003 << " bndryId: " << bndryId << " noCutPoints "
1004 << m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints);
1005 cellId = m_bndryCells->a[bndryId].m_cellId;
1006 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
1007 if((m_solver->c_noChildren(cellId) == 0 && m_solver->a_level(cellId) <= m_solver->maxRefinementLevel())
1008 || (m_solver->c_noChildren(cellId) > 0 && m_solver->a_level(cellId) == m_solver->maxRefinementLevel())) {
1009 // create one surface per space direction
1010 for(MInt i = 0; i < nDim; i++) {
1011 // if the surface is inclined, replace it by its projections into the
1012 // Cartesian frame of reference
1013 if(fabs(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i]) > epsilon) {
1014 m_surfaces.append();
1015 srfcId = m_solver->a_noSurfaces() - 1;
1016
1017 // add the boundary surface
1018 m_boundarySurfaces[m_noBoundarySurfaces] = srfcId;
1019 m_noBoundarySurfaces++;
1020
1021 // set the boundary condition
1022 m_solver->a_surfaceBndryCndId(srfcId) = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
1023
1024 // the coordinates of the new surface are shifted...
1025 for(MInt j = 0; j < nDim; j++) {
1026 m_solver->a_surfaceCoordinate(srfcId, j) = m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[j];
1027 }
1028
1029 // projection to compute the area of the surface
1030 m_solver->a_surfaceArea(srfcId) = m_bndryCells->a[bndryId].m_srfcs[0]->m_area
1031 * fabs(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i]);
1032
1033 // set the surface orientation
1034 m_solver->a_surfaceOrientation(srfcId) = i;
1035
1036 ASSERT(ghostCellId > -1, "");
1037
1038 // set the surface neigbors
1039 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] > F0) {
1040 m_solver->a_surfaceNghbrCellId(srfcId, 0) = ghostCellId;
1041 m_solver->a_surfaceNghbrCellId(srfcId, 1) = cellId;
1042 } else {
1043 m_solver->a_surfaceNghbrCellId(srfcId, 1) = ghostCellId;
1044 m_solver->a_surfaceNghbrCellId(srfcId, 0) = cellId;
1045 }
1046
1047 // set the pointer from the body surface to the cartesian surfaces
1048 m_bndryCells->a[bndryId].m_srfcVariables[0]->m_srfcId[i] = srfcId;
1049 }
1050 }
1051 }
1052 }
1053 }
1054}
1055
1056
1057//-----------------------------------------------------------------------------------------
1058
1059
1067template <MInt nDim, class SysEqn>
1069 TRACE();
1070
1071 MBool cellOk;
1072 MInt cellId, ghostCellId;
1073 MInt noCells = m_bndryCells->size();
1074 MInt srfcId = 0;
1075 MFloat epsilon = pow(10.0, -20.0);
1076 //---
1077
1078 m_noBoundarySurfaces = 0;
1079
1080 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
1081 cellOk = false;
1082
1083 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
1084 for(MInt i = 0; i < nDim; i++) {
1085 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = -1;
1086 }
1087 }
1088
1089 if(m_solver->a_hasProperty(m_bndryCells->a[bndryId].m_cellId, SolverCell::IsInvalid)) continue;
1090
1091 // do not consider grid halo cells; only those which have a non-halo cell as master
1092 if(m_solver->a_isHalo(m_bndryCells->a[bndryId].m_cellId)) {
1093 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) {
1094 if(!m_solver->a_isHalo(m_bndryCells->a[bndryId].m_linkedCellId)) cellOk = true;
1095 }
1096 } else {
1097 cellOk = true;
1098 }
1099
1100 if(cellOk) {
1101 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
1102 cellId = m_bndryCells->a[bndryId].m_cellId;
1103 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
1104 MInt gridcellId = cellId;
1105 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitClone)) {
1106 gridcellId = m_solver->m_splitChildToSplitCell.find(cellId)->second;
1107 }
1108 if((m_solver->c_noChildren(gridcellId) == 0 && m_solver->a_level(cellId) <= m_solver->maxRefinementLevel())
1109 || (m_solver->c_noChildren(gridcellId) > 0 && m_solver->a_level(cellId) == m_solver->maxRefinementLevel())) {
1110 // create one surface per space direction
1111 for(MInt i = 0; i < nDim; i++) {
1112 // if the surface is inclined, replace it by its projections into the
1113 // Cartesian frame of reference
1114 if(fabs(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]) > epsilon) {
1115 m_surfaces.append();
1116 srfcId = m_solver->a_noSurfaces() - 1;
1117
1118 // add the boundary surface
1119 m_boundarySurfaces[m_noBoundarySurfaces] = srfcId;
1120 m_noBoundarySurfaces++;
1121
1122 // set the boundary condition
1123 m_solver->a_surfaceBndryCndId(srfcId) = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId;
1124
1125 // the coordinates of the new surface are shifted...
1126 for(MInt j = 0; j < nDim; j++) {
1127 m_solver->a_surfaceCoordinate(srfcId, j) = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[j];
1128 }
1129
1130 // projection to compute the area of the surface
1131 m_solver->a_surfaceArea(srfcId) = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
1132 * fabs(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]);
1133
1134 // set the surface orientation
1135 m_solver->a_surfaceOrientation(srfcId) = i;
1136
1137 // set the surface neigbors
1138 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i] > F0) {
1139 m_solver->a_surfaceNghbrCellId(srfcId, 0) = ghostCellId;
1140 m_solver->a_surfaceNghbrCellId(srfcId, 1) = cellId;
1141 } else {
1142 m_solver->a_surfaceNghbrCellId(srfcId, 1) = ghostCellId;
1143 m_solver->a_surfaceNghbrCellId(srfcId, 0) = cellId;
1144 }
1145
1146 // set the pointer from the body surface to the cartesian surfaces
1147 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = srfcId;
1148 }
1149 }
1150 }
1151 }
1152 }
1153 }
1154}
1155
1156
1157//-----------------------------------------------------------------------------------------
1158
1170template <MInt nDim, class SysEqn>
1172 TRACE();
1173
1174 const MInt noBndrySurfaces = m_noBoundarySurfaces;
1175 const MInt noVars = CV->noVariables;
1176 const MInt surfaceVarMemory = m_solver->m_surfaceVarMemory;
1177 MFloat* surfaceVar = (MFloat*)(&(m_solver->a_surfaceVariable(0, 0, 0)));
1178 MInt nghbr0, nghbr1, bndryId, ghostSurf;
1179 //---
1180
1181#ifdef _OPENMP
1182#pragma omp parallel for
1183#endif
1184 for(MInt bs = 0; bs < noBndrySurfaces; bs++) {
1185 nghbr0 = m_solver->a_surfaceNghbrCellId(m_boundarySurfaces[bs], 0);
1186 nghbr1 = m_solver->a_surfaceNghbrCellId(m_boundarySurfaces[bs], 1);
1187 if(m_solver->a_isBndryGhostCell(nghbr0)) {
1188 bndryId = m_solver->a_bndryId(m_solver->getAssociatedInternalCell(nghbr0));
1189 ghostSurf = 0;
1190 for(MInt srfcId = 0; srfcId < m_bndryCells->a[bndryId].m_noSrfcs; srfcId++) {
1191 if(m_bndryCells->a[bndryId].m_srfcVariables[srfcId]->m_ghostCellId == nghbr0) {
1192 ghostSurf = srfcId;
1193 break;
1194 }
1195 }
1196 // set left an right value to ghost cell value and image value, respectively
1197 // for( MInt var = 0; var < noVars; var++ ) {
1198 // surfaceVar[ m_boundarySurfaces[bs]*surfaceVarMemory + var ] =
1199 // m_solver->a_pvariable( nghbr0 , var );
1200 // surfaceVar[ m_boundarySurfaces[bs]*surfaceVarMemory + noVars + var ] =
1201 // m_bndryCells->a[bndryId].m_srfcVariables[ghostSurf]->m_imageVariables[var];
1202 // }
1203 // set both left and right value to mean of ghost cell value and image value
1204 for(MInt var = 0; var < noVars; var++) {
1205 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + var] =
1206 F1B2
1207 * (m_solver->a_pvariable(nghbr0, var)
1208 + m_bndryCells->a[bndryId].m_srfcVariables[ghostSurf]->m_imageVariables[var]);
1209 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + noVars + var] =
1210 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + var];
1211 }
1212 } else if(m_solver->a_isBndryGhostCell(nghbr1)) {
1213 bndryId = m_solver->a_bndryId(m_solver->getAssociatedInternalCell(nghbr1));
1214 ghostSurf = 0;
1215 for(MInt srfcId = 0; srfcId < m_bndryCells->a[bndryId].m_noSrfcs; srfcId++) {
1216 if(m_bndryCells->a[bndryId].m_srfcVariables[srfcId]->m_ghostCellId == nghbr1) {
1217 ghostSurf = srfcId;
1218 break;
1219 }
1220 }
1221 // set right an left value to ghost cell value and image value, respectively
1222 // for( MInt var = 0; var < noVars; var++ ) {
1223 // surfaceVar[ m_boundarySurfaces[bs]*surfaceVarMemory + var ] =
1224 // m_solver->a_pvariable( nghbr1 , var );
1225 // surfaceVar[ m_boundarySurfaces[bs]*surfaceVarMemory + noVars + var ] =
1226 // m_bndryCells->a[bndryId].m_srfcVariables[ghostSurf]->m_imageVariables[var];
1227 // }
1228 // set both left and right value to mean of ghost cell value and image value
1229 for(MInt var = 0; var < noVars; var++) {
1230 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + var] =
1231 F1B2
1232 * (m_solver->a_pvariable(nghbr1, var)
1233 + m_bndryCells->a[bndryId].m_srfcVariables[ghostSurf]->m_imageVariables[var]);
1234 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + noVars + var] =
1235 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + var];
1236 }
1237 } else
1238 cerr << "[ " << domainId() << " ]"
1239 << " Error in FvBndryCndXD::correctBoundarySurfaceVariablesMGC; This case should not occur! "
1240 << " surface " << m_boundarySurfaces[bs] << " has no ghost cell neighbor! "
1241 << "neighbors: " << nghbr0 << " " << nghbr1 << endl;
1242 }
1243}
1244
1245//-----------------------------------------------------------------------------------------
1246
1257template <MInt nDim, class SysEqn>
1259 TRACE();
1260
1261 const MInt noBndrySurfaces = m_noBoundarySurfaces;
1262 const MInt noVars = CV->noVariables;
1263 const MInt surfaceVarMemory = m_solver->m_surfaceVarMemory;
1264 MFloat* surfaceVar = (MFloat*)(&(m_solver->a_surfaceVariable(0, 0, 0)));
1265 MInt nghbr0, nghbr1;
1266 //---
1267
1268#ifdef _OPENMP
1269#pragma omp parallel for
1270#endif
1271 for(MInt bs = 0; bs < noBndrySurfaces; bs++) {
1272 nghbr0 = m_solver->a_surfaceNghbrCellId(m_boundarySurfaces[bs], 0);
1273 nghbr1 = m_solver->a_surfaceNghbrCellId(m_boundarySurfaces[bs], 1);
1274 if(m_solver->a_isBndryGhostCell(nghbr0)) {
1275 for(MInt var = 0; var < noVars; var++) {
1276 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + var] = m_solver->a_pvariable(nghbr0, var);
1277 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + noVars + var] = m_solver->a_pvariable(nghbr0, var);
1278 }
1279 } else if(m_solver->a_isBndryGhostCell(nghbr1)) {
1280 for(MInt var = 0; var < noVars; var++) {
1281 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + var] = m_solver->a_pvariable(nghbr1, var);
1282 surfaceVar[m_boundarySurfaces[bs] * surfaceVarMemory + noVars + var] = m_solver->a_pvariable(nghbr1, var);
1283 }
1284 } else
1285 cerr << "[ " << domainId() << " ]"
1286 << " Error in FvBndryCndXD::correctBoundarySurfaceVariablesMGCSurface; This case should not occur! "
1287 << " surface " << m_boundarySurfaces[bs] << " has no ghost cell neighbor! "
1288 << "neighbors: " << nghbr0 << " " << nghbr1 << endl;
1289 }
1290}
1291
1292
1293//-----------------------------------------------------------------------------
1294
1295
1296template <MInt nDim, class SysEqn>
1298 TRACE();
1299
1300 // loop over all different boundary conditions
1301 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
1302 (this->*bndryCndHandlerNeumann[bcId])(bcId);
1303 }
1304
1305 copySlopesToSmallCells();
1306
1307 if(!m_cellMerging) storeBoundaryVariables();
1308}
1309
1310
1311//-----------------------------------------------------------------------------
1312template <MInt nDim, class SysEqn>
1314 TRACE();
1315
1316 const MInt noBndryCells = m_bndryCells->size();
1317 const MInt noPVars = PV->noVariables;
1318#ifndef NDEBUG
1319 MInt nanCounter = 0;
1320 const MInt nanCounterMax = 5 * noPVars;
1321#endif
1322
1323#ifdef _OPENMP
1324#pragma omp parallel for
1325#endif
1326 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
1327 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
1328 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
1329 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
1330 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
1331 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
1332 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
1333 for(MInt v = 0; v < noPVars; v++) {
1334 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v] =
1335 F1B2 * (m_solver->a_pvariable(ghostCellId, v) + m_solver->a_pvariable(cellId, v));
1336#ifndef NDEBUG
1337 if(std::isnan(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v]) && nanCounter < nanCounterMax) {
1338 cerr << domainId() << ": nan detected in boundary surface var " << v << " " << cellId << " ("
1339 << m_solver->c_globalId(cellId) << ") " << ghostCellId << " halo:" << m_solver->a_isHalo(cellId)
1340 << " (" << m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient) << ")"
1341 << " /vars " << m_solver->a_pvariable(ghostCellId, v) << " " << m_solver->a_pvariable(cellId, v) << " "
1342 << m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v] << " ("
1343 << &m_solver->a_pvariable(cellId, v) << ")"
1344 << " /coords " << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1) << " "
1345 << m_solver->a_coordinate(cellId, 2) << " /bndCnd " << m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId
1346 << " /lvl " << m_solver->a_level(cellId) << " /halo " << m_solver->a_isHalo(cellId) << endl;
1347 nanCounter++;
1348 if(nanCounter == nanCounterMax) {
1349 cerr << domainId() << ": nan detected in boundary surface ... skipping further output" << std::endl;
1350 }
1351 }
1352#endif
1353 }
1354
1355 ASSERT((approx(sysEqn().temperature_ES(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO],
1356 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P]),
1357 m_Bc3011WallTemperature, F5 * MFloatEps))
1358 || (m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId != 3011 || isDetChem<SysEqn>),
1359 "isothermal wall 3011 fail");
1360 }
1361#ifdef _OPENMP
1362#pragma omp critical
1363 {
1364#endif
1365 MFloatScratchSpace dummyPvariables(m_bndryCells->a[bndryId].m_noSrfcs, PV->noVariables, AT_, "dummyPvariables");
1366 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
1367 // if ( m_bndryCell[ bndryId ].m_srfcs[srfc]->m_bndryCndId / 1000 != 3 ) continue;
1368 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
1369 MFloat normal[3] = {F0, F0, F0};
1370 for(MInt i = 0; i < nDim; i++) {
1371 normal[i] = m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i];
1372 }
1373 /*MFloat cnt = F0;
1374 for ( MInt i = 0; i < nDim; i++ ) {
1375 normal[i] = m_solver->a_coordinate( cellId , i ) - m_solver->a_coordinate( ghostCellId , i );
1376 cnt += POW2(normal[i]);
1377 }
1378 cnt = sqrt(cnt);
1379 for ( MInt i = 0; i < nDim; i++ ) {
1380 normal[i] /= cnt;
1381 }*/
1382 for(MInt v = 0; v < noPVars; v++) {
1383 if(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] == BC_DIRICHLET) {
1384 for(MInt s = 0;
1385 s < mMin((signed)m_bndryCell[bndryId].m_recNghbrIds.size(), m_bndryCells->a[bndryId].m_noSrfcs);
1386 s++) {
1387 dummyPvariables(s, v) = m_bndryCell[bndryId].m_srfcVariables[s]->m_primVars[v];
1388 }
1389 MFloat imageVar = F0;
1390 for(MInt n = 0; n < (signed)m_bndryCell[bndryId].m_recNghbrIds.size(); n++) {
1391 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[n];
1392 const MFloat nghbrPvariable = (n < m_bndryCells->a[bndryId].m_noSrfcs)
1393 ? dummyPvariables(n, v)
1394 : m_solver->a_pvariable(nghbrId, v);
1395 if(nghbrId < 0
1396 || m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size()
1397 != m_bndryCell[bndryId].m_recNghbrIds.size()) {
1398 cerr << nghbrId << " " << m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size()
1399 << " " << m_bndryCell[bndryId].m_recNghbrIds.size() << endl;
1400 }
1401 ASSERT(nghbrId > -1
1402 && m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size()
1403 == m_bndryCell[bndryId].m_recNghbrIds.size(),
1404 "");
1405 imageVar += m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariable;
1406 }
1407 // MFloat vf = m_solver->a_cellVolume( cellId ) /
1408 // pow(m_solver->c_cellLengthAtCell(cellId),(MFloat)nDim); MFloat fac = maia::math::deltaFun( vf, 0.90, F1
1409 // ); imageVar = ( fac*m_solver->a_pvariable( cellId , v ) + (F1-fac)*imageVar );
1410 m_solver->a_pvariable(ghostCellId, v) =
1411 F2 * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v] - imageVar;
1412 } else if(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] == BC_NEUMANN) {
1413 MFloat dn0 = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
1414 // MFloat dn0 = F0;
1415 MFloat dn = F0;
1416 for(MInt i = 0; i < nDim; i++) {
1417 // dn0 += ( m_solver->a_coordinate( cellId , i ) - m_bndryCell[ bndryId ].m_srfcs[srfc]->m_coordinates[
1418 // i ] ) * normal[ i ];
1419 dn += (m_solver->a_coordinate(cellId, i) - m_solver->a_coordinate(ghostCellId, i)) * normal[i];
1420 }
1421 m_solver->a_pvariable(ghostCellId, v) =
1422 m_solver->a_pvariable(cellId, v) - dn * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v];
1423 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v] =
1424 m_solver->a_pvariable(cellId, v) - dn0 * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v];
1425 } else if(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] == BC_ROBIN) {
1426 MFloat phi = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
1427 MFloat dn = F0;
1428 for(MInt i = 0; i < nDim; i++) {
1429 phi += (m_solver->a_coordinate(cellId, i) - m_bndryCell[bndryId].m_srfcs[srfc]->m_coordinates[i])
1430 * normal[i];
1431 // dn += ( m_bndryCell[ bndryId ].m_srfcs[srfc]->m_coordinates[ i ] - m_solver->a_coordinate(
1432 // ghostCellId , i )) * normal[ i ];
1433 dn += (m_solver->a_coordinate(cellId, i) - m_solver->a_coordinate(ghostCellId, i)) * normal[i];
1434 }
1435 dn -= m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
1436 if(dn + phi < 1e-8) {
1437 cerr << domainId() << ": warning very small distance " << m_solver->c_globalId(cellId) << " " << phi
1438 << " " << dn << " " << normal[0] << " " << normal[1] << " " << normal[2] << endl;
1439 }
1440 const MFloat beta = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_robinFactor;
1441 const MFloat delta = m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v];
1442 // const MFloat fac = ( F1 + beta*dn ) / ( F1 - beta*phi );
1443 const MFloat fac = (F1 + F1B2 * beta * (dn + phi)) / (F1 - F1B2 * beta * (dn + phi));
1444 // const MFloat fac2 = ( dn + phi ) / ( F1 - beta*phi );
1445 const MFloat fac2 = (dn + phi) / (F1 - F1B2 * beta * (dn + phi));
1446 m_solver->a_pvariable(ghostCellId, v) = fac * m_solver->a_pvariable(cellId, v) - fac2 * delta;
1447 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v] =
1448 (dn * m_solver->a_pvariable(cellId, v) + phi * m_solver->a_pvariable(ghostCellId, v)) / (dn + phi);
1449
1450 if(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId == 3007) {
1451 MFloat imageVar = F0;
1452 for(MInt s = 0;
1453 s < mMin((signed)m_bndryCell[bndryId].m_recNghbrIds.size(), m_bndryCells->a[bndryId].m_noSrfcs);
1454 s++) {
1455 dummyPvariables(s, v) = m_solver->a_pvariable(cellId, v);
1456 }
1457 for(MInt n = 0; n < (signed)m_bndryCell[bndryId].m_recNghbrIds.size(); n++) {
1458 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[n];
1459 const MFloat nghbrPvariable = (n < m_bndryCells->a[bndryId].m_noSrfcs)
1460 ? dummyPvariables(n, v)
1461 : m_solver->a_pvariable(nghbrId, v);
1462 imageVar += m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariable;
1463 }
1464
1465 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v] =
1466 F0; //( imageVar - m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_primVars[v] ) / dn
1467 //+ beta * m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_primVars[v];
1468 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v] = imageVar;
1469
1470 // imageVar = F2*m_solver->a_pvariable(cellId, v) - imageVar;
1471 // m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_primVars[v] = imageVar;
1472 }
1473 } else if(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] == BC_ISOTHERMAL) {
1474 continue;
1475 } else {
1476 mTerm(1, AT_,
1477 "Unknown BC type: " + to_string(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId) + "/"
1478 + to_string(v) + "/" + to_string(m_bndryCells->a[bndryId].m_noSrfcs) + "/"
1479 + to_string(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v]) + " "
1480 + to_string(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area) + " "
1481 + to_string(m_solver->a_hasProperty(cellId, SolverCell::IsCutOff)));
1482 }
1483 }
1484 if(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->RHO] == BC_ISOTHERMAL) {
1485 // const MFloat Ts = bodyTemperatureRatio * m_solver->m_TInfinity;
1486 const MFloat Ts = sysEqn().temperature_ES(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO],
1487 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P]);
1488
1489 // if ( true) cerr << "bc: " << Ts/m_solver->m_TInfinity << endl;
1490 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO] =
1491 sysEqn().density_ES(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P], Ts);
1492 for(MInt s = 0;
1493 s < mMin((signed)m_bndryCell[bndryId].m_recNghbrIds.size(), m_bndryCells->a[bndryId].m_noSrfcs);
1494 s++) {
1495 for(MInt vv = 0; vv < noPVars; vv++) {
1496 dummyPvariables(s, vv) = m_bndryCell[bndryId].m_srfcVariables[s]->m_primVars[vv];
1497 }
1498 }
1499
1500 MFloat dn00 = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
1501 // MFloat dn00 = F0;
1502 // MFloat dn0 = F0;
1503 MFloat dn = F0;
1504 for(MInt i = 0; i < nDim; i++) {
1505 // dn0 += ( m_bndryCell[ bndryId ].m_srfcs[srfc]->m_coordinates[ i ] - m_solver->a_coordinate( ghostCellId
1506 // , i )) * normal[ i ];
1507 dn += (m_solver->a_coordinate(cellId, i) - m_solver->a_coordinate(ghostCellId, i)) * normal[i];
1508 // dn00 += (m_solver->a_coordinate( cellId , i ) - m_bndryCell[ bndryId ].m_srfcs[srfc]->m_coordinates[ i
1509 // ])
1510 // * normal[ i ];
1511 }
1512 MFloat dn0 = dn - dn00;
1513
1514 MFloat imageVar = F0;
1515 for(MInt n = 0; n < (signed)m_bndryCell[bndryId].m_recNghbrIds.size(); n++) {
1516 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[n];
1517 const MFloat nghbrPvariableP = (n < m_bndryCells->a[bndryId].m_noSrfcs)
1518 ? dummyPvariables(n, PV->P)
1519 : m_solver->a_pvariable(nghbrId, PV->P);
1520 imageVar += m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariableP;
1521 }
1522 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] = m_solver->a_pvariable(cellId, PV->P);
1523 m_solver->a_pvariable(ghostCellId, PV->P) =
1524 F2 * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] - imageVar;
1525 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->P] =
1526 (imageVar - m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P]) / dn0;
1527 imageVar = F0;
1528 for(MInt n = 0; n < (signed)m_bndryCell[bndryId].m_recNghbrIds.size(); n++) {
1529 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[n];
1530 const MInt noSrfcs = m_bndryCells->a[bndryId].m_noSrfcs;
1531 const MFloat nghbrPvariableP =
1532 (n < noSrfcs) ? dummyPvariables(n, PV->P) : m_solver->a_pvariable(nghbrId, PV->P);
1533 const MFloat nghbrPvariableRho =
1534 (n < noSrfcs) ? dummyPvariables(n, PV->RHO) : m_solver->a_pvariable(nghbrId, PV->RHO);
1535 if(nghbrId < 0
1536 || m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size()
1537 != m_bndryCell[bndryId].m_recNghbrIds.size()) {
1538 cerr << nghbrId << " " << m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size() << " "
1539 << m_bndryCell[bndryId].m_recNghbrIds.size() << endl;
1540 }
1541 ASSERT(nghbrId > -1
1542 && m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size()
1543 == m_bndryCell[bndryId].m_recNghbrIds.size(),
1544 "");
1545 imageVar += m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n]
1546 * sysEqn().temperature_ES(nghbrPvariableRho, nghbrPvariableP);
1547 }
1548
1549 MFloat dTdn = (imageVar - Ts) / dn0;
1550
1551 const MInt noNghbrIds = m_solver->a_noReconstructionNeighbors(cellId);
1552
1553 MInt maxIter = 100;
1554 MFloat res = 99999.9;
1555 MInt iter = 0;
1556 while(iter < maxIter && res > 1e-8) {
1557 MFloat pg = m_solver->a_pvariable(ghostCellId, PV->P);
1558 MFloat ps = m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P];
1559 for(MInt i = 0; i < nDim; i++) {
1560 m_solver->a_slope(cellId, PV->P, i) = F0;
1561 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
1562 const MInt nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
1563 const MInt offset0 = m_solver->a_reconstructionData(cellId) + nghbr;
1564 m_solver->a_slope(cellId, PV->P, i) +=
1565 m_solver->m_reconstructionConstants[nDim * offset0 + i]
1566 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
1567 }
1568 }
1569 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
1570 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] = m_solver->a_pvariable(cellId, PV->P);
1571 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->P] = F0;
1572 for(MInt i = 0; i < nDim; i++) {
1573 m_solver->a_pvariable(ghostCellId, PV->P) +=
1574 (m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i))
1575 * m_solver->a_slope(cellId, PV->P, i);
1576 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] +=
1577 (m_bndryCell[bndryId].m_srfcs[srfc]->m_coordinates[i] - m_solver->a_coordinate(cellId, i))
1578 * m_solver->a_slope(cellId, PV->P, i);
1579 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->P] +=
1580 m_solver->a_slope(cellId, PV->P, i) * normal[i];
1581 }
1582 m_solver->a_pvariable(ghostCellId, PV->P) =
1583 m_solver->a_pvariable(cellId, PV->P)
1584 - dn * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->P];
1585 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] =
1586 m_solver->a_pvariable(cellId, PV->P)
1587 - dn00 * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->P];
1588
1589 res = mMax(fabs(m_solver->a_pvariable(ghostCellId, PV->P) - pg),
1590 fabs(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] - ps));
1591 iter++;
1592 }
1593
1594 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO] =
1595 sysEqn().density_ES(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P], Ts);
1596
1597 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->RHO] =
1598 sysEqn().density_ES(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->P], Ts)
1599 - (m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO] * dTdn) / Ts;
1600
1601 m_solver->a_pvariable(ghostCellId, PV->RHO) =
1602 m_solver->a_pvariable(cellId, PV->RHO)
1603 - dn * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->RHO];
1604 }
1605 }
1606#ifdef _OPENMP
1607 }
1608#endif
1609 }
1610 }
1611}
1612
1613
1614//-----------------------------------------------------------------------------
1615
1616
1617template <MInt nDim, class SysEqn>
1619 TRACE();
1620 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
1621 (this->*bndryCndHandlerVariables[bcId])(bcId);
1622 }
1623}
1624
1625
1626//-----------------------------------------------------------------------------
1627
1628
1629template <MInt nDim, class SysEqn>
1631 TRACE();
1632
1633 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++)
1634 (this->*bndryCndHandlerCutOffVariables[bcId])(bcId);
1635}
1636
1637
1638template <MInt nDim, class SysEqn>
1640 TRACE();
1641
1642 // calls functions to initialize boundary conditions
1643 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++) {
1644 (this->*(bndryCndHandlerCutOffInit[bcId]))(bcId);
1645 }
1646}
1647
1648//-----------------------------------------------------------------------------
1649
1650template <MInt nDim, class SysEqn>
1652 TRACE();
1653
1654 MInt noCells = m_solver->noInternalCells();
1655 std::set<std::tuple<MInt, MInt, MInt, MBool>> cutOffBndryDirections;
1656
1657 if(!Context::propertyExists("cutOffBndryIds", m_solverId) && !m_solver->m_cutOffInterface.size()) {
1658 mTerm(1, AT_,
1659 "createBoundaryAtCutoff is set but no cutOff boundary condition is set in cutOffBndryIds or "
1660 "cutOffInterface, fix your property file");
1661 }
1662
1663 // add cutOffDirection boundary conditions
1664 if(Context::propertyExists("cutOffBndryIds", m_solverId)) {
1675 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
1685 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
1686 if(noCutOffDirections != noCutOffBndryIds)
1687 mTerm(1, AT_,
1688 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
1689 std::set<MInt> diffBcs;
1690 for(MInt i = 0; i < noCutOffBndryIds; i++) {
1691 MInt cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
1692 MInt cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
1693 if(m_solver->m_cutOffInterface.find(cutOffBndryIdTmp) != m_solver->m_cutOffInterface.end()) {
1694 mTerm(1, AT_, "same cut off bc in cutOffBndryIds and cutOffInterface");
1695 }
1696 // Store wether the cutOffBndry is inside the cut-off box or not
1697 MInt cutOffInside = 0;
1698 if(Context::propertyExists("cutOffInside", m_solverId)) {
1699 cutOffInside = Context::getSolverProperty<MBool>("cutOffInside", m_solverId, AT_, i);
1700 }
1701 cutOffBndryDirections.insert(make_tuple(cutOffBndryIdTmp, cutOffDirectionTmp, i, cutOffInside));
1702 diffBcs.insert(cutOffBndryIdTmp);
1703 }
1704
1705 // clusters the boundary conditions:
1706 // using one bcId for more directions results in one entry in m_sortedCutOffCells
1718 m_clusterCutOffBcs = false;
1719 m_clusterCutOffBcs = Context::getSolverProperty<MBool>("clusterCutOffBcs", m_solverId, AT_, &m_clusterCutOffBcs);
1720 if(m_clusterCutOffBcs)
1721 m_noCutOffBndryCndIds = diffBcs.size();
1722 else
1723 m_noCutOffBndryCndIds = noCutOffBndryIds;
1724 }
1725 // add cutOffInterface boundary conditions
1726 m_noCutOffBndryCndIds += m_solver->m_cutOffInterface.size();
1727 //---
1728 allocateCutOffMemory();
1729
1730 // Read the cut-off box. This can be used to prescribe different cut-off BCs and the same cartedian grid cut-off
1731 MFloatScratchSpace cutOffInsideBox(2 * nDim, AT_, "cutOffInsideBox");
1732 if(Context::propertyExists("cutOffInside", m_solverId)) {
1733 for(MInt d = 0; d < 2 * nDim; d++) {
1734 cutOffInsideBox[d] = Context::getSolverProperty<MFloat>("cutOffInsideBox", m_solverId, AT_, d);
1735 }
1736 } else {
1737 cutOffInsideBox.fill(F0);
1738 }
1739
1740 m_log << "*************************" << endl;
1741 m_log << "Creating cut-off boundary" << endl;
1742 m_log << "*************************" << endl;
1743
1744 MInt bc = 0;
1745 // add cells to cutOffDirection boundary conditions
1746 for(auto it = cutOffBndryDirections.begin(); it != cutOffBndryDirections.end(); it++) {
1747 MInt bcId = get<0>(*it);
1748 MInt direction = get<1>(*it);
1749 MBool cutOffInside = get<3>(*it);
1750
1751 // search cells in cut off direction
1752 for(MInt cellId = 0; cellId < noCells; cellId++) {
1753 if(m_solver->a_isHalo(cellId)) continue;
1754 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
1755 if(m_solver->a_hasNeighbor(cellId, direction, false) != 0) continue;
1756 if(m_solver->a_bndryId(cellId) > -1 && m_bndryCells->a[m_solver->a_bndryId(cellId)].m_externalFaces[direction])
1757 continue;
1758 if(m_solver->c_parentId(cellId) > -1) {
1759 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId), direction, false) != 0) {
1760 continue;
1761 }
1762 }
1763
1764 if(m_solver->m_engineSetup && m_solver->m_noGapRegions > 2) {
1765 if(bcId == 209199 && m_solver->a_coordinate(cellId, 2) > 0) continue;
1766 if(bcId == 309199 && m_solver->a_coordinate(cellId, 2) < 0) continue;
1767 }
1768
1769 m_solver->a_hasProperty(cellId, SolverCell::IsCutOff) = true;
1770
1771 // If cell is cut-off cell, check wether cell should be added to current cut-off BCs
1772 MBool insideCutOffBox = true;
1773 for(MInt d = 0; d < nDim; d++) {
1774 if(m_solver->c_coordinate(cellId, d) < cutOffInsideBox[d]
1775 || m_solver->c_coordinate(cellId, d) > cutOffInsideBox[nDim + d]) {
1776 insideCutOffBox = false;
1777 }
1778 }
1779
1780 if(insideCutOffBox != cutOffInside) continue;
1781
1782 m_sortedCutOffCells[bc]->a[m_sortedCutOffCells[bc]->size()] = cellId;
1783 m_sortedCutOffCells[bc]->append();
1784 }
1785 if(!m_clusterCutOffBcs || std::next(it) == cutOffBndryDirections.end() || bcId != get<0>(*(std::next(it)))) {
1786 m_cutOffBndryCndIds[bc] = bcId;
1787 m_log << bc << ": " << m_cutOffBndryCndIds[bc] << " is cutOffDirection boundary condition" << endl;
1788 if(m_cbcCutOff) {
1789 // Map bcId to cbcId
1790 m_cbcBndryCndIds[bc] = get<2>(*it);
1791 }
1792 bc++;
1793 }
1794 }
1795
1796 // add cells to cutOffInterface boundary conditions
1797 for(auto it = m_solver->m_cutOffInterface.begin(); it != m_solver->m_cutOffInterface.end(); it++, bc++) {
1798 m_cutOffBndryCndIds[bc] = *it;
1799 m_log << bc << ": " << m_cutOffBndryCndIds[bc] << " is cutOffInterface boundary condition" << endl;
1800 for(MInt cellId = 0; cellId < noCells; cellId++) {
1801 if(m_solver->a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
1802 if(!m_solver->a_isInterface(cellId)) continue;
1803 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
1804 if(m_solver->a_isHalo(cellId)) continue;
1805 if(m_cutOffBndryCndIds[bc] != isCutOffInterface(cellId)) continue;
1806
1807 m_solver->a_hasProperty(cellId, SolverCell::IsCutOff) = true;
1808 m_sortedCutOffCells[bc]->a[m_sortedCutOffCells[bc]->size()] = cellId;
1809 m_sortedCutOffCells[bc]->append();
1810 }
1811 }
1812
1813 exchangeCutOffBoundaryCells();
1814}
1815//-----------------------------------------------------------------------------
1816
1822template <MInt nDim, class SysEqn>
1824 TRACE();
1825 if(m_createBoundaryAtCutoff) {
1826 // ASSERT(m_noCutOffBndryCndIds>0,"noCutOffBndryCndIds ==0");
1827 if(m_noCutOffBndryCndIds == 0) TERMM(1, "cut off is on, but no boundary conditions are available! ");
1828
1829 if(m_noCutOffBndryCndIds >= m_maxNoBndryCndIds) TERMM(1, "too many cut off bndryIds! ");
1830
1831 // Cleanup anything already present in m_sortedCutOffCells
1832 for(auto& i : m_sortedCutOffCells) {
1833 delete i;
1834 }
1835 m_sortedCutOffCells.clear();
1836
1837 m_log << "no cut off bcs " << m_noCutOffBndryCndIds << endl;
1838 for(MInt n = 0; n < m_noCutOffBndryCndIds; n++) {
1839 auto* sortedList = new List<MInt>(m_maxNoBndryCells);
1840 sortedList->setSize(0);
1841 m_sortedCutOffCells.push_back(sortedList);
1842 }
1843
1844 m_cbcCutOff = false;
1845 m_cbcCutOff = Context::getSolverProperty<MBool>("cutOffcbc", m_solverId, AT_, &m_cbcCutOff);
1846
1847 m_cbcSmallCellCorrection = false;
1848 m_cbcSmallCellCorrection =
1849 Context::getSolverProperty<MBool>("cbcSmallCellCorrection", m_solverId, AT_, &m_cbcSmallCellCorrection);
1850
1851 if(m_cbcCutOff) {
1852 m_cbcDir.resize(m_noCutOffBndryCndIds);
1853 m_cbcRelax.resize(m_noCutOffBndryCndIds);
1854 m_cbcLref.resize(m_noCutOffBndryCndIds);
1855 m_cbcInflowArea.resize(m_noCutOffBndryCndIds);
1856 m_cbcReferencePoint.resize(m_noCutOffBndryCndIds);
1857 m_dirNormal.resize(m_noCutOffBndryCndIds);
1858 m_dirTangent.resize(m_noCutOffBndryCndIds);
1859 m_cbcDomainMin.resize(m_noCutOffBndryCndIds);
1860 m_cbcBndryCndIds.resize(m_noCutOffBndryCndIds, -1);
1861 }
1862 }
1863}
1864
1865//-----------------------------------------------------------------------------
1866
1872template <MInt nDim, class SysEqn>
1874 TRACE();
1875 // exchange cells for all cut off boundary condition and add them to the corresponding lists
1876 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++) {
1877 MInt bcIdNr = m_cutOffBndryCndIds[bcId];
1878 MInt noInternalCutOffCells = m_sortedCutOffCells[bcId]->size();
1879 m_log << "processing bcIdNr " << bcIdNr << " with " << noInternalCutOffCells << " internal cut off cells...";
1880 MIntScratchSpace intSendRecBuffers(m_solver->a_noCells(), AT_, "intSendRecBuffers");
1881 intSendRecBuffers.fill(0);
1882 // gather b_properties[SolverCell::IsCutOff] only for current cut off bc
1883 MInt cnt = 0;
1884 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
1885 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
1886 intSendRecBuffers[cellId] = m_solver->a_hasProperty(cellId, SolverCell::IsCutOff);
1887 if(intSendRecBuffers[cellId] > 0 && m_solver->a_isWindow(cellId)) cnt++;
1888 }
1889 m_log << "... " << cnt << " window cut off cells to exchange to all domains ... ";
1890 // exchange b_properties only on window cells and receive corresponding data on halo cells
1891 m_solver->exchangeData(intSendRecBuffers.getPointer(), 1);
1892 // scatter data to cell collector and append halo cell to the cut off boundary collector
1893 for(MInt i = 0; i < m_solver->noNeighborDomains(); i++) {
1894 for(MInt j = 0; j < m_solver->noHaloCells(i); j++) {
1895 MInt thishaloCellId = m_solver->haloCellId(i, j);
1896 if(!m_solver->a_hasProperty(thishaloCellId, SolverCell::IsOnCurrentMGLevel)) continue;
1897 if(m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff)) continue;
1898 m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff) = intSendRecBuffers[thishaloCellId];
1899 if(m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff)) {
1900 m_sortedCutOffCells[bcId]->a[m_sortedCutOffCells[bcId]->size()] = thishaloCellId;
1901 m_sortedCutOffCells[bcId]->append();
1902 }
1903 }
1904 }
1905 // Note: Azimuthal window and halo cells might not be on same grid level. Therefore, intSendRecBuffers are modified
1906 // for parent data
1907 if(m_solver->grid().azimuthalPeriodicity()) {
1908 MInt axDir = m_solver->grid().raw().m_azimuthalAxialDir;
1909 // Modify parent data
1910 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
1911 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
1912 if(m_solver->a_hasProperty(cellId, SolverCell::IsCutOff)) {
1913 if(m_solver->c_parentId(cellId) > -1) {
1914 intSendRecBuffers[m_solver->c_parentId(cellId)] = true;
1915 }
1916 }
1917 }
1918 m_solver->exchangeDataAzimuthal(intSendRecBuffers.getPointer(), 1);
1919 for(MInt i = 0; i < m_solver->grid().noAzimuthalNeighborDomains(); i++) {
1920 for(MInt j = 0; j < m_solver->grid().noAzimuthalHaloCells(i); j++) {
1921 MInt thishaloCellId = m_solver->grid().azimuthalHaloCell(i, j);
1922 if(!m_solver->a_hasProperty(thishaloCellId, SolverCell::IsOnCurrentMGLevel)) continue;
1923 if(m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff)) continue;
1924 if(intSendRecBuffers[thishaloCellId] > 0) {
1925 if(!m_solver->a_hasNeighbor(thishaloCellId, axDir)) {
1926 if(m_solver->c_parentId(thishaloCellId) < 0
1927 || (m_solver->c_parentId(thishaloCellId) > -1
1928 && !m_solver->a_hasNeighbor(m_solver->c_parentId(thishaloCellId), axDir))) {
1929 m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff) = intSendRecBuffers[thishaloCellId];
1930 }
1931 } else if(!m_solver->a_hasNeighbor(thishaloCellId, axDir + 1)) {
1932 if(m_solver->c_parentId(thishaloCellId) < 0
1933 || (m_solver->c_parentId(thishaloCellId) > -1
1934 && !m_solver->a_hasNeighbor(m_solver->c_parentId(thishaloCellId), axDir + 1))) {
1935 m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff) = intSendRecBuffers[thishaloCellId];
1936 }
1937 }
1938 }
1939 if(m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff)) {
1940 m_sortedCutOffCells[bcId]->a[m_sortedCutOffCells[bcId]->size()] = thishaloCellId;
1941 m_sortedCutOffCells[bcId]->append();
1942 }
1943 }
1944 }
1945 for(MUint i = 0; i < m_solver->m_azimuthalRemappedNeighborDomains.size(); i++) {
1946 for(MUint j = 0; j < m_solver->m_azimuthalRemappedHaloCells[i].size(); j++) {
1947 MInt thishaloCellId = m_solver->m_azimuthalRemappedHaloCells[i][j];
1948 if(!m_solver->a_hasProperty(thishaloCellId, SolverCell::IsOnCurrentMGLevel)) continue;
1949 if(m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff)) continue;
1950 if(intSendRecBuffers[thishaloCellId]
1951 && (!m_solver->a_hasNeighbor(thishaloCellId, axDir)
1952 || !m_solver->a_hasNeighbor(thishaloCellId, axDir + 1))) {
1953 m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff) = intSendRecBuffers[thishaloCellId];
1954 }
1955 if(m_solver->a_hasProperty(thishaloCellId, SolverCell::IsCutOff)) {
1956 m_sortedCutOffCells[bcId]->a[m_sortedCutOffCells[bcId]->size()] = thishaloCellId;
1957 m_sortedCutOffCells[bcId]->append();
1958 }
1959 }
1960 }
1961 }
1962 m_log << " finished. " << endl
1963 << " number received cut off cells = " << m_sortedCutOffCells[bcId]->size() - noInternalCutOffCells
1964 << " for current bcId = " << bcIdNr << endl;
1965 }
1966}
1967
1968//-----------------------------------------------------------------------------
1969
1970/*
1971 * \author Tim Wegmann, Juli. 2019
1972 *
1973 */
1974template <MInt nDim, class SysEqn>
1976 TRACE();
1977
1978 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
1979
1980 // add cells to cutOffDirection noundary conditions
1981 for(MInt dir = 0; dir < noCutOffDirections; dir++) {
1982 MInt direction = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, dir);
1983 // search cells in cut off direction
1984 for(MInt cellId = 0; cellId < m_solver->noInternalCells(); cellId++) {
1985 if(m_solver->c_noChildren(cellId) > 0) continue;
1986 if(m_solver->a_hasNeighbor(cellId, direction) != 0) continue;
1987 if(m_solver->a_isInterface(cellId)) continue;
1988 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
1989
1990 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
1991
1992 if(m_solver->c_parentId(cellId) > -1) {
1993 const MInt parent = m_solver->c_parentId(cellId);
1994 if(m_solver->a_hasNeighbor(parent, direction) != 0) continue;
1995 if(m_solver->a_isInterface(parent)) continue;
1996 }
1997 cutOffCells(cellId) = 1;
1998 MInt parentId = m_solver->c_parentId(cellId);
1999 while(parentId > -1 && parentId < m_solver->a_noCells()) {
2000 cutOffCells(parentId) = 1;
2001 parentId = m_solver->c_parentId(parentId);
2002 }
2003 }
2004 }
2005
2006 m_solver->exchangeData(&cutOffCells(0), 1);
2007}
2008
2009//-----------------------------------------------------------------------------
2010
2011/*
2012 * \author Thomas Schiden, Feb. 2016
2013 *
2014 */
2015template <MInt nDim, class SysEqn>
2017 if(!m_solver->m_cutOffInterface.size()) return 0;
2018
2019 // a. Create target for check
2020 const MFloat cellHalfLength = m_solver->c_cellLengthAtCell(cellId) / F2;
2021 MFloat target[6];
2022 std::vector<MInt> nodeList;
2023
2024 for(MInt j = 0; j < nDim; j++) {
2025 target[j] = m_solver->a_coordinate(cellId, j) - cellHalfLength;
2026 target[j + nDim] = m_solver->a_coordinate(cellId, j) + cellHalfLength;
2027 }
2028
2029 // b. Do the intersection test
2030 if(m_gridCutTest == "SAT")
2031 m_solver->m_geometry->getIntersectionElements(target, nodeList, cellHalfLength, &m_solver->a_coordinate(cellId, 0));
2032 else
2033 m_solver->m_geometry->getIntersectionElements(target, nodeList);
2034
2035 const MInt noNodes = nodeList.size();
2036 if(noNodes == 0) return 0;
2037
2038 // c. check for the lowest bcId
2039 MInt bndCndId = m_solver->m_geometry->elements[nodeList[0]].m_bndCndId;
2040 for(MInt n = 1; n < noNodes; n++) {
2041 bndCndId = mMin(m_solver->m_geometry->elements[nodeList[n]].m_bndCndId, bndCndId);
2042 }
2043 if(m_solver->m_cutOffInterface.find(bndCndId) == m_solver->m_cutOffInterface.end())
2044 return 0;
2045 else
2046 return bndCndId;
2047}
2048
2049//-----------------------------------------------------------------------------
2050
2051// template <MInt nDim, class SysEqn>
2052// void FvBndryCndXD<nDim,SysEqn>::applyNonReflectingBC()
2053//{
2054// TRACE();
2055//
2056// for( MInt bcId = 0; bcId < m_noBndryCndIds; bcId++ )
2057// (this->*nonReflectingBoundaryCondition[bcId]) (bcId);
2058//}
2059
2060
2061//-----------------------------------------------------------------------------
2062
2063
2064template <MInt nDim, class SysEqn>
2066 TRACE();
2067
2068 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++)
2069 (this->*nonReflectingCutOffBoundaryCondition[bcId])(bcId);
2070}
2071
2072
2073//-----------------------------------------------------------------------------
2074
2075
2076template <MInt nDim, class SysEqn>
2078 TRACE();
2079
2080 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++)
2081 (this->*nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId])(bcId);
2082}
2083
2084
2085//-----------------------------------------------------------------------------
2086
2087
2088template <MInt nDim, class SysEqn>
2090 TRACE();
2091
2092 // loop over all different boundary conditions
2093 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
2094 (this->*bndryCndHandlerSlopesInviscid[bcId])(bcId);
2095 }
2096}
2097
2098
2099//-----------------------------------------------------------------------------
2100
2101
2102template <MInt nDim, class SysEqn>
2104 TRACE();
2105
2106 // loop over all different boundary conditions
2107 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++) {
2108 (this->*bndryCndHandlerCutOffSlopesInviscid[bcId])(bcId);
2109 }
2110}
2111
2112
2113//-----------------------------------------------------------------------------
2114
2115
2116template <MInt nDim, class SysEqn>
2118 TRACE();
2119
2120 NEW_TIMER_GROUP_STATIC(tg_initTimer, "updateGhostCellSlopesViscous");
2121 NEW_TIMER_STATIC(t_timertotal, "total", tg_initTimer);
2122 NEW_SUB_TIMER_STATIC(t_viscSlopes, "bndryViscousSlopes", t_timertotal);
2123 NEW_SUB_TIMER_STATIC(t_cghost, "correctGhostCellSlopesViscous", t_timertotal);
2124
2125 RECORD_TIMER_START(t_timertotal);
2126 RECORD_TIMER_START(t_viscSlopes);
2127 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
2128 (this->*bndryViscousSlopes[bcId])(bcId);
2129 }
2130 RECORD_TIMER_STOP(t_viscSlopes);
2131
2132 RECORD_TIMER_START(t_cghost);
2133 if(!m_cellMerging) {
2134 correctGhostCellSlopesViscous();
2135 }
2136 RECORD_TIMER_STOP(t_cghost);
2137 RECORD_TIMER_STOP(t_timertotal);
2138}
2139
2140
2141//-----------------------------------------------------------------------------
2142
2143
2144template <MInt nDim, class SysEqn>
2146 TRACE();
2147
2148 const MInt noBndryCells = m_bndryCells->size();
2149 const MInt noPVars = PV->noVariables;
2150
2151#ifdef _OPENMP
2152#pragma omp parallel for
2153#endif
2154 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
2155 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
2156 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
2157 continue;
2158 }
2159 if(m_solver->a_isHalo(cellId)) {
2160 continue;
2161 }
2162 if(m_bndryCell[bndryId].m_recNghbrIds.size() == 0) {
2163 continue;
2164 }
2165 if(m_solver->a_hasProperty(cellId, SolverCell::IsCutOff)) {
2166 continue;
2167 }
2168
2169 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
2170 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
2171 MFloat normal[3] = {F0, F0, F0};
2172 for(MInt i = 0; i < nDim; i++) {
2173 normal[i] = m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i];
2174 }
2175 MFloat dng = F0;
2176 for(MInt i = 0; i < nDim; i++) {
2177 dng += (m_solver->a_coordinate(cellId, i) - m_solver->a_coordinate(ghostCellId, i)) * normal[i];
2178 }
2179 dng -= m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
2180
2181 for(MInt v = 0; v < noPVars; v++) {
2182 switch(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v]) {
2183 case BC_DIRICHLET:
2184 // case BC_ISOTHERMAL:
2185 case BC_UNSET:
2186 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v] =
2187 (m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v] - m_solver->a_pvariable(ghostCellId, v))
2188 / dng;
2189 // m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_normalDeriv[v] = ( m_solver->a_pvariable( cellId , v) -
2190 // m_solver->a_pvariable( ghostCellId , v) ) / dng;
2191 for(MInt i = 0; i < nDim; i++) {
2192 m_solver->a_slope(ghostCellId, v, i) =
2193 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v] * normal[i];
2194 // m_solver->a_slope( ghostCellId , v, i) = m_solver->a_slope( cellId , v, i); //use this if local density
2195 // peaks/drops occur
2196 }
2197 break;
2198
2199 case BC_NEUMANN:
2200 case BC_ISOTHERMAL:
2201 for(MInt i = 0; i < nDim; i++) {
2202 m_solver->a_slope(ghostCellId, v, i) =
2203 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v] * normal[i];
2204 }
2205 break;
2206
2207 case BC_ROBIN:
2208 for(MInt i = 0; i < nDim; i++) {
2209 m_solver->a_slope(ghostCellId, v, i) =
2210 normal[i]
2211 * (m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v]
2212 - m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_robinFactor
2213 * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v]);
2214 }
2215 break;
2216
2217 default: {
2218 stringstream errorMessage;
2219 errorMessage << "ERROR: Invalid BC type with value = "
2220 << m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] << ", variable number" << v
2221 << ", at bc = " << m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId;
2222 mTerm(1, AT_, errorMessage.str());
2223 }
2224 }
2225
2226 for(MInt i = 0; i < nDim; i++) {
2227 m_solver->a_slope(ghostCellId, v, i) =
2228 2.0 * m_solver->a_slope(ghostCellId, v, i) - m_solver->a_slope(cellId, v, i);
2229 }
2230 }
2231 }
2232 }
2233}
2234
2235//-----------------------------------------------------------------------------
2236
2237template <MInt nDim, class SysEqn>
2239 TRACE();
2240
2241 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++) {
2242 (this->*bndryCutOffViscousSlopes[bcId])(bcId);
2243 }
2244}
2245
2246template <MInt nDim, class SysEqn>
2248 TRACE();
2249
2250 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
2251 (this->*bndryCndHandlerInit[bcId])(bcId);
2252 }
2253
2254 if(!m_cellMerging) setBCTypes();
2255
2256 if(m_solver->m_wmLES) {
2257 initWMSurfaces();
2258 }
2259}
2260
2261
2262//-------------------------------------------------------------------------------
2263
2264
2265template <MInt nDim, class SysEqn>
2267 TRACE();
2268 const MInt noPVars = PV->noVariables;
2269 set<MInt> unhandledBCs;
2270
2271 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
2272 if((updateOnlyBndryCndId > -1) && (m_bndryCndIds[bcId] != updateOnlyBndryCndId)) {
2273 continue;
2274 }
2275
2276 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
2277 MInt bndryId = m_sortedBndryCells->a[id];
2278
2279 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
2280 ASSERT(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId > -1, "");
2281 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId != m_bndryCndIds[bcId]) {
2282 continue;
2283 }
2284
2285 // initialization: Dirichlet type and zero normal derivatives, individual specifications below
2286 for(MInt v = 0; v < noPVars; v++) {
2287 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] = BC_DIRICHLET;
2288 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v] = F0;
2289 }
2290 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_robinFactor = F0;
2291
2292 // set species variable to BC_NEUMANN
2293 for(MInt s = 0; s < m_noSpecies; s++) {
2294 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->Y[s]] = BC_NEUMANN;
2295 }
2296
2297 switch(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId) {
2298 //---
2299 // supersonic inflow conditions
2300 //---
2301 case 0:
2302 case 1091:
2303 case 1092:
2304 case 1101:
2305 case 1102:
2306 //---
2307 // STG
2308 //---
2309 case 7909:
2310 case 7910:
2311 case 7911:
2312 case 7912:
2313 case 7913:
2314 // do nothing, all Dirichlet is correct
2315 break;
2316
2317 //---
2318 // subsonic inflow conditions
2319 //---
2320 case 1001:
2321 case 1009:
2322 case 1011:
2323 case 1021:
2324 case 2011:
2325 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->P] = BC_NEUMANN;
2326 if(m_isEEGas || isDetChem<SysEqn>) {
2327 for(MInt s = 0; s < m_noSpecies; s++) {
2328 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->Y[s]] = BC_DIRICHLET;
2329 }
2330 }
2331 break;
2332
2333 case 2907:
2334 case 3011: // isothermal wall
2335 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->P] = BC_NEUMANN;
2336 if(m_isEEGas) {
2337 for(MInt s = 0; s < m_noSpecies; s++) {
2338 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->Y[s]] = BC_DIRICHLET;
2339 }
2340 }
2341 break;
2342
2343 //---
2344 // subsonic outflow condition
2345 //---
2346 case 1002:
2347 case 1012:
2348 case 1022:
2349 case 1099:
2350 for(MInt i = 0; i < nDim; i++) {
2351 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->VV[i]] = BC_NEUMANN;
2352 }
2353 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->RHO] = BC_NEUMANN;
2354 if(m_isEEGas) {
2355 for(MInt s = 0; s < m_noSpecies; s++) {
2356 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->Y[s]] = BC_DIRICHLET;
2357 }
2358 }
2359 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
2360 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
2361 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->NN[r]] = BC_NEUMANN;
2362 }
2363 }
2364 break;
2365
2366 //---
2367 // supersonic outflow conditions
2368 //---
2369 //---
2370 // adiabatic fixed wall conditions
2371 //---
2372 case 3002:
2373 case 30021:
2374 case 3003:
2375 case 3009:
2376 case 3399: // wall-modeling based on viscous fluxes
2377 case 3466:
2378 case 3600:
2379 case 4000:
2380 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->RHO] = BC_NEUMANN;
2381 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->P] = BC_NEUMANN;
2382 break;
2383
2384 //---
2385 // isothermal moving wall condition
2386 //---
2387 case 3008:
2388 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->P] = BC_NEUMANN;
2389 // labels:FV BC_ISOTHERMAL is a hack for MB
2390 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->RHO] = BC_ISOTHERMAL;
2391 break;
2392
2393 //---
2394 // adiabatic moving wall conditions
2395 //---
2396 case 3006:
2397 case 3067: // labels:FV euler/non euler hack
2398 case 3007: // labels:FV euler hack
2399 case 3060:
2400 case 3010:
2401 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->RHO] = BC_ROBIN;
2402 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->P] = BC_ROBIN;
2403 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_robinFactor = F0;
2404 break;
2405
2406 //---
2407 // symmetry condition about x-axis
2408 //---
2409 case 100100:
2410 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->P] = BC_NEUMANN;
2411 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->RHO] = BC_NEUMANN;
2412 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->U] = BC_NEUMANN;
2413
2414 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
2415 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
2416 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->NN[r]] = BC_NEUMANN;
2417 }
2418 }
2419 break;
2420
2421 //---
2422 // undefined -> reset to BC_UNSET
2423 //---
2424 default:
2425 for(MInt v = 0; v < noPVars; v++) {
2426 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] = BC_UNSET;
2427 }
2428 unhandledBCs.insert(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId);
2429 break;
2430 }
2431 }
2432 }
2433 }
2434 if(m_firstUseSetBCTypes) {
2435 for(MInt unhandledBC : unhandledBCs) {
2436 cerr0 << "Boundary condition " << unhandledBC << " not handled in FvBndryCndXD::setBCTypes(). "
2437 << "Defaulting to Dirichlet-type behavior - but on occurrence of a small cell an error will be thrown."
2438 << endl;
2439 m_log << "Boundary condition " << unhandledBC << " not handled in FvBndryCndXD::setBCTypes(). "
2440 << "Defaulting to Dirichlet-type behavior - but on occurrence of a small cell an error will be thrown."
2441 << endl;
2442 }
2443 if(unhandledBCs.empty()) {
2444 m_log << "All boundary conditions handled in FvBndryCndXD::setBCTypes()." << endl;
2445 }
2446 m_firstUseSetBCTypes = false;
2447 }
2448}
2449
2450//-------------------------------------------------------------------------------
2451
2452
2459template <MInt nDim, class SysEqn>
2461 TRACE();
2462 mDeallocate(bndryCndHandlerVariables);
2463 mAlloc(bndryCndHandlerVariables, m_maxNoBndryCndIds, "bndryCndHandlerVariables", AT_);
2464
2465 mDeallocate(bndryCndHandlerSpongeVariables);
2466 mAlloc(bndryCndHandlerSpongeVariables, mMax(1, m_noSpongeBndryCndIds), "bndryCndHandlerSpongeVariables", AT_);
2467
2468 mDeallocate(bndryCndHandlerCutOffVariables);
2469 mAlloc(bndryCndHandlerCutOffVariables, m_maxNoBndryCndIds, "bndryCndHandlerCutOffVariables", AT_);
2470
2471 mDeallocate(bndryCndHandlerCutOffInit);
2472 mAlloc(bndryCndHandlerCutOffInit, m_maxNoBndryCndIds, "bndryCndHandlerCutOffInit", &FvBndryCndXD::bc0, AT_);
2473
2474 // mDeallocate( nonReflectingBoundaryCondition );
2475 // mAlloc( nonReflectingBoundaryCondition, m_maxNoBndryCndIds, "nonReflectingBoundaryCondition", AT_ );
2476
2477 mDeallocate(nonReflectingCutOffBoundaryCondition);
2478 mAlloc(nonReflectingCutOffBoundaryCondition, m_maxNoBndryCndIds, "nonReflectingCutOffBoundaryCondition", AT_);
2479
2480 mDeallocate(nonReflectingBoundaryConditionAfterTreatmentCutOff);
2481 mAlloc(nonReflectingBoundaryConditionAfterTreatmentCutOff, m_maxNoBndryCndIds,
2482 "nonReflectingBoundaryConditionAfterTreatmentCutOff", AT_);
2483
2484 mDeallocate(bndryCndHandlerCutOffSlopesInviscid);
2485 mAlloc(bndryCndHandlerCutOffSlopesInviscid, m_maxNoBndryCndIds, "bndryCndHandlerCutOffSlopesInviscid", AT_);
2486
2487 mDeallocate(bndryCndHandlerSlopesInviscid);
2488 mAlloc(bndryCndHandlerSlopesInviscid, m_maxNoBndryCndIds, "bndryCndHandlerSlopesInviscid", AT_);
2489
2490 mDeallocate(bndryViscousSlopes);
2491 mAlloc(bndryViscousSlopes, m_maxNoBndryCndIds, "bndryViscousSlopes", AT_);
2492
2493 mDeallocate(bndryCutOffViscousSlopes);
2494 mAlloc(bndryCutOffViscousSlopes, m_maxNoBndryCndIds, "bndryCutOffViscousSlopes", AT_);
2495
2496 mDeallocate(bndryCndHandlerInit);
2497 mAlloc(bndryCndHandlerInit, m_maxNoBndryCndIds, "bndryCndHandlerInit", AT_);
2498
2499 mDeallocate(bndryCndHandlerNeumann);
2500 mAlloc(bndryCndHandlerNeumann, m_maxNoBndryCndIds, "bndryCndHandlerNeumann", AT_);
2501
2502 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++) {
2503 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2504 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
2505 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2506 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2507 nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId] = &FvBndryCndXD::bc0;
2508
2509 switch(m_cutOffBndryCndIds[bcId]) {
2510 case 0: // do nothing
2511 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2512 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2513 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2514 break;
2515
2516 case 10910: // parabolic inflow - y-direction
2517 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc10910;
2518 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000co;
2519 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc1000co;
2520 break;
2521
2522 case 109100:
2523 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2524 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2525 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2526 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1091;
2527 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2528 break;
2529
2530 case 109101: // subsonic characteristic inflow -> partially reflecting, T0, u, v is prescribed, incl. transverse
2531 // terms
2532 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2533 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2534 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2535 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1091a;
2536 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2537 break;
2538
2539 case 309101: // subsonic characteristic turbulent inflow -> partially reflecting, T0, u, v is prescribed, incl.
2540 // transverse terms
2541 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2542 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2543 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2544 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc3091a;
2545 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2546 break;
2547
2548 case 209101: // subsonic characteristic inflow -> partially reflecting, T0, u, v is prescribed, incl. transverse
2549 // terms
2550 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2551 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2552 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2553 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc2091a;
2554 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2555 break;
2556
2557 case 209102: // subsonic characteristic inflow ->fully reflecting, T0, u, v is prescribed, incl. transverse terms
2558 // + forcing
2559 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2560 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2561 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2562 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc2091b;
2563 nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId] = &FvBndryCndXD::cbc2091b_after;
2564 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2565 break;
2566
2567 case 109103: // subsonic characteristic inflow ->fully reflecting, p0,T0,v is prescribed, incl. shear and
2568 // transverse terms
2569 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2570 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2571 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2572 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1091c;
2573 nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId] = &FvBndryCndXD::cbc1091c_after;
2574 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2575 break;
2576
2577 case 109104: // subsonic characteristic inflow -> partially reflecting, p0,T0,v is prescribed, incl. shear and
2578 // transverse terms, profile of u1 is prescribed
2579 case 1091040:
2580 case 1091041:
2581 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2582 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2583 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2584 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1091d;
2585 nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId] = &FvBndryCndXD::cbc1091d_after;
2586 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2587 break;
2588
2589 case 209104: // subsonic characteristic inflow -> partially reflecting, p0,T0,v is prescribed, incl. shear and
2590 // transverse terms, profile of u1 is prescribed
2591 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2592 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2593 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2594 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc2091d;
2595 nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId] = &FvBndryCndXD::cbc2091d_after;
2596 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2597 break;
2598
2599 case 109105: // subsonic characteristic inflow ->fully reflecting, p, u, v is prescribed, incl. transverse terms
2600 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2601 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2602 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2603 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1091e;
2604 nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId] = &FvBndryCndXD::cbc1091e_after;
2605 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2606 break;
2607
2608 case 109199: // subsonic characteristic inflow/outflow switch -> uses 109104 and 109900 methods
2609 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2610 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2611 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2612 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1099_1091d;
2613 nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId] = &FvBndryCndXD::cbc1099_1091d_after;
2614 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2615 break;
2616 case 109198: // subsonic characteristic inflow/outflow switch -> uses 109104 and 109900 methods
2617 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2618 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co; // bc0;
2619 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co; // bc0;
2620 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1099_1091_local;
2621 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2622 break;
2623
2624 case 209198: // subsonic characteristic inflow/outflow switch -> uses 109104 and 109900 methods
2625 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2626 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2627 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2628 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1099_1091_local_comb;
2629 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2630 break;
2631
2632 case 309198: // subsonic characteristic inflow/outflow switch -> uses 109104 and 109900 methods
2633 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2634 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2635 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2636 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc2099_1091_local_comb;
2637 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2638 break;
2639
2640 // subsonic characteristic inflow/outflow switch by crank-angle
2641 case 209199: // combined inflow with 309199
2642 case 309199:
2643 case 409199: // single outflow
2644 case 509199: // single inflow
2645 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2646 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2647 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2648 if(!m_solver->m_engineSetup) {
2649 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1099_1091_engine;
2650 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2651 } else {
2652 IF_CONSTEXPR(nDim == 3) {
2653 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1099_1091_engineOld;
2654 }
2655 else {
2656 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1099_1091_engine;
2657 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2658 }
2659 }
2660 break;
2661
2662 case 109900:
2663 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2664 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2665 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2666 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1099;
2667 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2668 break;
2669 case 109910:
2670 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2671 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2672 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2673 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc109910;
2674 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2675 break;
2676 case 109911:
2677 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2678 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2679 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2680 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc109911;
2681 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2682 break;
2683
2684 case 109901: // subsonic characteristic outflow -> fully reflecting, p is prescribed, incl. shear and transverse
2685 // terms
2686 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc0;
2687 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
2688 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::bc0;
2689 nonReflectingCutOffBoundaryCondition[bcId] = &FvBndryCndXD::cbc1099a;
2690 nonReflectingBoundaryConditionAfterTreatmentCutOff[bcId] = &FvBndryCndXD::cbc1099a_after;
2691 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInitCbc;
2692 break;
2693
2694 case 10990: // simple outflow, fixed pressure
2695 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc10990;
2696 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000co;
2697 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc1000co;
2698 break;
2699
2700 case 10970: // simple outflow, fixed pressure
2701 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc10970;
2702 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000co;
2703 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc1000co;
2704 break;
2705
2706 case 10980: // simple inflow, x-direction, fixed pressure
2707 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc10980;
2708 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000co;
2709 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc1000co;
2710 break;
2711
2712 case 11110: // inflow/outflow from RANS
2713 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc11110;
2714 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co; // TODO labels:FV
2715 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co; // TODO labels:FV
2716 break;
2717
2718 // characteristic inflow b.c. - x/y/z direction - top hat velocity profile - progress variable
2719 // for forced response
2720 case 17516:
2721 case 17616:
2722 case 17716:
2723 case 17816:
2724 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc17516;
2725 break;
2726
2727 case 1251:
2728 case 1261:
2729 case 1271:
2730 case 1281:
2731 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1251;
2732 break;
2733
2734 // Round Jet inflow b.c. - x/y/z direction - parabolic velocity profile
2735 case 19516:
2736 case 19616:
2737 case 19716:
2738 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc19516;
2739 break;
2740
2741 // simple outflow b.c. - x/y/z direction - progress variable
2742 case 17530:
2743 case 17531:
2744 case 17532:
2745 case 17533:
2746 case 17534:
2747 case 17535:
2748 case 1743:
2749 case 1753:
2750 case 1763:
2751 case 1773:
2752 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1753;
2753 break;
2754
2755 // simple outflow b.c. pressure infinity - x/y/z direction - progress variable
2756 case 1745:
2757 case 1755:
2758 case 1765:
2759 case 1775:
2760 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1755;
2761 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2762 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2763 break;
2764
2765 // linear shear flow (initial condition 466)
2766 case 17110:
2767 case 17111:
2768 case 17112:
2769 case 17113:
2770 case 17114:
2771 case 17115:
2772 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc17110;
2773 break;
2774
2775 // simple outflow b.c. - pos. x/y/z direction - passive scalar
2776 case 1952:
2777 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1952;
2778 break;
2779
2780 // non-reflecting outflow b.c. - species
2781 case 19520:
2782 case 19720:
2783 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc19520;
2784 break;
2785
2786 // simple inflow b.c. - x/y/z direction - passive scalar
2787 case 1156:
2788 case 1166:
2789 case 1176:
2790 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1156;
2791 break;
2792
2793 // supersonic inflow with acoustic and entropy waves
2794 case 2700:
2795 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc2700;
2796 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit2700;
2797 break;
2798 // supersonic inflow with acoustic and entropy waves, single modes
2799 case 2800:
2800 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc2700;
2801 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit2700;
2802 break;
2803
2804 case 2770:
2805 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc2770;
2806 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit2770;
2807 break;
2808
2809 // extrapolation of all variables and slopes
2810 case 2710:
2811 case 2711:
2812 case 2712:
2813 case 2713:
2814 case 2714:
2815 case 2715:
2816 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc2710;
2817 // bndryCndHandlerCutOffSlopesInviscid[bcId] =
2818 // &FvBndryCndXD::bc2710s;
2819 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc2710co;
2820 break;
2821
2822 // extrapolation of all variables and slopes
2823 case 2720:
2824 case 2721:
2825 case 2722:
2826 case 2723:
2827 case 2724:
2828 case 2725:
2829 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc2720;
2830 // bndryCndHandlerCutOffSlopesInviscid[bcId] =
2831 // &FvBndryCndXD::bc2710s;
2832 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc2720co;
2833 break;
2834
2835 // Euler cut-off boundary condition
2836 case 29053:
2837 case 29052:
2838 case 29050:
2839 case 29051:
2840 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc29050;
2841 /*
2842 bndryCndHandlerCutOffSlopesInviscid[bcId] =
2843 &FvBndryCndXD::sbc00co;
2844 bndryCutOffViscousSlopes[bcId] =
2845 &FvBndryCndXD::sbc00co;*/
2846 break;
2847
2848 // random-eddy inflow cut-off boundary condition
2849 case 1601:
2850 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1601;
2851 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2852 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2853 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit1601;
2854 break;
2855 // random-eddy inflow cut-off boundary condition with a velocity profile (turbulent slot flame)
2856 case 1602:
2857 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1602;
2858 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2859 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2860 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit1601;
2861 break;
2862 // random-eddy inflow cut-off boundary condition with mean velocity profile for 3D round jet
2863 case 1603:
2864 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1603;
2865 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2866 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2867 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit1601;
2868 break;
2869 // random-eddy inflow cut-off BC with mean velocity profile for 3D round jet (1603 updated)
2870 case 1604:
2871 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1604;
2872 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2873 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2874 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit1601;
2875 break;
2876 // random-eddy inflow cut-off boundary condition with mean velocity profile for 3D chevron jet
2877 case 1606:
2878 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1606;
2879 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2880 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2881 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit1601;
2882 break;
2883
2884 case 1791:
2885 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1791;
2886 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2887 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2888 break;
2889
2890
2891 case 1792:
2892 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc1792;
2893 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2894 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2895 break;
2896
2897 // outflow cut-off
2898 case 16010:
2899 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc16010;
2900 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2901 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2902 break;
2903 case 16011:
2904 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc16011;
2905 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2906 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2907 break;
2908
2909 // Euler cut-off boundary condition
2910 case 16012:
2911 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc16012;
2912 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2913 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2914 break;
2915 case 16013:
2916 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc16013;
2917 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2918 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2919 break;
2920 case 16014:
2921 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc16014;
2922 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2923 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2924 break;
2925 case 16015:
2926 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc16015;
2927 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2928 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2929 break;
2930
2931 //---Zonal BC---
2932 case 7901:
2933 IF_CONSTEXPR(hasPV_N<SysEqn>::value) {
2934 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc7901;
2935 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit7901;
2936 }
2937 break;
2938 case 7902:
2939 IF_CONSTEXPR(hasPV_N<SysEqn>::value) {
2940 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc7902;
2941 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit7902;
2942 }
2943 else mTerm(1, AT_, "BC7902 only works with a SysEqn that has PV->N");
2944 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2945 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2946 break;
2947 case 7905:
2948 IF_CONSTEXPR(hasPV_N<SysEqn>::value) {
2949 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc7905;
2950 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit7905;
2951 }
2952 else mTerm(1, AT_, "BC7905 only works with a SysEqn that has PV->N");
2953 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2954 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2955 break;
2956 case 7903:
2957 IF_CONSTEXPR(!hasPV_N<SysEqn>::value)
2958 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2959 else mTerm(1, AT_, "BC7908 only works for LES");
2960 break;
2961 case 7909:
2962 IF_CONSTEXPR(!hasPV_N<SysEqn>::value) {
2963 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc7809;
2964 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit7809;
2965 }
2966 else mTerm(1, AT_, "BC7908 only works for LES");
2967 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2968 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2969 break;
2970 case 30022:
2971 bndryCndHandlerCutOffVariables[bcId] = &FvBndryCndXD::bc30022;
2972 bndryCndHandlerCutOffSlopesInviscid[bcId] = &FvBndryCndXD::sbc00co;
2973 bndryCutOffViscousSlopes[bcId] = &FvBndryCndXD::sbc00co;
2974 bndryCndHandlerCutOffInit[bcId] = &FvBndryCndXD::bcInit30022;
2975 break;
2976
2977 default: {
2978 stringstream errorMessage;
2979 errorMessage << "ERROR: Switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
2980 << " not matching any case." << endl;
2981 mTerm(1, AT_, errorMessage.str());
2982 }
2983 }
2984 }
2985 // set the pointer to the corresponding bc functions
2986 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
2987 switch(m_bndryCndIds[bcId]) {
2988 case 0:
2989 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1000;
2990 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
2991 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
2992 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
2993 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
2994 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
2995 break;
2996
2997 case 1:
2998 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc01;
2999 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3000 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3001 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3002 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3003 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
3004 break;
3005
3006 // Symmetry boundary condition about x-axis
3007 case 100100:
3008 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc100100;
3009 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3010 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3011 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3012 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1002;
3013 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1002;
3014 break;
3015
3016 // simple inflow b.c. - x direction
3017 case 1001:
3018 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1001;
3019 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3020 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3021 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3022 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3023 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<0>;
3024 break;
3025 case 1009:
3026 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1009;
3027 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3028 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3029 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3030 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3031 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<0>;
3032 break;
3033 // simple inflow b.c. - y direction
3034 case 1011:
3035 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1001;
3036 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3037 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3038 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3039 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3040 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<1>;
3041 break;
3042
3043 // simple inflow b.c. - y direction
3044 case 2011:
3045 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1001coflowY;
3046 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3047 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3048 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3049 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3050 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<1>;
3051 break;
3052 // combined jet inflow/wall boundary condition
3053 case 1401:
3054 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1401;
3055 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3056 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3057 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3058 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3059 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<0>;
3060 break;
3061 // simple inflow b.c. - x direction - species
3062 case 1801:
3063 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1801;
3064 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3065 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3066 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3067 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3068 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2901<0>;
3069 break;
3070 // simple inflow b.c. - y direction - passive scalar
3071 case 1901:
3072 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1901;
3073 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3074 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3075 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3076 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3077 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2901<0>;
3078 break;
3079 // simple inflow b.c. - y direction - passive scalar
3080 case 1911:
3081 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1901;
3082 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3083 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3084 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3085 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3086 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2901<1>;
3087 break;
3088 // simple inflow b.c. - z direction - passive scalar
3089 case 1921:
3090 IF_CONSTEXPR(nDim == 3) {
3091 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1901;
3092 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3093 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3094 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3095 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3096 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2901<2>;
3097 }
3098 else {
3099 TERM(-1);
3100 }
3101 break;
3102 // simple outflow b.c.
3103 case 1002:
3104 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1002;
3105 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3106 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3107 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3108 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3109 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<0>;
3110 break;
3111
3112 case 1012:
3113 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1002;
3114 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3115 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3116 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3117 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3118 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<1>;
3119 break;
3120 case 1021:
3121 IF_CONSTEXPR(nDim == 3) {
3122 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1001;
3123 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3124 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3125 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3126 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3127 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<2>;
3128 }
3129 else {
3130 TERM(-1);
3131 }
3132 break;
3133
3134 case 1022:
3135 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1002;
3136 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3137 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3138 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3139 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3140 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<2>;
3141 break;
3142
3143 case 1003:
3144 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1003;
3145 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3146 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3147 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3148 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3149 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<0>;
3150 break;
3151
3152 case 1004:
3153 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1004;
3154 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3155 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3156 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3157 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3158 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<0>;
3159 break;
3160
3161 case 1005:
3162 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1005;
3163 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3164 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3165 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3166 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3167 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<0>;
3168 break;
3169
3170 // laminar tube inflow b.c. - normal direction
3171 case 1091:
3172 case 1092:
3173 if(m_multipleGhostCells) {
3174 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1091MGC;
3175 } else {
3176 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1091;
3177 }
3178 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3179 if(m_multipleGhostCells) {
3180 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<true>;
3181 } else {
3182 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3183 }
3184 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3185 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3186 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
3187 break;
3188
3189 // simple outflow b.c. normal direction
3190 case 1098:
3191 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1102;
3192 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3193 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3194 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3195 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3196 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
3197 break;
3198 case 1099:
3199 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1099MGC;
3200 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3201 if(m_multipleGhostCells) {
3202 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<true>;
3203 } else {
3204 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3205 }
3206 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3207 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3208 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
3209 break;
3210 case 2001:
3211 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc2001;
3212 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3213 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3214 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3215 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3216 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<false>;
3217 break;
3218
3219 case 2002:
3220 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc2002;
3221 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3222 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3223 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3224 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3225 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
3226 break;
3227
3228 case 2003:
3229 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3230 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3231 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumann;
3232 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc2003;
3233 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3234 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
3235 break;
3236
3237
3238 // solid wall Euler b.c.
3239 case 3002:
3240 if(m_multipleGhostCells) {
3241 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<true>;
3242 } else {
3243 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3244 }
3245
3246 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3247 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumann;
3248 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3249
3250 if(m_multipleGhostCells) {
3251 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<true>;
3252 } else {
3253 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<false>;
3254 }
3255
3256 if(m_bndryCndIds[bcId] == 3002) {
3257 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3002;
3258 }
3259 break;
3260 case 30021:
3261 if(m_multipleGhostCells) {
3262 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<true>;
3263 } else {
3264 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3265 }
3266
3267 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3268 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumann;
3269 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3270
3271 if(m_multipleGhostCells) {
3272 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<true>;
3273 } else {
3274 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<false>;
3275 }
3276
3277 if(m_bndryCndIds[bcId] == 30021) {
3278 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc30021;
3279 }
3280 break;
3281 case 3399: // spalding wall model adiabatic no slip b.c. using precomputed mue_wm
3282 if(m_multipleGhostCells) {
3283 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<true>;
3284 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3285 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3399<true>;
3286 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<true>;
3287 } else {
3288 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3289 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumann;
3290 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3399<false>;
3291 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<false>;
3292 }
3293 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3294 break;
3295
3296
3297 // solid wall b.c.
3298 case 3003:
3299 case 3009:
3300 case 4003: // not used for force calculation etc.
3301 case 3037:
3302 case 3905:
3303 case 30040:
3304 case 30050:
3305 case 4000:
3306 case 4001:
3307 if(m_multipleGhostCells) {
3308 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<true>;
3309 } else {
3310 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3311 }
3312 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3313 if(m_multipleGhostCells) {
3314 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3315 } else {
3316 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumann;
3317 }
3318 if(m_multipleGhostCells) {
3319 if(m_bndryCndIds[bcId] == 3003 || m_bndryCndIds[bcId] == 3009) {
3320 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3003<true>;
3321 } else if(m_bndryCndIds[bcId] == 3037) {
3322 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3037MGC;
3323 }
3324 } else {
3325 if(m_bndryCndIds[bcId] == 4000) {
3326 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc4000;
3327 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit4000<true>;
3328 } else if(m_bndryCndIds[bcId] == 4001) {
3329 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc4001;
3330 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit4000<true>;
3331 } else {
3332 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3003<false>;
3333 }
3334 }
3335 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3336 if(m_multipleGhostCells) {
3337 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<true>;
3338 } else {
3339 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<false>;
3340 }
3341 break;
3342
3343 case 3004:
3344 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3345 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3346 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3347 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc0;
3348 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3349 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<false>;
3350 break;
3351
3352 case 3005:
3353 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0004;
3354 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3355 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3356 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc0;
3357 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3358 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<false>;
3359 break;
3360
3361
3362 // isothermal solid wall b.c.
3363 case 3011:
3364 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3365 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumannIso;
3366 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3011;
3367 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3368 if(m_multipleGhostCells) {
3369 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<true>;
3370 } else {
3371 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2000<false>;
3372 }
3373 break;
3374
3375
3376 case 3006: // moving wall b.c. adiabatic
3377 case 3010: // moving wall b.c. isothermal
3378 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bc0;
3379 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumannMb;
3380 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3006;
3381 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3382 bndryViscousSlopes[bcId] = &FvBndryCndXD::bc0;
3383 break;
3384
3385 // moving wall b.c. without boundary slopes
3386 case 3060:
3387 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bc0;
3388 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumannMb;
3389 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3006;
3390 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::bc0;
3391 bndryViscousSlopes[bcId] = &FvBndryCndXD::bc0;
3392 break;
3393
3394 // moving wall euler b.c.
3395 case 3007:
3396 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bc0;
3397 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumannMb;
3398 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3007;
3399 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000; // bc0;
3400 bndryViscousSlopes[bcId] = &FvBndryCndXD::bc0;
3401 break;
3402
3403 // moving wall euler b.c. isothermal without slopes and Neumann-Type
3404 case 3008:
3405 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bc0;
3406 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumannMb;
3407 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3006;
3408 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::bc0; // sbc1000;
3409 bndryViscousSlopes[bcId] = &FvBndryCndXD::bc0;
3410 break;
3411
3412 // simple and fast solid fixed adiabatic wall b.c. for non-merging small cell treatment
3413
3414 case 3600:
3415 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bc0;
3416 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3417 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bcNeumann3600;
3418 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3600;
3419 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3420 bndryViscousSlopes[bcId] = &FvBndryCndXD::bc0;
3421 break;
3422
3423 // simple shear flow (initialCondition 466)
3424 case 3466:
3425 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bc0;
3426 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3427 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3428 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc3466;
3429 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3430 bndryViscousSlopes[bcId] = &FvBndryCndXD::bc0;
3431 break;
3432
3433
3434 // no-slip wall b.c. (x direction) - passive scalar
3435 case 2907:
3436 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0002<false>;
3437 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3438 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3439 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc2907;
3440 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3441 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
3442 break;
3443
3444 // combustion
3445 // (do not compute species ghost cell gradients according to sbc2000)
3446 case 1101:
3447 case 1102:
3448 if(m_bndryCndIds[bcId] == 1101) {
3449 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1101;
3450 } else if(m_bndryCndIds[bcId] == 1102) {
3451 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1102;
3452 }
3453 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3454 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3455 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3456 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3457 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<0>;
3458 break;
3459
3460 case 1111:
3461 case 1112:
3462 if(m_bndryCndIds[bcId] == 1111) {
3463 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1101;
3464 } else if(m_bndryCndIds[bcId] == 1112) {
3465 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1102;
3466 }
3467 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3468 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3469 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3470 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3471 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<1>;
3472 break;
3473
3474 case 1121:
3475 case 1122:
3476 if(m_bndryCndIds[bcId] == 1121) {
3477 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1101;
3478 } else if(m_bndryCndIds[bcId] == 1122) {
3479 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc1102;
3480 }
3481 // nonReflectingBoundaryCondition[bcId] = &FvBndryCndXD::bc0;
3482 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit0001;
3483 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3484 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3485 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc2001<2>;
3486 break;
3487
3488 case 7909:
3489 case 7910:
3490 case 7911:
3491 case 7912:
3492 case 7913:
3493 // stg
3494 IF_CONSTEXPR(!hasPV_N<SysEqn>::value) {
3495 bndryCndHandlerVariables[bcId] = &FvBndryCndXD::bc7909;
3496 bndryCndHandlerInit[bcId] = &FvBndryCndXD::bcInit7909;
3497 }
3498 else mTerm(1, AT_, to_string(m_cutOffBndryCndIds[bcId]) + " only works for LES");
3499 bndryCndHandlerNeumann[bcId] = &FvBndryCndXD::bc0Var;
3500 bndryCndHandlerSlopesInviscid[bcId] = &FvBndryCndXD::sbc1000;
3501 bndryViscousSlopes[bcId] = &FvBndryCndXD::sbc1000;
3502 break;
3503
3504 case 4100:
3505 mTerm(1, AT_,
3506 "This boundary condition id was only used for the ghost fluid solver, which has been removed in Nov. "
3507 "2012. There is an alternative b.c. id that uses the same methods (minus the GF stuff): 4000");
3508 break;
3509
3510 case 4101:
3511 mTerm(1, AT_,
3512 "This boundary condition id was only used for the ghost fluid solver, which has been removed in Nov. "
3513 "2012. There is an alternative b.c. id that uses the same methods (minus the GF stuff): 4001");
3514 break;
3515
3516 default: {
3517 std::stringstream errorMsg;
3518 errorMsg << "FvBndryCndXD::initBndryCells error" << std::endl
3519 << "#" << bcId << " Unknown Boundary Condition Id: " << m_bndryCndIds[bcId] << std::endl;
3520 mTerm(1, AT_, errorMsg.str());
3521 }
3522 }
3523 }
3524}
3525
3526
3527// ---------------------------------------------------------------------------------
3528
3529
3560template <MInt nDim, class SysEqn>
3562 TRACE();
3563
3564 MBool spongeCellsFound = false;
3565 MBool append = false;
3566 MInt bcSpId, spongeCellId;
3567 MInt noBndryCells = m_bndryCells->size();
3568 MInt s1 = -1, s2 = -1, s3 = -1; // for sponge coordinate area directions
3569 MFloat spongeCoordMin2 = F0, spongeCoordMax2 = F0, spongeCoordMin = F0, spongeCoordMax = F0, spongeCoordFace = F0;
3570 MInt cellId, currentSpongeCellId, oldSortedSpongeBndryCellsSize;
3571 MFloat maxSpongeFactor = 0.0, minSpongeFactor = 100.0, maxSpongeFactorOverlap = 0.0, minSpongeFactorOverlap = 100.0;
3572 MFloat cellFaceCoordinate = -11111.0;
3573 MFloat halfCellWidth = F1B2 * m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel());
3574 MInt count = 0; // number of sponge cells laying in three sponge zones
3575 MInt cntHalo = 0;
3576 MInt cntHaloInside = 0;
3577 MFloatScratchSpace distance(m_solver->a_noCells(), AT_, "distance");
3578 //---
3579
3580 m_solver->m_noCellsInsideSpongeLayer = 0;
3581 m_sortedSpongeBndryCells->setSize(0);
3582 for(MInt bcId = 0; bcId < m_noSpongeBndryCndIds; bcId++)
3583 m_spongeBndryCells[bcId] = 0;
3584
3585 // reseting sponge information
3586 for(MInt c = 0; c < m_solver->a_noCells(); c++) {
3587 m_solver->a_hasProperty(c, SolverCell::IsInSpongeLayer) = false;
3588 m_solver->a_spongeFactor(c) = F0;
3589 }
3590
3591 std::vector<MFloat> minSpongeCoords(2 * m_noSpongeBndryCndIds);
3592 std::vector<MFloat> maxSpongeCoords(2 * m_noSpongeBndryCndIds);
3593
3594 // find sponge cells at boundary (see "at cut off" below)
3595 for(MInt bcId = 0; bcId < m_noSpongeBndryCndIds; bcId++) {
3596 bcSpId = m_spongeBndryCndIds[bcId];
3597 spongeCellsFound = false;
3598 spongeCoordMin = 10000;
3599 spongeCoordMax = -10000;
3600 spongeCoordMin2 = 10000;
3601 spongeCoordMax2 = -10000;
3602 spongeCoordFace = -99999999.0;
3603 m_spongeCoord[bcId] = -99999999.0;
3604 cellFaceCoordinate = -11111.0;
3605 m_log << "*************************************************************" << endl;
3606 m_log << "Information for sponge boundary Id: " << bcSpId << endl;
3607 m_log << "*************************************************************" << endl;
3608
3609 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
3610 append = false;
3611 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
3612 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == bcSpId) {
3613 append = true;
3614 break; // append spongeCellId and go to next boundary cell
3615 }
3616 }
3617 if(append) {
3618 spongeCellId = m_bndryCells->a[bndryId].m_cellId;
3619 m_sortedSpongeBndryCells->a[m_sortedSpongeBndryCells->size()] = spongeCellId;
3620 m_sortedSpongeBndryCells->append();
3621 spongeCellsFound = true;
3622 m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer) = true;
3623 }
3624 }
3625 if(spongeCellsFound) {
3626 m_log << "Collecting " << m_sortedSpongeBndryCells->size() - m_spongeBndryCells[bcId]
3627 << " sponge cells at the boundary ... ";
3628 m_spongeBndryCells[bcId + 1] = m_sortedSpongeBndryCells->size();
3629 m_log << " ok" << endl;
3630 }
3631
3632 if(!spongeCellsFound) {
3633 // find sponge cells at cut off
3634 for(MInt bcCut = 0; bcCut < m_noCutOffBndryCndIds; bcCut++) {
3635 if(bcSpId != m_cutOffBndryCndIds[bcCut]) continue;
3636 spongeCellsFound = true; // not used here but for information that sponge cells are found here
3637 m_log << "Collecting ";
3638 for(MInt id = 0; id < m_sortedCutOffCells[bcCut]->size(); id++) {
3639 spongeCellId = m_sortedCutOffCells[bcCut]->a[id];
3640 m_sortedSpongeBndryCells->a[m_sortedSpongeBndryCells->size()] = spongeCellId;
3641 m_sortedSpongeBndryCells->append();
3642 m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer) = true;
3643 }
3644 m_spongeBndryCells[bcId + 1] = m_sortedSpongeBndryCells->size();
3645 m_log << m_sortedSpongeBndryCells->size() - m_spongeBndryCells[bcId]
3646 << " sponge cells at the cut-off boundary ... ";
3647 m_log << " ok" << endl;
3648 break;
3649 }
3650 }
3651
3652 if(!spongeCellsFound || ((m_sortedSpongeBndryCells->size() - m_spongeBndryCells[bcId]) == 0)) {
3653 m_log << "sponge cells not yet found on domain " << domainId() << endl;
3654 m_spongeBndryCells[bcId + 1] = m_spongeBndryCells[bcId];
3655 }
3656 // reset the sponge factor to a positive value
3657 m_spongeFactor[bcId] = abs(m_spongeFactor[bcId]);
3658
3659 MInt vz = -1;
3660 switch(m_spongeDirections[bcId]) {
3661 case 1:
3662 m_log << "POSITIVE_XWALL" << endl;
3663 s1 = 1;
3664 s2 = 0;
3665 s3 = 2;
3666 vz = 0;
3667 m_spongeFactor[bcId] = -m_spongeFactor[bcId];
3668 break;
3669 case 0:
3670 m_log << "NEGATIVE_XWALL" << endl;
3671 s1 = 1;
3672 s2 = 0;
3673 s3 = 2;
3674 vz = 1;
3675 break;
3676 case 3:
3677 m_log << "POSITIVE_YWALL" << endl;
3678 s1 = 0;
3679 s2 = 1;
3680 s3 = 2;
3681 vz = 0;
3682 m_spongeFactor[bcId] = -m_spongeFactor[bcId];
3683 break;
3684 case 2:
3685 m_log << "NEGATIVE_YWALL" << endl;
3686 s1 = 0;
3687 s2 = 1;
3688 s3 = 2;
3689 vz = 1;
3690 break;
3691 case 5:
3692 m_log << "POSITIVE_ZWALL" << endl;
3693 s1 = 0;
3694 s2 = 2;
3695 s3 = 1;
3696 vz = 0;
3697 m_spongeFactor[bcId] = -m_spongeFactor[bcId];
3698 break;
3699 case 4:
3700 m_log << "NEGATIVE_ZWALL" << endl;
3701 s1 = 0;
3702 s2 = 2;
3703 s3 = 1;
3704 vz = 1;
3705 break;
3706 default: {
3707 mTerm(1, AT_, "wrong sponge direction selected");
3708 }
3709 }
3710 TERMM_IF_COND(vz != 0 && vz != 1, "ERROR: invalid coordinate orientation of sponge vz = " + std::to_string(vz));
3711
3712 IF_CONSTEXPR(nDim == 3) {
3713 // find min sponge edge - only for information
3714 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
3715 cellId = m_sortedSpongeBndryCells->a[id];
3716 cellFaceCoordinate = m_solver->a_coordinate(cellId, s3) - F1B2 * m_solver->c_cellLengthAtCell(cellId);
3717 spongeCoordMin2 = mMin(spongeCoordMin2, cellFaceCoordinate);
3718 }
3719
3720 // find max sponge edge - only for information
3721 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
3722 cellId = m_sortedSpongeBndryCells->a[id];
3723 cellFaceCoordinate = m_solver->a_coordinate(cellId, s3) + F1B2 * m_solver->c_cellLengthAtCell(cellId);
3724 spongeCoordMax2 = mMax(spongeCoordMax2, cellFaceCoordinate);
3725 }
3726
3727 // find min sponge edge - only for information
3728 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
3729 cellId = m_sortedSpongeBndryCells->a[id];
3730 cellFaceCoordinate = m_solver->a_coordinate(cellId, s1) - F1B2 * m_solver->c_cellLengthAtCell(cellId);
3731 spongeCoordMin = mMin(spongeCoordMin, cellFaceCoordinate);
3732 }
3733
3734 // find max sponge edge - only for information and define max sponge area in spongeCoordDirection
3735 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
3736 cellId = m_sortedSpongeBndryCells->a[id];
3737 halfCellWidth = F1B2 * m_solver->c_cellLengthAtCell(cellId);
3738 cellFaceCoordinate = m_solver->a_coordinate(cellId, s1) + halfCellWidth;
3739 if(spongeCoordMax < cellFaceCoordinate) {
3740 spongeCoordMax = cellFaceCoordinate;
3741 if(m_spongeFactor[bcId] > 0) {
3742 m_spongeCoord[bcId] =
3743 m_solver->a_coordinate(cellId, s2) + m_spongeLayerThickness * m_spongeFactor[bcId] - halfCellWidth;
3744 spongeCoordFace = m_solver->a_coordinate(cellId, s2) - halfCellWidth;
3745 } else {
3746 m_spongeCoord[bcId] =
3747 m_solver->a_coordinate(cellId, s2) + m_spongeLayerThickness * m_spongeFactor[bcId] + halfCellWidth;
3748 spongeCoordFace = m_solver->a_coordinate(cellId, s2) + halfCellWidth;
3749 }
3750 }
3751 }
3752
3753 if(noDomains() == 1) {
3754 if(approx(spongeCoordMin2, 10000.0, MFloatEps) || approx(spongeCoordMax2, -10000.0, MFloatEps)
3755 || approx(spongeCoordMin, 10000.0, MFloatEps) || approx(spongeCoordMax, -10000.0, MFloatEps)
3756 || approx(m_spongeCoord[bcId], -111111.0, MFloatEps)) {
3757 cerr << "Warning: sponge boundary Id " << bcSpId << " info ( rank " << domainId() << " ): " << endl;
3758 cerr << "Warning: boundary cell edge couldn't be found" << endl;
3759 cerr << "sponge edge coordinate[" << s3 << "] = " << spongeCoordMin2 << endl;
3760 cerr << "sponge edge coordinate[" << s3 << "] = " << spongeCoordMax2 << endl;
3761 cerr << "sponge edge coordinate[" << s1 << "] = " << spongeCoordMin << endl;
3762 cerr << "sponge edge coordinate[" << s1 << "] = " << spongeCoordMax << endl;
3763 cerr << "sponge cells defined up to coordinate[" << s2 << "] = " << m_spongeCoord[bcId] << endl;
3764 mTerm(1, AT_, "Warning: boundary cell edge couldn't be found");
3765 }
3766 }
3767 }
3768 else { // 2D code
3769 // find min sponge edge - only for information
3770 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
3771 cellId = m_sortedSpongeBndryCells->a[id];
3772 cellFaceCoordinate = m_solver->a_coordinate(cellId, s1) - F1B2 * m_solver->c_cellLengthAtCell(cellId);
3773 spongeCoordMin = mMin(spongeCoordMin, cellFaceCoordinate);
3774 }
3775
3776 // find max sponge edge - only for information and define max sponge area in spongeCoordDirection
3777 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
3778 cellId = m_sortedSpongeBndryCells->a[id];
3779 halfCellWidth = F1B2 * m_solver->c_cellLengthAtCell(cellId);
3780 cellFaceCoordinate = m_solver->a_coordinate(cellId, s1) + halfCellWidth;
3781 if(spongeCoordMax < cellFaceCoordinate) {
3782 spongeCoordMax = cellFaceCoordinate;
3783 if(m_spongeFactor[bcId] > 0) {
3784 m_spongeCoord[bcId] =
3785 m_solver->a_coordinate(cellId, s2) + m_spongeLayerThickness * m_spongeFactor[bcId] - halfCellWidth;
3786 spongeCoordFace = m_solver->a_coordinate(cellId, s2) - halfCellWidth;
3787 } else {
3788 m_spongeCoord[bcId] =
3789 m_solver->a_coordinate(cellId, s2) + m_spongeLayerThickness * m_spongeFactor[bcId] + halfCellWidth;
3790 spongeCoordFace = m_solver->a_coordinate(cellId, s2) + halfCellWidth;
3791 }
3792 }
3793 }
3794 if(noDomains() == 1) {
3795 if(approx(spongeCoordMin, 10000.0, MFloatEps) || approx(spongeCoordMax, -10000.0, MFloatEps)
3796 || approx(m_spongeCoord[bcId], -111111.0, MFloatEps)) {
3797 mTerm(1, AT_, " boundary cell edge couldn't be found");
3798 }
3799 }
3800 }
3801
3802
3803 // MPI exchange of sponge coordinates + sponge boundary Id + algorithm going over all cells
3804 MPI_Allreduce(MPI_IN_PLACE, &spongeCoordMin, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
3805 "spongeCoordMin");
3806 MPI_Allreduce(MPI_IN_PLACE, &spongeCoordMax, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
3807 "spongeCoordMax");
3808 IF_CONSTEXPR(nDim == 3) {
3809 MPI_Allreduce(MPI_IN_PLACE, &spongeCoordMin2, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
3810 "spongeCoordMin2");
3811 MPI_Allreduce(MPI_IN_PLACE, &spongeCoordMax2, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
3812 "spongeCoordMax2");
3813 }
3814 MPI_Allreduce(MPI_IN_PLACE, &m_spongeCoord[bcId], 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
3815 "m_spongeCoord[ bcId ]");
3816 MPI_Allreduce(MPI_IN_PLACE, &spongeCoordFace, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
3817 "spongeCoordFace");
3818
3819 IF_CONSTEXPR(nDim == 3) {
3820 m_log << "sponge edge coordinate[" << s3 << "] = " << spongeCoordMin2 << endl;
3821 m_log << "sponge edge coordinate[" << s3 << "] = " << spongeCoordMax2 << endl;
3822 }
3823 m_log << "sponge edge coordinate[" << s1 << "] = " << spongeCoordMin << endl;
3824 m_log << "sponge edge coordinate[" << s1 << "] = " << spongeCoordMax << endl;
3825 m_log << "sponge face coordinate[" << s2 << "] = " << spongeCoordFace << endl;
3826 m_log << "sponge cells defined up to coordinate[" << s2 << "] = " << m_spongeCoord[bcId] << endl;
3827
3828 minSpongeCoords[2 * bcId] = spongeCoordMin;
3829 minSpongeCoords[2 * bcId + 1] = spongeCoordMin2;
3830 maxSpongeCoords[2 * bcId] = spongeCoordMax;
3831 maxSpongeCoords[2 * bcId + 1] = spongeCoordMax2;
3832
3833 // Check for a previous sponge boundary in the same direction and prevent overwriting its
3834 // values Note: this does not work properly for more than 2 sponge boundaries in one direction
3835 const MInt dir = m_spongeDirections[bcId];
3836 MBool isAdditionalSpongeInDir = false;
3837 MInt firstSpongeBcIdInDir = -1;
3838 MInt firstSpongeIdInDir = -1;
3839 for(MInt i = 0; i < bcId; i++) {
3840 if(m_spongeDirections[i] == dir) {
3841 isAdditionalSpongeInDir = true;
3842 firstSpongeBcIdInDir = m_spongeBndryCndIds[i];
3843 firstSpongeIdInDir = i;
3844 break;
3845 }
3846 }
3847 if(isAdditionalSpongeInDir) {
3848 m_log << "additional sponge in direction " << dir << ", skipping cells with BC " << firstSpongeBcIdInDir
3849 << " intersection" << std::endl;
3850 }
3851
3852 // determine sponge cells
3853 m_log << "Creating ";
3854 oldSortedSpongeBndryCellsSize = m_spongeBndryCells[bcId + 1];
3855
3856 for(MInt id = 0; id < m_solver->a_noCells(); id++) {
3857 // continue for sponge cells at boundary, already in list
3858 if(m_solver->a_hasProperty(id, SolverCell::IsInSpongeLayer)) continue;
3859 if(m_solver->c_noChildren(id) > 0) continue;
3860
3861 if(vz == 0 && m_solver->a_coordinate(id, s2) < m_spongeCoord[bcId]) continue;
3862 if(vz == 1 && m_solver->a_coordinate(id, s2) > m_spongeCoord[bcId]) continue;
3863
3864 if(m_solver->a_coordinate(id, s1) > spongeCoordMax) continue;
3865 if(m_solver->a_coordinate(id, s1) < spongeCoordMin) continue;
3866 IF_CONSTEXPR(nDim == 3) {
3867 if(m_solver->a_coordinate(id, s3) > spongeCoordMax2) continue;
3868 if(m_solver->a_coordinate(id, s3) < spongeCoordMin2) continue;
3869 }
3870
3871 // Check for a bcId intersection if this an additional sponge in this direction
3872 if(isAdditionalSpongeInDir) {
3873 std::set<MInt> bcIds;
3874 MFloat line[2 * nDim];
3875 const MFloat halfLength = 0.5 * m_solver->c_cellLengthAtCell(id);
3876
3877 MBool skip = false;
3878
3879 // TODO labels:FV speedup by checking bounding box of additional sponge in direction
3880 MBool insideBox = true;
3881 {
3882 const MFloat pos1 = m_solver->a_coordinate(id, s1);
3883 const MFloat pos2 = m_solver->a_coordinate(id, s3);
3884 const MInt offset = 2 * firstSpongeIdInDir;
3885 if(pos1 + halfLength < minSpongeCoords[offset] || pos1 - halfLength > maxSpongeCoords[offset]) {
3886 insideBox = false;
3887 } else if(pos2 + halfLength < minSpongeCoords[offset + 1]
3888 || pos2 - halfLength > maxSpongeCoords[offset + 1]) {
3889 insideBox = false;
3890 }
3891 }
3892
3893 // Loop over all cell corner coordinates in the boundary plane
3894 if(insideBox) {
3895 const MFloat outDir = (vz == 0) ? 1.0 : -1.0;
3896 for(MInt i = 0; i < 2 && !skip; i++) {
3897 for(MInt j = 0; j < (nDim - 1) && !skip; j++) {
3898 std::copy_n(&m_solver->a_coordinate(id, 0), nDim, &line[0]);
3899 std::copy_n(&m_solver->a_coordinate(id, 0), nDim, &line[nDim]);
3900 // Second point lies outside the geometry
3901 line[s2] = line[s2] + outDir * 2 * m_solver->c_cellLengthAtLevel(0);
3902
3903 line[s1] -= pow(-1.0, i) * halfLength;
3904 line[s1 + nDim] = line[s1];
3905
3906 IF_CONSTEXPR(nDim == 3) {
3907 line[s3] -= pow(-1.0, j) * halfLength;
3908 line[s3 + nDim] = line[s3];
3909 }
3910
3911 // Get boundary condition ids cut by the line from the cell corner through the
3912 // boundary plane and check if the first sponge-bc id is present and skip if so
3913 m_solver->m_geometry->getLineIntersectingElementsBcIds(line, bcIds);
3914 if(bcIds.size() > 0 && (bcIds.count(firstSpongeBcIdInDir) > 0)) {
3915 skip = true;
3916 }
3917 }
3918 }
3919 }
3920 if(skip) continue;
3921 }
3922
3923 m_sortedSpongeBndryCells->a[m_sortedSpongeBndryCells->size()] = id;
3924 m_sortedSpongeBndryCells->append();
3925 }
3926 m_spongeBndryCells[bcId + 1] = m_sortedSpongeBndryCells->size();
3927 // reseting property 14, will be set later and needed for spongefactor calculation
3928 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
3929 currentSpongeCellId = m_sortedSpongeBndryCells->a[id];
3930 m_solver->a_hasProperty(currentSpongeCellId, SolverCell::IsInSpongeLayer) = false;
3931 }
3932
3933 if(noDomains() == 0) {
3934 if(oldSortedSpongeBndryCellsSize == m_sortedSpongeBndryCells->size()) {
3935 m_log << "Warning: Only first row of sponge boundary ID " << m_spongeBndryCndIds[bcId]
3936 << " was identified as sponge cells" << endl;
3937 m_log << " Possible reason could be that the spongeFactor has to be multiplied by -1" << endl;
3938 m_log << " Possible reason could be wrong sponge coordinates communicated" << endl;
3939 cerr << "Warning: Only first row of sponge boundary ID " << m_spongeBndryCndIds[bcId]
3940 << " was identified as sponge cells" << endl;
3941 cerr << " Possible reason could be that the spongeFactor has to be multiplied by -1" << endl;
3942 cerr << " Possible reason could be wrong sponge coordinates communicated" << endl;
3943 }
3944 }
3945 m_log << m_sortedSpongeBndryCells->size() - oldSortedSpongeBndryCellsSize << " additional sponge cells ... ";
3946 m_log << " ok" << endl;
3947 m_spongeBndryCells[bcId + 1] = m_sortedSpongeBndryCells->size();
3948 m_log << "total number of sponge cells " << m_spongeBndryCells[bcId + 1] - m_spongeBndryCells[bcId] << endl;
3949 m_log << "*************************************************" << endl << endl;
3950 MInt startBcId = 0;
3951 MInt endBcId = bcId;
3952
3953 // setting sponge information for all other sponge boundary ids, which were already identified to identifiy
3954 // overlapping sponge cells and sponge boundary ids
3955 for(MInt id = m_spongeBndryCells[startBcId]; id < m_spongeBndryCells[endBcId]; id++) {
3956 spongeCellId = m_sortedSpongeBndryCells->a[id];
3957 m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer) = true;
3958 }
3959
3960 switch(m_spongeLayerLayout) {
3961 case 0: {
3962 const MFloat spongeThicknessEpsilon = m_spongeLayerThickness / 10000000.0;
3963 MFloat spongeEpsilon = m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel()) / 1000.0;
3964 MFloat beta = m_spongeBeta;
3965 MFloat constant;
3966 MFloat spongeFactorBcId = m_spongeLayerThickness * abs(m_spongeFactor[bcId]);
3967 MFloat spongeDistanceFactor = F1 / (mMax(spongeEpsilon, spongeFactorBcId));
3968 MFloat spongeDistance = F0;
3969
3970 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
3971 bcSpId = m_spongeBndryCndIds[bcId];
3972 spongeCellId = m_sortedSpongeBndryCells->a[id];
3973 if(m_solver->a_isHalo(spongeCellId)) cntHalo++;
3974 // compute the max sigma sponge value if already identified in one sponge area
3975 if(m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer)) {
3976 // compute the distance to the spongeCoordinate
3977 spongeDistance = abs(m_solver->a_coordinate(spongeCellId, s2) - m_spongeCoord[bcId]) * spongeDistanceFactor;
3978 distance.p[spongeCellId] = mMax(distance.p[spongeCellId], spongeDistance);
3979 // compute the dissipation function...
3980 // if(bcSpId==17616)
3981 // constant = tanh(distance.p[spongeCellId]*5.0);
3982 // else
3983 constant = pow(distance.p[spongeCellId], beta);
3984 constant *= m_sigmaSpongeBndryId[bcId];
3985
3986 // if distance to small than sponge cell keeps the spongeFactor that it already owns
3987 if(distance.p[spongeCellId] > spongeThicknessEpsilon) {
3988 if(m_solver->a_spongeBndryId(spongeCellId, 1) == -1) {
3989 // second sponge Id of the sponge cell which lays in two sponge areas
3990 m_solver->a_spongeBndryId(spongeCellId, 1) = bcSpId;
3991 // compute the max sponge Factor for sponge cells which are laying in two sponge areas
3992 m_solver->a_spongeFactor(spongeCellId) = mMax(constant, m_solver->a_spongeFactor(spongeCellId));
3993 } else if(nDim == 3 && m_solver->a_spongeBndryId(spongeCellId, 2) == -1) {
3994 // third sponge Id of the sponge cell which lays in third sponge areas (only possible for 3 dimensional
3995 // cases)
3996 m_solver->a_spongeBndryId(spongeCellId, 2) = bcSpId;
3997 m_solver->a_spongeFactor(spongeCellId) = mMax(constant, m_solver->a_spongeFactor(spongeCellId));
3998 if(!m_solver->a_isHalo(spongeCellId)) count++;
3999 IF_CONSTEXPR(nDim == 2) {
4000 cerr << "ERROR: three sponge boundary Ids: " << m_solver->a_spongeBndryId(spongeCellId, 0) << ", "
4001 << m_solver->a_spongeBndryId(spongeCellId, 1) << ", ";
4002 cerr << m_solver->a_spongeBndryId(spongeCellId, 2)
4003 << "founded for one cell -> not possible for 2 dimensional case" << endl;
4004 stringstream errorMessage;
4005 errorMessage << " three sponge boundary Ids: " << m_solver->a_spongeBndryId(spongeCellId, 0) << ", "
4006 << m_solver->a_spongeBndryId(spongeCellId, 1) << ", "
4007 << m_solver->a_spongeBndryId(spongeCellId, 2)
4008 << "founded for one cell -> not possible for 2 dimensional case";
4009 mTerm(1, AT_, errorMessage.str());
4010 }
4011 } else {
4012 stringstream errorMessage;
4013 IF_CONSTEXPR(nDim == 3) {
4014 errorMessage << "four sponge boundary Ids: " << m_solver->a_spongeBndryId(spongeCellId, 0) << ", "
4015 << m_solver->a_spongeBndryId(spongeCellId, 1) << ", "
4016 << m_solver->a_spongeBndryId(spongeCellId, 2) << ", " << bcSpId
4017 << "founded for one cell -> not possible for 3 dimensional case";
4018 }
4019 else {
4020 errorMessage << "three sponge boundary Ids: " << m_solver->a_spongeBndryId(spongeCellId, 0) << ", "
4021 << m_solver->a_spongeBndryId(spongeCellId, 1) << ", " << bcSpId
4022 << "founded for one cell -> not possible for 2 dimensional case";
4023 }
4024 mTerm(1, AT_, errorMessage.str());
4025 }
4026 if(m_solver->m_spongeTimeDependent[bcId] > 0)
4027 m_solver->a_spongeFactorStart(spongeCellId) = m_solver->a_spongeFactor(spongeCellId);
4028
4029 maxSpongeFactorOverlap = mMax(maxSpongeFactorOverlap, m_solver->a_spongeFactor(spongeCellId));
4030 minSpongeFactorOverlap = mMin(minSpongeFactorOverlap, m_solver->a_spongeFactor(spongeCellId));
4031 // if(!(m_solver->a_spongeFactor(spongeCellId))<=0 && !(m_solver->a_spongeFactor(spongeCellId)) >=0)
4032 // cerr << m_solver->a_spongeFactor(spongeCellId)<< endl;
4033 }
4034 } else { // cells which are not already identified as sponge cells
4035
4036 m_solver->a_spongeFactor(spongeCellId) = F0;
4037 // compute the distance to the spongeCoordinate
4038 distance.p[spongeCellId] =
4039 abs(m_solver->a_coordinate(spongeCellId, s2) - m_spongeCoord[bcId]) * spongeDistanceFactor;
4040 // compute the dissipation function...
4041 // if(bcSpId==17616)
4042 // constant = tanh(distance.p[spongeCellId]*5.0);
4043 // else
4044 constant = pow(distance.p[spongeCellId], beta);
4045 constant *= m_sigmaSpongeBndryId[bcId];
4046
4047 if(distance.p[spongeCellId] > spongeThicknessEpsilon) {
4048 m_solver->m_cellsInsideSpongeLayer[m_solver->m_noCellsInsideSpongeLayer] = spongeCellId;
4049 m_solver->m_noCellsInsideSpongeLayer++;
4050 if(m_solver->a_isHalo(spongeCellId)) cntHaloInside++;
4051
4052 m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer) = true;
4053 m_solver->a_spongeFactor(spongeCellId) = constant;
4054 if(m_solver->m_spongeTimeDependent[bcId] > 0) m_solver->a_spongeFactorStart(spongeCellId) = constant;
4055
4056 m_solver->a_spongeBndryId(spongeCellId, 0) = bcSpId;
4057 m_solver->a_spongeBndryId(spongeCellId, 1) =
4058 -1; // second possible sponge Id if the cell is laying in two sponge areas
4059 // for 3 dimensional case
4060 IF_CONSTEXPR(nDim == 3) {
4061 m_solver->a_spongeBndryId(spongeCellId, 2) =
4062 -1; // third possible sponge Id if the cell is laying in two sponge areas
4063 }
4064 // if(!(m_solver->a_spongeFactor( spongeCellId ))<=0 && !(m_solver->a_spongeFactor( spongeCellId )) >=0)
4065 // {
4066 // cerr << m_solver->a_spongeFactor( spongeCellId ) << endl;
4067 // mTerm(1,AT_);
4068 // }
4069 maxSpongeFactor = mMax(maxSpongeFactor, m_solver->a_spongeFactor(spongeCellId));
4070 minSpongeFactor = mMin(minSpongeFactor, m_solver->a_spongeFactor(spongeCellId));
4071 }
4072 }
4073 }
4074 break;
4075 }
4076 // tanh function for sponge forcing
4077 case 10: {
4078 const MFloat spongeThicknessEpsilon = m_spongeLayerThickness / 10000000.0;
4079 MFloat spongeEpsilon = m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel()) / 1000.0;
4080 MFloat constant;
4081 MFloat spongeFactorBcId = m_spongeLayerThickness * abs(m_spongeFactor[bcId]);
4082 MFloat spongeDistanceFactor = F1 / (mMax(spongeEpsilon, spongeFactorBcId));
4083 MFloat spongeDistance = F0;
4084 /*
4085 if(m_spongeBndryCndIds[bcId]==17616 && m_solver->m_spongeTimeDependent[bcId]>0){
4086 MString errorMessage="check code for bcId 17616 and sponge time dependent because tanh function for
4087 spongeFactor calc is used"; mTerm(AT_,1,errorMessage);
4088 }
4089 */
4090 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
4091 bcSpId = m_spongeBndryCndIds[bcId];
4092 spongeCellId = m_sortedSpongeBndryCells->a[id];
4093 if(m_solver->a_isHalo(spongeCellId)) cntHalo++;
4094 // compute the max sigma sponge value if already identified in one sponge area
4095 if(m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer)) {
4096 // compute the distance to the spongeCoordinate
4097 spongeDistance = abs(m_solver->a_coordinate(spongeCellId, s2) - m_spongeCoord[bcId]) * spongeDistanceFactor;
4098 distance.p[spongeCellId] = mMax(distance.p[spongeCellId], spongeDistance);
4099 // compute the dissipation function...
4100 constant = F1 - F1B2 * tanh(5.0) + F1B2 * tanh((F2 * (distance.p[spongeCellId]) - F1) * 5.0);
4101 constant *= m_sigmaSpongeBndryId[bcId];
4102 // if distance to small than sponge cell keeps the spongeFactor that it already owns
4103 if(distance.p[spongeCellId] > spongeThicknessEpsilon) {
4104 if(m_solver->a_spongeBndryId(spongeCellId, 1) == -1) {
4105 // second sponge Id of the sponge cell which lays in two sponge areas
4106 m_solver->a_spongeBndryId(spongeCellId, 1) = bcSpId;
4107 // compute the max sponge Factor for sponge cells which are laying in two sponge areas
4108 m_solver->a_spongeFactor(spongeCellId) = mMax(constant, m_solver->a_spongeFactor(spongeCellId));
4109 } else if(nDim == 3 && m_solver->a_spongeBndryId(spongeCellId, 2) == -1) {
4110 // third sponge Id of the sponge cell which lays in third sponge areas (only possible for 3 dimensional
4111 // cases)
4112 m_solver->a_spongeBndryId(spongeCellId, 2) = bcSpId;
4113 m_solver->a_spongeFactor(spongeCellId) = mMax(constant, m_solver->a_spongeFactor(spongeCellId));
4114 if(!m_solver->a_isHalo(spongeCellId)) count++;
4115 IF_CONSTEXPR(nDim == 2) {
4116 cerr << "ERROR: three sponge boundary Ids: " << m_solver->a_spongeBndryId(spongeCellId, 0) << ", "
4117 << m_solver->a_spongeBndryId(spongeCellId, 1) << ", ";
4118 cerr << m_solver->a_spongeBndryId(spongeCellId, 2)
4119 << "founded for one cell -> not possible for 2 dimensional case" << endl;
4120 mTerm(1, AT_);
4121 }
4122 } else {
4123 cerr << "ERROR: four sponge boundary Ids: " << m_solver->a_spongeBndryId(spongeCellId, 0) << ", "
4124 << m_solver->a_spongeBndryId(spongeCellId, 1) << ", ";
4125 cerr << m_solver->a_spongeBndryId(spongeCellId, 2) << ", " << bcSpId
4126 << "founded for one cell -> not possible for 3 dimensional case" << endl;
4127 mTerm(1, AT_);
4128 }
4129
4130 if(m_solver->m_spongeTimeDependent[bcId] > 0)
4131 m_solver->a_spongeFactorStart(spongeCellId) = m_solver->a_spongeFactor(spongeCellId);
4132
4133 maxSpongeFactorOverlap = mMax(maxSpongeFactorOverlap, m_solver->a_spongeFactor(spongeCellId));
4134 minSpongeFactorOverlap = mMin(minSpongeFactorOverlap, m_solver->a_spongeFactor(spongeCellId));
4135 // if(!(m_solver->a_spongeFactor( spongeCellId))<=0 && !(m_solver->a_spongeFactor( spongeCellId)) >=0)
4136 // cerr << m_solver->a_spongeFactor(spongeCellId) << endl;
4137 }
4138 } else { // cells which are not already identified as sponge cells
4139
4140 m_solver->a_spongeFactor(spongeCellId) = F0;
4141 // compute the distance to the spongeCoordinate
4142 distance.p[spongeCellId] =
4143 abs(m_solver->a_coordinate(spongeCellId, s2) - m_spongeCoord[bcId]) * spongeDistanceFactor;
4144 // compute the dissipation function...
4145 constant =
4146 F1 - F1B2 * tanh(5.0) + F1B2 * tanh((F2 * (distance.p[spongeCellId]) - F1) * 5.0); // stephans tanh
4147 // constant = POW2(distance.p[spongeCellId]); // standard x^2
4148 // constant = F1B2 - F1B2*cos(PI*distance.p[spongeCellId]);
4149
4150 constant *= m_sigmaSpongeBndryId[bcId];
4151
4152 if(distance.p[spongeCellId] > spongeThicknessEpsilon) {
4153 m_solver->m_cellsInsideSpongeLayer[m_solver->m_noCellsInsideSpongeLayer] = spongeCellId;
4154 m_solver->m_noCellsInsideSpongeLayer++;
4155 if(m_solver->a_isHalo(spongeCellId)) cntHaloInside++;
4156
4157 m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer) = true;
4158 m_solver->a_spongeFactor(spongeCellId) = constant;
4159 if(m_solver->m_spongeTimeDependent[bcId] > 0) m_solver->a_spongeFactorStart(spongeCellId) = constant;
4160
4161 m_solver->a_spongeBndryId(spongeCellId, 0) = bcSpId;
4162 m_solver->a_spongeBndryId(spongeCellId, 1) =
4163 -1; // second possible sponge Id if the cell is laying in two sponge areas
4164 // for 3 dimensional case
4165 IF_CONSTEXPR(nDim == 3) {
4166 m_solver->a_spongeBndryId(spongeCellId, 2) =
4167 -1; // third possible sponge Id if the cell is laying in two sponge areas
4168 }
4169 // if(!(m_solver->a_spongeFactor( spongeCellId ))<=0 && !(m_solver->a_spongeFactor( spongeCellId )) >=0)
4170 // {
4171 // cerr << m_solver->a_spongeFactor( spongeCellId ) << endl;
4172 // mTerm(1,AT_);
4173 // }
4174 maxSpongeFactor = mMax(maxSpongeFactor, m_solver->a_spongeFactor(spongeCellId));
4175 minSpongeFactor = mMin(minSpongeFactor, m_solver->a_spongeFactor(spongeCellId));
4176 }
4177 }
4178 }
4179 break;
4180 }
4181 default: {
4182 stringstream errorMessage;
4183 errorMessage << "ERROR: spongeLayerLayout " << m_spongeLayerLayout << " does not exist!" << endl;
4184 mTerm(1, AT_, errorMessage.str());
4185 }
4186 }
4187 // reseting sponge information of all boundary Ids to identifiy overlapping sponge cells at more than one boundary
4188 for(MInt id = m_spongeBndryCells[startBcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
4189 spongeCellId = m_sortedSpongeBndryCells->a[id];
4190 m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer) = false;
4191 }
4192 }
4193 MInt noHaloSpongeCells = cntHalo;
4194 MInt noSpongeCells = m_spongeBndryCells[m_noSpongeBndryCndIds] - cntHalo;
4195 MInt noInternalSpongeCells = m_solver->m_noCellsInsideSpongeLayer - cntHaloInside;
4196 MInt noOverlappingSpongeCells3d = count;
4197
4198 MPI_Allreduce(MPI_IN_PLACE, &noHaloSpongeCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
4199 "noHaloSpongeCells");
4200 MPI_Allreduce(MPI_IN_PLACE, &noSpongeCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noSpongeCells");
4201 MPI_Allreduce(MPI_IN_PLACE, &noInternalSpongeCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
4202 "noInternalSpongeCells");
4203
4204 IF_CONSTEXPR(nDim == 3)
4205 MPI_Allreduce(MPI_IN_PLACE, &noOverlappingSpongeCells3d, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
4206 "noOverlappingSpongeCells3d");
4207 MPI_Allreduce(MPI_IN_PLACE, &maxSpongeFactor, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
4208 "maxSpongeFactor");
4209 MPI_Allreduce(MPI_IN_PLACE, &minSpongeFactor, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
4210 "minSpongeFactor");
4211 MPI_Allreduce(MPI_IN_PLACE, &maxSpongeFactorOverlap, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
4212 "maxSpongeFactorOverlap");
4213 MPI_Allreduce(MPI_IN_PLACE, &minSpongeFactorOverlap, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
4214 "minSpongeFactorOverlap");
4215
4216 m_log << "*********************" << endl;
4217 m_log << "Sponge cell summary" << endl;
4218 m_log << "*********************" << endl;
4219 m_log << noSpongeCells << " sponge cells + " << endl;
4220 m_log << noHaloSpongeCells << " sponge halo cells created" << endl;
4221 m_log << "with " << noInternalSpongeCells << " internal sponge cells and " << endl;
4222 m_log << "with " << noSpongeCells - noInternalSpongeCells - noOverlappingSpongeCells3d
4223 << " sponge cells laying in 2 sponge areas and " << endl;
4224 m_log << "with " << noOverlappingSpongeCells3d << " sponge cells laying in 3 sponge areas " << endl;
4225 m_log << "max sponge factor: " << maxSpongeFactor << endl;
4226 m_log << "min sponge factor: " << minSpongeFactor << endl;
4227 m_log << "max sponge factor overlap: " << maxSpongeFactorOverlap << endl;
4228 m_log << "min sponge factor overlap: " << minSpongeFactorOverlap << endl;
4229 m_log << endl;
4230 if((!(maxSpongeFactor >= F0) && !(maxSpongeFactor <= F0)) || (!(minSpongeFactor >= F0) && !(minSpongeFactor <= F0))) {
4231 mTerm(1, AT_, "error: maximum sponge factor is nan");
4232 }
4233 if(maxSpongeFactor < 0 || minSpongeFactor < 0) {
4234 mTerm(1, AT_, "sponge Factor is negative");
4235 }
4236 if(m_spongeTimeDep) {
4237 m_log << "***********************************" << endl;
4238 m_log << "Time dependent sponge cell summary" << endl;
4239 m_log << "***********************************" << endl;
4240 for(MInt bcId = 0; bcId < m_noSpongeBndryCndIds; bcId++) {
4241 bcSpId = m_spongeBndryCndIds[bcId];
4242 if(m_spongeTimeDependent[bcId] < 1) continue;
4243 if(m_spongeTimeDependent[bcId] == 1) {
4244 m_log << "time dependent sponge decreasing function at sponge boundary " << bcSpId << endl;
4245 m_log << "sponge decreasing start at iteration: " << m_spongeStartIteration[bcId] << endl;
4246 m_log << "sponge decreasing end at iteration: " << m_spongeEndIteration[bcId] << endl;
4247 m_log << "sponge start value: " << m_sigmaSpongeBndryId[bcId] << endl;
4248 m_log << "sponge end value will be zero" << endl << endl;
4249 } else if(m_spongeTimeDependent[bcId] == 2) {
4250 m_log << "time dependent sponge increasing function at sponge boundary " << bcSpId << endl;
4251 m_log << "sponge increasing start at iteration: " << m_spongeStartIteration[bcId] << endl;
4252 m_log << "sponge increasing end at iteration: " << m_spongeEndIteration[bcId] << endl << endl;
4253 } else if(m_spongeTimeDependent[bcId] == 3) {
4254 m_log << "time dependent sponge decreasing function at sponge boundary " << bcSpId << endl;
4255 m_log << "sponge decreasing start at iteration: " << m_spongeStartIteration[bcId] << endl;
4256 m_log << "sponge decreasing end at iteration: " << m_spongeEndIteration[bcId] << endl;
4257 m_log << "sponge start value: " << m_sigmaSpongeBndryId[bcId] << endl;
4258 m_log << "sponge end value: " << m_sigmaEndSpongeBndryId[bcId] << endl << endl;
4259 }
4260 }
4261 }
4262
4263 // setting property 14 for all sponge cells
4264 for(MInt bcId = 0; bcId < m_noSpongeBndryCndIds; bcId++) {
4265 for(MInt id = m_spongeBndryCells[bcId]; id < m_spongeBndryCells[bcId + 1]; id++) {
4266 spongeCellId = m_sortedSpongeBndryCells->a[id];
4267 m_solver->a_hasProperty(spongeCellId, SolverCell::IsInSpongeLayer) = true;
4268 }
4269 }
4270
4271 // this following line should be removed if we switch to a use of function pointers to the specific sponge bounary
4272 // condition
4273 m_sortedSpongeBndryCells->setSize(0);
4274}
4275
4276// --------------------------------------------------------------------
4277
4278
4284template <MInt nDim, class SysEqn>
4286 TRACE();
4287
4288 MInt noDirs = 2 * nDim;
4289 MInt cellId;
4290 MInt bndryId;
4291 MInt nghbrId;
4292 MInt ghostCellId;
4293 MInt temp;
4294 MInt bnd;
4295 MInt id;
4296 MInt linkedCell;
4297 MInt noReconstructIds = 0;
4298 ScratchSpace<MInt> reconstructIds(100, AT_, "reconstructIds");
4299 //---
4300
4301 for(MInt bc = m_bndryCndCells[bcId]; bc < m_bndryCndCells[bcId + 1]; bc++) {
4302 bndryId = m_sortedBndryCells->a[bc];
4303 cellId = m_bndryCells->a[bndryId].m_cellId;
4304 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
4305 if(m_bndryCells->a[bndryId].m_linkedCellId == -1) {
4306 // reset
4307 noReconstructIds = 0;
4308
4309 // add the ghost cell
4310 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
4311 reconstructIds[noReconstructIds] = ghostCellId;
4312 noReconstructIds++;
4313
4314 // add all neighbors
4315 for(MInt c = m_solver->m_identNghbrIds[cellId * noDirs]; c < m_solver->m_identNghbrIds[(cellId + 1) * noDirs];
4316 c++) {
4317 reconstructIds[noReconstructIds] = m_solver->m_storeNghbrIds[c];
4318 noReconstructIds++;
4319 }
4320
4321 // identify boundary neighbors: add their internal neighbors
4322 temp = noReconstructIds;
4323 for(MInt k = 0; k < temp; k++) {
4324 id = reconstructIds[k];
4325 bnd = m_solver->a_bndryId(id);
4326 if(bnd > -1) {
4327 for(MInt c = m_solver->m_identNghbrIds[id * noDirs]; c < m_solver->m_identNghbrIds[(id + 1) * noDirs];
4328 c++) {
4329 nghbrId = m_solver->m_storeNghbrIds[c];
4330 if(m_solver->a_bndryId(nghbrId) == -1) {
4331 reconstructIds[noReconstructIds] = nghbrId;
4332 noReconstructIds++;
4333 }
4334 }
4335 }
4336 }
4337
4338 // replace slave neighbors by their master cells
4339 // if master==cellId add all neighbors of the slave cell
4340 temp = noReconstructIds;
4341 for(MInt k = 0; k < temp; k++) {
4342 id = reconstructIds[k];
4343 bnd = m_solver->a_bndryId(id);
4344 if(bnd > -1) {
4345 linkedCell = m_bndryCells->a[bnd].m_linkedCellId;
4346 if(linkedCell > -1) {
4347 reconstructIds[k] = linkedCell;
4348 if(linkedCell == cellId) {
4349 for(MInt c = m_solver->m_identNghbrIds[id * noDirs]; c < m_solver->m_identNghbrIds[(id + 1) * noDirs];
4350 c++) {
4351 nghbrId = m_solver->m_storeNghbrIds[c];
4352 if(m_solver->a_bndryId(nghbrId) > -1) {
4353 if(m_bndryCells->a[m_solver->a_bndryId(nghbrId)].m_linkedCellId == -1) {
4354 reconstructIds[noReconstructIds] = nghbrId;
4355 noReconstructIds++;
4356 } else {
4357 reconstructIds[noReconstructIds] = m_bndryCells->a[m_solver->a_bndryId(nghbrId)].m_linkedCellId;
4358 noReconstructIds++;
4359 }
4360 } else {
4361 reconstructIds[noReconstructIds] = nghbrId;
4362 noReconstructIds++;
4363 }
4364 }
4365 }
4366 }
4367 }
4368 }
4369
4370 // remove cellId from list
4371 temp = noReconstructIds;
4372 for(MInt k = temp - 1; k > -1; k--) {
4373 if(reconstructIds[k] == cellId) {
4374 noReconstructIds--;
4375 reconstructIds[k] = reconstructIds[noReconstructIds];
4376 }
4377 }
4378
4379 // sort the list
4380 maia::math::quickSort(reconstructIds.begin(), 0, noReconstructIds - 1);
4381 m_solver->a_noReconstructionNeighbors(cellId) =
4382 mMin(m_cells.noRecNghbrs(), maia::math::removeDoubleEntries(reconstructIds.begin(), noReconstructIds));
4383
4384 for(MInt k = 0; k < m_solver->a_noReconstructionNeighbors(cellId); k++) {
4385 m_solver->a_reconstructionNeighborId(cellId, k) = reconstructIds[k];
4386 }
4387 }
4388 }
4389 }
4390}
4391
4392
4393//---------------------------------------------------------------------------------------------
4394
4395
4408template <MInt nDim, class SysEqn>
4409template <MBool MGC>
4411 TRACE();
4412
4413 static constexpr MInt noDirs = 2 * nDim;
4414 MInt temp = 0;
4415 MInt noReconstructIds = 0;
4416 MIntScratchSpace reconstructIds(MGC ? 100 : noDirs + 1, AT_, "reconstructIds");
4417 //---
4418
4419 // loop over all non-slave boundary cells
4420 for(MInt bc = m_bndryCndCells[bcId]; bc < m_bndryCndCells[bcId + 1]; bc++) {
4421 const MInt bndryId = m_sortedBndryCells->a[bc];
4422 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
4423 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
4424 if(m_solver->a_hasProperty(cellId, SolverCell::IsInvalid)) continue;
4425 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
4426 if((!MGC && m_bndryCells->a[bndryId].m_linkedCellId == -1)
4427 || (MGC && m_bndryCells->a[bndryId].m_linkedCellId > -1)) {
4428 // reset
4429 noReconstructIds = 0;
4430
4431 if(MGC) {
4432 // add the ghost cell
4433 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
4434 reconstructIds[noReconstructIds] = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
4435 noReconstructIds++;
4436 }
4437 } else {
4438 // add the ghost cell
4439 reconstructIds.p[noReconstructIds] = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
4440 noReconstructIds = 1;
4441 }
4442
4443 // add all neighbors
4444 for(MInt c = m_solver->m_identNghbrIds[cellId * noDirs]; c < m_solver->m_identNghbrIds[(cellId + 1) * noDirs];
4445 c++) {
4446 reconstructIds.p[noReconstructIds] = m_solver->m_storeNghbrIds[c];
4447 noReconstructIds++;
4448 }
4449
4450 // replace slave neighbors by their master cells
4451 // if master==cellId add all neighbors of the slave cell
4452 temp = noReconstructIds;
4453 for(MInt k = 0; k < temp; k++) {
4454 const MInt id = reconstructIds.p[k];
4455 if(m_solver->a_bndryId(id) > -1) {
4456 const MInt linkedCell = m_bndryCells->a[m_solver->a_bndryId(id)].m_linkedCellId;
4457 if(linkedCell > -1) {
4458 reconstructIds.p[k] = linkedCell;
4459 if(linkedCell == cellId) {
4460 for(MInt c = m_solver->m_identNghbrIds[id * noDirs]; c < m_solver->m_identNghbrIds[(id + 1) * noDirs];
4461 c++) {
4462 const MInt nghbrId = m_solver->m_storeNghbrIds[c];
4463 if(m_solver->a_bndryId(nghbrId) > -1) {
4464 if(m_bndryCells->a[m_solver->a_bndryId(nghbrId)].m_linkedCellId == -1) {
4465 reconstructIds.p[noReconstructIds] = nghbrId;
4466 noReconstructIds++;
4467 } else {
4468 reconstructIds.p[noReconstructIds] = m_bndryCells->a[m_solver->a_bndryId(nghbrId)].m_linkedCellId;
4469 noReconstructIds++;
4470 }
4471 } else {
4472 reconstructIds.p[noReconstructIds] = nghbrId;
4473 noReconstructIds++;
4474 }
4475 }
4476 if(MGC) {
4477 MInt bnd = m_solver->a_bndryId(id);
4478 // add other ghost-cells to the reconstruction stencil
4479 for(MInt srfcSM = 0; srfcSM < m_bndryCells->a[bnd].m_noSrfcs; srfcSM++) {
4480 reconstructIds[noReconstructIds] = m_bndryCells->a[bnd].m_srfcVariables[srfcSM]->m_ghostCellId;
4481 noReconstructIds++;
4482 }
4483 }
4484 }
4485 }
4486 }
4487 }
4488
4489 // remove cellId from list
4490 temp = noReconstructIds;
4491 for(MInt k = temp - 1; k > -1; k--) {
4492 if(reconstructIds.p[k] == cellId) {
4493 noReconstructIds--;
4494 reconstructIds.p[k] = reconstructIds.p[noReconstructIds];
4495 }
4496 }
4497
4498 // sort the list
4499 maia::math::quickSort(reconstructIds.getPointer(), 0, noReconstructIds - 1);
4500 m_solver->a_noReconstructionNeighbors(cellId) =
4501 maia::math::removeDoubleEntries(reconstructIds.getPointer(), noReconstructIds);
4502
4503 for(MInt k = 0; k < m_solver->a_noReconstructionNeighbors(cellId); k++) {
4504 m_solver->a_reconstructionNeighborId(cellId, k) = reconstructIds.p[k];
4505 }
4506 }
4507 }
4508 }
4509
4510 // compute the least-squares constants k_i for the ghost cell (Neumann bc)
4511 if(!MGC) {
4512 computeNeumannLSConstants(bcId);
4513 }
4514}
4515
4516
4517//---------------------------------------------------------------------------------------------
4518
4519
4528template <MInt nDim, class SysEqn>
4530 TRACE();
4531
4532 MInt noDirs = 2 * nDim;
4533 MInt requiredNoCells, tmpCell;
4534 IF_CONSTEXPR(nDim == 2) requiredNoCells = 7;
4535 IF_CONSTEXPR(nDim == 3) requiredNoCells = 9;
4536 MInt cellId, bndryId, nghbrId, ghostCellId, temp, bnd, id, linkedCell;
4537 MInt noReconstructIds;
4538 MIntScratchSpace reconstructIds(100, AT_, "reconstructIds");
4539 stack<MInt> tmpStack;
4540 //---
4541
4542 // loop over all non-slave boundary cells
4543 for(MInt bc = m_bndryCndCells[bcId]; bc < m_bndryCndCells[bcId + 1]; bc++) {
4544 bndryId = m_sortedBndryCells->a[bc];
4545 cellId = m_bndryCells->a[bndryId].m_cellId;
4546 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
4547 if(m_bndryCells->a[bndryId].m_linkedCellId == -1) {
4548 // reset
4549 noReconstructIds = 0;
4550
4551 // add the ghost cell
4552 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
4553 reconstructIds[noReconstructIds] = ghostCellId;
4554 noReconstructIds++;
4555
4556 // add all neighbors
4557 for(MInt c = m_solver->m_identNghbrIds[cellId * noDirs]; c < m_solver->m_identNghbrIds[(cellId + 1) * noDirs];
4558 c++) {
4559 reconstructIds[noReconstructIds] = m_solver->m_storeNghbrIds[c];
4560 noReconstructIds++;
4561 tmpStack.push(m_solver->m_storeNghbrIds[c]);
4562 }
4563
4564 while(noReconstructIds < requiredNoCells) {
4565 // put all cells on s stack
4566 for(MInt n = 0; n < noReconstructIds; n++) {
4567 tmpStack.push(reconstructIds[n]);
4568 }
4569
4570 // add all neighbors of reconstructIds
4571 while(!tmpStack.empty()) {
4572 tmpCell = tmpStack.top();
4573 tmpStack.pop();
4574 for(MInt c = m_solver->m_identNghbrIds[tmpCell * noDirs];
4575 c < m_solver->m_identNghbrIds[(tmpCell + 1) * noDirs];
4576 c++) {
4577 reconstructIds[noReconstructIds] = m_solver->m_storeNghbrIds[c];
4578 noReconstructIds++;
4579 }
4580 }
4581
4582 // replace slave neighbors by their master cells
4583 // a) if master==cellId add all neighbors of the slave cell
4584 temp = noReconstructIds;
4585 for(MInt k = 0; k < temp; k++) {
4586 id = reconstructIds[k];
4587 bnd = m_solver->a_bndryId(id);
4588 if(bnd > -1) {
4589 linkedCell = m_bndryCells->a[bnd].m_linkedCellId;
4590 if(linkedCell > -1) {
4591 reconstructIds[k] = linkedCell;
4592 if(linkedCell == cellId) {
4593 for(MInt c = m_solver->m_identNghbrIds[id * noDirs]; c < m_solver->m_identNghbrIds[(id + 1) * noDirs];
4594 c++) {
4595 nghbrId = m_solver->m_storeNghbrIds[c];
4596 if(m_solver->a_bndryId(nghbrId) > -1) {
4597 if(m_bndryCells->a[m_solver->a_bndryId(nghbrId)].m_linkedCellId == -1) {
4598 reconstructIds[noReconstructIds] = nghbrId;
4599 noReconstructIds++;
4600 } else {
4601 reconstructIds[noReconstructIds] = m_bndryCells->a[m_solver->a_bndryId(nghbrId)].m_linkedCellId;
4602 noReconstructIds++;
4603 }
4604 } else {
4605 reconstructIds[noReconstructIds] = nghbrId;
4606 noReconstructIds++;
4607 }
4608 }
4609 }
4610 }
4611 }
4612 }
4613 // b) remove all the small cells
4614 temp = noReconstructIds;
4615 for(MInt k = 0; k < temp; k++) {
4616 id = reconstructIds[k];
4617 bnd = m_solver->a_bndryId(id);
4618 if(bnd > -1) {
4619 linkedCell = m_bndryCells->a[bnd].m_linkedCellId;
4620 if(linkedCell > -1) reconstructIds[k] = linkedCell;
4621 }
4622 }
4623
4624 // remove cellId from list
4625 temp = noReconstructIds;
4626 for(MInt k = temp - 1; k > -1; k--) {
4627 if(reconstructIds[k] == cellId) {
4628 noReconstructIds--;
4629 reconstructIds[k] = reconstructIds[noReconstructIds];
4630 }
4631 }
4632
4633 // sort the list
4634 maia::math::quickSort(reconstructIds.begin(), 0, noReconstructIds - 1);
4635 m_solver->a_noReconstructionNeighbors(cellId) =
4636 maia::math::removeDoubleEntries(reconstructIds.begin(), noReconstructIds);
4637
4638 for(MInt k = 0; k < m_solver->a_noReconstructionNeighbors(cellId); k++)
4639 m_solver->a_reconstructionNeighborId(cellId, k) = reconstructIds[k];
4640 }
4641 }
4642 }
4643 }
4644
4645 // compute the least-squares constants k_i for the ghost cell (Neumann bc)
4646 computeNeumannLSConstants(bcId);
4647}
4648
4654template <MInt nDim, class SysEqn>
4656 TRACE();
4657
4658 m_bc1251ForcingAmplitude =
4659 Context::getSolverProperty<MFloat>("bc1251ForcingAmplitude", m_solverId, AT_, &m_bc1251ForcingAmplitude);
4660 m_bc1251ForcingWavelength =
4661 Context::getSolverProperty<MFloat>("bc1251ForcingWavelength", m_solverId, AT_, &m_bc1251ForcingWavelength);
4662 m_bc1251ForcingDirection =
4663 Context::getSolverProperty<MInt>("bc1251ForcingDirection", m_solverId, AT_, &m_bc1251ForcingDirection);
4664
4665 const MFloat inletSoundSpeed = sysEqn().speedOfSound(m_solver->m_rhoInfinity, m_solver->m_PInfinity);
4666 m_bc1251ForcingFrequency = inletSoundSpeed / m_bc1251ForcingWavelength;
4667
4668 MInt cellId, nghbrId, d = 0;
4669 const MFloat time = m_solver->m_time;
4670
4671 switch(m_cutOffBndryCndIds[bcId]) {
4672 case 1251:
4673 d = 0;
4674 break;
4675 case 1261:
4676 d = 1;
4677 break;
4678 case 1271:
4679 d = 2;
4680 break;
4681 case 1281:
4682 d = 3;
4683 break;
4684 default: {
4685 stringstream errorMessage;
4686 errorMessage << "ERROR: switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
4687 << " not matching any case." << endl;
4688 mTerm(1, AT_, errorMessage.str());
4689 }
4690 }
4691
4692 const MInt mainVelocityDirection = (d == 0 || d == 1) ? 0 : 1;
4693 const MInt secondaryVelocityDirection = (d == 0 || d == 1) ? 1 : 0;
4694
4695 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
4696 cellId = m_sortedCutOffCells[bcId]->a[id];
4697 nghbrId = m_solver->c_neighborId(cellId, d);
4698
4699 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
4700
4701 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
4702
4703 m_solver->a_pvariable(cellId, PV->VV[mainVelocityDirection]) =
4704 (F1 + m_bc1251ForcingAmplitude * sin(2.0 * PI * m_bc1251ForcingFrequency * time))
4705 * m_solver->m_VVInfinity[mainVelocityDirection];
4706
4707 m_solver->a_pvariable(cellId, PV->VV[secondaryVelocityDirection]) = 0;
4708
4709 IF_CONSTEXPR(isDetChem<SysEqn>) {
4710 for(MInt s = 0; s < m_noSpecies; s++) {
4711 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->m_YInfinity[s];
4712 }
4713 }
4714 }
4715}
4716
4717
4718//------------------------------------------------------------------------------
4719
4729template <MInt nDim, class SysEqn>
4731 TRACE();
4732
4733 MInt forcing = m_solver->m_forcing;
4734 MInt cellId, nghbrId, d = 0; // s=0,dir=-1;
4735 MFloat time = m_solver->m_time;
4736 MFloat St = m_solver->m_flameStrouhal;
4737 MFloat ampl = m_solver->m_forcingAmplitude;
4738 // MFloat massFlux = F0, density = F0, pressure = F0, velocity = F0, count = 0;
4739 // MFloat maxXCoord = F0, minXCoord = F0, area = F0;
4740 MFloat xPlus, xNegative;
4741 // MFloat integrateFactor = m_solver->m_velocityMagnitudeFactor;
4742 //---
4743 // MFloat vz = F1;
4744 // MFloat yOffsetInject = F0;
4745 // static MInt opposite[6] = {1,0,3,2,5,4};
4746
4747 switch(m_cutOffBndryCndIds[bcId]) {
4748 case 17516:
4749 d = 1; //,vz=F1;//dir=1;s=0;
4750 break;
4751 case 17616:
4752 d = 3; //,vz=F1;//dir=0;s=1;
4753 break;
4754 case 17716:
4755 d = 5; //,vz=F1;//dir=2;s=2;
4756 break;
4757 case 17816:
4758 d = 0; //,vz=-F1;//dir=1;s=0;
4759 break;
4760 default: {
4761 stringstream errorMessage;
4762 errorMessage << "ERROR: switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
4763 << " not matching any case." << endl;
4764 mTerm(1, AT_, errorMessage.str());
4765 }
4766 }
4767
4768 if(!forcing) {
4769 // loop over all concerning cells
4770 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
4771 cellId = m_sortedCutOffCells[bcId]->a[id];
4772 nghbrId = m_solver->c_neighborId(cellId, d);
4773
4774 // compute the pressure gradient with internal cells
4775 // slope = m_solver->a_pvariable( nghbrId2 , PV->P ) - m_solver->a_pvariable( nghbrId ,
4776 // PV->P ) ;
4777
4778 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P); // + slope;
4779
4780 // compute the density from inside of the domain using the pressure
4781 m_solver->a_pvariable(cellId, PV->RHO) =
4782 sysEqn().density_ES(m_solver->a_pvariable(cellId, PV->P), m_solver->m_TInfinity);
4783
4784 /*
4785 // set the velocities
4786 for( MInt i=0; i<nDim; i++ ){
4787 xPlus = m_solver->a_coordinate( cellId , opposite[i]) + radius + yOffsetInject;
4788 xNegative = m_solver->a_coordinate( cellId , opposite[i]) - radius + yOffsetInject;
4789 m_solver->a_pvariable( cellId , PV->VV[i] ) =
4790 vz*m_solver->m_VVInfinity[i]*(F1B2*(F1+tanh(xPlus*m_shearLayerStrength))*(F1-tanh(xNegative*m_shearLayerStrength))-F1);
4791 }
4792 */
4793
4794 // set the velocities
4795 m_solver->a_pvariable(cellId, PV->VV[0]) = 0;
4796
4797 xPlus = m_solver->a_coordinate(cellId, 0) + m_radiusVelFlameTube;
4798 xNegative = m_solver->a_coordinate(cellId, 0) - m_radiusVelFlameTube;
4799
4800 m_solver->a_pvariable(cellId, PV->VV[1]) =
4801 m_solver->m_VInfinity
4802 * (F1B2 * (F1 + tanh(xPlus * m_shearLayerStrength)) * (F1 - tanh(xNegative * m_shearLayerStrength)) - F1);
4803 // m_solver->a_pvariable( cellId , PV->VV[1] ) = m_solver->m_VInfinity*(tanh(5.0)-F1B2*tanh(5.0) +
4804 // F1B2*tanh((neg2*xNegative - 0.05)*5.0/0.05))*(tanh(5.0)-F1B2*tanh(5.0) + F1B2*tanh((F2*xPlus -
4805 // 0.05)*5.0/0.05));
4806
4807 // m_solver->a_pvariable( cellId , PV->VV[1] ) =
4808 // F1B4*(1+tanh(xPlus*100.0))*(1-tanh(xNegative*100.0))*m_solver->m_VInfinity;//*integrateFactor;
4809
4810 // set the progress variable
4811 IF_CONSTEXPR(hasPV_C<SysEqn>::value) m_solver->a_pvariable(cellId, PV->C) = F0;
4812 /*
4813 if(!m_solver->a_isHalo( nghbrId ))
4814 if(m_solver->m_massFlux || m_solver->m_plenumWall) {
4815
4816 // mass flux
4817 massFlux += m_solver->a_pvariable( nghbrId , PV->VV[1] ) * m_solver->a_pvariable( nghbrId , PV->RHO
4818 );
4819
4820 // velocity
4821 velocity+= m_solver->a_pvariable( nghbrId , PV->VV[1] );
4822
4823 // pressure
4824 pressure += m_solver->a_pvariable( nghbrId , PV->P );
4825
4826 // density
4827 density += m_solver->a_pvariable( nghbrId , PV->RHO );
4828
4829 count++;
4830
4831 }
4832 */
4833 }
4834 } else {
4835 // loop over all concerning cells
4836 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
4837 cellId = m_sortedCutOffCells[bcId]->a[id];
4838 nghbrId = m_solver->c_neighborId(cellId, d);
4839
4840 // compute the pressure gradient with internal cells
4841 // slope = m_solver->a_pvariable( nghbrId2 , PV->P ) - m_solver->a_pvariable( nghbrId , PV->P
4842 // ) ;
4843
4844 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P); // + slope;
4845
4846 // compute the density from inside of the domain using the pressure
4847 m_solver->a_pvariable(cellId, PV->RHO) =
4848 sysEqn().density_ES(m_solver->a_pvariable(cellId, PV->P), m_solver->m_TInfinity);
4849
4850 // set the velocities
4851 m_solver->a_pvariable(cellId, PV->VV[0]) = 0;
4852
4853 xPlus = m_solver->a_coordinate(cellId, 0) + m_radiusVelFlameTube;
4854 xNegative = m_solver->a_coordinate(cellId, 0) - m_radiusVelFlameTube;
4855
4856 m_solver->a_pvariable(cellId, PV->VV[1]) =
4857 m_solver->m_VInfinity
4858 * (F1B2 * (F1 + tanh(xPlus * m_shearLayerStrength)) * (F1 - tanh(xNegative * m_shearLayerStrength)) - F1);
4859 m_solver->a_pvariable(cellId, PV->VV[1]) *= (F1 + ampl * sin(St * time));
4860
4861 // m_solver->a_pvariable( cellId , PV->VV[1] ) = m_solver->m_VInfinity*(tanh(5.0)-F1B2*tanh(5.0) +
4862 // F1B2*tanh((neg2*xNegative - 0.05)*5.0/0.05))*(tanh(5.0)-F1B2*tanh(5.0) + F1B2*tanh((F2*xPlus -
4863 // 0.05)*5.0/0.05)); m_solver->a_pvariable( cellId , PV->VV[1] ) =
4864 // F1B4*(1+tanh(xPlus*100.0))*(1-tanh(xNegative*100.0))*m_solver->m_VInfinity*( F1 + ampl * sin( St * time
4865 // ));//* integrateFactor ;
4866
4867 // set the progress variable
4868 IF_CONSTEXPR(hasPV_C<SysEqn>::value) m_solver->a_pvariable(cellId, PV->C) = F0;
4869 /*
4870 if(!m_solver->a_isHalo( nghbrId ))
4871 if(m_solver->m_massFlux || m_solver->m_plenumWall) {
4872
4873 // mass flux
4874 massFlux += m_solver->a_pvariable( nghbrId , PV->VV[1] ) * m_solver->a_pvariable( nghbrId , PV->RHO
4875 );
4876
4877 // velocity
4878 velocity+= m_solver->a_pvariable( nghbrId , PV->VV[1] );
4879
4880 // pressure
4881 pressure += m_solver->a_pvariable( nghbrId , PV->P );
4882
4883 // density
4884 density += m_solver->a_pvariable( nghbrId , PV->RHO );
4885
4886 count++;
4887
4888 // calculate maximum y coordinate
4889 maxXCoord = mMax(maxXCoord,m_solver->a_coordinate( cellId , 0));
4890
4891 // calculate minimum y coordinate
4892 minXCoord = mMin(minXCoord,m_solver->a_coordinate( cellId , 0));
4893 }
4894 */
4895 }
4896 }
4897 /*
4898 if((m_solver->m_massFlux || m_solver->m_plenumWall) && m_solver->m_RKStep == (m_solver->m_noRKSteps-1)) {
4899 density = density/count;
4900 pressure = pressure/count;
4901 velocity = velocity/count;
4902 massFlux = massFlux/count;
4903 area = abs(maxXCoord) + abs(minXCoord) + m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel());
4904 massFlux *= area;
4905
4906 // cerr << area << endl;
4907
4908 FILE* datei;
4909 datei = fopen("massFluxInflow", "a+");
4910 fprintf(datei, " %d", globalTimeStep);
4911 fprintf(datei, " %f", m_solver->m_time);
4912 fprintf(datei, " %-10.10f", massFlux );
4913 fprintf(datei, " %-10.10f", velocity );
4914 fprintf(datei, " %-10.10f", density );
4915 fprintf(datei, " %-10.10f", pressure );
4916 fprintf(datei, "\n");
4917 fclose(datei);
4918 }
4919 */
4920}
4921
4922//------------------------------------------------------------------------------
4923
4933template <MInt nDim, class SysEqn>
4935 TRACE();
4936 MInt cellId, nghbrId, d = 0; // s=0,dir=-1;
4937 MFloat radius, jet; // rnd, fi, psi, Str;
4938 switch(m_cutOffBndryCndIds[bcId]) {
4939 case 19516:
4940 d = 1; // s=0;dir=1;
4941 break;
4942 case 19616:
4943 d = 3; // s=1;dir=0;
4944 break;
4945 case 19716:
4946 d = 5; // s=2;dir=2;
4947 break;
4948 default: {
4949 stringstream errorMessage;
4950 errorMessage << "ERROR: switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
4951 << " not matching any case." << endl;
4952 mTerm(1, AT_, errorMessage.str());
4953 }
4954 }
4955 // if( !forcing) {
4956 // loop over all concerning cells
4957 // loop over all concerning cells
4958 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
4959 cellId = m_sortedCutOffCells[bcId]->a[id];
4960 nghbrId = m_solver->c_neighborId(cellId, d);
4961
4962 // set the temperature
4963 // m_solver->a_pvariable( cellId , PV->T ) = PV->TInfinity;
4964
4965 // compute the radial position
4966 radius = F0;
4967 for(MInt i = 0; i < nDim; i++)
4968 if(i != d / 2) radius += POW2(m_solver->a_coordinate(cellId, i));
4969 radius = sqrt(radius);
4970
4971 // Jet mean velocity profile
4972 jet = F1B2 * (1 + tanh((m_jetHeight - radius) / (2 * m_momentumThickness)));
4973
4974 // Inflow mean density profile (Crocco-Busemann)
4975 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity * (1 / (sysEqn().CroccoBusemann(m_Ma, jet)));
4976 // m_solver->a_pvariable( cellId , PV->RHO ) = m_solver->m_rhoInfinity;
4977 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
4978 // Choose 0.05 for momentum thickness ref: Bogey&Bailly
4979 if(radius <= m_jetHeight) {
4980 // The following line is the original line from Onur which contains an error that was fixed below
4981 // m_solver->a_pvariable(cellId, PV->VV[0]) =F1B2* m_targetVelocityFactor*
4982 // (1+tanh((m_jetHeight-radius)/(2*m_momentumThickness)));
4983 m_solver->a_pvariable(cellId, PV->VV[0]) =
4984 F1B2 * m_solver->m_VVInfinity[0] * (1 + tanh((m_jetHeight - radius) / (2 * m_momentumThickness)));
4985 m_solver->a_pvariable(cellId, PV->VV[1]) = m_solver->m_VVInfinity[1];
4986 m_solver->a_pvariable(cellId, PV->VV[2]) = m_solver->m_VVInfinity[2];
4987 } else {
4988 m_solver->a_pvariable(cellId, PV->VV[0]) = F0;
4989 m_solver->a_pvariable(cellId, PV->VV[1]) = F0;
4990 m_solver->a_pvariable(cellId, PV->VV[2]) = F0;
4991 }
4992 }
4993}
4994
4995//--------------------------------------------------------------------------------
4996
5006template <MInt nDim, class SysEqn>
5008 TRACE();
5009
5010 MInt forcing = m_solver->m_forcing;
5011 MInt cellId, nghbrId, d = 0;
5012 MFloat massFlux = F0, density = F0, pressure = F0, velocity = F0, count = 0;
5013 MFloat maxXCoord = F0, minXCoord = F0, area = F0;
5014 MFloat refPressure = m_solver->m_PInfinity;
5015 if(m_solver->m_combustion) {
5016 refPressure = m_solver->m_pressureFlameTube;
5017 }
5018 // --- end of initialization
5019
5020 switch(m_cutOffBndryCndIds[bcId]) {
5021 case 17530:
5022 d = 1;
5023 break;
5024 case 17531:
5025 d = 0;
5026 break;
5027 case 17532:
5028 d = 3;
5029 break;
5030 case 17533:
5031 d = 2;
5032 break;
5033 case 17534:
5034 d = 5;
5035 break;
5036 case 17535:
5037 d = 4;
5038 break;
5039 case 1743:
5040 d = 0;
5041 break;
5042 case 1753:
5043 d = 1;
5044 break;
5045 case 1763:
5046 d = 2;
5047 break;
5048 case 1773:
5049 d = 4;
5050 break;
5051 default: {
5052 stringstream errorMessage;
5053 errorMessage << "ERROR: switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
5054 << " not matching any case." << endl;
5055 mTerm(1, AT_, errorMessage.str());
5056 }
5057 }
5058
5059 if(!forcing) {
5060 // loop over all concerning cells
5061 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
5062 cellId = m_sortedCutOffCells[bcId]->a[id];
5063 nghbrId = m_solver->c_neighborId(cellId, d);
5064
5065 // zero-gradient density
5066 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
5067
5068 // zero-gradient velocity
5069 for(MInt i = 0; i < nDim; i++)
5070 m_solver->a_pvariable(cellId, PV->VV[i]) = m_solver->a_pvariable(nghbrId, PV->VV[i]);
5071
5072 // set the pressure
5073 m_solver->a_pvariable(cellId, PV->P) = F2 * refPressure - m_solver->a_pvariable(nghbrId, PV->P);
5074
5075 // zero-gradient progress variable
5076 for(MInt s = 0; s < m_noSpecies; s++)
5077 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->a_pvariable(nghbrId, PV->Y[s]);
5078
5079 if(!m_solver->a_isHalo(nghbrId))
5080 if(m_solver->m_combustion) {
5081 if(m_solver->m_massFlux || m_solver->m_plenumWall) {
5082 // mass flux
5083 massFlux += m_solver->a_pvariable(nghbrId, PV->VV[1]) * m_solver->a_pvariable(nghbrId, PV->RHO);
5084
5085 // velocity
5086 velocity += m_solver->a_pvariable(nghbrId, PV->VV[1]);
5087
5088 // pressure
5089 pressure += m_solver->a_pvariable(nghbrId, PV->P);
5090
5091 // density
5092 density += m_solver->a_pvariable(nghbrId, PV->RHO);
5093
5094 count++;
5095
5096 // calculate maximum y coordinate
5097 maxXCoord = mMax(maxXCoord, m_solver->a_coordinate(cellId, 0));
5098
5099 // calculate minimum y coordinate
5100 minXCoord = mMin(minXCoord, m_solver->a_coordinate(cellId, 0));
5101 }
5102 }
5103 }
5104 } else {
5105 // MFloat factorSurface = 0.5686867;
5106 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
5107 cellId = m_sortedCutOffCells[bcId]->a[id];
5108 nghbrId = m_solver->c_neighborId(cellId, d);
5109
5110 // zero-gradient density
5111 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
5112
5113 // zero-gradient velocity
5114 for(MInt i = 0; i < nDim; i++)
5115 m_solver->a_pvariable(cellId, PV->VV[i]) = m_solver->a_pvariable(nghbrId, PV->VV[i]);
5116
5117 // TOutlet = 1.0 / ( 1.0 + 0.5 * gammaMinusOne *
5118 // POW2(m_Ma*factorSurface*m_solver->m_rhoInfinity/m_solver->a_pvariable(nghbrId, PV->RHO)*( F1 + ampl *
5119 // sin( St * time ))));
5120
5121 // POutlet = sysEqn().pressure_IR(TOutlet);
5122
5123 m_solver->a_pvariable(cellId, PV->P) = F2 * refPressure - m_solver->a_pvariable(nghbrId, PV->P);
5124
5125 // zero-gradient progress variable
5126 for(MInt i = 0; i < m_noSpecies; i++)
5127 m_solver->a_pvariable(cellId, PV->Y[i]) = m_solver->a_pvariable(nghbrId, PV->Y[i]);
5128
5129 if(!m_solver->a_isHalo(nghbrId))
5130 if(m_solver->m_combustion) {
5131 if(m_solver->m_massFlux || m_solver->m_plenumWall) {
5132 // mass flux
5133 massFlux += m_solver->a_pvariable(nghbrId, PV->VV[1]) * m_solver->a_pvariable(nghbrId, PV->RHO);
5134
5135 // velocity
5136 velocity += m_solver->a_pvariable(nghbrId, PV->VV[1]);
5137
5138 // pressure
5139 pressure += m_solver->a_pvariable(nghbrId, PV->P);
5140
5141 // density
5142 density += m_solver->a_pvariable(nghbrId, PV->RHO);
5143
5144 count++;
5145
5146 // calculate maximum y coordinate
5147 maxXCoord = mMax(maxXCoord, m_solver->a_coordinate(cellId, 0));
5148
5149 // calculate minimum y coordinate
5150 minXCoord = mMin(minXCoord, m_solver->a_coordinate(cellId, 0));
5151 }
5152 }
5153 }
5154 }
5155 if(m_solver->m_combustion) {
5156 if((m_solver->m_massFlux || m_solver->m_plenumWall) && m_solver->m_RKStep == (m_solver->m_noRKSteps - 1)) {
5157 if(noDomains() > 1) mTerm(1, AT_, "parallize mass flux computation in bc1753");
5158 density = density / count;
5159 pressure = pressure / count;
5160 velocity = velocity / count;
5161 massFlux = massFlux / count;
5162 area = abs(maxXCoord) + abs(minXCoord) + m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel());
5163 massFlux *= area;
5164
5165 // cerr << area << endl;
5166
5167 FILE* datei;
5168 datei = fopen("massFluxOutflow", "a+");
5169 fprintf(datei, " %d", globalTimeStep);
5170 fprintf(datei, " %f", m_solver->m_time);
5171 fprintf(datei, " %-10.10f", massFlux);
5172 fprintf(datei, " %-10.10f", velocity);
5173 fprintf(datei, " %-10.10f", density);
5174 fprintf(datei, " %-10.10f", pressure);
5175 fprintf(datei, "\n");
5176 fclose(datei);
5177 }
5178 }
5179}
5180
5181//------------------------------------------------------------------------------
5182
5183
5193template <MInt nDim, class SysEqn>
5195 TRACE();
5196
5197 MInt cellId = -1, nghbrId = -1, d = 0;
5198 MFloat pressure = m_solver->m_PInfinity;
5199 if(m_solver->m_jet) pressure = m_solver->m_jetPressure;
5200
5201 // --- end of initialization
5202
5203 switch(m_cutOffBndryCndIds[bcId]) {
5204 case 1745:
5205 d = 1;
5206 break;
5207 case 1755:
5208 d = 0;
5209 break;
5210 case 1765:
5211 d = 2;
5212 break;
5213 case 1775:
5214 d = 4;
5215 break;
5216 default: {
5217 stringstream errorMessage;
5218 errorMessage << "ERROR: switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
5219 << " not matching any case." << endl;
5220 mTerm(1, AT_, errorMessage.str());
5221 }
5222 }
5223
5224 // loop over all concerning cells
5225 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
5226 cellId = m_sortedCutOffCells[bcId]->a[id];
5227 nghbrId = m_solver->c_neighborId(cellId, d);
5228
5229 // zero-gradient density
5230 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
5231
5232 // zero-gradient velocity
5233 for(MInt i = 0; i < nDim; i++)
5234 m_solver->a_pvariable(cellId, PV->VV[i]) = m_solver->a_pvariable(nghbrId, PV->VV[i]);
5235
5236 // zero gradient pressure
5237 m_solver->a_pvariable(cellId, PV->P) = F2 * pressure - m_solver->a_pvariable(nghbrId, PV->P);
5238
5239 // zero-gradient progress variable
5240 for(MInt s = 0; s < m_noSpecies; s++) {
5241 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->a_pvariable(nghbrId, PV->Y[s]);
5242 }
5243 }
5244}
5245
5246//------------------------------------------------------------------------------
5247
5248
5255template <MInt nDim, class SysEqn>
5256template <MBool MGC>
5258 TRACE();
5259 const MInt noSpecies = m_noSpecies;
5260
5261#ifdef _OPENMP
5262#pragma omp parallel for
5263#endif
5264 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
5265 const MInt bndryId = m_sortedBndryCells->a[id];
5266 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
5267 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
5268 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
5269 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
5270 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
5271
5272 for(MInt i = 0; i < nDim; i++) {
5273 if(MGC) {
5274 if(m_surfaceGhostCell) {
5275 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = 0.0;
5276 } else {
5277 m_solver->a_pvariable(ghostCellId, PV->VV[i]) =
5278 -m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->VV[i]];
5279 }
5280 } else {
5281 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = -m_solver->a_pvariable(cellId, PV->VV[i]);
5282 }
5283 }
5284 if(MGC) {
5285 m_solver->a_pvariable(ghostCellId, PV->RHO) =
5286 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->RHO];
5287 m_solver->a_pvariable(ghostCellId, PV->P) =
5288 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->P];
5289 } else {
5290 // simplified Neumann: assuming the line boundary-ghost is normal to the boundary surface)
5291 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
5292 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
5293 }
5294
5295 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
5296 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
5297 if(MGC) {
5298 if(m_surfaceGhostCell) {
5299 m_solver->a_pvariable(ghostCellId, PV->N) = 0.0;
5300 } else {
5301 m_solver->a_pvariable(ghostCellId, PV->N) =
5302 -m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->N];
5303 }
5304 } else {
5305 m_solver->a_pvariable(ghostCellId, PV->N) = -m_solver->a_pvariable(cellId, PV->N);
5306 }
5307 }
5308 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
5309 // k
5310 m_solver->a_pvariable(ghostCellId, PV->K) = -m_solver->a_pvariable(cellId, PV->K);
5311 // omega
5312 const MFloat rRe = F1 / sysEqn().m_Re0;
5313 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
5314 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
5315 const MFloat omega = m_solver->a_pvariable(cellId, PV->OMEGA);
5316 const MFloat T = sysEqn().temperature_ES(rho, p);
5317 const MFloat mue = sysEqn().sutherlandLaw(T);
5318 const MFloat nu = mue / rho;
5319 const MFloat beta1 = RM_KOMEGA::beta0;
5320 MFloat d = sqrt(POW2(m_solver->a_coordinate(cellId, 0) - m_solver->a_coordinate(ghostCellId, 0))
5321 + POW2(m_solver->a_coordinate(cellId, 1) - m_solver->a_coordinate(ghostCellId, 1)));
5322 IF_CONSTEXPR(nDim == 3) {
5323 d = sqrt(POW2(m_solver->a_coordinate(cellId, 0) - m_solver->a_coordinate(ghostCellId, 0))
5324 + POW2(m_solver->a_coordinate(cellId, 1) - m_solver->a_coordinate(ghostCellId, 1))
5325 + POW2(m_solver->a_coordinate(cellId, 2) - m_solver->a_coordinate(ghostCellId, 2)));
5326 }
5327 const MFloat nu_surface = nu - m_solver->a_slope(cellId, PV->N, 1) * d;
5328 const MFloat omega_surface = pow(rRe, 2.0) * 60 * nu_surface / (beta1 * POW2(d));
5329 m_solver->a_pvariable(ghostCellId, PV->OMEGA) = F2 * omega_surface - omega;
5330 }
5331 }
5332
5333 for(MInt s = 0; s < noSpecies; s++) {
5334 if(MGC) {
5335 m_solver->a_pvariable(ghostCellId, PV->Y[s]) =
5336 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->Y[s]];
5337 } else {
5338 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
5339 }
5340 }
5341 }
5342 }
5343 }
5344 }
5345}
5346
5347template <MInt nDim, class SysEqn>
5348template <MBool MGC>
5350 TRACE();
5351
5352 m_4000timeStepOffset = Context::getSolverProperty<MInt>("bc4000timeStepOffset", m_solverId, AT_);
5353 m_4000timeInterval = Context::getSolverProperty<MInt>("bc4000timeInterval", m_solverId, AT_);
5354 m_wFactor = Context::getSolverProperty<MFloat>("wFactor", m_solverId, AT_);
5355}
5356
5363template <MInt nDim, class SysEqn>
5365 TRACE();
5366
5367 const MFloat G = m_wFactor * m_solver->m_UInfinity;
5368
5369 MFloat factor = F1;
5370 if(m_4000timeStepOffset > 0) {
5371 if(globalTimeStep > m_4000timeStepOffset) {
5372 factor = tanh((MFloat)(globalTimeStep - m_4000timeStepOffset) / m_4000timeInterval * PI);
5373 }
5374 }
5375
5376
5377#ifdef _OPENMP
5378#pragma omp parallel for
5379#endif
5380 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
5381 const MInt bndryId = m_sortedBndryCells->a[id];
5382 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
5383 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
5384 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
5385 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
5386 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
5387
5388 m_solver->a_pvariable(ghostCellId, PV->U) = -m_solver->a_pvariable(cellId, PV->U);
5389 m_solver->a_pvariable(ghostCellId, PV->V) = -m_solver->a_pvariable(cellId, PV->V);
5390 m_solver->a_pvariable(ghostCellId, PV->W) = 2.0 * factor * G - m_solver->a_pvariable(cellId, PV->W);
5391
5392 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
5393 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
5394 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = -m_solver->a_pvariable(cellId, PV->NN[r]);
5395 }
5396 }
5397
5398 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
5399
5400 for(MInt s = 0; s < m_noSpecies; s++) {
5401 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
5402 }
5403 }
5404 }
5405 }
5406 }
5407}
5408
5415template <MInt nDim, class SysEqn>
5417 TRACE();
5418
5419 const MFloat G = m_wFactor * m_solver->m_UInfinity;
5420 const MInt timeStepOffset = m_4000timeStepOffset;
5421
5422#ifdef _OPENMP
5423#pragma omp parallel for
5424#endif
5425 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
5426 const MInt bndryId = m_sortedBndryCells->a[id];
5427 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
5428 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
5429 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
5430 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
5431 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
5432
5433 m_solver->a_pvariable(ghostCellId, PV->U) = -m_solver->a_pvariable(cellId, PV->U);
5434 m_solver->a_pvariable(ghostCellId, PV->V) = -m_solver->a_pvariable(cellId, PV->V);
5435
5436 MFloat factor = F1;
5437
5438 if(globalTimeStep < m_4000timeStepOffset) {
5439 factor = 1 - cos(PI / (MFloat)timeStepOffset * (globalTimeStep - m_solver->m_restartTimeStep));
5440 }
5441
5442 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
5443 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
5444 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = -m_solver->a_pvariable(cellId, PV->NN[r]);
5445 }
5446 }
5447
5448 m_solver->a_pvariable(ghostCellId, PV->W) = 2.0 * factor * G - m_solver->a_pvariable(cellId, PV->W);
5449 }
5450 }
5451 }
5452 }
5453}
5454
5455
5462template <MInt nDim, class SysEqn>
5464 TRACE();
5465
5466#ifdef _OPENMP
5467#pragma omp parallel for
5468#endif
5469 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
5470 const MInt bndryId = m_sortedBndryCells->a[id];
5471 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
5472 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
5473 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
5474 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
5475 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
5476
5477 for(MInt i = 0; i < nDim; i++) {
5478 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = -m_solver->a_pvariable(cellId, PV->VV[i]);
5479 }
5480 const MFloat pressure = m_solver->a_pvariable(cellId, PV->P);
5481
5482 m_solver->a_pvariable(ghostCellId, PV->P) = pressure;
5483 // 2 * density of the set temperature - density of the cell
5484 m_solver->a_pvariable(ghostCellId, PV->RHO) =
5485 2 * sysEqn().density_ES(pressure, m_Bc3011WallTemperature) - m_solver->a_pvariable(cellId, PV->RHO);
5486
5487 IF_CONSTEXPR(isDetChem<SysEqn>)
5488 m_solver->a_pvariable(ghostCellId, PV->RHO) =
5489 F2 * m_solver->a_avariable(cellId, AV->W_MEAN) * pressure
5490 / (m_solver->m_gasConstant * m_Bc3011WallTemperature)
5491 - m_solver->a_pvariable(cellId, PV->RHO); // to do: needs to be checked
5492
5493 for(MInt s = 0; s < m_noSpecies; s++) {
5494 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
5495 }
5496 }
5497 }
5498 }
5499 }
5500}
5501
5509template <MInt nDim, class SysEqn>
5511 TRACE();
5512
5513 const MInt noSpecies = m_noSpecies;
5514
5515#ifdef _OPENMP
5516#pragma omp parallel for
5517#endif
5518 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
5519 const MInt bndryId = m_sortedBndryCells->a[id];
5520 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
5521 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
5522 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
5523 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
5524 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
5525
5526 MFloat wallNormalVelocity = F0;
5527
5528 for(MInt i = 0; i < nDim; i++)
5529 wallNormalVelocity +=
5530 m_solver->a_pvariable(cellId, PV->VV[i]) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
5531
5532 for(MInt i = 0; i < nDim; i++)
5533 m_solver->a_pvariable(ghostCellId, PV->VV[i]) =
5534 m_solver->a_pvariable(cellId, PV->VV[i])
5535 - F2 * wallNormalVelocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
5536
5537 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
5538 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
5539
5540 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
5541 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
5542 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = m_solver->a_pvariable(cellId, PV->NN[r]);
5543 }
5544 }
5545
5546 for(MInt s = 0; s < noSpecies; s++)
5547 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
5548 }
5549 }
5550 }
5551 }
5552}
5553
5554
5562template <MInt nDim, class SysEqn>
5564 TRACE();
5565
5566 const MInt noSpecies = m_noSpecies;
5567
5568#ifdef _OPENMP
5569#pragma omp parallel for
5570#endif
5571 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
5572 const MInt bndryId = m_sortedBndryCells->a[id];
5573 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
5574 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
5575 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
5576 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
5577 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
5578
5579 MFloat wallNormalVelocity = F0;
5580
5581 for(MInt i = 0; i < nDim; i++)
5582 wallNormalVelocity +=
5583 m_solver->a_pvariable(cellId, PV->VV[i]) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
5584
5585 for(MInt i = 0; i < nDim; i++)
5586 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = m_solver->a_pvariable(cellId, PV->VV[i]);
5587 // - F2 * wallNormalVelocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
5588
5589 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
5590 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
5591
5592 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
5593 for(MInt r = 0; r < m_noRansEquations; ++r) {
5594 m_solver->a_pvariable(ghostCellId, PV->N) = m_solver->a_pvariable(cellId, PV->N);
5595 }
5596 }
5597
5598 for(MInt s = 0; s < noSpecies; s++)
5599 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
5600 }
5601 }
5602 }
5603 }
5604}
5605
5606
5607/* Computes the p and rho slopes on boundary cells using the least-squares method
5608 *
5609 */
5610template <MInt nDim, class SysEqn>
5612 TRACE();
5613
5614#ifdef _OPENMP
5615#pragma omp parallel for
5616#endif
5617 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
5618 const MInt bndryId = m_sortedBndryCells->a[id];
5619 const MInt linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
5620 const MInt cellId = (linkedCell > -1) ? linkedCell : m_bndryCells->a[bndryId].m_cellId;
5621 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
5622 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
5623 if(linkedCell == -1 || m_solver->a_bndryId(linkedCell) == -1) {
5624 // reset the slopes
5625 for(MInt i = 0; i < nDim; i++) {
5626 m_solver->a_slope(cellId, PV->RHO, i) = F0;
5627 m_solver->a_slope(cellId, PV->P, i) = F0;
5628 }
5629
5630 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
5631 const MInt nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
5632 for(MInt i = 0; i < nDim; i++) {
5633 m_solver->a_slope(cellId, PV->RHO, i) +=
5634 m_reconstructionConstants[bndryId][nghbr * nDim + i]
5635 * (m_solver->a_pvariable(nghbrId, PV->RHO) - m_solver->a_pvariable(cellId, PV->RHO));
5636 m_solver->a_slope(cellId, PV->P, i) +=
5637 m_reconstructionConstants[bndryId][nghbr * nDim + i]
5638 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
5639 }
5640 }
5641
5642 // apply the Neumann bc
5643 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
5644 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
5645 for(MInt i = 0; i < nDim; i++) {
5646 const MFloat dx = m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i);
5647 m_solver->a_pvariable(ghostCellId, PV->RHO) += dx * m_solver->a_slope(cellId, PV->RHO, i);
5648 m_solver->a_pvariable(ghostCellId, PV->P) += dx * m_solver->a_slope(cellId, PV->P, i);
5649 }
5650 }
5651 }
5652 }
5653}
5654
5655/* Computes the p and rho slopes on boundary cells using the least-squares method
5656 *
5657 */
5658template <MInt nDim, class SysEqn>
5660 TRACE();
5661
5662#ifdef _OPENMP
5663#pragma omp parallel for
5664#endif
5665 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
5666 const MInt bndryId = m_sortedBndryCells->a[id];
5667 const MInt linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
5668 const MInt cellId = (linkedCell > -1) ? linkedCell : m_bndryCells->a[bndryId].m_cellId;
5669 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
5670 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
5671 if(linkedCell == -1 || m_solver->a_bndryId(linkedCell) == -1) {
5672 for(MInt i = 0; i < nDim; i++) {
5673 m_solver->a_slope(cellId, PV->P, i) = F0;
5674 }
5675
5676 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
5677 const MInt nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
5678 for(MInt i = 0; i < nDim; i++) {
5679 m_solver->a_slope(cellId, PV->P, i) +=
5680 m_reconstructionConstants[bndryId][nghbr * nDim + i]
5681 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
5682 }
5683 }
5684
5685 // apply the Neumann bc
5686 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
5687 MFloat dp = F0;
5688 for(MInt i = 0; i < nDim; i++) {
5689 dp += (m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i))
5690 * m_solver->a_slope(cellId, PV->P, i);
5691 }
5692 m_solver->a_pvariable(ghostCellId, PV->P) += dp;
5693
5694 // change surface density according to wall temperature and dp
5695 IF_CONSTEXPR(isDetChem<SysEqn>) {
5696 m_solver->a_pvariable(ghostCellId, PV->RHO) +=
5697 m_solver->a_avariable(cellId, AV->W_MEAN) * dp / (m_Bc3011WallTemperature * m_solver->m_gasConstant);
5698 }
5699 else {
5700 m_solver->a_pvariable(ghostCellId, PV->RHO) += sysEqn().density_ES(dp, m_Bc3011WallTemperature);
5701 }
5702 }
5703 }
5704 }
5705}
5706
5712template <MInt nDim, class SysEqn>
5714 TRACE();
5715
5716 MInt d = 0, cellId, nghbrId;
5717 //---
5718
5719 switch(m_cutOffBndryCndIds[bcId]) {
5720 case 17110:
5721 d = 1;
5722 break;
5723 case 17111:
5724 d = 0;
5725 break;
5726 case 17112:
5727 d = 3;
5728 break;
5729 case 17113:
5730 d = 2;
5731 break;
5732 case 17114:
5733 d = 5;
5734 break;
5735 case 17115:
5736 d = 4;
5737 break;
5738 default: {
5739 stringstream errorMessage;
5740 errorMessage << "ERROR: switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
5741 << " not matching any case." << endl;
5742 mTerm(1, AT_, errorMessage.str());
5743 }
5744 }
5745
5746 MFloat bbox[6] = {F0, F0, F0, F0, F0, F0};
5747 m_solver->m_geometry->getBoundingBox(bbox);
5748 const MFloat deltaY = bbox[1 + nDim] - bbox[1];
5749 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
5750 cellId = m_sortedCutOffCells[bcId]->a[id];
5751 MFloat vel[3] = {F0, F0, F0};
5752 MFloat dy = m_solver->a_coordinate(cellId, 1) / deltaY;
5753 vel[0] = F2 * m_solver->m_UInfinity * dy;
5754 nghbrId = m_solver->c_neighborId(cellId, d);
5755 if((dy > F0 && d == 1) || (dy < F0 && d == 0)) { // inflow
5756 for(MInt i = 0; i < nDim; i++)
5757 m_solver->a_pvariable(cellId, PV->VV[i]) = vel[i];
5758 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
5759 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
5760 } else { // outflow
5761 for(MInt v = 0; v < PV->noVariables; v++)
5762 m_solver->a_pvariable(cellId, v) = m_solver->a_pvariable(nghbrId, v);
5763 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
5764 }
5765 }
5766}
5767
5768//-----------------------------------------------------------------------------
5769
5770template <MInt nDim, class SysEqn>
5772 TRACE();
5773
5774 MInt noCells = m_bndryCells->size();
5775
5776 for(MInt id = 0; id < noCells; id++) {
5777 for(MInt srfc = 0; srfc < m_bndryCells->a[id].m_noSrfcs; srfc++) {
5778 MInt ghostCellId = m_bndryCells->a[id].m_srfcVariables[srfc]->m_ghostCellId;
5779 MInt cellId = m_bndryCells->a[id].m_cellId;
5780 for(MInt i = 0; i < FV->noVariables; i++) {
5781 m_solver->a_rightHandSide(ghostCellId, i) = m_solver->a_rightHandSide(cellId, i);
5782 }
5783 }
5784 }
5785}
5786
5787
5788//----------------------------------------------------------------------
5789
5798template <MInt nDim, class SysEqn>
5800 TRACE();
5801
5802 // find out global number and kind of boundary conditions...
5803 MIntScratchSpace comm_allBndryIds_scratch(m_maxNoBndryCndIds, AT_, "comm_allBndryIds_scratch");
5804 MIntScratchSpace comm_allBndryIds_result_scratch(noDomains() * m_maxNoBndryCndIds, AT_,
5805 "comm_allBndryIds_result_scratch");
5806 MInt* comm_allBndryIds = comm_allBndryIds_scratch.getPointer();
5807 MInt* comm_allBndryIds_result = comm_allBndryIds_result_scratch.getPointer();
5808 for(MInt i = 0; i < noDomains() * m_maxNoBndryCndIds; i++) {
5809 comm_allBndryIds_result[i] = -1;
5810 }
5811
5812 MPI_Group world_group;
5813 MPI_Comm_group(mpiComm(), &world_group, AT_, "world_group");
5814
5815 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
5816 comm_allBndryIds[bcId] = m_bndryCndIds[bcId];
5817 }
5818 for(MInt bcId = m_noBndryCndIds; bcId < m_maxNoBndryCndIds; bcId++) {
5819 comm_allBndryIds[bcId] = -1;
5820 }
5821
5822 MPI_Allgather(comm_allBndryIds, m_maxNoBndryCndIds, MPI_INT, comm_allBndryIds_result, m_maxNoBndryCndIds, MPI_INT,
5823 mpiComm(), AT_, "comm_allBndryIds", "comm_allBndryIds_result");
5824
5825 MIntScratchSpace sortedBndryCndIds_scratch(m_maxNoBndryCndIds, AT_, "sortedBndryCndIds_scratch");
5826 MInt* sortedBndryCndIds = sortedBndryCndIds_scratch.getPointer();
5827 MInt realNoBndryCndIds = 0;
5828 for(MInt i = 0; i < m_maxNoBndryCndIds * noDomains(); i++) {
5829 if(comm_allBndryIds_result[i] > -1) sortedBndryCndIds[realNoBndryCndIds++] = comm_allBndryIds_result[i];
5830 }
5831 maia::math::quickSort(sortedBndryCndIds, 0, realNoBndryCndIds - 1);
5832 realNoBndryCndIds = maia::math::removeDoubleEntries(sortedBndryCndIds, realNoBndryCndIds);
5833
5834 MIntScratchSpace procs_bcId_scratch(realNoBndryCndIds * noDomains(), AT_, "procs_bcId_scratch");
5835 MInt* procs_bcId = procs_bcId_scratch.getPointer();
5836 MIntScratchSpace noProcs_scratch(realNoBndryCndIds, AT_, "noProcs_scratch");
5837 MInt* noProcs = noProcs_scratch.getPointer();
5838
5839 // this is just a workaround, needs fixing! allocation should be placed in the constructor or so!
5840 // needs to be done by every rank, also those that become inactive! -> moved to resetBndryCommunication()
5841 // if(m_comm_bc_init > 0)
5842 // {
5843 // for( MInt i = 0; i < m_comm_bc_init; i++ )
5844 // {
5845 // if(m_comm_bc[ i ] != MPI_COMM_NULL && m_comm_bc[i] != MPI_COMM_WORLD)
5846 // MPI_Comm_free(&m_comm_bc[ i ], AT_, "m_comm_bc[i]");
5847 // }
5848 //}
5849 mDeallocate(m_comm_bc);
5850 if(realNoBndryCndIds > 0) {
5851 mAlloc(m_comm_bc, realNoBndryCndIds, "m_comm_bc", AT_);
5852 }
5853
5854 mDeallocate(m_bc_comm_pointer);
5855 mAlloc(m_bc_comm_pointer, m_maxNoBndryCndIds, "m_bc_comm_pointer", -1, AT_);
5856
5857 for(MInt i = 0; i < realNoBndryCndIds; i++) {
5858 noProcs[i] = 0;
5859 for(MInt p = 0; p < noDomains(); p++) {
5860 for(MInt j = 0; j < m_maxNoBndryCndIds; j++) {
5861 if(comm_allBndryIds_result[p * m_maxNoBndryCndIds + j] == sortedBndryCndIds[i]) {
5862 procs_bcId[noProcs[i]++] = p;
5863 }
5864 }
5865 }
5866 MPI_Group bc_group;
5867 MPI_Group_incl(world_group, noProcs[i], procs_bcId, &bc_group, AT_);
5868
5869 MPI_Comm_create(mpiComm(), bc_group, &m_comm_bc[i], AT_, "m_comm_bc[i]");
5870
5871 MPI_Group_free(&bc_group, AT_);
5872 }
5873
5874 // set the current numnber of communicators (for next call)
5875 m_comm_bc_init = realNoBndryCndIds;
5876
5877 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
5878 for(MInt i = 0; i < realNoBndryCndIds; i++) {
5879 if(m_bndryCndIds[bcId] == sortedBndryCndIds[i]) {
5880 m_bc_comm_pointer[bcId] = i;
5881 }
5882 }
5883 }
5884
5885
5886 IF_CONSTEXPR(nDim == 3) {
5887 if(m_solver->m_vtuGeometryOutput.empty()) {
5888 m_log << "VTU geometry output for boundaryIds: ";
5889 for(MInt i = 0; i < realNoBndryCndIds; i++) {
5890 if((sortedBndryCndIds[i] >= 3000 && sortedBndryCndIds[i] < 4000)
5891 || string2enum(m_solver->m_outputFormat) == VTP) {
5892 m_solver->m_vtuGeometryOutput.insert(sortedBndryCndIds[i]);
5893 m_log << sortedBndryCndIds[i] << " ";
5894 }
5895 }
5896 m_log << endl;
5897 }
5898 }
5899
5900
5901 // find out global number and kind of cutOff boundary conditions...
5902 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++) {
5903 if(m_sortedCutOffCells[bcId]->size() > 0) {
5904 comm_allBndryIds[bcId] = m_cutOffBndryCndIds[bcId];
5905 } else {
5906 comm_allBndryIds[bcId] = -1;
5907 }
5908 }
5909 for(MInt bcId = m_noCutOffBndryCndIds; bcId < m_maxNoBndryCndIds; bcId++) {
5910 comm_allBndryIds[bcId] = -1;
5911 }
5912 for(MInt i = 0; i < noDomains() * m_maxNoBndryCndIds; i++) {
5913 comm_allBndryIds_result[i] = -1;
5914 }
5915
5916 MPI_Allgather(comm_allBndryIds, m_maxNoBndryCndIds, MPI_INT, comm_allBndryIds_result, m_maxNoBndryCndIds, MPI_INT,
5917 mpiComm(), AT_, "comm_allBndryIds", "comm_allBndryIds_result");
5918
5919 realNoBndryCndIds = 0;
5920 for(MInt i = 0; i < m_maxNoBndryCndIds * noDomains(); i++) {
5921 if(comm_allBndryIds_result[i] > -1) sortedBndryCndIds[realNoBndryCndIds++] = comm_allBndryIds_result[i];
5922 }
5923 maia::math::quickSort(sortedBndryCndIds, 0, realNoBndryCndIds - 1);
5924 realNoBndryCndIds = maia::math::removeDoubleEntries(sortedBndryCndIds, realNoBndryCndIds);
5925
5926 if(realNoBndryCndIds == 0) {
5927 return;
5928 }
5929
5930 MIntScratchSpace procs_bcIdCo_scratch(realNoBndryCndIds * noDomains(), AT_, "procs_bcIdCo_scratch");
5931 procs_bcId = procs_bcIdCo_scratch.getPointer();
5932 MIntScratchSpace noProcsCo_scratch(realNoBndryCndIds, AT_, "noProcsCo_scratch");
5933 noProcs = noProcsCo_scratch.getPointer();
5934
5935
5936 // this is just a workaround, needs fixing! allocation should be placed in the constructor or so!
5937 // needs to be done by every rank, also those that become inactive! -> moved to resetBndryCommunication()
5938 // if(m_comm_bcCo_init > 0)
5939 // {
5940 // for( MInt i = 0; i < m_comm_bcCo_init; i++ )
5941 // {
5942 // if(m_comm_bcCo[ i ] != MPI_COMM_NULL && m_comm_bcCo[i] != MPI_COMM_WORLD)
5943 // MPI_Comm_free(&m_comm_bcCo[ i ], AT_, "m_comm_bcCo[]i");
5944 // }
5945 //}
5946 mDeallocate(m_comm_bcCo);
5947 if(realNoBndryCndIds > 0) {
5948 mAlloc(m_comm_bcCo, realNoBndryCndIds, "m_comm_bcCo", AT_);
5949 }
5950
5951 mDeallocate(m_bcCo_comm_pointer);
5952 mAlloc(m_bcCo_comm_pointer, m_maxNoBndryCndIds, "m_bcCo_comm_pointer", -1, AT_);
5953
5954 for(MInt i = 0; i < realNoBndryCndIds; i++) {
5955 noProcs[i] = 0;
5956 for(MInt p = 0; p < noDomains(); p++) {
5957 for(MInt j = 0; j < m_maxNoBndryCndIds; j++) {
5958 if(comm_allBndryIds_result[p * m_maxNoBndryCndIds + j] == sortedBndryCndIds[i]) {
5959 procs_bcId[noProcs[i]++] = p;
5960 }
5961 }
5962 }
5963 MPI_Group bc_group;
5964 MPI_Group_incl(world_group, noProcs[i], procs_bcId, &bc_group, AT_);
5965
5966 MPI_Comm_create(mpiComm(), bc_group, &m_comm_bcCo[i], AT_, "m_comm_bcCo[i]");
5967
5968 MPI_Group_free(&bc_group, AT_);
5969 }
5970
5971 // set the number communicators for next call
5972 m_comm_bcCo_init = realNoBndryCndIds;
5973
5974 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++) {
5975 if(m_sortedCutOffCells[bcId]->size() == 0) continue;
5976
5977 for(MInt i = 0; i < realNoBndryCndIds; i++) {
5978 if(m_cutOffBndryCndIds[bcId] == sortedBndryCndIds[i]) {
5979 m_bcCo_comm_pointer[bcId] = i;
5980 }
5981 }
5982 }
5983
5984 MPI_Group_free(&world_group, AT_);
5985}
5986
5989
5990template <MInt nDim>
5992 if(loadRandomNumbers()) return;
5993
5994 m_log << " generate Random Numbers ..." << endl;
5995
5996 // obtain random numbers from Mersenne Twister and calculate derived values
5997 MFloat d1;
5998 MFloat d2;
5999 MFloat d3;
6000 MFloat xi1;
6001 MFloat xi2;
6002 MFloat xi3;
6003 MFloat zeta1;
6004 MFloat zeta2;
6005 MFloat zeta3;
6006 MFloat vc;
6007 for(MInt n = 0; n < m_noOfModes; n++) {
6008 std::normal_distribution<> dist{1.0, 1.0};
6009 m_omega[n] = dist(randNumGen);
6010
6011 std::normal_distribution<> dist2{0.0, 0.5};
6012 d1 = dist2(randNumGen);
6013 d2 = dist2(randNumGen);
6014 d3 = dist2(randNumGen);
6015
6016 std::normal_distribution<> dist3{0.0, 1.0};
6017 xi1 = dist3(randNumGen);
6018 xi2 = dist3(randNumGen);
6019 xi3 = dist3(randNumGen);
6020 zeta1 = dist3(randNumGen);
6021 zeta2 = dist3(randNumGen);
6022 zeta3 = dist3(randNumGen);
6023
6024 // calculate derived vars
6025 m_p1[n] = zeta2 * d3 - zeta3 * d2;
6026 m_p2[n] = zeta3 * d1 - zeta1 * d3;
6027 m_p3[n] = zeta1 * d2 - zeta2 * d1;
6028 m_q1[n] = xi2 * d3 - xi3 * d2;
6029 m_q2[n] = xi3 * d1 - xi1 * d3;
6030 m_q3[n] = xi1 * d2 - xi2 * d1;
6031
6032 // ---------------------------------------------------
6033 // Beginning of Modification by Shin
6034 // Scaling by vc is not necessary.
6035 //
6036 if(smirnov == 1) {
6037 vc = 1; // The scaling comes later with c1, c2, and c3.
6038 } else {
6039 vc = sqrt(1.5
6040 * ((uuref * d1 * d1 + vvref * d2 * d2 + wwref * d3 * d3
6041 + 2.0 * (uvref * d1 * d2 + uwref * d1 * d3 + vwref * d2 * d3))
6042 / (d1 * d1 + d2 * d2 + d3 * d3)));
6043 }
6044
6045 m_dhat1[n] = d1 * m_v_b / vc;
6046 m_dhat2[n] = d2 * m_v_b / vc;
6047 m_dhat3[n] = d3 * m_v_b / vc;
6048 //
6049 // End of Modification by Shin
6050 // ---------------------------------------------------
6051 }
6052
6053 // in case of multisolver, the random numbers from solver 0 are broadcast to all solvers
6054 if(m_commValues) {
6055 ScratchSpace<MFloat> sendRecvBuffer(m_noOfModes * 10, AT_, "sendRecvBuffer");
6056 if(m_rank_bc1601 == 0) {
6057 for(MInt n = 0; n < m_noOfModes; n++) {
6058 sendRecvBuffer[n + 0 * m_noOfModes] = m_omega[n];
6059 }
6060 for(MInt n = 0; n < m_noOfModes; n++) {
6061 sendRecvBuffer[n + 1 * m_noOfModes] = m_p1[n];
6062 }
6063 for(MInt n = 0; n < m_noOfModes; n++) {
6064 sendRecvBuffer[n + 2 * m_noOfModes] = m_p2[n];
6065 }
6066 for(MInt n = 0; n < m_noOfModes; n++) {
6067 sendRecvBuffer[n + 3 * m_noOfModes] = m_p3[n];
6068 }
6069 for(MInt n = 0; n < m_noOfModes; n++) {
6070 sendRecvBuffer[n + 4 * m_noOfModes] = m_q1[n];
6071 }
6072 for(MInt n = 0; n < m_noOfModes; n++) {
6073 sendRecvBuffer[n + 5 * m_noOfModes] = m_q2[n];
6074 }
6075 for(MInt n = 0; n < m_noOfModes; n++) {
6076 sendRecvBuffer[n + 6 * m_noOfModes] = m_q3[n];
6077 }
6078 for(MInt n = 0; n < m_noOfModes; n++) {
6079 sendRecvBuffer[n + 7 * m_noOfModes] = m_dhat1[n];
6080 }
6081 for(MInt n = 0; n < m_noOfModes; n++) {
6082 sendRecvBuffer[n + 8 * m_noOfModes] = m_dhat2[n];
6083 }
6084 for(MInt n = 0; n < m_noOfModes; n++) {
6085 sendRecvBuffer[n + 9 * m_noOfModes] = m_dhat3[n];
6086 }
6087 }
6088
6089 MPI_Bcast(&sendRecvBuffer[0], 10 * m_noOfModes, MPI_DOUBLE, 0, m_comm_bc1601, AT_, "sendRecvBuffer[0]");
6090
6091 if(m_rank_bc1601 != 0) {
6092 for(MInt n = 0; n < m_noOfModes; n++) {
6093 m_omega[n] = sendRecvBuffer[n];
6094 }
6095 for(MInt n = 0; n < m_noOfModes; n++) {
6096 m_p1[n] = sendRecvBuffer[n + 1 * m_noOfModes];
6097 }
6098 for(MInt n = 0; n < m_noOfModes; n++) {
6099 m_p2[n] = sendRecvBuffer[n + 2 * m_noOfModes];
6100 }
6101 for(MInt n = 0; n < m_noOfModes; n++) {
6102 m_p3[n] = sendRecvBuffer[n + 3 * m_noOfModes];
6103 }
6104 for(MInt n = 0; n < m_noOfModes; n++) {
6105 m_q1[n] = sendRecvBuffer[n + 4 * m_noOfModes];
6106 }
6107 for(MInt n = 0; n < m_noOfModes; n++) {
6108 m_q2[n] = sendRecvBuffer[n + 5 * m_noOfModes];
6109 }
6110 for(MInt n = 0; n < m_noOfModes; n++) {
6111 m_q3[n] = sendRecvBuffer[n + 6 * m_noOfModes];
6112 }
6113 for(MInt n = 0; n < m_noOfModes; n++) {
6114 m_dhat1[n] = sendRecvBuffer[n + 7 * m_noOfModes];
6115 }
6116 for(MInt n = 0; n < m_noOfModes; n++) {
6117 m_dhat2[n] = sendRecvBuffer[n + 8 * m_noOfModes];
6118 }
6119 for(MInt n = 0; n < m_noOfModes; n++) {
6120 m_dhat3[n] = sendRecvBuffer[n + 9 * m_noOfModes];
6121 }
6122 }
6123 }
6124
6125 if((m_rank_bc1601 == 0) || (!m_commValues)) { // write the random numbers into a file (only domain 0)
6126 ofstream writeRnd;
6127 MString file = "randVars";
6128 if(!m_commValues) {
6129 stringstream test;
6130 test << file;
6131 struct stat st {};
6132 if(stat((test.str()).c_str(), &st) != 0) {
6133#if defined(MAIA_MS_COMPILER)
6134#pragma message("WARNING: Not compatible")
6135 mTerm(0, "ERROR: Not implemented!");
6136#else
6137 mkdir((test.str()).c_str(), 0744);
6138#endif
6139 m_log << endl << "creating folder " << test.str() << " for random numbers" << endl;
6140 }
6141 test << "/" << file << "_D" << m_domainId;
6142 file.clear();
6143 file.append(test.str());
6144 }
6145 writeRnd.open(file.c_str(), ios_base::out | ios_base::trunc | ios_base::binary);
6146
6147 MFloat fnumber;
6148
6149 for(MInt n = 0; n < m_noOfModes; n++) {
6150 fnumber = m_omega[n];
6151#ifdef SWAP_ENDIAN
6152 fnumber = doubleSwap(fnumber);
6153#endif
6154 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6155 fnumber = m_p1[n];
6156#ifdef SWAP_ENDIAN
6157 fnumber = doubleSwap(fnumber);
6158#endif
6159 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6160 fnumber = m_p2[n];
6161#ifdef SWAP_ENDIAN
6162 fnumber = doubleSwap(fnumber);
6163#endif
6164 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6165 fnumber = m_p3[n];
6166#ifdef SWAP_ENDIAN
6167 fnumber = doubleSwap(fnumber);
6168#endif
6169 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6170 fnumber = m_q1[n];
6171#ifdef SWAP_ENDIAN
6172 fnumber = doubleSwap(fnumber);
6173#endif
6174 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6175 fnumber = m_q2[n];
6176#ifdef SWAP_ENDIAN
6177 fnumber = doubleSwap(fnumber);
6178#endif
6179 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6180 fnumber = m_q3[n];
6181#ifdef SWAP_ENDIAN
6182 fnumber = doubleSwap(fnumber);
6183#endif
6184 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6185 fnumber = m_dhat1[n];
6186#ifdef SWAP_ENDIAN
6187 fnumber = doubleSwap(fnumber);
6188#endif
6189 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6190 fnumber = m_dhat2[n];
6191#ifdef SWAP_ENDIAN
6192 fnumber = doubleSwap(fnumber);
6193#endif
6194 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6195 fnumber = m_dhat3[n];
6196#ifdef SWAP_ENDIAN
6197 fnumber = doubleSwap(fnumber);
6198#endif
6199 writeRnd.write(reinterpret_cast<char*>(&fnumber), sizeof(MFloat));
6200 }
6201 writeRnd.close();
6202 }
6203}
6204
6205template <MInt nDim>
6207 ifstream readRnd;
6208 MString file = "randVars";
6209 if(!m_commValues) {
6210 stringstream test;
6211 test << file << "/" << file << "_D" << m_domainId;
6212 file.clear();
6213 file.append(test.str());
6214 }
6215 readRnd.open(file.c_str(), ios_base::in | ios_base::binary);
6216
6217 if(!readRnd) {
6218 return false;
6219 }
6220
6221 m_log << " read Random numbers from restartFile " << file << " ..." << endl;
6222
6223 MFloat fnumber;
6224
6225 for(MInt n = 0; n < m_noOfModes; n++) {
6226 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6227#ifdef SWAP_ENDIAN
6228 fnumber = doubleSwap(fnumber);
6229#endif
6230 m_omega[n] = fnumber;
6231 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6232#ifdef SWAP_ENDIAN
6233 fnumber = doubleSwap(fnumber);
6234#endif
6235 m_p1[n] = fnumber;
6236 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6237#ifdef SWAP_ENDIAN
6238 fnumber = doubleSwap(fnumber);
6239#endif
6240 m_p2[n] = fnumber;
6241 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6242#ifdef SWAP_ENDIAN
6243 fnumber = doubleSwap(fnumber);
6244#endif
6245 m_p3[n] = fnumber;
6246 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6247#ifdef SWAP_ENDIAN
6248 fnumber = doubleSwap(fnumber);
6249#endif
6250 m_q1[n] = fnumber;
6251 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6252#ifdef SWAP_ENDIAN
6253 fnumber = doubleSwap(fnumber);
6254#endif
6255 m_q2[n] = fnumber;
6256 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6257#ifdef SWAP_ENDIAN
6258 fnumber = doubleSwap(fnumber);
6259#endif
6260 m_q3[n] = fnumber;
6261 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6262#ifdef SWAP_ENDIAN
6263 fnumber = doubleSwap(fnumber);
6264#endif
6265 m_dhat1[n] = fnumber;
6266 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6267#ifdef SWAP_ENDIAN
6268 fnumber = doubleSwap(fnumber);
6269#endif
6270 m_dhat2[n] = fnumber;
6271 readRnd.read((char*)(&fnumber), sizeof(MFloat));
6272#ifdef SWAP_ENDIAN
6273 fnumber = doubleSwap(fnumber);
6274#endif
6275 m_dhat3[n] = fnumber;
6276 }
6277 readRnd.close();
6278
6279 return true;
6280}
6281
6282template <MInt nDim>
6283Bc1601Class<nDim>::Bc1601Class(MPI_Comm& communicator, const MInt m_solverId, const MInt domainId, MFloat& u_total,
6284 MFloat& invSigmaSponge)
6285 : m_domainId(domainId) {
6286 m_comm_bc1601 = communicator;
6287 MPI_Comm_rank(m_comm_bc1601, &m_rank_bc1601);
6288 m_invSigmaSponge = invSigmaSponge;
6289
6290 // read properties
6298 m_l_b = Context::getSolverProperty<MFloat>("bc1601Lb", m_solverId, AT_);
6299
6307 m_noOfModes = 0;
6308 m_noOfModes = Context::getSolverProperty<MInt>("noOfRandomModes", m_solverId, AT_, &m_noOfModes);
6316 m_oldMode = 0;
6317 m_oldMode = Context::getSolverProperty<MInt>("bc1601OldMode", m_solverId, AT_, &m_oldMode);
6318
6319 if(m_oldMode) {
6320 m_commValues = false;
6321 } else {
6322 m_commValues = true;
6323 }
6332 m_commValues = Context::getSolverProperty<MBool>("bc1601CommValues", m_solverId, AT_, &m_commValues);
6333
6341 m_useUnif = false;
6342 m_useUnif = Context::getSolverProperty<MBool>("bc1601UseUnif", m_solverId, AT_, &m_useUnif);
6343
6344 MBool restart = false;
6345 restart = Context::getSolverProperty<MBool>("restartFile", m_solverId, AT_, &restart);
6346
6355 m_regenerateSeeding = false;
6357 Context::getSolverProperty<MBool>("bc1601RegenerateSeeding", m_solverId, AT_, &m_regenerateSeeding);
6358
6372 Context::getSolverProperty<MInt>("bc1601RegenerationInterval", m_solverId, AT_, &m_regenerationInterval);
6373
6375
6384 uuref = 0.0, uvref = 0.0, uwref = 0.0;
6385 vvref = 0.0, vwref = 0.0, wwref = 0.0;
6386 uuref = Context::getSolverProperty<MFloat>("uuref", m_solverId, AT_, &uuref);
6387 uvref = Context::getSolverProperty<MFloat>("uvref", m_solverId, AT_, &uvref);
6388 uwref = Context::getSolverProperty<MFloat>("uwref", m_solverId, AT_, &uwref);
6389 vvref = Context::getSolverProperty<MFloat>("vvref", m_solverId, AT_, &vvref);
6390 vwref = Context::getSolverProperty<MFloat>("vwref", m_solverId, AT_, &vwref);
6391 wwref = Context::getSolverProperty<MFloat>("wwref", m_solverId, AT_, &wwref);
6392
6393 // Shin's modification
6394 smirnov = false;
6407 smirnov = Context::getSolverProperty<MBool>("smirnov", m_solverId, AT_, &smirnov);
6408
6409
6410 // ------------------------------------------
6411 // Beginning of Shin's modification
6412 // Use smirnov to activate the Shin's modification
6413 //
6414 // For reference, remember the following lines in fvbndrycnd3d.cpp
6415 //
6416 // dummyTime = m_solver->m_time / m_bc1601->m_tau_b;
6417 // that = 2.0 * PI * dummyTime;
6418 // twopioverlb = 2.0 * PI / m_bc1601->m_l_b;
6419 // xhat = twopioverlb * m_solver->a_coordinate( cellId , 0);
6420 // yhat = twopioverlb * m_solver->a_coordinate( cellId , 1);
6421 // zhat = twopioverlb * m_solver->a_coordinate( cellId , 2);
6422
6423 if(smirnov == 1) {
6424 m_log << " Use Shin method for synthetic turbulence injection..." << endl;
6425 m_log << " It used Taylor hypothesis for temporal part" << endl;
6426
6427 m_v_b = sqrt(0.5 * (uuref + vvref + wwref));
6428 m_tau_b = m_l_b / u_total; // Always use Taylor's hypothesis
6429 } else {
6430 m_log << "It is not using Shin method for synthetic turbulence injection..." << endl;
6431
6432 // calculate time and velocity scales
6433 if(m_oldMode) {
6434 m_v_b = sqrt(0.5 * (uuref + vvref + wwref));
6435 m_tau_b = m_l_b / u_total;
6436 } else {
6437 if(m_useUnif) {
6438 m_v_b = u_total;
6439 } else {
6440 m_v_b = sqrt(0.5 * (uuref + vvref + wwref));
6441 }
6442 m_tau_b = m_l_b / m_v_b;
6443 }
6444 }
6445 // End of Shin's modification
6446 // ------------------------------------------
6447
6448
6449 // cholesky decompostion of reynolds stress tensor
6450 mAlloc(aa, 6, "aa", AT_);
6451 if(uuref <= 0.0) cerr << "WARNING in proc " << m_domainId << ": a11^2 <= 0 in bcInit1601" << endl;
6452 aa[0] = sqrt(uuref);
6453 aa[1] = uvref / aa[0];
6454 aa[2] = uwref / aa[0];
6455 if((vvref - aa[1] * aa[1]) <= 0.0) cerr << "WARNING in proc " << m_domainId << ": a22^2 <= 0 in bcInit1601" << endl;
6456 aa[3] = sqrt(vvref - aa[1] * aa[1]);
6457 aa[4] = (vwref - aa[1] * aa[2]) / aa[3];
6458 if((wwref - aa[2] * aa[2] - aa[4] * aa[4]) <= 0.0) {
6459 cerr << "WARNING in proc " << m_domainId << ": a33^2 <= 0 in bcInit1601" << endl;
6460 }
6461 aa[5] = sqrt(wwref - aa[2] * aa[2] - aa[4] * aa[4]);
6462
6463 // ---------------------------------------------------
6464 // Beginning of Shin's modification
6465 // Need to evaluate the eigenvectors and eigenvalues
6466
6467
6468 if(smirnov == 1) {
6469 MFloat Rey_str[3][3]; // Shin's modification
6470 MFloat eigval[3]; // Shin's modification
6471
6472 // eigvec = new MFloat[3][3]; // defined in fvbndrycndxd.h
6473
6474 Rey_str[0][0] = uuref;
6475 Rey_str[1][0] = uvref;
6476 Rey_str[2][0] = uwref;
6477 Rey_str[0][1] = uvref;
6478 Rey_str[1][1] = vvref;
6479 Rey_str[2][1] = vwref;
6480 Rey_str[0][2] = uwref;
6481 Rey_str[1][2] = vwref;
6482 Rey_str[2][2] = wwref;
6483
6484 maia::math::calcEigenVectors(Rey_str, eigvec, eigval); // defined in maiamath.h
6485
6486 c1 = sqrt(eigval[0]); // c1, c2, c3 are defined in fvbndrycndxd.h
6487 c2 = sqrt(eigval[1]);
6488 c3 = sqrt(eigval[2]);
6489
6490 // m_log << "Shin method eigen values are" << endl;
6491 // m_log << eigval[0] << ", " << eigval[1] << ", " << eigval[2] << endl;
6492 //
6493 // m_log << "Shin method eigen vectors are" << endl;
6494 // m_log << eigvec[0][0] << ", " << eigvec[0][1] << ", " << eigvec[0][2] << endl;
6495 // m_log << eigvec[1][0] << ", " << eigvec[1][1] << ", " << eigvec[1][2] << endl;
6496 // m_log << eigvec[2][0] << ", " << eigvec[2][1] << ", " << eigvec[2][2] << endl;
6497 }
6498 // End of Shin's modification
6499 // ---------------------------------------------------
6500
6501
6502 // reserve memory
6503 if(m_noOfModes > 0) {
6504 mAlloc(m_omega, m_noOfModes, "m_omega", AT_);
6505 mAlloc(m_p1, m_noOfModes, "m_p1", AT_);
6506 mAlloc(m_p2, m_noOfModes, "m_p2", AT_);
6507 mAlloc(m_p3, m_noOfModes, "m_p3", AT_);
6508 mAlloc(m_q1, m_noOfModes, "m_q1", AT_);
6509 mAlloc(m_q2, m_noOfModes, "m_q2", AT_);
6510 mAlloc(m_q3, m_noOfModes, "m_q3", AT_);
6511 mAlloc(m_dhat1, m_noOfModes, "m_dhat1", AT_);
6512 mAlloc(m_dhat2, m_noOfModes, "m_dhat2", AT_);
6513 mAlloc(m_dhat3, m_noOfModes, "m_dhat3", AT_);
6514 }
6515
6516 if(m_noOfModes > 0) {
6517 m_log << "Initialize 1601 random inflow with " << m_noOfModes << " random modes..." << endl;
6518
6519 if(restart) {
6520 if(!loadRandomNumbers()) mTerm(1, AT_, "Error opening random-variables file randVars");
6521 } else {
6523 }
6524
6525 m_log << "ok" << endl;
6526 }
6527}
6528
6529
6530template <MInt nDim>
6532 mDeallocate(aa);
6533 mDeallocate(m_omega);
6534 mDeallocate(m_p1);
6535 mDeallocate(m_p2);
6536 mDeallocate(m_p3);
6537 mDeallocate(m_q1);
6538 mDeallocate(m_q2);
6539 mDeallocate(m_q3);
6540 mDeallocate(m_dhat1);
6541 mDeallocate(m_dhat2);
6542 mDeallocate(m_dhat3);
6543}
6544
6545
6546template <MInt nDim>
6547void Bc1601Class<nDim>::calculateFlucts(const MFloat that, const MFloat xhat, const MFloat yhat, const MFloat zhat,
6548 MFloat* fluctChol) {
6549 MFloat xfluct = 0.0;
6550 MFloat yfluct = 0.0;
6551 MFloat zfluct = 0.0;
6552 MFloat tmpVar;
6553 MFloat B;
6554 MFloat D;
6555
6556 // -----------------------------------------
6557 // Beginning of Shin's modification
6558 //
6559 if(smirnov == 1) {
6560 MFloat xx;
6561 MFloat yy;
6562 MFloat zz;
6563
6564 for(MInt n = 0; n < m_noOfModes; n++) {
6565 // Counter-rotate the coordinate
6566 // * eigvec, c1, c2, c3 are defined in fvbndrycndxd.h
6567 // and evaluated in Bc1601Class::Bc1601Class
6568 xx = eigvec[0][0] * (xhat - that) + eigvec[1][0] * yhat + eigvec[2][0] * zhat;
6569 yy = eigvec[0][1] * (xhat - that) + eigvec[1][1] * yhat + eigvec[2][1] * zhat;
6570 zz = eigvec[0][2] * (xhat - that) + eigvec[1][2] * yhat + eigvec[2][2] * zhat;
6571
6572 // Here the anisotropic scaling is applied through c1, c2, and c3.
6573 tmpVar = m_dhat1[n] / c1 * xx + m_dhat2[n] / c2 * yy + m_dhat3[n] / c3 * zz;
6574 B = cos(tmpVar);
6575 D = sin(tmpVar);
6576
6577 xfluct += m_p1[n] * B + m_q1[n] * D;
6578 yfluct += m_p2[n] * B + m_q2[n] * D;
6579 zfluct += m_p3[n] * B + m_q3[n] * D;
6580 }
6581 } else {
6582 for(MInt n = 0; n < m_noOfModes; n++) {
6583 tmpVar = m_dhat1[n] * xhat + m_dhat2[n] * yhat + m_dhat3[n] * zhat + m_omega[n] * that;
6584
6585 B = cos(tmpVar);
6586 D = sin(tmpVar);
6587
6588 xfluct += m_p1[n] * B + m_q1[n] * D;
6589 yfluct += m_p2[n] * B + m_q2[n] * D;
6590 zfluct += m_p3[n] * B + m_q3[n] * D;
6591 }
6592 }
6593 //
6594 // End of Shin's modification
6595 // -----------------------------------------
6596
6597
6598 if(m_noOfModes > 0) {
6599 xfluct *= sqrt(2.0 / ((MFloat)m_noOfModes));
6600 yfluct *= sqrt(2.0 / ((MFloat)m_noOfModes));
6601 zfluct *= sqrt(2.0 / ((MFloat)m_noOfModes));
6602 } else {
6603 xfluct = 0.0;
6604 yfluct = 0.0;
6605 zfluct = 0.0;
6606 }
6607
6608 // -----------------------------------------------
6609 // Beginning of Shin's modification
6610 // Need to apply scaling and rotation by
6611 // eigenvalues and eigenvectors
6612 if(smirnov == 1) {
6613 MFloat w1;
6614 MFloat w2;
6615 MFloat w3;
6616
6617 w1 = c1 * xfluct; // w1, w2, w3 are defined locally
6618 w2 = c2 * yfluct; // c1, c2, c3 are defined in fvbndrycndxd.h
6619 w3 = c3 * zfluct;
6620
6621 // The following fluctChol means fluctuation by Smirnov's method.
6622 // * Lazy to change the variable names.
6623 // * eigvec are defined in fvbndrycndxd.h
6624 // and evaluated in Bc1601Class::Bc1601Class
6625 fluctChol[0] = eigvec[0][0] * w1 + eigvec[0][1] * w2 + eigvec[0][2] * w3;
6626 fluctChol[1] = eigvec[1][0] * w1 + eigvec[1][1] * w2 + eigvec[1][2] * w3;
6627 fluctChol[2] = eigvec[2][0] * w1 + eigvec[2][1] * w2 + eigvec[2][2] * w3;
6628
6629 } else {
6630 fluctChol[0] = xfluct * aa[0];
6631 fluctChol[1] = xfluct * aa[1] + yfluct * aa[3];
6632 fluctChol[2] = xfluct * aa[2] + yfluct * aa[4] + zfluct * aa[5];
6633 }
6634 // End of Shin's modification
6635 // -----------------------------------------------
6636}
6637
6638template <MInt nDim>
6639void Bc1601Class<nDim>::checkRegeneration(const MFloat time) { // time = m_solver->m_time / m_bc1601->m_tau_b;
6640 if(m_regenerateSeeding) {
6641 MInt dummy = floor(time / m_regenerationInterval);
6642 if(dummy > m_regenerationCounter) {
6643 m_regenerationCounter = dummy;
6644 generateAndCommRandomNumbers();
6645 }
6646 }
6647}
6648
6649
6657template <MInt nDim, class SysEqn>
6658template <MBool MGC>
6660 TRACE();
6661
6662 const MInt noPVars = PV->noVariables;
6663
6664#ifdef _OPENMP
6665#pragma omp parallel for
6666#endif
6667 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
6668 const MInt bndryId = m_sortedBndryCells->a[id];
6669 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
6670
6671 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
6672 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
6673 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
6674 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
6675
6676 MFloat preFactor = NAN;
6677 IF_CONSTEXPR(nDim == 3) {
6678 if(MGC) {
6679 // compute the distance between ghost and boundary cell (MGC formulation -> image Point)
6680 preFactor = 1.0
6681 / sqrt(POW2(m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[0]
6682 - m_solver->a_coordinate(ghostCellId, 0))
6683 + POW2(m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[1]
6684 - m_solver->a_coordinate(ghostCellId, 1))
6685 + POW2(m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[2]
6686 - m_solver->a_coordinate(ghostCellId, 2)))
6687 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_FJacobian;
6688 } else {
6689 // compute the distance between ghost and boundary cell and multiply with inverse Jacobian
6690 preFactor = 1.0
6691 / sqrt(POW2(m_solver->a_coordinate(cellId, 0) - m_solver->a_coordinate(ghostCellId, 0))
6692 + POW2(m_solver->a_coordinate(cellId, 1) - m_solver->a_coordinate(ghostCellId, 1))
6693 + POW2(m_solver->a_coordinate(cellId, 2) - m_solver->a_coordinate(ghostCellId, 2)))
6694 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_FJacobian;
6695 }
6696 }
6697 else {
6698 if(MGC) {
6699 // compute the distance between ghost and boundary cell (MGC formulation -> image Point)
6700 preFactor = 1.0
6701 / sqrt(POW2(m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[0]
6702 - m_solver->a_coordinate(ghostCellId, 0))
6703 + POW2(m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[1]
6704 - m_solver->a_coordinate(ghostCellId, 1)))
6705 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_FJacobian;
6706
6707 } else {
6708 // compute the distance between ghost and boundary cell and multiply with inverse Jacobian
6709 preFactor = 1.0
6710 / sqrt(POW2(m_solver->a_coordinate(cellId, 0) - m_solver->a_coordinate(ghostCellId, 0))
6711 + POW2(m_solver->a_coordinate(cellId, 1) - m_solver->a_coordinate(ghostCellId, 1)))
6712 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_FJacobian;
6713 }
6714 }
6715
6716 MFloat const1;
6717 MFloat const2;
6718 MFloat const3;
6719
6720 IF_CONSTEXPR(nDim == 3) {
6721 // compute the surface slopes
6722 const1 = (m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector0[1]
6723 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector1[2]
6724 - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector1[1]
6725 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector0[2])
6726 * preFactor;
6727
6728 const2 = (m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector0[2]
6729 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector1[0]
6730 - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector1[2]
6731 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector0[0])
6732 * preFactor;
6733
6734 const3 = (m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector0[0]
6735 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector1[1]
6736 - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector1[0]
6737 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_planeVector0[1])
6738 * preFactor;
6739 }
6740 else {
6741 const1 = preFactor * m_bndryCells->a[bndryId].m_srfcs[0]->m_planeVector0[1];
6742 const2 = -preFactor * m_bndryCells->a[bndryId].m_srfcs[0]->m_planeVector0[0];
6743 const3 = 0;
6744 }
6745
6746 // compute the slopes on the ghost cell
6747 for(MInt i = 0; i < nDim; i++) {
6748 MFloat factor = NAN;
6749 if(MGC) {
6750 factor = (m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->VV[i]]
6751 - m_solver->a_pvariable(ghostCellId, PV->VV[i]));
6752 } else {
6753 factor = (m_solver->a_pvariable(cellId, PV->VV[i]) - m_solver->a_pvariable(ghostCellId, PV->VV[i]));
6754 }
6755 m_solver->a_slope(ghostCellId, PV->VV[i], 0) =
6756 2.0 * factor * const1 - m_solver->a_slope(cellId, PV->VV[i], 0);
6757 m_solver->a_slope(ghostCellId, PV->VV[i], 1) =
6758 2.0 * factor * const2 - m_solver->a_slope(cellId, PV->VV[i], 1);
6759 IF_CONSTEXPR(nDim == 3) {
6760 m_solver->a_slope(ghostCellId, PV->VV[i], 2) =
6761 2.0 * factor * const3 - m_solver->a_slope(cellId, PV->VV[i], 2);
6762 }
6763 }
6764
6765
6766 for(MInt varId = nDim; varId < noPVars; varId++) {
6767 for(MInt i = 0; i < nDim; i++) {
6768 m_solver->a_slope(ghostCellId, varId, i) = -m_solver->a_slope(cellId, varId, i);
6769 }
6770 }
6771 }
6772 }
6773 }
6774 }
6775}
6776
6777
6784template <MInt nDim, class SysEqn>
6785template <MInt dir>
6787 TRACE();
6788 static_assert(dir <= nDim, "ERROR: Invalid direction!");
6789
6790 const MInt noPVars = PV->noVariables;
6791
6792#ifdef _OPENMP
6793#pragma omp parallel for
6794#endif
6795 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
6796 const MInt bndryId = m_sortedBndryCells->a[id];
6797 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
6798 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
6799 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
6800
6801 for(MInt v = 0; v < noPVars; v++) {
6802 if(dir == 0) {
6803 m_solver->a_slope(ghostCellId, v, 0) =
6804 (m_solver->a_pvariable(cellId, v) - m_solver->a_pvariable(ghostCellId, v))
6805 / (m_solver->a_coordinate(cellId, 0) - m_solver->a_coordinate(ghostCellId, 0));
6806 } else {
6807 m_solver->a_slope(ghostCellId, v, 0) = m_solver->a_slope(cellId, v, 0);
6808 }
6809
6810 if(dir == 1) {
6811 m_solver->a_slope(ghostCellId, v, 1) =
6812 (m_solver->a_pvariable(cellId, v) - m_solver->a_pvariable(ghostCellId, v))
6813 / (m_solver->a_coordinate(cellId, 1) - m_solver->a_coordinate(ghostCellId, 1));
6814 } else {
6815 m_solver->a_slope(ghostCellId, v, 1) = m_solver->a_slope(cellId, v, 1);
6816 }
6817
6818 IF_CONSTEXPR(nDim == 3) {
6819 if(dir == 2) {
6820 m_solver->a_slope(ghostCellId, v, 2) =
6821 (m_solver->a_pvariable(cellId, v) - m_solver->a_pvariable(ghostCellId, v))
6822 / (m_solver->a_coordinate(cellId, 2) - m_solver->a_coordinate(ghostCellId, 2));
6823 } else {
6824 m_solver->a_slope(ghostCellId, v, 2) = m_solver->a_slope(cellId, v, 2);
6825 }
6826 }
6827 }
6828
6829 // compute the slopes on the ghost cell
6830 for(MInt v = 0; v < noPVars; v++) {
6831 for(MInt i = 0; i < nDim; i++) {
6832 m_solver->a_slope(ghostCellId, v, i) =
6833 2.0 * m_solver->a_slope(ghostCellId, v, i) - m_solver->a_slope(cellId, v, i);
6834 }
6835 }
6836 }
6837 }
6838}
6839
6846template <MInt nDim, class SysEqn>
6847template <MInt dir>
6849 TRACE();
6850 static_assert(dir <= nDim, "ERROR: Invalid direction!");
6851
6852
6853 const MInt noPVars = PV->noVariables;
6854 ScratchSpace<MFloat> PVbndry(noPVars, AT_, "PVbndry");
6855 ScratchSpace<MFloat> PVghost(noPVars, AT_, "PVghost");
6856
6857 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
6858 const MInt bndryId = m_sortedBndryCells->a[id];
6859 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
6860 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
6861 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
6862
6863 // determine the primitive variables on the boundary and on the ghost cell
6864 const MFloat Frho = 1.0 / m_solver->a_variable(cellId, CV->RHO);
6865 const MFloat FrhoGhost = 1.0 / m_solver->a_variable(ghostCellId, CV->RHO);
6866 // velocitites
6867 for(MInt i = 0; i < nDim; i++) {
6868 PVbndry[i] = m_solver->a_variable(cellId, CV->RHO_VV[i]) * Frho;
6869 PVghost[i] = m_solver->a_variable(ghostCellId, CV->RHO_VV[i]) * FrhoGhost;
6870 }
6871
6872 // density
6873 PVbndry[PV->RHO] = m_solver->a_variable(cellId, CV->RHO);
6874 PVghost[PV->RHO] = m_solver->a_variable(ghostCellId, CV->RHO);
6875
6876 // pressure
6877 MFloat rhoU2 = 0.0;
6878 for(MInt i = 0; i < nDim; i++) {
6879 rhoU2 += POW2(m_solver->a_variable(cellId, CV->RHO_VV[i]));
6880 }
6881 PVbndry[PV->P] =
6882 sysEqn().pressure(m_solver->a_variable(cellId, CV->RHO), rhoU2, m_solver->a_variable(cellId, CV->RHO_E));
6883
6884 rhoU2 = F0;
6885 for(MInt i = 0; i < nDim; i++) {
6886 rhoU2 += POW2(m_solver->a_variable(ghostCellId, CV->RHO_VV[i]));
6887 }
6888 PVghost[PV->P] = sysEqn().pressure(m_solver->a_variable(ghostCellId, CV->RHO), rhoU2,
6889 m_solver->a_variable(ghostCellId, CV->RHO_E));
6890
6891 // passive scalar
6892 for(MInt s = 0; s < m_noSpecies; s++) {
6893 PVbndry[PV->Y[s]] = m_solver->a_variable(cellId, CV->RHO_Y[s]) * Frho;
6894 PVghost[PV->Y[s]] = m_solver->a_variable(ghostCellId, CV->RHO_Y[s]) * FrhoGhost;
6895 }
6896
6897 for(MInt var = 0; var < noPVars; var++) {
6898 if(dir == 0) {
6899 m_solver->a_slope(ghostCellId, var, 0) =
6900 (PVbndry[var] - PVghost[var])
6901 / (m_solver->a_coordinate(cellId, 0) - m_solver->a_coordinate(ghostCellId, 0));
6902 } else {
6903 m_solver->a_slope(ghostCellId, var, 0) = m_solver->a_slope(cellId, var, 0);
6904 }
6905
6906 if(dir == 1) {
6907 m_solver->a_slope(ghostCellId, var, 1) =
6908 (PVbndry[var] - PVghost[var])
6909 / (m_solver->a_coordinate(cellId, 1) - m_solver->a_coordinate(ghostCellId, 1));
6910 } else {
6911 m_solver->a_slope(ghostCellId, var, 1) = m_solver->a_slope(cellId, var, 1);
6912 }
6913
6914 IF_CONSTEXPR(nDim == 3) {
6915 if(dir == 2) {
6916 m_solver->a_slope(ghostCellId, var, 2) =
6917 (PVbndry[var] - PVghost[var])
6918 / (m_solver->a_coordinate(cellId, 2) - m_solver->a_coordinate(ghostCellId, 2));
6919 } else {
6920 m_solver->a_slope(ghostCellId, var, 2) = m_solver->a_slope(cellId, var, 2);
6921 }
6922 }
6923 }
6924
6925 // compute the slopes on the ghost cell
6926 for(MInt varId = 0; varId < noPVars; varId++) {
6927 for(MInt i = 0; i < nDim; i++) {
6928 m_solver->a_slope(ghostCellId, varId, i) =
6929 2.0 * m_solver->a_slope(ghostCellId, varId, i) - m_solver->a_slope(cellId, varId, i);
6930 }
6931 }
6932 }
6933 }
6934}
6935//------------------------------------------------------------------------------
6936
6937// Regular no slip condition is applied
6938template <MInt nDim, class SysEqn>
6939template <MBool MGC>
6941 TRACE();
6942 const MInt noSpecies = m_noSpecies;
6943
6944#ifdef _OPENMP
6945#pragma omp parallel for
6946#endif
6947 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
6948 const MInt bndryId = m_sortedBndryCells->a[id];
6949 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
6950 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
6951 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
6952 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
6953 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
6954
6955 for(MInt i = 0; i < nDim; i++) {
6956 if(MGC) {
6957 if(m_surfaceGhostCell) {
6958 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = 0.0;
6959 } else {
6960 m_solver->a_pvariable(ghostCellId, PV->VV[i]) =
6961 -m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->VV[i]];
6962 }
6963 } else {
6964 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = -m_solver->a_pvariable(cellId, PV->VV[i]);
6965 }
6966 }
6967 if(MGC) {
6968 m_solver->a_pvariable(ghostCellId, PV->RHO) =
6969 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->RHO];
6970 m_solver->a_pvariable(ghostCellId, PV->P) =
6971 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->P];
6972 } else {
6973 // simplified Neumann: assuming the line boundary-ghost is normal to the boundary surface)
6974 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
6975 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
6976 }
6977
6978 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
6979 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
6980 if(MGC) {
6981 if(m_surfaceGhostCell) {
6982 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = 0.0;
6983 } else {
6984 m_solver->a_pvariable(ghostCellId, PV->NN[r]) =
6985 -m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->NN[r]];
6986 }
6987 } else {
6988 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = m_solver->a_pvariable(cellId, PV->NN[r]);
6989 }
6990 }
6991 }
6992 for(MInt s = 0; s < noSpecies; s++) {
6993 if(MGC) {
6994 m_solver->a_pvariable(ghostCellId, PV->Y[s]) =
6995 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->Y[s]];
6996 } else {
6997 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
6998 }
6999 }
7000 }
7001 }
7002 }
7003 }
7004}
7005
7006template <MInt nDim, class SysEqn>
7008 TRACE();
7009
7010 m_solver->m_wmSurfaces.clear();
7011
7012 if(PV->noVariables > 5) mTerm(1, AT_, "WMLES not implemented for noPVars > 5");
7013
7014 const MFloat utau = sqrt(m_solver->m_UInfinity / m_solver->m_wmDistance / sysEqn().m_Re0);
7015
7016 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
7017 MInt bc = m_bndryCndIds[bcId];
7018 switch(bc) {
7019 case 3399:
7020 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
7021 const MInt bndryId = m_sortedBndryCells->a[id];
7022 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
7023 if(m_solver->a_hasProperty(cellId, SolverCell::IsHalo)) continue;
7024 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
7025
7026 m_bndryCells->a[bndryId].m_isWMCell = true;
7027
7028 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
7029 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_wmSrfcId = (MInt)m_solver->m_wmSurfaces.size();
7030 m_solver->m_wmSurfaces.push_back(FvWMSurface<nDim>());
7031 m_solver->m_wmSurfaces.back().init(bndryId, srfc, utau);
7032 m_solver->m_wmSurfaces.back().m_wmUII = m_solver->m_UInfinity;
7033 if(std::isnan(m_solver->m_wmSurfaces.back().m_wmUTAU)) {
7034 MLong gId = m_solver->c_globalId(cellId);
7035 cerr << "utau is nan at globalId = " << gId << " bndryId = " << bndryId << " surfaceId = " << srfc
7036 << endl;
7037 m_log << "utau is nan at globalId = " << gId << " bndryId = " << bndryId << " surfaceId = " << srfc
7038 << endl;
7039 }
7040 }
7041 }
7042 break;
7043 default:
7044 break;
7045 }
7046 }
7047}
7048
7049
7054template <MInt nDim, class SysEqn>
7056 TRACE();
7057 const MFloat time = m_solver->m_time;
7058 const MInt bcNum = m_cutOffBndryCndIds[bcId];
7059
7060 for(MInt mode = 0; mode < m_modes; mode++) {
7061 const MFloat modeEtaMin = m_modeEtaMin[mode];
7062 const MFloat modePhi = m_modePhi[mode];
7063 const MFloat modeOmega = m_modeOmega[mode];
7064
7065 // 0. set the end of the wave(s)
7066 const MFloat modeEtaMax = -(MFloat)(m_nmbrOfModes[mode]) * PI;
7067
7068 // 1. pressure
7069 const MFloat pressure_f = m_modeAmp[mode] * m_solver->m_PInfinity * (MFloat)(m_modeType[mode]);
7070
7071 // 2. density
7072 const MFloat a = sysEqn().speedOfSound(m_solver->m_TInfinity);
7073 const MFloat density_f = m_modeType[mode] ? pressure_f / POW2(a) : m_modeAmp[mode] * m_solver->m_rhoInfinity;
7074
7075 // 3. velocity
7076 MFloat K = F0;
7077 for(MInt i = 0; i < nDim; i++) {
7078 K += pow(m_modeK[mode][i], 2);
7079 }
7080 K = sqrt(K);
7081 const MFloat acImp = a * m_solver->m_rhoInfinity;
7082 const MFloat modeVelocity = (MFloat)(m_modeType[mode]) * pressure_f / acImp;
7083 MFloat velocity_f[3];
7084 for(MInt i = 0; i < nDim; i++) {
7085 velocity_f[i] = (m_modeK[mode][i] * modeVelocity) / K;
7086 }
7087
7088 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
7089 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
7090 if(bcNum == 2770) {
7091 if(m_solver->a_coordinate(cellId, 1)
7092 < m_ys + (tan(m_solver->m_angle[0] + m_sigmaShock) * m_solver->a_coordinate(cellId, 0))) {
7093 continue;
7094 }
7095 }
7096 // 1. calculate cell dependant trigonometry
7097 MFloat trigTerm = F0;
7098 for(MInt i = 0; i < nDim; i++) {
7099 trigTerm += m_modeK[mode][i] * m_solver->a_coordinate(cellId, i);
7100 }
7101 trigTerm -= modeOmega * time;
7102 trigTerm += modePhi;
7103
7104 // 2. filter the wave
7105 if(bcNum == 2800) {
7106 // 2.a calculate the difference to the reference starting min value (trigTerm decreases in time)
7107 trigTerm -= modeEtaMin;
7108
7109 // 2.b apply the filter to the phase
7110 if(trigTerm > F0 || trigTerm < modeEtaMax) {
7111 trigTerm = F0;
7112 }
7113 }
7114
7115 // 3. convert phase to amplitude
7116 trigTerm = sin(trigTerm);
7117
7118 // 4. add fluctuations
7119 // density
7120 m_solver->a_pvariable(cellId, PV->RHO) += trigTerm * density_f;
7121
7122 // velocities
7123 for(MInt dim = 0; dim < m_solver->nDim; dim++) {
7124 m_solver->a_pvariable(cellId, PV->VV[dim]) += trigTerm * velocity_f[dim];
7125 }
7126
7127 // pressure
7128 m_solver->a_pvariable(cellId, PV->P) += trigTerm * pressure_f;
7129 }
7130 }
7131}
7132
7133
7134template <MInt nDim, class SysEqn>
7136 const MInt bcNum = m_cutOffBndryCndIds[bcId];
7137 m_log << endl << "initializing plane modes for bcId " << bcId << endl;
7138 m_log << " running for " << bcNum << endl;
7139
7140 const MFloat time = m_solver->m_restart ? m_solver->m_time : F0;
7141
7142 // 1. check the modes and allocate memory
7156 m_modes = Context::propertyLength("modeType", m_solverId);
7157 mAlloc(m_modeType, m_modes, "m_modeType", 0, AT_);
7158 for(MInt i = 0; i < m_modes; i++) {
7159 m_modeType[i] = Context::getSolverProperty<MInt>("modeType", m_solverId, AT_, i);
7160 }
7172 if(m_modes != Context::propertyLength("modeAmp", m_solverId)) mTerm(1, AT_, "modeAmp does not fit modeType");
7173 mAlloc(m_modeAmp, m_modes, "m_modeAmp", F0, AT_);
7174 for(MInt i = 0; i < m_modes; i++) {
7175 m_modeAmp[i] = Context::getSolverProperty<MFloat>("modeAmp", m_solverId, AT_, i);
7176 }
7187 if(m_modes != Context::propertyLength("modePhi", m_solverId)) mTerm(1, AT_, "modePhi does not fit modeType");
7188 mAlloc(m_modePhi, m_modes, "m_modePhi", F0, AT_);
7189 for(MInt i = 0; i < m_modes; i++) {
7190 m_modePhi[i] = Context::getSolverProperty<MFloat>("modePhi", m_solverId, AT_, i) * PI / 180.0;
7191 }
7201 if(m_modes * 2 != Context::propertyLength("modeAngle", m_solverId)) mTerm(1, AT_, "modeAngle does not fit modeType");
7202 MFloatScratchSpace modeAngle(m_modes, 2, AT_, "modeAngle");
7203 modeAngle.fill(F0);
7204 mAlloc(m_modeK, m_modes, nDim, "m_modeK", F0, AT_);
7205 for(MInt mode = 0; mode < m_modes; mode++) {
7206 for(MInt j = 0; j < nDim - 1; j++) {
7207 modeAngle(mode, j) = Context::getSolverProperty<MFloat>("modeAngle", m_solverId, AT_, mode * 2 + j) * PI / 180.0;
7208 }
7209 m_modeK[mode][0] = cos(modeAngle(mode, 0)) * cos(modeAngle(mode, 1));
7210 m_modeK[mode][1] = sin(modeAngle(mode, 0)) * cos(modeAngle(mode, 1));
7211 IF_CONSTEXPR(nDim == 3) m_modeK[mode][2] = sin(modeAngle(mode, 1));
7212 }
7213
7223 if(m_modes != Context::propertyLength("nmbrOfModes", m_solverId)) mTerm(1, AT_, "nmbrOfModes does not fit modeType");
7224 mAlloc(m_nmbrOfModes, m_modes, "m_nmbrOfModes", 0, AT_);
7225 for(MInt i = 0; i < m_modes; i++) {
7226 m_nmbrOfModes[i] = Context::getSolverProperty<MInt>("nmbrOfModes", m_solverId, AT_, i);
7227 }
7228 MFloatScratchSpace modeSr(m_modes, AT_, "modeSr");
7229 MFloat UInfinity = F0;
7230 for(MInt i = 0; i < nDim; i++) {
7231 UInfinity += POW2(m_solver->m_VVInfinity[i]);
7232 }
7233 UInfinity = sqrt(UInfinity);
7234
7235 MFloat lambdaParN = F0;
7236 for(MInt i = 0; i < nDim; i++) {
7237 if(m_solver->grid().periodicCartesianDir(i) > 0) {
7238 if(lambdaParN > F0) mTerm(1, AT_, "more then two periodic directions in initModes");
7239 lambdaParN += m_solver->grid().periodicCartesianLength(i);
7240 }
7241 }
7242 m_log << "periodic length " << lambdaParN << endl;
7243 if(lambdaParN > F0) {
7244 m_log << "periodicCartesianDir: calculating modeSr from nmbrPeriodicModes" << endl;
7245 MFloatScratchSpace nmbrPeriodicModes(m_modes, AT_, "nmbrPeriodicModes");
7256 if(m_modes != Context::propertyLength("nmbrPeriodicModes", m_solverId)) {
7257 mTerm(1, AT_, "nmbrPeriodicModes does not fit modeType");
7258 }
7259
7260 for(MInt i = 0; i < m_modes; i++) {
7261 nmbrPeriodicModes(i) = Context::getSolverProperty<MInt>("nmbrPeriodicModes", m_solverId, AT_, i);
7262 }
7263 // compute Sr number
7264 for(MInt mode = 0; mode < m_modes; mode++) {
7265 MFloat Uk = F0;
7266 for(MInt i = 0; i < nDim; i++) {
7267 Uk += m_solver->m_VVInfinity[i] * m_modeK[mode][i];
7268 }
7269
7270 MFloat lambdaDotKnorm = F0;
7271 for(MInt i = 0; i < nDim; i++) {
7272 if(m_solver->grid().periodicCartesianDir(i) > 0) {
7273 if(lambdaDotKnorm > F0) mTerm(1, AT_, "more then two periodic directions in initModes");
7274 lambdaDotKnorm += m_solver->grid().periodicCartesianLength(i) * m_modeK[mode][i];
7275 }
7276 }
7277
7278 if(lambdaDotKnorm / lambdaParN < pow(10, -3)) {
7279 m_log << " modeSr(" << mode << ") from property file" << endl;
7280 if(m_modes != Context::propertyLength("modeSr", m_solverId)) mTerm(1, AT_, "modeType does not fit modeSr");
7281 modeSr(mode) = Context::getSolverProperty<MInt>("modeSr", m_solverId, AT_, mode);
7282 } else {
7283 modeSr(mode) = nmbrPeriodicModes(mode) * m_solver->m_referenceLength
7284 * abs((MFloat)(m_modeType[mode]) * sysEqn().speedOfSound(m_solver->m_TInfinity) + Uk)
7285 / (UInfinity * abs(lambdaDotKnorm));
7286 }
7287 m_log << "modeSr(" << mode << ") = " << modeSr(mode) << endl;
7288 }
7289 } else {
7302 if(m_modes != Context::propertyLength("modeSr", m_solverId)) mTerm(1, AT_, "modeType does not fit modeSr");
7303 for(MInt i = 0; i < m_modes; i++) {
7304 modeSr(i) = Context::getSolverProperty<MFloat>("modeSr", m_solverId, AT_, i);
7305 }
7306 }
7307 // time considerations
7308 MFloat initTime;
7309 if(m_solver->m_restartBc2800) {
7310 initTime = m_solver->m_restartTimeBc2800;
7311 } else {
7312 initTime = time;
7313 m_solver->m_restartTimeBc2800 = time;
7314 }
7315 m_log << "time = " << time << endl;
7316 m_log << "initTime = " << initTime << endl;
7317
7318 // further memberVariables
7319 mAlloc(m_modeOmega, m_modes, "m_modeOmega", F0, AT_);
7320 mAlloc(m_modeEtaMin, m_modes, "m_modeEtaMin", F0, AT_);
7321 // fill the member variables
7322 for(MInt mode = 0; mode < m_modes; mode++) {
7323 m_log << "-- mode " << mode << " --" << endl;
7324 m_log << " modeType = " << m_modeType[mode] << endl;
7325 m_log << " modeSr = " << modeSr(mode) << endl;
7326 m_log << " modeAmp = " << m_modeAmp[mode] << endl;
7327 m_log << " modePhi = " << m_modePhi[mode] << endl;
7328 m_log << " nmbrOfModes= " << m_nmbrOfModes[mode] << endl;
7329 for(MInt i = 0; i < (nDim - 1); i++) {
7330 m_log << " modeAngle(" << i << ") = " << modeAngle(mode, i) << " (rad)" << endl;
7331 }
7332 // 3. calculate nondimensional mode properties
7333 // 3.1 omega
7334 m_modeOmega[mode] = F2 * PI * modeSr(mode) * UInfinity / m_solver->m_referenceLength;
7335 // 3.2 complete wave vector modeK
7336 MFloat Uk = F0;
7337 for(MInt i = 0; i < nDim; i++) {
7338 Uk += m_solver->m_VVInfinity[i] * m_modeK[mode][i];
7339 }
7340 const MFloat propVel = (MFloat)(m_modeType[mode]) * sysEqn().speedOfSound(m_solver->m_TInfinity);
7341 const MFloat K = m_modeOmega[mode] / abs(Uk + propVel);
7342 for(MInt i = 0; i < nDim; i++) {
7343 m_modeK[mode][i] *= K;
7344 }
7345 // output omega and k
7346 m_log << " Uk = " << Uk << endl;
7347 m_log << " modeOmega = " << m_modeOmega[mode] << endl;
7348 m_log << " K = " << K << endl;
7349 for(MInt i = 0; i < nDim; i++) {
7350 m_log << " modeK[" << i << "] = " << m_modeK[mode][i] << endl;
7351 }
7352 // 4. get the min wave phase
7353 MFloat modeEtaMin = std::numeric_limits<MFloat>::max();
7354 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
7355 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
7356 if(m_solver->a_isHalo(cellId)) continue;
7357 if(bcNum == 2770) {
7358 if(m_solver->a_coordinate(cellId, 1)
7359 < m_ys /* + (tan(m_solver->m_angle[0] + m_sigmaShock) * m_solver->a_coordinate(cellId , 0))*/) {
7360 continue;
7361 }
7362 }
7363
7364 MFloat eta = F0;
7365 for(MInt i = 0; i < nDim; i++) {
7366 eta += m_solver->a_coordinate(cellId, i) * m_modeK[mode][i];
7367 }
7368 eta -= m_modeOmega[mode] * initTime;
7369
7370 modeEtaMin = mMin(modeEtaMin, eta);
7371 }
7372 m_modeEtaMin[mode] = modeEtaMin;
7373 // 5. communicate the etaMin
7374 MPI_Allreduce(MPI_IN_PLACE, &(m_modeEtaMin[mode]), 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
7375 "(m_modeEtaMin[mode])");
7376
7377 m_log << " modeEtaMin = " << m_modeEtaMin[mode] << endl;
7378 }
7379 m_log << " mode initialisation finished" << endl;
7380}
7381
7382
7383template <MInt nDim, class SysEqn>
7385 const MInt bcNum = m_cutOffBndryCndIds[bcId];
7386 m_log << endl << "initializing bessel modes for bcId " << bcId << endl;
7387 m_log << " running for " << bcNum << endl;
7388
7389 const MFloat time = m_solver->m_restart ? m_solver->m_time : F0;
7390
7404 m_modes = Context::propertyLength("modeType", m_solverId);
7405 mAlloc(m_modeType, m_modes, "m_modeType", 0, AT_);
7406 for(MInt i = 0; i < m_modes; i++) {
7407 m_modeType[i] = Context::getSolverProperty<MInt>("modeType", m_solverId, AT_, i);
7408 }
7409
7421 if(m_modes != Context::propertyLength("modeAmp", m_solverId)) mTerm(1, AT_, "modeAmp does not fit modeType");
7422 mAlloc(m_modeAmp, m_modes, "m_modeAmp", F0, AT_);
7423 for(MInt i = 0; i < m_modes; i++) {
7424 m_modeAmp[i] = Context::getSolverProperty<MFloat>("modeAmp", m_solverId, AT_, i);
7425 }
7426
7438 if(m_modes != Context::propertyLength("modeAngle", m_solverId)) mTerm(1, AT_, "modeAngle does not fit modeType");
7439 MFloatScratchSpace modeAngle(m_modes, AT_, "modeAngle");
7440 for(MInt i = 0; i < m_modes; i++) {
7441 modeAngle(i) = Context::getSolverProperty<MFloat>("modeAnlge", m_solverId, AT_, i) * PI / 180.0;
7442 if(bcNum == 2800 && modeAngle(i) < F0) {
7443 mTerm(1, AT_,
7444 "error in modeAngle property: correct implementation of circumferential integrals not tested for "
7445 "negative radial wave numbers, switch sign");
7446 }
7447 }
7448
7460 if(m_modes != Context::propertyLength("modeSr", m_solverId)) mTerm(1, AT_, "modeType does not fit modeSr");
7461 MFloatScratchSpace modeSr(m_modes, AT_, "modeSr");
7462 for(MInt i = 0; i < m_modes; i++) {
7463 modeSr(i) = Context::getSolverProperty<MFloat>("modeSr", m_solverId, AT_, i);
7464 }
7465
7475 if(m_modes != Context::propertyLength("nmbrOfModes", m_solverId)) mTerm(1, AT_, "nmbrOfModes does not fit modeType");
7476 mAlloc(m_nmbrOfModes, m_modes, "m_nmbrOfModes", 0, AT_);
7477 for(MInt i = 0; i < m_modes; i++) {
7478 m_nmbrOfModes[i] = Context::getSolverProperty<MInt>("nmbrOfModes", m_solverId, AT_, i);
7479 }
7480
7481 // further memberVariables
7482 mAlloc(m_modeOmega, m_modes, "m_modeOmega", F0, AT_);
7483 mAlloc(m_modeK, m_modes, 2, "m_modeK", F0, AT_);
7484 mAlloc(m_modeEtaMin, m_modes, "m_modeEtaMin", F0, AT_);
7485 // storage for the results of the circumferential integrals, +0 is pressure, +1 is radial velocity
7486 mAlloc(m_besselTrig, m_modes * 2 * m_sortedCutOffCells[bcId]->size(), "m_besselTrig", F0, AT_);
7487
7488 // time considerations
7489 MFloat initTime;
7490 if(m_solver->m_restartBc2800) {
7491 initTime = m_solver->m_restartTimeBc2800;
7492 } else {
7493 initTime = time;
7494 m_solver->m_restartTimeBc2800 = time;
7495 }
7496 m_log << "time = " << time << endl;
7497 m_log << "initTime = " << initTime << endl;
7498
7499 // fill the member variables
7500 for(MInt mode = 0; mode < m_modes; mode++) {
7501 m_log << " modeType = " << m_modeType[mode] << endl;
7502 m_log << " modeSr = " << modeSr(mode) << endl;
7503 m_log << " modeAmp = " << m_modeAmp[mode] << endl;
7504 m_log << " modeAngle = " << modeAngle(mode) << " (rad)" << endl;
7505
7506 // omega
7507 m_modeOmega[mode] = F2 * PI * modeSr(mode) * m_solver->m_VVInfinity[0] / m_solver->m_referenceLength;
7508
7509 // wave vector modeK
7510 m_modeK[mode][0] = cos(modeAngle(mode)); // axial
7511 m_modeK[mode][1] = sin(modeAngle(mode)); // radial
7512 MFloat Uk = m_solver->m_VVInfinity[0] * m_modeK[mode][0];
7513 const MFloat propVel = (MFloat)(m_modeType[mode]) * sysEqn().speedOfSound(m_solver->m_TInfinity);
7514 const MFloat K = m_modeOmega[mode] / abs(Uk + propVel);
7515 for(MInt i = 0; i < 2; i++) {
7516 m_modeK[mode][i] *= K;
7517 }
7518
7519 // output
7520 m_log << " Uk = " << Uk << endl;
7521 m_log << " modeOmega = " << m_modeOmega[mode] << endl;
7522 m_log << " K = " << K << endl;
7523 for(MInt i = 0; i < 2; i++) {
7524 m_log << " modeK[" << i << "] = " << m_modeK[mode][i] << endl;
7525 }
7526
7527 // get the min wave phase
7528 MFloat modeEtaMin = std::numeric_limits<MFloat>::max();
7529 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
7530 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
7531 if(m_solver->a_isHalo(cellId)) continue;
7532 const MFloat x = m_solver->a_coordinate(cellId, 0);
7533 const MFloat r = sqrt(POW2(m_solver->a_coordinate(cellId, 1)) + POW2(m_solver->a_coordinate(cellId, 2)));
7534
7535 const MFloat eta = x * m_modeK[mode][0] - r * m_modeK[mode][1] - m_modeOmega[mode] * initTime - PIB2;
7536
7537 modeEtaMin = mMin(modeEtaMin, eta);
7538 }
7539 // communicate the etaMin
7540 MPI_Allreduce(MPI_IN_PLACE, &modeEtaMin, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "modeEtaMin");
7541 m_modeEtaMin[mode] = modeEtaMin;
7542 m_log << " modeEtaMin = " << m_modeEtaMin[mode] << endl;
7543 }
7544 m_log << " mode initialisation finished" << endl;
7545}
7546
7547
7548template <MInt nDim, class SysEqn>
7550 TRACE();
7551 const MFloat time = m_solver->m_time;
7552 const MBool isFiltered = m_cutOffBndryCndIds[bcId] == 2800 ? true : false;
7553 const MInt noCutOffCells = m_sortedCutOffCells[bcId]->size();
7554
7555 for(MInt mode = 0; mode < m_modes; mode++) {
7556 const MFloat modeOmega = m_modeOmega[mode];
7557 const MFloat modeEtaMin = m_modeEtaMin[mode];
7558 const MFloat dphi = m_nmbrOfModes[mode] * PI;
7559
7560 for(MInt id = 0; id < noCutOffCells; id++) {
7561 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
7562
7563 // polar coords
7564 const MFloat dy = m_solver->a_coordinate(cellId, 1);
7565 const MFloat dz = m_solver->a_coordinate(cellId, 2);
7566 const MFloat r = sqrt(POW2(dy) + POW2(dz));
7567
7568 // argument
7569 const MFloat xkxmot = m_modeK[mode][0] * m_solver->a_coordinate(cellId, 0) - modeOmega * time;
7570 const MFloat rkr = r * m_modeK[mode][1];
7571
7572 const MInt offset = mode * noCutOffCells + 2 * id;
7573
7574 if(isFiltered) {
7575 calcBesselFractions(xkxmot - modeEtaMin, rkr, dphi, m_besselTrig[offset], m_besselTrig[offset + 1]);
7576 } else {
7577 m_besselTrig[offset] = cos(xkxmot) * maia::math::besselJ0(rkr);
7578 m_besselTrig[offset + 1] = cos(xkxmot + PIB2) * maia::math::besselJ1(rkr);
7579 }
7580 }
7581 }
7582}
7583
7584
7585template <MInt nDim, class SysEqn>
7587 TRACE();
7588 const MInt noCutOffCells = m_sortedCutOffCells[bcId]->size();
7589
7590 for(MInt mode = 0; mode < m_modes; mode++) {
7591 // speed of sound
7592 const MFloat a = sysEqn().speedOfSound(m_solver->m_TInfinity);
7593
7594 // 1. pressure
7595 const MFloat pressure_f = m_modeAmp[mode] * m_solver->m_PInfinity * (MFloat)(m_modeType[mode]);
7596
7597 // 2. density
7598 const MFloat density_f = m_modeType[mode] ? pressure_f / POW2(a) : m_modeAmp[mode] * m_solver->m_rhoInfinity;
7599
7600 // 3. velocity
7601 const MFloat acImp = a * m_solver->m_rhoInfinity;
7602 const MFloat velocity_f = (MFloat)(m_modeType[mode]) * pressure_f / acImp;
7603 const MFloat cosIncl = cos(atan2(m_modeK[mode][1], m_modeK[mode][0]));
7604 const MFloat sinIncl = sin(atan2(m_modeK[mode][1], m_modeK[mode][0]));
7605
7606 for(MInt id = 0; id < noCutOffCells; id++) {
7607 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
7608
7609 const MFloat phi = atan2(m_solver->a_coordinate(cellId, 1), m_solver->a_coordinate(cellId, 2));
7610
7611 const MInt offset = mode * noCutOffCells + 2 * id;
7612 const MFloat trig_P_RHO_U = m_besselTrig[offset];
7613 const MFloat trig_V_W = m_besselTrig[offset + 1];
7614
7615 // density
7616 m_solver->a_pvariable(cellId, PV->RHO) += density_f * trig_P_RHO_U;
7617
7618 // axial velocity
7619 m_solver->a_pvariable(cellId, PV->U) += velocity_f * cosIncl * trig_P_RHO_U;
7620
7621 // radial velocity
7622 const MFloat radialVelocity = velocity_f * sinIncl * trig_V_W;
7623 m_solver->a_pvariable(cellId, PV->V) += radialVelocity * sin(phi);
7624 m_solver->a_pvariable(cellId, PV->W) += radialVelocity * cos(phi);
7625
7626 // pressure
7627 m_solver->a_pvariable(cellId, PV->P) += pressure_f * trig_P_RHO_U;
7628 }
7629 }
7630}
7631
7632
7633// xkxmot already accounts for modeEtaMin
7634template <MInt nDim, class SysEqn>
7636 MFloat& trig_P_RHO_U, MFloat& trig_V_W) {
7637 TRACE();
7638 const MFloat phiMax = xkxmot + rkr;
7639 const MFloat phiMin = xkxmot - rkr;
7640 const MFloat PIB2MinusDdhi = PIB2 - dphi;
7641 // numerics
7642 const MFloat DPSI = PI / 180; // resolution in circumferential direction
7643 const MInt MINN = 10; // minimal number of integration steps
7644 const MFloat INTDEC = PIB2; // do i calc (f) or (bessel - f~)
7645 if(phiMin >= PIB2 || phiMax <= PIB2MinusDdhi) {
7646 // rkr*cos(\hat{psi}) is not inside the kxmowt range
7647 trig_V_W = F0;
7648 trig_P_RHO_U = F0;
7649 } else if(phiMin >= PIB2MinusDdhi && phiMax <= PIB2) {
7650 // rkr*cos(\hat{psi}) is completely inside the kxmowt range
7651 trig_V_W = cos(xkxmot + PIB2) * maia::math::besselJ1(rkr);
7652 trig_P_RHO_U = cos(xkxmot) * maia::math::besselJ0(rkr);
7653 } else if(phiMin < PIB2MinusDdhi && phiMax > PIB2) {
7654 // rkr*cos(\hat{psi}) extends both limits of the kxmowt range
7655 const MFloat psihatmax = acos((PIB2 - xkxmot) / rkr);
7656 const MFloat psihatmin = acos((PIB2MinusDdhi - xkxmot) / rkr);
7657 if(psihatmin - psihatmax < INTDEC) {
7658 // from first intersection at psihatmax to second intersection at psihatmin
7659 const MInt noSeg = mMax((MInt)ceil((psihatmin - psihatmax) / DPSI), MINN);
7660 const MFloat dpsi = (psihatmin - psihatmax) / noSeg;
7661 MFloat firstValB1 = F0;
7662 MFloat resultB1 = F0;
7663 MFloat firstValB2 = F0;
7664 MFloat resultB2 = F0;
7665 for(MInt cnt = 1; cnt <= noSeg; cnt++) {
7666 const MFloat secondValB1 = maia::math::lincos(xkxmot + rkr * maia::math::lincos(psihatmax + cnt * dpsi));
7667 const MFloat secondValB2 = maia::math::lincos(psihatmax + cnt * dpsi) * secondValB1;
7668 resultB1 += F1B2 * (firstValB1 + secondValB1) * dpsi;
7669 resultB2 += F1B2 * (firstValB2 + secondValB2) * dpsi;
7670 firstValB1 = secondValB1;
7671 firstValB2 = secondValB2;
7672 }
7673 trig_P_RHO_U = resultB1 / PI;
7674 trig_V_W = resultB2 / PI;
7675 } else {
7676 // from zero to first intersection at psihatmax
7677 const MInt noSeg1 = mMax((MInt)ceil(psihatmax / DPSI), MINN);
7678 const MFloat dpsi1 = psihatmax / noSeg1;
7679 MFloat firstValB1 = maia::math::lincos(phiMax);
7680 MFloat firstValB2 = maia::math::lincos(phiMax);
7681 MFloat resultB1 = F0;
7682 MFloat resultB2 = F0;
7683 for(MInt cnt = 1; cnt <= noSeg1; cnt++) {
7684 const MFloat secondValB1 = maia::math::lincos(xkxmot + rkr * maia::math::lincos(cnt * dpsi1));
7685 const MFloat secondValB2 = maia::math::lincos(cnt * dpsi1) * secondValB1;
7686 resultB1 += F1B2 * (firstValB1 + secondValB1) * dpsi1;
7687 resultB2 += F1B2 * (firstValB2 + secondValB2) * dpsi1;
7688 firstValB1 = secondValB1;
7689 firstValB2 = secondValB2;
7690 }
7691 // from second intersection at psihatmin to PI
7692 const MInt noSeg2 = mMax((MInt)ceil((PI - psihatmin) / DPSI), MINN);
7693 const MFloat dpsi2 = (PI - psihatmin) / noSeg2;
7694 firstValB1 = F0;
7695 firstValB2 = F0;
7696 for(MInt cnt = 1; cnt <= noSeg2; cnt++) {
7697 const MFloat secondValB1 = maia::math::lincos(xkxmot + rkr * maia::math::lincos(psihatmin + cnt * dpsi2));
7698 const MFloat secondValB2 = maia::math::lincos(psihatmin + cnt * dpsi2) * secondValB1;
7699 resultB1 += F1B2 * (firstValB1 + secondValB1) * dpsi2;
7700 resultB2 += F1B2 * (firstValB2 + secondValB2) * dpsi2;
7701 firstValB1 = secondValB1;
7702 firstValB2 = secondValB2;
7703 }
7704 trig_P_RHO_U = cos(xkxmot) * maia::math::besselJ0(rkr) - resultB1 / PI;
7705 trig_V_W = cos(xkxmot + PIB2) * maia::math::besselJ1(rkr) - resultB2 / PI;
7706 }
7707 } else {
7708 // rkr*cos(\hat{psi}) extends at least one limit of the kxmowt range, the other one might be on the limit
7709 const MFloat psihatintersec = acos((((phiMax > PIB2) ? PIB2 : PIB2MinusDdhi) - xkxmot) / rkr);
7710 if(psihatintersec < INTDEC) {
7711 // from zero to intersection
7712 const MInt noSeg = mMax((MInt)ceil(psihatintersec / DPSI), MINN);
7713 const MFloat dpsi = psihatintersec / noSeg;
7714 MFloat firstValB1 = maia::math::lincos(phiMax);
7715 MFloat firstValB2 = maia::math::lincos(phiMax);
7716 MFloat resultB1 = F0;
7717 MFloat resultB2 = F0;
7718 for(MInt cnt = 1; cnt <= noSeg; cnt++) {
7719 const MFloat secondValB1 = maia::math::lincos(xkxmot + rkr * maia::math::lincos(cnt * dpsi));
7720 const MFloat secondValB2 = maia::math::lincos(cnt * dpsi) * secondValB1;
7721 resultB1 += F1B2 * (firstValB1 + secondValB1) * dpsi;
7722 resultB2 += F1B2 * (firstValB2 + secondValB2) * dpsi;
7723 firstValB1 = secondValB1;
7724 firstValB2 = secondValB2;
7725 }
7726 if(phiMax > PIB2) {
7727 trig_P_RHO_U = cos(xkxmot) * maia::math::besselJ0(rkr) - resultB1 / PI;
7728 trig_V_W = cos(xkxmot + PIB2) * maia::math::besselJ1(rkr) - resultB2 / PI;
7729 } else {
7730 trig_P_RHO_U = resultB1 / PI;
7731 trig_V_W = resultB2 / PI;
7732 }
7733 } else {
7734 // from intersection to PI
7735 const MInt noSeg = mMax((MInt)ceil((PI - psihatintersec) / DPSI), MINN);
7736 const MFloat dpsi = (PI - psihatintersec) / noSeg;
7737 MFloat firstValB1 = F0;
7738 MFloat firstValB2 = F0;
7739 MFloat resultB1 = F0;
7740 MFloat resultB2 = F0;
7741 for(MInt cnt = 1; cnt <= noSeg; cnt++) {
7742 const MFloat secondValB1 = maia::math::lincos(xkxmot + rkr * maia::math::lincos(psihatintersec + cnt * dpsi));
7743 const MFloat secondValB2 = maia::math::lincos(psihatintersec + cnt * dpsi) * secondValB1;
7744 resultB1 += F1B2 * (firstValB1 + secondValB1) * dpsi;
7745 resultB2 += F1B2 * (firstValB2 + secondValB2) * dpsi;
7746 firstValB1 = secondValB1;
7747 firstValB2 = secondValB2;
7748 }
7749 if(phiMax > PIB2) {
7750 trig_P_RHO_U = resultB1 / PI;
7751 trig_V_W = resultB2 / PI;
7752 } else {
7753 trig_P_RHO_U = cos(xkxmot) * maia::math::besselJ0(rkr) - resultB1 / PI;
7754 trig_V_W = cos(xkxmot + PIB2) * maia::math::besselJ1(rkr) - resultB2 / PI;
7755 }
7756 }
7757 }
7758}
7759
7760
7761template <MInt nDim, class SysEqn>
7763 TRACE();
7764
7765 MInt noCells = m_bndryCells->size();
7766
7767 // check boundary cell volumes
7768 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
7769 if(m_bndryCells->a[bndryId].m_volume <= 0) {
7770 cerr << "Cell " << m_bndryCells->a[bndryId].m_cellId << " at level "
7771 << m_solver->a_level(m_bndryCells->a[bndryId].m_cellId) << " has volume "
7772 << m_bndryCells->a[bndryId].m_volume << endl;
7773 cerr << "Cut points of cell " << m_bndryCells->a[bndryId].m_cellId << ":" << endl;
7774 for(MInt point = 0; point < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; point++) {
7775 for(MInt i = 0; i < nDim; i++) {
7776 cerr << point << " x" << i << " " << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[point][i] << endl;
7777 }
7778 }
7779 }
7780 /*
7781 if( m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints != 2 ) {
7782 cerr << "Cell "
7783 << m_bndryCells->a[ bndryId ].m_cellId
7784 << " at level "
7785 << m_solver->a_level( m_bndryCells->a[ bndryId ].m_cellId )
7786 << " does not have 2 cut points " << endl;
7787 }
7788 //check neighbors
7789 MInt counter = 0;
7790 for( MInt dirId = 0; dirId < 2*nDim; dirId++ ) {
7791 if( m_bndryCells->a[ bndryId ].m_noNghbrIds[ dirId ] > 0 ) {
7792 counter += m_bndryCells->a[ bndryId ].m_noNghbrIds[ dirId ];
7793 }
7794 }
7795 MInt bndryIdNghbr;
7796 if( counter < 2 || counter > 3 ) {
7797 cerr << "At level (direction 0) " << m_solver->a_level( m_bndryCells->a[ bndryId ].m_cellId ) << endl;
7798 cerr << "Number of boundary cell neighbors of " << m_bndryCells->a[ bndryId ].m_cellId << ": " << counter << endl;
7799 cerr << m_solver->a_coordinate( m_bndryCells->a[ bndryId ].m_cellId , 0 ) << " "
7800 << m_solver->a_coordinate( m_bndryCells->a[ bndryId ].m_cellId , 1 ) << " "
7801 << m_solver->c_cellLengthAtCell(m_bndryCells->a[ bndryId ].m_cellId ) << endl;
7802 cerr << "Number of cut points " << m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints << endl;
7803 for( MInt i = 0; i < m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints; i++ ) {
7804 cerr << m_bndryCells->a[ bndryId ].m_srfcs[0]->m_cutCoordinates[ i ][ 0 ] << " "
7805 << m_bndryCells->a[ bndryId ].m_srfcs[0]->m_cutCoordinates[ i ][ 1 ] << endl;
7806 }
7807 cerr << "Boundary cell neighbor information:" << endl;
7808 for( MInt dirId = 0; dirId < m_noDirs; dirId++ ) {
7809 if( m_bndryCells->a[ bndryId ].m_noNghbrIds[ dirId ] > 0 ) {
7810 cerr << "+++++" << endl;
7811 cerr << "Neighbor in " << dirId << " direction..." << endl;
7812 bndryIdNghbr = m_bndryCells->a[ bndryId ].m_nghbrIds[ dirId ][ 0 ];
7813 cerr << "...at level (direction 0) " << m_solver->a_level( m_bndryCells->a[ bndryIdNghbr ].m_cellId ) << endl;
7814 cerr << m_solver->a_coordinate( m_bndryCells->a[ bndryIdNghbr ].m_cellId , 0 ) << " "
7815 << m_solver->a_coordinate( m_bndryCells->a[ bndryIdNghbr ].m_cellId , 1 ) << " "
7816 << m_solver->c_cellLengthAtCell( m_bndryCells->a[ bndryIdNghbr ].m_cellId )]) << endl;
7817 cerr << "Number of cut points " << m_bndryCells->a[ bndryIdNghbr ].m_srfcs[0]->m_noCutPoints << endl;
7818 for( MInt i = 0; i < m_bndryCells->a[ bndryIdNghbr ].m_srfcs[0]->m_noCutPoints; i++ ) {
7819 cerr << m_bndryCells->a[ bndryIdNghbr ].m_srfcs[0]->m_cutCoordinates[ i ][ 0 ] << " "
7820 << m_bndryCells->a[ bndryIdNghbr ].m_srfcs[0]->m_cutCoordinates[ i ][ 1 ] << endl;
7821 }
7822 cerr << endl;
7823 }
7824 cerr << "+++++" << endl;
7825 }
7826 cerr << "-------------------------------" << endl;
7827 }
7828 */
7829 }
7830 // cout << "*** all boundary cells checked ***" << endl;
7831}
7832
7833
7850template <MInt nDim, class SysEqn>
7852 TRACE();
7853
7854 MInt noCells = m_bndryCells->size();
7855 MInt counter;
7856 MInt countChained;
7857 MInt formerMasterBnd;
7858 MInt cellId;
7859 MInt nghbrId;
7860 MInt count1;
7861 MInt count2;
7862 MInt primaryDirection = 0;
7863 MFloat maxComponent;
7864 MBool wall = false;
7865 //---
7866
7867 // reset collector of small cells
7868 m_smallBndryCells->setSize(0);
7869
7870 m_log << "Small cell treatment " << endl;
7871 m_log << "using " << m_volumeLimitWall << " " << m_volumeLimitOther << endl;
7872
7873 counter = 0;
7874 // set small cell flag
7875 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
7876 m_solver->a_slope(bndryId, 0, 0) = (MFloat) false;
7877 m_solver->a_slope(bndryId, 0, 1) = (MFloat) false;
7878 cellId = m_bndryCell[bndryId].m_cellId;
7879 wall = false;
7880 for(MInt srfcId = 0; srfcId < m_bndryCells->a[m_solver->a_bndryId(cellId)].m_noSrfcs; srfcId++) {
7881 if(m_bndryCell[bndryId].m_srfcs[srfcId]->m_bndryCndId / 1000 == 3) {
7882 wall = true;
7883 break;
7884 }
7885 }
7886 if(wall) {
7887 if(m_bndryCell[bndryId].m_volume / m_solver->grid().gridCellVolume(m_solver->a_level(cellId))
7888 < m_volumeLimitWall) {
7889 m_solver->a_slope(bndryId, 0, 0) = (MFloat) true;
7890 m_bndryCell[bndryId].m_linkedCellId = cellId;
7891 counter++;
7892 }
7893 } else {
7894 if(m_bndryCell[bndryId].m_volume / m_solver->grid().gridCellVolume(m_solver->a_level(cellId))
7895 < m_volumeLimitOther) {
7896 m_solver->a_slope(bndryId, 0, 0) = (MFloat) true;
7897 m_bndryCell[bndryId].m_linkedCellId = cellId;
7898 counter++;
7899 }
7900 }
7901 }
7902
7903 // check for potential master cells
7904 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
7905 m_solver->a_slope(bndryId, 1, 0) = (MFloat)(-1);
7906 m_solver->a_slope(bndryId, 1, 1) = (MFloat)(-1);
7907 if((MInt)m_solver->a_slope(bndryId, 0, 0)) {
7908 // set primary direction
7909 maxComponent = F0;
7910 for(MInt i = 0; i < nDim; i++) {
7911 if(fabs(m_bndryCell[bndryId].m_srfcs[0]->m_normalVector[i]) > maxComponent) {
7912 maxComponent = fabs(m_bndryCell[bndryId].m_srfcs[0]->m_normalVector[i]);
7913 if(m_bndryCell[bndryId].m_srfcs[0]->m_normalVector[i] < F0) {
7914 primaryDirection = 2 * i;
7915 } else {
7916 primaryDirection = 2 * i + 1;
7917 }
7918 }
7919 }
7920 //
7921 cellId = m_bndryCell[bndryId].m_cellId;
7922 if(m_solver->a_hasNeighbor(cellId, primaryDirection) > 0) {
7923 nghbrId = m_solver->c_neighborId(cellId, primaryDirection);
7924 if(m_solver->a_bndryId(nghbrId) > -1) {
7925 m_solver->a_slope(bndryId, 1, 1) = (MFloat)nghbrId;
7926 } else {
7927 m_solver->a_slope(bndryId, 1, 0) = (MFloat)nghbrId;
7928 }
7929 }
7930 }
7931 }
7932
7933 m_log << "Small cell treatment..." << endl;
7934 m_log << counter << " small cells to link" << endl;
7935
7936 count1 = 0;
7937 count2 = 0;
7938 countChained = 0;
7939
7940 // 1. connect small cells to internal master cells
7941 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
7942 if(!(MInt)m_solver->a_slope(bndryId, 0, 0)) continue;
7943 if((MInt)m_solver->a_slope(bndryId, 1, 0) == -1) continue;
7944 m_bndryCell[bndryId].m_linkedCellId = (MInt)m_solver->a_slope(bndryId, 1, 0);
7945 m_solver->a_slope(bndryId, 0, 1) = (MFloat) true;
7946 counter--;
7947 count1++;
7948 }
7949
7950 // 2. connect all small cells with at least one possible master cell
7951 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
7952 if(!(MInt)m_solver->a_slope(bndryId, 0, 0)) continue;
7953 if((MInt)m_solver->a_slope(bndryId, 0, 1)) continue;
7954 if((MInt)m_solver->a_slope(bndryId, 1, 1) == -1) continue;
7955 m_bndryCell[bndryId].m_linkedCellId = (MInt)m_solver->a_slope(bndryId, 1, 1);
7956 m_solver->a_slope(bndryId, 0, 1) = (MFloat) true;
7957 counter--;
7958 count2++;
7959 }
7960
7961 // 3. connect small cells the master of which is also a small cell to the master's master
7962 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
7963 if(!(MInt)m_solver->a_slope(bndryId, 0, 0)) continue;
7964 if(!(MInt)m_solver->a_slope(bndryId, 0, 1)) continue;
7965 if(m_solver->a_bndryId(m_bndryCell[bndryId].m_linkedCellId) == -1) continue;
7966 if(!(MInt)m_solver->a_slope(m_solver->a_bndryId(m_bndryCell[bndryId].m_linkedCellId), 0, 0)) continue;
7967 formerMasterBnd = m_solver->a_bndryId(m_bndryCell[bndryId].m_linkedCellId);
7968 m_bndryCell[bndryId].m_linkedCellId = m_bndryCell[formerMasterBnd].m_linkedCellId;
7969 countChained++;
7970 }
7971
7972 m_log << "Master cell statistics: " << endl;
7973 m_log << "__________________________________" << endl << endl;
7974 m_log << " * links to internal cells " << count1 << endl;
7975 m_log << " * links to boundary cells " << count2 << endl;
7976 m_log << " * chained links " << countChained << endl;
7977 m_log << "__________________________________" << endl;
7978
7979 // create small cells
7980 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
7981 if((MInt)m_solver->a_slope(bndryId, 0, 0) && (MInt)m_solver->a_slope(bndryId, 0, 1)) {
7982 m_smallBndryCells->append();
7983 m_smallBndryCells->a[m_smallBndryCells->size() - 1] = bndryId;
7984 }
7985 }
7986
7987 // fill the lists smallCellIds and masterCellIds
7988 noCells = m_smallBndryCells->size();
7989 for(MInt s = 0; s < noCells; s++) {
7990 m_solver->m_smallCellIds[s] = m_bndryCell[m_smallBndryCells->a[s]].m_cellId;
7991 m_solver->m_masterCellIds[s] = m_bndryCell[m_smallBndryCells->a[s]].m_linkedCellId;
7992 }
7993}
7994
7995
8016template <MInt nDim, class SysEqn>
8018 TRACE();
8019
8020 MInt noCells = m_bndryCells->size();
8021 MInt counter;
8022 MInt countChained;
8023 MInt cellId;
8024 MInt nghbrId;
8025 MInt count1;
8026 MInt count2;
8027 MInt primaryDirection = -1;
8028 MInt secondaryDirection = -1;
8029 MInt thirdDirection = -1;
8030 MFloat maxComponent;
8031 MBool wall = false;
8032 MInt srfc;
8033 MBool MGCPreferWallBoundaries = false;
8034 // claudia Achtung neu - alte claudia Testfaelle anpassen!
8035 // TINA_TC: MGC_preferWallBoundaries = true;
8036 // SUZI_TC: MGC_preferWallBoundaries = false;
8037
8048 MGCPreferWallBoundaries =
8049 Context::getSolverProperty<MBool>("MGC_preferWallBoundaries", m_solverId, AT_, &MGCPreferWallBoundaries);
8050 //---
8051
8052 // reset collector of small cells
8053 m_smallBndryCells->setSize(0);
8054
8055 m_log << "Small cell treatment " << endl;
8056 m_log << "using " << m_volumeLimitWall << " " << m_volumeLimitOther << endl;
8057
8058 counter = 0;
8059 // set small cell flag
8060 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8061 m_solver->a_slope(bndryId, 0, 0) = (MFloat) false;
8062 m_solver->a_slope(bndryId, 0, 1) = (MFloat) false;
8063 m_solver->a_slope(bndryId, 2, 0) = (MFloat)(-1);
8064 m_solver->a_slope(bndryId, 2, 1) = (MFloat) false;
8065 cellId = m_bndryCell[bndryId].m_cellId;
8066 m_bndryCell[bndryId].m_linkedCellId = -1;
8067 wall = false;
8068 for(MInt srfcId = 0; srfcId < m_bndryCells->a[m_solver->a_bndryId(cellId)].m_noSrfcs; srfcId++) {
8069 if(m_bndryCell[bndryId].m_srfcs[srfcId]->m_bndryCndId >= 3000
8070 && m_bndryCell[bndryId].m_srfcs[srfcId]->m_bndryCndId < 4000) {
8071 wall = true;
8072 break;
8073 }
8074 }
8075 if(m_solver->c_noChildren(cellId) > 0) continue;
8076 if(wall) {
8077 if(m_bndryCell[bndryId].m_volume / m_solver->grid().gridCellVolume(m_solver->a_level(cellId))
8078 < m_volumeLimitWall) {
8079 m_solver->a_slope(bndryId, 0, 0) = (MFloat) true;
8080 m_bndryCell[bndryId].m_linkedCellId = cellId;
8081 counter++;
8082 }
8083 } else {
8084 if(m_bndryCell[bndryId].m_volume / m_solver->grid().gridCellVolume(m_solver->a_level(cellId))
8085 < m_volumeLimitOther) {
8086 m_solver->a_slope(bndryId, 0, 0) = (MFloat) true;
8087 m_bndryCell[bndryId].m_linkedCellId = cellId;
8088 counter++;
8089 }
8090 }
8091 }
8092
8093 // check for potential master cells
8094 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8095 m_solver->a_slope(bndryId, 1, 0) = (MFloat)(-1);
8096 m_solver->a_slope(bndryId, 1, 1) = (MFloat)(-1);
8097 if((MInt)m_solver->a_slope(bndryId, 0, 0)) {
8098 srfc = 0;
8099 // if there is a prefered boundary surface on which the search for the master cell should be based, take this one
8100 for(MInt srfcId = 0; srfcId < m_bndryCells->a[bndryId].m_noSrfcs; srfcId++) {
8101 // prefer wall boundaries
8102 if(m_bndryCells->a[bndryId].m_srfcs[srfcId]->m_bndryCndId == 3003
8103 || m_bndryCells->a[bndryId].m_srfcs[srfcId]->m_bndryCndId == 3005) {
8104 srfc = srfcId;
8105 if(MGCPreferWallBoundaries) break;
8106 } else if(!MGCPreferWallBoundaries) {
8107 srfc = srfcId;
8108 break;
8109 }
8110 }
8111
8112 // set primary direction
8113 maxComponent = F0;
8114 primaryDirection = -1;
8115 for(MInt i = 0; i < nDim; i++) {
8116 if(fabs(m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVector[i]) > maxComponent) {
8117 maxComponent = fabs(m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVector[i]);
8118 thirdDirection = secondaryDirection;
8119 secondaryDirection = primaryDirection;
8120 if(m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVector[i] < F0) {
8121 primaryDirection = 2 * i;
8122 } else {
8123 primaryDirection = 2 * i + 1;
8124 }
8125 }
8126 }
8127 cellId = m_bndryCell[bndryId].m_cellId;
8128 // only valid for 3D...
8129 m_solver->a_slope(bndryId, 3, 0) = -1; // primary master
8130 m_solver->a_slope(bndryId, 3, 1) = -1; // secondary master
8131 m_solver->a_slope(bndryId, 3, 2) = -1; // third master
8132 if(primaryDirection > -1
8133 && m_solver->m_identNghbrIds[cellId * m_noDirs + primaryDirection]
8134 < m_solver->m_identNghbrIds[cellId * m_noDirs + primaryDirection + 1]) {
8135 nghbrId = m_solver->m_storeNghbrIds[m_solver->m_identNghbrIds[cellId * m_noDirs + primaryDirection]];
8136 m_solver->a_slope(bndryId, 3, 0) = (MFloat)nghbrId;
8137 }
8138 if(secondaryDirection > -1
8139 && m_solver->m_identNghbrIds[cellId * m_noDirs + secondaryDirection]
8140 < m_solver->m_identNghbrIds[cellId * m_noDirs + secondaryDirection + 1]) {
8141 nghbrId = m_solver->m_storeNghbrIds[m_solver->m_identNghbrIds[cellId * m_noDirs + secondaryDirection]];
8142 m_solver->a_slope(bndryId, 3, 1) = (MFloat)nghbrId;
8143 }
8144 if(thirdDirection > -1
8145 && m_solver->m_identNghbrIds[cellId * m_noDirs + thirdDirection]
8146 < m_solver->m_identNghbrIds[cellId * m_noDirs + thirdDirection + 1]) {
8147 nghbrId = m_solver->m_storeNghbrIds[m_solver->m_identNghbrIds[cellId * m_noDirs + thirdDirection]];
8148 m_solver->a_slope(bndryId, 3, 2) = (MFloat)nghbrId;
8149 }
8150
8151 nghbrId = m_solver->a_slope(bndryId, 3, 0);
8152 if(nghbrId > -1) {
8153 if(m_solver->a_bndryId(nghbrId) > -1) {
8154 m_solver->a_slope(bndryId, 1, 1) = (MFloat)nghbrId;
8155 } else {
8156 m_solver->a_slope(bndryId, 1, 0) = (MFloat)nghbrId;
8157 }
8158 } else {
8159 nghbrId = m_solver->a_slope(bndryId, 3, 1);
8160 if(nghbrId > -1) {
8161 if(m_solver->a_bndryId(nghbrId) > -1) {
8162 m_solver->a_slope(bndryId, 1, 1) = (MFloat)nghbrId;
8163 } else {
8164 m_solver->a_slope(bndryId, 1, 0) = (MFloat)nghbrId;
8165 }
8166 } else {
8167 nghbrId = m_solver->a_slope(bndryId, 3, 2);
8168 if(nghbrId > -1) {
8169 if(m_solver->a_bndryId(nghbrId) > -1) {
8170 m_solver->a_slope(bndryId, 1, 1) = (MFloat)nghbrId;
8171 } else {
8172 m_solver->a_slope(bndryId, 1, 0) = (MFloat)nghbrId;
8173 }
8174 } else {
8175 cerr << " " << domainId() << " " << cellId << " " << primaryDirection << " " << m_solver->c_parentId(cellId)
8176 << " " << m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId << endl;
8177 cerr << "Coordinates: " << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1)
8178 << " " << m_solver->a_coordinate(cellId, 2) << endl;
8179 cerr << "Normal vector: " << m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVector[0] << " "
8180 << m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVector[1] << " "
8181 << m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVector[2] << endl;
8182 cerr << m_solver->a_hasNeighbor(cellId, 0) << " " << m_solver->a_hasNeighbor(cellId, 1) << " "
8183 << m_solver->a_hasNeighbor(cellId, 2) << " " << m_solver->a_hasNeighbor(cellId, 3) << " ";
8184 IF_CONSTEXPR(nDim == 3) {
8185 cerr << m_solver->a_hasNeighbor(cellId, 4) << " " << m_solver->a_hasNeighbor(cellId, 5) << endl;
8186 }
8187 else cerr << endl;
8188 cerr << m_solver->c_neighborId(cellId, 0) << " " << m_solver->c_neighborId(cellId, 1) << " "
8189 << m_solver->c_neighborId(cellId, 2) << " " << m_solver->c_neighborId(cellId, 3) << " ";
8190 IF_CONSTEXPR(nDim == 3) {
8191 cerr << m_solver->c_neighborId(cellId, 4) << " " << m_solver->c_neighborId(cellId, 5) << endl;
8192 }
8193 else cerr << endl;
8194 cerr << "[" << domainId() << "]: Error in small cell treatment: No neighbor in any direction" << endl;
8195 if(m_solver->a_isHalo(cellId)) {
8196 m_solver->a_hasProperty(cellId, SolverCell::IsDummy) = true;
8197 m_solver->a_isBndryGhostCell(cellId) = false;
8198 m_solver->a_hasProperty(cellId, SolverCell::IsInterface) = false;
8199 m_solver->a_isPeriodic(cellId) = false;
8200 m_solver->a_hasProperty(cellId, SolverCell::IsCutOff) = false;
8201 m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) = true;
8202 m_solver->a_hasProperty(cellId, SolverCell::IsFlux) = false;
8203 m_solver->a_hasProperty(cellId, SolverCell::IsActive) = false;
8204 m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
8205 m_solver->a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = false;
8206 m_solver->a_slope(bndryId, 0, 0) = (MFloat) false;
8207 cerr << " cell inactive"
8208 << ", cellId: " << cellId << endl;
8209
8210 // this deletes all relations of the cell with neighbors, parents etc. but the cell itself remains in the
8211 // collector to prevent inconsistencies
8212 // Timw: deleting the cell is not allowed in the multisolver-concept!
8213 // m_solver->grid().deleteCell_MGC( cellId );
8214 m_solver->a_level(cellId) = -1;
8215 } else {
8216 cerr << "cell is no multi solver halo cell! " << endl;
8217 }
8218 }
8219 }
8220 }
8221 }
8222 }
8223
8224 m_log << "Small cell treatment..." << endl;
8225 m_log << counter << " small cells to link" << endl;
8226
8227 MInt invalidCounter = 0;
8228 stringstream filename;
8229
8230
8231 // 0. perform a check of the cells to be linked. Filter out invalid cells and check if any cell has an invalid cell as
8232 // potential master cell
8233 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8234 cellId = m_bndryCell[bndryId].m_cellId;
8235 if(!(MInt)m_solver->a_slope(bndryId, 0, 0)) continue;
8236 if(m_solver->a_hasProperty(cellId, SolverCell::IsInvalid)) {
8237 invalidCounter++;
8238 cerr << " found invalid small cell. Please check! CellId is " << cellId << " bndryId is " << bndryId
8239 << " counter is " << invalidCounter << ". Cell is no set to be non-small." << endl;
8240 filename.str("");
8241 filename << cellId << "_invalidSmall.stl";
8242
8243 m_solver->a_slope(bndryId, 0, 0) = (MFloat) false;
8244 }
8245 if((MInt)m_solver->a_slope(bndryId, 1, 0) > -1) {
8246 if(m_solver->a_hasProperty((MInt)m_solver->a_slope(bndryId, 1, 0), SolverCell::IsInvalid)) {
8247 cerr << " found small cell with invalid internal master. Please check! CellId is " << cellId << " bndryId is "
8248 << bndryId << ", master is " << (MInt)m_solver->a_slope(bndryId, 1, 0)
8249 << ". Cell is no set to be non-small." << endl;
8250 filename.str("");
8251 filename << cellId << "_smallInvalidMaster.stl";
8252 filename.str("");
8253 filename << (MInt)m_solver->a_slope(bndryId, 1, 0) << "_invalidMaster.stl";
8254
8255 m_solver->a_slope(bndryId, 0, 0) = (MFloat) false;
8256 }
8257 } else {
8258 if((MInt)m_solver->a_slope(bndryId, 1, 1) == -1) {
8259 cerr << " found small cell with no master. Please check! CellId is " << cellId << " bndryId is " << bndryId
8260 << ". Cell is no set to be non-small." << endl;
8261 filename.str("");
8262 filename << cellId << "_smallNoMaster.stl";
8263
8264 m_solver->a_slope(bndryId, 0, 0) = (MFloat) false;
8265 } else {
8266 if(m_solver->a_hasProperty((MInt)m_solver->a_slope(bndryId, 1, 1), SolverCell::IsInvalid)) {
8267 cerr << " found small cell with invalid bndry master. Please check! CellId is " << cellId << " bndryId is "
8268 << bndryId << ", master is " << (MInt)m_solver->a_slope(bndryId, 1, 1)
8269 << ". Cell is no set to be non-small." << endl;
8270 filename.str("");
8271 filename << cellId << "_smallInvalidMaster.stl";
8272 filename.str("");
8273 filename << (MInt)m_solver->a_slope(bndryId, 1, 1) << "_invalidMaster.stl";
8274
8275 m_solver->a_slope(bndryId, 0, 0) = (MFloat) false;
8276 }
8277 }
8278 }
8279 }
8280
8281
8282 count1 = 0;
8283 count2 = 0;
8284 countChained = 0;
8285 MInt countBigCluster = 0;
8286 MInt countSpecialcluster = 0;
8287 MInt master = -1;
8288 MInt masterBndryId = -1;
8289
8290 // 1. connect small cells to internal master cells -> direct connection
8291 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8292 cellId = m_bndryCell[bndryId].m_cellId;
8293 if(!(MInt)m_solver->a_slope(bndryId, 0, 0)) continue;
8294 if((MInt)m_solver->a_slope(bndryId, 1, 0) == -1) continue;
8295 m_bndryCell[bndryId].m_linkedCellId = (MInt)m_solver->a_slope(bndryId, 1, 0);
8296 m_solver->a_slope(bndryId, 0, 1) = (MFloat) true;
8297 count1++;
8298 }
8299
8300 // 2. connect remaining small cells which have a big boundary cell as master -> direct connection, first round
8301 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8302 if(!(MInt)m_solver->a_slope(bndryId, 0, 0)) continue;
8303 if((MInt)m_solver->a_slope(bndryId, 0, 1)) continue;
8304 if((MInt)m_solver->a_slope(bndryId, 1, 1) == -1) continue;
8305
8306 master = (MInt)m_solver->a_slope(bndryId, 1, 1);
8307 masterBndryId = m_solver->a_bndryId(master);
8308 // only connect to big cells
8309 if((MInt)m_solver->a_slope(masterBndryId, 0, 0)) continue;
8310
8311 m_bndryCell[bndryId].m_linkedCellId = master;
8312 m_solver->a_slope(bndryId, 0, 1) = (MFloat) true;
8313 count2++;
8314 }
8315
8316 // 3. connect remaining small cells with a small master to the masters master, if the small master is aleady tagged as
8317 // OK. Repeat until no cell with OK master remains with the OK tag
8318 MBool reconnected = true;
8319 while(reconnected) {
8320 reconnected = false;
8321 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8322 if(!(MInt)m_solver->a_slope(bndryId, 0, 0)) continue;
8323 if((MInt)m_solver->a_slope(bndryId, 0, 1)) continue;
8324 if((MInt)m_solver->a_slope(bndryId, 1, 1) == -1) continue;
8325
8326 master = (MInt)m_solver->a_slope(bndryId, 1, 1);
8327 masterBndryId = m_solver->a_bndryId(master);
8328 // only connect to OK cells
8329 if((MInt)m_solver->a_slope(masterBndryId, 0, 0)) {
8330 if((MInt)m_solver->a_slope(masterBndryId, 0, 1)) {
8331 m_bndryCell[bndryId].m_linkedCellId = m_bndryCell[masterBndryId].m_linkedCellId;
8332 m_solver->a_slope(bndryId, 0, 1) = (MFloat) true;
8333 countChained++;
8334 reconnected = true;
8335 }
8336 }
8337 }
8338 }
8339
8340
8341 // Now, only problematic small cells are left which would lead to infinity chains if treated as usual
8342 // 4. Identify clusters of connected small cells and give them a cluster number
8343 // collect all small cells belonging to one cluster in an array
8344 stack<MInt> clusterStack;
8345 MInt startCellId = -1;
8346 MInt currentCell = -1;
8347 MInt clusterColor = -1;
8348 MInt nghbrBndryId = -1;
8349 MIntScratchSpace clusterCells(counter, AT_, "clusterCells");
8350 MIntScratchSpace clusterCounter(counter / 2, AT_, "clusterCounter");
8351 MIntScratchSpace clusterFinished(counter / 2, AT_, "clusterFinished");
8352 MInt noClusterCells = 0;
8353 MInt checkMasterId;
8354 MBool changedColor = true;
8355 MInt checkMasterBndryId;
8356 MBool masterGrey;
8357 for(MInt i = 0; i < (MInt)counter / 2; i++) {
8358 clusterCounter[i] = 0;
8359 clusterFinished[i] = 0;
8360 }
8361
8362 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8363 if(!(MInt)m_solver->a_slope(bndryId, 0, 0)) continue;
8364 if((MInt)m_solver->a_slope(bndryId, 0, 1)) continue;
8365 if((MInt)m_solver->a_slope(bndryId, 2, 0) > -1) continue;
8366 startCellId = bndryId;
8367 checkMasterBndryId = startCellId;
8368 clusterColor++;
8369 m_solver->a_slope(startCellId, 2, 0) = (MFloat)clusterColor;
8370 clusterCells[noClusterCells++] = startCellId;
8371 clusterCounter[clusterColor]++;
8372 masterGrey = true;
8373 while(masterGrey) {
8374 checkMasterId = (MInt)m_solver->a_slope(checkMasterBndryId, 1, 1);
8375 checkMasterBndryId = m_solver->a_bndryId(checkMasterId);
8376 if((MInt)m_solver->a_slope(checkMasterBndryId, 2, 0) < 0) {
8377 m_solver->a_slope(checkMasterBndryId, 2, 0) = (MFloat)clusterColor;
8378 clusterCells[noClusterCells++] = checkMasterBndryId;
8379 clusterCounter[clusterColor]++;
8380 } else {
8381 masterGrey = false;
8382 }
8383 }
8384 changedColor = true;
8385 while(changedColor) {
8386 changedColor = false;
8387 for(MInt checkBndryId = 0; checkBndryId < noCells; checkBndryId++) {
8388 if(!(MInt)m_solver->a_slope(checkBndryId, 0, 0)) continue;
8389 if((MInt)m_solver->a_slope(checkBndryId, 0, 1)) continue;
8390 if((MInt)m_solver->a_slope(checkBndryId, 2, 0) > -1) continue;
8391 checkMasterId = (MInt)m_solver->a_slope(checkBndryId, 1, 1);
8392 checkMasterBndryId = m_solver->a_bndryId(checkMasterId);
8393 if((MInt)m_solver->a_slope(checkMasterBndryId, 2, 0) > -1) {
8394 m_solver->a_slope(checkBndryId, 2, 0) = m_solver->a_slope(checkMasterBndryId, 2, 0);
8395 clusterCells[noClusterCells++] = checkBndryId;
8396 clusterCounter[clusterColor]++;
8397 changedColor = true;
8398 }
8399 }
8400 }
8401 }
8402
8403 // 5. Check the small cell clusters. If a cluster has a volume big enough to be computed as a regular cell (security
8404 // factor: 2 * volumeLimitWall), the biggest cell will be the master and looses its small state. all other cells in
8405 // the cluster will point to the biggest cell.
8406 MFloat clusterVolume = F0;
8407 MInt maxVolumeCell = -1;
8408 MFloat maxVolume = F0;
8409 MInt minClusterLevel = 1000;
8410 MInt index = 0;
8411
8412 clusterColor++;
8413 for(MInt color = 0; color < clusterColor; color++) {
8414 clusterVolume = F0;
8415 maxVolume = F0;
8416 maxVolumeCell = -1;
8417 minClusterLevel = 1000;
8418 for(MInt cC = 0; cC < clusterCounter[color]; cC++) {
8419 currentCell = clusterCells[cC + index];
8420 cellId = m_bndryCells->a[currentCell].m_cellId;
8421 clusterVolume += m_bndryCell[currentCell].m_volume;
8422 if(m_bndryCell[currentCell].m_volume > maxVolume) {
8423 maxVolume = m_bndryCells->a[currentCell].m_volume;
8424 maxVolumeCell = currentCell;
8425 }
8426 if(m_solver->a_level(cellId) < minClusterLevel) minClusterLevel = m_solver->a_level(cellId);
8427 }
8428
8429 if(clusterVolume / m_solver->grid().gridCellVolume(minClusterLevel) >= /*F2 **/ m_volumeLimitWall) {
8430 // set maxVolumeCell as master cell with sufficient volume
8431 m_solver->a_slope(maxVolumeCell, 0, 0) = (MFloat) false;
8432 m_solver->a_slope(maxVolumeCell, 0, 1) = (MFloat) true;
8433 m_solver->a_slope(maxVolumeCell, 1, 0) = (MFloat)-1;
8434 m_solver->a_slope(maxVolumeCell, 1, 1) = (MFloat)-1;
8435 m_bndryCell[maxVolumeCell].m_linkedCellId = -1;
8436 counter--;
8437 countBigCluster++;
8438
8439 for(MInt cC = 0; cC < clusterCounter[color]; cC++) {
8440 currentCell = clusterCells[cC + index];
8441 if(currentCell == maxVolumeCell) {
8442 continue;
8443 }
8444 cellId = m_bndryCells->a[currentCell].m_cellId;
8445 m_solver->a_slope(currentCell, 0, 1) = (MFloat) true;
8446 m_solver->a_slope(currentCell, 1, 1) = (MFloat)m_bndryCells->a[maxVolumeCell].m_cellId;
8447
8448 m_bndryCell[currentCell].m_linkedCellId = m_bndryCell[maxVolumeCell].m_cellId;
8449
8450 counter--;
8451 countBigCluster++;
8452 }
8453 index += clusterCounter[color];
8454 clusterFinished[color] = 1;
8455 } else {
8456 index += clusterCounter[color];
8457 }
8458 }
8459
8460
8461 // 6. For all remaining clusters, a suitable master must be identified.
8462 // First, identify all possible neighbors which are OK (either small tagged with OK or big or internal neighbors)
8463 // Then, search for the best one
8464 // Connect all cluster cells to this master cell.
8465 const MInt maxNeighbors = 20;
8466 MInt clusterNeighbors[maxNeighbors];
8467 MInt noClusterNeighbors = 0;
8468 MInt clusterCentroid[3] = {0, 0, 0};
8469 MFloat minDist = 1000000000.0;
8470 MInt minDistNghbr = -1;
8471 MFloat dist = F0;
8472 index = 0;
8473 for(MInt color = 0; color < clusterColor; color++) {
8474 noClusterNeighbors = 0;
8475 clusterCentroid[0] = F0;
8476 clusterCentroid[1] = F0;
8477 clusterCentroid[2] = F0;
8478 if(clusterFinished[color]) {
8479 index += clusterCounter[color];
8480 continue;
8481 }
8482 for(MInt cC = 0; cC < clusterCounter[color]; cC++) {
8483 currentCell = clusterCells[cC + index];
8484 cellId = m_bndryCells->a[currentCell].m_cellId;
8485 for(MInt i = 0; i < nDim; i++) {
8486 clusterCentroid[i] += m_bndryCell[currentCell].m_volume * m_solver->a_coordinate(cellId, i);
8487 }
8488 for(MInt dir = 0; dir < m_noDirs; dir++) {
8489 for(MInt nghbrID = m_solver->m_identNghbrIds[cellId * m_noDirs + dir];
8490 nghbrID < m_solver->m_identNghbrIds[cellId * m_noDirs + dir + 1];
8491 nghbrID++) {
8492 nghbrId = m_solver->m_storeNghbrIds[nghbrID];
8493 nghbrBndryId = m_solver->a_bndryId(nghbrId);
8494 if(nghbrBndryId < 0) {
8495 clusterNeighbors[noClusterNeighbors++] = nghbrId;
8496 } else if(!(MInt)m_solver->a_slope(nghbrBndryId, 0, 0)) {
8497 clusterNeighbors[noClusterNeighbors++] = nghbrId;
8498 } else if((MInt)m_solver->a_slope(nghbrBndryId, 0, 1) && (!(MInt)m_solver->a_slope(nghbrBndryId, 2, 1))) {
8499 clusterNeighbors[noClusterNeighbors++] = nghbrId;
8500 } else {
8501 continue;
8502 }
8503 }
8504 }
8505 }
8506
8507 if(noClusterNeighbors == 0) {
8508 cerr << " cluster with no neighbors found. this should not happen. isolated small cell island - ... " << endl;
8509 for(MInt cC = 0; cC < clusterCounter[color]; cC++) {
8510 currentCell = clusterCells[cC + index];
8511 cellId = m_bndryCells->a[currentCell].m_cellId;
8512 filename.str("");
8513 filename << cellId << "_cluster_" << color << ".stl";
8514 recorrectCellCoordinates();
8515 writeStlFileOfCell(cellId, (filename.str()).c_str());
8516 rerecorrectCellCoordinates();
8517 }
8518 for(MInt cC = 0; cC < clusterCounter[color]; cC++) {
8519 currentCell = clusterCells[cC + index];
8520 cellId = m_bndryCells->a[currentCell].m_cellId;
8521
8522 m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) = true;
8523 cerr << " cell inactive"
8524 << ", cellId: " << cellId << endl;
8525
8526 // this deletes all relations of the cell with neighbors, parents etc. but the cell itself remains in the
8527 // collector to prevent inconsistencies
8528 // Timw: deleting the cell is not allowed in the multisolver-concept!
8529 // m_solver->grid().deleteCell_MGC( cellId );
8530 m_solver->a_level(cellId) = -1;
8531 m_solver->a_hasProperty(cellId, SolverCell::IsInactive) = true;
8532 m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
8533 m_solver->a_hasProperty(cellId, SolverCell::IsFlux) = false;
8534 m_solver->a_hasProperty(cellId, SolverCell::IsActive) = false;
8535 m_solver->a_isBndryGhostCell(cellId) = false;
8536 }
8537 index += clusterCounter[color];
8538 continue;
8539 }
8540
8541 minDist = 1000000000.0;
8542 minDistNghbr = -1;
8543
8544 for(MInt cN = 0; cN < noClusterNeighbors; cN++) {
8545 dist = F0;
8546 for(MInt i = 0; i < nDim; i++)
8547 dist += (m_solver->a_coordinate(clusterNeighbors[cN], i) - clusterCentroid[i])
8548 * (m_solver->a_coordinate(clusterNeighbors[cN], i) - clusterCentroid[i]);
8549 dist = sqrt(dist);
8550 if(dist < minDist) {
8551 minDist = dist;
8552 minDistNghbr = clusterNeighbors[cN];
8553 }
8554 }
8555 if(minDistNghbr == -1) {
8556 cerr << " cluster with no suitable neighbor found. this should not happen. cluster has " << noClusterNeighbors
8557 << " neighbors - exiting... " << endl;
8558
8559 index += clusterCounter[color];
8560 continue;
8561 }
8562
8563 for(MInt cC = 0; cC < clusterCounter[color]; cC++) {
8564 currentCell = clusterCells[cC + index];
8565 cellId = m_bndryCells->a[currentCell].m_cellId;
8566 master = minDistNghbr;
8567 masterBndryId = m_solver->a_bndryId(master);
8568 if(masterBndryId > -1 && (MInt)m_solver->a_slope(masterBndryId, 0, 0)) {
8569 master = m_bndryCells->a[masterBndryId].m_linkedCellId;
8570 masterBndryId = m_solver->a_bndryId(master);
8571 }
8572 m_solver->a_slope(currentCell, 0, 1) = (MFloat) true;
8573 m_solver->a_slope(currentCell, 1, 1) = (MFloat)master;
8574 m_solver->a_slope(currentCell, 2, 1) = (MFloat) true;
8575
8576 m_bndryCell[currentCell].m_linkedCellId = master;
8577
8578 counter--;
8579 countSpecialcluster++;
8580 }
8581 index += clusterCounter[color];
8582 clusterFinished[color] = 1;
8583 }
8584
8585
8586 m_log << "Master cell statistics: " << endl;
8587 m_log << "__________________________________" << endl << endl;
8588 m_log << " * links to internal cells " << count1 << endl;
8589 m_log << " * links to boundary cells " << count2 << endl;
8590 m_log << " * chained links " << countChained << endl;
8591 m_log << " * chained biggest cluster cell " << countBigCluster << endl;
8592 m_log << " * chained to special master " << countSpecialcluster << endl;
8593 m_log << "__________________________________" << endl;
8594
8595 // create small cells
8596 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8597 if((MInt)m_solver->a_slope(bndryId, 0, 0) && (MInt)m_solver->a_slope(bndryId, 0, 1)) {
8598 cellId = m_bndryCells->a[bndryId].m_cellId;
8599 if(!m_solver->a_hasProperty(cellId, SolverCell::IsInvalid)) {
8600 m_smallBndryCells->append();
8601 m_smallBndryCells->a[m_smallBndryCells->size() - 1] = bndryId;
8602 }
8603 }
8604 }
8605
8606
8607 // fill the lists smallCellIds and masterCellIds
8608 noCells = m_smallBndryCells->size();
8609 for(MInt s = 0; s < noCells; s++) {
8610 m_solver->m_smallCellIds[s] = m_bndryCell[m_smallBndryCells->a[s]].m_cellId;
8611 m_solver->m_masterCellIds[s] = m_bndryCell[m_smallBndryCells->a[s]].m_linkedCellId;
8612 }
8613}
8614
8615
8631template <MInt nDim, class SysEqn>
8633 TRACE();
8634
8635 MInt smallCell;
8636 MInt smallCellId;
8637 MInt master;
8638 MInt masterId;
8639 MInt noCells = m_solver->a_noCells();
8640 MInt noSmallCells = m_smallBndryCells->size();
8641 MFloat area;
8642 MFloat factor;
8643 MFloat totalVolume;
8644 MFloat coordinates;
8645 MFloat avrgCoordinates;
8646 MFloatScratchSpace oldNormalVector_scratch(nDim, AT_, "oldNormalVector_scratch");
8647 MFloat* oldNormalVector = oldNormalVector_scratch.getPointer();
8648 //---
8649
8650 // store all original coordinates, reset volumes
8651 for(MInt id = 0; id < noCells; id++) {
8652 m_solver->a_slope(id, 1, 0) = m_solver->grid().gridCellVolume(m_solver->a_level(id));
8653 for(MInt i = 0; i < nDim; i++) {
8654 m_solver->a_slope(id, 0, i) = m_solver->a_coordinate(id, i);
8655 }
8656 }
8657
8658 for(MInt smallId = 0; smallId < noSmallCells; smallId++) {
8659 smallCell = m_smallBndryCells->a[smallId];
8660 smallCellId = m_bndryCell[smallCell].m_cellId;
8661 masterId = m_bndryCell[smallCell].m_linkedCellId;
8662 master = m_solver->a_bndryId(masterId);
8663
8664 if(master > -1) {
8665 // first case: master cell is a boundary cell
8666 // ------------------------------------------
8667
8668 totalVolume = m_bndryCell[master].m_volume + m_bndryCell[smallCell].m_volume;
8669
8670 for(MInt v = 0; v < CV->noVariables; v++) {
8671 m_solver->a_variable(masterId, v) = (m_solver->a_variable(masterId, v) * m_bndryCell[master].m_volume
8672 + m_solver->a_variable(smallCellId, v) * m_bndryCell[smallCell].m_volume)
8673 / totalVolume;
8674 m_solver->a_variable(smallCellId, v) = m_solver->a_variable(masterId, v);
8675 }
8676 for(MInt v = 0; v < PV->noVariables; v++) {
8677 m_solver->a_pvariable(masterId, v) = (m_solver->a_pvariable(masterId, v) * m_bndryCell[master].m_volume
8678 + m_solver->a_pvariable(smallCellId, v) * m_bndryCell[smallCell].m_volume)
8679 / totalVolume;
8680 m_solver->a_pvariable(smallCellId, v) = m_solver->a_pvariable(masterId, v);
8681 }
8682
8683
8684 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8685 // update coordinates of the...
8686 coordinates = (m_solver->a_coordinate(masterId, spaceId) * m_bndryCell[master].m_volume
8687 + m_solver->a_coordinate(smallCellId, spaceId) * m_bndryCell[smallCell].m_volume)
8688 / totalVolume;
8689 // ...master cell
8690 m_bndryCell[master].m_coordinates[spaceId] += (coordinates - m_solver->a_coordinate(masterId, spaceId));
8691 m_solver->a_coordinate(masterId, spaceId) = coordinates;
8692
8693 // update surface coordinates
8694 // --------------------------
8695 // the new surface coordinates are the area-average of the small cell and
8696 // master cell body surfaces
8697 avrgCoordinates =
8698 (m_bndryCell[master].m_srfcs[0]->m_coordinates[spaceId] * m_bndryCell[master].m_srfcs[0]->m_area
8699 + m_bndryCell[smallCell].m_srfcs[0]->m_coordinates[spaceId] * m_bndryCell[smallCell].m_srfcs[0]->m_area)
8700 / (m_bndryCell[master].m_srfcs[0]->m_area + m_bndryCell[smallCell].m_srfcs[0]->m_area);
8701
8702 m_bndryCell[master].m_srfcs[0]->m_coordinates[spaceId] = avrgCoordinates;
8703
8704 // update surface orientation
8705 // --------------------------
8706 oldNormalVector[spaceId] = m_bndryCell[master].m_srfcs[0]->m_normalVector[spaceId];
8707 m_bndryCell[master].m_srfcs[0]->m_normalVector[spaceId] =
8708 m_bndryCell[master].m_srfcs[0]->m_normalVector[spaceId] * m_bndryCell[master].m_srfcs[0]->m_area
8709 + m_bndryCell[smallCell].m_srfcs[0]->m_normalVector[spaceId] * m_bndryCell[smallCell].m_srfcs[0]->m_area;
8710 }
8711 factor = 0;
8712 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8713 factor += POW2(m_bndryCell[master].m_srfcs[0]->m_normalVector[spaceId]);
8714 }
8715 factor = sqrt(factor);
8716 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8717 m_bndryCell[master].m_srfcs[0]->m_normalVector[spaceId] =
8718 m_bndryCell[master].m_srfcs[0]->m_normalVector[spaceId] / factor;
8719 }
8720
8721 // update surface area
8722 area = 0;
8723 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8724 area += m_bndryCell[master].m_srfcs[0]->m_normalVector[spaceId]
8725 * (oldNormalVector[spaceId] * m_bndryCell[master].m_srfcs[0]->m_area
8726 + m_bndryCell[smallCell].m_srfcs[0]->m_normalVector[spaceId]
8727 * m_bndryCell[smallCell].m_srfcs[0]->m_area);
8728 }
8729
8730 m_bndryCell[master].m_srfcs[0]->m_area = area;
8731
8732 // update cell volume = master cell volume + small cell volume
8733 m_bndryCell[master].m_volume = totalVolume;
8734
8735 } else {
8736 // second case: master is an internal cell
8737 // ---------------------------------------
8738 totalVolume = m_solver->a_slope(masterId, 1, 0) + m_bndryCell[smallCell].m_volume;
8739
8740 for(MInt v = 0; v < CV->noVariables; v++) {
8741 m_solver->a_variable(masterId, v) = (m_solver->a_variable(masterId, v) * m_solver->a_slope(masterId, 1, 0)
8742 + m_solver->a_variable(smallCellId, v) * m_bndryCell[smallCell].m_volume)
8743 / totalVolume;
8744 m_solver->a_variable(smallCellId, v) = m_solver->a_variable(masterId, v);
8745 }
8746 for(MInt v = 0; v < PV->noVariables; v++) {
8747 m_solver->a_pvariable(masterId, v) = (m_solver->a_pvariable(masterId, v) * m_solver->a_slope(masterId, 1, 0)
8748 + m_solver->a_pvariable(smallCellId, v) * m_bndryCell[smallCell].m_volume)
8749 / totalVolume;
8750 m_solver->a_pvariable(smallCellId, v) = m_solver->a_pvariable(masterId, v);
8751 }
8752
8753
8754 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8755 // update coordinates of the...
8756 coordinates = (m_solver->a_coordinate(masterId, spaceId) * m_solver->a_slope(masterId, 1, 0)
8757 + m_solver->a_coordinate(smallCellId, spaceId) * m_bndryCell[smallCell].m_volume)
8758 / totalVolume;
8759 // ...master cell
8760 m_solver->a_coordinate(masterId, spaceId) = coordinates;
8761 }
8762 m_solver->a_slope(masterId, 1, 0) = totalVolume;
8763 }
8764 }
8765
8766 // small cells are moved to the final position of their master cell
8767 // small cells with an internal master receive its original position
8768 for(MInt smallId = 0; smallId < noSmallCells; smallId++) {
8769 smallCell = m_smallBndryCells->a[smallId];
8770 smallCellId = m_bndryCell[smallCell].m_cellId;
8771 masterId = m_bndryCell[smallCell].m_linkedCellId;
8772 master = m_solver->a_bndryId(masterId);
8773
8774 for(MInt i = 0; i < nDim; i++) {
8775 m_bndryCell[smallCell].m_coordinates[i] +=
8776 (m_solver->a_coordinate(masterId, i) - m_solver->a_coordinate(smallCellId, i));
8777 m_solver->a_coordinate(smallCellId, i) = m_solver->a_coordinate(masterId, i);
8778 }
8779
8780 if(master == -1) {
8781 for(MInt i = 0; i < nDim; i++) {
8782 m_bndryCell[smallCell].m_masterCoordinates[i] = m_solver->a_slope(masterId, 0, i);
8783 }
8784 }
8785 }
8786}
8787
8788
8806template <MInt nDim, class SysEqn>
8808 TRACE();
8809
8810 MInt smallCell;
8811 MInt smallCellId;
8812 MInt master;
8813 MInt masterId;
8814 MInt noCells = m_solver->a_noCells();
8815 MInt noSmallCells = m_smallBndryCells->size();
8816 MFloat totalVolume;
8817 MFloat coordinates;
8818 //---
8819
8820 // store all original coordinates, reset volumes
8821 for(MInt id = 0; id < noCells; id++) {
8822 m_solver->a_slope(id, 1, 0) = m_solver->grid().gridCellVolume(m_solver->a_level(id));
8823 for(MInt i = 0; i < nDim; i++) {
8824 m_solver->a_slope(id, 0, i) = m_solver->a_coordinate(id, i);
8825 }
8826 }
8827
8828 for(MInt smallId = 0; smallId < noSmallCells; smallId++) {
8829 smallCell = m_smallBndryCells->a[smallId];
8830 smallCellId = m_bndryCell[smallCell].m_cellId;
8831 masterId = m_bndryCell[smallCell].m_linkedCellId;
8832 master = m_solver->a_bndryId(masterId);
8833
8834 if(master > -1) {
8835 // first case: master cell is a boundary cell
8836 // ------------------------------------------
8837
8838 totalVolume = m_bndryCell[master].m_volume + m_bndryCell[smallCell].m_volume;
8839
8840 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8841 // update coordinates of the...
8842 coordinates = (m_solver->a_coordinate(masterId, spaceId) * m_bndryCell[master].m_volume
8843 + m_solver->a_coordinate(smallCellId, spaceId) * m_bndryCell[smallCell].m_volume)
8844 / totalVolume;
8845 // ...master cell
8846 m_bndryCell[master].m_coordinates[spaceId] += (coordinates - m_solver->a_coordinate(masterId, spaceId));
8847 m_solver->a_coordinate(masterId, spaceId) = coordinates;
8848 }
8849
8850 // update cell volume = master cell volume + small cell volume
8851 m_bndryCell[master].m_volume = totalVolume;
8852
8853 } else {
8854 // second case: master is an internal cell
8855 // ---------------------------------------
8856 totalVolume = m_solver->a_slope(masterId, 1, 0) + m_bndryCell[smallCell].m_volume;
8857
8858 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8859 // update coordinates of the...
8860 coordinates = (m_solver->a_coordinate(masterId, spaceId) * m_solver->a_slope(masterId, 1, 0)
8861 + m_solver->a_coordinate(smallCellId, spaceId) * m_bndryCell[smallCell].m_volume)
8862 / totalVolume;
8863 // ...master cell
8864 m_solver->a_coordinate(masterId, spaceId) = coordinates;
8865 }
8866
8867 // if master has multiple small cells, volume must be updated!
8868 m_solver->a_slope(masterId, 1, 0) = totalVolume;
8869 }
8870 }
8871
8872 // small cells are moved to the final position of their master cell
8873 // small cells with an internal master receive its original position
8874 // in the masterCoordinates variable
8875 for(MInt smallId = 0; smallId < noSmallCells; smallId++) {
8876 smallCell = m_smallBndryCells->a[smallId];
8877 smallCellId = m_bndryCell[smallCell].m_cellId;
8878 masterId = m_bndryCell[smallCell].m_linkedCellId;
8879 master = m_solver->a_bndryId(masterId);
8880
8881 for(MInt i = 0; i < nDim; i++) {
8882 m_bndryCell[smallCell].m_coordinates[i] +=
8883 (m_solver->a_coordinate(masterId, i) - m_solver->a_coordinate(smallCellId, i));
8884 m_solver->a_coordinate(smallCellId, i) = m_solver->a_coordinate(masterId, i);
8885 }
8886
8887 if(master == -1) {
8888 for(MInt i = 0; i < nDim; i++) {
8889 m_bndryCell[smallCell].m_masterCoordinates[i] = m_solver->a_slope(masterId, 0, i);
8890 }
8891 }
8892 }
8893}
8894
8895
8907template <MInt nDim, class SysEqn>
8909 TRACE();
8910
8911 MInt cellId;
8912 MInt noChildren;
8913 MInt childCellId;
8914 MInt noCells = m_bndryCells->size();
8915 MFloat bndryCellVolumes;
8916 MFloat childVolume;
8917 MFloat volume;
8918 MFloatScratchSpace bndryXyz_scratch(nDim, AT_, "bndryXyz_scratch");
8919 MFloat* bndryXyz = bndryXyz_scratch.getPointer();
8920 MFloatScratchSpace cellXyz_scratch(nDim, AT_, "cellXyz_scratch");
8921 MFloat* cellXyz = cellXyz_scratch.getPointer();
8922 MFloatScratchSpace srfcXyz_scratch(nDim, AT_, "srfcXyz_scratch");
8923 MFloat* srfcXyz = srfcXyz_scratch.getPointer();
8924 MFloat srfcArea;
8925
8926 // ------------- end of initialization --------------
8927
8928 // loop over all levels
8929 for(MInt level = m_solver->maxRefinementLevel() - 1; level > 0; level--) {
8930 // loop over all boundary cells
8931 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
8932 // choose only those boundary cells at the current level
8933 cellId = m_bndryCells->a[bndryId].m_cellId;
8934 if(m_solver->a_level(cellId) == level) {
8935 noChildren = m_solver->c_noChildren(cellId);
8936
8937 if(noChildren > 0) {
8938 // reset temp. variables
8939 volume = 0;
8940 bndryCellVolumes = 0;
8941 srfcArea = 0;
8942 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8943 bndryXyz[spaceId] = 0;
8944 cellXyz[spaceId] = 0;
8945 srfcXyz[spaceId] = 0;
8946 }
8947
8948 // -------- average children cell coordinates and volumes ---------
8949 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
8950 if(m_solver->c_childId(cellId, childId) == -1) continue;
8951
8952 childCellId = m_solver->c_childId(cellId, childId);
8953
8954 if(m_solver->a_bndryId(childCellId) > -1) {
8955 volume += m_bndryCells->a[m_solver->a_bndryId(childCellId)].m_volume;
8956 bndryCellVolumes += m_bndryCells->a[m_solver->a_bndryId(childCellId)].m_volume;
8957
8958 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8959 bndryXyz[spaceId] += m_solver->a_coordinate(childCellId, spaceId)
8960 * m_bndryCells->a[m_solver->a_bndryId(childCellId)].m_volume;
8961 }
8962
8963 // average body surface of children
8964 srfcArea += m_bndryCells->a[m_solver->a_bndryId(childCellId)].m_srfcs[0]->m_area;
8965 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8966 srfcXyz[spaceId] += m_bndryCells->a[m_solver->a_bndryId(childCellId)].m_srfcs[0]->m_coordinates[spaceId]
8967 * m_bndryCells->a[m_solver->a_bndryId(childCellId)].m_srfcs[0]->m_area;
8968 }
8969
8970 } else {
8971 childVolume = m_solver->c_cellLengthAtCell(childCellId);
8972 for(MInt spaceId = 1; spaceId < nDim; spaceId++) {
8973 childVolume *= m_solver->c_cellLengthAtCell(childCellId);
8974 }
8975 volume += childVolume;
8976 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8977 cellXyz[spaceId] += m_solver->a_coordinate(childCellId, spaceId) * childVolume;
8978 }
8979 }
8980 }
8981
8982 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8983 cellXyz[spaceId] += bndryXyz[spaceId];
8984 cellXyz[spaceId] = cellXyz[spaceId] / volume;
8985 bndryXyz[spaceId] = bndryXyz[spaceId] / bndryCellVolumes;
8986 srfcXyz[spaceId] = srfcXyz[spaceId] / srfcArea;
8987 }
8988
8989 // ----------------------------------------------------------------
8990
8991 // correct the coordinate shift of the boundary cell
8992 // set the coordinates of the boundary cell
8993 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
8994 m_bndryCells->a[bndryId].m_coordinates[spaceId] +=
8995 cellXyz[spaceId] - m_solver->a_coordinate(cellId, spaceId);
8996 m_solver->a_coordinate(cellId, spaceId) = cellXyz[spaceId];
8997 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[spaceId] = srfcXyz[spaceId];
8998 }
8999
9000 // update coarse cell volume
9001 m_bndryCells->a[bndryId].m_volume = volume;
9002 }
9003 }
9004 }
9005 }
9006}
9007
9008
9015template <MInt nDim, class SysEqn>
9017 TRACE();
9018
9019 MInt bndryId;
9020 MInt cellId;
9021 MInt noCVars = CV->noVariables;
9022 MInt noFVars = FV->noVariables;
9023 MInt noCells = m_smallBndryCells->size();
9024 //---
9025
9026 for(MInt smallCellId = 0; smallCellId < noCells; smallCellId++) {
9027 bndryId = m_smallBndryCells->a[smallCellId];
9028 cellId = m_bndryCells->a[bndryId].m_cellId;
9029
9030 for(MInt varId = 0; varId < noCVars; varId++) {
9031 m_solver->a_tau(cellId, varId) = 0;
9032 }
9033 for(MInt varId = 0; varId < noFVars; varId++) {
9034 m_solver->a_rightHandSide(cellId, varId) = 0;
9035 }
9036 }
9037}
9038
9039
9044template <MInt nDim, class SysEqn>
9046 const MUint noVars = PV->noVariables;
9047 const MUint noSlopes = nDim * noVars;
9048 const MUint noSmallCells = m_smallBndryCells->size();
9049 const MInt* const RESTRICT smallCellIds = m_solver->m_smallCellIds;
9050 const MInt* const RESTRICT masterCellIds = m_solver->m_masterCellIds;
9051 MFloat* const RESTRICT slope = &m_solver->a_slope(0, 0, 0);
9052
9053 for(MUint c = 0; c < noSmallCells; ++c) {
9054 const MUint scId = smallCellIds[c];
9055 const MUint mcId = masterCellIds[c];
9056 MFloat* const RESTRICT smallCellSlopes = slope + scId * noSlopes;
9057 const MFloat* const RESTRICT masterCellSlopes = slope + mcId * noSlopes;
9058 for(MUint slopeId = 0; slopeId < noSlopes; ++slopeId) {
9059 smallCellSlopes[slopeId] = masterCellSlopes[slopeId];
9060 }
9061 }
9062}
9063
9069template <MInt nDim, class SysEqn>
9071 const MUint noBndrySurfaces = m_noBoundarySurfaces;
9072 const MUint noVars = PV->noVariables;
9073 const MUint surfaceVarMemory = 2 * noVars;
9074 MFloat* const RESTRICT surfaceVar = &m_solver->a_surfaceVariable(0, 0, 0);
9075 const MInt* const RESTRICT nghbrCellIds = &m_solver->a_surfaceNghbrCellId(0, 0);
9076 const MFloat* const RESTRICT vars = &m_solver->a_pvariable(0, 0);
9077
9078 if(m_cellMerging) {
9079 for(MUint bs = 0; bs < noBndrySurfaces; ++bs) {
9080 const MUint srfcId = m_boundarySurfaces[bs];
9081 const MUint srfcOffset = srfcId * surfaceVarMemory;
9082 const MFloat* const RESTRICT vars0 = vars + nghbrCellIds[srfcId * 2] * noVars;
9083 const MFloat* const RESTRICT vars1 = vars + nghbrCellIds[srfcId * 2 + 1] * noVars;
9084 MFloat* const RESTRICT surfaceVar0 = surfaceVar + srfcOffset;
9085 MFloat* const RESTRICT surfaceVar1 = surfaceVar0 + noVars;
9086 for(MUint v = 0; v < noVars; ++v) {
9087 const MFloat tmp = F1B2 * (vars0[v] + vars1[v]);
9088 surfaceVar0[v] = tmp;
9089 surfaceVar1[v] = tmp;
9090 }
9091 }
9092 } else {
9093 const MInt noBndryCells = m_bndryCells->size();
9094 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
9095 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
9096 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
9097 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9098 for(MInt i = 0; i < nDim; i++) {
9099 const MInt srfcId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i];
9100 if(srfcId < 0) continue;
9101 const MUint srfcOffset = srfcId * surfaceVarMemory;
9102 MFloat* const RESTRICT surfaceVar0 = surfaceVar + srfcOffset;
9103 MFloat* const RESTRICT surfaceVar1 = surfaceVar0 + noVars;
9104 for(MUint v = 0; v < noVars; ++v) {
9105 surfaceVar0[v] = m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v];
9106 surfaceVar1[v] = m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v];
9107 }
9108 }
9109 }
9110 }
9111 }
9112}
9113
9114
9128template <MInt nDim, class SysEqn>
9130 const MUint noSmallCells = m_smallBndryCells->size();
9131 const MUint noVars = CV->noVariables;
9132 const MInt* const RESTRICT smallIds = &m_smallBndryCells->a[0];
9133 const FvBndryCell<nDim, SysEqn>* const bCells = &m_bndryCells->a[0];
9134 MFloat* const RESTRICT vars = &m_solver->a_variable(0, 0);
9135
9136 // loop over all small boundary cells
9137 for(MUint smallId = 0; smallId < noSmallCells; ++smallId) {
9138 const MUint smallCell = smallIds[smallId];
9139 const MUint smallCellId = bCells[smallCell].m_cellId;
9140 const MUint masterId = bCells[smallCell].m_linkedCellId;
9141
9142 // copy the variables from master to slave cells
9143 MFloat* const RESTRICT smallCellVars = vars + smallCellId * noVars;
9144 const MFloat* const RESTRICT masterCellVars = vars + masterId * noVars;
9145 for(MUint v = 0; v < noVars; ++v) {
9146 smallCellVars[v] = masterCellVars[v];
9147 }
9148 }
9149}
9150
9151
9156template <MInt nDim, class SysEqn>
9158 TRACE();
9159
9160 const MInt noBndryCells = m_bndryCells->size();
9161 const MInt maxNoNghbrs = 200;
9162 const MInt noLayersStencil = m_noFluxRedistributionLayers;
9163 if(noDomains() > 1 && noLayersStencil > mMin(m_noFluxRedistributionLayers, m_solver->noHaloLayers())) {
9164 cerr << "Warning: noLayersStencil smaller than flux redistribution layers!" << endl;
9165 }
9166
9167 MIntScratchSpace nghbrList(maxNoNghbrs, AT_, "nghbrList");
9168 MIntScratchSpace layerId(maxNoNghbrs, AT_, "layerId");
9170
9171 for(MInt s = 0; s < FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces; s++) {
9172 dummyIds(s) = m_solver->maxNoGridCells() - FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces + s;
9173 if(dummyIds(s) < (m_solver->a_noCells())) {
9174 mTerm(1, AT_,
9175 "Increase cell collector! " + to_string(m_solver->a_noCells()) + " "
9177 }
9178 }
9179
9180 if(updateOnlyBndryCndId < 0) {
9181 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
9182 m_bndryCell[bndryId].m_recNghbrIds.resize(0);
9183 m_bndryCell[bndryId].m_cellVarsRecConst.resize(0);
9184 m_bndryCell[bndryId].m_cellDerivRecConst.resize(0);
9185 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9186 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.resize(0);
9187 }
9188 }
9189 } else {
9190 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
9191 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
9192 if(m_solver->a_isPeriodic(cellId) || m_solver->a_isHalo(cellId)) {
9193 m_bndryCell[bndryId].m_cellVarsRecConst.resize(0);
9194 m_bndryCell[bndryId].m_cellDerivRecConst.resize(0);
9195 }
9196 MBool skip = false;
9197 // if( m_solver->a_isPeriodic( cellId ) ) skip = true;
9198 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
9199 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) skip = true;
9200 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) skip = true;
9201 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitCell)) skip = true;
9202 if(m_solver->c_noChildren(cellId) > 0) skip = true;
9203 if(skip) {
9204 m_bndryCell[bndryId].m_recNghbrIds.resize(0);
9205 m_bndryCell[bndryId].m_cellVarsRecConst.resize(0);
9206 m_bndryCell[bndryId].m_cellDerivRecConst.resize(0);
9207 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9208 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.resize(0);
9209 }
9210 }
9211 }
9212 }
9213
9214 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
9215 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
9216 const MInt noSrfcs = m_bndryCells->a[bndryId].m_noSrfcs;
9217 MInt gridcellId = cellId;
9218 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitClone)) {
9219 gridcellId = m_solver->m_splitChildToSplitCell.find(cellId)->second;
9220 }
9221
9222 // if( m_solver->a_isPeriodic( cellId ) ) continue;
9223 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
9224 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
9225 if(!m_solver->a_hasProperty(cellId, SolverCell::IsSplitChild) && m_solver->c_noChildren(gridcellId) > 0) continue;
9226 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
9227
9228 MBool skip = false;
9229 if(updateOnlyBndryCndId > -1) {
9230 skip = true;
9231 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9232 if(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId == updateOnlyBndryCndId) skip = false;
9233 }
9234 }
9235 if(skip) continue;
9236
9237 m_bndryCell[bndryId].m_recNghbrIds.resize(0);
9238 m_bndryCell[bndryId].m_cellVarsRecConst.resize(0);
9239 m_bndryCell[bndryId].m_cellDerivRecConst.resize(0);
9240 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9241 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.resize(0);
9242 }
9243
9244 nghbrList.fill(-1);
9245 const MInt rootCell = (m_solver->a_hasProperty(cellId, SolverCell::IsSplitChild)
9246 || m_solver->a_hasProperty(cellId, SolverCell::IsSplitClone))
9247 ? m_solver->getAssociatedInternalCell(cellId)
9248 : cellId;
9249 ASSERT(rootCell > -1 && rootCell < m_solver->a_noCells(), "");
9250 const MInt addPoints = noSrfcs + 1;
9251 const MInt recSize = m_solver->template getAdjacentLeafCells<1, true>(rootCell, noLayersStencil, nghbrList, layerId)
9252 + addPoints; // my neighbors + my boundary-surface centroids + myself
9253
9254 if(recSize > maxNoNghbrs) {
9255 mTerm(1, AT_,
9256 "too many nghbrs " + to_string(recSize) + " " + to_string(cellId) + " "
9257 + to_string(m_solver->a_isHalo(cellId)));
9258 }
9259 if(recSize < nDim + 2) {
9260 cerr << "not enough neighbors " + to_string(recSize) + " " + to_string(recSize - addPoints) + " "
9261 + to_string(cellId)
9262 << " " << m_solver->a_isHalo(cellId) << endl;
9263 continue;
9264 }
9265 for(MInt k = recSize - 1; k >= addPoints; k--) {
9266 ASSERT(k - addPoints > -1, "");
9267 ASSERT(nghbrList(k - addPoints) > -1 && nghbrList(k - addPoints) < m_solver->a_noCells(), "");
9268 nghbrList(k) = nghbrList(k - addPoints);
9269 layerId(k) = layerId(k - addPoints);
9270 }
9271 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9272 nghbrList(srfc) = dummyIds(srfc);
9273 layerId(srfc) = 0;
9274 }
9275 nghbrList(noSrfcs) = cellId;
9276 layerId(noSrfcs) = 0;
9277
9278 m_bndryCell[bndryId].m_recNghbrIds.resize(recSize);
9279 m_bndryCell[bndryId].m_cellVarsRecConst.resize(recSize);
9280 for(MInt k = 0; k < recSize; k++) {
9281 m_bndryCell[bndryId].m_recNghbrIds[k] = nghbrList(k);
9282 m_bndryCell[bndryId].m_cellVarsRecConst[k] = (MFloat)layerId(k);
9283 }
9284 }
9285}
9286
9287
9292template <MInt nDim, class SysEqn>
9294 TRACE();
9295
9296 const MInt minRecDim = nDim + 1;
9297 // const MInt medRecDim = m_secondOrderRec ? 2*nDim + 1 : minRecDim;
9298 const MInt maxRecDim = m_secondOrderRec ? (IPOW2(nDim) + 2) : minRecDim;
9299 const MInt noBndryCells = m_bndryCells->size();
9300 const MInt maxNoSrfcs = 14;
9302 mTerm(1, AT_, "Increase maxNoSrfcs. " + to_string(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces));
9303 }
9304 const MInt maxNoNghbrs = 200;
9305 const MInt noLayersStencil = m_noFluxRedistributionLayers;
9306 const MFloat condNumThreshold = 1e7;
9307 MBool& firstRun = m_static_computeImagePointRecConst_firstRun;
9308 if(noDomains() > 1 && noLayersStencil > mMin(m_noFluxRedistributionLayers, m_solver->noHaloLayers())) {
9309 cerr << "Warning: noLayersStencil smaller than flux redistribution layers!" << endl;
9310 }
9311
9312 MIntScratchSpace layerId(maxNoNghbrs, AT_, "layerId");
9314 MFloatScratchSpace deltaXSurf(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, nDim, AT_, "deltaXSurf");
9315 MFloatScratchSpace imagePoint(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, nDim, AT_, "imagePoint");
9316 MFloatScratchSpace surfCoords(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, nDim, AT_, "surfCoords");
9317 MFloatScratchSpace deltaXSurfProj(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, nDim, AT_, "deltaXSurfProj");
9319 MFloatScratchSpace backup(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, maxRecDim, AT_, "backup");
9320 MFloatScratchSpace mat(maxNoNghbrs, maxRecDim, AT_, "mat_imagePoint");
9321 MFloatScratchSpace matInv(maxRecDim, maxNoNghbrs, AT_, "matInv");
9322 MFloatScratchSpace weights(maxNoNghbrs, AT_, "weights");
9323
9324 MFloat maxCondNum0 = F0;
9325 MFloat maxCondNum1 = F0;
9326 MFloat avgCondNum0 = F0;
9327 MFloat avgCondNum1 = F0;
9328 MFloat condCnt0 = F0;
9329 MFloat condCnt1 = F0;
9330
9331 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
9332 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
9333 const MInt noSrfcs = m_bndryCells->a[bndryId].m_noSrfcs;
9334 MInt gridcellId = cellId;
9335 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitClone)) {
9336 gridcellId = m_solver->m_splitChildToSplitCell.find(cellId)->second;
9337 }
9338
9339 // if( m_solver->a_isPeriodic( cellId ) ) continue;
9340 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
9341 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
9342 if(!m_solver->a_hasProperty(cellId, SolverCell::IsSplitChild) && m_solver->c_noChildren(gridcellId) > 0) continue;
9343 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
9344 if(m_bndryCell[bndryId].m_recNghbrIds.size() == 0) continue;
9345 MBool skip = false;
9346 if(updateOnlyBndryCndId > -1) {
9347 skip = true;
9348 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9349 if(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId == updateOnlyBndryCndId) skip = false;
9350 }
9351 }
9352 if(skip) continue;
9353
9354 const MFloat normalizationFactor =
9355 FPOW2(m_solver->a_level(cellId))
9356 / m_solver->c_cellLengthAtLevel(0); // scaling factor to reduce the condition number of the resulting eq. sys.
9357
9358 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9359 // const MInt ghostCellId = m_bndryCells->a[ bndryId ].m_srfcVariables[srfc]->m_ghostCellId;
9360 // ASSERT( ghostCellId > -1, "" );
9361 deltaNSurf[srfc] = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
9362 for(MInt i = 0; i < nDim; i++) {
9363 // normal(srfc,i) = m_bndryCell[ bndryId ].m_srfcs[srfc]->m_normalVector[ i ];
9364 normal(srfc, i) = m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i];
9365 }
9366 /*deltaNSurf[srfc] = F0;
9367 for ( MInt i = 0; i < nDim; i++ ) {
9368 normal(srfc,i) = m_bndryCell[ bndryId ].m_srfcs[srfc]->m_normalVector[ i ];
9369 deltaNSurf[srfc] += normal(srfc,i) * ( m_solver->a_coordinate( cellId , i ) - m_bndryCell[ bndryId
9370 ].m_srfcs[srfc]->m_coordinates[ i ] );
9371 }
9372 */
9373 }
9374
9375 MFloatScratchSpace dummyCoordinates(noSrfcs, nDim, AT_, "dummyCoordinates");
9376 MIntScratchSpace dummyLevel(noSrfcs, AT_, "dummyLevel");
9377 MFloatScratchSpace dummyCellVolume(noSrfcs, AT_, "dummyLevel");
9378 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9379 for(MInt i = 0; i < nDim; i++) {
9380 // deltaXSurf(srfc,i) = m_bndryCell[ bndryId ].m_srfcs[srfc]->m_coordinates[ i ] - m_solver->a_coordinate(
9381 // cellId , i );
9382 deltaXSurfProj(srfc, i) = -deltaNSurf[srfc] * normal(srfc, i);
9383 deltaXSurf(srfc, i) = deltaXSurfProj(srfc, i);
9384 // imagePoint(srfc,i) = m_solver->a_coordinate( cellId , i ) + ( F1B2 *
9385 // m_solver->c_cellLengthAtLevel(m_solver->a_level( cellId )) - deltaNSurf[srfc] ) * normal(srfc,i);
9386 // imagePoint(srfc,i) = m_solver->a_coordinate( cellId , i ) + mMax( F0, ( F1B2 *
9387 // m_solver->c_cellLengthAtLevel(m_solver->a_level( cellId )) - deltaNSurf[srfc] ) ) * normal(srfc,i); if
9388 // dn>dx/2 use cell coordinates, otherwise fixed wall distance of dx/2, i.e., the image point is never closer to
9389 // the surface than the corresponding cell:
9390 imagePoint(srfc, i) =
9391 m_solver->a_coordinate(cellId, i)
9392 + mMax(F0, (mMax(deltaNSurf[srfc], F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId)))
9393 - deltaNSurf[srfc]))
9394 * normal(srfc, i);
9395 surfCoords(srfc, i) = m_solver->a_coordinate(cellId, i) - deltaNSurf[srfc] * normal(srfc, i);
9396 }
9397
9398 const MInt dummyId = m_bndryCell[bndryId].m_recNghbrIds[srfc]; // dummyIds(srfc);
9399 dummyLevel[srfc] = m_solver->a_level(cellId);
9400 dummyCellVolume(srfc) = m_solver->grid().gridCellVolume(m_solver->a_level(cellId));
9401 m_solver->a_bndryId(dummyId) = -1;
9402 for(MInt i = 0; i < nDim; i++) {
9403 dummyCoordinates(srfc, i) = m_solver->a_coordinate(cellId, i) + deltaXSurfProj(srfc, i);
9404 }
9405 }
9406
9407 const MInt recSize = m_bndryCell[bndryId].m_recNghbrIds.size();
9408 const MInt noNghbrIds = recSize;
9409 for(MInt k = 0; k < noNghbrIds; k++) {
9410 layerId(k) = (MInt)m_bndryCell[bndryId].m_cellVarsRecConst[k];
9411 if(k <= noSrfcs && layerId(k) != 0) {
9412 mTerm(1, AT_, "FvBndryCndXD<nDim, SysEqn>::computeImagePointRecConst: Inconsistency 0.");
9413 }
9414 if(k > noSrfcs && (layerId(k) < 1 || layerId(k) > noLayersStencil)) {
9415 mTerm(1, AT_, "FvBndryCndXD::computeImagePointRecConst: Inconsistency 0b.");
9416 }
9417 }
9418 m_bndryCell[bndryId].m_cellVarsRecConst.resize(0);
9419
9420 mat.fill(F0);
9421 weights.fill(F0);
9422
9423 // image point reconstruction constants
9424 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9425 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.resize(recSize);
9426 ASSERT(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size()
9427 == m_bndryCell[bndryId].m_recNghbrIds.size(),
9428 "");
9429 for(MInt k = 0; k < noNghbrIds; k++) {
9430 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[k];
9431 const MFloat* const nghbrCoord =
9432 (k < noSrfcs) ? &dummyCoordinates(k, 0) : &(m_solver->a_coordinate(nghbrId, 0));
9433 const MInt nghbrLevel = (k < noSrfcs) ? dummyLevel[k] : m_solver->a_level(nghbrId);
9434 const MFloat nghbrCellVolume = (k < noSrfcs) ? dummyCellVolume(k) : m_solver->a_cellVolume(nghbrId);
9435 mat(k, 0) = F1;
9436 MFloat dx = F0;
9437 for(MInt i = 0; i < nDim; i++) {
9438 mat(k, 1 + i) = (nghbrCoord[i] - imagePoint(srfc, i)) * normalizationFactor;
9439 dx += POW2(nghbrCoord[i] - imagePoint(srfc, i));
9440 }
9441 weights(k) = maia::math::RBF(dx, POW2(m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId))))
9442 * maia::math::deltaFun(nghbrCellVolume / m_solver->grid().gridCellVolume(nghbrLevel), 1e-6, 0.1);
9443 // weights(k) = maia::math::RBF( dx, POW2( m_solver->c_cellLengthAtLevel( m_solver->a_level( cellId ) ) ) );
9444 // //no additional weights (may be useful for fixed boundaries)
9445
9446 if(layerId(k) > 1) {
9447 weights(k) = F0; // stencil is required also on the first halo layer from which only one additional layer is
9448 }
9449 // accessible, otherwise three halo layers are required for unique results
9450 }
9451
9452 const MInt recDim = minRecDim;
9453 maia::math::invert(mat, weights, matInv, noNghbrIds, recDim);
9454 const MFloat condNum = maia::math::frobeniusMatrixNormSquared(mat, noNghbrIds, recDim);
9455 maxCondNum0 = mMax(maxCondNum0, condNum);
9456 avgCondNum0 += condNum;
9457 condCnt0 += F1;
9458 if(condNum < F0 || condNum > condNumThreshold) {
9459 cerr << "() Warning: Image-point SVD failed (" << condNum << ") cell " << cellId << " ("
9460 << m_solver->c_globalId(cellId) << ") "
9461 << ", " << recSize << "x" << nDim + 1 << " vfrac "
9462 << m_bndryCells->a[bndryId].m_volume / m_solver->grid().gridCellVolume(m_solver->a_level(cellId))
9463 << " at timestep " << globalTimeStep << endl;
9464 for(MInt k = 0; k < recSize; k++) {
9465 cerr << m_bndryCell[bndryId].m_recNghbrIds[k] << " ";
9466 }
9467 cerr << endl;
9468 for(MInt k = 0; k < recSize; k++) {
9469 cerr << weights(k) << " ";
9470 }
9471 cerr << endl;
9472 for(MInt k = 0; k < recSize; k++) {
9473 const MFloat nghbrCellVolume =
9474 (k < noSrfcs) ? dummyCellVolume(k) : m_solver->a_cellVolume(m_bndryCell[bndryId].m_recNghbrIds[k]);
9475 cerr << nghbrCellVolume << " ";
9476 }
9477 cerr << endl;
9478 // for ( MInt k = 0; k < recSize; k++ ) { cerr << layerId(k) << " "; } cerr << endl;
9479 // for ( MInt k = 0; k < recSize; k++ ) { cerr << m_solver->a_level( m_bndryCell[ bndryId ].m_recNghbrIds[k] )
9480 // << " "; } cerr << endl; for ( MInt k = 0; k < recSize; k++ ) { cerr << m_solver->a_hasProperty( m_bndryCell[
9481 // bndryId ].m_recNghbrIds[k] , SolverCell::IsOnCurrentMGLevel) << " "; } cerr << endl;
9482 }
9483 for(MInt k = 0; k < noNghbrIds; k++) {
9484 for(MInt i = 0; i < nDim; i++) {
9485 matInv(1 + i, k) *= normalizationFactor;
9486 }
9487 }
9488 for(MInt k = 0; k < noNghbrIds; k++) {
9489 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[k] = matInv(0, k);
9490 }
9491
9492 MFloat phiSum = m_bndryCells->a[bndryId].m_gapDistance;
9493
9494 const MFloat dx0 = F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
9495 const MFloat dx1 = F2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
9496 const MFloat gapInd =
9497 F1 - mMax(F0, mMin(F1, (phiSum - dx0) / (dx1 - dx0))); // narrow gap indicator, reduce interpolation
9498 // order to increase stability
9499 if(gapInd > 1e-12) {
9500 for(MInt k = 0; k < noNghbrIds; k++) {
9501 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[k] *= (F1 - gapInd);
9502 }
9503 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[noSrfcs] += gapInd;
9504 }
9505 /*
9506 MBool reduceOrder = ( noSrfcs > 1 ) || ( phiSum < F2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId))) ;
9507 if ( reduceOrder ) { //|| m_bndryCell[ bndryId ].m_srfcs[srfc]->m_bndryCndId / 1000 != 3 ) {
9508 for ( MInt k = 0; k < noNghbrIds; k++ ) {
9509 m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_imagePointRecConst[k] = F0;
9510 }
9511 m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_imagePointRecConst[noSrfcs] = F1;
9512 } */
9513 }
9514 }
9515 if(firstRun || globalTimeStep % 100 == 0) {
9516 m_log << "Image point average (maximum) condition number: " << avgCondNum0 / condCnt0 << " (" << maxCondNum0
9517 << "), normal stress: " << avgCondNum1 / condCnt1 << " (" << maxCondNum1 << ")." << endl;
9518 }
9519
9520#ifndef NDEBUG
9521 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
9522 const MInt noSrfcs = m_bndryCells->a[bndryId].m_noSrfcs;
9523 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9524 if(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size()
9525 != m_bndryCell[bndryId].m_recNghbrIds.size()) {
9526 cerr << domainId() << ": " << bndryId << " " << srfc << " " << m_bndryCell[bndryId].m_recNghbrIds.size() << " "
9527 << m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.size() << endl;
9528 mTerm(1, AT_, "FvBndryCndXD::computeImagePointRecConst: Inconsistency 1.");
9529 }
9530 }
9531 }
9532#endif
9533
9534 firstRun = false;
9535}
9536
9537
9548template <MInt nDim, class SysEqn>
9550 TRACE();
9551
9552 if(m_smallCellRHSCorrection) {
9553 return;
9554 }
9555
9556 const MInt minRecDim = nDim + 1;
9557 const MInt medRecDim = 2 * nDim + 1;
9558 const MInt maxRecDim = m_secondOrderRec ? (IPOW2(nDim) + 2) : minRecDim;
9559 const MInt noBndryCells = m_bndryCells->size();
9560 const MInt maxNoSrfcs = 14;
9561 const MInt volFactor = nDim == 3 ? 4 : 2;
9563 mTerm(1, AT_, "Increase maxNoSrfcs. " + to_string(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces));
9564 }
9565 const MInt maxNoNghbrs = 200;
9566 const MInt noLayersStencil = m_noFluxRedistributionLayers;
9567 const MFloat condNumThreshold = 1e7;
9568 MBool& firstRun = m_static_initSmallCellCorrection_firstRun;
9569 if(noLayersStencil > mMin(m_noFluxRedistributionLayers, m_solver->noHaloLayers())) {
9570 cerr << "Warning: noLayersStencil smaller than flux redistribution layers!" << endl;
9571 }
9572 if(firstRun) m_log << "Initializing small cell treatment." << endl;
9573
9575 MFloatScratchSpace deltaXSurf(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, nDim, AT_, "deltaXSurf");
9576 MFloatScratchSpace deltaXSurfProj(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, nDim, AT_, "deltaXSurfProj");
9578 MFloatScratchSpace backup(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, maxRecDim, AT_, "backup");
9579 MFloatScratchSpace mat(maxNoNghbrs, maxRecDim, AT_, "mat_smallCells");
9580 MFloatScratchSpace matInv(maxRecDim, maxNoNghbrs, AT_, "matInv");
9581 MFloatScratchSpace weights(maxNoNghbrs, AT_, "weights");
9582
9583 MFloat maxCondNum0 = F0;
9584 MFloat maxCondNum1 = F0;
9585 MFloat avgCondNum0 = F0;
9586 MFloat avgCondNum1 = F0;
9587 MFloat condCnt0 = F0;
9588 MFloat condCnt1 = F0;
9589
9590 m_smallCutCells.clear();
9591 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
9592 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
9593 const MInt noSrfcs = m_bndryCells->a[bndryId].m_noSrfcs;
9594 MInt gridcellId = cellId;
9595 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitClone)) {
9596 gridcellId = m_solver->m_splitChildToSplitCell.find(cellId)->second;
9597 }
9598
9599 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
9600 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
9601 if(!m_solver->a_hasProperty(cellId, SolverCell::IsSplitChild) && m_solver->c_noChildren(gridcellId) > 0) continue;
9602 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
9603 if(m_solver->a_isPeriodic(cellId)) continue;
9604 if(m_solver->a_isHalo(cellId)) continue;
9605
9606 // commented version also applies smallCellCorrection for cutCells on lower levels, however
9607 // they only need to be stabilised if their volume falls below the threshold of the fines cells!
9608 // maxLevelChange
9609 const MFloat vfrac =
9610 (m_solver->m_localTS)
9611 ? m_solver->a_cellVolume(cellId) / m_solver->grid().gridCellVolume(m_solver->a_level(cellId))
9612 : m_solver->a_cellVolume(cellId) / m_solver->grid().gridCellVolume(m_solver->maxLevel());
9613 MBool atWall = false;
9614 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9615 if(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId / 1000 == 3) atWall = true;
9616 }
9617 MFloat volumeLimit = atWall ? m_volumeLimitWall : m_volumeLimitOther;
9618
9619 if(m_solver->a_level(cellId) < m_solver->maxLevel() && m_solver->m_bndryLevelJumps) {
9620 volumeLimit = volumeLimit * volFactor * (m_solver->maxLevel() - m_solver->a_level(cellId));
9621 }
9622
9623 if(vfrac < volumeLimit) {
9624 m_smallCutCells.push_back(bndryId);
9625 } else {
9626 // continue;
9627 }
9628
9629 MBool skip = false;
9630 if(updateOnlyBndryCndId > -1) {
9631 skip = true;
9632 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9633 if(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId == updateOnlyBndryCndId) skip = false;
9634 }
9635 }
9636 if(skip && vfrac < volumeLimit
9637 && m_bndryCell[bndryId].m_cellVarsRecConst.size()
9638 != IPOW2(noSrfcs) * m_bndryCell[bndryId].m_recNghbrIds.size()) {
9639 cerr << domainId() << ": strange skip " << cellId << " " << m_solver->c_globalId(cellId) << endl;
9640 }
9641 if(skip) continue;
9642
9643 const MFloat normalizationFactor =
9644 FPOW2(m_solver->a_level(cellId))
9645 / m_solver->c_cellLengthAtLevel(0); // scaling factor to reduce the condition number of the resulting eq. sys.
9646 const MInt recSize = m_bndryCell[bndryId].m_recNghbrIds.size();
9647 ASSERT(recSize > 0, "");
9648
9649 MFloatScratchSpace dummyCoordinates(noSrfcs, nDim, AT_, "dummyCoordinates");
9650 MIntScratchSpace dummyLevel(noSrfcs, AT_, "dummyLevel");
9651 MFloatScratchSpace dummyCellVolume(noSrfcs, AT_, "dummyCellVolume");
9652
9653 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9654 deltaNSurf[srfc] = F0;
9655 for(MInt i = 0; i < nDim; i++) {
9656 normal(srfc, i) = m_bndryCell[bndryId].m_srfcs[srfc]->m_normalVector[i];
9657 deltaNSurf[srfc] +=
9658 normal(srfc, i)
9659 * (m_solver->a_coordinate(cellId, i) - m_bndryCell[bndryId].m_srfcs[srfc]->m_coordinates[i]);
9660 }
9661 for(MInt i = 0; i < nDim; i++) {
9662 deltaXSurf(srfc, i) = m_bndryCell[bndryId].m_srfcs[srfc]->m_coordinates[i]
9663 - m_solver->a_coordinate(cellId, i); // Futile, see lines below!
9664 deltaXSurfProj(srfc, i) = -mMax(1e-12, deltaNSurf[srfc]) * normal(srfc, i);
9665 deltaXSurf(srfc, i) = deltaXSurfProj(srfc, i);
9666 }
9667
9668 const MInt dummyId = m_bndryCell[bndryId].m_recNghbrIds[srfc]; // dummyIds(srfc);
9669 dummyLevel[srfc] = m_solver->a_level(cellId);
9670 dummyCellVolume(srfc) = m_solver->grid().gridCellVolume(m_solver->a_level(cellId));
9671 m_solver->a_bndryId(dummyId) = -1;
9672 for(MInt i = 0; i < nDim; i++) {
9673 dummyCoordinates(srfc, i) = m_solver->a_coordinate(cellId, i) + deltaXSurfProj(srfc, i);
9674 }
9675 }
9676
9677 mat.fill(F0);
9678 weights.fill(F0);
9679
9680 MFloat counter = F0;
9681 for(MInt k = 0; k < recSize; k++) {
9682 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[k];
9683 const MInt nghbrLevel = (k < noSrfcs) ? dummyLevel[k] : m_solver->a_level(nghbrId);
9684 const MFloat nghbrCellVolume = (k < noSrfcs) ? dummyCellVolume(k) : m_solver->a_cellVolume(nghbrId);
9685 counter += (m_solver->a_bndryId(nghbrId) > -1)
9686 ? maia::math::deltaFun(nghbrCellVolume / m_solver->grid().gridCellVolume(nghbrLevel), 1e-8, F1)
9687 : F1;
9688 }
9689 const MInt recDim = mMax(
9690 minRecDim, (counter > (MFloat)maxRecDim) ? maxRecDim : ((counter > (MFloat)medRecDim) ? medRecDim : minRecDim));
9691 // const MInt recDim = maxRecDim;
9692 const MInt recDim2 = minRecDim;
9693 ASSERT(minRecDim, "");
9694 ASSERT(medRecDim, "");
9695
9696 for(MInt k = 0; k < recSize; k++) {
9697 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[k]; // nghbrList(k);
9698 const MFloat* const nghbrCoord = (k < noSrfcs) ? &dummyCoordinates(k, 0) : &(m_solver->a_coordinate(nghbrId, 0));
9699 const MInt nghbrLevel = (k < noSrfcs) ? dummyLevel[k] : m_solver->a_level(nghbrId);
9700 const MFloat nghbrCellVolume = (k < noSrfcs) ? dummyCellVolume(k) : m_solver->a_cellVolume(nghbrId);
9701 MFloat deltaX[3];
9702 MFloat dx = F0;
9703 for(MInt i = 0; i < nDim; i++) {
9704 deltaX[i] = (nghbrCoord[i] - m_solver->a_coordinate(cellId, i)) * normalizationFactor;
9705 dx += POW2(nghbrCoord[i] - m_solver->a_coordinate(cellId, i));
9706 }
9707
9708 MFloat nfac = F1;
9709 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9710 MFloat dn = F0;
9711 for(MInt i = 0; i < nDim; i++) {
9712 dn += (nghbrCoord[i] - m_bndryCell[bndryId].m_srfcs[srfc]->m_coordinates[i]) * normal(srfc, i);
9713 }
9714 MFloat deltan = 0.1 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
9715 nfac *= mMin(F1, mMax(F0, (dn + deltan) / deltan));
9716 // nfac *= mMin( F1, mMax( F0, (dn+deltan)/(F2*deltan) ) );
9717 }
9718 if(noSrfcs > 1) nfac = F1;
9719 // nfac=F1;
9720
9721 weights(k) = maia::math::RBF(dx, POW2(m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId))))
9722 * maia::math::deltaFun(nghbrCellVolume / m_solver->grid().gridCellVolume(nghbrLevel), 1e-8, 1.0);
9723
9724 if(k > noSrfcs) weights(k) *= nfac; // do not remove (stability)!
9725
9726 MInt cnt = 0;
9727 mat(k, cnt) = F1;
9728 cnt++;
9729 for(MInt i = 0; i < nDim; i++) {
9730 mat(k, cnt) = deltaX[i];
9731 cnt++;
9732 }
9733 for(MInt i = 0; i < nDim; i++) {
9734 if(cnt >= recDim) continue;
9735 mat(k, cnt) = F1B2 * POW2(deltaX[i]);
9736 cnt++;
9737 }
9738 for(MInt i = 0; i < nDim; i++) {
9739 for(MInt j = i + 1; j < nDim; j++) {
9740 if(cnt >= recDim) continue;
9741 mat(k, cnt) = deltaX[i] * deltaX[j];
9742 cnt++;
9743 }
9744 }
9745 }
9746
9747
9748 maia::math::invert(mat, weights, matInv, recSize, recDim);
9749 const MFloat condNum = maia::math::frobeniusMatrixNormSquared(mat, recSize, recDim);
9750
9751 maxCondNum0 = mMax(maxCondNum0, condNum);
9752 avgCondNum0 += condNum;
9753 condCnt0 += F1;
9754 if(condNum < F0 || condNum > condNumThreshold) {
9755 cerr << "(1) Warning: SVD failed (" << condNum << ") cell " << cellId << " (" << m_solver->c_globalId(cellId)
9756 << ") "
9757 << ", " << recSize << "x" << recDim << " vfrac " << setprecision(14)
9758 << m_bndryCells->a[bndryId].m_volume / m_solver->grid().gridCellVolume(m_solver->a_level(cellId))
9759 << setprecision(6) << ", p13: " << m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)
9760 << ", p15: " << m_solver->a_isHalo(cellId) << " at timestep " << globalTimeStep
9761 << ", coords: " << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 10) << " "
9762 << m_solver->a_coordinate(cellId, mMin(nDim - 1, 2)) << endl;
9763 // for ( MInt k = 0; k < recSize; k++ ) cerr << nghbrList(k) << " "; cerr << endl;
9764 // for ( MInt k = 0; k < recSize; k++ ) cerr << weights(k) << " "; cerr << endl;
9765
9766 const MFloat rank = maia::math::invertR(mat, weights, matInv, recSize, minRecDim);
9767 if(rank >= min(recSize, minRecDim)) {
9768 cerr << "Succeeded using reduced-order reconstruction." << endl;
9769 } else {
9770 cerr << "Failed also with reduced-order reconstruction, using fallback solution." << endl;
9771 }
9772 }
9773
9774 for(MInt k = 0; k < recSize; k++) {
9775 MInt cnt = 1;
9776 for(MInt i = 0; i < nDim; i++) {
9777 matInv(cnt, k) *= normalizationFactor;
9778 cnt++;
9779 }
9780 for(cnt = nDim + 1; cnt < recDim; cnt++) {
9781 matInv(cnt, k) *= POW2(normalizationFactor);
9782 }
9783 }
9784
9785 // for single boundary surface there is a Dirichlet and a Neumann stencil for the different
9786 // boundary conditions for multiple boundary surfaces, there can be combinations of
9787 // Neumann-Dirichlet or Dirichlet-Neumann boundary conditions, e.g., when a solid wall and an
9788 // outflow boundary intersect the cell, therefore IPOW2(noSrfcs) combinations
9789 m_bndryCell[bndryId].m_cellVarsRecConst.resize(recSize * IPOW2(noSrfcs));
9790 for(MInt p = 0; p < recSize; p++) {
9791 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * p] = matInv(0, p);
9792 }
9793
9794 // first and second derivatives at the cell centroid
9795 MInt noDerivs = maxRecDim - 1;
9796 m_bndryCell[bndryId].m_cellDerivRecConst.resize(noDerivs * recSize);
9797 std::fill_n(m_bndryCell[bndryId].m_cellDerivRecConst.begin(), noDerivs * recSize, F0);
9798 for(MInt k = 1; k < recDim; k++) {
9799 MInt id = k - 1;
9800 for(MInt p = 0; p < recSize; p++) {
9801 m_bndryCell[bndryId].m_cellDerivRecConst[noDerivs * p + id] = matInv(k, p);
9802 }
9803 }
9804
9805 if(condNum < F0 || condNum > condNumThreshold) {
9806 MFloat sumcnt = F0;
9807 for(MInt k = 0; k < recSize; k++) {
9808 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[k]; // nghbrList(k);
9809 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k] = F0;
9810 if(nghbrId == cellId) continue;
9811 MFloat dx = F0;
9812 for(MInt i = 0; i < nDim; i++) {
9813 dx += POW2(m_solver->a_coordinate(nghbrId, i) - m_solver->a_coordinate(cellId, i));
9814 }
9815 MFloat volume = m_solver->a_cellVolume(nghbrId);
9816 MFloat fac =
9817 maia::math::deltaFun(volume / m_solver->grid().gridCellVolume(m_solver->a_level(nghbrId)), 1e-8, 1.0);
9818 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k] = fac / mMax(1e-14, sqrt(dx));
9819 sumcnt += m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k];
9820 }
9821 for(MInt k = 0; k < recSize; k++) {
9822 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k] /= sumcnt;
9823 }
9824 }
9825
9826
9827 // backup Dirichlet stencil above
9828 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9829 for(MInt k = 0; k < recDim; k++) {
9830 backup(srfc, k) = mat(srfc, k);
9831 }
9832
9833 // !!!!!!!!!!!!!!!!!!!!!!!
9834 // !!!!!!!!!!!!!!!!!!!!!!!
9835 if(m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[PV->RHO] == BC_ISOTHERMAL) {
9836 weights(srfc) = F0; // !!!!!!!!!!!!!!!!!!!!!!! (extrapolation)
9837 }
9838 // !!!!!!!!!!!!!!!!!!!!!!!
9839 // !!!!!!!!!!!!!!!!!!!!!!!
9840 }
9841 for(MInt s = 1; s < IPOW2(noSrfcs); s++) { // zero'th bitset corresponds to full Dirichlet stencil determined above
9842 bitset<maxNoSrfcs> NeumannCode(s);
9843 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9844 if(NeumannCode.test(srfc)) {
9845 MFloat deltaX[3];
9846 MInt cnt = 1;
9847 const MFloat beta = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_robinFactor;
9848 if(std::isnan(beta)) cerr << "nan" << endl;
9849 // mat(srfc,0) = F0 ;
9850 mat(srfc, 0) = beta;
9851 for(MInt i = 0; i < nDim; i++) {
9852 deltaX[i] = deltaXSurfProj(srfc, i) * normalizationFactor;
9853 // mat( srfc , cnt ) = normal(srfc,i);
9854 mat(srfc, cnt) = normal(srfc, i) + beta * deltaX[i]; // Old line
9855 // mat(srfc, cnt) = normal(srfc, i) * normalizationFactor + beta * deltaX[i]; //TODO:Verify
9856 cnt++;
9857 }
9858 for(MInt i = 0; i < nDim; i++) {
9859 if(cnt >= recDim2) continue;
9860 // mat( srfc , cnt ) = normal(srfc,i) * deltaX[ i ];
9861 mat(srfc, cnt) = normal(srfc, i) * deltaX[i] + beta * F1B2 * POW2(deltaX[i]); // Old line
9862 // mat(srfc, cnt) = normal(srfc, i) * normalizationFactor * deltaX[i] + beta * F1B2 * POW2(deltaX[i]);
9863 cnt++;
9864 }
9865 for(MInt i = 0; i < nDim; i++) {
9866 for(MInt j = i + 1; j < nDim; j++) {
9867 if(cnt >= recDim2) continue;
9868 // mat( srfc , cnt ) = normal(srfc,i) * deltaX[ j ] + normal(srfc,j) * deltaX[ i ];
9869 // TODO: check
9870 // mat(srfc, cnt) = normal(srfc, i) * normalizationFactor * deltaX[j] + normal(srfc, j) *
9871 // normalizationFactor * deltaX[i] + beta * deltaX[i] * deltaX[j];
9872 mat(srfc, cnt) = normal(srfc, i) * deltaX[j] + normal(srfc, j) * deltaX[i] + beta * deltaX[i] * deltaX[j];
9873 cnt++;
9874 }
9875 }
9876 } else {
9877 for(MInt k = 0; k < recDim; k++) {
9878 mat(srfc, k) = backup(srfc, k);
9879 }
9880 }
9881 }
9882
9883 ASSERT(recDim2 <= recDim, "");
9884 maia::math::invert(mat, weights, matInv, recSize, recDim2);
9885 const MFloat condNum2 = maia::math::frobeniusMatrixNormSquared(mat, recSize, recDim2);
9886 maxCondNum1 = mMax(maxCondNum1, condNum2);
9887 avgCondNum1 += condNum;
9888 condCnt1 += F1;
9889 if(condNum2 < F0 || condNum2 > condNumThreshold) {
9890 cerr << "(2) Warning: SVD failed (" << condNum2 << ") cell " << cellId << " (" << m_solver->c_globalId(cellId)
9891 << ") "
9892 << ", " << recSize << "x" << recDim2 << " vfrac "
9893 << m_bndryCells->a[bndryId].m_volume / m_solver->grid().gridCellVolume(m_solver->a_level(cellId)) << endl;
9894 }
9895
9896 for(MInt k = 0; k < recSize; k++) {
9897 MInt cnt = 1;
9898 for(MInt i = 0; i < nDim; i++) {
9899 matInv(cnt, k) *= normalizationFactor;
9900 cnt++;
9901 }
9902 for(cnt = nDim + 1; cnt < recDim2; cnt++) {
9903 matInv(cnt, k) *= POW2(normalizationFactor);
9904 }
9905 }
9906 for(MInt p = 0; p < recSize; p++) {
9907 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * p + s] = matInv(0, p);
9908 }
9909
9910 // fallback solution: inverse distance weighting
9911 if(condNum2 < F0 || condNum2 > condNumThreshold) {
9912 MFloat sumcnt = F0;
9913 for(MInt k = 0; k < recSize; k++) {
9914 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[k]; // nghbrList(k);
9915 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k + s] = F0;
9916 if(nghbrId == cellId) continue;
9917 if(k < noSrfcs) continue;
9918 MFloat dx = F0;
9919 for(MInt i = 0; i < nDim; i++) {
9920 dx += POW2(m_solver->a_coordinate(nghbrId, i) - m_solver->a_coordinate(cellId, i));
9921 }
9922 MFloat volume = m_solver->a_cellVolume(nghbrId);
9923 MFloat fac =
9924 maia::math::deltaFun(volume / m_solver->grid().gridCellVolume(m_solver->a_level(nghbrId)), 1e-8, 1.0);
9925 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k + s] = fac / mMax(1e-14, sqrt(dx));
9926 sumcnt += m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k + s];
9927 }
9928 for(MInt k = 0; k < recSize; k++) {
9929 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k + s] /= sumcnt;
9930 }
9931 }
9932 }
9933 }
9934 if(firstRun || globalTimeStep % 100 == 0) {
9935 m_log << "Small cell treatment average (maximum) condition numbers == Dirichlet stencil: " << avgCondNum0 / condCnt0
9936 << " (" << maxCondNum0 << "), Neumann stencil: " << avgCondNum1 / condCnt1 << " (" << maxCondNum1 << ")."
9937 << endl;
9938 }
9939
9940 MLong smallCells = m_smallCutCells.size();
9941 MPI_Allreduce(MPI_IN_PLACE, &smallCells, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "smallCells");
9942
9943 if(firstRun || globalTimeStep % 100 == 0) {
9944 m_log << "Number of small cut cells for flux redistribution: " << m_smallCutCells.size() << "; global "
9945 << smallCells << endl;
9946 }
9947#ifndef NDEBUG
9948 /*
9949 for( MInt bndryId = 0; bndryId < noBndryCells; bndryId++ ) {
9950 const MInt noSrfcs = m_bndryCells->a[bndryId].m_noSrfcs;
9951 for(MInt srfc = 0; srfc < noSrfcs; srfc++){
9952 if ( m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_imagePointRecConst.size() !=
9953 m_bndryCell[ bndryId ].m_recNghbrIds.size() ) { cerr << domainId() << ": " << bndryId << " " <<
9954 srfc << " " << m_bndryCell[ bndryId ].m_recNghbrIds.size()
9955 << " " << m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_imagePointRecConst.size()
9956 << endl; mTerm(1,AT_, "FvBndryCndXD::bcInitSmallCellCorrection: Inconsistency 1.");
9957 }
9958 }
9959 }*/
9960 for(MUint smallc = 0; smallc < m_smallCutCells.size(); smallc++) {
9961 const MInt bndryId = m_smallCutCells[smallc];
9962 const MInt noSrfcs = m_bndryCells->a[bndryId].m_noSrfcs;
9963 if(m_bndryCell[bndryId].m_cellVarsRecConst.size() != IPOW2(noSrfcs) * m_bndryCell[bndryId].m_recNghbrIds.size()) {
9964 cerr << m_bndryCell[bndryId].m_cellVarsRecConst.size() << " "
9965 << IPOW2(noSrfcs) * m_bndryCell[bndryId].m_recNghbrIds.size() << " "
9966 << m_solver->a_isHalo(m_bndryCells->a[bndryId].m_cellId) << endl;
9967 mTerm(1, AT_, "FvBndryCndXD::initSmallCellCorrection: Inconsistency 1.");
9968 }
9969 }
9970#endif
9971
9972 firstRun = false;
9973}
9974
9975
9984template <MInt nDim, class SysEqn>
9986 TRACE();
9987
9988 static constexpr MInt cornerIndices[8][3] = {{-1, -1, -1}, {1, -1, -1}, {-1, 1, -1}, {1, 1, -1},
9989 {-1, -1, 1}, {1, -1, 1}, {-1, 1, 1}, {1, 1, 1}};
9990 MFloat corner[3] = {0, 0, 0};
9991 MBool inside = true;
9992 MFloat cellHalfLength = F1B2 * m_solver->c_cellLengthAtCell(cellId);
9993
9994 for(MInt i = 0; i < m_noCorners; i++) {
9995 for(MInt dim = 0; dim < nDim; dim++) {
9996 corner[dim] = m_solver->c_coordinate(cellId, dim) + cornerIndices[i][dim] * cellHalfLength;
9997 }
9998 IF_CONSTEXPR(nDim == 2) {
9999 if((MBool)m_solver->m_geometry->pointIsInside(corner)) {
10000 inside = false; // pointIsInside == true if Point is outside fluid domain
10001 }
10002 }
10003 else {
10004 if((MBool)m_solver->m_geometry->pointIsInside2(corner)) {
10005 inside = false; // pointIsInside == true if Point is outside fluid domain
10006 }
10007 }
10008 }
10009
10010 return inside;
10011}
10012
10013template <MInt nDim, class SysEqn>
10015 TRACE();
10016 static constexpr MInt cornerIndices[8][3] = {{-1, -1, -1}, {1, -1, -1}, {-1, 1, -1}, {1, 1, -1},
10017 {-1, -1, 1}, {1, -1, 1}, {-1, 1, 1}, {1, 1, 1}};
10018 MFloat corner[3] = {0, 0, 0};
10019 MBool outside = true;
10020 MFloat cellHalfLength = F1B2 * m_solver->c_cellLengthAtCell(cellId);
10021
10022 for(MInt i = 0; i < m_noCorners; i++) {
10023 for(MInt dim = 0; dim < nDim; dim++) {
10024 corner[dim] = m_solver->c_coordinate(cellId, dim) + cornerIndices[i][dim] * cellHalfLength;
10025 }
10026 IF_CONSTEXPR(nDim == 2) {
10027 if(!m_solver->m_geometry->pointIsInside(corner)) {
10028 outside = false; // pointIsInside == true if Point is outside fluid domain
10029 }
10030 }
10031 else {
10032 if(!m_solver->m_geometry->pointIsInside2(corner)) {
10033 outside = false; // pointIsInside == true if Point is outside fluid domain
10034 }
10035 }
10036 }
10037 return outside;
10038}
10039
10040template <MInt nDim, class SysEqn>
10042 TRACE();
10043 static constexpr MInt cornerIndices[8][3] = {{-1, -1, -1}, {1, -1, -1}, {-1, 1, -1}, {1, 1, -1},
10044 {-1, -1, 1}, {1, -1, 1}, {-1, 1, 1}, {1, 1, 1}};
10045 MFloat corner[3] = {0, 0, 0};
10046 MBool outside = true;
10047 MFloat cellHalfLength = F1B2 * m_solver->c_cellLengthAtLevel(level);
10048
10049 for(MInt i = 0; i < m_noCorners; i++) {
10050 for(MInt dim = 0; dim < nDim; dim++) {
10051 corner[dim] = coords[dim] + cornerIndices[i][dim] * cellHalfLength;
10052 }
10053 IF_CONSTEXPR(nDim == 2) {
10054 if(!m_solver->m_geometry->pointIsInside(corner)) {
10055 outside = false; // pointIsInside == true if Point is outside fluid domain
10056 }
10057 }
10058 else {
10059 if(!m_solver->m_geometry->pointIsInside2(corner)) {
10060 outside = false; // pointIsInside == true if Point is outside fluid domain
10061 }
10062 }
10063 }
10064 return outside;
10065}
10066
10067
10079template <MInt nDim, class SysEqn>
10081 TRACE();
10082
10097 MBool bndryRfnJump = false;
10098 bndryRfnJump = Context::getSolverProperty<MBool>("bndryRfnJump", m_solverId, AT_, &bndryRfnJump);
10099
10100 const MBool redirect = true;
10101 if(redirect && !bndryRfnJump) {
10102 m_cutCandidates.clear();
10103 m_cutCandidates.reserve((signed)m_bndryCells->size());
10104
10105
10106 for(MInt bndryId = 0; bndryId < (signed)m_bndryCells->size(); bndryId++) {
10107 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
10108 ASSERT((signed)m_cutCandidates.size() == bndryId, "");
10109 m_cutCandidates.emplace_back();
10110 m_cutCandidates[bndryId].cellId = cellId;
10111 m_solver->assertValidGridCellId(cellId);
10112 }
10113
10114 ASSERT((signed)m_cutCandidates.size() == (signed)m_bndryCells->size(), "");
10115
10116 m_noBndryCndIds = 0;
10117 m_noCutOffBndryCndIds = 0;
10118
10119 m_geometryIntersection->computeCutPointsFromSTL(m_cutCandidates);
10120
10121 // copy to bndrycnd-data
10122
10123 for(MInt cndt = 0; cndt < (signed)m_cutCandidates.size(); cndt++) {
10124 const MInt bndryCndId = m_cutCandidates[cndt].associatedBodyIds[0];
10125
10126 if(bndryCndId > 9999999) {
10127 m_bndryCells->a[cndt].m_srfcs[0]->m_bndryCndId = 9999999;
10128 m_bndryCells->a[cndt].m_srfcs[0]->m_noCutPoints = 0;
10129 ASSERT(m_cutCandidates[cndt].noCutPoints == 0, "");
10130 continue;
10131 }
10132
10133 // check if its a new bndryCndId:
10134 MBool newBndryCnd = true;
10135 for(MInt j = 0; j < m_noBndryCndIds; j++) {
10136 if(m_bndryCndIds[j] == bndryCndId) {
10137 newBndryCnd = false;
10138 break;
10139 }
10140 }
10141 if(newBndryCnd) {
10142 m_bndryCndIds[m_noBndryCndIds] = bndryCndId;
10143 m_noBndryCndIds++;
10144 }
10145
10146 const MInt noCutPoints = m_cutCandidates[cndt].noCutPoints;
10147 m_bndryCells->a[cndt].m_srfcs[0]->m_noCutPoints = noCutPoints;
10148 IF_CONSTEXPR(nDim == 2) { ASSERT(noCutPoints <= 2, ""); }
10149
10150 m_bndryCells->a[cndt].m_srfcs[0]->m_bndryCndId = bndryCndId;
10151
10152 for(MInt cutPoint = 0; cutPoint < noCutPoints; cutPoint++) {
10153 m_bndryCells->a[cndt].m_srfcs[0]->m_cutEdge[cutPoint] = m_cutCandidates[cndt].cutEdges[cutPoint];
10154 m_bndryCells->a[cndt].m_srfcs[0]->m_bodyId[cutPoint] = m_cutCandidates[cndt].cutBodyIds[cutPoint];
10155 for(MInt i = 0; i < nDim; i++) {
10156 m_bndryCells->a[cndt].m_srfcs[0]->m_cutCoordinates[cutPoint][i] =
10157 m_cutCandidates[cndt].cutPoints[cutPoint][i];
10158 }
10159 }
10160 }
10161
10162 if(m_solver->m_geometry->m_parallelGeometry) {
10163 checkCutPointsValidityParGeom();
10164 } else {
10165 checkCutPointsValidity();
10166 }
10167
10168 // sort m_bndryCndIds for multiple stg BC to prevent MPI error
10169 if(m_solver->m_zonal) {
10170 ScratchSpace<MFloat> sorting(m_noBndryCndIds, "sorting", FUN_);
10171 vector<int> sortingIndex(m_noBndryCndIds);
10172 for(MInt i = 0; i < m_noBndryCndIds; i++) {
10173 sorting[i] = m_bndryCndIds[i];
10174 }
10175 int x = 0;
10176 std::iota(sortingIndex.begin(), sortingIndex.end(), x++); // Initializing
10177 sort(sortingIndex.begin(), sortingIndex.end(), [&](int i, int j) { return sorting[i] < sorting[j]; });
10178
10179 for(MInt bcId = 0; bcId < m_noBndryCndIds; bcId++) {
10180 m_bndryCndIds[bcId] = sorting[sortingIndex[bcId]];
10181 }
10182 }
10183
10184 return;
10185 }
10186
10187 const MInt DOFStencil[12] = {1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
10188 const MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
10189 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
10190
10191 const MInt nodeStencil[2][12] = {{0, 1, 0, 2, 4, 5, 4, 6, 0, 1, 2, 3}, {2, 3, 1, 3, 6, 7, 5, 7, 4, 5, 6, 7}};
10192 const MInt noCells = m_bndryCells->size();
10193 const MFloat epsilon = 0.00000000001;
10194 const MInt maxNoCutPointsPerEdge = 10;
10195 MFloatScratchSpace a(nDim, AT_, "a_scratch");
10196 MFloatScratchSpace b(nDim, AT_, "b_scratch");
10197 MFloatScratchSpace c(nDim, AT_, "c_scratch");
10198 MFloatScratchSpace d(nDim, AT_, "d_scratch");
10199 MFloatScratchSpace e(nDim, AT_, "e_scratch");
10200 MFloatScratchSpace pP(nDim, AT_, "pP_scratch");
10201 MFloat target[6] = {0, 0, 0, 0, 0, 0};
10202 MFloatScratchSpace cutPointsEdge(maxNoCutPointsPerEdge, nDim, AT_, "cutPointsEdge");
10203 MFloatScratchSpace corners(m_noCorners, nDim, AT_, "corners");
10204 MFloatScratchSpace center(nDim, AT_, "center");
10205 //--- end of initialization
10206
10207 m_noBndryCndIds = 0;
10208 m_noCutOffBndryCndIds = 0;
10209
10210 // first loop over all bndry cells
10211 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
10212 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
10213 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints = 0;
10214 m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId = 9999999;
10215
10216 if(m_solver->c_noChildren(cellId) > 0) continue;
10217
10218 MFloat cellHalfLength = F1B2 * m_solver->c_cellLengthAtCell(cellId);
10219
10220 // compute cell corners -> will be used for cut point computation
10221 for(MInt i = 0; i < nDim; i++) {
10222 center[i] = m_solver->a_coordinate(cellId, i);
10223 }
10224 for(MInt n = 0; n < m_noCorners; n++) {
10225 for(MInt i = 0; i < nDim; i++) {
10226 corners(n, i) = center[i] + signStencil[n][i] * cellHalfLength;
10227 }
10228 }
10229
10230 // Define corners of current cell in target
10231 for(MInt i = 0; i < nDim; i++) {
10232 target[i] = center[i] - cellHalfLength * 1.05;
10233 target[i + nDim] = center[i] + cellHalfLength * 1.05;
10234 }
10235 MFloat eps = m_solver->c_cellLengthAtCell(cellId) / 10000000.0;
10236
10237 // get all triangles in currentCell (target)
10238 std::vector<MInt> nodeList;
10239 if(m_gridCutTest == "SAT") {
10240 m_solver->m_geometry->getIntersectionElements(target, nodeList, cellHalfLength,
10241 &m_solver->a_coordinate(cellId, 0));
10242 } else {
10243 m_solver->m_geometry->getIntersectionElements(target, nodeList);
10244 }
10245
10246 // loop over all edges
10247 for(MInt edge = 0; edge < m_noEdges; edge++) {
10248 const MInt edgeDOF = DOFStencil[edge]; // edge's degree of freedom
10249
10250 MInt noCutPointsEdge = 0;
10251 MBool edgeCut = false;
10252
10253 // compute end points of edge
10254 for(MInt i = 0; i < nDim; i++) {
10255 d[i] = corners(nodeStencil[0][edge], i);
10256 e[i] = corners(nodeStencil[1][edge], i);
10257 }
10258
10259 // check for edge-triangle intersection
10260 for(MInt n = 0; n < (signed)nodeList.size(); n++) {
10261 MBool cutsEdge = false;
10262 // const MInt bndryCndId = m_solver->m_geometry->elements[nodeList[n]].m_bndCndId;
10263
10264 IF_CONSTEXPR(nDim == 3) {
10265 const MInt spaceId = (edgeDOF + 1) % nDim;
10266 const MInt spaceId1 = (edgeDOF + 2) % nDim;
10267 const MInt spaceId2 = edgeDOF;
10268 // find out if element cuts edge; if yes, compute cut point -> 3D part
10269 MFloat p = F0;
10270 MFloat q = F0;
10271 for(MInt k = 0; k < nDim; k++) {
10272 a[k] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[0][k];
10273 b[k] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[1][k];
10274 c[k] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[2][k];
10275 }
10276 if(approx(a[spaceId1], b[spaceId1], MFloatEps) && !approx(a[spaceId1], c[spaceId1], MFloatEps)) {
10277 // aspaceId != bspaceId, otherwise a and b would be the same point
10278 q = (d[spaceId1] - a[spaceId1]) / (c[spaceId1] - a[spaceId1]);
10279 p = (d[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
10280 } else {
10281 if(!approx(a[spaceId1], b[spaceId1], MFloatEps) && approx(a[spaceId1], c[spaceId1], MFloatEps)) {
10282 // aspaceId != cspaceId, otherwise a and c would be the same point
10283 p = (d[spaceId1] - a[spaceId1]) / (b[spaceId1] - a[spaceId1]);
10284 q = (d[spaceId] - a[spaceId] - p * (b[spaceId] - a[spaceId])) / (c[spaceId] - a[spaceId]);
10285 } else {
10286 if(approx(a[spaceId], b[spaceId], MFloatEps) && !approx(a[spaceId], c[spaceId], MFloatEps)) {
10287 // aspaceId1 != bspaceId1, otherwise a and b would be the same point
10288 q = (d[spaceId] - a[spaceId]) / (c[spaceId] - a[spaceId]);
10289 p = (d[spaceId1] - a[spaceId1] - q * (c[spaceId1] - a[spaceId1])) / (b[spaceId1] - a[spaceId1]);
10290 } else {
10291 if(!approx(a[spaceId], b[spaceId], MFloatEps) && approx(a[spaceId], c[spaceId], MFloatEps)) {
10292 // aspaceId1 != cspaceId1, otherwise a and c would be the same point
10293 p = (d[spaceId] - a[spaceId]) / (b[spaceId] - a[spaceId]);
10294 q = (d[spaceId1] - a[spaceId1] - p * (b[spaceId1] - a[spaceId1])) / (c[spaceId1] - a[spaceId1]);
10295 } else {
10296 // aspaceId1 != bspaceId1 && aspaceId1 != cspaceId1 && aspaceId != bspaceId && aspaceId != cspaceId
10297 q = ((d[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
10298 - (b[spaceId1] - a[spaceId1]) * (d[spaceId] - a[spaceId]))
10299 / ((c[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
10300 - (b[spaceId1] - a[spaceId1]) * (c[spaceId] - a[spaceId]));
10301 p = (d[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
10302 }
10303 }
10304 }
10305 }
10306
10307
10308 if(p * q >= 0 || p * q < 0) {
10309 // compute s
10310 MFloat gamma = a[spaceId2] + p * (b[spaceId2] - a[spaceId2]) + q * (c[spaceId2] - a[spaceId2]);
10311 MFloat s = (gamma - d[spaceId2]) / (e[spaceId2] - d[spaceId2]);
10312
10313 if(s < -epsilon || s > F1 + epsilon || p < -epsilon || q < -epsilon || (p + q) > F1 + epsilon) {
10314 } else {
10315 cutsEdge = true;
10316 // cut point pP
10317 if(noCutPointsEdge < 10) {
10318 for(MInt k = 0; k < nDim; k++) {
10319 pP[k] = d[k] + s * (e[k] - d[k]);
10320 cutPointsEdge(noCutPointsEdge, k) = pP[k];
10321 }
10322 } else {
10323 mTerm(1, AT_, " Too many cut points on edge...");
10324 }
10325 }
10326 }
10327 }
10328 else { // 2D code
10329 if(m_solver->m_geometry->edgeTriangleIntersection(m_solver->m_geometry->elements[nodeList[n]].m_vertices[0],
10330 m_solver->m_geometry->elements[nodeList[n]].m_vertices[1],
10331 0, d.getPointer(), e.getPointer())) {
10332 for(MInt k = 0; k < nDim; k++) {
10333 a[k] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[0][k];
10334 b[k] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[1][k];
10335 }
10336
10337 MFloat gamma = (b[0] - a[0]) * (d[1] - e[1]) - (d[0] - e[0]) * (b[1] - a[1]);
10338 if(ABS(gamma) < 0.0000000000001) continue;
10339 MFloat s1 = ((d[0] - e[0]) * (a[1] - d[1]) - (d[1] - e[1]) * (a[0] - d[0])) / gamma;
10340 MFloat s2 = ((b[0] - a[0]) * (d[1] - a[1]) - (d[0] - a[0]) * (b[1] - a[1])) / gamma;
10341
10342 cutsEdge = true;
10343
10344 // cut point pP
10345 if(noCutPointsEdge < 10) {
10346 for(MInt k = 0; k < nDim; k++) {
10347 if(s1 * s1 < s2 * s2) {
10348 pP[k] = d[k] + s2 * (e[k] - d[k]);
10349 } else {
10350 pP[k] = a[k] + s1 * (b[k] - a[k]);
10351 }
10352 cutPointsEdge(noCutPointsEdge, k) = pP[k];
10353 }
10354 } else {
10355 mTerm(1, AT_, " Too many cut points on edge...");
10356 }
10357 }
10358 }
10359
10360 if(cutsEdge) {
10361 // store cut point
10362 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints < m_noEdges) {
10363 // set boundary condition (the one with the lowest Id
10364 if(m_solver->m_geometry->elements[nodeList[n]].m_bndCndId
10365 < m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId) {
10366 m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId =
10367 m_solver->m_geometry->elements[nodeList[n]].m_bndCndId;
10368 MBool newBndryCnd = true;
10369 for(MInt j = 0; j < m_noBndryCndIds; j++) {
10370 if(m_bndryCndIds[j] == m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId) {
10371 newBndryCnd = false;
10372 break;
10373 }
10374 }
10375 if(newBndryCnd) {
10376 m_bndryCndIds[m_noBndryCndIds] = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
10377 if(m_noBndryCndIds < m_maxNoBndryCndIds) {
10378 m_noBndryCndIds++;
10379 } else {
10380 mTerm(1, AT_, "Too many different boundary conditions...");
10381 }
10382 }
10383 }
10384
10385 // if this edge has already one cut point, check if the new cut point is a different one
10386 if(edgeCut) {
10387 // if the cut point is identical to onother one, special treatment is needed
10388
10389 MBool newCutPoint = true;
10390 for(MInt i = 0; i < noCutPointsEdge; i++) {
10391 MBool equal = (ABS(pP[0] - cutPointsEdge(i, 0)) < eps && ABS(pP[1] - cutPointsEdge(i, 1)) < eps);
10392 IF_CONSTEXPR(nDim == 3) equal = (equal && (ABS(pP[2] - cutPointsEdge(i, 2)) < eps));
10393 if(equal) {
10394 newCutPoint = false;
10395 break;
10396 }
10397 }
10398
10399 if(newCutPoint) {
10400 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints--;
10401 m_log << "removing two cut points, cell " << cellId << " edge " << edge << endl;
10402 m_log << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1) << " ";
10403 IF_CONSTEXPR(nDim == 3) m_log << m_solver->a_coordinate(cellId, 2) << endl;
10404 edgeCut = false;
10405 noCutPointsEdge++;
10406 } else {
10407 // coinciding cut points
10408 // ignoring one cut point
10409 }
10410 } else {
10411 // check, if cut point is really new!
10412 MBool newCutPoint = true;
10413 for(MInt i = 0; i < noCutPointsEdge; i++) {
10414 MBool equal = (ABS(pP[0] - cutPointsEdge(i, 0)) <= eps && ABS(pP[1] - cutPointsEdge(i, 1)) <= eps);
10415 IF_CONSTEXPR(nDim == 3) equal = (equal && (ABS(pP[2] - cutPointsEdge(i, 2)) <= eps));
10416 if(equal) {
10417 newCutPoint = false;
10418 }
10419 }
10420 if(newCutPoint) {
10421 edgeCut = true;
10422 // store cut points in the data structure
10423 MInt cutPointNo = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
10424 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPointNo] = edge;
10425 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cutPointNo] = 0; // bndryCndId;
10426 for(MInt i = 0; i < nDim; i++) {
10427 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPointNo][i] = pP[i];
10428 }
10429 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints++;
10430 noCutPointsEdge++;
10431 }
10432 }
10433 } else {
10434 cerr << "** Warning fvbndrycndxd: " << endl;
10435 cerr << "cell " << cellId << endl;
10436 cerr << " -> Boundary cell " << bndryId << " has more than " << m_noEdges << " cut points" << endl;
10437 cerr << " -> Additional cut points are neglected" << endl;
10438 cerr << cellId << " " << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1)
10439 << " ";
10440 IF_CONSTEXPR(nDim == 3) cerr << m_solver->a_coordinate(cellId, 2) << " ";
10441 cerr << m_solver->a_level(cellId) << endl;
10442 mTerm(1, AT_, "Boundary cell has more than m_noEdges cut points");
10443 }
10444 }
10445 }
10446 }
10447 } // end of first loop over all bndry cells
10448
10449 if(!bndryRfnJump) {
10450 if(m_solver->m_geometry->m_parallelGeometry) {
10451 checkCutPointsValidityParGeom();
10452 } else {
10453 checkCutPointsValidity();
10454 }
10455
10456 IF_CONSTEXPR(nDim == 2) {
10457 // cells should not have more than two cut points in 2D without special treatment
10458 for(MInt bndryId = noCells - 1; bndryId > -1; bndryId--) {
10459 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
10460
10461 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints > 2) {
10462 cerr << "** Fatal error fvbndrycndxd: " << endl;
10463 cerr << " -> 2D Boundary cell " << bndryId << "(" << cellId << ") has more than 2 cut points" << endl;
10464 cerr << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1) << endl;
10465 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
10466 cerr << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][0] << " "
10467 << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][1] << endl;
10468 }
10469 mTerm(1, AT_, "Boundary cell has more than 2 cut points");
10470 }
10471 }
10472 }
10473 return;
10474 }
10475
10476
10477 ASSERT(bndryRfnJump, "");
10478
10479 // m_bndryRfnJumpInformation initiation
10480 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
10481 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] = -1;
10482 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] = -1;
10483 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] = -1;
10484 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] = -1;
10485 }
10486
10487 MBool newCutPointAdjustment = false; // true;
10488
10489 m_log << "Boundary refinement jump method is active" << endl;
10490 m_log << "WARNING: Make sure you have correctly activated the halo cells in cartesiangrid.cpp; it is wrong on "
10491 "default because otherwise a lot of testcases 'break'."
10492 << endl;
10493 if(domainId() == 0) {
10494 cerr << "Boundary refinement jump method is active" << endl;
10495 cerr << "Make sure you have correctly activated the halo cells in cartesiangrid.cpp; it is wrong on default "
10496 "because otherwise a lot of testcases 'break'."
10497 << endl;
10498 }
10499 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
10500 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
10501
10502 if(m_solver->c_noChildren(cellId) > 0) continue;
10503
10504 // halo cells can't be deactivated even though an exchange from window to halo cells is used to transfer the correct
10505 // cut points if(m_solver->a_isHalo(cellId)) continue;
10506
10507 for(MInt direction = 0; direction < m_noDirs; direction++) {
10508 MBool problemCell = false;
10509
10510 if(m_solver->a_hasNeighbor(cellId, direction) == 0) {
10511 MInt parentId = m_solver->c_parentId(cellId);
10512 if(parentId > -1) {
10513 if(m_solver->a_hasNeighbor(parentId, direction) == 1) {
10514 problemCell = true;
10515 }
10516 }
10517 }
10518
10519 // problemCells are all fine bndryCells at the leveljump
10520
10521 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints == 0 && direction == 5 && problemCell == 0
10522 && m_solver->a_bndryId(cellId) != -5) {
10523 m_solver->a_bndryId(cellId) = -5;
10524 if(!checkInside(cellId)) {
10525 m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
10526 m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) = true;
10527 }
10528 cerr << "cell activation/deactivation in m1 loop; isonmg and isinvalid: "
10529 << m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " "
10530 << m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) << " cell id: " << cellId << endl;
10531 }
10532
10533 // loop over all bndryCells with leveljumps
10534 if(problemCell == true) {
10535 MInt parentId = m_solver->c_parentId(cellId);
10536 MInt nghbrId = m_solver->c_neighborId(parentId, direction);
10537 MInt nghbrbndryId = -1;
10538 MFloat cellHalfLengthParent = F1B2 * m_solver->c_cellLengthAtCell(parentId);
10539 MFloatScratchSpace cornersParent(m_noCorners, nDim, AT_, "corners");
10540 MFloatScratchSpace centerParent(nDim, AT_, "center");
10541
10542 MInt noCutPoints1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
10543 if(noCutPoints1 == 0) {
10544 // cerr << "no cut points on this cell after problem cell was found" << endl;
10545 }
10546 nghbrbndryId = m_solver->a_bndryId(nghbrId);
10547 if(nghbrbndryId == -1) {
10548 continue;
10549 }
10550 MInt noCutPointsNeighbor = m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_noCutPoints;
10551 if(noCutPointsNeighbor == 0) continue;
10552
10553 for(MInt i = 0; i < nDim; i++) {
10554 centerParent[i] = m_solver->a_coordinate(parentId, i);
10555 }
10556 for(MInt n = 0; n < m_noCorners; n++) {
10557 for(MInt i = 0; i < nDim; i++) {
10558 cornersParent(n, i) = centerParent[i] + signStencil[n][i] * cellHalfLengthParent;
10559 }
10560 }
10561
10562 MFloat cellHalfLengthNeighbor = F1B2 * m_solver->c_cellLengthAtCell(nghbrId);
10563 MFloatScratchSpace cornersNeighbor(m_noCorners, nDim, AT_, "corners");
10564 MFloatScratchSpace centerNeighbor(nDim, AT_, "center");
10565
10566 for(MInt i = 0; i < nDim; i++) {
10567 centerNeighbor[i] = m_solver->a_coordinate(nghbrId, i);
10568 }
10569 for(MInt n = 0; n < m_noCorners; n++) {
10570 for(MInt i = 0; i < nDim; i++) {
10571 cornersNeighbor(n, i) = centerNeighbor[i] + signStencil[n][i] * cellHalfLengthNeighbor;
10572 }
10573 }
10574
10575 MFloat cellHalfLengthCell = F1B2 * m_solver->c_cellLengthAtCell(cellId);
10576 MFloatScratchSpace cornersCell(m_noCorners, nDim, AT_, "corners");
10577 MFloatScratchSpace centerCell(nDim, AT_, "center");
10578
10579
10580 for(MInt i = 0; i < nDim; i++) {
10581 centerCell[i] = m_solver->a_coordinate(cellId, i);
10582 }
10583 for(MInt n = 0; n < m_noCorners; n++) {
10584 for(MInt i = 0; i < nDim; i++) {
10585 cornersCell(n, i) = centerCell[i] + signStencil[n][i] * cellHalfLengthCell;
10586 }
10587 }
10588
10589 const MInt cornerDirectionStencil[8][3] = {{0, 2, 4}, {1, 2, 4}, {0, 3, 4}, {1, 3, 4},
10590 {0, 2, 5}, {1, 2, 5}, {0, 3, 5}, {1, 3, 5}};
10591
10592 // maybe change eps to be dependend on cell length
10593 const MFloat eps = 0.0000001;
10594 MBool directionMatchesCorner = false;
10595 MInt cornerId = -1;
10596 for(MInt n = 0; n < m_noCorners; n++) {
10597 if(abs(cornersParent(n, 0) - cornersCell(n, 0)) < eps && abs(cornersParent(n, 1) - cornersCell(n, 1)) < eps
10598 && abs(cornersParent(n, 2) - cornersCell(n, 2)) < eps) {
10599 cornerId = n;
10600 }
10601 }
10602 for(MInt i = 0; i < 3; i++) {
10603 if(cornerDirectionStencil[cornerId][i] == direction) {
10604 directionMatchesCorner = true;
10605 }
10606 }
10607
10608 if(directionMatchesCorner == false) {
10609 cerr << "Direction does not match corner1111; this ERROR should not occur. Check your grid." << endl;
10610 continue;
10611 }
10612
10613 MFloatScratchSpace dParent(nDim, AT_, "d_scratch");
10614 MFloatScratchSpace eParent(nDim, AT_, "e_scratch");
10615 MFloatScratchSpace dNeighbor(nDim, AT_, "d_scratch");
10616 MFloatScratchSpace eNeighbor(nDim, AT_, "e_scratch");
10617 MFloatScratchSpace dCell(nDim, AT_, "d_scratch");
10618 MFloatScratchSpace eCell(nDim, AT_, "e_scratch");
10619
10620 for(MInt edge = 0; edge < m_noEdges; edge++) {
10621 for(MInt i = 0; i < nDim; i++) {
10622 dParent[i] = cornersParent(nodeStencil[0][edge], i);
10623 eParent[i] = cornersParent(nodeStencil[1][edge], i);
10624 dNeighbor[i] = cornersNeighbor(nodeStencil[0][edge], i);
10625 eNeighbor[i] = cornersNeighbor(nodeStencil[1][edge], i);
10626 dCell[i] = cornersCell(nodeStencil[0][edge], i);
10627 eCell[i] = cornersCell(nodeStencil[1][edge], i);
10628 }
10629 }
10630 const MInt directionEdgesStencil[6][4] = {{0, 4, 8, 10}, {1, 5, 9, 11}, {2, 6, 8, 9},
10631 {3, 7, 10, 11}, {0, 1, 2, 3}, {4, 5, 6, 7}};
10632
10633 const MInt directionEdgesStencilNeighbor[6][4] = {{1, 5, 9, 11}, {0, 4, 8, 10}, {3, 7, 10, 11},
10634 {2, 6, 8, 9}, {4, 5, 6, 7}, {0, 1, 2, 3}};
10635 MInt noEdgesCut = 0;
10636 MInt edgesCut[2] = {0, 0};
10637 if(noEdgesCut == 12341234) {
10638 cerr << edgesCut[1] << endl;
10639 }
10640 MInt edgesCutRm[2] = {-1, -1};
10641 MInt newEdgeCut[2] = {-1, -1};
10642 MFloat cutPointCoordinatesNeighbor[3][2] = {{0, 0}, {0, 0}, {0, 0}};
10643 for(MInt i = 0; i < noCutPointsNeighbor; i++) {
10644 for(MInt j = 0; j < 4; j++) {
10645 if(m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_cutEdge[i] == directionEdgesStencilNeighbor[direction][j]) {
10646 edgesCut[noEdgesCut] = m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_cutEdge[i];
10647 for(MInt k = 0; k < 3; k++) {
10648 cutPointCoordinatesNeighbor[k][noEdgesCut] =
10649 m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_cutCoordinates[i][k];
10650 }
10651 noEdgesCut++;
10652 }
10653 }
10654 }
10655
10656 if(noEdgesCut != 2 && noEdgesCut != 0) {
10657 cerr << "ERROR: noEdgesCut is not 0 or 2; Check if split cells are occuring." << endl;
10658 }
10659
10660 // noEdgesCut has to be equal to 2, otherwise the cell is a split cell and needs special treatment
10661 if(noEdgesCut == 2) {
10662 MInt noCutPoints = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
10663 if(noCutPoints == 0) {
10664 cerr << "No cut points on this cell right now" << endl;
10665 }
10666 if(noCutPoints == 1) {
10667 cerr << "There is only 1 cut points in total on this cell: cellId: " << cellId << endl;
10668 }
10669 if(noCutPoints == 2) {
10670 cerr << "There are only 2 cut points in total on this cell: cellId: " << cellId << endl;
10671 }
10672
10673 for(MInt i = 0; i < noCutPoints; i++) {
10674 MBool removed = false;
10675 for(MInt j = 0; j < 4; j++) {
10676 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[i]
10677 == directionEdgesStencil[direction][j]) { // delete cut point
10678 MInt rmCutEdge = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[i]; // removed cut edge
10679 for(MInt k = i; k < noCutPoints; k++) {
10680 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[k] =
10681 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[k + 1]; // remove cut edge
10682 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[k] =
10683 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[k + 1]; // remove bndryId
10684 for(MInt l = 0; l < 3; l++) {
10685 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[k][l] =
10686 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[k + 1][l]; // remove cut point coordinates
10687 }
10688 }
10689
10690 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints--; // reduce number of cut points
10691 noCutPoints--;
10692 removed = true;
10693 if(edgesCutRm[0] != -1) {
10694 edgesCutRm[1] = rmCutEdge; // safe information about the removed edge
10695 }
10696 if(edgesCutRm[0] == -1) {
10697 edgesCutRm[0] = rmCutEdge; // safe information about the removed edge
10698 }
10699 }
10700 }
10701 if(removed == true) i--;
10702 }
10703
10704 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints == 0) {
10705 cerr << "nocutpoints is zero for this cellid even though it should be at least 1: " << cellId << endl;
10706 }
10707 MFloat dP[3];
10708 MFloat cutPointOne[3] = {0, 0, 0};
10709 MFloat cutPointTwo[3] = {0, 0, 0};
10710 MFloat edgePointOne[3] = {0, 0, 0};
10711 MFloat edgePointTwo[3] = {0, 0, 0};
10712 MInt divisorPosition = -1;
10713 MFloat lineOne[3] = {0, 0, 0};
10714 MFloat lineTwo[3] = {0, 0, 0};
10715 MFloat cutPoint[3] = {0, 0, 0};
10716 MFloat divisor = 0;
10717 MInt noNewCutPoints = 0;
10718 for(MInt i = 0; i < 3; i++) {
10719 cutPointOne[i] = cutPointCoordinatesNeighbor[i][0];
10720 cutPointTwo[i] = cutPointCoordinatesNeighbor[i][1];
10721 }
10722 for(MInt i = 0; i < 4; i++) {
10723 MBool newCutPoint = false;
10724 MInt edge = directionEdgesStencil[direction][i];
10725 for(MInt j = 0; j < 3; j++) {
10726 edgePointOne[j] = cornersCell(nodeStencil[0][edge], j);
10727 edgePointTwo[j] = cornersCell(nodeStencil[1][edge], j);
10728 }
10729
10730 MBool zero = false;
10731 for(MInt l = 0; l < 3; l++) {
10732 for(MInt k = 0; k < 3; k++) {
10733 if(l == k) continue;
10734 if(zero == true) continue;
10735 if(abs(edgePointOne[l] - 0.0) < eps && abs(edgePointTwo[l] - 0.0) < eps
10736 && abs(edgePointOne[k] - edgePointTwo[k]) < eps
10737 && (!(abs(edgePointOne[k] - 0.0) < eps) || !(abs(edgePointTwo[k] - 0.0) < eps))) {
10738 zero = true; // special treatment for cells that have coordinates close or equal to zero because
10739 // otherwise this can cause division by 0
10740 divisorPosition = k;
10741 }
10742 }
10743 }
10744
10745 for(MInt l = 0; l < 3; l++) {
10746 for(MInt k = 0; k < 3; k++) {
10747 if(l == k) continue;
10748 if(zero == true) continue;
10749 if(abs(edgePointOne[l] - 0.0) < eps && abs(edgePointTwo[l] - 0.0) < eps
10750 && abs(edgePointOne[k] - edgePointTwo[k]) < eps
10751 && ((abs(edgePointOne[k] - 0.0) < eps) && (abs(edgePointTwo[k] - 0.0) < eps))) {
10752 zero = true;
10753 divisorPosition = k;
10754 }
10755 }
10756 }
10757
10758 if(zero == true) {
10759 for(MInt l = 0; l < 3; l++) {
10760 cutPointOne[l] = cutPointOne[l] + 1;
10761 cutPointTwo[l] = cutPointTwo[l] + 1;
10762 edgePointOne[l] = edgePointOne[l] + 1;
10763 edgePointTwo[l] = edgePointTwo[l] + 1;
10764 }
10765 }
10766
10767 lineOne[0] = (cutPointOne[1] * cutPointTwo[2] - cutPointOne[2] * cutPointTwo[1]);
10768 lineOne[1] = (cutPointOne[2] * cutPointTwo[0] - cutPointOne[0] * cutPointTwo[2]);
10769 lineOne[2] = (cutPointOne[0] * cutPointTwo[1] - cutPointOne[1] * cutPointTwo[0]);
10770
10771 lineTwo[0] = (edgePointOne[1] * edgePointTwo[2] - edgePointOne[2] * edgePointTwo[1]);
10772 lineTwo[1] = (edgePointOne[2] * edgePointTwo[0] - edgePointOne[0] * edgePointTwo[2]);
10773 lineTwo[2] = (edgePointOne[0] * edgePointTwo[1] - edgePointOne[1] * edgePointTwo[0]);
10774
10775 cutPoint[0] = (lineOne[1] * lineTwo[2] - lineOne[2] * lineTwo[1]);
10776 cutPoint[1] = (lineOne[2] * lineTwo[0] - lineOne[0] * lineTwo[2]);
10777 cutPoint[2] = (lineOne[0] * lineTwo[1] - lineOne[1] * lineTwo[0]);
10778
10779 dP[0] = cutPoint[0];
10780 dP[1] = cutPoint[1];
10781 dP[2] = cutPoint[2];
10782
10783 if(zero == true) {
10784 for(MInt l = 0; l < 3; l++) {
10785 cutPointOne[l] = cutPointOne[l] - 1;
10786 cutPointTwo[l] = cutPointTwo[l] - 1;
10787 edgePointTwo[l] = edgePointTwo[l] - 1;
10788 }
10789 }
10790
10791 if(zero == false) {
10792 for(MInt l = 0; l < 3; l++) {
10793 if(abs(cutPointOne[l] - cutPointTwo[l]) < eps && abs(cutPointOne[l] - edgePointOne[l]) < eps
10794 && abs(cutPointOne[l] - edgePointTwo[l]) < eps && abs(cutPointTwo[l] - edgePointTwo[l]) < eps) {
10795 divisorPosition = l;
10796 }
10797 }
10798 }
10799
10800 if(divisorPosition == -1) {
10801 cerr << "divisorPosition is -1; This ERROR shouldn't be able to occur. Maybe adjust 'eps'" << endl;
10802 for(MInt l = 0; l < 3; l++) {
10803 cerr << l << ": coordinate;"
10804 << "cutPointOne: " << cutPointOne[l] << " -- cutPointTwo: " << cutPointTwo[l]
10805 << " -- edgePointOne: " << edgePointOne[l] << " -- edgePointTwo: " << edgePointTwo[l] << endl;
10806 }
10807 cerr << "direction: " << direction << endl;
10808
10809 for(MInt n = 0; n < m_noCorners; n++) {
10810 cerr << "corner: " << n << endl;
10811 for(MInt l = 0; l < 3; l++) {
10812 cerr << "cornersCell: " << cornersCell(n, l) << endl;
10813 }
10814 }
10815
10816 for(MInt n = 0; n < m_noCorners; n++) {
10817 cerr << "corner neighbor: " << n << endl;
10818 for(MInt l = 0; l < 3; l++) {
10819 cerr << "cornersNeighbor: " << cornersNeighbor(n, l) << endl;
10820 }
10821 }
10822
10823 for(MInt l = 0; l < noCutPointsNeighbor; l++) {
10824 cerr << "----------------------------" << endl;
10825 cerr << "neighborcutpointnumber: " << l << endl;
10826 for(MInt k = 0; k < 3; k++) {
10827 cerr << m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_cutCoordinates[l][k] << endl;
10828 }
10829 noEdgesCut++;
10830 }
10831 }
10832
10833 divisor = cutPoint[divisorPosition];
10834 divisor = divisor / edgePointOne[divisorPosition];
10835
10836 MBool continueing = false;
10837 for(MInt k = 0; k < 3; k++) {
10838 cutPoint[k] = cutPoint[k] / divisor;
10839 if(std::isnan(cutPoint[k])) {
10840 cerr << "ERROR: NAN. Divisor: " << divisor << " cut point k: " << cutPoint[k] << " zero: " << zero
10841 << endl;
10842 cerr << "k: " << k << " edgepointone: " << edgePointOne[k] << " edgepointtwo: " << edgePointTwo[k]
10843 << endl;
10844 cerr << "k: " << k << " cutpointone: " << cutPointOne[k] << " cutpointtwo: " << cutPointTwo[k]
10845 << endl;
10846 cerr << "divisorPosition: " << divisorPosition << endl;
10847 cerr << "dP0: " << dP[0] << "dP1: " << dP[1] << "dP2: " << dP[2] << endl;
10848 cerr << "cut points are probably parallel to the edge. continue";
10849 continueing = true;
10850 }
10851 }
10852 if(continueing == true) {
10853 continueing = false;
10854 continue;
10855 }
10856
10857 if(zero == true) {
10858 for(MInt l = 0; l < 3; l++) {
10859 cutPoint[l] = cutPoint[l] - 1;
10860 edgePointOne[l] = edgePointOne[l] - 1;
10861 }
10862 }
10863
10864
10865 if(newCutPointAdjustment == true) {
10866 for(MInt m = 0; m < 3; m++) {
10867 if(abs(edgePointOne[m] - cutPoint[m]) < 0.00000001) {
10868 cutPoint[m] = edgePointOne[m];
10869 }
10870 }
10871 }
10872
10873 for(MInt n = 0; n < 3; n++) {
10874 if(edgePointTwo[n] > edgePointOne[n] && abs(edgePointOne[n] - cutPoint[n]) > epsilon
10875 && (edgePointTwo[n] - edgePointOne[n]) > (edgePointTwo[n] - cutPoint[n])
10876 && (edgePointTwo[n] - cutPoint[n]) > 0) {
10877 // cut point is on the edge
10878 newCutPoint = true;
10879 }
10880 if(edgePointTwo[n] < edgePointOne[n] && abs(edgePointOne[n] - cutPoint[n]) > epsilon
10881 && (edgePointOne[n] - edgePointTwo[n]) > (edgePointOne[n] - cutPoint[n])
10882 && (edgePointOne[n] - cutPoint[n]) > 0) {
10883 // cut point is on the edge
10884 newCutPoint = true;
10885 }
10886 }
10887
10888 if(newCutPoint == false) {
10889 continue;
10890 }
10891
10892 if(newEdgeCut[0] != -1) {
10893 newEdgeCut[1] = edge; // safe information about the new edge that gets cut
10894 }
10895 if(newEdgeCut[0] == -1) {
10896 newEdgeCut[0] = edge; // safe information about the new edge that gets cut
10897 }
10898 noNewCutPoints++;
10899 // store cut points in the data structure
10900 MInt cutPointNo = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
10901 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPointNo] = edge;
10902 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cutPointNo] =
10903 m_bndryCells->a[nghbrbndryId]
10904 .m_srfcs[0]
10905 ->m_bodyId[0]; // bndry condition of the cut points is set to be equal to one of the neighbor cut
10906 // point's bndry condition
10907 for(MInt x = 0; x < nDim; x++) {
10908 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPointNo][x] = cutPoint[x];
10909 }
10910 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints++;
10911 }
10912
10913 // in certain cases an additional cut point needs to be added
10914 for(MInt noOldEdge = 0; noOldEdge < 2; noOldEdge++) {
10915 MInt additionalCutEdge = -1;
10916 MFloat pointDifference[3] = {0, 0, 0};
10917 MFloat cutCoordinates[3] = {0, 0, 0};
10918
10919 const MInt edgeFaceStencil[6][4] = {{8, 10, 0, 4}, {9, 11, 1, 5}, {2, 6, 8, 9},
10920 {3, 7, 10, 11}, {0, 1, 2, 3}, {4, 5, 6, 7}};
10921
10922 const MInt edgeInCorner[8][3] = {{0, 2, 8}, {1, 2, 9}, {0, 3, 10}, {1, 3, 11},
10923 {4, 6, 8}, {5, 6, 9}, {4, 7, 10}, {5, 7, 11}};
10924
10925 for(MInt i = 0; i < 8; i++) {
10926 MInt additionalCutPoint = -1;
10927 MInt counter = 0;
10928 for(MInt j = 0; j < 3; j++) {
10929 // recent change: '&& edgesCutRm[1-noOldEdge]==newedg....'
10930 if(edgesCutRm[noOldEdge] != newEdgeCut[0] && edgesCutRm[1 - noOldEdge] == newEdgeCut[1]) {
10931 if(edgeInCorner[i][j] == edgesCutRm[noOldEdge]) {
10932 counter++;
10933 }
10934 if(edgeInCorner[i][j] == newEdgeCut[0]) {
10935 counter++;
10936 }
10937 if(counter == 2) {
10938 additionalCutPoint = 0;
10939 }
10940 }
10941 }
10942 counter = 0;
10943 // recent change: '&& edgesCutRm[1-noOldEdge]==newedg....'
10944 for(MInt j = 0; j < 3; j++) {
10945 if(edgesCutRm[noOldEdge] != newEdgeCut[1] && edgesCutRm[1 - noOldEdge] == newEdgeCut[0]
10946 && additionalCutPoint == -1) {
10947 if(edgeInCorner[i][j] == edgesCutRm[noOldEdge]) {
10948 counter++;
10949 }
10950 if(edgeInCorner[i][j] == newEdgeCut[1]) {
10951 counter++;
10952 }
10953 if(counter == 2) {
10954 additionalCutPoint = 1;
10955 }
10956 }
10957 }
10958 counter = 0;
10959
10960 for(MInt j = 0; j < 3; j++) {
10961 if(edgeInCorner[i][j] != edgesCutRm[noOldEdge]
10962 && edgeInCorner[i][j] != newEdgeCut[additionalCutPoint]) {
10963 additionalCutEdge = edgeInCorner[i][j];
10964 }
10965 }
10966
10967 if(edgesCutRm[0] == -1 && edgesCutRm[1] == -1 && noOldEdge == 1) {
10968 for(MInt j = 0; j < 3; j++) {
10969 if(additionalCutPoint != -1) {
10970 cerr << "ERROR in the additional cut point computation" << endl;
10971 }
10972 if(edgeInCorner[i][j] == newEdgeCut[0]) {
10973 counter++;
10974 }
10975 if(edgeInCorner[i][j] == newEdgeCut[1]) {
10976 counter++;
10977 }
10978 if(counter == 2) {
10979 additionalCutPoint = 2;
10980 }
10981 }
10982 counter = 0;
10983
10984 for(MInt j = 0; j < 3; j++) {
10985 if(additionalCutPoint == 2 && edgeInCorner[i][j] != newEdgeCut[0]
10986 && edgeInCorner[i][j] != newEdgeCut[1]) {
10987 additionalCutEdge = edgeInCorner[i][j];
10988 }
10989 }
10990 }
10991 if(additionalCutPoint != -1 && edgesCutRm[noOldEdge] != newEdgeCut[0]
10992 && edgesCutRm[noOldEdge] != newEdgeCut[1]) {
10993 // safe information about the corner that is no longer inside/outside of the geometry but was before
10994 // (for createCutFace)
10995 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] = i;
10996
10997 // the additional cut point is currently placed into the middle of the edge
10998 // this could be improved by calculating a more accurate position
10999 for(MInt j = 0; j < 3; j++) {
11000 edgePointOne[j] = cornersCell(nodeStencil[0][additionalCutEdge], j);
11001 edgePointTwo[j] = cornersCell(nodeStencil[1][additionalCutEdge], j);
11002 pointDifference[j] = edgePointTwo[j] - edgePointOne[j];
11003 pointDifference[j] = pointDifference[j] / 2;
11004 cutCoordinates[j] = edgePointOne[j] + pointDifference[j];
11005 }
11006
11007 MBool skip = false;
11008 // if on the edge for the additional cut point a cut point already exists, it needs to be removed
11009 // instead
11010 for(MInt x = 0; x < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; x++) {
11011 MBool removed = false;
11012
11013 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[x] == additionalCutEdge
11014 && additionalCutEdge != -1) {
11015 // delete cut edge
11016 for(MInt k = x; k < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; k++) {
11017 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[k] =
11018 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[k + 1];
11019 // remove bndry condition
11020 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[k] =
11021 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[k + 1];
11022 for(MInt l = 0; l < 3; l++) {
11023 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[k][l] =
11024 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[k + 1][l];
11025 }
11026 }
11027
11028 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints--;
11029 noCutPoints--;
11030 removed = true;
11031 }
11032 if(removed == true) {
11033 skip = true;
11034 x--;
11035 }
11036 }
11037
11038 if(skip == false) {
11039 noNewCutPoints++;
11040 // store cut points in the data structure
11041 MInt cutPointNo = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
11042 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPointNo] = additionalCutEdge;
11043 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cutPointNo] =
11044 m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_bodyId[0];
11045 for(MInt x = 0; x < nDim; x++) {
11046 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPointNo][x] = cutCoordinates[x];
11047 }
11048 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints++;
11049 }
11050
11051 // safe the problem face for createCutFace function
11052 for(MInt k = 0; k < 6; k++) {
11053 counter = 0;
11054 MInt problemFace = -1;
11055
11056 for(MInt l = 0; l < 4; l++) {
11057 if(additionalCutEdge == edgeFaceStencil[k][l]) {
11058 counter++;
11059 }
11060 if(edgesCutRm[0] == newEdgeCut[0] || edgesCutRm[1] == newEdgeCut[0]) {
11061 if(newEdgeCut[1] == edgeFaceStencil[k][l]) {
11062 counter++;
11063 }
11064 }
11065 if(edgesCutRm[0] == newEdgeCut[1] || edgesCutRm[1] == newEdgeCut[1]) {
11066 if(newEdgeCut[0] == edgeFaceStencil[k][l]) {
11067 counter++;
11068 }
11069 }
11070
11071 if(counter == 2
11072 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1) {
11073 problemFace = k;
11074 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] = k;
11075 }
11076
11077 if(counter == 2
11078 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] == -1) {
11079 problemFace = k;
11080 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] = k;
11081 }
11082 if(counter > 2) {
11083 cerr << "counter error 1: " << problemFace << endl;
11084 }
11085 }
11086 }
11087
11088 // recently added:
11089 for(MInt k = 0; k < 6; k++) {
11090 counter = 0;
11091 MInt problemFace = -1;
11092
11093 for(MInt l = 0; l < 4; l++) {
11094 if(additionalCutEdge == edgeFaceStencil[k][l]) {
11095 counter++;
11096 }
11097 if(edgesCutRm[0] != newEdgeCut[0] && edgesCutRm[0] != newEdgeCut[1]) {
11098 if(edgesCutRm[0] == edgeFaceStencil[k][l]) {
11099 counter++;
11100 }
11101 }
11102 if(edgesCutRm[1] != newEdgeCut[0] && edgesCutRm[1] != newEdgeCut[1]) {
11103 if(edgesCutRm[1] == edgeFaceStencil[k][l]) {
11104 counter++;
11105 }
11106 }
11107
11108 if(counter == 2
11109 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1) {
11110 problemFace = k;
11111 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] = k;
11112 }
11113
11114 if(counter == 2
11115 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] == -1) {
11116 problemFace = k;
11117 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] = k;
11118 }
11119
11120 if(counter > 2) {
11121 cerr << "counter ERROR 1: " << problemFace << endl;
11122 }
11123 }
11124 }
11125
11126 // recently added:
11127 if(additionalCutPoint == 2) {
11128 for(MInt k = 0; k < 6; k++) {
11129 counter = 0;
11130 MInt problemFace = -1;
11131 for(MInt l = 0; l < 4; l++) {
11132 if(additionalCutEdge == edgeFaceStencil[k][l]) {
11133 counter++;
11134 }
11135 }
11136 for(MInt l = 0; l < 4; l++) {
11137 if(counter == 1) {
11138 if(newEdgeCut[0] == edgeFaceStencil[k][l]) {
11139 counter++;
11140 }
11141 if(newEdgeCut[1] == edgeFaceStencil[k][l]) {
11142 counter++;
11143 }
11144 }
11145
11146 if(counter == 2
11147 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1
11148 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] != -1) {
11149 cerr << "error: third face is found1; first face: "
11150 << m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0]
11151 << " second face: "
11152 << m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2]
11153 << " current face: " << k << " additionalcutedge: " << additionalCutEdge
11154 << " this should be ok if the additional cut edge is on the second face AND the current "
11155 "face"
11156 << endl;
11157 }
11158
11159 if(counter == 2
11160 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1) {
11161 problemFace = k;
11162 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] = k;
11163 counter = 0;
11164 }
11165
11166 if(counter == 2
11167 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] == -1) {
11168 problemFace = k;
11169 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] = k;
11170 counter = 0;
11171 }
11172
11173 if(counter > 2) {
11174 cerr << "counter error 1: " << problemFace << endl;
11175 }
11176 }
11177 }
11178 }
11179
11180 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1
11181 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] != -1) {
11182 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] != -1) {
11183 cerr << "a second direction is found: " << direction << " currently saved direction: "
11184 << m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3]
11185 << "first face: "
11186 << m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0]
11187 << " second face: "
11188 << m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2]
11189 << " corner: "
11190 << m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] << endl;
11191 }
11192 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] = direction;
11193 }
11194
11195 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0]
11196 == m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2]) {
11197 cerr << "ERROR: somehow a face is detected as a problem face twice" << endl;
11198 }
11199 }
11200 }
11201
11202 if(newEdgeCut[0] == -1 && newEdgeCut[1] == -1) {
11203 for(MInt i = 0; i < 8; i++) {
11204 MInt additionalCutPoint = -1;
11205 MInt counter = 0;
11206
11207 additionalCutEdge = -1;
11208 for(MInt j = 0; j < 3; j++) {
11209 if(edgeInCorner[i][j] == edgesCutRm[0]) {
11210 counter++;
11211 }
11212 if(edgeInCorner[i][j] == edgesCutRm[1]) {
11213 counter++;
11214 }
11215 if(counter == 2) {
11216 additionalCutPoint = 1;
11217 }
11218 }
11219 counter = 0;
11220 if(additionalCutPoint == 1 && noOldEdge == 0) {
11221 for(MInt j = 0; j < 3; j++) {
11222 if(edgeInCorner[i][j] != edgesCutRm[0] && edgeInCorner[i][j] != edgesCutRm[1]) {
11223 additionalCutEdge = edgeInCorner[i][j];
11224 }
11225 }
11226 for(MInt j = 0; j < 3; j++) {
11227 edgePointOne[j] = cornersCell(nodeStencil[0][additionalCutEdge], j);
11228 edgePointTwo[j] = cornersCell(nodeStencil[1][additionalCutEdge], j);
11229 pointDifference[j] = edgePointTwo[j] - edgePointOne[j];
11230 pointDifference[j] = pointDifference[j] / 2;
11231 cutCoordinates[j] = edgePointOne[j] + pointDifference[j];
11232 }
11233
11234 if(additionalCutPoint != -1) {
11235 // safe information about the corner that is no longer inside/outside of the geometry but was before
11236 // (for createCutFace)
11237 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] = i;
11238 }
11239 // if the cell used to be cut and isnt cut anymore it is also a problem cell
11240 for(MInt k = 0; k < 6; k++) {
11241 counter = 0;
11242 MInt problemFace = -1;
11243 for(MInt l = 0; l < 4; l++) {
11244 if(additionalCutEdge == edgeFaceStencil[k][l]) {
11245 counter++;
11246 }
11247 }
11248 for(MInt l = 0; l < 4; l++) {
11249 if(counter == 1) {
11250 if(newEdgeCut[0] == -1 && newEdgeCut[1] == -1) {
11251 if(edgesCutRm[1] == edgeFaceStencil[k][l] || edgesCutRm[0] == edgeFaceStencil[k][l]) {
11252 counter++;
11253 }
11254 }
11255 if(counter == 2
11256 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1) {
11257 problemFace = k;
11258 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] = k;
11259 }
11260
11261 if(counter == 2
11262 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] == -1) {
11263 problemFace = k;
11264 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] = k;
11265 }
11266 counter = 1;
11267 if(counter != 1) {
11268 cerr << problemFace << endl;
11269 }
11270 }
11271 }
11272 }
11273 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1
11274 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] != -1) {
11275 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] = direction;
11276 }
11277
11278 MBool skip = false;
11279 // if on the edge for the additional cut point a cut point already exists, it needs to be removed
11280 // instead
11281 for(MInt x = 0; x < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; x++) {
11282 MBool removed = false;
11283
11284 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[x] == additionalCutEdge
11285 && additionalCutEdge != -1) {
11286 // delete cut edge
11287 for(MInt k = x; k < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; k++) {
11288 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[k] =
11289 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[k + 1];
11290 // remove bndryId! has to be tested!
11291 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[k] =
11292 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[k + 1];
11293 for(MInt l = 0; l < 3; l++) {
11294 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[k][l] =
11295 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[k + 1][l];
11296 }
11297 }
11298
11299 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints--;
11300 noCutPoints--;
11301 removed = true;
11302 }
11303 if(removed == true) {
11304 skip = true;
11305 // cerr << "test" << endl;
11306 x--;
11307 }
11308 }
11309
11310 // safe that the new cuts are creating an edge that used to be inside/outside the geometry and is not
11311 // anymore AND that the created face triangles are always outside if they used to be inside before and
11312 // vise verca
11313 if(skip == false) {
11314 noNewCutPoints++;
11315 // store cut points in the data structure
11316 MInt cutPointNo = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
11317 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPointNo] = additionalCutEdge;
11318 //übergangslösung für das setzen der bndry id
11319 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cutPointNo] =
11320 m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_bodyId[0];
11321 for(MInt x = 0; x < nDim; x++) {
11322 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPointNo][x] = cutCoordinates[x];
11323 }
11324 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints++;
11325 }
11326 }
11327 }
11328 }
11329 }
11330 }
11331 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints == 0
11332 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] != -1) {
11333 MFloat testCorner[3];
11334 cerr << "bndry cell that is no longer cut is found."
11335 << " it is checked if it is inside or outside; cellId: " << cellId << endl;
11336 m_solver->a_bndryId(cellId) = -5;
11337 for(MInt i = 0; i < 3; i++) {
11338 testCorner[i] =
11339 cornersCell(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1], i);
11340 }
11341 // if the corner used to be inside of the fluid domain (which is checked by pointisinside2 -> true if outside
11342 // of the fluid domain) the cell is now completely outside of the fluid domain and vise verca
11343 m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) =
11344 m_solver->m_geometry->pointIsInside2(testCorner);
11345 m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) = !m_solver->m_geometry->pointIsInside2(testCorner);
11346 m_solver->a_bndryId(cellId) = -5;
11347 m_solver->a_isInterface(cellId) = false;
11348 deleteBndryCell(bndryId);
11349 if(bndryId < m_bndryCells->size()) {
11350 m_solver->a_bndryId(m_bndryCells->a[bndryId].m_cellId) = bndryId;
11351 }
11352 if(!m_solver->m_geometry->pointIsInside2(testCorner)) {
11353 }
11354 }
11355 if(edgesCutRm[0] == -1 && edgesCutRm[1] == -1 && newEdgeCut[0] == -1 && newEdgeCut[1] == -1) {
11356 MFloat testCorner[3];
11357 MBool testBool = false;
11358 for(MInt j = 0; j < 4; j++) {
11359 for(MInt i = 0; i < 3; i++) {
11360 testCorner[i] = cornersCell(nodeStencil[0][directionEdgesStencil[direction][j]], i);
11361 }
11362 if(j > 0 && testBool != m_solver->m_geometry->pointIsInside2(testCorner)) {
11363 cerr << "ERROR: cell is not cut but it is not completely inside or completely"
11364 << " outside of the fluid region" << endl;
11365 }
11366 testBool = m_solver->m_geometry->pointIsInside2(testCorner);
11367 }
11368 if(m_solver->m_geometry->pointIsInside2(testCorner)) {
11369 // cerr << "this cell has a surface that needs to have no area: " << cellId << endl;
11370 // cerr << "nghbr is: " << nghbrId << endl;
11371 m_solver->m_bndryRfnJumpInformation_[cellId] = nghbrId;
11372 }
11373 }
11374 }
11375 } // loop over all directions
11376 } // loop over all boundary cells
11377 //##start of the "not yet boundary cell" part
11378 //
11379 // part that finds the new boundary cells and safes them:
11380 for(MInt cell = 0; cell < m_solver->a_noCells(); cell++) {
11381 if(m_solver->a_bndryId(cell) > -1) {
11382 continue;
11383 }
11384
11385 if(m_solver->c_noChildren(cell) != 0) { // m_solver->c_noChildren(cell)_ > 0)
11386 continue;
11387 }
11388
11389 MInt cellId = cell;
11390 // don't skip halo cells
11391 // if(m_solver->a_isHalo(cellId))
11392 // continue;
11393 MInt bndryId;
11394 for(MInt direction = 0; direction < m_noDirs; direction++) {
11395 MBool problemCell = false;
11396
11397 if(m_solver->a_hasNeighbor(cellId, direction) == 0) {
11398 MInt parentId = m_solver->c_parentId(cellId);
11399 if(parentId > -1) {
11400 if(m_solver->a_hasNeighbor(parentId, direction) == 1) {
11401 problemCell = true;
11402 }
11403 }
11404 }
11405
11406 if(problemCell == true) { // cellId is always the finer cell
11407 MInt parentId = m_solver->c_parentId(cellId);
11408 MInt nghbrId = m_solver->c_neighborId(parentId, direction);
11409 MInt nghbrbndryId = -1;
11410 MFloat cellHalfLengthParent = F1B2 * m_solver->c_cellLengthAtCell(parentId);
11411 MFloatScratchSpace cornersParent(m_noCorners, nDim, AT_, "corners");
11412 MFloatScratchSpace centerParent(nDim, AT_, "center");
11413
11414 nghbrbndryId = m_solver->a_bndryId(nghbrId);
11415 if(nghbrbndryId == -1) {
11416 continue;
11417 }
11418 MInt noCutPointsNeighbor = m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_noCutPoints;
11419 if(noCutPointsNeighbor == 0) continue;
11420
11421 for(MInt i = 0; i < nDim; i++)
11422 centerParent[i] = m_solver->a_coordinate(parentId, i);
11423
11424 for(MInt n = 0; n < m_noCorners; n++)
11425 for(MInt i = 0; i < nDim; i++)
11426 cornersParent(n, i) = centerParent[i] + signStencil[n][i] * cellHalfLengthParent;
11427
11428 MFloat cellHalfLengthNeighbor = F1B2 * m_solver->c_cellLengthAtCell(nghbrId);
11429 MFloatScratchSpace cornersNeighbor(m_noCorners, nDim, AT_, "corners");
11430 MFloatScratchSpace centerNeighbor(nDim, AT_, "center");
11431
11432 for(MInt i = 0; i < nDim; i++)
11433 centerNeighbor[i] = m_solver->a_coordinate(nghbrId, i);
11434 for(MInt n = 0; n < m_noCorners; n++)
11435 for(MInt i = 0; i < nDim; i++)
11436 cornersNeighbor(n, i) = centerNeighbor[i] + signStencil[n][i] * cellHalfLengthNeighbor;
11437
11438 MFloat cellHalfLengthCell = F1B2 * m_solver->c_cellLengthAtCell(cellId);
11439 MFloatScratchSpace cornersCell(m_noCorners, nDim, AT_, "corners");
11440 MFloatScratchSpace centerCell(nDim, AT_, "center");
11441
11442 for(MInt i = 0; i < nDim; i++)
11443 centerCell[i] = m_solver->a_coordinate(cellId, i);
11444 for(MInt n = 0; n < m_noCorners; n++)
11445 for(MInt i = 0; i < nDim; i++)
11446 cornersCell(n, i) = centerCell[i] + signStencil[n][i] * cellHalfLengthCell;
11447 const MInt cornerDirectionStencil[8][3] = {{0, 2, 4}, {1, 2, 4}, {0, 3, 4}, {1, 3, 4},
11448 {0, 2, 5}, {1, 2, 5}, {0, 3, 5}, {1, 3, 5}};
11449 const MFloat eps = 0.0000001;
11450 MBool directionMatchesCorner = false;
11451 MInt cornerId = -1;
11452 for(MInt n = 0; n < m_noCorners; n++) {
11453 if(abs(cornersParent(n, 0) - cornersCell(n, 0)) < eps && abs(cornersParent(n, 1) - cornersCell(n, 1)) < eps
11454 && abs(cornersParent(n, 2) - cornersCell(n, 2)) < eps) {
11455 cornerId = n;
11456 }
11457 }
11458 for(MInt i = 0; i < 3; i++) {
11459 if(cornerDirectionStencil[cornerId][i] == direction) {
11460 directionMatchesCorner = true;
11461 }
11462 }
11463 if(directionMatchesCorner == false) {
11464 cerr << "direction: " << direction << endl;
11465 cerr << "direction doesnt match corner! This shouldn't be able to happen."
11466 << " Check your grid. Corner id: " << cornerId << endl;
11467 continue;
11468 }
11469
11470 MFloatScratchSpace dParent(nDim, AT_, "d_scratch");
11471 MFloatScratchSpace eParent(nDim, AT_, "e_scratch");
11472 MFloatScratchSpace dNeighbor(nDim, AT_, "d_scratch");
11473 MFloatScratchSpace eNeighbor(nDim, AT_, "e_scratch");
11474 MFloatScratchSpace dCell(nDim, AT_, "d_scratch");
11475 MFloatScratchSpace eCell(nDim, AT_, "e_scratch");
11476
11477 for(MInt edge = 0; edge < m_noEdges; edge++) {
11478 for(MInt i = 0; i < nDim; i++) {
11479 dParent[i] = cornersParent(nodeStencil[0][edge], i);
11480 eParent[i] = cornersParent(nodeStencil[1][edge], i);
11481
11482 dNeighbor[i] = cornersNeighbor(nodeStencil[0][edge], i);
11483 eNeighbor[i] = cornersNeighbor(nodeStencil[1][edge], i);
11484
11485 dCell[i] = cornersCell(nodeStencil[0][edge], i);
11486 eCell[i] = cornersCell(nodeStencil[1][edge], i);
11487 }
11488 }
11489 const MInt directionEdgesStencil[6][4] = {{0, 4, 8, 10}, {1, 5, 9, 11}, {2, 6, 8, 9},
11490 {3, 7, 10, 11}, {0, 1, 2, 3}, {4, 5, 6, 7}};
11491 const MInt directionEdgesStencilNeighbor[6][4] = {{1, 5, 9, 11}, {0, 4, 8, 10}, {3, 7, 10, 11},
11492 {2, 6, 8, 9}, {4, 5, 6, 7}, {0, 1, 2, 3}};
11493 MInt noEdgesCut = 0;
11494 MInt newEdgeCut[2] = {-1, -1};
11495 MFloat cutPointCoordinatesNeighbor[3][2] = {{0, 0}, {0, 0}, {0, 0}};
11496 for(MInt i = 0; i < noCutPointsNeighbor; i++) {
11497 for(MInt j = 0; j < 4; j++) {
11498 if(m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_cutEdge[i] == directionEdgesStencilNeighbor[direction][j]) {
11499 for(MInt k = 0; k < 3; k++) {
11500 cutPointCoordinatesNeighbor[k][noEdgesCut] =
11501 m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_cutCoordinates[i][k];
11502 }
11503 noEdgesCut++;
11504 }
11505 }
11506 }
11507 if(noEdgesCut == 2) {
11508 // here starts the computation of the new cut points
11509 MFloat cutPointOne[3] = {0, 0, 0};
11510 MFloat cutPointTwo[3] = {0, 0, 0};
11511 MFloat edgePointOne[3] = {0, 0, 0};
11512 MFloat edgePointTwo[3] = {0, 0, 0};
11513 MInt divisorPosition = -1;
11514 MFloat lineOne[3] = {0, 0, 0};
11515 MFloat lineTwo[3] = {0, 0, 0};
11516 MFloat cutPoint[3] = {0, 0, 0};
11517 MFloat divisor = 0;
11518 MInt noNewCutPoints = 0;
11519 for(MInt i = 0; i < 3; i++) {
11520 cutPointOne[i] = cutPointCoordinatesNeighbor[i][0];
11521 cutPointTwo[i] = cutPointCoordinatesNeighbor[i][1];
11522 }
11523 for(MInt i = 0; i < 4; i++) {
11524 MBool newCutPoint = false;
11525 MInt edge = directionEdgesStencil[direction][i];
11526 for(MInt j = 0; j < 3; j++) {
11527 edgePointOne[j] = cornersCell(nodeStencil[0][edge], j);
11528 edgePointTwo[j] = cornersCell(nodeStencil[1][edge], j);
11529 }
11530 MBool zero = false;
11531 for(MInt l = 0; l < 3; l++) {
11532 for(MInt k = 0; k < 3; k++) {
11533 if(l == k) continue;
11534 if(zero == true) continue;
11535 if(abs(edgePointOne[l] - 0.0) < eps && abs(edgePointTwo[l] - 0.0) < eps
11536 && abs(edgePointOne[k] - edgePointTwo[k]) < eps
11537 && (!(abs(edgePointOne[k] - 0.0) < eps) || !(abs(edgePointTwo[k] - 0.0) < eps))) {
11538 zero = true;
11539 divisorPosition = k;
11540 }
11541 }
11542 }
11543 for(MInt l = 0; l < 3; l++) {
11544 for(MInt k = 0; k < 3; k++) {
11545 if(l == k) continue;
11546 if(zero == true) continue;
11547 if(abs(edgePointOne[l] - 0.0) < eps && abs(edgePointTwo[l] - 0.0) < eps
11548 && abs(edgePointOne[k] - edgePointTwo[k]) < eps
11549 && ((abs(edgePointOne[k] - 0.0) < eps) && (abs(edgePointTwo[k] - 0.0) < eps))) {
11550 zero = true;
11551 divisorPosition = k;
11552 }
11553 }
11554 }
11555 if(zero == true) {
11556 for(MInt l = 0; l < 3; l++) {
11557 cutPointOne[l] = cutPointOne[l] + 1;
11558 cutPointTwo[l] = cutPointTwo[l] + 1;
11559 edgePointOne[l] = edgePointOne[l] + 1;
11560 edgePointTwo[l] = edgePointTwo[l] + 1;
11561 }
11562 }
11563
11564 lineOne[0] = (cutPointOne[1] * cutPointTwo[2] - cutPointOne[2] * cutPointTwo[1]);
11565 lineOne[1] = (cutPointOne[2] * cutPointTwo[0] - cutPointOne[0] * cutPointTwo[2]);
11566 lineOne[2] = (cutPointOne[0] * cutPointTwo[1] - cutPointOne[1] * cutPointTwo[0]);
11567
11568 lineTwo[0] = (edgePointOne[1] * edgePointTwo[2] - edgePointOne[2] * edgePointTwo[1]);
11569 lineTwo[1] = (edgePointOne[2] * edgePointTwo[0] - edgePointOne[0] * edgePointTwo[2]);
11570 lineTwo[2] = (edgePointOne[0] * edgePointTwo[1] - edgePointOne[1] * edgePointTwo[0]);
11571
11572 cutPoint[0] = (lineOne[1] * lineTwo[2] - lineOne[2] * lineTwo[1]);
11573 cutPoint[1] = (lineOne[2] * lineTwo[0] - lineOne[0] * lineTwo[2]);
11574 cutPoint[2] = (lineOne[0] * lineTwo[1] - lineOne[1] * lineTwo[0]);
11575
11576 if(zero == true) {
11577 for(MInt l = 0; l < 3; l++) {
11578 cutPointOne[l] = cutPointOne[l] - 1;
11579 cutPointTwo[l] = cutPointTwo[l] - 1;
11580 edgePointTwo[l] = edgePointTwo[l] - 1;
11581 }
11582 }
11583 if(zero == false) {
11584 for(MInt l = 0; l < 3; l++) {
11585 if(abs(cutPointOne[l] - cutPointTwo[l]) < eps && abs(cutPointOne[l] - edgePointOne[l]) < eps
11586 && abs(cutPointOne[l] - edgePointTwo[l]) < eps && abs(cutPointTwo[l] - edgePointTwo[l]) < eps) {
11587 divisorPosition = l;
11588 }
11589 }
11590 }
11591 if(divisorPosition == -1) {
11592 cerr << "divisorPosition,new is -1; this shouldn't be possible" << endl;
11593 for(MInt l = 0; l < 3; l++) {
11594 cerr << l << ": coordinate;"
11595 << "cutPointOne: " << cutPointOne[l] << " -- cutPointTwo: " << cutPointTwo[l]
11596 << " -- edgePointOne: " << edgePointOne[l] << " -- edgePointTwo: " << edgePointTwo[l] << endl;
11597 }
11598 cerr << "zero: " << zero << endl;
11599 cerr << "direction: " << direction << endl;
11600 }
11601 divisor = cutPoint[divisorPosition];
11602 divisor = divisor / edgePointOne[divisorPosition];
11603
11604 MBool continueing = false;
11605 for(MInt k = 0; k < 3; k++) {
11606 cutPoint[k] = cutPoint[k] / divisor;
11607 if(std::isnan(cutPoint[k])) {
11608 cerr << "ERROR: NAN. Divisor: " << divisor << " cut point k: " << cutPoint[k] << " zero: " << zero
11609 << endl;
11610 cerr << "k: " << k << " edgepointone: " << edgePointOne[k] << " edgepointtwo: " << edgePointTwo[k]
11611 << endl;
11612 cerr << "k: " << k << " cutpointone: " << cutPointOne[k] << " cutpointtwo: " << cutPointTwo[k]
11613 << endl;
11614 cerr << "divisorPosition: " << divisorPosition << endl;
11615 cerr << "cut points are probably parallel to the edge. continue";
11616 continueing = true;
11617 }
11618 }
11619 if(continueing == true) {
11620 continueing = false;
11621 continue;
11622 }
11623
11624 if(zero == true) {
11625 for(MInt l = 0; l < 3; l++) {
11626 cutPoint[l] = cutPoint[l] - 1;
11627 edgePointOne[l] = edgePointOne[l] - 1;
11628 }
11629 }
11630 if(newCutPointAdjustment == true) {
11631 for(MInt m = 0; m < 3; m++) {
11632 if(abs(edgePointOne[m] - cutPoint[m]) < 0.00000001) { // TODO labels:FV,toenhance,
11633 // why this number, isnt there
11634 // some functionwide eps
11635 cutPoint[m] = edgePointOne[m];
11636 }
11637 }
11638 }
11639 for(MInt n = 0; n < 3; n++) {
11640 if(edgePointTwo[n] > edgePointOne[n] && abs(edgePointOne[n] - cutPoint[n]) > eps
11641 && (edgePointTwo[n] - edgePointOne[n]) > (edgePointTwo[n] - cutPoint[n])
11642 && (edgePointTwo[n] - cutPoint[n]) > 0) {
11643 // cerr << "cut point is on the edge" << endl;
11644 newCutPoint = true;
11645 }
11646 if(edgePointTwo[n] < edgePointOne[n] && abs(edgePointOne[n] - cutPoint[n]) > eps
11647 && (edgePointOne[n] - edgePointTwo[n]) > (edgePointOne[n] - cutPoint[n])
11648 && (edgePointOne[n] - cutPoint[n]) > 0) {
11649 // cerr << "cut point is on the edge" << endl;
11650 newCutPoint = true;
11651 }
11652 }
11653
11654 if(newCutPoint == false) {
11655 continue;
11656 }
11657 cerr << "(this is not an error) a non boundary cell with cut points has been found. parentId: " << parentId
11658 << " cellId: " << cellId << endl;
11659 // create a new boundary cell
11660 bndryId = m_bndryCells->size() - 1;
11661 if(m_bndryCells->a[bndryId].m_cellId != cellId) {
11662 cerr << "(this is not an error) creating a new boundary cell; cellId: " << cellId
11663 << " bndryCellId: " << m_bndryCells->a[bndryId].m_cellId << endl;
11664 // increase collector size by one
11665 MInt size = m_bndryCells->size();
11666 cerr << size << endl;
11667 m_bndryCells->resetSize(size + 1);
11668 bndryId++;
11669
11670 // set the boundary cell properties of the new boundary cell
11671 m_solver->a_isInterface(cellId) = true;
11672 m_solver->a_bndryId(cellId) = bndryId;
11673 m_bndryCells->a[bndryId].m_cellId = cellId;
11674 m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = true;
11675 m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) = false;
11676 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] = -1;
11677 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] = -1;
11678 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] = -1;
11679 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] = -1;
11680 }
11681
11682 if(m_bndryCells->a[bndryId].m_cellId == cellId) {
11683 // store the cut point in the new boundary cell
11684 cerr << "(this is not an error) cut point is saved in the new boundary cell; cellId: " << cellId
11685 << " bndryId: " << bndryId << endl;
11686 if(newEdgeCut[0] != -1) {
11687 newEdgeCut[1] = edge;
11688 }
11689 if(newEdgeCut[0] == -1) {
11690 newEdgeCut[0] = edge;
11691 }
11692 noNewCutPoints++;
11693 // store cut points in the data structure
11694 MInt cutPointNo = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
11695 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPointNo] = edge;
11696 // set the bndry cnd
11697 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cutPointNo] =
11698 m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_bodyId[0];
11699 for(MInt x = 0; x < nDim; x++) {
11700 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPointNo][x] = cutPoint[x];
11701 }
11702 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints++;
11703 m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId =
11704 m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_bndryCndId;
11705 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints == 2) {
11706 MInt counter = 0;
11707 MFloat pointDifference[3] = {0, 0, 0};
11708 MFloat cutCoordinates[3] = {0, 0, 0};
11709 const MInt edgeInCorner[8][3] = {{0, 2, 8}, {1, 2, 9}, {0, 3, 10}, {1, 3, 11},
11710 {4, 6, 8}, {5, 6, 9}, {4, 7, 10}, {5, 7, 11}};
11711 MInt additionalCutEdge = -1;
11712 for(MInt x = 0; x < 8; x++) {
11713 for(MInt z = 0; z < 3; z++) {
11714 if(edgeInCorner[x][z] == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[0]) {
11715 counter++;
11716 }
11717 if(edgeInCorner[x][z] == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[1]) {
11718 counter++;
11719 }
11720 }
11721 if(counter == 2) {
11722 for(MInt y = 0; y < 3; y++) {
11723 if(edgeInCorner[x][y] != m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[0]
11724 && edgeInCorner[x][y] != m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[1]) {
11725 additionalCutEdge = edgeInCorner[x][y];
11726 }
11727 }
11728 }
11729 counter = 0;
11730 }
11731 for(MInt j = 0; j < 3; j++) {
11732 edgePointOne[j] = cornersCell(nodeStencil[0][additionalCutEdge], j);
11733 edgePointTwo[j] = cornersCell(nodeStencil[1][additionalCutEdge], j);
11734 pointDifference[j] = edgePointTwo[j] - edgePointOne[j];
11735 pointDifference[j] = pointDifference[j] / 2;
11736 cutCoordinates[j] = edgePointOne[j] + pointDifference[j];
11737 }
11738 // store cut points in the data structure
11739 MInt cutPointNo3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
11740 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPointNo3] = additionalCutEdge;
11741 // set the bndry cnd
11742 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cutPointNo3] =
11743 m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_bodyId[0];
11744 for(MInt x = 0; x < nDim; x++) {
11745 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPointNo3][x] = cutCoordinates[x];
11746 }
11747 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints++;
11748 }
11749 cerr << "(this is not an error) number of cut points (should first be 1 and then 3): "
11750 << m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints << endl;
11751 }
11752 }
11753
11754 if(newEdgeCut[0] != -1 && newEdgeCut[1] != -1) {
11755 bndryId = m_bndryCells->size() - 1;
11756 MInt additionalCutEdge = -1;
11757 MFloat pointDifference[3] = {0, 0, 0};
11758 MFloat cutCoordinates[3] = {0, 0, 0};
11759 const MInt edgeFaceStencil[6][4] = {{8, 10, 0, 4}, {9, 11, 1, 5}, {2, 6, 8, 9},
11760 {3, 7, 10, 11}, {0, 1, 2, 3}, {4, 5, 6, 7}};
11761 const MInt edgeInCorner[8][3] = {{0, 2, 8}, {1, 2, 9}, {0, 3, 10}, {1, 3, 11},
11762 {4, 6, 8}, {5, 6, 9}, {4, 7, 10}, {5, 7, 11}};
11763 for(MInt i = 0; i < 8; i++) {
11764 MInt additionalCutPoint = -1;
11765 MInt counter = 0;
11766 additionalCutEdge = -1;
11767 for(MInt j = 0; j < 3; j++) {
11768 if(edgeInCorner[i][j] == newEdgeCut[0]) {
11769 counter++;
11770 }
11771 if(edgeInCorner[i][j] == newEdgeCut[1]) {
11772 counter++;
11773 }
11774 if(counter == 2) {
11775 additionalCutPoint = 1;
11776 // is this correct?
11777 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] = i;
11778 cerr << i << endl;
11779 }
11780 }
11781 counter = 0;
11782 if(additionalCutPoint == 1) {
11783 for(MInt j = 0; j < 3; j++) {
11784 if(edgeInCorner[i][j] != newEdgeCut[0] && edgeInCorner[i][j] != newEdgeCut[1]) {
11785 additionalCutEdge = edgeInCorner[i][j];
11786 }
11787 }
11788 for(MInt j = 0; j < 3; j++) {
11789 edgePointOne[j] = cornersCell(nodeStencil[0][additionalCutEdge], j);
11790 edgePointTwo[j] = cornersCell(nodeStencil[1][additionalCutEdge], j);
11791 pointDifference[j] = edgePointTwo[j] - edgePointOne[j];
11792 pointDifference[j] = pointDifference[j] / 2;
11793 cutCoordinates[j] = edgePointOne[j] + pointDifference[j];
11794 }
11795 // if the cell used to be cut and isnt cut anymore it is also a problem cell
11796 for(MInt k = 0; k < 6; k++) {
11797 counter = 0;
11798 MInt problemFace = -1;
11799 for(MInt l = 0; l < 4; l++) {
11800 if(additionalCutEdge == edgeFaceStencil[k][l]) {
11801 counter++;
11802 }
11803 }
11804 for(MInt l = 0; l < 4; l++) {
11805 if(counter == 1) {
11806 if(newEdgeCut[0] != -1 && newEdgeCut[1] != -1) {
11807 if(newEdgeCut[1] == edgeFaceStencil[k][l] || newEdgeCut[0] == edgeFaceStencil[k][l]) {
11808 counter++;
11809 }
11810 }
11811 if(counter == 2
11812 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1) {
11813 problemFace = k;
11814 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] = k;
11815 }
11816 if(counter == 2
11817 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] == -1) {
11818 problemFace = k;
11819 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] = k;
11820 }
11821 counter = 1;
11822 if(counter != 1) {
11823 cerr << problemFace << endl;
11824 }
11825 }
11826 }
11827 }
11828 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] != -1
11829 && m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] != -1) {
11830 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] = direction;
11831 }
11832 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints == 50) {
11833 noNewCutPoints++;
11834 // store cut points in the data structure
11835 MInt cutPointNo = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
11836 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPointNo] = additionalCutEdge;
11837 // set the bndry cnd
11838 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cutPointNo] =
11839 m_bndryCells->a[nghbrbndryId].m_srfcs[0]->m_bodyId[0];
11840 for(MInt x = 0; x < nDim; x++) {
11841 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPointNo][x] = cutCoordinates[x];
11842 }
11843 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints++;
11844 }
11845 }
11846 } // loop from 0 to 7, might be corners
11847 } // newEdgeCut condition
11848 } // noEdgesCut == 2 condition
11849 } // if problem cell
11850 } // loop over direction
11851 } // loop over all cells
11852
11853
11854 checkCutPointsValidity();
11855 // some not-inside and not-boundary cells in the grid are made inactive.
11856 // These cells follow from setting ggp_keepOutsideBndryCellChildren = 1
11857 // during the grid generation. CutOffInterface cells need to be excluded
11858 // No idea what this -5 code does ... may be bs
11859 // TODO labels:FV,toenhance additional actually-outside cells should be created on demand during
11860 // the solver run, then this 'dangerous' loop over all cells is obsolete in
11861 // the bndrycnd class
11862 for(MInt cellId = 0; cellId < m_solver->a_noCells(); cellId++) {
11863 if(m_solver->a_bndryId(cellId) == -1 && !checkInside(cellId)) { //&&
11865 //&& m_solver->c_noChildren( cellId ) == 0
11866 //&& isCutOffInterface(cellId))){
11867 m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
11868 m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) = true;
11869 }
11870 if(m_solver->a_bndryId(cellId) == -5) {
11871 m_solver->a_bndryId(cellId) = -1;
11872 }
11873 }
11874
11875
11876 // plotAllCutPoints();
11877}
11878
11879
11889template <MInt nDim, class SysEqn>
11891 TRACE();
11892
11893 const MInt noCells = m_bndryCells->size();
11894 // boundary cells with not enough cut points should be removed -> important: check, if corresponding cell should also
11895 // be removed! mark boundary cells with less than 3/2 cut points
11896 for(MInt bndryId = noCells - 1; bndryId > -1; bndryId--) {
11897 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
11898 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints < nDim) {
11899#ifndef NDEBUG
11900 m_log << "cell " << cellId << " on level " << m_solver->a_level(cellId) << " with globalId "
11901 << m_solver->c_globalId(cellId) << " has less than " << nDim << " cut points! deleting bndryCell! " << endl;
11902#endif
11903
11904 m_solver->a_isInterface(cellId) = false;
11905 m_solver->a_hasProperty(cellId, SolverCell::IsMovingBnd) = false;
11906 m_solver->a_bndryId(cellId) = -1;
11907 m_solver->a_bndryId(m_bndryCells->a[bndryId].m_cellId) = -1;
11908 deleteBndryCell(bndryId);
11909
11910 // If the deleted bounday cell was not the last cell in m_bndryCells the last cell was moved
11911 // to the position of the deleted cell and its corresponding bndryId needs to be updated!
11912 if(bndryId < m_bndryCells->size()) {
11913 m_solver->a_bndryId(m_bndryCells->a[bndryId].m_cellId) = bndryId;
11914 }
11915
11916 // if cell is not located fully in the fluid domain, mark it as inactive
11917 // do not really delete the cell, as this leas to inconsistencies with the other domains resulting from cell
11918 // reordering!
11919 if(!checkInside(cellId)) {
11920#ifndef NDEBUG
11921 if(m_solver->c_noChildren(cellId) == 0) {
11922 cerr << domainId() << ": cell deactivated"
11923 << ", cellId " << cellId << ", globalId " << m_solver->c_globalId(cellId) << ", level "
11924 << m_solver->a_level(cellId) << endl;
11925 }
11926#endif
11927 m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
11928 m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) = true;
11929
11930 MInt parentId = m_solver->c_parentId(cellId);
11931 MInt itCnt = 0;
11932 while(parentId > -1) {
11933 m_solver->a_hasProperty(parentId, SolverCell::IsOnCurrentMGLevel) = false;
11934 m_solver->a_hasProperty(parentId, SolverCell::IsInvalid) = true;
11935 // cerr << domainId() <<": parent " << parentId << " " << m_solver->c_globalId( parentId ) << endl;
11936 // if ( m_solver->c_parentId( parentId ) == -1 ) cerr << domainId() <<": parent " << parentId << endl;
11937 parentId = m_solver->c_parentId(parentId);
11938 itCnt++;
11939 if(itCnt > m_solver->maxLevel() - m_solver->minLevel()) {
11940 mTerm(1, AT_, "Invalid parent relations.");
11941 }
11942 }
11943 }
11944 }
11945 }
11946}
11947
11948
11959template <MInt nDim, class SysEqn>
11961 TRACE();
11962
11963 // 1. basic init
11964 const MInt noCells = m_bndryCells->size();
11965 const MInt* traverseOrder = traverseCorners2D;
11966 IF_CONSTEXPR(nDim == 3) traverseOrder = traverseCorners3D;
11967
11968 MInt noCorners = IPOW2(nDim);
11969 MInt noShares = noCorners - 1;
11970
11971 MIntScratchSpace sharedCorners(noCorners, noShares, AT_, "sharedCorners");
11972 for(MInt c = 0; c < noCorners; c++) {
11973 for(MInt s = 0; s < noShares; s++) {
11974 IF_CONSTEXPR(nDim == 2) { sharedCorners(c, s) = sharedCornerNeighs2D[c][s]; }
11975 else {
11976 sharedCorners(c, s) = sharedCornerNeighs3D[c][s];
11977 }
11978 }
11979 }
11980
11981
11982 // 2. prepare: how many of the cells that we need to consider are totally outside?
11983 vector<MInt> missing;
11984
11985 // 2.1 find first only those that are easily detectable, i.e., cells that have a neighbor which is not an
11986 // interface cell. That is, run over all neighbors and check for the property IsInterface.
11987 // If a cell has only interface neighbors, it is added to the missing list that is processed in 2.2.
11988 for(MInt bndryId = noCells - 1; bndryId > -1; bndryId--) {
11989 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints < nDim) {
11990 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
11991 MBool found = false;
11992 MInt insidePt = -1;
11993
11994 // search a corner point that is inside for sure
11995 for(MInt corner = 0; corner < IPOW2(nDim); corner++) {
11996 for(MInt s = 0; s < noShares; s++) {
11997 MInt dir = sharedCorners(corner, s);
11998 if(m_solver->a_hasNeighbor(cellId, dir)
11999 && !m_solver->a_hasProperty(m_solver->c_neighborId(cellId, dir), SolverCell::IsInterface)) {
12000 found = true;
12001 insidePt = corner;
12002 break;
12003 }
12004 }
12005 if(found) break;
12006 }
12007
12008 // we found a corner of the current cell that is definitively inside
12009 if(found) {
12010 // perform a check if there is a way to an outside cell, then this cell
12011 // is not completely located inside
12012 cout << insidePt << " " << traverseOrder << endl;
12013 } else {
12014 }
12015 /*
12016
12017
12018 //run over all neighbors
12019 for(MInt n = 0; n < noNeigh; n++)
12020 {
12021 //great we found one
12022 if(m_solver->a_hasNeighbor(cellId, n) && !m_solver->a_hasProperty( m_solver->c_neighborId(cellId,n) ,
12023 SolverCell::IsInterface) )
12024 {
12025 found = true;
12026 bndCellIsOutside.insert(pair<MInt,MBool>(cellId,true));
12027 break;
12028 }
12029
12030 if(found)
12031 break;
12032 }
12033
12034 //the cell is either isolated or all neighbors are interface cells
12035 if(!found)
12036 missing.push_back(cellId);
12037
12038 */
12039 }
12040 }
12041
12042
12043 // 2.2 run over the cells that have
12044 if(!missing.empty()) {
12045 }
12046
12047 for(MInt bndryId = noCells - 1; bndryId > -1; bndryId--) {
12048 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
12049
12050 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints < nDim) {
12051#ifndef NDEBUG
12052 m_log << "cell " << cellId << " on level " << m_solver->a_level(cellId) << " with globalId "
12053 << m_solver->c_globalId(cellId) << " has less than " << nDim << " cut points! deleting bndryCell! " << endl;
12054#endif
12055
12056 m_solver->a_isInterface(cellId) = false;
12057 m_solver->a_bndryId(cellId) = -1;
12058 m_solver->a_bndryId(m_bndryCells->a[bndryId].m_cellId) = -1;
12059 deleteBndryCell(bndryId);
12060
12061 // If the deleted bounday cell was not the last cell in m_bndryCells the last cell was moved
12062 // to the position of the deleted cell and its corresponding bndryId needs to be updated!
12063 if(bndryId < m_bndryCells->size()) {
12064 m_solver->a_bndryId(m_bndryCells->a[bndryId].m_cellId) = bndryId;
12065 }
12066
12067 // if cell is not located fully in the fluid domain, mark it as inactive
12068 // do not really delete the cell, as this leas to inconsistencies with the other domains resulting from cell
12069 // reordering!
12070 if(!checkInside(cellId)) {
12071#ifndef NDEBUG
12072 if(m_solver->c_noChildren(cellId) == 0)
12073 cerr << domainId() << ": cell deactivated"
12074 << ", cellId " << cellId << ", globalId " << m_solver->c_globalId(cellId) << ", level "
12075 << m_solver->a_level(cellId) << endl;
12076#endif
12077
12078 m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
12079 m_solver->a_hasProperty(cellId, SolverCell::IsInvalid) = true;
12080
12081 MInt parentId = m_solver->c_parentId(cellId);
12082 while(parentId > -1) {
12083 m_solver->a_hasProperty(parentId, SolverCell::IsOnCurrentMGLevel) = false;
12084 m_solver->a_hasProperty(parentId, SolverCell::IsInvalid) = true;
12085
12086 parentId = m_solver->c_parentId(parentId);
12087 }
12088 }
12089 }
12090 }
12091}
12092
12093
12094// required for bndryRfnJumpMethod
12095// exchange of all window cell cut information to corresponding halo cells
12096// 30 informations need to be exchanged (noCutPoints(1), cutEdges(6), bodyId(1), cutCoordinates(18),
12097// m_bndryRfnJumpInformation(4)
12098template <MInt nDim, class SysEqn>
12100 TRACE();
12101 MBool bndryRfnJump = false;
12102 bndryRfnJump = Context::getSolverProperty<MBool>("bndryRfnJump", m_solverId, AT_, &bndryRfnJump);
12103
12104 if(bndryRfnJump == 0) {
12105 return;
12106 }
12107 m_log << "processing MInts " << endl;
12108 MIntScratchSpace idSendRecBuffers(m_solver->a_noCells() * 12, AT_, "idSendRecBuffers");
12109 idSendRecBuffers.fill(0);
12110
12111 MInt cnt = 0;
12112 for(MInt cellId = 0; cellId < m_solver->a_noCells(); cellId++) {
12113 if(m_solver->a_bndryId(cellId) < 0) {
12114 continue;
12115 }
12116 MInt bndryId = m_solver->a_bndryId(cellId);
12117 idSendRecBuffers[cellId * 12 + 0] = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
12118 idSendRecBuffers[cellId * 12 + 1] = m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[0];
12119 idSendRecBuffers[cellId * 12 + 2] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[0];
12120 idSendRecBuffers[cellId * 12 + 3] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[1];
12121 idSendRecBuffers[cellId * 12 + 4] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[2];
12122 idSendRecBuffers[cellId * 12 + 5] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[3];
12123 idSendRecBuffers[cellId * 12 + 6] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[4];
12124 idSendRecBuffers[cellId * 12 + 7] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[5];
12125 idSendRecBuffers[cellId * 12 + 8] = m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0];
12126 idSendRecBuffers[cellId * 12 + 9] = m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1];
12127 idSendRecBuffers[cellId * 12 + 10] = m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2];
12128 idSendRecBuffers[cellId * 12 + 11] = m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3];
12129
12130 if(idSendRecBuffers[cellId * 12 + 0] > 0 && m_solver->a_isWindow(cellId)) {
12131 cnt++;
12132 }
12133 }
12134 m_log << "... " << cnt << " window boundary cells to exchange to all domains ... (Ids) " << endl;
12135
12136 m_solver->exchangeData(&idSendRecBuffers[0], 12);
12137
12138 for(MInt i = 0; i < m_solver->noNeighborDomains(); i++) {
12139 for(MInt j = 0; j < m_solver->noHaloCells(i); j++) {
12140 MInt thishaloCellId = m_solver->haloCellId(i, j);
12141 MInt bndryId = m_solver->a_bndryId(thishaloCellId);
12142 if(m_solver->a_bndryId(thishaloCellId) < 0) {
12143 continue;
12144 }
12145 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints = idSendRecBuffers[thishaloCellId * 12 + 0];
12146 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[0] = idSendRecBuffers[thishaloCellId * 12 + 1];
12147 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[1] = idSendRecBuffers[thishaloCellId * 12 + 1];
12148 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[2] = idSendRecBuffers[thishaloCellId * 12 + 1];
12149 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[3] = idSendRecBuffers[thishaloCellId * 12 + 1];
12150 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[4] = idSendRecBuffers[thishaloCellId * 12 + 1];
12151 m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[5] = idSendRecBuffers[thishaloCellId * 12 + 1];
12152 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[0] = idSendRecBuffers[thishaloCellId * 12 + 2];
12153 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[1] = idSendRecBuffers[thishaloCellId * 12 + 3];
12154 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[2] = idSendRecBuffers[thishaloCellId * 12 + 4];
12155 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[3] = idSendRecBuffers[thishaloCellId * 12 + 5];
12156 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[4] = idSendRecBuffers[thishaloCellId * 12 + 6];
12157 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[5] = idSendRecBuffers[thishaloCellId * 12 + 7];
12158 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] =
12159 idSendRecBuffers[thishaloCellId * 12 + 8];
12160 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] =
12161 idSendRecBuffers[thishaloCellId * 12 + 9];
12162 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] =
12163 idSendRecBuffers[thishaloCellId * 12 + 10];
12164 m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] =
12165 idSendRecBuffers[thishaloCellId * 12 + 11];
12166 }
12167 }
12168 m_log << " finished. " << endl;
12169
12170 m_log << "processing MFloats " << endl;
12171 MFloatScratchSpace floatSendRecBuffers(m_solver->a_noCells() * 18, AT_, "floatSendRecBuffers");
12172 floatSendRecBuffers.fill(0);
12173
12174 cnt = 0;
12175 for(MInt cellId = 0; cellId < m_solver->a_noCells(); cellId++) {
12176 if(m_solver->a_bndryId(cellId) < 0) {
12177 continue;
12178 }
12179 MInt bndryId = m_solver->a_bndryId(cellId);
12180
12181 floatSendRecBuffers[cellId * 18 + 0] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[0][0];
12182 floatSendRecBuffers[cellId * 18 + 1] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[0][1];
12183 floatSendRecBuffers[cellId * 18 + 2] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[0][2];
12184 floatSendRecBuffers[cellId * 18 + 3] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[1][0];
12185 floatSendRecBuffers[cellId * 18 + 4] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[1][1];
12186 floatSendRecBuffers[cellId * 18 + 5] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[1][2];
12187 floatSendRecBuffers[cellId * 18 + 6] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[2][0];
12188 floatSendRecBuffers[cellId * 18 + 7] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[2][1];
12189 floatSendRecBuffers[cellId * 18 + 8] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[2][2];
12190 floatSendRecBuffers[cellId * 18 + 9] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[3][0];
12191 floatSendRecBuffers[cellId * 18 + 10] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[3][1];
12192 floatSendRecBuffers[cellId * 18 + 11] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[3][2];
12193 floatSendRecBuffers[cellId * 18 + 12] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[4][0];
12194 floatSendRecBuffers[cellId * 18 + 13] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[4][1];
12195 floatSendRecBuffers[cellId * 18 + 14] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[4][2];
12196 floatSendRecBuffers[cellId * 18 + 15] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[5][0];
12197 floatSendRecBuffers[cellId * 18 + 16] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[5][1];
12198 floatSendRecBuffers[cellId * 18 + 17] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[5][2];
12199 if((floatSendRecBuffers[cellId * 18 + 0] > 0 || floatSendRecBuffers[cellId * 18 + 1] > 0
12200 || floatSendRecBuffers[cellId * 18 + 2] > 0 || floatSendRecBuffers[cellId * 18 + 3] > 0
12201 || floatSendRecBuffers[cellId * 18 + 4] > 0 || floatSendRecBuffers[cellId * 18 + 5] > 0
12202 || floatSendRecBuffers[cellId * 18 + 6] > 0 || floatSendRecBuffers[cellId * 18 + 7] > 0
12203 || floatSendRecBuffers[cellId * 18 + 8] > 0 || floatSendRecBuffers[cellId * 18 + 9] > 0
12204 || floatSendRecBuffers[cellId * 18 + 10] > 0 || floatSendRecBuffers[cellId * 18 + 11] > 0
12205 || floatSendRecBuffers[cellId * 18 + 12] > 0 || floatSendRecBuffers[cellId * 18 + 13] > 0
12206 || floatSendRecBuffers[cellId * 18 + 14] > 0 || floatSendRecBuffers[cellId * 18 + 15] > 0
12207 || floatSendRecBuffers[cellId * 18 + 16] > 0 || floatSendRecBuffers[cellId * 18 + 17] > 0
12208 || floatSendRecBuffers[cellId * 18 + 0] < 0 || floatSendRecBuffers[cellId * 18 + 1] < 0
12209 || floatSendRecBuffers[cellId * 18 + 2] < 0 || floatSendRecBuffers[cellId * 18 + 3] < 0
12210 || floatSendRecBuffers[cellId * 18 + 4] < 0 || floatSendRecBuffers[cellId * 18 + 5] < 0
12211 || floatSendRecBuffers[cellId * 18 + 6] < 0 || floatSendRecBuffers[cellId * 18 + 7] < 0
12212 || floatSendRecBuffers[cellId * 18 + 8] < 0 || floatSendRecBuffers[cellId * 18 + 9] < 0
12213 || floatSendRecBuffers[cellId * 18 + 10] < 0 || floatSendRecBuffers[cellId * 18 + 11] < 0
12214 || floatSendRecBuffers[cellId * 18 + 12] < 0 || floatSendRecBuffers[cellId * 18 + 13] < 0
12215 || floatSendRecBuffers[cellId * 18 + 14] < 0 || floatSendRecBuffers[cellId * 18 + 15] < 0
12216 || floatSendRecBuffers[cellId * 18 + 16] < 0 || floatSendRecBuffers[cellId * 18 + 17] < 0)
12217 && m_solver->a_isWindow(cellId)) {
12218 cnt++;
12219 }
12220 }
12221 m_log << "... " << cnt << " window boundary cells to exchange to all domains ... (Floats) " << endl;
12222
12223
12224 m_solver->exchangeData(&floatSendRecBuffers[0], 18);
12225 for(MInt i = 0; i < m_solver->noNeighborDomains(); i++) {
12226 for(MInt j = 0; j < m_solver->noHaloCells(i); j++) {
12227 MInt thishaloCellId = m_solver->haloCellId(i, j);
12228 MInt bndryId = m_solver->a_bndryId(thishaloCellId);
12229 if(m_solver->a_bndryId(thishaloCellId) < 0) {
12230 continue;
12231 }
12232
12233 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[0][0] = floatSendRecBuffers[thishaloCellId * 18 + 0];
12234 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[0][1] = floatSendRecBuffers[thishaloCellId * 18 + 1];
12235 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[0][2] = floatSendRecBuffers[thishaloCellId * 18 + 2];
12236 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[1][0] = floatSendRecBuffers[thishaloCellId * 18 + 3];
12237 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[1][1] = floatSendRecBuffers[thishaloCellId * 18 + 4];
12238 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[1][2] = floatSendRecBuffers[thishaloCellId * 18 + 5];
12239 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[2][0] = floatSendRecBuffers[thishaloCellId * 18 + 6];
12240 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[2][1] = floatSendRecBuffers[thishaloCellId * 18 + 7];
12241 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[2][2] = floatSendRecBuffers[thishaloCellId * 18 + 8];
12242 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[3][0] = floatSendRecBuffers[thishaloCellId * 18 + 9];
12243 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[3][1] = floatSendRecBuffers[thishaloCellId * 18 + 10];
12244 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[3][2] = floatSendRecBuffers[thishaloCellId * 18 + 11];
12245 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[4][0] = floatSendRecBuffers[thishaloCellId * 18 + 12];
12246 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[4][1] = floatSendRecBuffers[thishaloCellId * 18 + 13];
12247 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[4][2] = floatSendRecBuffers[thishaloCellId * 18 + 14];
12248 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[5][0] = floatSendRecBuffers[thishaloCellId * 18 + 15];
12249 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[5][1] = floatSendRecBuffers[thishaloCellId * 18 + 16];
12250 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[5][2] = floatSendRecBuffers[thishaloCellId * 18 + 17];
12251 }
12252 }
12253 m_log << " finished. " << endl;
12254}
12255
12256
12261template <MInt nDim, class SysEqn>
12263 TRACE();
12264
12265 const MChar* fileName = "AllCutPoints_";
12266 stringstream fileName2;
12267 fileName2 << fileName << domainId() << ".vtk";
12268 ofstream ofl;
12269 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
12270
12271 MInt noCutPoints = 0;
12272 const MInt noCells = m_bndryCells->size();
12273
12274 //-------------------------------------
12275
12276 // count the total number of cut points
12277 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
12278 noCutPoints += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
12279 }
12280
12281 if(ofl) {
12282 ofl.setf(ios::fixed);
12283 ofl.precision(20);
12284
12285 ofl << "# vtk DataFile Version 3.0" << endl
12286 << "MAIAD intersectionPoints file" << endl
12287 << "ASCII" << endl
12288 << "DATASET POLYDATA" << endl
12289 << "POINTS " << noCutPoints << " float" << endl;
12290
12291 // write each cut point in the data file
12292 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
12293 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints > 0) {
12294 for(MInt edge = 0; edge < m_noEdges; edge++) {
12295 for(MInt n = 0; n < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; n++) {
12296 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[n] == edge) {
12297 for(MInt i = 0; i < nDim; i++) {
12298 ofl << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[n][i] << " ";
12299 }
12300 IF_CONSTEXPR(nDim == 2) ofl << F0 << " ";
12301 ofl << endl;
12302 }
12303 }
12304 }
12305 }
12306 }
12307
12308 ofl << "VERTICES " << noCutPoints << " " << noCutPoints * 2 << endl;
12309 for(MInt i = 0; i < noCutPoints; i++) {
12310 ofl << "1 " << i << endl;
12311 }
12312 }
12313
12314 ofl.close();
12315}
12316
12317
12323template <MInt nDim, class SysEqn>
12325 MFloat* referencePoint) {
12326 MFloat inflowArea = F0;
12327 for(MInt i = F0; i < nDim; i++) {
12328 referencePoint[i] = F0;
12329 }
12330
12331 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
12332 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
12333
12334 if(m_solver->a_isHalo(cellId)) continue;
12335 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
12336 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
12337
12338 const MInt bndryId = m_solver->a_bndryId(cellId);
12339
12340 MFloat area = F0;
12341 if(bndryId > -1) {
12342 // identify the "boundary surface" between cutoff boundary cell
12343 // and neighboring layer cell if cell is a boundary cell
12344 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
12345 if(srfcId > -1) {
12346 area = m_solver->a_surfaceArea(srfcId);
12347 } else {
12348 for(MInt dir = 0; dir < m_noDirs; dir++) {
12349 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dir];
12350 if(srfcId > -1) break;
12351 }
12352 if(srfcId == -1) {
12353 cerr << "[" << domainId() << "]: did not find associated surface in dir " << dirN << " for cell " << cellId
12354 << endl;
12355 writeStlFileOfCell(cellId, "cell.stl");
12356 mTerm(1, AT_, "something went wrong!");
12357 }
12358 area = m_solver->a_surfaceArea(srfcId);
12359 }
12360 } else {
12361 IF_CONSTEXPR(nDim == 2) { area = m_solver->c_cellLengthAtCell(cellId); }
12362 else {
12363 area = POW2(m_solver->c_cellLengthAtCell(cellId));
12364 }
12365 }
12366 inflowArea += area;
12367 // compute midpoint of inflow boundary and mean normal
12368 for(MInt i = 0; i < nDim; i++) {
12369 referencePoint[i] += m_solver->a_coordinate(cellId, i) * area;
12370 }
12371 }
12372
12373 MInt minDom = domainId();
12374
12375 if(noDomains() > 1) {
12376 const MInt noExchangeData = 1 + nDim;
12377 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
12378 comm_buff[0] = inflowArea;
12379 for(MInt i = 0; i < nDim; i++) {
12380 comm_buff[i + 1] = referencePoint[i];
12381 }
12382
12383 MPI_Allreduce(MPI_IN_PLACE, &comm_buff[0], noExchangeData, MPI_DOUBLE, MPI_SUM,
12384 m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_, "MPI_IN_PLACE", "comm_buff[0]");
12385 MPI_Allreduce(MPI_IN_PLACE, &minDom, 1, MPI_INT, MPI_MIN, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
12386 "MPI_IN_PLACE", "minDom");
12387
12388 inflowArea = comm_buff[0];
12389 for(MInt i = 0; i < nDim; i++) {
12390 referencePoint[i] = comm_buff[i + 1];
12391 }
12392 }
12393
12394 for(MInt i = 0; i < nDim; i++) {
12395 referencePoint[i] /= inflowArea;
12396 }
12397
12398 stringstream referencePointOutputStream;
12399 referencePointOutputStream << referencePoint[0] << " " << referencePoint[1] << " ";
12400 IF_CONSTEXPR(nDim == 3) referencePointOutputStream << referencePoint[2] << " ";
12401
12402 if(domainId() == minDom) {
12403 cerr << " [" << domainId() << "]: bndryId: " << bcId << " refPoint: " << referencePointOutputStream.str()
12404 << ", area: " << inflowArea << endl;
12405 }
12406
12407 return inflowArea;
12408}
12409
12410
12411/*
12412 * \author Daniel Hartmann, 22.12.2006
12413 *
12414 */
12415template <MInt nDim, class SysEqn>
12417 TRACE();
12418
12419 MInt noCells = m_solver->a_noCells();
12420 MInt noDirs = 2 * nDim;
12421 //--- end of initialization
12422
12423 m_bndryCells->resetSize(0);
12424
12425 for(MInt cellId = 0; cellId < noCells; cellId++) {
12426 if(m_solver->a_isInterface(cellId)) {
12427 if(isCutOffInterface(cellId)) {
12428 continue;
12429 }
12430 MInt bndryId = m_bndryCells->size();
12431 m_bndryCells->append();
12432 m_bndryCells->a[bndryId].m_cellId = cellId;
12433 m_bndryCells->a[bndryId].m_linkedCellId = -1;
12434 for(MInt face = 0; face < noDirs; face++) {
12435 m_bndryCells->a[bndryId].m_associatedSrfc[face] = -1;
12436 }
12437 for(MInt i = 0; i < nDim; i++) {
12438 m_bndryCells->a[bndryId].m_coordinates[i] = F0;
12439 }
12440 }
12441 }
12442}
12443
12444
12450template <MInt nDim, class SysEqn>
12452 TRACE();
12453
12454 createBndryCells();
12455
12456 computeReverseMap();
12457
12458 computeCutPoints();
12459
12460 // bndryRfnJumpMethod needs this
12461 exchangeComputedCutPoints();
12462
12463 if(m_multipleGhostCells || m_solver->m_useCreateCutFaceMGC) {
12464 createCutFaceMGC();
12465#ifndef NDEBUG
12466 cerr << "cut faces created! " << endl;
12467#endif
12468 } else {
12469 createCutFace();
12470 }
12471
12472 // compute special cut cells at in/outflow boundaries where the sharp edge should be preserved
12473 if(m_multipleGhostCells) {
12474 MFloatScratchSpace normal_scratch(nDim, AT_, "normal_scratch");
12475 MFloatScratchSpace referencePoint_scratch(nDim, AT_, "referencePoint_scratch");
12476 MFloat* normal = normal_scratch.getPointer();
12477 MFloat* referencePoint = referencePoint_scratch.getPointer();
12478 MInt noInflowCorrectionBoundaries = 0;
12479 MInt bcId;
12480 MBool normalsCentersSpecified = false;
12481 if(Context::propertyExists("inflowCorrectionBoundaries", m_solverId)) {
12493 noInflowCorrectionBoundaries = Context::propertyLength("inflowCorrectionBoundaries", m_solverId);
12494 }
12495 if(noInflowCorrectionBoundaries) {
12496 if(Context::propertyExists("inflowCorrectionNormals", m_solverId)
12497 && Context::propertyExists("inflowCorrectionCenters", m_solverId)) {
12498 normalsCentersSpecified = true;
12499
12512 if(Context::propertyLength("inflowCorrectionNormals", m_solverId) < noInflowCorrectionBoundaries * nDim) {
12513 cerr << " Warning in FvBndryCnd3D::generateBndryCells: property inflowCorrectionNormals has not enough "
12514 "entries! Go on without normals specified. Please check!"
12515 << endl;
12516 normalsCentersSpecified = false;
12517 }
12518 if(Context::propertyLength("inflowCorrectionCenters", m_solverId) < noInflowCorrectionBoundaries * nDim) {
12519 cerr << " Warning in FvBndryCnd3D::generateBndryCells: property inflowCorrectionCenters has not enough "
12520 "entries! Go on without normals specified. Please check!"
12521 << endl;
12522 normalsCentersSpecified = false;
12523 }
12524 }
12525 }
12526 for(MInt i = 0; i < noInflowCorrectionBoundaries; i++) {
12527 bcId = Context::getSolverProperty<MInt>("inflowCorrectionBoundaries", m_solverId, AT_, i);
12528 if(normalsCentersSpecified) {
12529 cerr << " reading normal and reference point for bndry " << i << " with bcId " << bcId << endl;
12530 for(MInt d = 0; d < nDim; d++) {
12531 normal[d] = Context::getSolverProperty<MFloat>("inflowCorrectionNormals", m_solverId, AT_, i * nDim + d);
12532 referencePoint[d] =
12533 Context::getSolverProperty<MFloat>("inflowCorrectionCenters", m_solverId, AT_, i * nDim + d);
12534 }
12535 cerr << " normal: " << normal[0] << " " << normal[1] << " " << normal[2] << ", refPOint: " << referencePoint[0]
12536 << " " << referencePoint[1] << " " << referencePoint[2] << endl;
12537 correctInflowBoundary(bcId, normal, referencePoint);
12538 } else {
12539 correctInflowBoundary(bcId);
12540 }
12541 }
12542 }
12543
12544 ASSERT(!m_cellCoordinatesCorrected, "");
12545 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
12546 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
12547 if(m_solver->a_hasProperty(cellId, SolverCell::IsInvalid)) continue;
12548 m_bndryCells->a[bndryId].m_gapDistance = std::numeric_limits<MFloat>::max();
12549 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
12550 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance = F0;
12551 for(MInt i = 0; i < nDim; i++) {
12552 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i] =
12553 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
12554 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance +=
12555 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
12556 * (m_solver->a_coordinate(cellId, i) + m_bndryCells->a[bndryId].m_coordinates[i]
12557 - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]);
12558 }
12559 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance =
12560 mMax(F0, m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance);
12561 }
12562 }
12563
12564
12565 if(m_createBoundaryAtCutoff) createBoundaryAtCutoff();
12566
12567 createBndryCndHandler();
12568
12569 createSortedBndryCellList();
12570
12571 if(m_createSpongeBoundary) createSpongeAtSpongeBndryCnds();
12572
12573 checkBoundaryCells();
12574
12575
12576 // create intracommunicator for boundary condition ids
12577 if(globalNoDomains() > 1) {
12578 initBndryCommunications();
12579
12580 // check cutOff-boundary-communicators
12581 for(MInt bcId = 0; bcId < m_noCutOffBndryCndIds; bcId++) {
12582 if(m_sortedCutOffCells[bcId]->size() > 0) {
12583 MInt noTotalCutOffCellsCheck = m_sortedCutOffCells[bcId]->size();
12584 MPI_Allreduce(MPI_IN_PLACE, &noTotalCutOffCellsCheck, 1, MPI_INT, MPI_SUM,
12585 m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_, "INPLACE", "noTotalCutOffCellsCheck");
12586 }
12587 }
12588 }
12589}
12590
12591
12598template <MInt nDim, class SysEqn>
12600 TRACE();
12601
12602
12603 const MInt noCells = m_bndryCells->size();
12604 for(MInt id = 0; id < noCells; id++) {
12605 for(MInt srfc = 0; srfc < m_bndryCells->a[id].m_noSrfcs; srfc++) {
12606 const MInt cellId = m_bndryCells->a[id].m_cellId;
12607 if(!m_multipleGhostCells) {
12608 if(m_solver->c_noChildren(cellId) > 0 || (!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel))) {
12609 continue;
12610 }
12611 }
12612 MFloat testVector0[nDim]{};
12613 MInt component[nDim - 1]{};
12614
12615
12616 if(fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[0])
12617 < fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[1])) {
12618 IF_CONSTEXPR(nDim == 3) {
12619 if(fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[0])
12620 < fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[2])) {
12621 component[0] = 0;
12622 if(fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[1])
12623 < fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[2])) {
12624 component[1] = 1;
12625 } else {
12626 component[1] = 2;
12627 }
12628 } else {
12629 component[0] = 2;
12630 component[1] = 0;
12631 }
12632 }
12633 else IF_CONSTEXPR(nDim == 2) {
12634 component[0] = 0;
12635 }
12636 } else
12637 IF_CONSTEXPR(nDim == 3) {
12638 if(fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[1])
12639 < fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[2])) {
12640 component[0] = 1;
12641 if(fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[0])
12642 < fabs(m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[2])) {
12643 component[1] = 0;
12644 } else {
12645 component[1] = 2;
12646 }
12647 } else {
12648 component[0] = 2;
12649 component[1] = 1;
12650 }
12651 }
12652 else IF_CONSTEXPR(nDim == 2) {
12653 component[0] = 1;
12654 }
12655
12656 testVector0[component[0]] = F1;
12657
12658 // (i) first vector
12659 // scalar product of test vector and normal vector
12660 MFloat sp[nDim - 1]{};
12661 for(MInt i = 0; i < nDim; i++) {
12662 sp[0] += testVector0[i] * m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[i];
12663 }
12664 // 1st orthogonal vector
12665 for(MInt i = 0; i < nDim; i++) {
12666 m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[i] =
12667 testVector0[i] - sp[0] * m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[i];
12668 }
12669 // normalize (use sp[0])
12670 sp[0] = F0;
12671 for(MInt i = 0; i < nDim; i++) {
12672 sp[0] += POW2(m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[i]);
12673 }
12674 sp[0] = F1 / sqrt(sp[0]);
12675 for(MInt i = 0; i < nDim; i++) {
12676 m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[i] *= sp[0];
12677 }
12678 IF_CONSTEXPR(nDim == 3) {
12679 // (ii) second vector
12680 MFloat testVector1[nDim]{};
12681 testVector1[component[1]] = F1;
12682 // scalar product of test vector and normal vector
12683 sp[0] = F0;
12684 for(MInt i = 0; i < nDim; i++) {
12685 sp[0] += testVector1[i] * m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[i];
12686 }
12687 // scalar product of test vector and first plane vector
12688 sp[1] = F0;
12689 for(MInt i = 0; i < nDim; i++) {
12690 sp[1] += testVector1[i] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[i];
12691 }
12692 // 1st orthogonal vector
12693 for(MInt i = 0; i < nDim; i++) {
12694 m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[i] =
12695 testVector1[i] - sp[0] * m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[i]
12696 - sp[1] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[i];
12697 }
12698 // normalize (use sp[])
12699 sp[0] = F0;
12700 for(MInt i = 0; i < nDim; i++) {
12701 sp[0] += POW2(m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[i]);
12702 }
12703 sp[0] = F1 / sqrt(sp[0]);
12704 for(MInt i = 0; i < nDim; i++) {
12705 m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[i] *= sp[0];
12706 }
12707 }
12708
12709 MFloat normalVector[nDim];
12710 if(m_multipleGhostCells) {
12711 // compute the normal vector - already given by surface normal
12712 for(MInt i = 0; i < nDim; i++) {
12713 normalVector[i] = m_bndryCells->a[id].m_srfcs[srfc]->m_normalVector[i];
12714 }
12715 } else {
12716 const MInt ghostCellId = m_bndryCells->a[id].m_srfcVariables[srfc]->m_ghostCellId;
12717
12718 // compute the normal vector - unit vector in direction cellCenter->ghostCellCenter
12719 MFloat coordinates[nDim];
12720
12721 for(MInt i = 0; i < nDim; i++) {
12722 coordinates[i] = m_solver->a_coordinate(cellId, i) - m_solver->a_coordinate(ghostCellId, i);
12723 }
12724 MFloat FtotalDistance = F0;
12725 for(MInt i = 0; i < nDim; i++) {
12726 FtotalDistance += POW2(coordinates[i]);
12727 }
12728 FtotalDistance = F1 / sqrt(FtotalDistance);
12729 for(MInt i = 0; i < nDim; i++) {
12730 normalVector[i] = coordinates[i] * FtotalDistance;
12731 }
12732 }
12733
12734 // compute the Jacobian
12735 MFloat JacobianQuotient;
12736
12737 IF_CONSTEXPR(nDim == 2) {
12738 JacobianQuotient = normalVector[0] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[1]
12739 - normalVector[1] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[0];
12740 }
12741 else IF_CONSTEXPR(nDim == 3) {
12742 JacobianQuotient = normalVector[0] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[1]
12743 * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[2]
12744 + normalVector[1] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[2]
12745 * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[0]
12746 + normalVector[2] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[0]
12747 * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[1]
12748 - normalVector[0] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[2]
12749 * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[1]
12750 - normalVector[1] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[0]
12751 * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[2]
12752 - normalVector[2] * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector0[1]
12753 * m_bndryCells->a[id].m_srfcs[srfc]->m_planeVector1[0];
12754 }
12755 m_bndryCells->a[id].m_srfcs[srfc]->m_FJacobian = F1 / JacobianQuotient;
12756 }
12757 }
12758}
12759
12760
12765template <MInt nDim, class SysEqn>
12767 TRACE();
12768
12769 MInt size = m_bndryCells->size();
12770 if(size == 0) {
12771 mTerm(1, AT_, "collector is empty.");
12772 }
12773 void* from;
12774 void* to;
12775 MLong dataSize;
12776 char* rawMemory = m_bndryCells->getRawPointer();
12778 to = (void*)(rawMemory + dataSize * (MLong)id);
12779 from = (void*)(rawMemory + dataSize * (size - 1));
12780
12781 // 3. if the cell to delete is already the last cell we are finished here...
12782 if(size - 1 == id) {
12783 // 3.a tidy up your old place
12784 m_bndryCells->a[size - 1].allocateElements(from, (void*)m_bndryCells->getRawPointer(), size - 1);
12785 // 3.b Decrease current collector size by one (Note: was previously done before tidying up)
12786 m_bndryCells->setSize(size - 1);
12787 return;
12788 }
12789
12790 // 4. Move last cell to freed space
12791 // a. copy members of last cell to free space
12792 m_bndryCells->a[id] = m_bndryCells->a[size - 1];
12793
12794 // b. Move raw memory to free space
12795 memcpy(to, from, dataSize);
12796
12797 // c. call moveElements (which shifts pointers
12798 // to the new destination
12799 m_bndryCells->a[id].moveElements(to);
12800
12801 // d. tidy up your old place
12802 m_bndryCells->a[size - 1].allocateElements(from, (void*)m_bndryCells->getRawPointer(), size - 1);
12803
12804 // 8. Decrease current collector size by one
12805 m_bndryCells->setSize(size - 1);
12806}
12807
12808
12815template <MInt nDim, class SysEqn>
12817 TRACE();
12818
12819 MInt cellId;
12820 MInt bndryId;
12821 MInt masterCellId;
12822 MInt noSurfaces = m_solver->a_noSurfaces();
12823 MInt otherId[2] = {1, 0};
12824 //--- end of initialization
12825
12826
12827 for(MInt srfcId = 0; srfcId < noSurfaces; srfcId++) {
12828 for(MInt nghbrId = 0; nghbrId < 2; nghbrId++) {
12829 cellId = m_solver->a_surfaceNghbrCellId(srfcId, nghbrId);
12830 if(m_solver->a_bndryId(cellId) < 0) {
12831 continue;
12832 }
12833
12834 bndryId = m_solver->a_bndryId(cellId);
12835 // check whether the cell is a slave cell
12836 if(m_bndryCells->a[bndryId].m_linkedCellId == -1) {
12837 continue;
12838 }
12839
12840 masterCellId = m_bndryCells->a[bndryId].m_linkedCellId;
12841
12842 // check whether the other neighbor of the surface is the
12843 // master cell
12844 if(m_solver->a_surfaceNghbrCellId(srfcId, otherId[nghbrId]) == masterCellId) {
12845 // THIS CASE SHOULD NOT APPEAR
12846 cerr << " srfc: " << srfcId << " cellId: " << cellId << " master: " << masterCellId
12847 << " other neighbor: " << m_solver->a_surfaceNghbrCellId(srfcId, otherId[nghbrId]) << endl;
12848 mTerm(1, AT_, "correctMasterSlaveSurfaces ERROR, exiting...");
12849
12850 } else {
12851 // shift the Id to the master cell
12852 m_solver->a_surfaceNghbrCellId(srfcId, nghbrId) = masterCellId;
12853 }
12854 }
12855 }
12856}
12857
12858
12866template <MInt nDim, class SysEqn>
12868 TRACE();
12869
12870 const MInt noSmallCells = m_smallBndryCells->size();
12871 MInt bndryId;
12872 MInt nghbrId;
12873 MInt cellId;
12874 MInt noNghbrIds;
12875 MInt id;
12876 MInt noUnknowns = nDim;
12877 MFloatScratchSpace x_scratch(nDim, AT_, "x_scratch");
12878 MFloat* x = x_scratch.getPointer();
12879 MBool bcCell = false;
12880 //---
12881
12882 // cell-center reconstruction
12883 for(MInt bc = m_bndryCndCells[bcId]; bc < m_bndryCndCells[bcId + 1]; bc++) {
12884 bndryId = m_sortedBndryCells->a[bc];
12885 cellId = m_bndryCells->a[bndryId].m_cellId;
12886 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
12887 continue;
12888 }
12889 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) {
12890 continue;
12891 }
12892 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) {
12893 continue;
12894 }
12895 if(m_solver->c_noChildren(cellId) > 0) {
12896 continue;
12897 }
12898
12899 noNghbrIds = m_solver->a_noReconstructionNeighbors(cellId);
12900
12901 // loop over least-squares cell cluster
12902 for(MInt cell = 0; cell < noNghbrIds; cell++) {
12903 id = m_solver->a_reconstructionNeighborId(cellId, cell);
12904 if(!m_solver->a_isBndryGhostCell(id)) {
12905 for(MInt i = 0; i < nDim; i++) {
12906 x[i] = m_solver->a_coordinate(id, i);
12907 }
12908 } else {
12909 computeMirrorCoordinates(m_solver->a_bndryId(m_solver->getAssociatedInternalCell(id)), x);
12910 }
12911
12912 for(MInt i = 0; i < nDim; i++) {
12913 m_solver->m_A[cell][i] = x[i] - m_solver->a_coordinate(cellId, i);
12914 }
12915 // additional terms for a higher-order reconstruction
12916 if(m_solver->m_orderOfReconstruction == 2) {
12917 for(MInt i = 0; i < nDim; i++) {
12918 m_solver->m_A[cell][nDim + i] = POW2(x[i] - m_solver->a_coordinate(cellId, i));
12919 }
12920 m_solver->m_A[cell][2 * nDim + 1] =
12921 (x[0] - m_solver->a_coordinate(cellId, 0)) * (x[1] - m_solver->a_coordinate(cellId, 1));
12922 m_solver->m_A[cell][2 * nDim + 2] =
12923 (x[0] - m_solver->a_coordinate(cellId, 0)) * (x[2] - m_solver->a_coordinate(cellId, 2));
12924 m_solver->m_A[cell][2 * nDim + 3] =
12925 (x[1] - m_solver->a_coordinate(cellId, 1)) * (x[2] - m_solver->a_coordinate(cellId, 2));
12926 }
12927 }
12928
12929 // compute ATA
12930 for(MInt i = 0; i < noUnknowns; i++) {
12931 for(MInt j = 0; j < noUnknowns; j++) {
12932 m_solver->m_ATA[i][j] = F0;
12933 for(MInt k = 0; k < noNghbrIds; k++) {
12934 m_solver->m_ATA[i][j] += m_solver->m_A[k][i] * m_solver->m_A[k][j];
12935 }
12936 }
12937 }
12938
12939 // invert ATA
12940 const MFloat epsilon = POW3(m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel()) / (1000.0));
12941 maia::math::inverse(m_solver->m_ATA, m_solver->m_ATAi, noUnknowns, epsilon);
12942
12943 // compute (ATA)^(-1) * AT
12944 for(MInt i = 0; i < noUnknowns; i++) {
12945 for(MInt j = 0; j < noNghbrIds; j++) {
12946 m_solver->m_ATA[i][j] = F0;
12947 for(MInt k = 0; k < noUnknowns; k++) {
12948 m_solver->m_ATA[i][j] += m_solver->m_ATAi[i][k] * m_solver->m_A[j][k];
12949 }
12950 }
12951 }
12952
12953 // loop over least-squares cell cluster
12954 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
12955 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
12956
12957 // compute the constants
12958 if(!m_solver->a_isBndryGhostCell(nghbrId)) {
12959 for(MInt i = 0; i < nDim; i++) {
12960 m_reconstructionConstants[bndryId][nDim * nghbr + i] = m_solver->m_ATA[i][nghbr];
12961 }
12962 } else {
12963 for(MInt i = 0; i < nDim; i++) {
12964 m_reconstructionConstants[bndryId][nDim * nghbr + i] = F0;
12965 }
12966 }
12967 }
12968 }
12969
12970 // loop over all slave cells with internal master
12971 for(MInt sid = 0; sid < noSmallCells; sid++) {
12972 bcCell = false;
12973 bndryId = m_smallBndryCells->a[sid];
12974 cellId = m_bndryCells->a[bndryId].m_linkedCellId;
12975 // check, if cell is indeed a boundary cell with bc bcId:
12976 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
12977 // only compute reconstruction constants for the cells with the respective boundary condition
12978 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
12979 bcCell = true;
12980 break;
12981 }
12982 }
12983 if(!bcCell) {
12984 continue;
12985 }
12986 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
12987 continue;
12988 }
12989 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) {
12990 continue;
12991 }
12992 if(m_solver->a_bndryId(cellId) > -1) {
12993 continue;
12994 }
12995
12996 // take all neighbors of the master cell
12997 noNghbrIds = m_solver->a_noReconstructionNeighbors(cellId);
12998
12999 // loop over least-squares cell cluster
13000 for(MInt cell = 0; cell < noNghbrIds; cell++) {
13001 id = m_solver->a_reconstructionNeighborId(cellId, cell);
13002 if(!m_solver->a_isBndryGhostCell(id)) {
13003 for(MInt i = 0; i < nDim; i++) {
13004 x[i] = m_solver->a_coordinate(id, i);
13005 }
13006 } else {
13007 computeMirrorCoordinates(m_solver->a_bndryId(m_solver->getAssociatedInternalCell(id)), x);
13008 }
13009
13010 for(MInt i = 0; i < nDim; i++) {
13011 m_solver->m_A[cell][i] = x[i] - m_solver->a_coordinate(cellId, i);
13012 }
13013 // additional terms for a higher-order reconstruction
13014 if(m_solver->m_orderOfReconstruction == 2) {
13015 for(MInt i = 0; i < nDim; i++) {
13016 m_solver->m_A[cell][nDim + i] = POW2(x[i] - m_solver->a_coordinate(cellId, i));
13017 }
13018 m_solver->m_A[cell][2 * nDim + 1] =
13019 (x[0] - m_solver->a_coordinate(cellId, 0)) * (x[1] - m_solver->a_coordinate(cellId, 1));
13020 m_solver->m_A[cell][2 * nDim + 2] =
13021 (x[0] - m_solver->a_coordinate(cellId, 0)) * (x[2] - m_solver->a_coordinate(cellId, 2));
13022 m_solver->m_A[cell][2 * nDim + 3] =
13023 (x[1] - m_solver->a_coordinate(cellId, 1)) * (x[2] - m_solver->a_coordinate(cellId, 2));
13024 }
13025 }
13026
13027 // compute ATA
13028 for(MInt i = 0; i < noUnknowns; i++) {
13029 for(MInt j = 0; j < noUnknowns; j++) {
13030 m_solver->m_ATA[i][j] = F0;
13031 for(MInt k = 0; k < noNghbrIds; k++) {
13032 m_solver->m_ATA[i][j] += m_solver->m_A[k][i] * m_solver->m_A[k][j];
13033 }
13034 }
13035 }
13036
13037 // invert ATA
13038 const MFloat epsilon = POW3(m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel()) / (1000.0));
13039 maia::math::inverse(m_solver->m_ATA, m_solver->m_ATAi, noUnknowns, epsilon);
13040
13041 // compute (ATA)^(-1) * AT
13042 for(MInt i = 0; i < noUnknowns; i++) {
13043 for(MInt j = 0; j < noNghbrIds; j++) {
13044 m_solver->m_ATA[i][j] = F0;
13045 for(MInt k = 0; k < noUnknowns; k++) {
13046 m_solver->m_ATA[i][j] += m_solver->m_ATAi[i][k] * m_solver->m_A[j][k];
13047 }
13048 }
13049 }
13050
13051 // loop over least-squares cell cluster
13052 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
13053 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
13054
13055 // compute the constants
13056 if(!m_solver->a_isBndryGhostCell(nghbrId)) {
13057 for(MInt i = 0; i < nDim; i++) {
13058 m_reconstructionConstants[bndryId][nDim * nghbr + i] = m_solver->m_ATA[i][nghbr];
13059 }
13060 } else {
13061 for(MInt i = 0; i < nDim; i++) {
13062 m_reconstructionConstants[bndryId][nDim * nghbr + i] = F0;
13063 }
13064 }
13065 }
13066 }
13067}
13068
13082template <MInt nDim, class SysEqn>
13084 TRACE();
13085
13086 MInt nghbrId = 0;
13087 MInt cellId;
13088 MInt linkedCell;
13089 MFloatScratchSpace dx_scratch(nDim, AT_, "dx_scratch");
13090 MFloat* dx = dx_scratch.getPointer();
13091 MFloat eps = F0;
13092 MFloat oldVar = F0;
13093 MFloat diff = F0;
13094
13095 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
13096 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
13097 cellId = m_bndryCells->a[bndryId].m_cellId;
13098 linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
13099 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13100 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) {
13101 continue;
13102 }
13103 if(!m_solver->a_hasProperty(cellId, SolverCell::IsFlux)) {
13104 continue;
13105 }
13106
13107
13108 // if cell is a small cell with bndry cell Master, use this reconstruction stencil. Otherwise, use your own
13109 // stencil.
13110 if(linkedCell > -1) {
13111 cellId = linkedCell;
13112 }
13113
13114 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) {
13115 continue;
13116 }
13117 if(!m_solver->a_hasProperty(cellId, SolverCell::IsFlux)) {
13118 continue;
13119 }
13120
13121
13122 // compute the slopes based only on the fluid cells - no ghost cells (bndry cnd not taken into account)
13123 if(mode == 0) {
13124 // reset the slopes
13125 for(MInt i = 0; i < nDim; i++) {
13126 for(MInt varId = 0; varId < PV->noVariables; varId++) {
13127 m_solver->a_slope(cellId, varId, i) = F0;
13128 }
13129 }
13130
13131 // compute the slopes for the interpolation -
13132 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
13133 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
13134 // skip ghost cells (reconstruction constants are set to zero - skip nevertheless!
13135 // important if ghost cell variables are not yet set properly!
13136 if(m_solver->a_isBndryGhostCell(nghbrId)) {
13137 continue;
13138 }
13139 for(MInt i = 0; i < nDim; i++) {
13140 for(MInt varId = 0; varId < PV->noVariables; varId++) {
13141 m_solver->a_slope(cellId, varId, i) +=
13142 m_reconstructionConstants[bndryId][nghbr * nDim + i]
13143 * (m_solver->a_pvariable(nghbrId, varId) - m_solver->a_pvariable(cellId, varId));
13144 }
13145 }
13146 }
13147 }
13148
13149 // compute the offset of mp relative to the cell center
13150 for(MInt i = 0; i < nDim; i++) {
13151 dx[i] =
13152 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageCoordinates[i] - m_solver->a_coordinate(cellId, i);
13153 }
13154
13155 // compute Image Point variable
13156 for(MInt varId = 0; varId < PV->noVariables; varId++) {
13157 // store old value for computation of max. rel. change
13158 oldVar = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[varId];
13159
13160 // compute image point value
13161 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[varId] =
13162 m_solver->a_pvariable(cellId, varId);
13163 for(MInt i = 0; i < nDim; i++) {
13164 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[varId] +=
13165 dx[i] * m_solver->a_slope(cellId, varId, i);
13166 }
13167 // compute relative change
13168 diff = abs((oldVar - m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[varId])
13169 / m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[varId]);
13170 if(diff > eps) {
13171 eps = diff;
13172 }
13173 }
13174 }
13175 }
13176 }
13177 return eps;
13178}
13179
13186template <MInt nDim, class SysEqn>
13188 TRACE();
13189
13190 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "Info: untested for 3D."); }
13191
13192 MInt nghbrId = 0;
13193 MInt cellId;
13194 MInt bndryId;
13195 MInt ghostCellId;
13196 MInt linkedCell;
13197 MFloatScratchSpace dx(nDim, AT_, "dx");
13198 MFloat thermalProfileStartFactor = m_solver->m_thermalProfileStartFactor;
13199 const MFloat TInfinity =
13200 m_solver->m_burntUnburntTemperatureRatio * m_solver->m_temperatureFlameTube * thermalProfileStartFactor;
13201 //---
13202
13203 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13204 bndryId = m_sortedBndryCells->a[id];
13205 cellId = m_bndryCells->a[bndryId].m_cellId;
13206 linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
13207 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
13208 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13209 if(linkedCell > -1) {
13210 cellId = linkedCell;
13211 }
13212 if(linkedCell == -1 || m_solver->a_bndryId(linkedCell) == -1) {
13213 // reset the slopes
13214 for(MInt i = 0; i < nDim; i++) {
13215 m_solver->a_slope(cellId, PV->P, i) = F0;
13216 }
13217
13218 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
13219 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
13220 for(MInt i = 0; i < nDim; i++) {
13221 m_solver->a_slope(cellId, PV->P, i) +=
13222 m_reconstructionConstants[bndryId][nghbr * nDim + i]
13223 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
13224 }
13225 }
13226
13227 // compute the offset of mp relative to the cell center
13228 for(MInt i = 0; i < nDim; i++) {
13229 dx.p[i] = m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i);
13230 }
13231
13232 // apply the Neumann bc for the pressure
13233 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13234 for(MInt i = 0; i < nDim; i++) {
13235 m_solver->a_pvariable(ghostCellId, PV->P) += dx.p[i] * m_solver->a_slope(cellId, PV->P, i);
13236 }
13237
13238 // compute the density assuming that on the boundary cell T=T_inf
13239 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13240 sysEqn().density_ES(m_solver->a_pvariable(ghostCellId, PV->P), TInfinity);
13241 }
13242 }
13243 }
13244}
13245
13252template <MInt nDim, class SysEqn>
13254 TRACE();
13255
13256 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "Info: untested for 3D."); }
13257
13258 MInt nghbrId = 0;
13259 MInt cellId;
13260 MInt bndryId;
13261 MInt ghostCellId;
13262 MInt linkedCell;
13263 MFloatScratchSpace dx(nDim, AT_, "dx");
13264 MFloat deltaX = m_solver->m_deltaXtemperatureProfile;
13265 MFloat xOffsetTemperatureRise = m_radiusFlameTube + F1B2 * m_solver->m_flameRadiusOffset;
13266 MFloat neg2 = -F2;
13267 MFloat thermalProfileStartFactor = m_solver->m_thermalProfileStartFactor;
13268 //---
13269
13270 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13271 bndryId = m_sortedBndryCells->a[id];
13272 cellId = m_bndryCells->a[bndryId].m_cellId;
13273 linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
13274 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
13275 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13276 if(linkedCell > -1) {
13277 cellId = linkedCell;
13278 }
13279 if(linkedCell == -1 || m_solver->a_bndryId(linkedCell) == -1) {
13280 // reset the slopes
13281 for(MInt i = 0; i < nDim; i++) {
13282 m_solver->a_slope(cellId, PV->P, i) = F0;
13283 }
13284
13285 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
13286 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
13287 for(MInt i = 0; i < nDim; i++) {
13288 m_solver->a_slope(cellId, PV->P, i) +=
13289 m_reconstructionConstants[bndryId][nghbr * nDim + i]
13290 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
13291 }
13292 }
13293
13294 // compute the offset of mp relative to the cell center
13295 for(MInt i = 0; i < nDim; i++) {
13296 dx.p[i] = m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i);
13297 }
13298
13299 // apply the Neumann bc for the pressure
13300 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13301 for(MInt i = 0; i < nDim; i++) {
13302 m_solver->a_pvariable(ghostCellId, PV->P) += dx.p[i] * m_solver->a_slope(cellId, PV->P, i);
13303 }
13304
13305 MFloat temperatureProfile;
13306 if(m_solver->a_coordinate(cellId, 0) > F0) {
13307 temperatureProfile =
13308 (m_solver->m_temperatureFlameTube * thermalProfileStartFactor
13309 + (m_solver->m_burntUnburntTemperatureRatio
13310 - m_solver->m_temperatureFlameTube * thermalProfileStartFactor)
13311 * (tanh(5.0) - F1B2 * tanh(5.0)
13312 + F1B2
13313 * tanh((F2 * (m_solver->a_coordinate(cellId, 0) - xOffsetTemperatureRise) - deltaX) * 5.0
13314 / deltaX)));
13315 } else {
13316 temperatureProfile =
13317 (m_solver->m_temperatureFlameTube * thermalProfileStartFactor
13318 + (m_solver->m_burntUnburntTemperatureRatio
13319 - m_solver->m_temperatureFlameTube * thermalProfileStartFactor)
13320 * (tanh(5.0) - F1B2 * tanh(5.0)
13321 + F1B2
13322 * tanh((neg2 * (m_solver->a_coordinate(cellId, 0) + xOffsetTemperatureRise) - deltaX)
13323 * 5.0 / deltaX)));
13324 }
13325
13326 // compute the density assuming that on the boundary cell T=T_inf
13327 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13328 sysEqn().density_ES(m_solver->a_pvariable(ghostCellId, PV->P), temperatureProfile);
13329 }
13330 }
13331 }
13332}
13333
13340template <MInt nDim, class SysEqn>
13342 TRACE();
13343
13344 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "Info: untested for 3D."); }
13345
13346 MInt nghbrId = 0;
13347 MInt cellId;
13348 MInt bndryId;
13349 MInt ghostCellId;
13350 MInt linkedCell;
13351 MFloatScratchSpace dx(nDim, AT_, "dx");
13352 MFloat deltaX = m_solver->m_deltaXtemperatureProfile;
13353 MFloat xOffsetTemperatureRise = m_radiusFlameTube + F1B2 * m_solver->m_flameRadiusOffset;
13354 MFloat thermalProfileStartFactor = m_solver->m_thermalProfileStartFactor;
13355 MFloat tempHalfBurnt = m_solver->m_temperatureFlameTube * F1B2 * m_solver->m_burntUnburntTemperatureRatio;
13356 MFloat tempBurnt =
13357 m_solver->m_temperatureFlameTube * m_solver->m_burntUnburntTemperatureRatio * thermalProfileStartFactor;
13358 MFloat neg2 = -F2;
13359 //---
13360
13361 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13362 bndryId = m_sortedBndryCells->a[id];
13363 cellId = m_bndryCells->a[bndryId].m_cellId;
13364 linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
13365 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
13366 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13367 if(linkedCell > -1) {
13368 cellId = linkedCell;
13369 }
13370 if(linkedCell == -1 || m_solver->a_bndryId(linkedCell) == -1) {
13371 // reset the slopes
13372 for(MInt i = 0; i < nDim; i++) {
13373 m_solver->a_slope(cellId, PV->P, i) = F0;
13374 }
13375
13376 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
13377 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
13378 for(MInt i = 0; i < nDim; i++) {
13379 m_solver->a_slope(cellId, PV->P, i) +=
13380 m_reconstructionConstants[bndryId][nghbr * nDim + i]
13381 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
13382 }
13383 }
13384
13385 // compute the offset of mp relative to the cell center
13386 for(MInt i = 0; i < nDim; i++) {
13387 dx.p[i] = m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i);
13388 }
13389
13390 // apply the Neumann bc for the pressure
13391 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13392 for(MInt i = 0; i < nDim; i++) {
13393 m_solver->a_pvariable(ghostCellId, PV->P) += dx.p[i] * m_solver->a_slope(cellId, PV->P, i);
13394 }
13395
13396 MFloat temperatureProfile;
13397 if(m_solver->a_coordinate(cellId, 0) > F0) {
13398 temperatureProfile =
13399 tempHalfBurnt
13400 + (tempBurnt - tempHalfBurnt)
13401 * (tanh(5.0) - F1B2 * tanh(5.0)
13402 + F1B2
13403 * tanh((F2 * (m_solver->a_coordinate(cellId, 0) - xOffsetTemperatureRise) - deltaX) * 5.0
13404 / deltaX));
13405 } else {
13406 temperatureProfile =
13407 tempHalfBurnt
13408 + (tempBurnt - tempHalfBurnt)
13409 * (tanh(5.0) - F1B2 * tanh(5.0)
13410 + F1B2
13411 * tanh((neg2 * (m_solver->a_coordinate(cellId, 0) + xOffsetTemperatureRise) - deltaX) * 5.0
13412 / deltaX));
13413 }
13414
13415 // compute the density assuming that on the boundary cell T=T_inf
13416 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13417 sysEqn().density_ES(m_solver->a_pvariable(ghostCellId, PV->P), temperatureProfile);
13418 }
13419 }
13420 }
13421}
13422
13429template <MInt nDim, class SysEqn>
13431 TRACE();
13432
13433 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "Info: untested for 3D."); }
13434
13435 MInt nghbrId = 0;
13436 MInt cellId;
13437 MInt bndryId;
13438 MInt ghostCellId;
13439 MInt linkedCell;
13440 MFloatScratchSpace dx(nDim, AT_, "dx");
13441 MFloat deltaY = m_solver->m_deltaYtemperatureProfile;
13442 MFloat yOffsetTemperatureRise = m_solver->m_yOffsetFlameTube - deltaY;
13443 //---
13444
13445 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13446 bndryId = m_sortedBndryCells->a[id];
13447 cellId = m_bndryCells->a[bndryId].m_cellId;
13448 linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
13449 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
13450 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13451 if(linkedCell > -1) {
13452 cellId = linkedCell;
13453 }
13454 if(linkedCell == -1 || m_solver->a_bndryId(linkedCell) == -1) {
13455 // reset the slopes
13456 for(MInt i = 0; i < nDim; i++) {
13457 m_solver->a_slope(cellId, PV->P, i) = F0;
13458 }
13459
13460 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
13461 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
13462 for(MInt i = 0; i < nDim; i++) {
13463 m_solver->a_slope(cellId, PV->P, i) +=
13464 m_reconstructionConstants[bndryId][nghbr * nDim + i]
13465 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
13466 }
13467 }
13468
13469 // compute the offset of mp relative to the cell center
13470 for(MInt i = 0; i < nDim; i++) {
13471 dx.p[i] = m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i);
13472 }
13473
13474 // apply the Neumann bc for the pressure
13475 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13476 for(MInt i = 0; i < nDim; i++) {
13477 m_solver->a_pvariable(ghostCellId, PV->P) += dx.p[i] * m_solver->a_slope(cellId, PV->P, i);
13478 }
13479
13480 const MFloat temperatureProfile =
13481 ((m_solver->m_temperatureFlameTube
13482 + (m_solver->m_burntUnburntTemperatureRatio - m_solver->m_temperatureFlameTube)
13483 * (tanh(5.0) - F1B2 * tanh(5.0)
13484 + F1B2
13485 * tanh((F2 * (m_solver->a_coordinate(cellId, 1) - yOffsetTemperatureRise) - deltaY) * 5.0
13486 / deltaY))));
13487
13488 // compute the density assuming that on the boundary cell T=T_inf
13489 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13490 sysEqn().density_ES(m_solver->a_pvariable(ghostCellId, PV->P), temperatureProfile);
13491 }
13492 }
13493 }
13494}
13495
13502template <MInt nDim, class SysEqn>
13504 TRACE();
13505
13506 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "Info: untested for 3D."); }
13507
13508 MInt nghbrId = 0;
13509 MInt cellId;
13510 MInt bndryId;
13511 MInt ghostCellId;
13512 MInt linkedCell;
13513 MFloatScratchSpace dx(nDim, AT_, "dx");
13514 MFloat deltaY = m_solver->m_deltaYtemperatureProfile;
13515 MFloat yOffsetTemperatureRise = m_solver->m_yOffsetFlameTube - deltaY;
13516 //---
13517
13518 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13519 bndryId = m_sortedBndryCells->a[id];
13520 cellId = m_bndryCells->a[bndryId].m_cellId;
13521 linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
13522 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
13523 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13524 if(linkedCell > -1) {
13525 cellId = linkedCell;
13526 }
13527 if(linkedCell == -1 || m_solver->a_bndryId(linkedCell) == -1) {
13528 // reset the slopes
13529 for(MInt i = 0; i < nDim; i++) {
13530 m_solver->a_slope(cellId, PV->P, i) = F0;
13531 }
13532
13533 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
13534 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
13535 for(MInt i = 0; i < nDim; i++) {
13536 m_solver->a_slope(cellId, PV->P, i) +=
13537 m_reconstructionConstants[bndryId][nghbr * nDim + i]
13538 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
13539 }
13540 }
13541
13542 // compute the offset of mp relative to the cell center
13543 for(MInt i = 0; i < nDim; i++) {
13544 dx.p[i] = m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i);
13545 }
13546
13547 // apply the Neumann bc for the pressure
13548 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13549 for(MInt i = 0; i < nDim; i++) {
13550 m_solver->a_pvariable(ghostCellId, PV->P) += dx.p[i] * m_solver->a_slope(cellId, PV->P, i);
13551 }
13552
13553
13554 const MFloat temperatureProfile =
13555 (m_solver->m_temperatureFlameTube
13556 + (F1B2 * m_solver->m_burntUnburntTemperatureRatio - m_solver->m_temperatureFlameTube)
13557 * (tanh(5.0) - F1B2 * tanh(5.0)
13558 + F1B2
13559 * tanh((F2 * (m_solver->a_coordinate(cellId, 1) - yOffsetTemperatureRise) - deltaY) * 5.0
13560 / deltaY)));
13561
13562 // compute the density assuming that on the boundary cell T=T_inf
13563 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13564 sysEqn().density_ES(m_solver->a_pvariable(ghostCellId, PV->P), temperatureProfile);
13565 }
13566 }
13567 }
13568}
13569
13576template <MInt nDim, class SysEqn>
13578 TRACE();
13579
13580 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "Info: untested for 3D."); }
13581
13582 MInt nghbrId = 0;
13583 MInt cellId;
13584 MInt bndryId;
13585 MInt ghostCellId;
13586 MInt linkedCell;
13587 MFloatScratchSpace dx(nDim, AT_, "dx");
13588 const MFloat TInfinityUnburnt = m_solver->m_temperatureFlameTube;
13589 //---
13590
13591 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13592 bndryId = m_sortedBndryCells->a[id];
13593 cellId = m_bndryCells->a[bndryId].m_cellId;
13594 linkedCell = m_bndryCells->a[bndryId].m_linkedCellId;
13595 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
13596 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13597 if(linkedCell > -1) {
13598 cellId = linkedCell;
13599 }
13600 if(linkedCell == -1 || m_solver->a_bndryId(linkedCell) == -1) {
13601 // reset the slopes
13602 for(MInt i = 0; i < nDim; i++) {
13603 m_solver->a_slope(cellId, PV->P, i) = F0;
13604 }
13605
13606 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
13607 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
13608 for(MInt i = 0; i < nDim; i++) {
13609 m_solver->a_slope(cellId, PV->P, i) +=
13610 m_reconstructionConstants[bndryId][nghbr * nDim + i]
13611 * (m_solver->a_pvariable(nghbrId, PV->P) - m_solver->a_pvariable(cellId, PV->P));
13612 }
13613 }
13614
13615 // compute the offset of mp relative to the cell center
13616 for(MInt i = 0; i < nDim; i++) {
13617 dx.p[i] = m_solver->a_coordinate(ghostCellId, i) - m_solver->a_coordinate(cellId, i);
13618 }
13619
13620 // apply the Neumann bc for the pressure
13621 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13622 for(MInt i = 0; i < nDim; i++) {
13623 m_solver->a_pvariable(ghostCellId, PV->P) += dx.p[i] * m_solver->a_slope(cellId, PV->P, i);
13624 }
13625
13626 // compute the density assuming that on the boundary cell T=T_inf
13627 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13628 sysEqn().density_ES(m_solver->a_pvariable(ghostCellId, PV->P), TInfinityUnburnt);
13629 }
13630 }
13631 }
13632}
13633
13637template <MInt nDim, class SysEqn>
13639 TRACE();
13640
13641 //---
13642
13643 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13644 const MInt bndryId = m_sortedBndryCells->a[id];
13645 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
13646
13647 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13648 const MBool gapCell = m_solver->a_hasProperty(cellId, SolverCell::IsGapCell);
13649
13650 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
13651 MInt k = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0];
13652 ASSERT(k > -1 && k < m_solver->m_noEmbeddedBodies + m_solver->m_noPeriodicGhostBodies, "");
13653 if(k < 0 || k >= m_solver->m_noEmbeddedBodies + m_solver->m_noPeriodicGhostBodies) {
13654 mTerm(1, AT_, "Invalid body id: " + to_string(k));
13655 }
13656
13657 MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
13658 MFloat normal[nDim];
13659 MFloat delta[3] = {F0, F0, F0};
13660 MFloat dr[3] = {F0, F0, F0};
13661 MFloat dw[3] = {F0, F0, F0};
13662 MFloat dg[3] = {F0, F0, F0};
13663 MFloat du[3] = {F0, F0, F0};
13664 MFloat dv[3] = {F0, F0, F0};
13665 MFloat dn = F0;
13666 for(MInt i = 0; i < nDim; i++) {
13667 normal[i] = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
13668 dr[i] = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i] - m_solver->m_bodyCenter[k * nDim + i];
13669 du[i] = m_solver->m_bodyAcceleration[k * nDim + i];
13670 dv[i] = m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]]
13671 - m_solver->m_bodyVelocity[k * nDim + i];
13672 dn += (m_solver->a_coordinate(cellId, i) - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i])
13673 * normal[i];
13674
13675 if(gapCell && m_solver->m_gapInitMethod > 0) {
13676 du[i] = 0;
13677 dv[i] = 0;
13678 }
13679 }
13680
13681 for(MInt i = 0; i < 3; i++) {
13682 dw[i] = m_solver->m_bodyAngularAcceleration[k * 3 + i];
13683 dg[i] = m_solver->m_bodyAngularVelocity[k * 3 + i];
13684 }
13685 // assemble material acceleration
13686 delta[0] = du[0] + dw[1] * dr[2] - dw[2] * dr[1] + dg[1] * dv[2] - dg[2] * dv[1];
13687 delta[1] = du[1] + dw[2] * dr[0] - dw[0] * dr[2] + dg[2] * dv[0] - dg[0] * dv[2];
13688 delta[2] = du[2] + dw[0] * dr[1] - dw[1] * dr[0] + dg[0] * dv[1] - dg[1] * dv[0];
13689
13690
13691 MFloat an = F0;
13692 for(MInt i = 0; i < nDim; i++) {
13693 an += normal[i] * delta[i];
13694 }
13695
13696 MFloat surfTemp =
13697 sysEqn().temperature_ES(m_solver->a_pvariable(cellId, PV->RHO), m_solver->a_pvariable(cellId, PV->P));
13698 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == 3008
13699 || m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == 3010) {
13700 surfTemp = m_solver->m_bodyTemperature[m_solver->m_internalBodyId[k]];
13701 // Timw engine specific
13702 // labels:FV Tina-engine liner-Temperatur hack:
13703 if(m_solver->m_engineSetup && m_solver->m_noGapRegions >= 1 && k == 0) {
13704 if(m_solver->a_coordinate(cellId, 1) > 0) {
13705 surfTemp = 1;
13706 } else if(m_solver->a_coordinate(cellId, 1) > -0.1 && m_solver->a_coordinate(cellId, 1) < 0) {
13707 // linear interpolation between T_infinity and surface temperature
13708 surfTemp = 1 + m_solver->a_coordinate(cellId, 1) / -0.1 * (surfTemp - 1);
13709 }
13710 }
13711 }
13712
13713 const MFloat beta = sysEqn().gamma_Ref() * an / surfTemp;
13714 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_robinFactor = beta;
13715
13716 if(fabs(F1 - beta * dn) < 1e-3) {
13717 cerr << "Warning: small denom Robin BC: " << k << " " << m_solver->m_internalBodyId[k] << " " << beta << " "
13718 << dn << " " << an << " " << surfTemp << " " << srfc << endl;
13719 }
13720 const MFloat fac = (F1 + beta * dn) / (F1 - beta * dn);
13721
13722 m_solver->a_pvariable(ghostCellId, PV->P) = fac * m_solver->a_pvariable(cellId, PV->P);
13723 m_solver->a_pvariable(ghostCellId, PV->RHO) = fac * m_solver->a_pvariable(cellId, PV->RHO);
13724
13725 // JANNIK: should this be here?
13726 for(MInt s = 0; s < m_noSpecies; s++) {
13727 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
13728 }
13729
13730 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
13731 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
13732 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = -m_solver->a_pvariable(cellId, PV->NN[r]);
13733 }
13734 }
13735
13736 MFloat pressure = F1B2 * (m_solver->a_pvariable(cellId, PV->P) + m_solver->a_pvariable(ghostCellId, PV->P));
13737 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] = pressure;
13738
13739 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == 3007) {
13740 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO] =
13741 m_solver->a_pvariable(cellId, PV->RHO)
13742 * pow(pressure / m_solver->a_pvariable(cellId, PV->P), sysEqn().gamma_Ref());
13743 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13744 F2 * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO]
13745 - m_solver->a_pvariable(cellId, PV->RHO);
13746 } else if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == 3008
13747 || m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == 3010) {
13748 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO] = sysEqn().density_ES(pressure, surfTemp);
13749 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13750 F2 * m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO]
13751 - m_solver->a_pvariable(cellId, PV->RHO);
13752 } else {
13753 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO] =
13754 F1B2 * (m_solver->a_pvariable(cellId, PV->RHO) + m_solver->a_pvariable(ghostCellId, PV->RHO));
13755 }
13756 }
13757 }
13758 }
13759}
13760
13761
13762//------------------------------------------------------------------------------
13763
13773template <MInt nDim, class SysEqn>
13775 TRACE();
13776
13777#ifdef _OPENMP
13778#pragma omp parallel for
13779#endif
13780 // loop over all concerning boundary cells
13781 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13782 const MInt cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
13783 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13784 const MInt ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[0]->m_ghostCellId;
13785
13786 // set the density
13787 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13788 2.0 * m_solver->m_rhoInfinity - m_solver->a_pvariable(cellId, PV->RHO);
13789
13790
13791 // set the velocities
13792 for(MInt i = 0; i < nDim; i++) {
13793 m_solver->a_pvariable(ghostCellId, PV->VV[i]) =
13794 2.0 * m_solver->m_VVInfinity[i] - m_solver->a_pvariable(cellId, PV->VV[i]);
13795 }
13796
13797 // set the pressure of the ghost cell equal to that of the boundary cell
13798 m_solver->a_pvariable(ghostCellId, PV->P) = 2.0 * m_solver->m_PInfinity;
13799 }
13800 }
13801}
13802
13811template <MInt nDim, class SysEqn>
13813 TRACE();
13814
13815#ifdef _OPENMP
13816#pragma omp parallel for
13817#endif
13818 // loop over all concerning boundary cells
13819 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13820 const MInt cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
13821 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13822 const MInt ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[0]->m_ghostCellId;
13823
13824 // set the density
13825 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
13826
13827 // set the velocities
13828 for(MInt i = 0; i < nDim; i++) {
13829 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = -m_solver->a_pvariable(cellId, PV->VV[i]);
13830 }
13831
13832 // set the pressure of the ghost cell equal to that of the boundary cell
13833 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13834
13835 for(MInt s = 0; s < m_noSpecies; s++) {
13836 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
13837 }
13838 }
13839 }
13840}
13841
13842
13852template <MInt nDim, class SysEqn>
13854 TRACE();
13855
13856#ifdef _OPENMP
13857#pragma omp parallel for
13858#endif
13859 // loop over all concerning boundary cells
13860 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13861 const MInt cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
13862 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13863 const MInt ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[0]->m_ghostCellId;
13864
13865 // set the density
13866 m_solver->a_pvariable(ghostCellId, PV->RHO) =
13867 2.0 * m_solver->m_rhoInfinity - m_solver->a_pvariable(cellId, PV->RHO);
13868
13869 // set the velocities
13870 for(MInt i = 0; i < nDim; i++) {
13871 m_solver->a_pvariable(ghostCellId, PV->VV[i]) =
13872 F2 * m_solver->m_VVInfinity[i] - m_solver->a_pvariable(cellId, PV->VV[i]);
13873 }
13874
13875 // set the pressure of the ghost cell equal to that of the boundary cell
13876 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13877 IF_CONSTEXPR(hasPV_C<SysEqn>::value) {
13878 if(m_combustion) {
13879 m_solver->a_pvariable(ghostCellId, PV->C) = -m_solver->a_pvariable(cellId, PV->C);
13880 }
13881 }
13882 IF_CONSTEXPR(isDetChem<SysEqn>) {
13883 for(MInt s = 0; s < m_noSpecies; s++) {
13884 m_solver->a_pvariable(ghostCellId, PV->Y[s]) =
13885 2.0 * m_solver->m_YInfinity[s] - m_solver->a_pvariable(cellId, PV->Y[s]);
13886 }
13887 }
13888 else {
13889 if(m_isEEGas) {
13890 m_solver->a_pvariable(ghostCellId, PV->Y[0]) =
13891 2.0 * m_solver->m_EEGas.alphaIn - m_solver->a_pvariable(cellId, PV->Y[0]);
13892 } else {
13893 for(MInt s = 0; s < m_noSpecies; s++) {
13894 m_solver->a_pvariable(cellId, PV->Y[s]) = 1.0;
13895 }
13896 }
13897 }
13898 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
13899 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
13900 m_solver->a_pvariable(ghostCellId, PV->N) =
13901 2.0 * m_solver->m_nuTildeInfinity - m_solver->a_pvariable(cellId, PV->N);
13902 }
13903 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
13904 m_solver->a_pvariable(ghostCellId, PV->K) =
13905 2.0 * m_solver->m_kInfinity - m_solver->a_pvariable(cellId, PV->K);
13906 m_solver->a_pvariable(ghostCellId, PV->OMEGA) =
13907 2.0 * m_solver->m_omegaInfinity - m_solver->a_pvariable(cellId, PV->OMEGA);
13908 }
13909 }
13910 }
13911 }
13912}
13913
13924template <MInt nDim, class SysEqn>
13926 TRACE();
13927
13928#ifdef _OPENMP
13929#pragma omp parallel for
13930#endif
13931 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13932 const MInt cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
13933 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13934 const MInt ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[0]->m_ghostCellId;
13935
13936 // set the density
13937 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
13938
13939 // set the velocities
13940 for(MInt i = 0; i < nDim; i++) {
13941 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = m_solver->a_pvariable(cellId, PV->VV[i]);
13942 }
13943
13944 // set the pressure
13945 m_solver->a_pvariable(ghostCellId, PV->P) = 2.0 * m_solver->m_PInfinity - m_solver->a_pvariable(cellId, PV->P);
13946
13947 if(isDetChem<SysEqn> || m_isEEGas) {
13948 for(MInt s = 0; s < m_noSpecies; s++) {
13949 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
13950 }
13951 } else {
13952 for(MInt s = 0; s < m_noSpecies; s++) {
13953 m_solver->a_pvariable(cellId, PV->Y[s]) = 0.0;
13954 }
13955 }
13956
13957
13958 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
13959 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
13960 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = m_solver->a_pvariable(cellId, PV->NN[r]);
13961 }
13962 }
13963 }
13964 }
13965}
13966
13976template <MInt nDim, class SysEqn>
13978 TRACE();
13979
13980#ifdef _OPENMP
13981#pragma omp parallel for
13982#endif
13983 // loop over all concerning boundary cells
13984 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
13985 const MInt cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
13986 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
13987 const MInt ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[0]->m_ghostCellId;
13988
13989 // Density
13990 m_solver->a_pvariable(ghostCellId, PV->RHO) = 2.0 * m_solver->m_rhoCg - m_solver->a_pvariable(cellId, PV->RHO);
13991
13992 // Velocities
13993 m_solver->a_pvariable(ghostCellId, PV->VV[0]) = 2.0 * m_solver->m_UCg - m_solver->a_pvariable(cellId, PV->U);
13994 m_solver->a_pvariable(ghostCellId, PV->VV[1]) = 2.0 * m_solver->m_VCg - m_solver->a_pvariable(cellId, PV->V);
13995 m_solver->a_pvariable(ghostCellId, PV->VV[2]) = 2.0 * m_solver->m_WCg - m_solver->a_pvariable(cellId, PV->W);
13996
13997 // Pressure
13998 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
13999
14000 // Species
14001 if(!m_isEEGas) {
14002 for(MInt s = 0; s < m_noSpecies; s++) {
14003 m_solver->a_pvariable(cellId, PV->Y[s]) = 1.0;
14004 }
14005 }
14006
14007 // RANS
14008 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
14009 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
14010 m_solver->a_pvariable(ghostCellId, PV->N) =
14011 2.0 * m_solver->m_nuTildeInfinity - m_solver->a_pvariable(cellId, PV->N);
14012 }
14013 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
14014 m_solver->a_pvariable(ghostCellId, PV->K) =
14015 2.0 * m_solver->m_kInfinity - m_solver->a_pvariable(cellId, PV->K);
14016 m_solver->a_pvariable(ghostCellId, PV->OMEGA) =
14017 2.0 * m_solver->m_omegaInfinity - m_solver->a_pvariable(cellId, PV->OMEGA);
14018 }
14019 }
14020 }
14021 }
14022}
14023
14028template <MInt nDim, class SysEqn>
14030 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bcInit1050 is untested for 2D!"); }
14031 TRACE();
14032
14033 MInt noCells = m_bndryCells->size();
14034 MFloat eps = 0.0001 / FPOW2(m_solver->maxRefinementLevel());
14035// --- end of initialization
14036
14037// loop over all concerning boundary cells
14038#ifdef _OPENMP
14039#pragma omp parallel for
14040#endif
14041 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
14042 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId == 1051) {
14043 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
14044 MFloat coordinates[nDim];
14045 MFloat coordinatesP[nDim];
14046 for(MInt i = 0; i < nDim; i++) {
14047 coordinates[i] = m_solver->a_coordinate(cellId, i) - m_bndryCells->a[bndryId].m_coordinates[i];
14048 }
14049 for(MInt bndryId2 = 0; bndryId2 < noCells; bndryId2++) {
14050 if(m_bndryCells->a[bndryId2].m_srfcs[0]->m_bndryCndId == 1052) {
14051 MInt periodicCellId = m_bndryCells->a[bndryId2].m_cellId;
14052 for(MInt i = 0; i < nDim; i++) {
14053 coordinatesP[i] = m_solver->a_coordinate(periodicCellId, i) - m_bndryCells->a[bndryId2].m_coordinates[i];
14054 }
14055 if(fabs(coordinates[0] - coordinatesP[0]) < eps && fabs(coordinates[1] - coordinatesP[1]) < eps) {
14056 m_bndryCells->a[bndryId].m_periodicCellId = periodicCellId;
14057 m_bndryCells->a[bndryId2].m_periodicCellId = cellId;
14058 break;
14059 }
14060 }
14061 }
14062 }
14063 }
14064}
14065
14066//--------------------------------------------------------------------------
14083template <MInt nDim, class SysEqn>
14085 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc1091 is untested for 2D!"); }
14086 TRACE();
14087
14088 MInt cellId;
14089 MInt bndryId;
14090 MInt ghostCellId;
14091 MFloat R;
14092 MFloat massflux = F0;
14093 MFloat inflowArea = F0;
14094 MFloat pressure = F0;
14095 MFloat localVel = F0;
14096 MFloat density = F0;
14097 MFloat referencePoint[3] = {0.0, 0.0, 0.0};
14098 MFloat normal[3] = {0.0, 0.0, 0.0};
14099 MFloat radius = F0;
14100 MFloat velocity = F0;
14101
14102 // --- end of initialization
14103
14104 // compute current massflux, inflow area, reference Point and normal of the inflow area
14105 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
14106 cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
14107 bndryId = m_solver->a_bndryId(cellId);
14108 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
14109 for(MInt srfc = 0; srfc < m_bndryCells->a[m_sortedBndryCells->a[id]].m_noSrfcs; srfc++) {
14110 // search for surfaces which belong to the respective boundary condition
14111 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
14112 // compute massflux through the first cell layer
14113 massflux -= (((m_solver->a_pvariable(cellId, PV->U)) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
14114 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0]
14115 + (m_solver->a_pvariable(cellId, PV->V)) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
14116 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1]
14117 + (m_solver->a_pvariable(cellId, PV->W)) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
14118 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2])
14119 * (m_solver->a_pvariable(cellId, PV->RHO)));
14120 inflowArea += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
14121
14122 // compute midpoint of inflow boundary and mean normal
14123 for(MInt i = 0; i < 3; i++) {
14124 referencePoint[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]
14125 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
14126 normal[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
14127 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
14128 }
14129 }
14130 }
14131 }
14132 }
14133 for(MInt i = 0; i < 3; i++) {
14134 referencePoint[i] /= inflowArea;
14135 normal[i] /= inflowArea;
14136 }
14137
14138 // compute massflux per unit area
14139 massflux /= inflowArea;
14140
14141 // compute static pressure and density iteratively (see e.g. thesis of Ingolf Hoerschler)
14142 pressure = sysEqn().p_Ref();
14143 for(MInt i = 0; i < 20; i++) {
14144 pressure = sysEqn().pressure_IRit(pressure, massflux);
14145 }
14146 pressure = pressure * sysEqn().p_Ref();
14147 density = sysEqn().density_IR_P(pressure);
14148
14149 localVel = massflux / density;
14150
14151 R = sqrt(inflowArea / PI);
14152 radius = F0;
14153 velocity = F0;
14154
14155 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
14156 cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
14157 bndryId = m_solver->a_bndryId(cellId);
14158 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
14159 for(MInt srfc = 0; srfc < m_bndryCells->a[m_sortedBndryCells->a[id]].m_noSrfcs; srfc++) {
14160 // search for surfaces which belong to the respective boundary condition
14161 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
14162 ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[srfc]->m_ghostCellId;
14163
14164 // compute radius of the boundary surface and compute velocity according to parabolic profile
14165 radius = POW2(m_solver->a_coordinate(cellId, 0) - referencePoint[0])
14166 + POW2(m_solver->a_coordinate(cellId, 1) - referencePoint[1])
14167 + POW2(m_solver->a_coordinate(cellId, 2) - referencePoint[2]);
14168 velocity = 2.0 * localVel * (1 - radius / POW2(R));
14169
14170 // set ghost cell variables such that p, rho, v_i are attained on the boundary surface; v is assumed to be
14171 // normal to the surface
14172 m_solver->a_pvariable(ghostCellId, PV->RHO) = F2 * density - m_solver->a_pvariable(cellId, PV->RHO);
14173 m_solver->a_pvariable(ghostCellId, PV->P) = F2 * pressure - m_solver->a_pvariable(cellId, PV->P);
14174 m_solver->a_pvariable(ghostCellId, PV->U) =
14175 -F2 * velocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0]
14176 - m_solver->a_pvariable(cellId, PV->U);
14177 m_solver->a_pvariable(ghostCellId, PV->V) =
14178 -F2 * velocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1]
14179 - m_solver->a_pvariable(cellId, PV->V);
14180 m_solver->a_pvariable(ghostCellId, PV->W) =
14181 -F2 * velocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2]
14182 - m_solver->a_pvariable(cellId, PV->W);
14183 }
14184 }
14185 }
14186 }
14187}
14188
14196template <MInt nDim, class SysEqn>
14198 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function bc1101 is untested for 3D!"); }
14199
14200 TRACE();
14201
14202 //----------------------------------------------------------------------------
14203
14204 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
14205 const MInt bndryId = m_sortedBndryCells->a[id];
14206 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
14207 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
14208 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
14209
14210 // density
14211 m_solver->a_variable(ghostCellId, CV->RHO) = F2 * m_solver->m_rhoInfinity - m_solver->a_variable(cellId, CV->RHO);
14212 const MFloat fRho = F1 / m_solver->a_variable(cellId, CV->RHO);
14213
14214 // velocities
14215 m_solver->a_variable(ghostCellId, CV->RHO_VV[0]) =
14216 m_solver->a_variable(ghostCellId, CV->RHO)
14217 * (F2 * m_solver->m_UInfinity - m_solver->a_variable(cellId, CV->RHO_VV[0]) * fRho);
14218
14219 m_solver->a_variable(ghostCellId, CV->RHO_VV[1]) =
14220 m_solver->a_variable(ghostCellId, CV->RHO)
14221 * (F2 * m_solver->m_VInfinity - m_solver->a_variable(cellId, CV->RHO_VV[1]) * fRho);
14222
14223 MFloat rhoU =
14224 POW2(m_solver->a_variable(cellId, CV->RHO_VV[0])) + POW2(m_solver->a_variable(cellId, CV->RHO_VV[1]));
14225 IF_CONSTEXPR(nDim == 3) { rhoU += POW2(m_solver->a_variable(cellId, CV->RHO_VV[2])); }
14226
14227 MFloat rhoUGC = POW2(m_solver->a_variable(ghostCellId, CV->RHO_VV[0]))
14228 + POW2(m_solver->a_variable(ghostCellId, CV->RHO_VV[1]));
14229 IF_CONSTEXPR(nDim == 3) { rhoUGC += POW2(m_solver->a_variable(ghostCellId, CV->RHO_VV[2])); }
14230 // pressure
14231 const MFloat pressureBC =
14232 sysEqn().pressure(m_solver->a_variable(cellId, CV->RHO), rhoU, m_solver->a_variable(cellId, CV->RHO_E));
14233
14234 const MFloat pressureGC = pressureBC;
14235
14236 const MFloat vel = rhoUGC / POW2(m_solver->a_variable(ghostCellId, CV->RHO));
14237
14238 m_solver->a_variable(ghostCellId, CV->RHO_E) =
14239 sysEqn().internalEnergy(pressureGC, m_solver->a_variable(ghostCellId, CV->RHO), vel);
14240
14241 /*
14242 // species
14243 for( MInt i=0; i<noSpecies-1; i++ ) {
14244 m_solver->a_variable( ghostCellId , CV->RHO_Y[i] ) =
14245 m_solver->a_variable( ghostCellId , CV->RHO ) *
14246 ( F2 * m_Yi81[i] -
14247 m_solver->a_variable( cellId , CV->RHO_Y[ i ] ) * fRho );
14248 }
14249 */
14250 }
14251 }
14252}
14253
14261template <MInt nDim, class SysEqn>
14263 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function bc1102 is untested for 3D!"); }
14264
14265 TRACE();
14266
14267 // pressure loss from inflow to outflow
14268 const MFloat deltaP = 0.0;
14269 // 5.0 * m_solver->m_rhoInfinity * m_solver->m_UInfinity * m_solver->m_UInfinity;
14270
14271 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
14272 const MInt bndryId = m_sortedBndryCells->a[id];
14273 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
14274 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
14275 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
14276
14277 // density
14278 m_solver->a_variable(ghostCellId, CV->RHO) = m_solver->a_variable(cellId, CV->RHO);
14279
14280 // momentum fluxes
14281 m_solver->a_variable(ghostCellId, CV->RHO_VV[0]) = m_solver->a_variable(cellId, CV->RHO_VV[0]);
14282 m_solver->a_variable(ghostCellId, CV->RHO_VV[1]) = m_solver->a_variable(cellId, CV->RHO_VV[1]);
14283 IF_CONSTEXPR(nDim == 3) {
14284 m_solver->a_variable(ghostCellId, CV->RHO_VV[2]) = m_solver->a_variable(cellId, CV->RHO_VV[2]);
14285 }
14286
14287 MFloat rhoU =
14288 POW2(m_solver->a_variable(cellId, CV->RHO_VV[0])) + POW2(m_solver->a_variable(cellId, CV->RHO_VV[1]));
14289 IF_CONSTEXPR(nDim == 3) { rhoU += POW2(m_solver->a_variable(cellId, CV->RHO_VV[2])); }
14290 // pressure
14291 const MFloat pressureBC =
14292 sysEqn().pressure(m_solver->a_variable(cellId, CV->RHO), rhoU, m_solver->a_variable(cellId, CV->RHO_E));
14293 const MFloat pressureGC = F2 * (m_solver->m_PInfinity - deltaP) - pressureBC;
14294 const MFloat vel = rhoU / m_solver->a_variable(ghostCellId, CV->RHO);
14295
14296
14297 m_solver->a_variable(ghostCellId, CV->RHO_E) =
14298 sysEqn().internalEnergy(pressureGC, m_solver->a_variable(cellId, CV->RHO), vel);
14299
14300 /*
14301 // species
14302 for( MInt i=0; i<noSpecies-1; i++ ) {
14303 m_solver->a_variable( ghostCellId , CV->RHO_Y[ i ] ) =
14304 m_solver->a_variable( ghostCellId , CV->RHO ) * fRho *
14305 m_solver->a_variable( cellId , CV->RHO_Y[ i ] );
14306 }
14307 */
14308 }
14309 }
14310}
14311
14323template <MInt nDim, class SysEqn>
14325 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc1156 is untested for 2D!"); }
14326 TRACE();
14327
14328 MInt cellId;
14329 MInt nghbrId;
14330 MInt d = 0;
14331 MFloat radius;
14332 MFloat jet; //, profile_T;//radius2;
14333 // --- end of initialization
14334
14335 switch(m_cutOffBndryCndIds[bcId]) {
14336 case 1156:
14337 d = 1;
14338 break;
14339 case 1166:
14340 d = 3;
14341 break;
14342 case 1176:
14343 d = 5;
14344 break;
14345 default: {
14346 stringstream errorMessage;
14347 errorMessage << "ERROR: Switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
14348 << " not matching any case." << endl;
14349 mTerm(1, AT_, errorMessage.str());
14350 }
14351 }
14352 // loop over all concerning cells
14353 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
14354 cellId = m_sortedCutOffCells[bcId]->a[id];
14355 nghbrId = m_solver->c_neighborId(cellId, d);
14356 // compute the radial position
14357 radius = F0;
14358 for(MInt i = 0; i < nDim; i++) {
14359 if(i != d / 2) radius += POW2(m_solver->a_coordinate(cellId, i));
14360 }
14361 radius = sqrt(radius);
14362
14363 // Jet mean velocity profile
14364 jet = (F1 / 0.90 - F1) * F1B2 * (1 + tanh((m_primaryJetRadius - radius) / (2 * m_momentumThickness)))
14365 + F1B2 * (1 + tanh((m_secondaryJetRadius - radius) / (2 * m_momentumThickness)));
14366
14367 // Set the velocities [Choose 0.05 for momentum thickness ref: Bogey&Bailly]
14368 m_solver->a_pvariable(cellId, PV->VV[0]) = jet * m_targetVelocityFactor * m_targetVelocityFactor;
14369 m_solver->a_pvariable(cellId, PV->VV[1]) = F0;
14370 m_solver->a_pvariable(cellId, PV->VV[2]) = F0;
14371 if(radius <= m_primaryJetRadius) {
14372 // hot air jet
14373 //--------------
14374 // inflow mean density profile (Crocco-Buseman)
14375 m_solver->a_pvariable(cellId, PV->RHO) =
14376 m_solver->m_rhoInfinity * (1 / sysEqn().CroccoBusemann(m_Ma, jet)) / m_solver->m_densityRatio;
14377 // set the pressure of the ghost cell equal to that of the boundary cell
14378 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14379 } else if(radius <= m_secondaryJetRadius && m_primaryJetRadius <= radius) {
14380 // cold air jet
14381 //--------------
14382 // inflow mean density profile (Crocco-Buseman relation)
14383 //-----
14384 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity * (1 / sysEqn().CroccoBusemann(m_Ma, jet));
14385 // set the pressure of the ghost cell equal to that of the boundary cell
14386 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14387 }
14388 // else{
14389 // m_solver->a_pvariable( cellId , PV->P ) = m_solver->a_pvariable( nghbrId , PV->P );
14390 // m_solver->a_pvariable( cellId , PV->RHO ) = m_solver->m_rhoInfinity;
14391 // m_solver->a_pvariable( cellId , PV->VV[0] ) = F0;
14392 // m_solver->a_pvariable( cellId , PV->VV[1] ) = F0;
14393 // m_solver->a_pvariable( cellId , PV->VV[2] ) = F0;
14394 //}
14395 }
14396}
14397
14409template <MInt nDim, class SysEqn>
14411 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc1601 is untested for 2D!"); }
14412 TRACE();
14413
14414 if(m_sortedCutOffCells[bcId]->size() == 0) {
14415 return;
14416 }
14417
14418 MFloat dummyTime;
14419 MFloat that;
14420 MFloat twopioverlb;
14421
14422 MInt cellId;
14423 MInt nghbrId;
14424 MFloat xhat;
14425 MFloat yhat;
14426 MFloat zhat;
14427 MFloat spongeCorrection;
14428 MFloat fluctChol[3];
14429
14430 dummyTime = m_solver->m_time / m_bc1601->m_tau_b;
14431
14432 m_bc1601->checkRegeneration(dummyTime);
14433
14434 that = 2.0 * PI * dummyTime;
14435 twopioverlb = 2.0 * PI / m_bc1601->m_l_b;
14436
14437 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
14438 cellId = m_sortedCutOffCells[bcId]->a[id];
14439 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
14440 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
14441
14442 nghbrId = m_solver->c_neighborId(cellId, 1); // neighbor in +x dir.
14443
14444 xhat = twopioverlb * m_solver->a_coordinate(cellId, 0);
14445 yhat = twopioverlb * m_solver->a_coordinate(cellId, 1);
14446 zhat = twopioverlb * m_solver->a_coordinate(cellId, 2);
14447
14448 m_bc1601->calculateFlucts(that, xhat, yhat, zhat, fluctChol);
14449
14450 // correction factor for the sponge layer
14451 // so that fluctuations are reduced toward the edges in the sponge layer
14452 spongeCorrection = 1.0;
14453 if(m_solver->m_noSpongeFactors > 0) {
14454 spongeCorrection = 1.0 - m_solver->a_spongeFactor(cellId) * m_bc1601->m_invSigmaSponge;
14455 }
14456
14457 m_solver->a_pvariable(cellId, PV->VV[0]) = m_solver->m_UInfinity + fluctChol[0] * spongeCorrection;
14458 m_solver->a_pvariable(cellId, PV->VV[1]) = m_solver->m_VInfinity + fluctChol[1] * spongeCorrection;
14459 m_solver->a_pvariable(cellId, PV->VV[2]) = m_solver->m_WInfinity + fluctChol[2] * spongeCorrection;
14460
14461 // set the density
14462 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
14463
14464 // extrapolate the pressure (dp/dn = 0)
14465 if(m_solver->checkNeighborActive(cellId, 1)) {
14466 nghbrId = m_solver->c_neighborId(cellId, 1);
14467 if(nghbrId < 0) {
14468 cutOffBcMissingNeighbor(cellId, "bc1601");
14469 } else {
14470 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14471 }
14472 } else {
14473 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
14474 }
14475
14476 // species
14477 for(MInt s = 0; s < m_noSpecies; s++) {
14478 m_solver->a_pvariable(cellId, PV->Y[s]) = 1.0;
14479 }
14480 }
14481}
14482
14483
14489template <MInt nDim, class SysEqn>
14491 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bcInit1601 is untested for 2D!"); }
14492 TRACE();
14493
14494 // Store the boundary condition id (required if weighting of bc1601 is enabled since the actual boundary condition
14495 // using the bc1601-framework can vary)
14496 m_bc1601_bcId = bcId;
14497
14498 // build MPI Communicator
14499 const MInt noBc1601Cells = m_sortedCutOffCells[bcId]->size();
14500 ScratchSpace<MInt> bc1601CellsPerDomain(noDomains(), AT_, "bc1601CellsPerDomain");
14501
14502
14503 MPI_Allgather(&noBc1601Cells, 1, MPI_INT, &bc1601CellsPerDomain[0], 1, MPI_INT, mpiComm(), AT_, "noBc1601Cells ",
14504 "bc1601CellsPerDomain");
14505
14506
14507 const MInt totalNoBc1601Cells = std::accumulate(&bc1601CellsPerDomain[0], &bc1601CellsPerDomain[0] + noDomains(), 0);
14508 m_log << "BC1601 inflow boundary total number of cells: " << totalNoBc1601Cells << std::endl;
14509 if(domainId() == 0) {
14510 std::cerr << "BC1601 inflow boundary total number of cells: " << totalNoBc1601Cells << std::endl;
14511 }
14512
14513 MInt noInvolvedRanks = 0;
14514 ScratchSpace<MInt> involvedRanks(noDomains(), AT_, "involvedRanks");
14515 // Determine list of ranks with boundary cells
14516 for(MInt i = 0; i < noDomains(); i++) {
14517 if(bc1601CellsPerDomain[i] > 0) {
14518 involvedRanks[noInvolvedRanks] = i;
14519 ++noInvolvedRanks;
14520 }
14521 }
14522
14523 MPI_Comm newcomm;
14524 MPI_Group group;
14525 MPI_Group newgroup;
14526 MPI_Comm_group(mpiComm(), &group, AT_, "group");
14527 MPI_Group_incl(group, noInvolvedRanks, &involvedRanks[0], &newgroup, AT_);
14528
14529 MPI_Comm_create(mpiComm(), newgroup, &newcomm, AT_, "newcomm");
14530
14531 MPI_Group_free(&group, AT_);
14532 MPI_Group_free(&newgroup, AT_);
14533
14534 // if not involved, exit
14535 if(noBc1601Cells == 0) {
14536 return;
14537 }
14538
14539
14540 MFloat u_total = sysEqn().temperature_IR(m_solver->m_Ma);
14541 u_total = m_solver->m_Ma * sqrt(u_total);
14542
14543 MFloat invSigmaSponge = 1.0;
14544 if(m_solver->m_noSpongeFactors > 0) {
14545 if(m_solver->m_sigmaSponge > 0.0) invSigmaSponge = 1.0 / m_solver->m_sigmaSponge;
14546 }
14547
14548 if(m_bc1601 != nullptr) {
14549 delete m_bc1601;
14550 }
14551
14552 // create instance
14553
14554 m_bc1601 = new Bc1601Class<nDim>(newcomm, m_solverId, domainId(), u_total, invSigmaSponge);
14555
14556
14557 // Free memory
14558
14566 m_bc1601MoveGenOutOfSponge = false;
14567 m_bc1601MoveGenOutOfSponge =
14568 Context::getSolverProperty<MBool>("bc1601MoveGenOutOfSponge", m_solverId, AT_, &m_bc1601MoveGenOutOfSponge);
14569 if(m_bc1601MoveGenOutOfSponge) {
14570 MInt nghbrId;
14571 MInt noCellsToMove;
14572 // noCellsToMove = 10;
14573 // m_solver->c_cellLengthAtLevel( m_solver->a_level( cellId ) + 1 );
14574 noCellsToMove = ceil(m_spongeLayerThickness * m_spongeFactor[0]
14575 / m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel()));
14576 m_log << endl
14577 << "Move bc1601 by " << noCellsToMove << " rows into the domain, because of initial Sponge layer " << endl
14578 << endl;
14579 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
14580 nghbrId = m_sortedCutOffCells[bcId]->a[id];
14581 for(MInt i = 0; i < noCellsToMove; i++) {
14582 nghbrId = m_solver->c_neighborId(nghbrId, 1); // neighbor in +x dir.
14583 }
14584 m_sortedCutOffCells[bcId]->a[id] = nghbrId;
14585 }
14586 }
14587}
14588
14589
14600template <MInt nDim, class SysEqn>
14602 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc1602 is untested for 2D!"); }
14603 TRACE();
14604
14605 MFloat dummyTime;
14606 MFloat that;
14607 MFloat twopioverlb;
14608 MFloat factor1;
14609 MFloat factor2;
14610 MFloat b1;
14611 MFloat b2;
14612 MInt ghost1;
14613 MInt in1;
14614 MFloat xhat;
14615 MFloat yhat;
14616 MFloat zhat;
14617 MFloat fluctChol[3];
14618 MFloat velocity = F0;
14619 MInt d = 3;
14620 b1 = m_shearLayerThickness;
14621 b2 = m_shearLayerThickness;
14622 MFloat massflux = F0;
14623 MFloat jetInflowArea = F0;
14624
14625 if(((globalTimeStep - m_solver->m_restartTimeStep) <= 1 || globalTimeStep == 0) && !m_solver->m_restart) {
14626 m_log << "computing mass flux " << endl;
14627
14628 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
14629 ghost1 = m_sortedCutOffCells[bcId]->a[id];
14630 if(m_solver->a_isHalo(ghost1)) continue;
14631
14632 MFloat jetArea = POW2(m_solver->c_cellLengthAtCell(ghost1));
14633 factor1 = m_solver->a_coordinate(ghost1, 0);
14634 factor2 = m_solver->a_coordinate(ghost1, 2);
14635
14636 velocity = m_solver->m_Ma
14637 * (F1B2 * (1 + tanh(b1 * (factor1 + m_solver->m_jetHalfWidth)))
14638 * (1 - tanh(b1 * (factor1 - m_solver->m_jetHalfWidth)))
14639 - 1)
14640 * (F1B2 * (1 + tanh(b2 * (factor2 + m_solver->m_jetHalfLength)))
14641 * (1 - tanh(b2 * (factor2 - m_solver->m_jetHalfLength)))
14642 - 1);
14643 massflux += m_solver->a_variable(ghost1, PV->RHO) * velocity * jetArea;
14644 jetInflowArea += jetArea;
14645 }
14646 MPI_Allreduce(MPI_IN_PLACE, &massflux, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "massflux");
14647 MPI_Allreduce(MPI_IN_PLACE, &jetInflowArea, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
14648 "jetInflowArea");
14649
14650
14651 // compute static pressure and density iteratively (see e.g. thesis of Ingolf Hoerschler)
14652 // compute massflux per unit area
14653 massflux /= jetInflowArea;
14654 m_solver->m_jetPressure = m_solver->m_PInfinity;
14655 m_solver->m_jetDensity = m_solver->m_rhoInfinity;
14656 m_solver->m_jetTemperature = sysEqn().temperature_ES(m_solver->m_jetDensity, m_solver->m_jetPressure);
14657 m_log << "calculated pressure" << m_solver->m_jetPressure << endl;
14658 m_log << "calculated density" << m_solver->m_jetDensity << endl;
14659 m_log << "calculated temperature at inflow " << m_solver->m_jetTemperature << endl;
14660 m_log << "calculated massflux" << massflux << endl;
14661 }
14662 // MFloat FTInfinity = F1/m_solver->m_jetTemperature;
14663
14664 if(m_sortedCutOffCells[bcId]->size() == 0) {
14665 return;
14666 }
14667
14668 dummyTime = m_solver->m_time / m_bc1601->m_tau_b;
14669
14670 m_bc1601->checkRegeneration(dummyTime);
14671
14672 that = 2.0 * PI * dummyTime;
14673 twopioverlb = 2.0 * PI / m_bc1601->m_l_b;
14674
14675 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
14676 ghost1 = m_sortedCutOffCells[bcId]->a[id];
14677 in1 = m_solver->c_neighborId(ghost1, d);
14678
14679 factor1 = m_solver->a_coordinate(ghost1, 0);
14680 factor2 = m_solver->a_coordinate(ghost1, 2);
14681
14682 xhat = twopioverlb * m_solver->a_coordinate(ghost1, 0);
14683 yhat = twopioverlb * m_solver->a_coordinate(ghost1, 1);
14684 zhat = twopioverlb * m_solver->a_coordinate(ghost1, 2);
14685 fluctChol[0] = 0;
14686 fluctChol[1] = 0;
14687 fluctChol[2] = 0;
14688 m_bc1601->calculateFlucts(that, xhat, yhat, zhat, fluctChol);
14689
14690 // correction factor for the sponge layer
14691 // so that fluctuations are reduced toward the edges in the sponge layer
14692 /*
14693 spongeCorrection = 1.0;
14694 if (m_solver->m_noSpongeFactors > 0)
14695 spongeCorrection = 1.0 - m_solver->a_spongeFactor(ghost1) * m_bc1601->m_invSigmaSponge;
14696 */
14697
14698 // set variables in the cut-off cell at the desired value
14699 // NOT at the exact interface
14700 /*
14701 velocity = m_solver->m_jetConst[0]*pow(x,20);
14702 velocity +=m_solver->m_jetConst[1]*pow(x,19);
14703 velocity +=m_solver->m_jetConst[2]*pow(x,18);
14704 velocity +=m_solver->m_jetConst[3]*pow(x,17);
14705 velocity +=m_solver->m_jetConst[4]*pow(x,16);
14706 velocity +=m_solver->m_jetConst[5]*pow(x,15);
14707 velocity +=m_solver->m_jetConst[6]*pow(x,14);
14708 velocity +=m_solver->m_jetConst[7]*pow(x,13);
14709 velocity +=m_solver->m_jetConst[8]*pow(x,12);
14710 velocity +=m_solver->m_jetConst[9]*pow(x,11);
14711 velocity +=m_solver->m_jetConst[10]*pow(x,10);
14712 velocity +=m_solver->m_jetConst[11]*pow(x,9);
14713 velocity +=m_solver->m_jetConst[12]*pow(x,8);
14714 velocity +=m_solver->m_jetConst[13]*pow(x,7);
14715 velocity +=m_solver->m_jetConst[14]*pow(x,6);
14716 velocity +=m_solver->m_jetConst[15]*pow(x,5);
14717 velocity +=m_solver->m_jetConst[16]*pow(x,4);
14718 velocity +=m_solver->m_jetConst[17]*pow(x,3);
14719 velocity +=m_solver->m_jetConst[18]*pow(x,2);
14720 velocity +=m_solver->m_jetConst[19]*pow(x,1);
14721 velocity +=m_solver->m_jetConst[20];*/
14722
14723 fluctChol[0] *= (F1B2 * (1 + tanh(b1 * (factor1 + m_solver->m_jetHalfWidth)))
14724 * (1 - tanh(b1 * (factor1 - m_solver->m_jetHalfWidth)))
14725 - 1);
14726 fluctChol[0] *= (F1B2 * (1 + tanh(b2 * (factor2 + m_solver->m_jetHalfLength)))
14727 * (1 - tanh(b2 * (factor2 - m_solver->m_jetHalfLength)))
14728 - 1);
14729
14730 fluctChol[2] *= (F1B2 * (1 + tanh(b1 * (factor1 + m_solver->m_jetHalfWidth)))
14731 * (1 - tanh(b1 * (factor1 - m_solver->m_jetHalfWidth)))
14732 - 1);
14733 fluctChol[2] *= (F1B2 * (1 + tanh(b2 * (factor2 + m_solver->m_jetHalfLength)))
14734 * (1 - tanh(b2 * (factor2 - m_solver->m_jetHalfLength)))
14735 - 1);
14736
14737 m_solver->a_pvariable(ghost1, PV->U) = F2 * fluctChol[0] - m_solver->a_pvariable(in1, PV->U);
14738 velocity = m_solver->m_Ma;
14739
14740 m_solver->a_pvariable(ghost1, PV->V) = F2 * (velocity + fluctChol[1])
14741 * (F1B2 * (1 + tanh(b1 * (factor1 + m_solver->m_jetHalfWidth)))
14742 * (1 - tanh(b1 * (factor1 - m_solver->m_jetHalfWidth)))
14743 - 1)
14744 * (F1B2 * (1 + tanh(b2 * (factor2 + m_solver->m_jetHalfLength)))
14745 * (1 - tanh(b2 * (factor2 - m_solver->m_jetHalfLength)))
14746 - 1)
14747 - m_solver->a_pvariable(in1, PV->V);
14748
14749 m_solver->a_pvariable(ghost1, PV->W) = F2 * fluctChol[2] - m_solver->a_pvariable(in1, PV->W);
14750
14751 // extrapolate the pressure (dp/dn = 0)
14752 // set the pressure
14753 m_solver->a_pvariable(ghost1, PV->P) = m_solver->a_pvariable(in1, PV->P);
14754
14755 // setting density
14756 m_solver->a_pvariable(ghost1, PV->RHO) = F2 * m_solver->m_jetDensity - m_solver->a_pvariable(in1, PV->RHO);
14757
14758 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
14759 if(m_combustion) {
14760 m_solver->a_pvariable(ghost1, PV->C) = F0; //-var[ in1 ][ PV->C ];
14761 }
14762 }
14763}
14764
14765
14776template <MInt nDim, class SysEqn>
14778 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc1603 is untested for 2D!"); }
14779 TRACE();
14780
14781 if(m_sortedCutOffCells[bcId]->size() == 0) {
14782 return;
14783 }
14784
14785 MFloat that = 0;
14786 MFloat twopioverlb = 0;
14787 MFloat xhat;
14788 MFloat yhat;
14789 MFloat zhat;
14790 if(m_jetInletTurbulence) {
14791 const MFloat dummyTime = m_solver->m_time / m_bc1601->m_tau_b;
14792 m_bc1601->checkRegeneration(dummyTime);
14793 that = 2.0 * PI * dummyTime;
14794 twopioverlb = 2.0 * PI / m_bc1601->m_l_b;
14795 }
14796 MFloat fluctChol[3] = {0., 0., 0.};
14797
14798 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
14799 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
14800 const MInt nghbrId = m_solver->c_neighborId(cellId, 1); // neighbor in +x dir.
14801 const MFloat radius = sqrt(POW2(m_solver->a_coordinate(cellId, 1)) + POW2(m_solver->a_coordinate(cellId, 2)));
14802
14803 // if (radius<=m_jetHeight){
14804 if(radius <= F1B2) { // TODO labels:FV
14805 if(m_jetInletTurbulence) {
14806 xhat = twopioverlb * m_solver->a_coordinate(cellId, 0);
14807 yhat = twopioverlb * m_solver->a_coordinate(cellId, 1);
14808 zhat = twopioverlb * m_solver->a_coordinate(cellId, 2);
14809 m_bc1601->calculateFlucts(that, xhat, yhat, zhat, fluctChol);
14810 }
14811
14812 // TODO labels:FV
14813 m_solver->a_pvariable(cellId, PV->VV[0]) = F1B2 * m_Ma * (1 + tanh((radius) / (0.05))) + fluctChol[0];
14814 m_solver->a_pvariable(cellId, PV->VV[1]) = m_solver->m_VInfinity + fluctChol[1];
14815 m_solver->a_pvariable(cellId, PV->VV[2]) = m_solver->m_WInfinity + fluctChol[2];
14816
14817 MFloat profil;
14818 profil = F1B2 * (1 + tanh((radius) / (0.05)));
14819
14820 /* MFloat profil; */
14821 /* profil = F1B2*m_Ma* (1+tanh((m_jetHeight-radius)/(2*m_momentumThickness))); */
14822 /* // Set velocity profile with or without fluctuations */
14823 /* m_solver->a_pvariable(cellId, PV->VV[0]) = profil*m_Ma + fluctChol[0]; */
14824 /* m_solver->a_pvariable(cellId, PV->VV[1]) = m_solver->m_VInfinity + fluctChol[1]; */
14825 /* m_solver->a_pvariable(cellId, PV->VV[2]) = m_solver->m_WInfinity + fluctChol[2]; */
14826
14827 // set the density Crocco-Buesemann relation
14828 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity * (1 / sysEqn().CroccoBusemann(m_Ma, profil));
14829 // extrapolate the pressure (dp/dn = 0)
14830 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14831 } else {
14832 m_solver->a_pvariable(cellId, PV->VV[0]) = F0;
14833 m_solver->a_pvariable(cellId, PV->VV[1]) = F0;
14834 m_solver->a_pvariable(cellId, PV->VV[2]) = F0;
14835
14836 // set the density without Crocco-Buesemann relation
14837 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
14838 // extrapolate the pressure (dp/dn = 0)
14839 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14840 }
14841 }
14842}
14843
14844
14851template <MInt nDim, class SysEqn>
14853 TRACE();
14854 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc1604 is untested for 2D!"); }
14855
14856 if(m_sortedCutOffCells[bcId]->size() == 0) {
14857 return;
14858 }
14859
14860 MFloat that = 0;
14861 MFloat twopioverlb = 0;
14862 MFloat xhat;
14863 MFloat yhat;
14864 MFloat zhat;
14865 if(m_jetInletTurbulence) {
14866 const MFloat dummyTime = m_solver->m_time / m_bc1601->m_tau_b;
14867 m_bc1601->checkRegeneration(dummyTime);
14868 that = 2.0 * PI * dummyTime;
14869 twopioverlb = 2.0 * PI / m_bc1601->m_l_b;
14870 }
14871 MFloat fluctChol[3] = {0.0, 0.0, 0.0};
14872
14873 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
14874 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
14875 const MInt nghbrId = m_solver->c_neighborId(cellId, 1); // neighbor in +x dir.
14876 if(nghbrId < 0) {
14877 cutOffBcMissingNeighbor(cellId, "bc1604");
14878 continue;
14879 }
14880
14881 const MFloat radius = sqrt(POW2(m_solver->a_coordinate(cellId, 1)) + POW2(m_solver->a_coordinate(cellId, 2)));
14882
14883 if(radius
14884 <= 1.5 * m_jetHeight) { // Note: was just m_jetHeight but jet profile has still a value of 0.5 at this position
14885 if(m_jetInletTurbulence) {
14886 xhat = twopioverlb * m_solver->a_coordinate(cellId, 0);
14887 yhat = twopioverlb * m_solver->a_coordinate(cellId, 1);
14888 zhat = twopioverlb * m_solver->a_coordinate(cellId, 2);
14889 m_bc1601->calculateFlucts(that, xhat, yhat, zhat, fluctChol);
14890 }
14891
14892 const MFloat jet = 0.5 * (1.0 + tanh((m_jetHeight - radius) / (2 * m_momentumThickness)));
14893
14894 // Set velocity profile with or without fluctuations
14895 m_solver->a_pvariable(cellId, PV->VV[0]) = jet * m_solver->m_VVInfinity[0] + fluctChol[0];
14896 m_solver->a_pvariable(cellId, PV->VV[1]) = m_solver->m_VVInfinity[1] + fluctChol[1];
14897 m_solver->a_pvariable(cellId, PV->VV[2]) = m_solver->m_VVInfinity[2] + fluctChol[2];
14898
14899 // set the density Crocco-Buesemann relation
14900 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity / sysEqn().CroccoBusemann(m_Ma, jet);
14901 // extrapolate the pressure (dp/dn = 0)
14902 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14903 } else {
14904 m_solver->a_pvariable(cellId, PV->VV[0]) = F0;
14905 m_solver->a_pvariable(cellId, PV->VV[1]) = F0;
14906 m_solver->a_pvariable(cellId, PV->VV[2]) = F0;
14907 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
14908 // extrapolate the pressure (dp/dn = 0)
14909 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14910 }
14911 }
14912}
14913
14914
14924template <MInt nDim, class SysEqn>
14926 TRACE();
14927 IF_CONSTEXPR(nDim == 2) { TERMM(1, "bc1606 not useful in 2D"); }
14928
14929 if(m_sortedCutOffCells[bcId]->size() == 0) {
14930 return;
14931 }
14932
14933 MFloat fluctChol[3];
14934
14935 const MFloat dummyTime = m_solver->m_time / m_bc1601->m_tau_b;
14936 m_bc1601->checkRegeneration(dummyTime);
14937
14938 const MFloat that = 2.0 * PI * dummyTime;
14939 const MFloat twopioverlb = 2.0 * PI / m_bc1601->m_l_b;
14940 const MFloat jetTurbulence = (m_jetInletTurbulence) ? 1.0 : 0.0;
14941 const MFloat inletRadius = m_solver->m_inletRadius;
14942 const MFloat deltaMomentum = m_momentumThickness * inletRadius;
14943
14944 const MFloat densityAmbient = m_solver->m_rhoInfinity;
14945 const MFloat density_i = m_solver->m_nozzleInletRho;
14946
14947 // u(r) / u_i = jet = tanh((R-r)/2delta)
14948 const MFloat u_i = m_solver->m_nozzleInletU;
14949 const MFloat Ma_i = m_solver->m_maNozzleInlet;
14950
14951 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
14952 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
14953 const MInt nghbrId = m_solver->c_neighborId(cellId, 1); // neighbor in +x dir.
14954 if(nghbrId < 0) {
14955 cutOffBcMissingNeighbor(cellId, "bc1606");
14956 continue;
14957 }
14958
14959 const MFloat radius =
14960 sqrt(POW2(m_solver->a_coordinate(cellId, 1) - 0.0) + POW2(m_solver->a_coordinate(cellId, 2) - 0.0));
14961
14962 if(radius <= inletRadius) {
14963 const MFloat xhat = twopioverlb * m_solver->a_coordinate(cellId, 0);
14964 const MFloat yhat = twopioverlb * m_solver->a_coordinate(cellId, 1);
14965 const MFloat zhat = twopioverlb * m_solver->a_coordinate(cellId, 2);
14966
14967 m_bc1601->calculateFlucts(that, xhat, yhat, zhat, fluctChol);
14968
14969 // velocity profile, zero at wall
14970 const MFloat jet = tanh((inletRadius - radius) / (2.0 * deltaMomentum));
14971
14972 // Without Crocco-Busemann:
14973 // var[cellId][PV->RHO ]= density_i;
14974
14975 // With Crocco-Busemann:
14976 m_solver->a_pvariable(cellId, PV->RHO) = density_i / sysEqn().CroccoBusemann(Ma_i, jet);
14977 // TODO labels:FV,toenhance scale u/v/w fluctuations near the wall?
14978 m_solver->a_pvariable(cellId, PV->VV[0]) = u_i * jet + fluctChol[0] * jetTurbulence;
14979 m_solver->a_pvariable(cellId, PV->VV[1]) = fluctChol[1] * jetTurbulence;
14980 m_solver->a_pvariable(cellId, PV->VV[2]) = fluctChol[2] * jetTurbulence;
14981
14982 // Extrapolate pressure
14983 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14984 } else {
14985 m_solver->a_pvariable(cellId, PV->VV[0]) = 0.0;
14986 m_solver->a_pvariable(cellId, PV->VV[1]) = 0.0;
14987 m_solver->a_pvariable(cellId, PV->VV[2]) = 0.0;
14988
14989 m_solver->a_pvariable(cellId, PV->RHO) = densityAmbient;
14990
14991 // extrapolate the pressure (dp/dn = 0)
14992 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
14993 }
14994 }
14995}
14996
14997
15004template <MInt nDim, class SysEqn>
15006 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc1792 is untested for 2D!"); }
15007 TRACE();
15008
15009 MFloat radius_1;
15010 MFloat phi_1;
15011 MInt cellId;
15012 MInt d;
15013 MInt nghbrId;
15014
15015 d = 1;
15016
15017 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
15018 cellId = m_sortedCutOffCells[bcId]->a[id];
15019
15020
15021 nghbrId = m_solver->c_neighborId(cellId, d);
15022
15023 radius_1 = sqrt((m_solver->a_coordinate(cellId, 1) - 200.0) * (m_solver->a_coordinate(cellId, 1) - 200.0)
15024 + (m_solver->a_coordinate(cellId, 2) - 200.0) * (m_solver->a_coordinate(cellId, 2) - 200.0));
15025 if((m_solver->a_coordinate(cellId, 1) - 200.0) >= 0 && (m_solver->a_coordinate(cellId, 2) - 200.0) >= 0) {
15026 phi_1 = asin((m_solver->a_coordinate(cellId, 1) - 200.0) / radius_1);
15027 } else if((m_solver->a_coordinate(cellId, 1) - 200.0) >= 0 && (m_solver->a_coordinate(cellId, 2) - 200.0) < 0) {
15028 phi_1 = PI - asin((m_solver->a_coordinate(cellId, 1) - 200.0) / radius_1);
15029 } else if((m_solver->a_coordinate(cellId, 1) - 200.0) < 0 && (m_solver->a_coordinate(cellId, 2) - 200.0) < 0) {
15030 phi_1 = PI - asin((m_solver->a_coordinate(cellId, 1) - 200.0) / radius_1);
15031 } else {
15032 phi_1 = 2 * PI + asin((m_solver->a_coordinate(cellId, 1) - 200.0) / radius_1);
15033 }
15034
15035
15036 m_solver->a_pvariable(cellId, PV->U) = m_solver->m_UInfinity;
15037 m_solver->a_pvariable(cellId, PV->V) = m_solver->m_VInfinity * cos(phi_1) / 29.0 * radius_1;
15038 m_solver->a_pvariable(cellId, PV->W) = -m_solver->m_VInfinity * sin(phi_1) / 29.0 * radius_1;
15039
15040 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
15041 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
15042 }
15043}
15052template <MInt nDim, class SysEqn>
15054 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc1952 is untested for 2D!"); }
15055 TRACE();
15056
15057 MInt cellId;
15058 MInt nghbrId;
15059 MInt d = 0;
15060 //---
15061
15062 switch(m_cutOffBndryCndIds[bcId]) {
15063 case 1952:
15064 d = 0;
15065 break;
15066 case 1972:
15067 d = 4;
15068 break;
15069 default: {
15070 stringstream errorMessage;
15071 errorMessage << "ERROR: Switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
15072 << " not matching any case." << endl;
15073 mTerm(1, AT_, errorMessage.str());
15074 }
15075 }
15076
15077 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
15078 cellId = m_sortedCutOffCells[bcId]->a[id];
15079 nghbrId = m_solver->c_neighborId(cellId, d);
15080
15081 // zero-gradient density
15082 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
15083
15084 // zero-gradient velocity
15085 for(MInt i = 0; i < nDim; i++) {
15086 m_solver->a_pvariable(cellId, PV->VV[i]) = m_solver->a_pvariable(nghbrId, PV->VV[i]);
15087 }
15088
15089 // set the pressure
15090 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
15091
15092 // zero-gradient species
15093 for(MInt s = 0; s < m_noSpecies; s++) {
15094 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->a_pvariable(nghbrId, PV->Y[s]);
15095 }
15096 }
15097}
15098
15099
15107template <MInt nDim, class SysEqn>
15109 TRACE();
15110
15111#ifdef _OPENMP
15112#pragma omp parallel for
15113#endif
15114 // set mean flow values
15115 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
15116 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
15117 // density
15118 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
15119 // velocities
15120 for(MInt dim = 0; dim < m_solver->nDim; dim++) {
15121 m_solver->a_pvariable(cellId, PV->VV[dim]) = m_solver->m_VVInfinity[dim];
15122 }
15123 // pressure
15124 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
15125 }
15126
15127 // add the modes
15128 if(m_besselModes) {
15129 // time ist constant during the rk steps, we only need to integrate once
15130 if(!m_solver->m_RKStep) {
15131 precomputeBesselTrigonometry(bcId);
15132 }
15133 // add the modes using the precomputed bessel fractions
15134 addBesselModes(bcId);
15135 } else {
15136 addModes(bcId);
15137 }
15138}
15139
15140
15147template <MInt nDim, class SysEqn>
15149 TRACE();
15150
15162 m_besselModes = Context::getSolverProperty<MInt>("besselModes", m_solverId, AT_, &m_besselModes);
15163
15164 if(m_besselModes) {
15165 initBesselModes(bcId);
15166 } else {
15167 initModes(bcId);
15168 }
15169}
15170
15171
15187template <MInt nDim, class SysEqn>
15189 TRACE();
15190 m_log << endl << "bcInit2770 for bcId " << bcId << endl;
15191 // read bc2770 properties
15192
15204 // number of cells for the shock solution at the boundary
15205 m_noShockBcCells = 21;
15206 m_noShockBcCells = Context::getSolverProperty<MInt>("noShockBcCells", m_solverId, AT_, &m_noShockBcCells);
15207
15218 // number of cells for the shock solution at the boundary
15219 m_shockFromInnerSolution = false;
15220 m_shockFromInnerSolution =
15221 Context::getSolverProperty<MBool>("shockFromInnerSolution", m_solverId, AT_, &m_shockFromInnerSolution);
15222
15234 // shock angle, see fluidmechanics lecture notes
15235 m_sigmaShock = Context::getSolverProperty<MFloat>("sigmaShock", m_solverId, AT_, &m_sigmaShock);
15236 m_sigmaShock *= PI / 180.0;
15237
15238 // y-location of shock position at the boundary
15250 m_ys = Context::getSolverProperty<MFloat>("ys", m_solverId, AT_);
15251
15252 MFloat srf = F4;
15266 srf = Context::getSolverProperty<MFloat>("srf", m_solverId, AT_, &srf);
15267 MInt dom = -1;
15268 MIntScratchSpace tmpTargetCells(m_noShockBcCells, AT_, "tmpTargetCells");
15269 tmpTargetCells.fill(-1);
15270 MFloatScratchSpace tmpTargetCoords(nDim, AT_, "tmpTargetCoords");
15271 MFloatScratchSpace tmpSrcVars(m_noShockBcCells, PV->noVariables, AT_, "tmpSrcVars");
15272 tmpSrcVars.fill(-std::numeric_limits<MFloat>::max());
15273
15274 // find the cell on the boundary at the upper shock region border
15275 //(m_ys + m_noShockBcCells/2 * cellLength)
15276 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
15277 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
15278 const MFloat cellLength = m_solver->c_cellLengthAtCell(cellId);
15279 // skip halos
15280 if(m_solver->a_isHalo(cellId)) {
15281 continue;
15282 }
15283 if(m_solver->a_coordinate(cellId, 1) + cellLength / F2 >= m_ys + m_noShockBcCells / 2 * cellLength
15284 && m_solver->a_coordinate(cellId, 1) - cellLength / F2 < m_ys + m_noShockBcCells / 2 * cellLength) {
15285 dom = domainId();
15286 tmpTargetCells[0] = cellId;
15287 for(MInt dim = 0; dim < nDim; dim++) {
15288 tmpTargetCoords[dim] = m_solver->a_coordinate(cellId, dim);
15289 }
15290 break;
15291 }
15292 }
15293
15294 // communicate the upper shock region border
15295 MPI_Allreduce(MPI_IN_PLACE, &dom, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "dom");
15296 MPI_Bcast(tmpTargetCoords.begin(), nDim, MPI_DOUBLE, dom, mpiComm(), AT_, "tmpTargetCoords.begin()");
15297
15298 // save the cell ids in the boundary shock region of every domain
15299 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
15300 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
15301 const MFloat cellLength = m_solver->c_cellLengthAtCell(cellId);
15302
15303 if(m_solver->a_isHalo(cellId)) { // TODO labels:FV,totest Stephan says I need to set the bc at halo cells, check!
15304 continue;
15305 }
15306
15307 MFloat y_coord = tmpTargetCoords[1];
15308 for(MInt i = 1; i < m_noShockBcCells; i++) {
15309 y_coord -= cellLength;
15310 if(m_solver->a_coordinate(cellId, 1) + cellLength / F2 >= y_coord
15311 && m_solver->a_coordinate(cellId, 1) - cellLength / F2 < y_coord) {
15312 tmpTargetCells[i] = cellId;
15313 }
15314 }
15315 }
15316
15317 // save a shock solution for the boundary shock region
15318 if(m_solver->m_restart) {
15319 if(m_shockFromInnerSolution) {
15320 m_log << "using shock solution from inside of the domain" << endl;
15321 // get the solution from the inner shock region
15322 MFloatScratchSpace tmpSrcCoords(nDim, AT_, "tmpSrcCoords");
15323 tmpSrcCoords[0] = tmpTargetCoords[0]
15324 + 0.8; // TODO labels:FV,toenhance distance is hardcoded, is there a min/max cell value to use?
15325 tmpSrcCoords[1] = tmpTargetCoords[1] + (tan(m_solver->m_angle[0] + m_sigmaShock) * 0.8);
15326 for(MInt id = 0; id < m_solver->noInternalCells(); id++) {
15327 const MFloat cellLength = m_solver->c_cellLengthAtCell(id);
15328 if(m_solver->c_noChildren(id) > 0) {
15329 continue;
15330 }
15331 MFloat y_src_coord = tmpSrcCoords[1];
15332 for(MInt i = 0; i < m_noShockBcCells; i++) {
15333 if(m_solver->a_coordinate(id, 0) + cellLength / F2 >= tmpSrcCoords[0]
15334 && m_solver->a_coordinate(id, 0) - cellLength / F2 < tmpSrcCoords[0]
15335 && m_solver->a_coordinate(id, 1) + cellLength / F2 >= y_src_coord
15336 && m_solver->a_coordinate(id, 1) - cellLength / F2 < y_src_coord) {
15337 // density
15338 tmpSrcVars(i, PV->RHO) = m_solver->a_pvariable(id, PV->RHO);
15339 // velocities
15340 for(MInt dim = 0; dim < m_solver->nDim; dim++) {
15341 tmpSrcVars(i, PV->VV[dim]) = m_solver->a_pvariable(id, PV->VV[dim]);
15342 }
15343 // pressure
15344 tmpSrcVars(i, PV->P) = m_solver->a_pvariable(id, PV->P);
15345 }
15346 MFloat y_src = y_src_coord - cellLength;
15347 y_src_coord = y_src;
15348 }
15349 }
15350 // communicate the shock solution in the inner shock region
15351 MPI_Allreduce(MPI_IN_PLACE, tmpSrcVars.begin(), m_noShockBcCells * PV->noVariables, MPI_DOUBLE, MPI_MAX,
15352 mpiComm(), AT_, "MPI_IN_PLACE", "tmpSrcVars.begin()");
15353
15354 } else {
15355 m_log << "using shock solution from the inlet boundary of the domain" << endl;
15356 // get the solution from the boundary shock region
15357 for(MInt i = 0; i < m_noShockBcCells; i++) {
15358 const MInt cellId = tmpTargetCells[i];
15359 if(cellId != -1) {
15360 // density
15361 tmpSrcVars(i, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
15362 // velocities
15363 for(MInt dim = 0; dim < m_solver->nDim; dim++) {
15364 tmpSrcVars(i, PV->VV[dim]) = m_solver->a_pvariable(cellId, PV->VV[dim]);
15365 }
15366 // pressure
15367 tmpSrcVars(i, PV->P) = m_solver->a_pvariable(cellId, PV->P);
15368 }
15369 }
15370 }
15371 } else {
15372 m_log << "using analytic shock solution" << endl;
15373 // if we are not restarting, blend between up and downstream of the shock
15374 // calculate the flow downstream of the shock, see fluidmechanics lecture notes
15375 const MFloat gamma = sysEqn().gamma_Ref();
15376 const MFloat gammaPlusOne = gamma + F1;
15377 const MFloat gammaMinusOne = gamma - F1;
15378 const MFloat Ma = m_solver->m_Ma;
15379 const MFloat Ma_ns = POW2(Ma * sin(m_sigmaShock));
15380 const MFloat fact_pressure = F1 + (F2 * gamma / gammaPlusOne) * (Ma_ns - F1);
15381 const MFloat fact_density = (gammaPlusOne * Ma_ns) / (gammaMinusOne * Ma_ns + F2);
15382 // rotate the velocities into the shock aligned coordinate system
15383 const MFloat angle = PI / F2 - m_sigmaShock;
15384 const MFloat un1 = m_solver->m_VVInfinity[0] * cos(angle) - m_solver->m_VVInfinity[1] * sin(angle);
15385 const MFloat ut1 = m_solver->m_VVInfinity[0] * sin(angle) + m_solver->m_VVInfinity[1] * cos(angle);
15386 // apply the shock conditions
15387 const MFloat un2 = un1 / fact_density;
15388 const MFloat ut2 = ut1;
15389 // rotate the velocities back to cartesian coordinate system
15390 const MFloat ux2 = un2 * cos(angle) + ut2 * sin(angle);
15391 const MFloat uy2 = -un2 * sin(angle) + ut2 * cos(angle);
15392 // check the mach number downstream for supersonic flow
15393 const MFloat a2 =
15394 sysEqn().speedOfSound(m_solver->m_rhoInfinity * fact_density, m_solver->m_PInfinity * fact_pressure);
15395 m_log << "Ma_2x = " << ux2 / a2 << ", Ma_2y = " << uy2 / a2 << endl;
15396 // if(ux2/a2 <= F1 || uy2/a2 <= F1)
15397 // mTerm(1, AT_, "bc2770: downstream supersonic assumptions are violated");
15398 // set the variables
15399 for(MInt i = 0; i < m_noShockBcCells; i++) {
15400 // however i want to blend, F0 is upstream and F1 is downstream
15401 // srf (shock region factor): how much do i want to compress my analytic shock into the m_noShockBcCells cells
15402 // srf = 1 is all over m_noShockBcCells, srf = 2 is m_noShockBcCells/2 and so on
15403 MFloat fb = mMax(mMin(((MFloat)i / (m_noShockBcCells - 1) - F1B2) * srf, F1B2), -F1B2) + F1B2;
15404 m_log << "fb ( " << i << ") = " << fb << endl;
15405
15406 // density
15407 tmpSrcVars(i, PV->RHO) = m_solver->m_rhoInfinity * ((F1 - fb) + fb * fact_density);
15408 // velocities
15409 tmpSrcVars(i, PV->VV[0]) = (F1 - fb) * m_solver->m_VVInfinity[0] + fb * ux2;
15410 tmpSrcVars(i, PV->VV[1]) = (F1 - fb) * m_solver->m_VVInfinity[1] + fb * uy2;
15411 // pressure
15412 tmpSrcVars(i, PV->P) = m_solver->m_PInfinity * ((F1 - fb) + fb * fact_pressure);
15413 }
15414 }
15415
15416 // count the cells in the boundary shock region of this domain
15417 MInt noShockBcCellsInDomain = 0;
15418 for(MInt i = 0; i < m_noShockBcCells; i++) {
15419 if(tmpTargetCells[i] != -1) {
15420 noShockBcCellsInDomain++;
15421 }
15422 }
15423
15424 // allocate permanent memory for the boundary shock region
15425 mAlloc(m_Bc2770TargetCells, noShockBcCellsInDomain, "Bc2770TargetCells", AT_);
15426 mAlloc(m_shockBcVars, noShockBcCellsInDomain, PV->noVariables, "m_shockBcVars", AT_);
15427
15428 // fill the permanent memory
15429 MInt k = 0;
15430 for(MInt i = 0; i < m_noShockBcCells; i++) {
15431 if(tmpTargetCells[i] != -1) {
15432 m_Bc2770TargetCells[k] = tmpTargetCells[i];
15433 for(MInt var = 0; var < PV->noVariables; var++) {
15434 m_shockBcVars[k][var] = tmpSrcVars(i, var);
15435 }
15436 k++;
15437 }
15438 }
15439 m_noShockBcCells = noShockBcCellsInDomain;
15440
15441 initModes(bcId);
15442
15443 m_log << "initialization of bc2770 done" << endl;
15444}
15445
15446
15454template <MInt nDim, class SysEqn>
15456 TRACE();
15457
15458 MInt direction = m_cutOffBndryCndIds[bcId] - 2710;
15459
15460 if(direction % 2) {
15461 direction--;
15462 } else {
15463 direction++;
15464 }
15465
15466 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
15467 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
15468 if(m_solver->a_hasProperty(cellId, SolverCell::IsPeriodicWithRot)) {
15469 continue;
15470 }
15471 MLong nghbrId = m_solver->c_neighborId(cellId, direction);
15472
15473 if(nghbrId < 0) {
15474 continue;
15475 }
15476 if(m_solver->c_noChildren(nghbrId) > 0) {
15477 MFloat coCoord = m_solver->a_coordinate(cellId, direction / 2);
15478 MInt childCnt = 0;
15479 // reset cut off cell
15480 for(MInt i = 0; i < PV->noVariables; i++) {
15481 m_solver->a_pvariable(cellId, i) = F0;
15482 }
15483 // use parents neighbours childs, but only the close ones, should be four
15484 for(MInt child = 0; child < IPOW2(nDim); child++) {
15485 MLong childId = m_solver->c_childId(nghbrId, child);
15486 if(childId < 0) {
15487 continue;
15488 }
15489 if(abs(m_solver->a_coordinate(childId, direction / 2) - coCoord) > m_solver->c_cellLengthAtCell(cellId)) {
15490 continue;
15491 }
15492 childCnt++;
15493 for(MInt i = 0; i < PV->noVariables; i++) {
15494 m_solver->a_pvariable(cellId, i) += m_solver->a_pvariable(childId, i);
15495 }
15496 }
15497 // divide by number of cells used
15498 for(MInt i = 0; i < PV->noVariables; i++) {
15499 m_solver->a_pvariable(cellId, i) /= (MFloat)childCnt;
15500 }
15501 } else {
15502 for(MInt i = 0; i < PV->noVariables; i++) {
15503 m_solver->a_pvariable(cellId, i) = m_solver->a_pvariable(nghbrId, i);
15504 }
15505 }
15506 }
15507}
15508
15509
15517template <MInt nDim, class SysEqn>
15519 TRACE();
15520
15521 MInt direction = m_cutOffBndryCndIds[bcId] - 2720;
15522
15523 if(direction % 2) {
15524 direction--;
15525 } else {
15526 direction++;
15527 }
15528
15529 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
15530 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
15531 if(m_solver->a_hasProperty(cellId, SolverCell::IsPeriodicWithRot)) {
15532 continue;
15533 }
15534 MLong nghbrId = m_solver->c_neighborId(cellId, direction);
15535
15536 if(nghbrId < 0) {
15537 continue;
15538 }
15539 if(m_solver->c_noChildren(nghbrId) > 0) {
15540 MFloat coCoord = m_solver->a_coordinate(cellId, direction / 2);
15541 MInt childCnt = 0;
15542 // reset cut off cell
15543 for(MInt i = 0; i < PV->noVariables; i++) {
15544 m_solver->a_pvariable(cellId, i) = F0;
15545 }
15546 // use parents neighbours childs, but only the close ones, should be four
15547 for(MInt child = 0; child < IPOW2(nDim); child++) {
15548 MLong childId = m_solver->c_childId(nghbrId, child);
15549 if(childId < 0) {
15550 continue;
15551 }
15552 if(abs(m_solver->a_coordinate(childId, direction / 2) - coCoord) > m_solver->c_cellLengthAtCell(cellId)) {
15553 continue;
15554 }
15555 childCnt++;
15556 for(MInt i = 0; i < PV->noVariables; i++) {
15557 m_solver->a_pvariable(cellId, i) += m_solver->a_pvariable(childId, i);
15558 }
15559 }
15560 // divide by number of cells used
15561 for(MInt i = 0; i < PV->noVariables; i++) {
15562 m_solver->a_pvariable(cellId, i) /= (MFloat)childCnt;
15563 }
15564
15565 m_solver->a_pvariable(cellId, PV->P) = F2 * m_solver->m_postShockPV[PV->P] - m_solver->a_pvariable(cellId, PV->P);
15566 } else {
15567 for(MInt i = 0; i < PV->P; i++) {
15568 m_solver->a_pvariable(cellId, i) = m_solver->a_pvariable(nghbrId, i);
15569 }
15570
15571 m_solver->a_pvariable(cellId, PV->P) =
15572 F2 * m_solver->m_postShockPV[PV->P] - m_solver->a_pvariable(nghbrId, PV->P);
15573
15574 for(MInt i = PV->P + 1; i < PV->noVariables; i++) {
15575 m_solver->a_pvariable(cellId, i) = m_solver->a_pvariable(nghbrId, i);
15576 }
15577 }
15578 }
15579}
15580
15589template <MInt nDim, class SysEqn>
15591 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc2907 is untested for 2D!"); }
15592 TRACE();
15593
15594 MInt cellId;
15595 MInt bndryId;
15596 MInt ghostCellId;
15597 MFloat TInfinity = m_solver->m_TInfinity;
15598 if(m_combustion) TInfinity = m_solver->m_burntUnburntTemperatureRatio;
15599
15600 //---end of initialization
15601
15602 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
15603 bndryId = m_sortedBndryCells->a[id];
15604 cellId = m_bndryCells->a[bndryId].m_cellId;
15605 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
15606 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
15607
15608 // set the velocities
15609 if(abs(m_solver->a_coordinate(cellId, 0)) >= m_solver->m_jetCoflowOffset
15610 && // jet radius R = 0.5 + 0.125 distance = 0.625to coflow
15611 abs(m_solver->a_coordinate(cellId, 0)) <= m_solver->m_jetCoflowEndOffset
15612 && // jet radius R = 0.5 + 0.125 distance = 0.625to coflow
15613 abs(m_solver->a_coordinate(cellId, 2)) <= m_solver->m_jetHalfLength) { // half jet length L = 8.33/2
15614
15615 m_solver->a_pvariable(ghostCellId, PV->V) = F2 * m_solver->m_MaCoflow - m_solver->a_pvariable(cellId, PV->V);
15616 m_solver->a_pvariable(ghostCellId, PV->U) = -m_solver->a_pvariable(cellId, PV->U);
15617 m_solver->a_pvariable(ghostCellId, PV->W) = -m_solver->a_pvariable(cellId, PV->W);
15618
15619 // set the pressure
15620 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
15621 // changed to dirichlet bc
15622 // m_solver->a_pvariable( ghostCellId , PV->RHO ) = F2*CV->m_rhoInfinity -
15623 // m_solver->a_pvariable( cellId , PV->RHO );
15624 // compute the density from inside of the domain using the pressure
15625 m_solver->a_pvariable(ghostCellId, PV->RHO) =
15626 sysEqn().density_ES(m_solver->a_pvariable(cellId, PV->P), TInfinity);
15627
15628 // set the species
15629 for(MInt s = 0; s < m_noSpecies; s++) {
15630 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
15631 }
15632
15633 } else {
15634 m_solver->a_pvariable(ghostCellId, PV->V) = -m_solver->a_pvariable(cellId, PV->V);
15635 m_solver->a_pvariable(ghostCellId, PV->U) = -m_solver->a_pvariable(cellId, PV->U);
15636 m_solver->a_pvariable(ghostCellId, PV->W) = -m_solver->a_pvariable(cellId, PV->W);
15637
15639 // set the density
15640 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
15641
15642 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
15643
15644 // set the species
15645 for(MInt s = 0; s < m_noSpecies; s++) {
15646 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
15647 }
15648 }
15649 }
15650 }
15651}
15652
15659template <MInt nDim, class SysEqn>
15661 TRACE();
15662
15663 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
15664 MInt bndryId = m_sortedBndryCells->a[id];
15665 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
15666
15667 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
15668 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
15669 MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
15670 if(ghostCellId < 0 && ghostCellId >= m_solver->a_noCells()) {
15671 mTerm(1, AT_, "Ghost cell: " + to_string(ghostCellId));
15672 }
15673 MInt k = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0];
15674 ASSERT(k > -1 && k < m_solver->m_noEmbeddedBodies + m_solver->m_noPeriodicGhostBodies, "");
15675 if(k < 0 || k >= m_solver->m_noEmbeddedBodies + m_solver->m_noPeriodicGhostBodies) {
15676 mTerm(1, AT_, "Invalid body id: " + to_string(k));
15677 }
15678
15679
15680 MFloat vel[3] = {0.0, 0.0, 0.0};
15681 for(MInt i = 0; i < nDim; i++) {
15682 vel[i] = m_solver->m_bodyVelocity[k * nDim + i];
15683 }
15684
15685 MFloat dx[3]{};
15686 MFloat omega[3]{};
15687 MFloat vrad[3]{};
15688 MFloat dn = 0;
15689 for(MInt i = 0; i < nDim; i++) {
15690 dn += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
15691 * (m_solver->a_coordinate(cellId, i) - m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]);
15692 }
15693 for(MInt i = 0; i < nDim; i++) {
15694 dx[i] = m_solver->a_coordinate(cellId, i) - dn * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
15695 - m_solver->m_bodyCenter[k * nDim + i];
15696 }
15697 for(MInt i = 0; i < 3; i++) {
15698 omega[i] = m_solver->m_bodyAngularVelocity[k * 3 + i];
15699 }
15700 vrad[0] = omega[1] * dx[2] - omega[2] * dx[1];
15701 vrad[1] = omega[2] * dx[0] - omega[0] * dx[2];
15702 IF_CONSTEXPR(nDim == 3) vrad[2] = omega[0] * dx[1] - omega[1] * dx[0];
15703
15704 for(MInt i = 0; i < nDim; i++) {
15705 vel[i] += vrad[i];
15706 }
15707
15708 for(MInt i = 0; i < nDim; i++) {
15709 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = F2 * vel[i] - m_solver->a_pvariable(cellId, PV->VV[i]);
15710 }
15711
15712 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
15713 for(MInt r = 0; r < m_solver->m_noRansEquations; r++) {
15714 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = -m_solver->a_pvariable(cellId, PV->NN[r]);
15715 }
15716 }
15717
15718
15719 for(MInt s = 0; s < m_noSpecies; s++) {
15720 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
15721 }
15722 }
15723 }
15724 }
15725
15726 // gap-Cell correction!
15727 if(m_solver->m_closeGaps && !m_solver->m_gapCells.empty()) {
15728 // update of nearGap-Cells with secondBody-Id!
15729 setGapGhostCellVariables(bcId);
15730 }
15731}
15732
15736template <MInt nDim, class SysEqn>
15738 TRACE();
15739
15740 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
15741 const MInt bndryId = m_sortedBndryCells->a[id];
15742 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
15743
15744 if(!m_solver->a_isGapCell(cellId)) continue;
15745 // if( m_solver->a_hasProperty( cellId , SolverCell::IsNotGradient) ) continue;
15746 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
15747
15748 const MInt gapCellId = m_solver->m_gapCellId[cellId];
15749 ASSERT(gapCellId > -1, "");
15750 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
15751 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
15752 for(MInt i = 0; i < nDim; i++) {
15753 const MFloat vel = m_solver->m_gapCells[gapCellId].surfaceVelocity[i];
15754 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = F2 * vel - m_solver->a_pvariable(cellId, PV->VV[i]);
15755 }
15756 }
15757 }
15758}
15759
15760
15767template <MInt nDim, class SysEqn>
15769#ifdef _OPENMP
15770#pragma omp parallel for
15771#endif
15772 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
15773 const MInt bndryId = m_sortedBndryCells->a[id];
15774 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
15775
15776 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
15777 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
15778 MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
15779
15780 MInt k = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0];
15781 ASSERT(k > -1 && k < m_solver->m_noEmbeddedBodies + m_solver->m_noPeriodicGhostBodies, "");
15782 if(k < 0 || k >= m_solver->m_noEmbeddedBodies + m_solver->m_noPeriodicGhostBodies) {
15783 mTerm(1, AT_, "Invalid body id: " + to_string(k));
15784 }
15785
15786 MFloat vel[nDim];
15787 MFloat surfVel[nDim];
15788 for(MInt i = 0; i < nDim; i++) {
15789 surfVel[i] = m_solver->m_bodyVelocity[k * nDim + i];
15790 }
15791 MFloat dx[3] = {F0, F0, F0};
15792 MFloat omega[3] = {F0, F0, F0};
15793 MFloat vrad[3] = {F0, F0, F0};
15794 for(MInt i = 0; i < nDim; i++) {
15795 dx[i] = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i] - m_solver->m_bodyCenter[k * nDim + i];
15796 }
15797 for(MInt i = 0; i < 3; i++) {
15798 omega[i] = m_solver->m_bodyAngularVelocity[k * 3 + i];
15799 }
15800 vrad[0] = omega[1] * dx[2] - omega[2] * dx[1];
15801 vrad[1] = omega[2] * dx[0] - omega[0] * dx[2];
15802 IF_CONSTEXPR(nDim == 3) vrad[2] = omega[0] * dx[1] - omega[1] * dx[0];
15803
15804 for(MInt i = 0; i < nDim; i++) {
15805 surfVel[i] += vrad[i];
15806 }
15807 /*
15808 MFloat imageVel[3] = {F0,F0,F0};
15809 for(MInt s = 0; s < mMin((signed)m_bndryCell[ bndryId ].m_recNghbrIds.size(),m_bndryCells->a[ bndryId
15810 ].m_noSrfcs); s++){ const MInt dummyId = m_bndryCell[ bndryId ].m_recNghbrIds[s]; for( MInt i=0; i<nDim;
15811 i++ ) { m_solver->a_pvariable( dummyId , PV->VV[i] ) = surfVel[i];
15812 }
15813 }
15814 for ( MUint n = 0; n < m_bndryCell[ bndryId ].m_recNghbrIds.size(); n++ ) {
15815 const MInt nghbrId = m_bndryCell[ bndryId ].m_recNghbrIds[n];
15816 if ( nghbrId < 0 || m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_imagePointRecConst.size() !=
15817 m_bndryCell[ bndryId ].m_recNghbrIds.size() ) { cerr << nghbrId << " " << m_bndryCell[ bndryId
15818 ].m_srfcVariables[srfc]->m_imagePointRecConst.size() << " " << m_bndryCell[ bndryId ].m_recNghbrIds.size() <<
15819 endl;
15820 }
15821 ASSERT ( nghbrId > -1 && m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_imagePointRecConst.size() ==
15822 m_bndryCell[ bndryId ].m_recNghbrIds.size(), "" ); for( MInt i=0; i<nDim; i++ ) { imageVel[i] += m_bndryCell[
15823 bndryId ].m_srfcVariables[srfc]->m_imagePointRecConst[n] * m_solver->a_pvariable( nghbrId ,
15824 PV->VV[i]);
15825 }
15826 }
15827
15828 MFloat normal[3] = {F0,F0,F0};
15829 MFloat cnt = F0;
15830 for ( MInt i = 0; i < nDim; i++ ) {
15831 normal[i] = m_solver->a_coordinate( cellId , i ) - m_solver->a_coordinate( ghostCellId , i );
15832 cnt += POW2(normal[i]);
15833 }
15834 cnt = sqrt(cnt);
15835 for ( MInt i = 0; i < nDim; i++ ) {
15836 normal[i] /= cnt;
15837 }
15838
15839
15840 // 1. set the surface velocities
15841 for( MInt i=0; i<nDim; i++ ) {
15842 vel[i] = imageVel[i];//m_solver->a_pvariable( cellId , PV->VV[i] );
15843 for( MInt j=0; j<nDim; j++ ) {
15844 vel[i] +=
15845 normal[i] * //m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_normalVector[ i ] *
15846 ( surfVel[ j ] - imageVel[i] ) //m_solver->a_pvariable( cellId , PV->VV[j] ) )
15847 * normal[j] ;//m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_normalVector[ j ] ;
15848 }
15849 }*/
15850
15851 // 1. set the surface velocities
15852 for(MInt i = 0; i < nDim; i++) {
15853 vel[i] = m_solver->a_pvariable(cellId, PV->VV[i]);
15854 for(MInt j = 0; j < nDim; j++) {
15855 vel[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
15856 * (surfVel[j] - m_solver->a_pvariable(cellId, PV->VV[j]))
15857 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[j];
15858 }
15859 }
15860
15861
15862 for(MInt i = 0; i < nDim; i++) {
15863 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = F2 * vel[i] - m_solver->a_pvariable(cellId, PV->VV[i]);
15864 m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = vel[i];
15865 }
15866 }
15867 }
15868 }
15869}
15870
15871
15877template <MInt nDim, class SysEqn>
15879 TRACE();
15880
15881 MFloat vel[3]{};
15882 MFloat bbox[6]{};
15883 m_solver->m_geometry->getBoundingBox(bbox);
15884 const MFloat deltaY = bbox[1 + nDim] - bbox[1];
15885
15886 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
15887 MInt bndryId = m_sortedBndryCells->a[id];
15888 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
15889 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
15890 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
15891 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
15892 MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
15893
15894 vel[0] = F2 * m_solver->m_UInfinity * m_bndryCell[bndryId].m_srfcs[0]->m_coordinates[1] / deltaY;
15895 for(MInt i = 0; i < nDim; i++) {
15896 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = F2 * vel[i] - m_solver->a_pvariable(cellId, PV->VV[i]);
15897 }
15898
15899 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
15900 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
15901 }
15902 }
15903 }
15904 }
15905}
15906
15907
15914template <MInt nDim, class SysEqn>
15916 TRACE();
15917#ifdef _OPENMP
15918#pragma omp parallel for
15919#endif
15920 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
15921 MInt bndryId = m_sortedBndryCells->a[id];
15922 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
15923 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
15924 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
15925 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
15926 MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
15927 for(MInt i = 0; i < nDim; i++) {
15928 m_solver->a_pvariable(ghostCellId, PV->VV[i]) = -m_solver->a_pvariable(cellId, PV->VV[i]);
15929 }
15930 }
15931 }
15932 }
15933 }
15934}
15935
15940template <MInt nDim, class SysEqn>
15942 TRACE();
15943
15944#ifdef _OPENMP
15945#pragma omp parallel for
15946#endif
15947 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
15948 MInt bndryId = m_sortedBndryCells->a[id];
15949 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
15950 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
15951 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
15952 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
15953 MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
15954 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
15955 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
15956 for(MInt s = 0; s < m_noSpecies; s++) {
15957 m_solver->a_pvariable(ghostCellId, PV->Y[s]) = m_solver->a_pvariable(cellId, PV->Y[s]);
15958 }
15959 }
15960 }
15961 }
15962 }
15963}
15964
15971template <MInt nDim, class SysEqn>
15973 TRACE();
15974
15975 if(m_sortedCutOffCells[bcId]->size() == 0) return;
15976
15977 const MInt otherDir[4] = {1, 0, 3, 2};
15978
15979 if(m_firstUseBc10970) {
15980 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
15981 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
15982 if(noCutOffDirections != noCutOffBndryIds)
15983 mTerm(1, AT_,
15984 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
15985 MInt cutOffBndryIdTmp, cutOffDirectionTmp;
15986 for(MInt i = 0; i < noCutOffBndryIds; i++) {
15987 cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
15988 cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
15989 if(cutOffBndryIdTmp == m_cutOffBndryCndIds[bcId]) {
15990 m_dirNBc10970 = otherDir[cutOffDirectionTmp];
15991 break;
15992 }
15993 }
15994
15995 m_pModeBc10970 = 0;
15996 m_pModeBc10970 = Context::getSolverProperty<MInt>("BC10970Mode", m_solverId, AT_, &m_pModeBc10970);
15997 m_firstUseBc10970 = false;
15998 }
15999 //---
16000
16001 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16002 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16003 MInt nghbrId = m_solver->c_neighborId(cellId, m_dirNBc10970);
16004
16005 // set the density
16006 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
16007
16008 // set the velocities
16009 for(MInt i = 0; i < nDim; i++)
16010 m_solver->a_pvariable(cellId, PV->VV[i]) = m_solver->a_pvariable(nghbrId, PV->VV[i]);
16011
16012 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
16013 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
16014 m_solver->a_pvariable(cellId, PV->NN[r]) = m_solver->a_pvariable(nghbrId, PV->NN[r]);
16015 }
16016 }
16017
16018 // set the pressure
16019 if(m_pModeBc10970 == 0) {
16020 m_solver->a_pvariable(cellId, PV->P) = F2 * (m_solver->m_PInfinity) - m_solver->a_pvariable(nghbrId, PV->P);
16021 } else if(m_pModeBc10970 == 1) {
16022 m_solver->a_pvariable(cellId, PV->P) = 0.9 * m_solver->m_PInfinity;
16023 } else {
16024 mTerm(1, AT_, "Unknown pressure mode in BC10970");
16025 }
16026 }
16027}
16028
16035template <MInt nDim, class SysEqn>
16037 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function bc10980 is untested for 3D!"); }
16038 TRACE();
16039
16040
16041 if(m_sortedCutOffCells[bcId]->size() == 0) return;
16042
16043 const MInt otherDir[4] = {1, 0, 3, 2};
16044
16045 if(m_firstUseBc10980) {
16046 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
16047 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
16048 if(noCutOffDirections != noCutOffBndryIds)
16049 mTerm(1, AT_,
16050 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
16051 MInt cutOffBndryIdTmp, cutOffDirectionTmp;
16052 for(MInt i = 0; i < noCutOffBndryIds; i++) {
16053 cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
16054 cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
16055 if(cutOffBndryIdTmp == m_cutOffBndryCndIds[bcId]) {
16056 m_dirNBc10980 = otherDir[cutOffDirectionTmp];
16057 break;
16058 }
16059 }
16060
16061 m_firstUseBc10980 = false;
16062 }
16063 //---
16064
16065 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16066 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16067 MInt nghbrId = m_solver->c_neighborId(cellId, m_dirNBc10980);
16068
16069 // set the density
16070 m_solver->a_pvariable(cellId, PV->RHO) = F2 * m_solver->m_rhoInfinity - m_solver->a_pvariable(nghbrId, PV->RHO);
16071
16072 // set the velocities
16073 for(MInt i = 0; i < nDim; i++)
16074 m_solver->a_pvariable(cellId, PV->VV[i]) =
16075 F2 * m_solver->m_VVInfinity[i] - m_solver->a_pvariable(nghbrId, PV->VV[i]);
16076
16077 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
16078 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
16079 m_solver->a_pvariable(cellId, PV->N) = F2 * m_solver->m_nuTildeInfinity - m_solver->a_pvariable(nghbrId, PV->N);
16080 }
16081 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
16082 m_solver->a_pvariable(cellId, PV->K) = F2 * m_solver->m_kInfinity - m_solver->a_pvariable(nghbrId, PV->K);
16083 m_solver->a_pvariable(cellId, PV->OMEGA) =
16084 F2 * m_solver->m_omegaInfinity - m_solver->a_pvariable(nghbrId, PV->OMEGA);
16085 }
16086 }
16087
16088 // set the pressure
16089 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
16090 }
16091}
16092
16093
16099template <MInt nDim, class SysEqn>
16101 TRACE();
16102
16103 if(m_sortedCutOffCells[bcId]->size() == 0) return;
16104
16105 if(m_firstUseBc11110) {
16106 //
16107 // if (m_clusterCutOffBcs==false)
16108 // mTerm(1, AT_, "WARNING: m_clusterCutOffBcs=false");
16109
16110 /* MInt noCutOffBndryIds = Context::propertyLength( "cutOffBndryIds", m_solverId);
16111 MInt noCutOffDirections = Context::propertyLength( "cutOffDirections", m_solverId);
16112 if( noCutOffDirections != noCutOffBndryIds )
16113 mTerm(1, AT_, "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please
16114 check!"); MInt cutOffBndryIdTmp, cutOffDirectionTmp; for(MInt i=0; i < noCutOffBndryIds; i++){
16115 cutOffBndryIdTmp = Context::getSolverProperty<MInt>( "cutOffBndryIds", m_solverId, AT_, i);
16116 cutOffDirectionTmp = Context::getSolverProperty<MInt>( "cutOffDirections", m_solverId, AT_, i);
16117 if( cutOffBndryIdTmp == m_cutOffBndryCndIds[ bcId ] ){
16118 m_dirNBc11110 = otherDir[cutOffDirectionTmp];
16119 break;
16120 }
16121 }*/
16122
16123 // save target values from RANS
16124 constexpr const MInt noVars = nDim + 2;
16125
16126 mAlloc(m_targetValuesBC11110, m_sortedCutOffCells[bcId]->size(), noVars, "m_targetValuesBC11110", AT_);
16127 mAlloc(m_dirNBc11110, m_sortedCutOffCells[bcId]->size(), "m_dirNBc11110", AT_);
16128
16129 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); ++id) {
16130 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16131 MBool found = false;
16132 for(MInt dir = 0; dir < 2 * nDim; ++dir) {
16133 if(m_solver->a_hasNeighbor(cellId, dir) == 0) {
16134 m_dirNBc11110[id] = dir;
16135 found = true;
16136 break;
16137 }
16138 }
16139 if(!found) mTerm(1, AT_, "");
16140 }
16141
16142 MFloat zCoord = 0;
16143 IF_CONSTEXPR(nDim == 2) {
16155 zCoord = Context::getSolverProperty<MFloat>("zCoordFor2DInterpolation", m_solverId, AT_, &zCoord);
16156 }
16157
16158 // Coordinates need to be reorderd
16159 std::vector<std::vector<MFloat>> coords(3);
16160 for(MInt d = 0; d < 3; ++d)
16161 coords[d].resize(m_sortedCutOffCells[bcId]->size());
16162
16163 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); ++id) {
16164 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16165 for(MInt d = 0; d < nDim; ++d) {
16166 coords[d][id] = m_solver->a_coordinate(cellId, d);
16167 }
16168 }
16169 IF_CONSTEXPR(nDim == 2) {
16170 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); ++id) {
16171 // const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16172 coords[2][id] = zCoord;
16173 }
16174 }
16175
16176 // labels:FV hack, since prepareInterpolation takes C-type pointer to pointer as input argument
16177 MInt c_ = 0;
16178 std::vector<MFloat*> coords_ptr(nDim);
16179 for(auto& c_ptr : coords)
16180 coords_ptr[c_++] = c_ptr.data();
16181
16182 StructuredInterpolation<3>* structuredInterpolation =
16183 new StructuredInterpolation<3>(m_comm_bcCo[m_bcCo_comm_pointer[bcId]]);
16184 MInt temp[] = {m_sortedCutOffCells[bcId]->size(), 1, 1};
16185 structuredInterpolation->prepareInterpolationField(&temp[0], coords_ptr.data());
16186
16187 // pvariableNames saves the conversion between the naming of the primitive variables of the FvCartesianSolver and
16188 // the structured solver
16189 std::array<MString, /*solver->PV->noVariables*/ noVars> pvariableNames;
16190 pvariableNames[PV->U] = "u";
16191 pvariableNames[PV->V] = "v";
16192 IF_CONSTEXPR(nDim == 3) pvariableNames[PV->W] = "w";
16193 pvariableNames[PV->P] = "p";
16194 pvariableNames[PV->RHO] = "rho";
16195
16196 std::vector<MFloat> vars(m_sortedCutOffCells[bcId]->size());
16197 for(MInt var = 0; var < noVars /*solver->PV->noVariables*/; var++) {
16198 structuredInterpolation->interpolateField(pvariableNames[var], &vars[0]);
16199 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); ++id) {
16200 // const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16201 m_targetValuesBC11110[id][var] = vars[id];
16202 }
16203 }
16204
16205 m_firstUseBc11110 = false;
16206 }
16207 //---
16208 const MInt otherDir[6] = {1, 0, 3, 2, 5, 4};
16209
16210 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16211 const MInt dimN = (MInt)m_dirNBc11110[id] / 2;
16212 const MInt dir = (m_dirNBc11110[id] % 2) * 2 - 1;
16213
16214 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16215 const MInt nghbrId = m_solver->c_neighborId(cellId, otherDir[m_dirNBc11110[id]]);
16216
16217 // Determine if boundary is inflow or outflow
16218 const MBool isOutflow = (m_targetValuesBC11110[id][PV->VV[dimN]] * dir > 0) ? true : false;
16219
16220 if(isOutflow) {
16221 // set the density
16222 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
16223
16224 // set the velocities
16225 for(MInt i = 0; i < nDim; i++)
16226 m_solver->a_pvariable(cellId, PV->VV[i]) = m_solver->a_pvariable(nghbrId, PV->VV[i]);
16227
16228 // set the pressure
16229 m_solver->a_pvariable(cellId, PV->P) =
16230 F2 * m_targetValuesBC11110[id][PV->P] - m_solver->a_pvariable(nghbrId, PV->P);
16231 } else {
16232 // set the density
16233 m_solver->a_pvariable(cellId, PV->RHO) =
16234 F2 * m_targetValuesBC11110[id][PV->RHO] - m_solver->a_pvariable(nghbrId, PV->RHO);
16235
16236 // set the velocities
16237 for(MInt i = 0; i < nDim; i++)
16238 m_solver->a_pvariable(cellId, PV->VV[i]) =
16239 F2 * m_targetValuesBC11110[id][PV->VV[i]] - m_solver->a_pvariable(nghbrId, PV->VV[i]);
16240
16241 // set the pressure
16242 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
16243 }
16244 }
16245}
16246
16247
16248template <MInt nDim, class SysEqn>
16250 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc16010 is untested for 2D!"); }
16251 TRACE();
16252
16253 if(m_sortedCutOffCells[bcId]->size() == 0) {
16254 return;
16255 }
16256
16257 const MInt d = 0; // -x direction
16258 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16259 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16260
16261 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
16262 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
16263
16264 if(m_solver->checkNeighborActive(cellId, d)) {
16265 const MInt nghbrId = m_solver->c_neighborId(cellId, d);
16266 if(nghbrId < 0) {
16267 cutOffBcMissingNeighbor(cellId, "bc16010");
16268 } else {
16269 // set the velocities
16270 m_solver->a_pvariable(cellId, PV->U) = m_solver->a_pvariable(nghbrId, PV->U);
16271 m_solver->a_pvariable(cellId, PV->V) = m_solver->a_pvariable(nghbrId, PV->V);
16272 m_solver->a_pvariable(cellId, PV->W) = m_solver->a_pvariable(nghbrId, PV->W);
16273 // set the density
16274 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
16275 // set the pressure
16276 m_solver->a_pvariable(cellId, PV->P) = F2 * m_solver->m_PInfinity - m_solver->a_pvariable(nghbrId, PV->P);
16277
16278 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
16279 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
16280 m_solver->a_pvariable(cellId, PV->NN[r]) = m_solver->a_pvariable(nghbrId, PV->NN[r]);
16281 }
16282 }
16283 }
16284 } else {
16285 m_solver->a_pvariable(cellId, PV->U) = m_solver->m_UInfinity;
16286 m_solver->a_pvariable(cellId, PV->V) = m_solver->m_VInfinity;
16287 m_solver->a_pvariable(cellId, PV->W) = m_solver->m_WInfinity;
16288 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
16289 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
16290 }
16291
16292 // species
16293 for(MInt s = 0; s < m_noSpecies; s++) {
16294 m_solver->a_pvariable(cellId, PV->Y[s]) = F0;
16295 }
16296 }
16297}
16298
16304template <MInt nDim, class SysEqn>
16306 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc16011 is untested for 2D!"); }
16307 TRACE();
16308
16309 if(m_sortedCutOffCells[bcId]->size() == 0) {
16310 return;
16311 }
16312
16313 const MInt d = 1;
16314 // loop over all concerning cells
16315 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16316 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16317
16318 // set the velocities
16319 m_solver->a_pvariable(cellId, PV->U) = m_solver->m_UInfinity;
16320 m_solver->a_pvariable(cellId, PV->V) = m_solver->m_VInfinity;
16321 m_solver->a_pvariable(cellId, PV->W) = m_solver->m_WInfinity;
16322 // set the density
16323 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
16324
16325 if(m_solver->checkNeighborActive(cellId, d)) {
16326 const MInt nghbrId = m_solver->c_neighborId(cellId, d);
16327 if(nghbrId < 0) {
16328 cutOffBcMissingNeighbor(cellId, "bc16011");
16329 } else {
16330 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
16331 }
16332 } else {
16333 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
16334 }
16335
16336 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
16337 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
16338 m_solver->a_pvariable(cellId, PV->N) = m_solver->m_nuTildeInfinity;
16339 }
16340 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
16341 m_solver->a_pvariable(cellId, PV->K) = m_solver->m_kInfinity;
16342 m_solver->a_pvariable(cellId, PV->OMEGA) = m_solver->m_omegaInfinity;
16343 }
16344 }
16345
16346 // set the species
16347 for(MInt s = 0; s < m_noSpecies; s++)
16348 m_solver->a_pvariable(cellId, PV->Y[s]) = 1.0;
16349 }
16350}
16351
16357template <MInt nDim, class SysEqn>
16359 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc16012 is untested for 2D!"); }
16360 TRACE();
16361
16362 const MInt d = 3;
16363 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16364 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16365 const MInt nghbrId = m_solver->c_neighborId(cellId, d);
16366 if(nghbrId < 0) {
16367 cutOffBcMissingNeighbor(cellId, "bc16012");
16368 } else {
16369 // set the velocities
16370 m_solver->a_pvariable(cellId, PV->U) = m_solver->a_pvariable(nghbrId, PV->U);
16371 m_solver->a_pvariable(cellId, PV->V) = -m_solver->a_pvariable(nghbrId, PV->V);
16372 m_solver->a_pvariable(cellId, PV->W) = m_solver->a_pvariable(nghbrId, PV->W);
16373 // set the density
16374 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
16375 // set the density
16376 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
16377 // set the species
16378 for(MInt s = 0; s < m_noSpecies; s++)
16379 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->a_pvariable(nghbrId, PV->Y[s]);
16380 }
16381 }
16382}
16383
16389template <MInt nDim, class SysEqn>
16391 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc16013 is untested for 2D!"); }
16392 TRACE();
16393
16394 const MInt d = 2;
16395 // loop over all concerning cells
16396 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16397 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16398 const MInt nghbrId = m_solver->c_neighborId(cellId, d);
16399 if(nghbrId < 0) {
16400 cutOffBcMissingNeighbor(cellId, "bc16013");
16401 } else {
16402 // set the velocities
16403 m_solver->a_pvariable(cellId, PV->U) = m_solver->a_pvariable(nghbrId, PV->U);
16404 m_solver->a_pvariable(cellId, PV->V) = -m_solver->a_pvariable(nghbrId, PV->V);
16405 m_solver->a_pvariable(cellId, PV->W) = m_solver->a_pvariable(nghbrId, PV->W);
16406 // set the density
16407 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
16408 // set the density
16409 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
16410 // set the species
16411 for(MInt s = 0; s < m_noSpecies; s++)
16412 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->a_pvariable(nghbrId, PV->Y[s]);
16413 }
16414 }
16415}
16416
16422template <MInt nDim, class SysEqn>
16424 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc16014 is untested for 2D!"); }
16425 TRACE();
16426
16427 const MInt d = 5;
16428 // loop over all concerning cells
16429 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16430 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16431 const MInt nghbrId = m_solver->c_neighborId(cellId, d);
16432 if(nghbrId < 0) {
16433 cutOffBcMissingNeighbor(cellId, "bc16014");
16434 } else {
16435 // set the velocities
16436 m_solver->a_pvariable(cellId, PV->U) = m_solver->a_pvariable(nghbrId, PV->U);
16437 m_solver->a_pvariable(cellId, PV->V) = m_solver->a_pvariable(nghbrId, PV->V);
16438 m_solver->a_pvariable(cellId, PV->W) = -m_solver->a_pvariable(nghbrId, PV->W);
16439 // set the density
16440 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
16441 // set the density
16442 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
16443 // set the species
16444 for(MInt s = 0; s < m_noSpecies; s++)
16445 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->a_pvariable(nghbrId, PV->Y[s]);
16446 }
16447 }
16448}
16449
16455template <MInt nDim, class SysEqn>
16457 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function bc16015 is untested for 2D!"); }
16458 TRACE();
16459
16460 const MInt d = 4;
16461 // loop over all concerning cells
16462 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16463 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16464 const MInt nghbrId = m_solver->c_neighborId(cellId, d);
16465 if(nghbrId < 0) {
16466 cutOffBcMissingNeighbor(cellId, "bc16015");
16467 } else {
16468 // set the velocities
16469 m_solver->a_pvariable(cellId, PV->U) = m_solver->a_pvariable(nghbrId, PV->U);
16470 m_solver->a_pvariable(cellId, PV->V) = m_solver->a_pvariable(nghbrId, PV->V);
16471 m_solver->a_pvariable(cellId, PV->W) = -m_solver->a_pvariable(nghbrId, PV->W);
16472 // set the density
16473 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
16474 // set the density
16475 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
16476 // set the species
16477 for(MInt s = 0; s < m_noSpecies; s++)
16478 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->a_pvariable(nghbrId, PV->Y[s]);
16479 }
16480 }
16481}
16482
16483
16484// ----- ZONAL -----
16485template <MInt nDim, class SysEqn>
16486template <class _, std::enable_if_t<hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
16488 TRACE();
16489
16490 m_log << endl << "::bcInit7901: ..." << endl;
16491
16492 const MFloat eps = 1e-08;
16493
16494 m_7901faceNormalDir = 0;
16495 m_7901wallDir = 1;
16496 m_7901periodicDir = 2;
16497 if(Context::propertyExists("bc7901faceNormalDir")) {
16498 m_7901faceNormalDir = Context::getSolverProperty<MInt>("bc7901faceNormalDir", m_solverId, AT_);
16499 }
16500 if(Context::propertyExists("bc7901wallDir")) {
16501 m_7901wallDir = Context::getSolverProperty<MInt>("bc7901wallDir", m_solverId, AT_);
16502 }
16503 if(Context::propertyExists("bc7901periodicDir")) {
16504 m_7901periodicDir = Context::getSolverProperty<MInt>("bc7901periodicDir", m_solverId, AT_);
16505 }
16506
16507 m_7901StartTimeStep = m_solver->m_stgStartTimeStep;
16508
16509 // Prepare the exchange cells for zonal RANS-LES method
16510 MInt noBc7901Cells = 0;
16511 MInt noBc7901Locations = 0;
16512 MFloat periodicL = 0;
16513 MBool first = true;
16514
16515 // m_7901BcCells.clear();
16516 m_7901wallNormalLocations.clear();
16517
16518 // ======================================================
16519 // 1) Determine m_7901BcCells
16520 // ======================================================
16521 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16522 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16523 MFloat halfCellLength = m_solver->grid().halfCellLength(cellId);
16524 if(first) {
16525 periodicL = m_solver->a_coordinate(cellId, m_7901periodicDir);
16526 // cerr << m_solver->domainId() << " " << cellId << ": " << periodicL << endl;
16527 first = false;
16528 }
16529
16530 if(abs(m_solver->a_coordinate(cellId, m_7901periodicDir) + halfCellLength - eps - periodicL) < halfCellLength) {
16531 // m_7901BcCells.push_back(cellId);
16532 m_7901wallNormalLocations.push_back(m_solver->a_coordinate(cellId, m_7901wallDir));
16533 noBc7901Locations++;
16534 }
16535 noBc7901Cells++;
16536 }
16537
16538 // if not involved, exit
16539 if(noBc7901Cells == 0) return;
16540
16541 /* // ====================================================== */
16542 /* // 2) Create communicator for bc7901 from m_comm_bcCo[m_bcCo_comm_pointer[bcId]] communicator */
16543 /* // ====================================================== */
16544 /* m_log << " + ... building reconstructNut communicator ..." << endl; */
16545
16546 /* const MPI_Comm& comm7901 = m_comm_bcCo[m_bcCo_comm_pointer[bcId]]; */
16547 /* MInt comm_size; */
16548 /* MPI_Comm_size(comm7901, &comm_size); */
16549 /* MInt* rntRanks = new MInt[comm_size]; */
16550 /* MInt myRntRank = m_solver->domainId(); */
16551
16552 /* /\* MPI_Allgather(&noBc7901Cells, 1, MPI_INT, bc7901CellsperDomain, 1, MPI_INT, *\/ */
16553 /* /\* m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_, "noBc7901Cells ", "bc7901CellsperDomain" ); *\/ */
16554 /* MPI_Allgather(&myRntRank, 1, MPI_INT, rntRanks, 1, MPI_INT, */
16555 /* comm7901, AT_, "myRntRank", "rntRanks" ); */
16556
16557 /* MInt rntRoot = rntRanks[0]; */
16558 /* MInt myCommRank = 0; */
16559 /* for(MInt r = 0; r < comm_size; r++){ */
16560 /* if(myRntRank == rntRanks[r]){ */
16561 /* myCommRank = r; */
16562 /* break; */
16563 /* } */
16564 /* } */
16565
16566 /* //cerr << myRntRank << " " << myCommRank << ": " << noBc7901Locations << endl; */
16567
16568 /* // ====================================================== */
16569 /* // 3) Determine global locations in wall-normal direction for spanwise average */
16570 /* // ====================================================== */
16571 /* MInt globalNoBc7901Locations = 0; */
16572
16573 /* MPI_Allreduce(&noBc7901Locations, &globalNoBc7901Locations, 1, */
16574 /* MPI_INT, MPI_SUM, comm7901, */
16575 /* AT_, "noBc7901Locations", "globalNoBc7901Locations"); */
16576
16577 /* ScratchSpace<MFloat> globalBc7901Locations(globalNoBc7901Locations, "globalBc7901Locations", FUN_); */
16578
16579 /* ScratchSpace<MInt> recvbuf( comm_size, "recvbuf", FUN_); */
16580 /* recvbuf.fill(0); */
16581
16582 /* MPI_Gather(&noBc7901Locations, 1, MPI_INT, */
16583 /* &recvbuf[0], 1, MPI_INT, 0, comm7901 , */
16584 /* AT_, "noBc7901Locations", "recvbuf" ); */
16585
16586 /* ScratchSpace<MInt> displs( comm_size, "displspos", FUN_); */
16587 /* if(myRntRank == rntRoot){ */
16588 /* MInt offset = 0; */
16589 /* for (MInt dom = 0; dom < comm_size; dom ++){ */
16590 /* displs[dom] = offset; */
16591 /* offset += recvbuf[dom]; */
16592 /* } */
16593 /* } */
16594
16595 /* MPI_Gatherv(&m_7901wallNormalLocations[0], noBc7901Locations, MPI_DOUBLE, */
16596 /* &globalBc7901Locations[0], &recvbuf[myCommRank], &displs[myCommRank], MPI_DOUBLE, */
16597 /* 0, comm7901, AT_, "m_7901wallNormalLocations", "globalBc7901Locations" ); */
16598
16599 /* MPI_Bcast(&globalBc7901Locations[0], globalNoBc7901Locations, */
16600 /* MPI_DOUBLE, 0, comm7901, AT_, "globalBc7901Locations" ); */
16601
16602 /* m_7901globalWallNormalLocations.clear(); */
16603
16604 /* for(MInt i = 0; i < globalNoBc7901Locations; i++){ */
16605 /* MFloat L = globalBc7901Locations[i]; */
16606 /* if(std::find(m_7901globalWallNormalLocations.begin(), m_7901globalWallNormalLocations.end(), L) ==
16607 * m_7901globalWallNormalLocations.end()) { */
16608 /* m_7901globalWallNormalLocations.push_back(L); */
16609 /* } */
16610 /* } */
16611
16612 /* m_7901globalNoWallNormalLocations = (MInt)m_7901globalWallNormalLocations.size(); */
16613
16614 /* std::sort(m_7901globalWallNormalLocations.begin(), */
16615 /* m_7901globalWallNormalLocations.end()); */
16616
16617 /* /\* if(myRntRank == rntRoot){ *\/ */
16618 /* /\* cerr << "----------------------------" << endl; *\/ */
16619 /* /\* cerr << m_7901globalNoWallNormalLocations << ": " << m_7901globalNoWallNormalLocations << endl; *\/ */
16620 /* /\* for(MInt i = 0; i < m_7901globalNoWallNormalLocations; i++){ *\/ */
16621 /* /\* cerr << m_7901globalWallNormalLocations[i] << endl; *\/ */
16622 /* /\* } *\/ */
16623 /* /\* } *\/ */
16624
16625
16626 /* // ====================================================== */
16627 /* // 4) Determine local cells in periodic locations of global wall-normal locations */
16628 /* // ====================================================== */
16629 /* mAlloc(m_7901periodicLocations, m_7901globalNoWallNormalLocations, */
16630 /* "m_7901periodicLocations", FUN_); */
16631
16632 /* mAlloc(m_7901globalNoPeriodicLocations, m_7901globalNoWallNormalLocations, */
16633 /* "m_7901globalNoPeriodicLocations", 0, FUN_); */
16634
16635 /* for(MInt i = 0; i < m_7901globalNoWallNormalLocations; i++){ */
16636 /* m_7901periodicLocations[i].clear(); */
16637 /* } */
16638
16639 /* mAlloc(m_7901periodicIndex, noBc7901Cells, "m_7901periodicIndex", FUN_); */
16640
16641 /* vector<MInt> noPeriodicLocations (m_7901globalNoWallNormalLocations, F0); */
16642
16643 /* for(MInt i = 0; i < m_7901globalNoWallNormalLocations; i++){ */
16644 /* //MInt count = 0; */
16645 /* for( MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++ ){ */
16646 /* MInt cellId = m_sortedCutOffCells[bcId]->a[id]; */
16647 /* if(abs(m_solver->a_coordinate(cellId,m_7901wallDir)-m_7901globalWallNormalLocations[i]) */
16648 /* < eps){ */
16649 /* m_7901periodicIndex[id] = i; */
16650 /* if(!m_solver->a_isHalo(cellId)){ */
16651 /* m_7901periodicLocations[i].push_back(cellId); */
16652 /* ++noPeriodicLocations[i]; */
16653 /* } */
16654 /* } */
16655 /* } */
16656 /* } */
16657
16658 /* MPI_Allreduce(&noPeriodicLocations[0], &m_7901globalNoPeriodicLocations[0], */
16659 /* m_7901globalNoWallNormalLocations, MPI_INT, MPI_SUM, comm7901, AT_, */
16660 /* "7901noPeriodicLocations", "m_7901globalNoPeriodicLocations"); */
16661
16662 /* // ====================================================== */
16663 /* // 5) Init spanwise average */
16664 /* // ====================================================== */
16665 /* //mAlloc(m_7901LESAverageOld, PV->noVariables, m_7901globalNoWallNormalLocations, "m_7901LESAverageOld",
16666 * F0, FUN_); */
16667 /* mAlloc(m_7901LESAverage, PV->noVariables, m_7901globalNoWallNormalLocations, "m_7901LESAverage", F0,
16668 * FUN_); */
16669
16670
16671 //========================================================================
16672
16673 // MInt noBc7901Cells = m_sortedCutOffCells[bcId]->size();
16674
16675 /* mAlloc(m_7901LESAverage, PV->noVariables, "m_7901LESAverage", FUN_); */
16676
16677 /* for(MInt var = 0; var < PV->noVariables; var++){ */
16678 /* m_7901LESAverage[var].clear(); */
16679 /* } */
16680
16681 /* for(MInt var = 0; var < PV->noVariables; var++){ */
16682 /* for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++){ */
16683 /* MInt cellId = m_sortedCutOffCells[bcId]->a[id]; */
16684 /* m_7901LESAverage[var].push_back(m_solver->m_LESVarAverage[var][cellId]); */
16685 /* } */
16686 /* } */
16687
16688 /* m_7901StartTimeStep = Context::getSolverProperty<MInt>("7901StartTimeStep", m_solver->m_solverId, AT_,
16689 * &m_7901StartTimeStep); */
16690
16691
16692 m_log << "::bcInit7901: ... FINISHED" << endl;
16693}
16694
16695template <MInt nDim, class SysEqn>
16696template <class _, std::enable_if_t<hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
16698 TRACE();
16699
16700 m_log << endl << "::bcInit7902: ..." << endl;
16701
16702 const MFloat eps = 1e-08;
16703
16704 m_7902faceNormalDir = 1;
16705 m_7902wallDir = 1;
16706 m_7902periodicDir = 2;
16707 if(Context::propertyExists("bc7902faceNormalDir")) {
16708 m_7902faceNormalDir = Context::getSolverProperty<MInt>("bc7902faceNormalDir", m_solverId, AT_);
16709 }
16710 if(Context::propertyExists("bc7902wallDir")) {
16711 m_7902wallDir = Context::getSolverProperty<MInt>("bc7902wallDir", m_solverId, AT_);
16712 }
16713 if(Context::propertyExists("bc7902periodicDir")) {
16714 m_7902periodicDir = Context::getSolverProperty<MInt>("bc7902periodicDir", m_solverId, AT_);
16715 }
16716
16717 m_7902StartTimeStep = m_solver->m_rntStartTimeStep;
16718
16719 // Prepare the exchange cells for zonal RANS-LES method
16720 MInt noBc7902Cells = 0;
16721 MInt noBc7902Locations = 0;
16722 MFloat periodicL = 0;
16723 MBool first = true;
16724
16725 // m_7902BcCells.clear();
16726 m_7902wallNormalLocations.clear();
16727
16728 // ======================================================
16729 // 1) Determine m_7902BcCells
16730 // ======================================================
16731 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16732 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16733 MFloat halfCellLength = m_solver->grid().halfCellLength(cellId);
16734 if(first) {
16735 periodicL = m_solver->a_coordinate(cellId, m_7902periodicDir);
16736 // cerr << m_solver->domainId() << " " << cellId << ": " << periodicL << endl;
16737 first = false;
16738 }
16739
16740 if(abs(m_solver->a_coordinate(cellId, m_7902periodicDir) + halfCellLength - eps - periodicL) < halfCellLength) {
16741 // m_7902BcCells.push_back(cellId);
16742 m_7902wallNormalLocations.push_back(m_solver->a_coordinate(cellId, m_7902wallDir));
16743 noBc7902Locations++;
16744 }
16745 noBc7902Cells++;
16746 }
16747
16748 // if not involved, exit
16749 if(noBc7902Cells == 0) return;
16750
16751 // ======================================================
16752 // 2) Create communicator for bc7902 from m_comm_bcCo[m_bcCo_comm_pointer[bcId]] communicator
16753 // ======================================================
16754 m_log << " + ... building reconstructNut communicator ..." << endl;
16755
16756 const MPI_Comm& comm7902 = m_comm_bcCo[m_bcCo_comm_pointer[bcId]];
16757 MInt comm_size;
16758 MPI_Comm_size(comm7902, &comm_size);
16759 MInt* rntRanks = new MInt[comm_size];
16760 MInt myRntRank = m_solver->domainId();
16761
16762 /* MPI_Allgather(&noBc7902Cells, 1, MPI_INT, bc7902CellsperDomain, 1, MPI_INT, */
16763 /* m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_, "noBc7902Cells ", "bc7902CellsperDomain" ); */
16764 if(comm_size > 0) {
16765 MPI_Allgather(&myRntRank, 1, MPI_INT, rntRanks, 1, MPI_INT, comm7902, AT_, "myRntRank", "rntRanks");
16766 }
16767
16768 MInt rntRoot = rntRanks[0];
16769 MInt myCommRank = 0;
16770 for(MInt r = 0; r < comm_size; r++) {
16771 if(myRntRank == rntRanks[r]) {
16772 myCommRank = r;
16773 break;
16774 }
16775 }
16776
16777 m_rntRoot = rntRanks[0];
16778
16779 // ======================================================
16780 // 3) Determine global locations in wall-normal direction for spanwise average
16781 // ======================================================
16782 MInt globalNoBc7902Locations = 0;
16783
16784 if(comm_size > 0) {
16785 MPI_Allreduce(&noBc7902Locations, &globalNoBc7902Locations, 1, MPI_INT, MPI_SUM, comm7902, AT_, "noBc7902Locations",
16786 "globalNoBc7902Locations");
16787 } else {
16788 globalNoBc7902Locations = noBc7902Locations;
16789 }
16790
16791 ScratchSpace<MFloat> globalBc7902Locations(globalNoBc7902Locations, "globalBc7902Locations", FUN_);
16792
16793 if(comm_size > 0) {
16794 ScratchSpace<MInt> recvbuf(comm_size, "recvbuf", FUN_);
16795 recvbuf.fill(0);
16796
16797 MPI_Gather(&noBc7902Locations, 1, MPI_INT, &recvbuf[0], 1, MPI_INT, 0, comm7902, AT_, "noBc7902Locations",
16798 "recvbuf");
16799
16800
16801 ScratchSpace<MInt> displs(comm_size, "displspos", FUN_);
16802 if(myRntRank == rntRoot) {
16803 MInt offset = 0;
16804 for(MInt dom = 0; dom < comm_size; dom++) {
16805 displs[dom] = offset;
16806 offset += recvbuf[dom];
16807 }
16808 }
16809
16810 MPI_Gatherv(&m_7902wallNormalLocations[0], noBc7902Locations, MPI_DOUBLE, &globalBc7902Locations[0],
16811 &recvbuf[myCommRank], &displs[myCommRank], MPI_DOUBLE, 0, comm7902, AT_, "m_7902wallNormalLocations",
16812 "globalBc7902Locations");
16813
16814 MPI_Bcast(&globalBc7902Locations[0], globalNoBc7902Locations, MPI_DOUBLE, 0, comm7902, AT_,
16815 "globalBc7902Locations");
16816
16817 m_7902globalWallNormalLocations.clear();
16818
16819 for(MInt i = 0; i < globalNoBc7902Locations; i++) {
16820 MFloat L = globalBc7902Locations[i];
16821 if(std::find(m_7902globalWallNormalLocations.begin(), m_7902globalWallNormalLocations.end(), L)
16822 == m_7902globalWallNormalLocations.end()) {
16823 m_7902globalWallNormalLocations.push_back(L);
16824 }
16825 }
16826
16827 } else {
16828 for(MInt i = 0; i < globalNoBc7902Locations; i++) {
16829 MFloat L = m_7902wallNormalLocations[i];
16830 if(std::find(m_7902globalWallNormalLocations.begin(), m_7902globalWallNormalLocations.end(), L)
16831 == m_7902globalWallNormalLocations.end()) {
16832 m_7902globalWallNormalLocations.push_back(L);
16833 }
16834 }
16835 }
16836
16837 m_7902globalNoWallNormalLocations = (MInt)m_7902globalWallNormalLocations.size();
16838
16839 std::sort(m_7902globalWallNormalLocations.begin(), m_7902globalWallNormalLocations.end());
16840
16841 // ======================================================
16842 // 4) Determine local cells in periodic locations of global wall-normal locations
16843 // ======================================================
16844 mAlloc(m_7902periodicLocations, m_7902globalNoWallNormalLocations, "m_7902periodicLocations", FUN_);
16845
16846 mAlloc(m_7902globalNoPeriodicLocations, m_7902globalNoWallNormalLocations, "m_7902globalNoPeriodicLocations", 0,
16847 FUN_);
16848
16849 for(MInt i = 0; i < m_7902globalNoWallNormalLocations; i++) {
16850 m_7902periodicLocations[i].clear();
16851 }
16852
16853 mAlloc(m_7902periodicIndex, noBc7902Cells, "m_7902periodicIndex", FUN_);
16854
16855 vector<MInt> noPeriodicLocations(m_7902globalNoWallNormalLocations, F0);
16856
16857 for(MInt i = 0; i < m_7902globalNoWallNormalLocations; i++) {
16858 // MInt count = 0;
16859 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16860 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
16861 if(abs(m_solver->a_coordinate(cellId, m_7902wallDir) - m_7902globalWallNormalLocations[i]) < eps) {
16862 m_7902periodicIndex[id] = i;
16863 if(!m_solver->a_isHalo(cellId)) {
16864 m_7902periodicLocations[i].push_back(cellId);
16865 ++noPeriodicLocations[i];
16866 }
16867 }
16868 }
16869 }
16870
16871 if(comm_size > 0) {
16872 MPI_Allreduce(&noPeriodicLocations[0], &m_7902globalNoPeriodicLocations[0], m_7902globalNoWallNormalLocations,
16873 MPI_INT, MPI_SUM, comm7902, AT_, "7902noPeriodicLocations", "m_7902globalNoPeriodicLocations");
16874 }
16875
16876
16877 // ======================================================
16878 // 5) Init spanwise average
16879 // ======================================================
16880 mAlloc(m_7902LESAverage, PV->noVariables, m_7902globalNoWallNormalLocations, "m_7902LESAverage", F0, FUN_);
16881
16882 for(MInt var = 0; var < PV->noVariables; var++) {
16883 for(MInt i = 0; i < m_7902globalNoWallNormalLocations; i++) {
16884 for(MInt p = 0; p < (MInt)m_7902periodicLocations[i].size(); p++) {
16885 MInt cellId = m_7902periodicLocations[i][p];
16886 m_7902LESAverage[var][i] += m_solver->a_pvariable(cellId, var) / m_7902globalNoPeriodicLocations[i];
16887 }
16888 }
16889 }
16890
16891
16892 for(MInt var = 0; var < PV->noVariables; var++) {
16893 if(comm_size > 0) {
16894 MPI_Allreduce(MPI_IN_PLACE, m_7902LESAverage[var], m_7902globalNoWallNormalLocations, MPI_DOUBLE, MPI_SUM,
16895 m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_, "MPI_IN_PLACE", "m_7902LESAverage");
16896 }
16897 }
16898
16899 m_log << "::bcInit7902: ... FINISHED" << endl;
16900}
16901
16902
16903template <MInt nDim, class SysEqn>
16904template <class _, std::enable_if_t<hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
16906 TRACE();
16907
16908 m_log << endl << "::bcInit7905: ..." << endl;
16909
16910 m_7902faceNormalDir = 1;
16911 m_7902wallDir = 1;
16912 m_7902periodicDir = 2;
16913 if(Context::propertyExists("bc7902faceNormalDir")) {
16914 m_7902faceNormalDir = Context::getSolverProperty<MInt>("bc7902faceNormalDir", m_solverId, AT_);
16915 }
16916 if(Context::propertyExists("bc7902wallDir")) {
16917 m_7902wallDir = Context::getSolverProperty<MInt>("bc7902wallDir", m_solverId, AT_);
16918 }
16919 if(Context::propertyExists("bc7902periodicDir")) {
16920 m_7902periodicDir = Context::getSolverProperty<MInt>("bc7902periodicDir", m_solverId, AT_);
16921 }
16922
16923 m_7902StartTimeStep = m_solver->m_rntStartTimeStep;
16924
16925 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
16926 }
16927
16928 m_log << "::bcInit7902: ... FINISHED" << endl;
16929}
16930
16931
16932template <MInt nDim, class SysEqn>
16933template <class _, std::enable_if_t<!hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
16935 TRACE();
16936
16937 m_log << endl << "::bcInit:" + to_string(m_bndryCndIds[bcId]) + " ..." << endl;
16938
16939 m_startSTGTimeStep = Context::getSolverProperty<MInt>("startSTGTimeStep", m_solverId, AT_, &m_startSTGTimeStep);
16940
16941 IF_CONSTEXPR(!isEEGas<SysEqn> && !isDetChem<SysEqn>) {
16942 /*
16943 0) Check if stg is active
16944 1) Loop over all boundary cells;
16945 Skip cells if !IsOnCurrentMGLevel;
16946 Check if cell has multiple ghost cells;
16947 Save cells participating in stg and pass them later to MSTG constructor;
16948 Mark if current rank has cells involved in current stg
16949 2) Create communicator for bc7909 from m_comm_bc[m_bc_comm_pointer[bcId]] communicator
16950 --> ranks which have no STG cells return
16951 3) Determine normal to STG boundary (by now only +x and -x allowed);
16952 Determine y-coordinate of adjacent solid wall (assume wall with constant y in spanwise
16953 direction); Determine normal pointing from the solid wall to the domain;
16954 y-coordinate of adjacent wall is the closest one, from those read in by a property;
16955 4) Create MSTG object
16956 */
16957
16958 // ======================================================
16959 // 0) Check if stg is active
16960 // ======================================================
16961 if(!m_solver->m_stgIsActive) TERMM(1, "m_stgIsActive=false but BC 7909, 7910, ... exists!");
16962
16963 // ======================================================
16964 // 1) Loop over all boundary cells;
16965 // Skip cells if !IsOnCurrentMGLevel;
16966 // Check if cell has multiple ghost cells;
16967 // Save cells participating in stg and pass them later to MSTG constructor
16968 // Mark if current rank has cells involved in current stg
16969 // ======================================================
16970 ScratchSpace<MInt> stgBcCells(m_bndryCndCells[bcId + 1] - m_bndryCndCells[bcId], AT_, "stgBcCells");
16971
16972 MInt noBc7909Cells = 0;
16973 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
16974 const MInt bndryId = m_sortedBndryCells->a[id];
16975 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
16976
16977 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
16978 if(m_bndryCells->a[bndryId].m_noSrfcs > 1) {
16979 mTerm(1, AT_, "Multiple ghost cells by now not supported by STG!");
16980 }
16981 stgBcCells[noBc7909Cells++] = cellId;
16982 m_stgBcCells.push_back(cellId);
16983 }
16984 }
16985
16986 m_stgLocal[bcId] = noBc7909Cells > 0;
16987
16988#ifndef NDEBUG
16989 if(!m_stgLocal[bcId]) {
16990 cout << "RANK " << m_solver->domainId() << " has no 7909 cells, although it was entering bcInit7909 " << endl;
16991 }
16992#endif
16993
16994 // ======================================================
16995 // 2) Create communicator for bc7909 from m_comm_bc[m_bc_comm_pointer[bcId]] communicator
16996 // ======================================================
16997 m_log << "::bcInit" + to_string(m_bndryCndIds[bcId]) + ": ... building stg communicator ..." << endl;
16998 const MPI_Comm& comm7909 = m_comm_bc[m_bc_comm_pointer[bcId]];
16999 MInt comm_size;
17000 MPI_Comm_size(comm7909, &comm_size);
17001 MInt* bc7909CellsperDomain = new MInt[comm_size];
17002 MInt* stgRanks = new MInt[comm_size];
17003 MInt myStgRank = m_solver->domainId();
17004
17005 if(noDomains() > 1) {
17006 MPI_Allgather(&noBc7909Cells, 1, MPI_INT, bc7909CellsperDomain, 1, MPI_INT, comm7909, AT_, "noBc7909Cells ",
17007 "bc7909CellsperDomain");
17008 MPI_Allgather(&myStgRank, 1, MPI_INT, stgRanks, 1, MPI_INT, comm7909, AT_, "myStgRank", "stgRanks");
17009 }
17010
17011 MInt noInvolvedRanks = 0;
17012 MInt* involvedRanks = new MInt[comm_size];
17013 for(MInt i = 0; i < comm_size; i++) {
17014 if(bc7909CellsperDomain[i]) {
17015 involvedRanks[noInvolvedRanks] = i;
17016 ++noInvolvedRanks;
17017 }
17018 }
17019
17020 MPI_Comm commStg;
17021 MPI_Group group, groupStg;
17022 MPI_Comm_group(comm7909, &group, AT_, "group");
17023 MPI_Group_incl(group, noInvolvedRanks, involvedRanks, &groupStg, AT_);
17024
17025 MPI_Comm_create(comm7909, groupStg, &commStg, AT_, "commStg");
17026 m_commStg = commStg;
17027
17028 // if not involved, exit
17029 if(!noBc7909Cells) return;
17030
17031 // ======================================================
17032 // 3) Determine normal to STG boundary
17033 // Determine normal pointing from the solid wall to the domain;
17034 // ======================================================
17035
17036 // JANNIK:change this for cylinder transformation
17037
17038 static constexpr const MFloat eps = 1e-8;
17039 std::vector<MInt> faces = {0, 0, 0, 0, 0, 0};
17040 for(MInt i = 0; i < noBc7909Cells; ++i) {
17041 const MInt cellId = stgBcCells[i];
17042 const MInt bndryId = m_solver->a_bndryId(cellId);
17043 const MFloat* const n = &m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0];
17044 if(abs(n[0] - 1.0) < eps)
17045 ++faces[0];
17046 else if(abs(n[0] + 1.0) < eps)
17047 ++faces[1];
17048 else if(abs(n[1] - 1.0) < eps)
17049 ++faces[2];
17050 else if(abs(n[1] + 1.0) < eps)
17051 ++faces[3];
17052 else if(abs(n[2] - 1.0) < eps)
17053 ++faces[4];
17054 else if(abs(n[2] + 1.0) < eps)
17055 ++faces[5];
17056 }
17057
17058 const MInt stgFaceNormalDir = std::max_element(faces.begin(), faces.end()) - faces.begin();
17059 for(MInt i = 0; i < 2 * nDim; i++) {
17060 if(i != stgFaceNormalDir) {
17061 if(faces[i] != 0) mTerm(1, AT_, "Something went wrong, STG plane is only allowed in one direction!");
17062 }
17063 }
17064
17065 MInt stgDir = stgFaceNormalDir;
17066 if(noDomains() > 1) {
17067 MPI_Allreduce(&stgFaceNormalDir, &stgDir, 1, MPI_INT, MPI_MIN, comm7909, AT_, "dirN", "stgDir");
17068 }
17069 // Sanity check: check if all ranks of STG have normal direction
17070 if(stgFaceNormalDir != stgDir) {
17071 mTerm(1, AT_, "Something went wrong, STG plane is only allowed in one direction!");
17072 } else {
17073 stgDir = stgFaceNormalDir / 2;
17074 }
17075
17076 MInt stgWallNormalDir = 3;
17077 MInt noCoords_ = Context::propertyLength("stgWallNormalDir");
17078 for(MInt i = 0; i < noCoords_; i++) {
17079 if(m_bndryCndIds[bcId] == 7909 + i) {
17080 stgWallNormalDir = Context::getBasicProperty<MFloat>("stgWallNormalDir", AT_, i);
17081 }
17082 }
17083
17084 MInt wallDir = stgWallNormalDir / 2;
17085
17086 // ======================================================
17087 // 4) Create MSTG object
17088 // ======================================================
17089 m_log << "::bcInit7909: ... creating MSTG object ..." << endl;
17090
17091 switch(string2enum(m_solver->m_bc7909RANSSolverType)) {
17092 case MAIA_FINITE_VOLUME: {
17093 // TODO labels:FV don't forget to delete the objects later
17096 m_bndryCndIds[bcId],
17097 commStg,
17098 &stgBcCells[0],
17099 noBc7909Cells,
17100 stgFaceNormalDir,
17101 stgDir,
17102 stgWallNormalDir,
17103 wallDir,
17104 false);
17105
17106 m_log << "::bcInit" + to_string(m_bndryCndIds[bcId]) + ": ... creating MSTG object finished..." << endl;
17107 stgBC->init(0);
17108 m_stgBC.insert(std::pair<MInt, MSTG<nDim, MAIA_FINITE_VOLUME, MAIA_FINITE_VOLUME>*>(bcId, stgBC));
17109 break;
17110 }
17111 case MAIA_STRUCTURED: {
17112 // TODO labels:FV don't forget to delete the objects later
17114 // stgBC = static_cast<MSTGInterface<nDim>*>(
17116 m_bndryCndIds[bcId],
17117 commStg,
17118 &stgBcCells[0],
17119 noBc7909Cells,
17120 stgFaceNormalDir,
17121 stgDir,
17122 stgWallNormalDir,
17123 wallDir,
17124 false);
17125
17126 m_log << "::bcInit" + to_string(m_bndryCndIds[bcId]) + ": ... creating MSTG object finished..." << endl;
17127 stgBCStrcd->init(0);
17128 m_stgBCStrcd.insert(std::pair<MInt, MSTG<nDim, MAIA_STRUCTURED, MAIA_FINITE_VOLUME>*>(bcId, stgBCStrcd));
17129 break;
17130 }
17131 default:
17132 mTerm(1, AT_, "Not yet implemented for solver " + m_solver->m_bc7909RANSSolverType);
17133 }
17134
17135 m_log << "::bcInit7909: ... FINISHED" << endl;
17136 }
17137}
17138
17139
17140template <MInt nDim, class SysEqn>
17141template <class _, std::enable_if_t<!hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
17143 TRACE();
17144
17145 m_log << endl << "::bcInit:" + to_string(m_cutOffBndryCndIds[bcId]) + " ..." << endl;
17146 m_startSTGTimeStep = Context::getSolverProperty<MInt>("startSTGTimeStep", m_solverId, AT_, &m_startSTGTimeStep);
17147
17148 IF_CONSTEXPR(!isEEGas<SysEqn> && !isDetChem<SysEqn>) {
17149 /*
17150 0) Check if stg is active
17151 1) Loop over all boundary cells;
17152 Skip cells if !IsOnCurrentMGLevel;
17153 Check if cell has multiple ghost cells;
17154 Save cells participating in stg and pass them later to STG constructor;
17155 Mark if current rank has cells involved in current stg
17156 2) Create communicator for bc7909 from m_comm_bc[m_bc_comm_pointer[bcId]] communicator
17157 --> ranks which have no STG cells return
17158 3) Determine normal to STG boundary (by now only +x and -x allowed);
17159 Determine y-coordinate of adjacent solid wall (assume wall with constant y in spanwise
17160 direction); Determine normal pointing from the solid wall to the domain;
17161 y-coordinate of adjacent wall is the closest one, from those read in by a property;
17162 4) Create STG object
17163 */
17164
17165 // ======================================================
17166 // 0) Check if stg is active
17167 // ======================================================
17168 if(!m_solver->m_stgIsActive) return; // TERMM(1, "m_stgIsActive=false but CBC 7909, 7910, ... exists!");
17169
17170
17171 // ======================================================
17172 // 1) Loop over all boundary cells;
17173 // Skip cells if !IsOnCurrentMGLevel;
17174 // Check if cell has multiple ghost cells;
17175 // Save cells participating in stg and pass them later to STG constructor
17176 // Mark if current rank has cells involved in current stg
17177 // ======================================================
17178 ScratchSpace<MInt> stgBcCells(m_sortedCutOffCells[bcId]->size(), AT_, "stgBcCells");
17179
17180 MInt noBc7909Cells = 0;
17181 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17182 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
17183 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17184 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
17185 stgBcCells[noBc7909Cells++] = cellId;
17186 m_stgBcCells.push_back(cellId);
17187 }
17188 }
17189
17190 m_stgLocal[bcId] = noBc7909Cells > 0;
17191
17192 // if not involved, exit
17193 if(!(noBc7909Cells > 0)) return;
17194
17195#ifndef NDEBUG
17196 if(!m_stgLocal[bcId]) {
17197 cout << "RANK " << m_solver->domainId() << " has no 7909 cells, although it was entering cbcInit7909 " << endl;
17198 }
17199#endif
17200
17201 // ======================================================
17202 // 2) Create communicator for bc7909 from m_comm_bcCo[m_bcCo_comm_pointer[bcId]] communicator
17203 // ======================================================
17204 m_log << "::bcInit" + to_string(m_cutOffBndryCndIds[bcId]) + ": ... building stg communicator ..." << endl;
17205 const MPI_Comm& comm7909 = m_comm_bcCo[m_bcCo_comm_pointer[bcId]];
17206 MInt comm_size;
17207 MPI_Comm_size(comm7909, &comm_size);
17208 MInt* bc7909CellsperDomain = new MInt[comm_size];
17209 MInt* stgRanks = new MInt[comm_size];
17210 MInt myStgRank = m_solver->domainId();
17211
17212 if(noDomains() > 1) {
17213 MPI_Allgather(&noBc7909Cells, 1, MPI_INT, bc7909CellsperDomain, 1, MPI_INT, comm7909, AT_, "noBc7909Cells ",
17214 "bc7909CellsperDomain");
17215 MPI_Allgather(&myStgRank, 1, MPI_INT, stgRanks, 1, MPI_INT, comm7909, AT_, "myStgRank", "stgRanks");
17216 }
17217
17218 MInt noInvolvedRanks = 0;
17219 MInt* involvedRanks = new MInt[comm_size];
17220 for(MInt i = 0; i < comm_size; i++) {
17221 if(bc7909CellsperDomain[i]) {
17222 involvedRanks[noInvolvedRanks] = i;
17223 ++noInvolvedRanks;
17224 }
17225 }
17226
17227 MPI_Comm commStg;
17228 MPI_Group group, groupStg;
17229 MPI_Comm_group(comm7909, &group, AT_, "group");
17230 MPI_Group_incl(group, noInvolvedRanks, involvedRanks, &groupStg, AT_);
17231
17232 MPI_Comm_create(comm7909, groupStg, &commStg, AT_, "commStg");
17233 m_commStg = commStg;
17234
17235 // ======================================================
17236 // 3) Determine normal to STG boundary
17237 // Determine normal pointing from the solid wall to the domain;
17238 // ======================================================
17239
17240 // JANNIK:change this for cylinder transformation
17241
17242 // static constexpr const MFloat eps = 1e-8;
17243 std::vector<MInt> faces = {0, 0, 0, 0, 0, 0};
17244 for(MInt i = 0; i < noBc7909Cells; ++i) {
17245 const MInt cellId = stgBcCells[i];
17246
17247 for(MInt d = 0; d < 2 * nDim; d++) {
17248 if(!m_solver->a_hasNeighbor(cellId, d, false)) {
17249 ++faces[d];
17250 }
17251 }
17252
17253 // const MFloat* const n = &m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0];
17254 // if(abs(n[0] - 1.0) < eps)
17255 // ++faces[0];
17256 // else if(abs(n[0] + 1.0) < eps)
17257 // ++faces[1];
17258 // else if(abs(n[1] - 1.0) < eps)
17259 // ++faces[2];
17260 // else if(abs(n[1] + 1.0) < eps)
17261 // ++faces[3];
17262 // else if(abs(n[2] - 1.0) < eps)
17263 // ++faces[4];
17264 // else if(abs(n[2] + 1.0) < eps)
17265 // ++faces[5];
17266 }
17267
17268 const MInt stgFaceNormalDir = std::max_element(faces.begin(), faces.end()) - faces.begin();
17269 // cerr << m_solver->domainId() << " " << stgFaceNormalDir << endl;
17270 // for(MInt d = 0; d < 2*nDim; d++){
17271 // cerr << faces[d] << endl;
17272 // }
17273 // for(MInt i = 0; i < 2 * nDim; i++) {
17274 // if(i != stgFaceNormalDir) {
17275 // if(faces[i] != 0) mTerm(1, AT_, "Something went wrong, STG plane is only allowed in one direction!");
17276 // }
17277 // }
17278
17279 MInt stgDir = stgFaceNormalDir;
17280 if(noDomains() > 1) {
17281 MPI_Allreduce(&stgFaceNormalDir, &stgDir, 1, MPI_INT, MPI_MIN, comm7909, AT_, "dirN", "stgDir");
17282 }
17283 // Sanity check: check if all ranks of STG have normal direction
17284 // if(stgFaceNormalDir != stgDir) {
17285 // mTerm(1, AT_, "Something went wrong, STG plane is only allowed in one direction!");
17286 // } else {
17287 // stgDir = stgFaceNormalDir / 2;
17288 // }
17289
17290 MInt stgWallNormalDir = 3;
17291 MInt noCoords_ = Context::propertyLength("stgWallNormalDir");
17292 for(MInt i = 0; i < noCoords_; i++) {
17293 if(m_cutOffBndryCndIds[bcId] == 7909 + i) {
17294 stgWallNormalDir = Context::getBasicProperty<MFloat>("stgWallNormalDir", AT_, i);
17295 }
17296 }
17297
17298 MInt wallDir = stgWallNormalDir / 2;
17299
17300 // cerr << stgFaceNormalDir << " " << stgDir << " " << stgWallNormalDir << " " << wallDir << endl;
17301
17302 // ======================================================
17303 // 4) Create MSTG object
17304 // ======================================================
17305 m_log << "::bcInit7909: ... creating MSTG object ..." << endl;
17306
17307 switch(string2enum(m_solver->m_bc7909RANSSolverType)) {
17308 case MAIA_FINITE_VOLUME: {
17309 // TODO: don't forget to delete the objects later
17312 m_cutOffBndryCndIds[bcId],
17313 commStg,
17314 &stgBcCells[0],
17315 noBc7909Cells,
17316 stgFaceNormalDir,
17317 stgDir,
17318 stgWallNormalDir,
17319 wallDir,
17320 true);
17321
17322 m_log << "::bcInit" + to_string(m_cutOffBndryCndIds[bcId]) + ": ... creating MSTG object finished..." << endl;
17323
17324 if(m_stgBC.find(bcId) != m_stgBC.end()) {
17325 if(m_solver->m_wasAdapted || m_solver->m_wasBalancedZonal) {
17326 // if(globalTimeStep > m_solver->m_restartTimeStep+1){
17327 m_stgBC[bcId]->saveStg();
17328 delete m_stgBC[bcId];
17329 m_stgBC.erase(bcId);
17330 stgBC->init(0);
17331 m_stgBC.insert(std::pair<MInt, MSTG<nDim, MAIA_FINITE_VOLUME, MAIA_FINITE_VOLUME>*>(bcId, stgBC));
17332
17333 cerr << "init bc7909 " << m_solver->m_wasAdapted << " " << m_solver->m_wasBalancedZonal << endl;
17334 }
17335 } else {
17336 stgBC->init(0);
17337 m_stgBC.insert(std::pair<MInt, MSTG<nDim, MAIA_FINITE_VOLUME, MAIA_FINITE_VOLUME>*>(bcId, stgBC));
17338 }
17339
17340 break;
17341 }
17342
17343 default:
17344 mTerm(1, AT_, "Not yet implemented for solver " + m_solver->m_bc7909RANSSolverType);
17345 }
17346
17347 m_log << "::bcInit7909: ... FINISHED" << endl;
17348 }
17349}
17350
17351
17358template <MInt nDim, class SysEqn>
17359template <class _, std::enable_if_t<hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
17361 TRACE();
17362
17363 if(m_sortedCutOffCells[bcId]->size() == 0) {
17364 return;
17365 }
17366
17367 MInt cellId, nghbrId, d = m_7901faceNormalDir;
17368 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17369 cellId = m_sortedCutOffCells[bcId]->a[id];
17370
17371 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17372 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17373
17374 if(m_solver->checkNeighborActive(cellId, d)) {
17375 nghbrId = m_solver->c_neighborId(cellId, d);
17376 if(nghbrId < 0) {
17377 cutOffBcMissingNeighbor(cellId, "bc7901");
17378 } else {
17379 // set the velocities
17380 m_solver->a_pvariable(cellId, PV->U) = m_solver->a_pvariable(nghbrId, PV->U);
17381 m_solver->a_pvariable(cellId, PV->V) = m_solver->a_pvariable(nghbrId, PV->V);
17382 m_solver->a_pvariable(cellId, PV->W) = m_solver->a_pvariable(nghbrId, PV->W);
17383 // set the density
17384 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
17385 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
17386 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
17387 m_solver->a_pvariable(cellId, PV->NN[r]) = m_solver->a_pvariable(nghbrId, PV->NN[r]);
17388 }
17389 }
17390
17391 MFloat pressureTarget = m_solver->m_PInfinity; // m_solver->m_LESValues[PV->P][cellId];
17392
17393 m_solver->a_pvariable(cellId, PV->P) = pressureTarget;
17394 if(m_noSpecies > 0) {
17395 m_solver->a_pvariable(cellId, PV->Y[0]) = m_solver->m_LESValues[PV->Y[0]][cellId];
17396 }
17397 }
17398 } else {
17399 m_solver->a_pvariable(cellId, PV->U) = m_solver->m_UInfinity;
17400 m_solver->a_pvariable(cellId, PV->V) = m_solver->m_VInfinity;
17401 m_solver->a_pvariable(cellId, PV->W) = m_solver->m_WInfinity;
17402 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
17403 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
17404 }
17405 }
17406}
17407
17414template <MInt nDim, class SysEqn>
17415template <class _, std::enable_if_t<hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
17417 TRACE();
17418
17419 if(m_sortedCutOffCells[bcId]->size() == 0) return;
17420
17421 if(globalTimeStep % m_solver->m_zonalTransferInterval == 0 //&& globalTimeStep != m_solver->m_restartTimeStep
17422 && m_solver->m_RKStep == 0) {
17423 for(MInt var = 0; var < PV->noVariables; var++) {
17424 for(MInt i = 0; i < m_7902globalNoWallNormalLocations; i++) {
17425 m_7902LESAverage[var][i] = F0;
17426 }
17427 }
17428
17429 for(MInt var = 0; var < PV->noVariables; var++) {
17430 for(MInt i = 0; i < m_7902globalNoWallNormalLocations; i++) {
17431 for(MInt p = 0; p < (MInt)m_7902periodicLocations[i].size(); p++) {
17432 MInt cellId = m_7902periodicLocations[i][p];
17433
17434 ASSERT(cellId < (MInt)m_solver->m_LESValues[var].size(),
17435 "Trying to access data [" + to_string(var) + "][" + to_string(cellId) + "] in m_LESValues with length "
17436 + to_string(m_solver->m_LESValues[var].size()) + ", domainId: " + to_string(m_solver->domainId()));
17437
17438 m_7902LESAverage[var][i] += m_solver->m_LESValues[var][cellId] / m_7902globalNoPeriodicLocations[i];
17439 }
17440 }
17441 }
17442
17443 if(noDomains() > 1) {
17444 for(MInt var = 0; var < PV->noVariables; var++) {
17445 MPI_Allreduce(MPI_IN_PLACE, m_7902LESAverage[var], m_7902globalNoWallNormalLocations, MPI_DOUBLE, MPI_SUM,
17446 m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_, "MPI_IN_PLACE", "m_7902LESAverage");
17447 }
17448 }
17449 }
17450
17451 MInt cellId, nghbrId, d = m_7902faceNormalDir;
17452 // Prepare the exchange cells for zonal RANS-LES method
17453 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17454 cellId = m_sortedCutOffCells[bcId]->a[id];
17455
17456 // InitialRange
17457 if(globalTimeStep < m_7902StartTimeStep) {
17458 // Velocities
17459 m_solver->a_pvariable(cellId, PV->U) = m_solver->m_UInfinity;
17460 m_solver->a_pvariable(cellId, PV->V) = m_solver->m_VInfinity;
17461 m_solver->a_pvariable(cellId, PV->W) = m_solver->m_WInfinity;
17462 // Density
17463 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
17464 // Turbulent viscosity
17465 m_solver->a_pvariable(cellId, PV->N) = m_solver->m_nuTildeInfinity;
17466
17467 // fully developed LES solution
17468 } else {
17469 for(MInt var = 0; var < PV->noVariables; var++) {
17470 MInt index = m_7902periodicIndex[id];
17471 m_solver->a_pvariable(cellId, var) = m_7902LESAverage[var][index];
17472 }
17473 }
17474
17475 // Pressure
17476 if(m_solver->checkNeighborActive(cellId, d)) {
17477 nghbrId = m_solver->c_neighborId(cellId, d);
17478 if(nghbrId < 0) {
17479 cutOffBcMissingNeighbor(cellId, "bc7902");
17480 } else {
17481 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
17482 }
17483 } else {
17484 TERMM(1, "ERROR in bc7902");
17485 }
17486 }
17487}
17488
17495template <MInt nDim, class SysEqn>
17496template <class _, std::enable_if_t<hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
17498 TRACE();
17499
17500 if(m_sortedCutOffCells[bcId]->size() == 0) return;
17501
17502 MInt cellId, nghbrId, d = m_7902faceNormalDir;
17503 // Prepare the exchange cells for zonal RANS-LES method
17504 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17505 cellId = m_sortedCutOffCells[bcId]->a[id];
17506
17507 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17508 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17509
17510 // InitialRange
17511 if(globalTimeStep < m_7902StartTimeStep) {
17512 // Velocities
17513 m_solver->a_pvariable(cellId, PV->U) = m_solver->m_UInfinity;
17514 m_solver->a_pvariable(cellId, PV->V) = m_solver->m_VInfinity;
17515 m_solver->a_pvariable(cellId, PV->W) = m_solver->m_WInfinity;
17516 // Density
17517 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
17518 // Turbulent viscosity
17519 m_solver->a_pvariable(cellId, PV->N) = m_solver->m_nuTildeInfinity;
17520
17521 // fully developed LES solution
17522 } else {
17523 for(MInt var = 0; var < PV->noVariables; var++) {
17524 m_solver->a_pvariable(cellId, var) = m_solver->m_LESValues[var][cellId];
17525 }
17526 }
17527
17528 // Pressure
17529 if(m_solver->checkNeighborActive(cellId, d)) {
17530 nghbrId = m_solver->c_neighborId(cellId, d);
17531 if(nghbrId < 0) {
17532 cutOffBcMissingNeighbor(cellId, "bc7905");
17533 } else {
17534 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
17535 }
17536 } else {
17537 TERMM(1, "ERROR in bc7905");
17538 }
17539 }
17540}
17541
17548template <MInt nDim, class SysEqn>
17549template <class _, std::enable_if_t<!hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
17551 TRACE();
17552
17553 /* if(m_sortedCutOffCells[bcId]->size() == 0) return; */
17554
17555 MInt cellId, nghbrId, d = 0;
17556 // Prepare the exchange cells for zonal RANS-LES method
17557 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17558 cellId = m_sortedCutOffCells[bcId]->a[id];
17559
17560 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17561 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17562
17563 // set boundary values
17564 if(m_solver->checkNeighborActive(cellId, d)) {
17565 nghbrId = m_solver->c_neighborId(cellId, d);
17566 if(nghbrId < 0) {
17567 cutOffBcMissingNeighbor(cellId, "bc7903");
17568 } else {
17569 // set the velocities
17570 m_solver->a_pvariable(cellId, PV->U) = m_solver->a_pvariable(nghbrId, PV->U);
17571 m_solver->a_pvariable(cellId, PV->V) = m_solver->a_pvariable(nghbrId, PV->V);
17572 m_solver->a_pvariable(cellId, PV->W) = m_solver->a_pvariable(nghbrId, PV->W);
17573 // set the density
17574 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
17575
17576 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_RANSValues[PV->P][cellId];
17577
17578 for(MInt s = 0; s < m_noSpecies; s++)
17579 m_solver->a_pvariable(cellId, PV->Y[s]) = m_solver->a_pvariable(nghbrId, PV->Y[s]);
17580 }
17581 } else {
17582 TERMM(1, "ERROR in bc7903");
17583 }
17584 }
17585}
17586
17593template <MInt nDim, class SysEqn>
17594template <class _, std::enable_if_t<!hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
17596 TRACE();
17597
17598 IF_CONSTEXPR(isEEGas<SysEqn>)
17599 TERMM(1, "bc7809 not working for AIAFvSysEqnEEGas");
17600
17601 if(m_stgLocal[bcId]) {
17602 switch(string2enum(m_solver->m_bc7909RANSSolverType)) {
17603 case MAIA_FINITE_VOLUME: {
17604 m_stgBC[bcId]->bc7909();
17605 break;
17606 }
17607 case MAIA_STRUCTURED: {
17608 m_stgBCStrcd[bcId]->bc7909();
17609 break;
17610 }
17611 default:
17612 mTerm(1, AT_, "Not yet implemented for solver " + m_solver->m_bc7909RANSSolverType);
17613 }
17614 if(m_solver->m_noSpecies > 0) {
17615 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
17616 MInt bndryId = m_sortedBndryCells->a[id];
17617 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
17618 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
17619 const MInt ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[0]->m_ghostCellId;
17620 for(MInt i = 0; i < m_noSpecies; i++) {
17621 m_solver->a_pvariable(ghostCellId, PV->Y[i]) = F0;
17622 }
17623 }
17624 }
17625 }
17626 }
17627}
17628
17635template <MInt nDim, class SysEqn>
17636template <class _, std::enable_if_t<!hasPV_N<SysEqn>::value, _*>, std::enable_if_t<nDim == 3, _*>>
17638 TRACE();
17639
17640 IF_CONSTEXPR(isEEGas<SysEqn>)
17641 TERMM(1, "bc7809 not working for AIAFvSysEqnEEGas");
17642
17643 if(m_sortedCutOffCells[bcId]->size() == 0) {
17644 return;
17645 }
17646
17647 MInt d = 1;
17648
17649 if(!m_solver->m_stgIsActive) {
17650 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17651 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
17652 // set variables
17653 // for(MInt var = 0; var < PV->noVariables; var++) {
17654 m_solver->a_pvariable(cellId, PV->U) = m_solver->m_RANSValues[PV->U][cellId];
17655 m_solver->a_pvariable(cellId, PV->V) = m_solver->m_RANSValues[PV->V][cellId];
17656 m_solver->a_pvariable(cellId, PV->W) = m_solver->m_RANSValues[PV->W][cellId];
17657 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_RANSValues[PV->RHO][cellId];
17658 }
17659 // return;
17660 } else {
17661 if(m_stgLocal[bcId]) {
17662 switch(string2enum(m_solver->m_bc7909RANSSolverType)) {
17663 case MAIA_FINITE_VOLUME: {
17664 m_stgBC[bcId]->bc7909();
17665 break;
17666 }
17667 case MAIA_STRUCTURED: {
17668 m_stgBCStrcd[bcId]->bc7909();
17669 break;
17670 }
17671
17672 default:
17673 mTerm(1, AT_, "Not yet implemented for solver " + m_solver->m_bc7909RANSSolverType);
17674 }
17675 }
17676
17677 if(m_solver->m_noSpecies > 0) {
17678 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17679 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
17680 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
17681 for(MInt i = 0; i < m_noSpecies; i++) {
17682 m_solver->a_pvariable(cellId, PV->Y[i]) = F0;
17683 }
17684 }
17685 }
17686 }
17687 }
17688
17689 // set pressure
17690 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17691 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
17692 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17693 if(m_solver->checkNeighborActive(cellId, d)) {
17694 const MInt nghbrId = m_solver->c_neighborId(cellId, d);
17695 if(nghbrId < 0) {
17696 cutOffBcMissingNeighbor(cellId, "bc7909");
17697 } else {
17698 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
17699 }
17700 } else {
17701 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
17702 }
17703 }
17704}
17705
17706
17712template <MInt nDim, class SysEqn>
17714 TRACE();
17715
17716 IF_CONSTEXPR(isEEGas<SysEqn>)
17717 TERMM(1, "bc7809 not working for AIAFvSysEqnEEGas");
17718
17719 if(m_sortedCutOffCells[bcId]->size() == 0) {
17720 return;
17721 }
17722
17723 const MInt d = 2;
17724 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17725 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
17726 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17727 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17728 if(m_solver->checkNeighborActive(cellId, d)) {
17729 const MInt nghbrId = m_solver->c_neighborId(cellId, d);
17730 if(nghbrId < 0) {
17731 cutOffBcMissingNeighbor(cellId, "bc30022");
17732 } else {
17733 m_solver->a_pvariable(cellId, PV->U) = m_solver->a_pvariable(nghbrId, PV->U);
17734 m_solver->a_pvariable(cellId, PV->V) = m_horTargetData[id][1];
17735 m_solver->a_pvariable(cellId, PV->W) = m_solver->m_WInfinity;
17736 m_solver->a_pvariable(cellId, PV->RHO) = m_horTargetData[id][2];
17737 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
17738 }
17739 } else {
17740 m_solver->a_pvariable(cellId, PV->U) = m_solver->m_UInfinity;
17741 m_solver->a_pvariable(cellId, PV->V) = m_solver->m_VInfinity;
17742 m_solver->a_pvariable(cellId, PV->W) = m_solver->m_WInfinity;
17743 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->m_rhoInfinity;
17744 m_solver->a_pvariable(cellId, PV->P) = m_solver->m_PInfinity;
17745 }
17746 }
17747}
17748// --- ZONAL ENDS ---
17749
17755template <MInt nDim, class SysEqn>
17757#ifndef NDEBUG
17758 ASSERT(m_solver->a_isHalo(cellId) && g_multiSolverGrid,
17759 "Error in " + bcName + ": missing neighbor for (halo) cut-off cell only allowed in multisolver case (halo = "
17760 + to_string(m_solver->a_isHalo(cellId)) + "; multisolver = " + to_string(g_multiSolverGrid) + ")");
17761#else
17762 std::ignore = bcName;
17763#endif
17764 const MFloat nanValue = std::numeric_limits<MFloat>::quiet_NaN();
17765 std::fill_n(&m_solver->a_pvariable(cellId, 0), PV->noVariables, nanValue);
17766}
17767
17768
17776template <MInt nDim, class SysEqn>
17778 TRACE();
17779
17780#ifdef _OPENMP
17781#pragma omp parallel for
17782#endif
17783 // loop over all concerning boundary cells
17784 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
17785 const MInt cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
17786 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
17787 const MInt ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[0]->m_ghostCellId;
17788
17789 // set the density
17790 m_solver->a_pvariable(ghostCellId, PV->RHO) = m_solver->a_pvariable(cellId, PV->RHO);
17791
17792 // set the velocities
17793 m_solver->a_pvariable(ghostCellId, PV->U) = m_solver->a_pvariable(cellId, PV->U);
17794 m_solver->a_pvariable(ghostCellId, PV->V) = -m_solver->a_pvariable(cellId, PV->V);
17795
17796 // set the pressure of the ghost cell equal to that of the boundary cell
17797 m_solver->a_pvariable(ghostCellId, PV->P) = m_solver->a_pvariable(cellId, PV->P);
17798
17799 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
17800 for(MInt r = 0; r < m_solver->m_noRansEquations; ++r) {
17801 m_solver->a_pvariable(ghostCellId, PV->NN[r]) = m_solver->a_pvariable(cellId, PV->N);
17802 }
17803 }
17804 }
17805 }
17806}
17807
17808
17814template <MInt nDim, class SysEqn>
17816 TRACE();
17817
17818 MInt cellId, d;
17819 MLong nghbrId;
17820 //---end of initialization
17821
17822 MInt Dir[nDim];
17823 for(MInt i = 0; i < nDim; i++) {
17824 Dir[i] = 1;
17825 }
17826 switch(m_cutOffBndryCndIds[bcId]) {
17827 case 29050:
17828 d = 1;
17829 Dir[0] = -1;
17830 break;
17831 case 29051:
17832 d = 0;
17833 Dir[0] = -1;
17834 break;
17835 case 29052:
17836 d = 2;
17837 Dir[1] = -1;
17838 break;
17839 case 29053:
17840 d = 3;
17841 Dir[1] = -1;
17842 break;
17843 case 29054:
17844 IF_CONSTEXPR(nDim == 2) mTerm(1, AT_, "bc29054: symmetry in z-direction not possible for 2D");
17845 d = 4;
17846 Dir[2] = -1;
17847 break;
17848 case 29055:
17849 IF_CONSTEXPR(nDim == 2) mTerm(1, AT_, "bc29054: symmetry in z-direction not possible for 2D");
17850 d = 5;
17851 Dir[2] = -1;
17852 break;
17853 default: {
17854 stringstream errorMessage;
17855 errorMessage << "ERROR: Switch variable 'm_cutOffBndryCndIds[ bcId ]' with value " << m_cutOffBndryCndIds[bcId]
17856 << " not matching any case." << endl;
17857 mTerm(1, AT_, errorMessage.str());
17858 }
17859 }
17860
17861 // loop over all concerning cells
17862 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17863 cellId = m_sortedCutOffCells[bcId]->a[id];
17864 nghbrId = m_solver->c_neighborId(cellId, d);
17865
17866 // set the velocities
17867 m_solver->a_pvariable(cellId, PV->U) = Dir[0] * m_solver->a_pvariable(nghbrId, PV->U);
17868 m_solver->a_pvariable(cellId, PV->V) = Dir[1] * m_solver->a_pvariable(nghbrId, PV->V);
17869 IF_CONSTEXPR(nDim == 3) { m_solver->a_pvariable(cellId, PV->W) = Dir[2] * m_solver->a_pvariable(nghbrId, PV->W); }
17870 // set the density
17871 m_solver->a_pvariable(cellId, PV->RHO) = m_solver->a_pvariable(nghbrId, PV->RHO);
17872
17873 // set the density
17874 m_solver->a_pvariable(cellId, PV->P) = m_solver->a_pvariable(nghbrId, PV->P);
17875
17876 // set the species
17877 for(MInt i = 0; i < m_noSpecies; i++) {
17878 m_solver->a_pvariable(cellId, PV->Y[i]) = m_solver->a_pvariable(nghbrId, PV->Y[i]);
17879 }
17880 }
17881}
17882
17883
17890template <MInt nDim, class SysEqn>
17892 TRACE();
17893
17894 if(m_sortedCutOffCells[bcId]->size() == 0) {
17895 return;
17896 }
17897
17898 MInt cbcId = m_cbcBndryCndIds[bcId];
17899
17900 MInt dirN = m_cbcDir[cbcId][0];
17901 MInt dimN = m_cbcDir[cbcId][1];
17902 MInt dimT1 = m_cbcDir[cbcId][2];
17903 MInt dimT2 = m_cbcDir[cbcId][nDim];
17904
17905 MInt last = nDim + 1;
17906
17907 // Allocate memory
17908 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
17909 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
17910 MFloatScratchSpace gradP(nDim, AT_, "gradP");
17911 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
17912 gradY.fill(F0);
17913
17914 MFloatScratchSpace L(PV->noVariables, AT_, "L");
17915 MFloatScratchSpace T(PV->noVariables, AT_, "T");
17916 MFloatScratchSpace V(PV->noVariables, AT_, "V");
17917 MFloatScratchSpace K(PV->noVariables, AT_, "K");
17918
17919 MFloat mach[2] = {F0, F0};
17920 cbcMachCo(bcId, mach);
17921 MFloat meanM = mach[0];
17922 MFloat maxM = mach[1];
17923
17924 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
17925 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
17926 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
17927 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
17928 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
17929
17930 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
17931 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
17932
17933 MFloat T_target = sysEqn().temperature_IR(meanM);
17934 MFloat p_Target = sysEqn().pressure_IR(T_target);
17935 MFloat y_target = F1;
17936
17937 IF_CONSTEXPR(isDetChem<SysEqn>) {
17938 T_target = m_solver->m_detChem.infTemperature;
17939 p_Target = m_solver->m_detChem.infPressure;
17940 }
17941
17942 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
17943 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
17944
17945 if(m_solver->a_isHalo(cellId)) continue;
17946 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17947 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17948
17949 MInt bndryId = m_solver->a_bndryId(cellId);
17950 if(bndryId > -1) {
17951 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
17952 }
17953
17954 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
17955 V.fill(F0);
17956 if(m_cbcViscous) {
17957 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
17958 // BC specific
17959 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
17960 IF_CONSTEXPR(nDim == 3) gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0;
17961 // END BC specific
17962 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
17963 &cutOffStencilCellIds[0], &V[0]);
17964 }
17965
17966 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
17967 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
17968 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
17969
17970 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
17971 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
17972 const MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
17973 MFloat temp = sysEqn().temperature_ES(rho, p);
17974
17975 IF_CONSTEXPR(isDetChem<SysEqn>) {
17976 MFloat fMeanMolarWeight = F0;
17977 for(MUint s = 0; s < PV->m_noSpecies; s++) {
17978 fMeanMolarWeight += m_solver->a_pvariable(cellId, PV->Y[s]) * m_solver->m_fMolarMass[s];
17979 }
17980 MFloat meanMolarWeight = F1 / fMeanMolarWeight;
17981 temp = p / rho * meanMolarWeight / m_solver->m_gasConstant;
17982 }
17983
17984 const MFloat a = sysEqn().speedOfSound(rho, p);
17985
17986 if(dirN % 2 == 0) {
17987 L[0] = K[0] * (p - p_Target) + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
17988 } else {
17989 L[last] = K[last] * (p - p_Target) + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
17990 }
17991
17992 L[1] = K[1] * (temp - T_target) + (a * a * T[0] - T[last]) - V[last];
17993
17994 L[2] = K[2] * ut1 + T[2] + V[2];
17995
17996 IF_CONSTEXPR(nDim == 3) {
17997 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
17998 L[3] = K[3] * ut2 + T[3] + V[3];
17999 }
18000 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
18001 MFloat y = m_solver->a_pvariable(cellId, sysEqn().PV->Y[s]);
18002 L[last + 1 + s] = K[last + 1 + s] * (y - y_target);
18003 }
18004
18005 IF_CONSTEXPR(isDetChem<SysEqn>) {
18006 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
18007 MFloat y = m_solver->a_pvariable(cellId, sysEqn().PV->Y[s]);
18008 L[last + 1 + s] = K[last + 1 + s] * (y - m_solver->m_YInfinity[s]);
18009 }
18010 }
18011
18012 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
18013 }
18014}
18015
18022template <MInt nDim, class SysEqn>
18024 TRACE();
18025
18026 if(m_sortedCutOffCells[bcId]->size() == 0) {
18027 return;
18028 }
18029
18030 MInt cbcId = m_cbcBndryCndIds[bcId];
18031
18032 MInt dirN = m_cbcDir[cbcId][0];
18033 MInt dimN = m_cbcDir[cbcId][1];
18034 MInt dimT1 = m_cbcDir[cbcId][2];
18035
18036 MInt last = nDim + 1;
18037
18038 // Allocate memory
18039 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
18040 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
18041 MFloatScratchSpace gradP(nDim, AT_, "gradP");
18042 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
18043 gradY.fill(F0);
18044
18045 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
18046 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
18047 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
18048 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
18049 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
18050
18051 MFloatScratchSpace L(PV->noVariables, AT_, "L");
18052 MFloatScratchSpace T(PV->noVariables, AT_, "T");
18053 MFloatScratchSpace V(PV->noVariables, AT_, "V");
18054 MFloatScratchSpace K(PV->noVariables, AT_, "K");
18055
18056 MFloat mach[2] = {F0, F0};
18057 cbcMachCo(bcId, mach);
18058 MFloat meanM = mach[0];
18059 MFloat maxM = mach[1];
18060
18061 const MFloat gammaMinusOne = m_solver->m_gamma - 1.0;
18062
18063 // BC specific
18064 MBool solverProfile = Context::getSolverProperty<MBool>("solverProfile", m_solverId, AT_, &solverProfile);
18065 MFloat A = F0;
18066 IF_CONSTEXPR(nDim == 3) { A = sqrt(m_cbcInflowArea[cbcId] / PI); }
18067 else {
18068 A = m_cbcInflowArea[cbcId] * F1B2;
18069 }
18070 MFloat testSum2 = F0;
18071 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18072 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18073 if(m_solver->a_isHalo(cellId)) continue;
18074 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
18075 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18076 MInt bndryId = m_solver->a_bndryId(cellId);
18077
18078 MFloat area;
18079 if(bndryId > -1) {
18080 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
18081 if(srfcId > -1) {
18082 area = m_solver->a_surfaceArea(srfcId);
18083 } else {
18084 mTerm(1, AT_, "something went wrong!");
18085 }
18086 } else {
18087 IF_CONSTEXPR(nDim == 2) area = m_solver->c_cellLengthAtCell(cellId);
18088 IF_CONSTEXPR(nDim == 3) area = POW2(m_solver->c_cellLengthAtCell(cellId));
18089 }
18090
18091 MFloat rsquare;
18092 IF_CONSTEXPR(nDim == 2) {
18093 rsquare = POW2((m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]));
18094 }
18095 else {
18096 rsquare = POW2(m_solver->a_coordinate(cellId, 0) - m_cbcReferencePoint[cbcId][0])
18097 + POW2(m_solver->a_coordinate(cellId, 1) - m_cbcReferencePoint[cbcId][1])
18098 + POW2(m_solver->a_coordinate(cellId, 2) - m_cbcReferencePoint[cbcId][2]);
18099 }
18100 testSum2 += area * rsquare;
18101 }
18102 MPI_Allreduce(MPI_IN_PLACE, &testSum2, 3, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
18103 "testSum2", "testSum2Result");
18104
18105
18106 MFloat massflux_test;
18107 IF_CONSTEXPR(nDim == 2) { massflux_test = F3B4 / A * (m_cbcInflowArea[cbcId] - F1 / (A * A) * testSum2); }
18108 else {
18109 massflux_test = F2 * (F1 - testSum2 / (m_cbcInflowArea[cbcId] * A * A));
18110 }
18111 MFloat un_correctionFactor = F1;
18112 if(fabs(massflux_test) > m_solver->m_eps) {
18113 un_correctionFactor = F1 / massflux_test;
18114 }
18115 // END BC specific
18116
18117 // Target values
18118 MFloat massflux_target;
18119 massflux_target = m_solver->m_UInfinity * m_cbcInflowArea[cbcId]
18120 * sysEqn().density_ES(m_solver->m_PInfinity, m_solver->m_TInfinity);
18121 MFloat T_target = sysEqn().temperature_IR(meanM);
18122
18123 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
18124 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
18125
18126 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18127 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18128
18129 if(m_solver->a_isHalo(cellId)) continue;
18130 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
18131 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18132
18133 MInt bndryId = m_solver->a_bndryId(cellId);
18134 if(bndryId > -1) {
18135 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
18136 }
18137
18138 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
18139 V.fill(F0);
18140 if(m_cbcViscous) {
18141 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
18142 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
18143 &cutOffStencilCellIds[0], &V[0]);
18144 }
18145
18146 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
18147 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
18148 cbcDampingInflow(cellId, bcId, maxM, &K[0], "velocity");
18149
18150 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
18151 MFloat p = m_solver->a_pvariable(cellId, PV->P);
18152 MFloat a = sysEqn().speedOfSound(rho, p);
18153
18154 MFloat rsquare;
18155 MFloat un_target;
18156 if(nDim == 2) {
18157 rsquare = POW2((m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]));
18158 un_target = F3B4 * massflux_target / rho / A * (1 - rsquare / (A * A)) * un_correctionFactor;
18159 } else {
18160 rsquare = POW2(m_solver->a_coordinate(cellId, 0) - m_cbcReferencePoint[cbcId][0])
18161 + POW2(m_solver->a_coordinate(cellId, 1) - m_cbcReferencePoint[cbcId][1])
18162 + POW2(m_solver->a_coordinate(cellId, 2) - m_cbcReferencePoint[cbcId][2]);
18163 un_target = F2 * massflux_target / m_cbcInflowArea[cbcId] * (F1 - rsquare / (A * A)) / rho * un_correctionFactor;
18164 }
18165 if(solverProfile) {
18166 un_target = massflux_target / m_cbcInflowArea[cbcId] / rho;
18167 }
18168
18169 // BC specific
18170 L[2] = F0;
18171 L[3] = F0;
18172 T[2] = F0;
18173 T[3] = F0;
18174 // END BC specific
18175
18176 if(dirN % 2 == 0) {
18177 L[0] = L[last] + (T[last] - rho * a * T[1]);
18178 } else {
18179 L[last] = L[0] + (T[last] + rho * a * T[1]);
18180 }
18181
18182 L[1] = F1B2 * gammaMinusOne * (L[0] + L[last]) + (a * a * T[0] - T[last]);
18183
18184 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
18185
18186 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimN]) = F0;
18187 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT1]) = F0;
18188 m_solver->a_rightHandSide(cellId, CV->RHO_E) = F0;
18189 MFloat sign = F1;
18190 if(dirN % 2 == 0) {
18191 sign = -F1;
18192 }
18193 m_solver->a_pvariable(cellId, PV->VV[dimN]) = un_target * sign;
18194 m_solver->a_pvariable(cellId, PV->VV[dimT1]) = F0;
18195 m_solver->a_pvariable(cellId, PV->P) = T_target;
18196 IF_CONSTEXPR(nDim == 3) {
18197 MInt dimT2 = m_cbcDir[cbcId][nDim];
18198 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT2]) = F0;
18199 m_solver->a_pvariable(cellId, PV->VV[dimT1]) = F0;
18200 }
18201 }
18202}
18203
18204
18208template <MInt nDim, class SysEqn>
18210 TRACE();
18211 if(m_sortedCutOffCells[bcId]->size() == 0) {
18212 return;
18213 }
18214
18215 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18216 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18217 if(m_solver->a_isHalo(cellId)) continue;
18218 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18219
18220 const MInt bndryId = m_solver->a_bndryId(cellId);
18221
18222 if(bndryId > -1) {
18223 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) {
18224 continue;
18225 }
18226 }
18227
18228 // recompute the correct energy:
18229 const MFloat rho = m_solver->a_variable(cellId, CV->RHO);
18230 const MFloat u = m_solver->a_pvariable(cellId, PV->VV[0]);
18231 const MFloat v = m_solver->a_pvariable(cellId, PV->VV[1]);
18232 const MFloat T = m_solver->a_pvariable(cellId, PV->P);
18233 const MFloat p = sysEqn().pressure_ES(T, rho);
18234 MFloat velSquared = u * u + v * v;
18235 IF_CONSTEXPR(nDim == 3) {
18236 const MFloat w = m_solver->a_pvariable(cellId, PV->VV[2]);
18237 m_solver->a_variable(cellId, CV->RHO_VV[2]) = rho * w;
18238 velSquared += w * w;
18239 }
18240 m_solver->a_variable(cellId, CV->RHO_E) = sysEqn().internalEnergy(p, rho, velSquared);
18241 m_solver->a_variable(cellId, CV->RHO_VV[0]) = rho * u;
18242 m_solver->a_variable(cellId, CV->RHO_VV[1]) = rho * v;
18243 }
18244}
18245
18246
18254template <MInt nDim, class SysEqn>
18256 TRACE();
18257
18258 if(m_sortedCutOffCells[bcId]->size() == 0) {
18259 return;
18260 }
18261
18262 MInt cbcId = m_cbcBndryCndIds[bcId];
18263
18264 MInt dirN = m_cbcDir[cbcId][0];
18265 MInt dimN = m_cbcDir[cbcId][1];
18266 MInt dimT1 = m_cbcDir[cbcId][2];
18267 MInt dimT2 = m_cbcDir[cbcId][nDim];
18268
18269 MInt last = nDim + 1;
18270
18271 // Allocate memory
18272 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
18273 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
18274 MFloatScratchSpace gradP(nDim, AT_, "gradP");
18275 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
18276 gradY.fill(F0);
18277
18278 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
18279 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
18280 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
18281 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
18282 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
18283
18284 MFloatScratchSpace L(PV->noVariables, AT_, "L");
18285 MFloatScratchSpace T(PV->noVariables, AT_, "T");
18286 MFloatScratchSpace V(PV->noVariables, AT_, "V");
18287 MFloatScratchSpace K(PV->noVariables, AT_, "K");
18288
18289 MFloat mach[2] = {F0, F0};
18290 cbcMachCo(bcId, mach);
18291 MFloat meanM = mach[0];
18292 MFloat maxM = mach[1];
18293
18294 const MFloat gammaMinusOne = m_solver->m_gamma - 1.0;
18295
18296 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
18297 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
18298
18299 MFloat T_target = sysEqn().temperature_IR(meanM);
18300 MFloat p_Target = sysEqn().pressure_IR(T_target);
18301
18302 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18303 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18304
18305 if(m_solver->a_isHalo(cellId)) continue;
18306 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
18307 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18308
18309 MInt bndryId = m_solver->a_bndryId(cellId);
18310 if(bndryId > -1) {
18311 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
18312 }
18313
18314 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
18315 V.fill(F0);
18316 if(m_cbcViscous) {
18317 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
18318 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
18319 IF_CONSTEXPR(nDim == 3) gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0;
18320 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
18321 &cutOffStencilCellIds[0], &V[0]);
18322 }
18323
18324 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
18325 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
18326 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
18327
18328 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
18329 MFloat p = m_solver->a_pvariable(cellId, PV->P);
18330 MFloat a = sysEqn().speedOfSound(rho, p);
18331
18332 if(dirN % 2 == 0) {
18333 L[0] = -L[last] + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
18334 } else {
18335 L[last] = -L[0] + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
18336 }
18337
18338 L[1] = F1B2 * gammaMinusOne * (L[last] - L[0]) + (a * a * T[0] - T[last]) - V[last];
18339
18340 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
18341
18342 m_solver->a_rightHandSide(cellId, CV->RHO) = 0.0;
18343 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT1]) = 0.0;
18344 m_solver->a_rightHandSide(cellId, CV->RHO_E) = 0.0;
18345 IF_CONSTEXPR(nDim == 3) { m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT2]) = 0.0; }
18346 m_solver->a_pvariable(cellId, PV->RHO) = sysEqn().density_ES(p_Target, T_target);
18347 m_solver->a_pvariable(cellId, PV->VV[dimT1]) = 0.0;
18348 IF_CONSTEXPR(nDim == 3) { m_solver->a_pvariable(cellId, PV->VV[dimT2]) = 0.0; }
18349 m_solver->a_pvariable(cellId, PV->P) = p_Target;
18350 }
18351}
18352
18353
18357template <MInt nDim, class SysEqn>
18359 TRACE();
18360
18361 MInt otherDir[2 * nDim];
18362 for(MInt dim = 0; dim < nDim; dim++) {
18363 otherDir[2 * dim] = 2 * dim + 1;
18364 otherDir[2 * dim + 1] = 2 * dim;
18365 }
18366
18367 MBool& first = m_static_cbc1091c_after_first;
18368 MInt& dirN = m_static_cbc1091c_after_dirN;
18369 MInt& dimN = m_static_cbc1091c_after_dimN;
18370 MInt& dimT1 = m_static_cbc1091c_after_dimT1;
18371 MInt& dimT2 = m_static_cbc1091c_after_dimT2;
18372
18373 if(first) {
18374 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
18375 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
18376 if(noCutOffDirections != noCutOffBndryIds) {
18377 mTerm(1, AT_,
18378 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
18379 }
18380 MInt cutOffBndryIdTmp, cutOffDirectionTmp;
18381 for(MInt i = 0; i < noCutOffBndryIds; i++) {
18382 cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
18383 cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
18384 if(cutOffBndryIdTmp == m_cutOffBndryCndIds[bcId]) {
18385 dirN = otherDir[cutOffDirectionTmp];
18386 break;
18387 }
18388 }
18389 dimN = (MInt)dirN / 2;
18390 dimT1 = (dimN + 1) % nDim;
18391 IF_CONSTEXPR(nDim == 3) dimT2 = (dimT1 + 1) % nDim;
18392
18393 first = false;
18394 }
18395
18396 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18397 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18398 if(m_solver->a_isHalo(cellId)) continue;
18399 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18400
18401 MInt bndryId = m_solver->a_bndryId(cellId);
18402
18403 if(bndryId > -1) {
18404 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) {
18405 continue;
18406 }
18407 }
18408
18409 // recompute the correct energy:
18410 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
18411 MFloat u = m_solver->a_variable(cellId, CV->RHO_VV[dimN]) / m_solver->a_variable(cellId, CV->RHO);
18412 MFloat v = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
18413 MFloat p = m_solver->a_pvariable(cellId, PV->P);
18414 const MFloat vel = POW2(u) + POW2(v);
18415 MFloat E = sysEqn().internalEnergy(p, rho, vel);
18416
18417 IF_CONSTEXPR(nDim == 3) {
18418 // compute corrected energy
18419 MFloat w = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
18420 E += F1B2 * (w * w) * rho;
18421 m_solver->a_variable(cellId, CV->RHO_VV[dimT2]) = rho * w;
18422 }
18423
18424 m_solver->a_variable(cellId, CV->RHO_E) = E;
18425 }
18426}
18427
18428
18435template <MInt nDim, class SysEqn>
18437 TRACE();
18438
18439 if(m_sortedCutOffCells[bcId]->size() == 0) {
18440 return;
18441 }
18442
18443 MInt cbcId = m_cbcBndryCndIds[bcId];
18444 // Determine dirs
18445 MInt dirN = m_cbcDir[cbcId][0];
18446 MInt dimN = m_cbcDir[cbcId][1];
18447 MInt dimT1 = m_cbcDir[cbcId][2];
18448
18449 MInt last = nDim + 1;
18450
18451 // Allocate memory
18452 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
18453 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
18454 MFloatScratchSpace gradP(nDim, AT_, "gradP");
18455 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
18456 gradY.fill(F0);
18457
18458 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
18459 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
18460 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
18461 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
18462 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
18463
18464 MFloatScratchSpace L(PV->noVariables, AT_, "L");
18465 MFloatScratchSpace T(PV->noVariables, AT_, "T");
18466 MFloatScratchSpace V(PV->noVariables, AT_, "V");
18467 MFloatScratchSpace K(PV->noVariables, AT_, "K");
18468
18469 // Get mean/max mach number
18470 MFloat mach[2] = {F0, F0};
18471 cbcMachCo(bcId, mach);
18472 MFloat meanM = mach[0];
18473 MFloat maxM = mach[1];
18474
18475 // BC specific
18476 MBool solverProfile = Context::getSolverProperty<MBool>("solverProfile", m_solverId, AT_, &solverProfile);
18477 MFloat A = F0;
18478 IF_CONSTEXPR(nDim == 3) { A = sqrt(m_cbcInflowArea[cbcId] / PI); }
18479 else {
18480 A = m_cbcInflowArea[cbcId] * F1B2;
18481 }
18482 MFloat testSum2 = F0;
18483 MFloat massflux = F0;
18484 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18485 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18486 if(m_solver->a_isHalo(cellId)) continue;
18487 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
18488 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18489 MInt bndryId = m_solver->a_bndryId(cellId);
18490 MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
18491
18492 MFloat area;
18493 if(bndryId > -1) {
18494 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
18495 if(srfcId > -1) {
18496 area = m_solver->a_surfaceArea(srfcId);
18497 } else {
18498 mTerm(1, AT_, "something went wrong!");
18499 }
18500 } else {
18501 IF_CONSTEXPR(nDim == 2) area = m_solver->c_cellLengthAtCell(cellId);
18502 IF_CONSTEXPR(nDim == 3) area = POW2(m_solver->c_cellLengthAtCell(cellId));
18503 }
18504
18505 MFloat rsquare;
18506 IF_CONSTEXPR(nDim == 2) {
18507 rsquare = POW2((m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]));
18508 }
18509 else {
18510 rsquare = POW2(m_solver->a_coordinate(cellId, 0) - m_cbcReferencePoint[cbcId][0])
18511 + POW2(m_solver->a_coordinate(cellId, 1) - m_cbcReferencePoint[cbcId][1])
18512 + POW2(m_solver->a_coordinate(cellId, 2) - m_cbcReferencePoint[cbcId][2]);
18513 }
18514 testSum2 += area * rsquare;
18515 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
18516 const MFloat un_N = m_solver->a_pvariable(nghbrN, PV->VV[dimN]);
18517 massflux += un_N * area * rho;
18518 }
18519
18520 MPI_Allreduce(MPI_IN_PLACE, &massflux, 3, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
18521 "massflux", "massfluxResult");
18522 MPI_Allreduce(MPI_IN_PLACE, &testSum2, 3, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
18523 "testSum2", "testSum2Result");
18524
18525 MFloat massflux_test;
18526 IF_CONSTEXPR(nDim == 2) { massflux_test = F3B4 / A * (m_cbcInflowArea[cbcId] - F1 / (A * A) * testSum2); }
18527 else {
18528 massflux_test = F2 * (F1 - testSum2 / (m_cbcInflowArea[cbcId] * A * A));
18529 }
18530 MFloat un_correctionFactor = F1;
18531 if(fabs(massflux_test) > m_solver->m_eps) {
18532 un_correctionFactor = F1 / massflux_test;
18533 }
18534 // END BC specific
18535
18536 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
18537 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
18538
18539 MFloat T_target = sysEqn().temperature_IR(meanM);
18540 MFloat p_Target = sysEqn().pressure_IR(T_target);
18541
18542 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18543 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18544
18545 if(m_solver->a_isHalo(cellId)) continue;
18546 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
18547 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18548
18549 MInt bndryId = m_solver->a_bndryId(cellId);
18550 if(bndryId > -1) {
18551 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
18552 }
18553
18554 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
18555 if(m_cbcViscous) {
18556 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
18557 }
18558
18559 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
18560 MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
18561 MFloat p = m_solver->a_pvariable(cellId, PV->P);
18562 MFloat temp = sysEqn().temperature_ES(rho, p);
18563 MFloat a = sysEqn().speedOfSound(rho, p);
18564
18565 MFloat un_target;
18566 IF_CONSTEXPR(nDim == 3) {
18567 MFloat rsquare = POW2(m_solver->a_coordinate(cellId, 0) - m_cbcReferencePoint[cbcId][0])
18568 + POW2(m_solver->a_coordinate(cellId, 1) - m_cbcReferencePoint[cbcId][1])
18569 + POW2(m_solver->a_coordinate(cellId, 2) - m_cbcReferencePoint[cbcId][2]);
18570 un_target = F2 * massflux / m_cbcInflowArea[cbcId] * (F1 - rsquare / (A * A)) / un_correctionFactor;
18571 }
18572 else {
18573 MFloat rsquare = POW2((m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]));
18574 if(!solverProfile) {
18575 const MFloat mu = sysEqn().sutherlandLaw(temp);
18576 if(m_cbcViscous)
18577 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimT1] =
18578 -mu * F3B2 * massflux / (rho * A * A * A) * un_correctionFactor;
18579 }
18580 un_target = F3B4 * massflux / A * (1 - rsquare / (A * A)) * un_correctionFactor;
18581 if(solverProfile) {
18582 un_target = m_solver->m_UInfinity;
18583 }
18584 }
18585
18586 V.fill(F0);
18587 if(m_cbcViscous)
18588 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
18589 &cutOffStencilCellIds[0], &V[0]);
18590
18591 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
18592 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
18593 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
18594
18595 if(dirN % 2 == 0) {
18596 L[0] = K[0] * (p - p_Target) + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
18597 } else {
18598 L[last] = K[last] * (p - p_Target) + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
18599 }
18600
18601 L[1] = K[1] * (temp - T_target) + (a * a * T[0] - T[last]) - V[last];
18602 L[2] = K[2] * ut1 + T[2] + V[2];
18603 IF_CONSTEXPR(nDim == 3) {
18604 MInt dimT2 = m_cbcDir[cbcId][nDim];
18605 MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
18606 L[3] = K[3] * ut2 + T[3] + V[3];
18607 }
18608
18609 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
18610 m_solver->a_pvariable(cellId, PV->VV[dimN]) = un_target;
18611 }
18612}
18613
18614
18618template <MInt nDim, class SysEqn>
18620 TRACE();
18621
18622 MInt otherDir[2 * nDim];
18623 for(MInt dim = 0; dim < nDim; dim++) {
18624 otherDir[2 * dim] = 2 * dim + 1;
18625 otherDir[2 * dim + 1] = 2 * dim;
18626 }
18627
18628 MBool& first = m_static_cbc1091d_after_first;
18629 MInt& dirN = m_static_cbc1091d_after_dirN;
18630 MInt& dimN = m_static_cbc1091d_after_dimN;
18631 MInt& dimT1 = m_static_cbc1091d_after_dimT1;
18632 MInt& dimT2 = m_static_cbc1091d_after_dimT2;
18633
18634 if(first) {
18635 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
18636 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
18637 if(noCutOffDirections != noCutOffBndryIds) {
18638 mTerm(1, AT_,
18639 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
18640 }
18641 MInt cutOffBndryIdTmp, cutOffDirectionTmp;
18642 for(MInt i = 0; i < noCutOffBndryIds; i++) {
18643 cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
18644 cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
18645 if(cutOffBndryIdTmp == m_cutOffBndryCndIds[bcId]) {
18646 dirN = otherDir[cutOffDirectionTmp];
18647 break;
18648 }
18649 }
18650 dimN = (MInt)dirN / 2;
18651 dimT1 = (dimN + 1) % nDim;
18652 IF_CONSTEXPR(nDim == 3) dimT2 = (dimT1 + 1) % nDim;
18653
18654 first = false;
18655 }
18656
18657 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18658 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18659 if(m_solver->a_isHalo(cellId)) continue;
18660 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18661
18662 MInt bndryId = m_solver->a_bndryId(cellId);
18663
18664 if(bndryId > -1) {
18665 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) {
18666 continue;
18667 }
18668 }
18669
18670 // recompute the correct energy:
18671 MFloat rho = m_solver->a_variable(cellId, CV->RHO);
18672 MFloat u = m_solver->a_pvariable(cellId, PV->VV[dimN]);
18673 MFloat u_wrong = m_solver->a_variable(cellId, CV->RHO_VV[dimN]) / m_solver->a_variable(cellId, CV->RHO);
18674 MFloat v = m_solver->a_variable(cellId, CV->RHO_VV[dimT1]) / m_solver->a_variable(cellId, CV->RHO);
18675
18676 MFloat Sum_sq_u = u_wrong * u_wrong + v * v;
18677 MFloat E;
18678 IF_CONSTEXPR(nDim == 2) {
18679 MFloat p = sysEqn().pressure(rho, Sum_sq_u, m_solver->a_variable(cellId, CV->RHO_E));
18680 E = sysEqn().internalEnergy(p, rho, (u * u + v * v));
18681 }
18682 IF_CONSTEXPR(nDim == 3) {
18683 MFloat w = m_solver->a_variable(cellId, CV->RHO_VV[dimT2]) / m_solver->a_variable(cellId, CV->RHO);
18684 MFloat p = sysEqn().pressure(rho, Sum_sq_u, m_solver->a_variable(cellId, CV->RHO_E));
18685 Sum_sq_u += w * w;
18686 E = sysEqn().internalEnergy(p, rho, (u * u + v * v + w * w));
18687 }
18688 m_solver->a_variable(cellId, CV->RHO_VV[dimN]) = rho * u;
18689 m_solver->a_variable(cellId, CV->RHO_E) = E;
18690 }
18691}
18692
18699template <MInt nDim, class SysEqn>
18701 TRACE();
18702
18703 if(m_sortedCutOffCells[bcId]->size() == 0) {
18704 return;
18705 }
18706
18707 MInt cbcId = m_cbcBndryCndIds[bcId];
18708
18709 MInt dirN = m_cbcDir[cbcId][0];
18710 MInt dimN = m_cbcDir[cbcId][1];
18711 MInt dimT1 = m_cbcDir[cbcId][2];
18712 MInt dimT2 = m_cbcDir[cbcId][nDim];
18713
18714 MInt last = nDim + 1;
18715
18716 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
18717 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
18718 MFloatScratchSpace gradP(nDim, AT_, "gradP");
18719 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
18720 gradY.fill(F0);
18721
18722 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
18723 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
18724 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
18725 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
18726 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
18727
18728 MFloatScratchSpace L(PV->noVariables, AT_, "L");
18729 MFloatScratchSpace T(PV->noVariables, AT_, "T");
18730 MFloatScratchSpace V(PV->noVariables, AT_, "V");
18731 MFloatScratchSpace K(PV->noVariables, AT_, "K");
18732
18733 MFloat mach[2];
18734 cbcMachCo(bcId, mach);
18735 MFloat meanM = mach[0];
18736 MFloat maxM = mach[1];
18737
18738 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
18739 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
18740
18741 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18742 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18743
18744 if(m_solver->a_isHalo(cellId)) continue;
18745
18746 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
18747 V.fill(F0);
18748 if(m_cbcViscous) {
18749 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
18750 gradQ[dimN * nDim + dimN] = F0;
18751 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
18752 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
18753 cbcViscousTerms<(unsigned char)11111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
18754 &cutOffStencilCellIds[0], &V[0]);
18755 }
18756
18757 cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
18758 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
18759 cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
18760
18761 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
18762 MFloat p = m_solver->a_pvariable(cellId, PV->P);
18763 MFloat a = sysEqn().speedOfSound(rho, p);
18764 const MFloat targetPressure = m_solver->m_PInfinity - m_deltaPL;
18765
18766 MFloat beta = meanM;
18767 if(dirN % 2 == 0) {
18768 L[0] = -L[last] + (F1 - beta) * (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
18769 } else {
18770 L[last] = -L[0] + (F1 - beta) * (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
18771 }
18772 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
18773 m_solver->a_rightHandSide(cellId, CV->RHO_E) = 0.0;
18774 m_solver->a_pvariable(cellId, PV->P) = targetPressure;
18775 }
18776}
18777
18778
18782template <MInt nDim, class SysEqn>
18784 TRACE();
18785
18786 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18787 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18788
18789 if(m_solver->a_isHalo(cellId)) continue;
18790 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
18791 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18792
18793 MInt bndryId = m_solver->a_bndryId(cellId);
18794 if(bndryId > -1) {
18795 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
18796 }
18797
18798 // recompute the correct energy:
18799 MFloat rho = m_solver->a_variable(cellId, CV->RHO);
18800 MFloat u = m_solver->a_variable(cellId, CV->RHO_U) / rho;
18801 MFloat v = m_solver->a_variable(cellId, CV->RHO_V) / rho;
18802 MFloat p = m_solver->a_pvariable(cellId, PV->P);
18803 MFloat E = sysEqn().internalEnergy(p, rho, (u * u + v * v));
18804 IF_CONSTEXPR(nDim == 3) {
18805 MFloat w = m_solver->a_variable(cellId, CV->RHO_W) / rho;
18806 E = sysEqn().internalEnergy(p, rho, (u * u + v * v + w * w));
18807 }
18808
18809 m_solver->a_variable(cellId, CV->RHO_E) = E;
18810 }
18811}
18812
18819template <MInt nDim, class SysEqn>
18821 TRACE();
18822
18823 if(m_sortedCutOffCells[bcId]->size() == 0) {
18824 return;
18825 }
18826
18827 MInt cbcId = m_cbcBndryCndIds[bcId];
18828
18829 MInt dirN = m_cbcDir[cbcId][0];
18830 MInt dimN = m_cbcDir[cbcId][1];
18831 MInt dimT1 = m_cbcDir[cbcId][2];
18832 MInt dimT2 = m_cbcDir[cbcId][nDim];
18833
18834 MFloat& targetPressure = m_static_cbc1099_1091_local_targetPressure;
18835 MFloat& R = m_static_cbc1099_1091_local_R;
18836 MFloat& H = m_static_cbc1099_1091_local_H;
18837
18838 MFloat inflowArea = m_cbcInflowArea[cbcId];
18839 IF_CONSTEXPR(nDim == 3) { R = sqrt(inflowArea / PI); }
18840 IF_CONSTEXPR(nDim == 2) {
18841 targetPressure = sysEqn().p_Ref();
18842 H = inflowArea * F1B2;
18843 }
18844
18845 MInt last = nDim + 1;
18846 // MInt last = 4;
18847 if(last != 4) mTerm(1, AT_, "Last is not four!");
18848
18849 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
18850 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
18851 MFloatScratchSpace gradP(nDim, AT_, "gradP");
18852 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
18853 gradY.fill(F0);
18854
18855 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
18856 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
18857 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
18858 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
18859 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
18860
18861 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
18862 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
18863
18864 MFloatScratchSpace L(PV->noVariables, AT_, "L");
18865 MFloatScratchSpace T(PV->noVariables, AT_, "T");
18866 MFloatScratchSpace V(PV->noVariables, AT_, "V");
18867 MFloatScratchSpace K(PV->noVariables, AT_, "K");
18868
18869 MFloat massflux = F0;
18870 MFloat T_mean = F0;
18871 MFloat massflux_pos = F0;
18872 MFloat massflux_neg = F0;
18873
18874 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18875 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18876 MInt bndryId = m_solver->a_bndryId(cellId);
18877
18878 if(m_solver->a_isHalo(cellId)) continue;
18879 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
18880 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18881
18882 MFloat area = -1;
18883 if(bndryId > -1) {
18884 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
18885 if(srfcId > -1) {
18886 area = m_solver->a_surfaceArea(srfcId);
18887 IF_CONSTEXPR(nDim == 3) ASSERT(area <= POW2(m_solver->c_cellLengthAtCell(cellId)), "");
18888 } else {
18889 mTerm(1, AT_, "something went wrong!");
18890 }
18891 } else {
18892 IF_CONSTEXPR(nDim == 2) area = m_solver->c_cellLengthAtCell(cellId);
18893 IF_CONSTEXPR(nDim == 3) area = POW2(m_solver->c_cellLengthAtCell(cellId));
18894 }
18895
18896 ASSERT(area > -1, "");
18897 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
18898 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
18899 const MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
18900 const MFloat Temp = sysEqn().temperature_ES(rho, p);
18901 MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
18902 const MFloat un_N = m_solver->a_pvariable(nghbrN, PV->VV[dimN]);
18903
18904
18905 if(rho < F0 || std::isnan(rho) || std::isnan(un)) {
18906 cerr << "NAN detected in cutOff-Cell " << m_solver->c_globalId(cellId) << " " << m_solver->a_isHalo(cellId) << " "
18907 << m_solver->a_bndryId(cellId) << " " << rho << endl;
18908 }
18909
18910 if(un_N > F0) {
18911 massflux_pos += un_N * area;
18912 } else {
18913 massflux_neg += un_N * area;
18914 }
18915
18916 massflux += un_N * area * rho;
18917 T_mean += Temp * area;
18918 }
18919
18920 MFloat mach[2] = {F0, F0};
18921 cbcMachCo(bcId, mach);
18922 MFloat meanM = mach[0];
18923 MFloat maxM = mach[1];
18924
18925 MInt noExchangeData = 4;
18926 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
18927 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
18928 comm_buff[0] = massflux;
18929 comm_buff[1] = T_mean;
18930 comm_buff[2] = massflux_pos;
18931 comm_buff[3] = massflux_neg;
18932
18933 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 4, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
18934 AT_, "comm_buff[0]", "comm_buff_result[0]");
18935
18936 massflux = comm_buff_result[0];
18937 T_mean = comm_buff_result[1];
18938 massflux_pos = comm_buff_result[2];
18939 massflux_neg = comm_buff_result[3];
18940
18941 T_mean /= inflowArea;
18942
18943 const MFloat gammaMinusOne = m_solver->m_gamma - 1.0;
18944
18945 MFloat T_target = 1 - gammaMinusOne * F1B2 * (massflux * massflux / inflowArea / inflowArea);
18946 MFloat p_Target = sysEqn().pressure_IR(T_target);
18947
18948 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
18949 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
18950
18951 if(m_solver->a_isHalo(cellId)) continue;
18952 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
18953 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
18954
18955 MInt bndryId = m_solver->a_bndryId(cellId);
18956 if(bndryId > -1) {
18957 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
18958 }
18959
18960 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
18961 V.fill(F0);
18962 if(m_cbcViscous) {
18963 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
18964 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
18965 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
18966 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
18967 &cutOffStencilCellIds[0], &V[0]);
18968 }
18969
18970 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
18971
18972 // This is where you differentiate between inflow and outflow
18973 MFloat un_mean = m_solver->a_pvariable(cellId, PV->VV[dimN]);
18974
18975 MBool hasBndryNghbr = false;
18976 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
18977 MInt recNghbr = m_solver->a_reconstructionNeighborId(cellId, nghbr);
18978 if(m_solver->a_bndryId(recNghbr) > -1) hasBndryNghbr = true;
18979 }
18980
18981 MFloat massFluxSum = (abs(massflux_neg) + abs(massflux_pos));
18982 MFloat negMassFluxFactor = F0;
18983 MFloat posMassFluxFactor = F0;
18984 if(massFluxSum > m_solver->m_eps) {
18985 negMassFluxFactor = abs(massflux_neg) / massFluxSum;
18986 posMassFluxFactor = abs(massflux_pos) / massFluxSum;
18987 } else {
18988 if(dirN % 2 == 0) {
18989 negMassFluxFactor = F1;
18990 } else {
18991 posMassFluxFactor = F1;
18992 }
18993 }
18994
18995 MBool isInflow = true;
18996 if(dirN % 2 == 0) {
18997 if(un_mean > F0) {
18998 isInflow = false;
18999 } else {
19000 T_target = negMassFluxFactor * T_target + posMassFluxFactor * T_mean;
19001 }
19002 } else {
19003 if(un_mean < F0) {
19004 isInflow = false;
19005 } else {
19006 T_target = posMassFluxFactor * T_target + posMassFluxFactor * T_mean;
19007 }
19008 }
19009
19010 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
19011 const MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
19012 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
19013 MFloat a = sysEqn().speedOfSound(rho, p);
19014 const MFloat Temp = sysEqn().temperature_ES(rho, p);
19015
19016 if(isInflow) {
19017 targetPressure = p_Target;
19018 MFloat beta = F0;
19019
19020 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
19021 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
19022
19023 MFloat LN = 100;
19024 K[0] = K[0] * m_cbcLref[cbcId] / LN;
19025 K[1] = K[1] * m_cbcLref[cbcId] / LN;
19026 K[2] = K[2] * m_cbcLref[cbcId] / LN * 100;
19027 K[last] = K[last] * m_cbcLref[cbcId] / LN;
19028
19029 MFloat ceta = F1;
19030 if(dirN % 2 == 0)
19031 ceta = -F1;
19032 else
19033 ceta = F1;
19034
19035 // Timw: don't use BndryNghbr-correction!
19036 if((m_solver->a_bndryId(cellId) > -1 || hasBndryNghbr) && false) {
19037 if(dirN % 2 == 0) {
19038 L[0] = K[0] * (p - targetPressure);
19039 } else {
19040 L[last] = K[last] * (p - targetPressure);
19041 }
19042 L[1] = K[1] * (Temp - T_target);
19043 L[2] = K[2] * ut1;
19044 IF_CONSTEXPR(nDim == 3) {
19045 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
19046 L[3] = K[2] * ut2;
19047 }
19048 } else {
19049 if(dirN % 2 == 0) {
19050 L[0] = K[0] * (p - targetPressure) + (beta - 1) * (T[last] + ceta * rho * a * T[1])
19051 + (V[last] + ceta * rho * a * V[1]);
19052 } else {
19053 L[last] = K[last] * (p - targetPressure) + (beta - 1) * (T[last] + ceta * rho * a * T[1])
19054 + (V[last] + ceta * rho * a * V[1]);
19055 }
19056
19057 L[1] = K[1] * (Temp - T_target) - (a * a * T[0] - T[last]) + (a * a * V[0] - V[last]);
19058 L[2] = K[2] * ut1 - T[2] * 0.9;
19059 IF_CONSTEXPR(nDim == 3) {
19060 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
19061 K[3] = K[3] * m_cbcLref[cbcId] / LN * 100;
19062 L[3] = K[3] * ut2 - T[3] * 0.9;
19063 }
19064 }
19065 } else {
19066 targetPressure = sysEqn().p_Ref();
19067 MFloat beta = meanM;
19068
19069 cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
19070 cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
19071
19072 // for fv-mb: LN = 100.0
19073 MFloat LN = 100;
19074 K[0] = K[0] * m_cbcLref[cbcId] * m_sigmaNonRefl / LN;
19075 K[2] = m_cbcRelax[cbcId][2] * a / LN * 10;
19076
19077 MFloat ceta = F1;
19078 if(dirN % 2 == 0)
19079 ceta = -F1;
19080 else
19081 ceta = F1;
19082
19083 MFloat deltaP = (p - targetPressure);
19084 MFloat tmpP = sysEqn().pressure_ES(T_mean, rho) - targetPressure;
19085 if((m_solver->a_bndryId(cellId) > -1 || hasBndryNghbr)) {
19086 if(tmpP > deltaP) deltaP = tmpP;
19087 if(dirN % 2 == 0) // outflow on pos. coordinate direction -> L1 has to be modeled
19088 L[0] = K[0] * (deltaP);
19089 else
19090 L[last] = K[0] * (deltaP);
19091
19092 } else {
19093 if(tmpP > deltaP) deltaP = tmpP;
19094 if(dirN % 2 == 0) {
19095 L[0] = K[0] * (deltaP) + (beta - 1) * (T[last] + ceta * rho * a * T[1]) + (V[last] + ceta * rho * a * V[0]);
19096 } else {
19097 L[last] =
19098 K[0] * (deltaP) + (beta - 1) * (T[last] + ceta * rho * a * T[1]) + (V[last] + ceta * rho * a * V[1]);
19099 }
19100
19101 IF_CONSTEXPR(nDim == 3) {
19102 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
19103 L[2] += K[2] * ut1;
19104 L[3] += K[2] * ut2;
19105 }
19106 }
19107 }
19108 IF_CONSTEXPR(nDim == 3) {
19109 if((m_solver->a_bndryId(cellId) > -1 || hasBndryNghbr)) {
19110 T[0] = F0;
19111 T[1] = F0;
19112 T[2] = F0;
19113 T[3] = F0;
19114 T[last] = F0;
19115 V[0] = F0;
19116 V[1] = F0;
19117 V[2] = F0;
19118 V[3] = F0;
19119 V[last] = F0;
19120 }
19121 }
19122 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
19123 }
19124}
19125
19126
19132template <MInt nDim, class SysEqn>
19134 TRACE();
19135
19136 if(m_sortedCutOffCells[bcId]->size() == 0) {
19137 return;
19138 }
19139
19140 MInt cbcId = m_cbcBndryCndIds[bcId];
19141
19142 MInt dirN = m_cbcDir[cbcId][0];
19143 MInt dimN = m_cbcDir[cbcId][1];
19144 MInt dimT1 = m_cbcDir[cbcId][2];
19145 MInt dimT2 = m_cbcDir[cbcId][nDim];
19146
19147 MFloat outFlowArea = m_cbcInflowArea[cbcId];
19148
19149 MInt last = nDim + 1;
19150
19151 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
19152 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
19153 MFloatScratchSpace gradP(nDim, AT_, "gradP");
19154 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
19155 gradY.fill(F0);
19156
19157
19158 MFloatScratchSpace L(PV->noVariables, AT_, "L");
19159 MFloatScratchSpace T(PV->noVariables, AT_, "T");
19160 MFloatScratchSpace V(PV->noVariables, AT_, "V");
19161 MFloatScratchSpace K(PV->noVariables, AT_, "K");
19162
19163 MFloat massflux = F0;
19164 MFloat T_mean = F0;
19165 MFloat rho_mean = F0;
19166
19167 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
19168 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
19169 MInt bndryId = m_solver->a_bndryId(cellId);
19170
19171 if(m_solver->a_isHalo(cellId)) continue;
19172 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19173 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19174
19175 MFloat area;
19176 if(bndryId > -1) {
19177 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
19178 // cell
19179 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
19180 if(srfcId > -1) {
19181 area = m_solver->a_surfaceArea(srfcId);
19182 } else {
19183 mTerm(1, AT_, "something went wrong!");
19184 }
19185 } else {
19186 IF_CONSTEXPR(nDim == 3) area = POW2(m_solver->c_cellLengthAtCell(cellId));
19187 IF_CONSTEXPR(nDim == 2) area = m_solver->c_cellLengthAtCell(cellId);
19188 }
19189
19190 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
19191 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
19192 const MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
19193 const MFloat Temp = sysEqn().temperature_ES(rho, p);
19194
19195 massflux += un * area * rho;
19196 T_mean += Temp * area;
19197 IF_CONSTEXPR(nDim == 2) rho_mean += rho * area;
19198 }
19199
19200 MFloat mach[2] = {F0, F0};
19201 cbcMachCo(bcId, mach);
19202 MFloat meanM = mach[0];
19203 MFloat maxM = mach[1];
19204
19205 MInt noExchangeData = 2;
19206 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
19207 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
19208 comm_buff[0] = massflux;
19209 comm_buff[1] = T_mean;
19210
19211
19212 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 2, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
19213 AT_, "comm_buff[0]", "comm_buff_result[0]");
19214
19215 IF_CONSTEXPR(nDim == 2) {
19216 MPI_Allreduce(MPI_IN_PLACE, &rho_mean, 1, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
19217 "MPI_IN_PLACE", "rho_mean");
19218 rho_mean /= outFlowArea;
19219
19220 const MFloat gammaMinusOne = m_solver->m_gamma - 1.0;
19221 MFloat T_target = 1 - gammaMinusOne * F1B2 * (massflux * massflux / outFlowArea / outFlowArea);
19222 MFloat p_Target = sysEqn().pressure_ES(T_target, rho_mean);
19223 MFloat p_test = p_Target;
19224 for(MInt i = 0; i < 20; i++) {
19225 p_test = sysEqn().pressure_IRit(p_test, massflux);
19226 }
19227 m_solver->m_jetPressure = p_Target;
19228 m_solver->m_jetDensity = rho_mean; // gamma*p_Target/T_target;
19229 m_solver->m_jetTemperature = T_target;
19230 }
19231
19232 massflux = comm_buff_result[0];
19233 T_mean = comm_buff_result[1];
19234 T_mean /= outFlowArea;
19235
19236 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
19237 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
19238 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
19239 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
19240 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
19241
19242 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
19243 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
19244
19245 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
19246 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
19247
19248 if(m_solver->a_isHalo(cellId)) continue;
19249 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19250 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19251
19252 MInt bndryId = m_solver->a_bndryId(cellId);
19253 if(bndryId > -1) {
19254 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
19255 }
19256
19257 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
19258 V.fill(F0);
19259 if(m_cbcViscous) {
19260 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
19261 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
19262 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
19263 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
19264 &cutOffStencilCellIds[0], &V[0]);
19265 }
19266
19267 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
19268
19269 // This is where you differentiate between inflow and outflow
19270 MFloat un_mean = m_solver->a_pvariable(cellId, PV->VV[dimN]);
19271 MFloat T_target_new = 0.0;
19272
19273 MBool isInflow = true;
19274 if(dirN % 2 == 0) {
19275 if(un_mean > F0) {
19276 isInflow = false;
19277 } else {
19278 T_target_new = T_mean;
19279 }
19280 } else {
19281 if(un_mean < F0) {
19282 isInflow = false;
19283 } else {
19284 T_target_new = T_mean;
19285 }
19286 }
19287
19288 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
19289 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
19290 MFloat a = sysEqn().speedOfSound(rho, p);
19291 const MFloat Temp = sysEqn().temperature_ES(rho, p);
19292
19293 const MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
19294
19295 MFloat targetPressure;
19296
19297 if(isInflow) {
19298 targetPressure = 0.0;
19299 MFloat beta = F0;
19300
19301 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
19302 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
19303
19304 IF_CONSTEXPR(nDim == 3) {
19305 K[2] = K[2] * 100;
19306 K[3] = K[3] * 100;
19307 }
19308 K[last] = K[0];
19309
19310 MFloat ceta = F1;
19311 if(dirN % 2 == 0)
19312 ceta = -F1;
19313 else
19314 ceta = F1;
19315
19316 if(dirN % 2 == 0) {
19317 L[0] = K[0] * (p - targetPressure) + (beta - 1) * (T[last] + ceta * rho * a * T[1])
19318 + (V[last] + ceta * rho * a * V[1]);
19319 } else {
19320 L[last] = K[last] * (p - targetPressure) + (beta - 1) * (T[last] + ceta * rho * a * T[1])
19321 + (V[last] + ceta * rho * a * V[1]);
19322 }
19323
19324 L[1] = K[1] * (Temp - T_target_new) - (a * a * T[0] - T[last]) + (a * a * V[0] - V[last]);
19325 L[2] = K[2] * ut1;
19326 IF_CONSTEXPR(nDim == 3) {
19327 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
19328 L[3] = K[3] * ut2;
19329 }
19330 } else {
19331 targetPressure = sysEqn().p_Ref();
19332 MFloat beta = meanM;
19333
19334 cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
19335 cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
19336
19337 IF_CONSTEXPR(nDim == 3) {
19338 K[2] = K[2] * 100;
19339 K[3] = K[3] * 100;
19340 }
19341 K[0] = K[0] * m_sigmaNonRefl;
19342 K[last] = K[0];
19343
19344 MFloat ceta = F1;
19345 if(dirN % 2 == 0)
19346 ceta = -F1;
19347 else
19348 ceta = F1;
19349
19350 MFloat deltaP = (p - targetPressure);
19351
19352 if(dirN % 2 == 0) {
19353 L[0] = K[0] * (deltaP) + (beta - 1) * (T[last] + ceta * rho * a * T[1]) + (V[last] + ceta * rho * a * V[0]);
19354 } else {
19355 L[last] = K[0] * (deltaP) + (beta - 1) * (T[last] + ceta * rho * a * T[1]) + (V[last] + ceta * rho * a * V[1]);
19356 }
19357 L[2] = K[2] * ut1;
19358 IF_CONSTEXPR(nDim == 3) {
19359 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
19360 L[3] = K[2] * ut2;
19361 }
19362 }
19363 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
19364 }
19365}
19366
19367
19370template <MInt nDim, class SysEqn>
19372 TRACE();
19373
19374 const MInt noVars = PV->noVariables;
19375
19376 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
19377 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
19378
19379 // set the cut off slopes to zero
19380 for(MInt varId = 0; varId < noVars; varId++) {
19381 for(MInt i = 0; i < nDim; i++) {
19382 m_solver->a_slope(cellId, varId, i) = F0;
19383 }
19384 }
19385 }
19386}
19387
19388
19392template <MInt nDim, class SysEqn>
19393inline void FvBndryCndXD<nDim, SysEqn>::sbc1000(const MInt bcId /*, const MUint noSpecies_*/) {
19394 // TRACE();
19395 const MUint noVars = CV->noVariables; // 2 + nDim + noSpecies_ + m_solver->m_noRansEquations;
19396 const MInt* const RESTRICT sortedBndryIds = ALIGNED_I(m_sortedBndryCells->a);
19397 const MInt* const RESTRICT bndryCndIds = m_bndryCndIds;
19398 const FvBndryCell<nDim, SysEqn>* const bCells = m_bndryCells->a;
19399 const MInt firstBndryCell = m_bndryCndCells[bcId];
19400 const MInt lastBndryCell = m_bndryCndCells[bcId + 1];
19401
19402#ifdef _OPENMP
19403#pragma omp parallel for
19404#endif
19405 for(MInt id = firstBndryCell; id < lastBndryCell; ++id) {
19406 MInt bndryId = sortedBndryIds[id];
19407 MInt cellId = bCells[bndryId].m_cellId;
19408 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
19409 const MUint noSrfcs = bCells[bndryId].m_noSrfcs;
19410 const typename FvBndryCell<nDim, SysEqn>::BodySurface* const cellSurfaces = bCells[bndryId].m_srfcs[0];
19411 const typename FvBndryCell<nDim, SysEqn>::BodySurfaceVariables* const cellSurfaceVariables =
19412 m_bndryCells->a[bndryId].m_srfcVariables[0];
19413 for(MUint srfc = 0; srfc < noSrfcs; ++srfc) {
19414 if(cellSurfaces[srfc].m_bndryCndId == bndryCndIds[bcId]) {
19415 const MUint ghostCellId = cellSurfaceVariables[srfc].m_ghostCellId;
19416 MFloat* const RESTRICT ghostCellSlopes = ALIGNED_MF(&m_solver->a_slope(ghostCellId, 0, 0));
19417 const MFloat* const RESTRICT cellSlopes = ALIGNED_F(&m_solver->a_slope(cellId, 0, 0));
19418 // copy the slopes from the boundary cell to the ghost cell
19419 for(MUint varId = 0; varId < noVars; ++varId) {
19420 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
19421 ghostCellSlopes[varId * nDim + spaceId] = cellSlopes[varId * nDim + spaceId];
19422 }
19423 }
19424 }
19425 }
19426 }
19427 }
19428}
19429
19430
19433template <MInt nDim, class SysEqn>
19435 TRACE();
19436
19437 const MInt noVars = PV->noVariables;
19438 const MInt otherDir[6] = {1, 0, 3, 2, 5, 4};
19439
19440 MBool& first = m_static_sbc1000co_first;
19441 const MInt fixedMaxNoBndryCndIds = s_sbc1000co_fixedMaxNoBndryCndIds;
19442 MInt(&directions)[fixedMaxNoBndryCndIds] = m_static_sbc1000co_directions;
19443 if(first) { // TODO labels:FV move this to some initialization routine
19444 if(fixedMaxNoBndryCndIds < m_maxNoBndryCndIds) {
19445 mTerm(1, AT_, "fixedMaxNoBndryCndIds is too small. increase...");
19446 }
19447
19448 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
19449 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
19450 if(noCutOffDirections != noCutOffBndryIds) {
19451 mTerm(1, AT_,
19452 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
19453 }
19454 MInt cutOffBndryIdTmp, cutOffDirectionTmp;
19455 for(MInt bc = 0; bc < m_noCutOffBndryCndIds; bc++) {
19456 for(MInt i = 0; i < noCutOffBndryIds; i++) {
19457 cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
19458 cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
19459 if(cutOffBndryIdTmp == m_cutOffBndryCndIds[bc]) {
19460 directions[bc] = otherDir[cutOffDirectionTmp];
19461 break;
19462 }
19463 }
19464 }
19465
19466 first = false;
19467 }
19468 //---end of initialization
19469
19470 const MInt direction = directions[bcId];
19471
19472 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
19473 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
19474 MLong nghbrId = m_solver->c_neighborId(cellId, direction);
19475
19476 // continue if the neighbor does not exist -> happens on the second layer of halo cells
19477 if(nghbrId < 0) {
19478 TERMM_IF_NOT_COND(m_solver->a_isHalo(cellId), "Error: cell has no neighbor and is not a halo cell.");
19479 continue;
19480 }
19481
19482 if(m_solver->a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
19483
19484 if(m_solver->a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) {
19485 // copy the slopes from the boundary cell to the ghost cell
19486 for(MInt varId = 0; varId < noVars; varId++) {
19487 for(MInt i = 0; i < nDim; i++) {
19488 m_solver->a_slope(cellId, varId, i) = m_solver->a_slope(nghbrId, varId, i);
19489 }
19490 }
19491 }
19492 }
19493}
19494
19499template <MInt nDim, class SysEqn>
19501 TRACE();
19502
19503 MInt cellId;
19504 MInt ghostCellId = 0;
19505 const MInt noVars = PV->noVariables;
19506 //---end of initialization
19507
19508 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
19509 cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
19510 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
19511 ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[0]->m_ghostCellId;
19512
19513 // copy the slopes from the boundary cell to the ghost cell
19514 for(MInt varId = 0; varId < noVars; varId++) {
19515 m_solver->a_slope(ghostCellId, varId, 0) = m_solver->a_slope(cellId, varId, 0);
19516 m_solver->a_slope(ghostCellId, varId, 1) = -m_solver->a_slope(cellId, varId, 1);
19517 }
19518 }
19519 }
19520}
19521
19522
19529template <MInt nDim, class SysEqn>
19531 TRACE();
19532
19533 if(m_sortedCutOffCells[bcId]->size() == 0) {
19534 return;
19535 }
19536
19537 MInt cbcId = m_cbcBndryCndIds[bcId];
19538
19539 MInt dirN = m_cbcDir[cbcId][0];
19540 MInt dimN = m_cbcDir[cbcId][1];
19541 MInt dimT1 = m_cbcDir[cbcId][2];
19542
19543 MInt last = nDim + 1;
19544
19545 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
19546 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
19547 MFloatScratchSpace gradP(nDim, AT_, "gradP");
19548 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
19549 gradY.fill(F0);
19550
19551 MFloatScratchSpace L(PV->noVariables, AT_, "L");
19552 MFloatScratchSpace T(PV->noVariables, AT_, "T");
19553 MFloatScratchSpace V(PV->noVariables, AT_, "V");
19554 MFloatScratchSpace K(PV->noVariables, AT_, "K");
19555
19556 MFloat mach[2] = {F0, F0};
19557 cbcMachCo(bcId, mach);
19558 MFloat maxM = mach[1];
19559
19560 const MFloat gammaMinusOne = m_solver->m_gamma - 1.0;
19561
19562 MFloat T_target = sysEqn().temperature_IR(m_solver->m_Ma);
19563
19564 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
19565 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
19566
19567 if(m_solver->a_isHalo(cellId)) continue;
19568 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19569 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19570
19571 MInt bndryId = m_solver->a_bndryId(cellId);
19572
19573 if(bndryId > -1) {
19574 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
19575 }
19576
19577 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
19578 // labels:FV HACK
19579 gradVV[dimN * nDim + dimT1] = F0;
19580 gradVV[dimT1 * nDim + dimT1] = F0;
19581
19582 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
19583 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
19584
19585 cbcDampingInflow(cellId, bcId, maxM, &K[0], "velocity");
19586
19587 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
19588 MFloat p = m_solver->a_pvariable(cellId, PV->P);
19589 MFloat a = sysEqn().speedOfSound(rho, p);
19590
19591 MFloat un_target = m_solver->m_UInfinity;
19592 MFloat ut1_target = F0;
19593
19594 if(dirN % 2 == 0) {
19595 L[0] = L[last] + (T[last] - rho * a * T[1]);
19596 } else {
19597 L[last] = L[0] + (T[last] + rho * a * T[1]);
19598 }
19599
19600 L[1] = F1B2 * gammaMinusOne * (L[0] + L[last]) + (a * a * T[0] - T[last]);
19601
19602
19603 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
19604
19605 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimN]) = F0;
19606 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT1]) = F0;
19607 m_solver->a_rightHandSide(cellId, CV->RHO_E) = F0;
19608
19609 m_solver->a_pvariable(cellId, PV->VV[dimN]) = un_target;
19610 m_solver->a_pvariable(cellId, PV->VV[dimT1]) = ut1_target;
19611 m_solver->a_pvariable(cellId, PV->P) = T_target;
19612 }
19613}
19617template <MInt nDim, class SysEqn>
19619 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function cbc1091e_after is untested for 3D!"); }
19620 TRACE();
19621
19622 if(m_sortedCutOffCells[bcId]->size() == 0) return;
19623
19624 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
19625 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
19626
19627 if(m_solver->a_isHalo(cellId)) continue;
19628 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19629 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19630
19631 MInt bndryId = m_solver->a_bndryId(cellId);
19632
19633 if(bndryId > -1) {
19634 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
19635 }
19636
19637 // recompute the correct energy:
19638 MFloat rho = m_solver->a_variable(cellId, CV->RHO);
19639 MFloat u = m_solver->a_pvariable(cellId, PV->VV[0]);
19640 MFloat v = m_solver->a_pvariable(cellId, PV->VV[1]);
19641 MFloat T = m_solver->a_pvariable(cellId, PV->P);
19642 MFloat p = sysEqn().pressure_ES(T, rho);
19643 MFloat E = sysEqn().internalEnergy(p, rho, (u * u + v * v));
19644
19645 m_solver->a_variable(cellId, CV->RHO_VV[0]) = rho * u;
19646 m_solver->a_variable(cellId, CV->RHO_VV[1]) = rho * v;
19647 m_solver->a_variable(cellId, CV->RHO_E) = E;
19648 }
19649}
19650
19651
19655template <MInt nDim, class SysEqn>
19657 TRACE();
19658
19659 MInt cbcId = m_cbcBndryCndIds[bcId];
19660 MInt dirN = m_cbcDir[cbcId][0];
19661 MInt dimN = m_cbcDir[cbcId][1];
19662 MInt dimT1 = m_cbcDir[cbcId][2];
19663
19664 MFloat localMach[2] = {F0, F0};
19665
19666 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
19667 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
19668 MInt bndryId = m_solver->a_bndryId(cellId);
19669
19670 if(m_solver->a_isHalo(cellId)) continue;
19671 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19672 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19673 MFloat area = -1;
19674 if(bndryId > -1) {
19675 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
19676 if(srfcId > -1) {
19677 area = m_solver->a_surfaceArea(srfcId);
19678 IF_CONSTEXPR(nDim == 3) ASSERT(area <= POW2(m_solver->c_cellLengthAtCell(cellId)), "");
19679 } else {
19680 for(MInt dir = 0; dir < m_noDirs; dir++) {
19681 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dir];
19682 if(srfcId > -1) break;
19683 }
19684 if(srfcId == -1) {
19685 mTerm(1, AT_, "something went wrong!");
19686 }
19687 area = m_solver->a_surfaceArea(srfcId);
19688 }
19689 } else {
19690 IF_CONSTEXPR(nDim == 2) area = m_solver->c_cellLengthAtCell(cellId);
19691 IF_CONSTEXPR(nDim == 3) area = POW2(m_solver->c_cellLengthAtCell(cellId));
19692 }
19693
19694 area *= m_dirTangent[cbcId][dimT1];
19695
19696 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
19697 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
19698 const MFloat T = sysEqn().temperature_ES(rho, p);
19699 const MFloat a = sysEqn().speedOfSound(T);
19700
19701 MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]) * m_dirNormal[cbcId][dimN]
19702 + m_solver->a_pvariable(cellId, PV->VV[dimT1]) * m_dirNormal[cbcId][dimT1];
19703 IF_CONSTEXPR(nDim == 3) {
19704 MInt dimT2 = m_cbcDir[cbcId][nDim];
19705 un += m_solver->a_pvariable(cellId, PV->VV[dimT2]) * m_dirNormal[cbcId][dimT2];
19706 }
19707
19708 const MFloat M = fabs(un / a);
19709
19710 localMach[0] += fabs(M) * area;
19711 localMach[1] = mMax(localMach[1], M);
19712 }
19713
19714 MFloat globalMach[2] = {F0, F0};
19715
19716 if(m_solver->noDomains() > 1) {
19717 MPI_Allreduce(&localMach[0], &globalMach[0], 1, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
19718 "localMeanMach", "globalMeanMach");
19719 MPI_Allreduce(&localMach[1], &globalMach[1], 1, MPI_DOUBLE, MPI_MAX, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
19720 "localMaxMach", "globalMaxMach");
19721 }
19722
19723 MFloat inflowArea = m_cbcInflowArea[cbcId];
19724 globalMach[0] /= inflowArea;
19725
19726 mach[0] = globalMach[0];
19727 mach[1] = globalMach[1];
19728
19729 return;
19730}
19731
19732
19736template <MInt nDim, class SysEqn>
19737void FvBndryCndXD<nDim, SysEqn>::cbcTauQ(MInt bcId, MFloat* tau, MFloat* q, MInt* cutOffStencilCellIds) {
19738 TRACE();
19739
19740 auto index = [&](MInt dim0, MInt dim1, MInt dim2) { return dim0 * (nDim * nDim) + dim1 * nDim + dim2; };
19741
19742 MInt cbcId = m_cbcBndryCndIds[bcId];
19743
19744 MInt dimN = m_cbcDir[cbcId][1];
19745 MInt dimT1 = m_cbcDir[cbcId][2];
19746
19747 for(MInt i = 0; i < m_solver->maxNoGridCells(); i++) {
19748 cutOffStencilCellIds[i] = -1;
19749 }
19750
19751 MInt cellCounter = 0;
19752 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
19753 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
19754
19755 if(m_solver->a_isHalo(cellId)) continue;
19756 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19757 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19758
19759 MInt bndryId = m_solver->a_bndryId(cellId);
19760 if(bndryId > -1) {
19761 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
19762 }
19763
19764 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
19765 MFloat p = m_solver->a_pvariable(cellId, PV->P);
19766 MFloat T = sysEqn().temperature_ES(rho, p);
19767
19768 if(cutOffStencilCellIds[cellId] < 0) { // tau and q have not been computed yet
19769 MInt coId = cellCounter++;
19770 cutOffStencilCellIds[cellId] = coId;
19771
19772 MFloat dpdn = m_solver->a_slope(cellId, PV->P, dimN);
19773 MFloat dpdt1 = m_solver->a_slope(cellId, PV->P, dimT1);
19774 MFloat drhodn = m_solver->a_slope(cellId, PV->RHO, dimN);
19775 MFloat drhodt1 = m_solver->a_slope(cellId, PV->RHO, dimT1);
19776 MFloat dundn = m_solver->a_slope(cellId, PV->VV[dimN], dimN);
19777 MFloat dundt1 = m_solver->a_slope(cellId, PV->VV[dimN], dimT1);
19778 MFloat dut1dn = m_solver->a_slope(cellId, PV->VV[dimT1], dimN);
19779 MFloat dut1dt1 = m_solver->a_slope(cellId, PV->VV[dimT1], dimT1);
19780
19781 const MFloat mu = sysEqn().sutherlandLaw(T);
19782 MFloat divT = dundn + dut1dt1;
19783 IF_CONSTEXPR(nDim == 3) {
19784 MInt dimT2 = m_cbcDir[cbcId][nDim];
19785 MFloat dpdt2 = m_solver->a_slope(cellId, PV->P, dimT2);
19786 MFloat drhodt2 = m_solver->a_slope(cellId, PV->RHO, dimT2);
19787 MFloat dundt2 = m_solver->a_slope(cellId, PV->VV[dimN], dimT2);
19788 MFloat dut1dt2 = m_solver->a_slope(cellId, PV->VV[dimT1], dimT2);
19789 MFloat dut2dn = m_solver->a_slope(cellId, PV->VV[dimT2], dimN);
19790 MFloat dut2dt1 = m_solver->a_slope(cellId, PV->VV[dimT2], dimT1);
19791 MFloat dut2dt2 = m_solver->a_slope(cellId, PV->VV[dimT2], dimT2);
19792 divT = divT + dut2dt2;
19793
19794 tau[index(coId, dimN, dimT2)] = mu * (dundt2 + dut2dn);
19795 tau[index(coId, dimT2, dimN)] = tau[index(coId, dimN, dimT2)];
19796 tau[index(coId, dimT1, dimT2)] = mu * (dut1dt2 + dut2dt1);
19797 tau[index(coId, dimT2, dimT2)] = mu * (F2 * dut2dt2 - F2B3 * divT);
19798 tau[index(coId, dimT2, dimT1)] = tau[index(coId, dimT1, dimT2)];
19799
19800 q[index(0, coId, dimT2)] =
19801 mu * m_solver->m_gamma * sysEqn().cp_Ref() / (m_solver->m_Pr * rho) * (dpdt2 - p / rho * drhodt2);
19802 }
19803
19804 tau[index(coId, dimN, dimN)] = mu * (F2 * dundn - F2B3 * divT);
19805 tau[index(coId, dimN, dimT1)] = mu * (dundt1 + dut1dn);
19806 tau[index(coId, dimT1, dimN)] = tau[index(coId, dimN, dimT1)];
19807 tau[index(coId, dimT1, dimT1)] = mu * (F2 * dut1dt1 - F2B3 * divT);
19808
19809 q[index(0, coId, dimN)] =
19810 mu * m_solver->m_gamma * sysEqn().cp_Ref() / (m_solver->m_Pr * rho) * (dpdn - p / rho * drhodn);
19811 q[index(0, coId, dimT1)] =
19812 mu * m_solver->m_gamma * sysEqn().cp_Ref() / (m_solver->m_Pr * rho) * (dpdt1 - p / rho * drhodt1);
19813 }
19814
19815 for(MInt recN = 0; recN < m_solver->a_noReconstructionNeighbors(cellId); recN++) {
19816 MInt recNgbhr = m_solver->a_reconstructionNeighborId(cellId, recN);
19817 if(cutOffStencilCellIds[recNgbhr] < 0) {
19818 MInt coIdN = cellCounter++;
19819 cutOffStencilCellIds[recNgbhr] = coIdN;
19820 // compute shear tensor and heat flux on recNgbhr:
19821 MFloat pG = m_solver->a_pvariable(recNgbhr, PV->P);
19822 MFloat rhoG = m_solver->a_pvariable(recNgbhr, PV->RHO);
19823 MFloat TG = sysEqn().temperature_ES(rhoG, pG);
19824 MFloat muG = sysEqn().sutherlandLaw(TG);
19825 MFloat dpdnG = m_solver->a_slope(recNgbhr, PV->P, dimN);
19826 MFloat dpdt1G = m_solver->a_slope(recNgbhr, PV->P, dimT1);
19827 MFloat drhodnG = m_solver->a_slope(recNgbhr, PV->RHO, dimN);
19828 MFloat drhodt1G = m_solver->a_slope(recNgbhr, PV->RHO, dimT1);
19829 MFloat dundnG = m_solver->a_slope(recNgbhr, PV->VV[dimN], dimN);
19830 MFloat dundt1G = m_solver->a_slope(recNgbhr, PV->VV[dimN], dimT1);
19831 MFloat dut1dnG = m_solver->a_slope(recNgbhr, PV->VV[dimT1], dimN);
19832 MFloat dut1dt1G = m_solver->a_slope(recNgbhr, PV->VV[dimT1], dimT1);
19833
19834 MFloat divTG = dundnG + dut1dt1G;
19835
19836 IF_CONSTEXPR(nDim == 3) {
19837 MInt dimT2 = m_cbcDir[cbcId][nDim];
19838 MFloat dpdt2G = m_solver->a_slope(recNgbhr, PV->P, dimT2);
19839 MFloat drhodt2G = m_solver->a_slope(recNgbhr, PV->RHO, dimT2);
19840 MFloat dundt2G = m_solver->a_slope(recNgbhr, PV->VV[dimN], dimT2);
19841 MFloat dut1dt2G = m_solver->a_slope(recNgbhr, PV->VV[dimT1], dimT2);
19842 MFloat dut2dnG = m_solver->a_slope(recNgbhr, PV->VV[dimT2], dimN);
19843 MFloat dut2dt1G = m_solver->a_slope(recNgbhr, PV->VV[dimT2], dimT1);
19844 MFloat dut2dt2G = m_solver->a_slope(recNgbhr, PV->VV[dimT2], dimT2);
19845 divTG = divTG + dut2dt2G;
19846
19847 tau[index(coIdN, dimN, dimT2)] = muG * (dundt2G + dut2dnG);
19848 tau[index(coIdN, dimT2, dimN)] = tau[index(coIdN, dimN, dimT2)];
19849 tau[index(coIdN, dimT2, dimT2)] = muG * (2 * dut2dt2G - F2B3 * divTG);
19850 tau[index(coIdN, dimT1, dimT2)] = muG * (dut1dt2G + dut2dt1G);
19851 tau[index(coIdN, dimT2, dimT1)] = tau[index(coIdN, dimT1, dimT2)];
19852
19853 q[index(0, coIdN, dimT2)] =
19854 muG * m_solver->m_gamma * sysEqn().cp_Ref() / (m_solver->m_Pr * rhoG) * (dpdt2G - pG / rhoG * drhodt2G);
19855 }
19856
19857 tau[index(coIdN, dimN, dimN)] = muG * (F2 * dundnG - F2B3 * divTG);
19858 tau[index(coIdN, dimN, dimT1)] = muG * (dundt1G + dut1dnG);
19859 tau[index(coIdN, dimT1, dimN)] = tau[index(coIdN, dimN, dimT1)];
19860 tau[index(coIdN, dimT1, dimT1)] = muG * (2 * dut1dt1G - F2B3 * divTG);
19861
19862 q[index(0, coIdN, dimN)] =
19863 muG * m_solver->m_gamma * sysEqn().cp_Ref() / (m_solver->m_Pr * rhoG) * (dpdnG - pG / rhoG * drhodnG);
19864 q[index(0, coIdN, dimT1)] =
19865 muG * m_solver->m_gamma * sysEqn().cp_Ref() / (m_solver->m_Pr * rhoG) * (dpdt1G - pG / rhoG * drhodt1G);
19866 }
19867 }
19868 }
19869}
19870
19874template <MInt nDim, class SysEqn>
19876 MFloat* gradQ, MInt* cutOffStencilCellIds) {
19877 TRACE();
19878
19879 auto index = [&](MInt dim0, MInt dim1, MInt dim2) { return dim0 * (nDim * nDim) + dim1 * nDim + dim2; };
19880
19881 MInt cbcId = m_cbcBndryCndIds[bcId];
19882
19883 MInt dimN = m_cbcDir[cbcId][1];
19884 MInt dimT1 = m_cbcDir[cbcId][2];
19885
19886 MInt coId = cutOffStencilCellIds[cellId];
19887 MInt recData = m_solver->a_reconstructionData(cellId);
19888 for(MInt nghbr = 0; nghbr < m_solver->a_noReconstructionNeighbors(cellId); nghbr++) {
19889 MInt recNghbr = m_solver->a_reconstructionNeighborId(cellId, nghbr);
19890 MInt coIdN = cutOffStencilCellIds[recNghbr];
19891 for(MInt i = 0; i < nDim; i++) {
19892 MFloat recConst = m_solver->m_reconstructionConstants[nDim * (recData + nghbr) + i];
19893 gradTau[index(dimN, dimN, i)] += recConst * (tau[index(coIdN, dimN, dimN)] - tau[index(coId, dimN, dimN)]);
19894 gradTau[index(dimN, dimT1, i)] += recConst * (tau[index(coIdN, dimN, dimT1)] - tau[index(coId, dimN, dimT1)]);
19895 gradTau[index(dimT1, dimT1, i)] += recConst * (tau[index(coIdN, dimT1, dimT1)] - tau[index(coId, dimT1, dimT1)]);
19896 gradQ[index(0, dimN, i)] += recConst * (q[index(0, coIdN, dimN)] - q[index(0, coId, dimN)]);
19897 gradQ[index(0, dimT1, i)] += recConst * (q[index(0, coIdN, dimT1)] - q[index(0, coId, dimT1)]);
19898 IF_CONSTEXPR(nDim == 3) {
19899 MInt dimT2 = m_cbcDir[cbcId][nDim];
19900 gradTau[index(dimN, dimT2, i)] += recConst * (tau[index(coIdN, dimN, dimT2)] - tau[index(coId, dimN, dimT2)]);
19901 gradTau[index(dimT1, dimT2, i)] +=
19902 recConst * (tau[index(coIdN, dimT1, dimT2)] - tau[index(coId, dimT1, dimT2)]);
19903 gradTau[index(dimT2, dimT2, i)] +=
19904 recConst * (tau[index(coIdN, dimT2, dimT2)] - tau[index(coId, dimT2, dimT2)]);
19905 gradQ[index(0, dimT2, i)] += recConst * (q[index(0, coIdN, dimT2)] - q[index(0, coId, dimT2)]);
19906 }
19907 }
19908 }
19909}
19910
19911
19915template <MInt nDim, class SysEqn>
19916void FvBndryCndXD<nDim, SysEqn>::cbcGradients(MInt cellId, MInt bcId, MFloat* gradRho, MFloat* gradVV, MFloat* gradP,
19917 MFloat* gradY) {
19918 TRACE();
19919
19920 MInt cbcId = m_cbcBndryCndIds[bcId];
19921
19922 MInt dimN = m_cbcDir[cbcId][1];
19923 MInt dimT1 = m_cbcDir[cbcId][2];
19924 MInt dimT2 = m_cbcDir[cbcId][nDim];
19925
19926 gradRho[dimN] = m_solver->a_slope(cellId, PV->RHO, dimN) * m_dirNormal[cbcId][dimN]
19927 + m_solver->a_slope(cellId, PV->RHO, dimT1) * m_dirNormal[cbcId][dimT1];
19928 gradRho[dimT1] = m_solver->a_slope(cellId, PV->RHO, dimN) * m_dirTangent[cbcId][dimN]
19929 + m_solver->a_slope(cellId, PV->RHO, dimT1) * m_dirTangent[cbcId][dimT1];
19930
19931 gradVV[dimN * nDim + dimN] = m_solver->a_slope(cellId, PV->VV[dimN], dimN) * m_dirNormal[cbcId][dimN]
19932 + m_solver->a_slope(cellId, PV->VV[dimN], dimT1) * m_dirNormal[cbcId][dimT1];
19933 gradVV[dimN * nDim + dimT1] = m_solver->a_slope(cellId, PV->VV[dimN], dimN) * m_dirTangent[cbcId][dimN]
19934 + m_solver->a_slope(cellId, PV->VV[dimN], dimT1) * m_dirTangent[cbcId][dimT1];
19935 gradVV[dimT1 * nDim + dimN] = m_solver->a_slope(cellId, PV->VV[dimT1], dimN) * m_dirNormal[cbcId][dimN]
19936 + m_solver->a_slope(cellId, PV->VV[dimT1], dimT1) * m_dirNormal[cbcId][dimT1];
19937 gradVV[dimT1 * nDim + dimT1] = m_solver->a_slope(cellId, PV->VV[dimT1], dimN) * m_dirTangent[cbcId][dimN]
19938 + m_solver->a_slope(cellId, PV->VV[dimT1], dimT1) * m_dirTangent[cbcId][dimT1];
19939
19940 gradP[dimN] = m_solver->a_slope(cellId, PV->P, dimN) * m_dirNormal[cbcId][dimN]
19941 + m_solver->a_slope(cellId, PV->P, dimT1) * m_dirNormal[cbcId][dimT1];
19942 gradP[dimT1] = m_solver->a_slope(cellId, PV->P, dimN) * m_dirTangent[cbcId][dimN]
19943 + m_solver->a_slope(cellId, PV->P, dimT1) * m_dirTangent[cbcId][dimT1];
19944
19945 if(m_solver->m_noSpecies > 0) {
19946 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
19947 gradY[s * nDim + dimN] = m_solver->a_slope(cellId, PV->Y[s], dimN) * m_dirNormal[cbcId][dimN]
19948 + m_solver->a_slope(cellId, PV->Y[s], dimT1) * m_dirNormal[cbcId][dimT1];
19949 gradY[s * nDim + dimT1] = m_solver->a_slope(cellId, PV->Y[s], dimN) * m_dirTangent[cbcId][dimN]
19950 + m_solver->a_slope(cellId, PV->Y[s], dimT1) * m_dirNormal[cbcId][dimT1];
19951 }
19952 }
19953
19954 IF_CONSTEXPR(nDim == 3) {
19955 gradRho[dimN] += m_solver->a_slope(cellId, PV->RHO, dimT2) * m_dirNormal[cbcId][dimT2];
19956 gradRho[dimT1] += m_solver->a_slope(cellId, PV->RHO, dimT2) * m_dirTangent[cbcId][dimT2];
19957 gradRho[dimT2] = m_solver->a_slope(cellId, PV->RHO, dimT2);
19958
19959 gradVV[dimN * nDim + dimN] += m_solver->a_slope(cellId, PV->VV[dimN], dimT2) * m_dirNormal[cbcId][dimT2];
19960 gradVV[dimN * nDim + dimT1] += m_solver->a_slope(cellId, PV->VV[dimN], dimT2) * m_dirTangent[cbcId][dimT2];
19961 gradVV[dimN * nDim + dimT2] = m_solver->a_slope(cellId, PV->VV[dimN], dimT2);
19962 gradVV[dimT1 * nDim + dimN] += m_solver->a_slope(cellId, PV->VV[dimT1], dimT2) * m_dirNormal[cbcId][dimT2];
19963 gradVV[dimT1 * nDim + dimT1] += m_solver->a_slope(cellId, PV->VV[dimT1], dimT2) * m_dirTangent[cbcId][dimT2];
19964 gradVV[dimT1 * nDim + dimT2] = m_solver->a_slope(cellId, PV->VV[dimT1], dimT2);
19965 gradVV[dimT2 * nDim + dimN] = m_solver->a_slope(cellId, PV->VV[dimT2], dimN) * m_dirNormal[cbcId][dimN]
19966 + m_solver->a_slope(cellId, PV->VV[dimT2], dimT1) * m_dirNormal[cbcId][dimT1]
19967 + m_solver->a_slope(cellId, PV->VV[dimT2], dimT2) * m_dirNormal[cbcId][dimT2];
19968 gradVV[dimT2 * nDim + dimT1] = m_solver->a_slope(cellId, PV->VV[dimT2], dimN) * m_dirTangent[cbcId][dimN]
19969 + m_solver->a_slope(cellId, PV->VV[dimT2], dimT1) * m_dirTangent[cbcId][dimT1]
19970 + m_solver->a_slope(cellId, PV->VV[dimT2], dimT2) * m_dirTangent[cbcId][dimT2];
19971 gradVV[dimT2 * nDim + dimT2] = m_solver->a_slope(cellId, PV->VV[dimT2], dimT2);
19972
19973 gradP[dimN] += m_solver->a_slope(cellId, PV->P, dimT2) * m_dirNormal[cbcId][dimT2];
19974 gradP[dimT1] += m_solver->a_slope(cellId, PV->P, dimT2) * m_dirTangent[cbcId][dimT2];
19975 gradP[dimT2] = m_solver->a_slope(cellId, PV->P, dimT2);
19976 if(m_solver->m_noSpecies > 0) {
19977 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
19978 gradY[s * nDim + dimN] += m_solver->a_slope(cellId, PV->Y[s], dimT2) * m_dirNormal[cbcId][dimT2];
19979 gradY[s * nDim + dimT1] += m_solver->a_slope(cellId, PV->Y[s], dimT2) * m_dirTangent[cbcId][dimT2];
19980 gradY[s * nDim + dimT2] = m_solver->a_slope(cellId, PV->Y[s], dimT2);
19981 }
19982 }
19983 }
19984}
19985
19986
19992template <MInt nDim, class SysEqn>
19993template <MInt side>
19995 MFloat* gradP, MFloat* gradY, MFloat* L) {
19996 TRACE();
19997
19998 MInt cbcId = m_cbcBndryCndIds[bcId];
19999
20000 MInt dimN = m_cbcDir[cbcId][1];
20001 MInt dimT1 = m_cbcDir[cbcId][2];
20002 MInt dimT2 = m_cbcDir[cbcId][nDim];
20003
20004 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20005 MFloat un = F0;
20006 un = m_solver->a_pvariable(cellId, PV->VV[dimN]) * m_dirNormal[cbcId][dimN]
20007 + m_solver->a_pvariable(cellId, PV->VV[dimT1]) * m_dirNormal[cbcId][dimT1];
20008
20009 IF_CONSTEXPR(nDim == 3) { un += m_solver->a_pvariable(cellId, PV->VV[dimT2]) * m_dirNormal[cbcId][dimT2]; }
20010
20011 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20012 MFloat a = sysEqn().speedOfSound(rho, p);
20013
20014 MInt last = CV->noVariables - 1 - m_solver->m_noSpecies;
20015
20016 if(side == 1) {
20017 MFloat lambda1 = (un - a);
20018 MFloat lambda5 = (un + a);
20019 L[0] = lambda1 * (gradP[dimN] - rho * a * gradVV[dimN * nDim + dimN]);
20020 L[last] = lambda5 * (gradP[dimN] + rho * a * gradVV[dimN * nDim + dimN]);
20021 IF_CONSTEXPR(nDim == 3) { L[3] = un * (gradVV[dimT2 * nDim + dimN]); }
20022 } else if(side == 0) {
20023 MFloat lambda1 = (un - a);
20024 MFloat lambda2 = un;
20025 MFloat lambda5 = (un + a);
20026 L[0] = lambda1 * (gradP[dimN] - rho * a * gradVV[dimN * nDim + dimN]);
20027 L[1] = lambda2 * (a * a * gradRho[dimN] - gradP[dimN]);
20028 L[2] = lambda2 * (gradVV[dimT1 * nDim + dimN]);
20029 IF_CONSTEXPR(nDim == 3) { L[3] = lambda2 * (gradVV[dimT2 * nDim + dimN]); }
20030 L[last] = lambda5 * (gradP[dimN] + rho * a * gradVV[dimN * nDim + dimN]);
20031 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
20032 L[last + 1 + s] = lambda2 * gradY[s * nDim + dimN];
20033 }
20034 } else {
20035 mTerm(1, AT_, "Wrong template argument");
20036 }
20037}
20038
20039
20043template <MInt nDim, class SysEqn>
20044template <unsigned char tTerms>
20046 MFloat* gradP, MFloat* gradY, MFloat* T) {
20047 TRACE();
20048
20049 MInt cbcId = m_cbcBndryCndIds[bcId];
20050
20051 MInt dimN = m_cbcDir[cbcId][1];
20052 MInt dimT1 = m_cbcDir[cbcId][2];
20053 MInt dimT2 = m_cbcDir[cbcId][nDim];
20054
20055 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20056 MFloat ut1 = F0;
20057
20058 ut1 = m_solver->a_pvariable(cellId, PV->VV[dimN]) * m_dirTangent[cbcId][dimN]
20059 + m_solver->a_pvariable(cellId, PV->VV[dimT1]) * m_dirTangent[cbcId][dimT1];
20060
20061 MFloat ut2 = F0;
20062 IF_CONSTEXPR(nDim == 3) {
20063 ut1 += m_solver->a_pvariable(cellId, PV->VV[dimT2]) * m_dirTangent[cbcId][dimT2];
20064 ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
20065 }
20066
20067 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20068
20069 MInt last = CV->noVariables - 1 - m_solver->m_noSpecies;
20070
20071 if(tTerms & 1) {
20072 T[0] = -rho * gradVV[dimT1 * nDim + dimT1] - ut1 * gradRho[dimT1];
20073 IF_CONSTEXPR(nDim == 3) T[0] += (-rho * gradVV[dimT2 * nDim + dimT2] - ut2 * gradRho[dimT2]);
20074 }
20075
20076 if(tTerms & 2) {
20077 T[1] = -ut1 * gradVV[dimN * nDim + dimT1];
20078 IF_CONSTEXPR(nDim == 3) T[1] += (-ut2 * gradVV[dimN * nDim + dimT2]);
20079 }
20080
20081 if(tTerms & 3) {
20082 T[2] = -ut1 * gradVV[dimT1 * nDim + dimT1] - F1 / rho * gradP[dimT1];
20083 IF_CONSTEXPR(nDim == 3) T[2] += (-ut2 * gradVV[dimT1 * nDim + dimT2]);
20084 }
20085
20086 IF_CONSTEXPR(nDim == 3) {
20087 if(tTerms & 4) {
20088 T[3] = -ut1 * gradVV[dimT2 * nDim + dimT1] - ut2 * gradVV[dimT2 * nDim + dimT2] - F1 / rho * gradP[dimT2];
20089 }
20090 }
20091
20092 if(tTerms & 5) {
20093 T[last] = -ut1 * gradP[dimT1] - p * sysEqn().gamma_Ref() * gradVV[dimT1 * nDim + dimT1];
20094 IF_CONSTEXPR(nDim == 3) T[last] += (-ut2 * gradP[dimT2] - p * sysEqn().gamma_Ref() * gradVV[dimT2 * nDim + dimT2]);
20095 }
20096
20097 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
20098 T[last + 1 + s] = -ut1 * gradY[s * nDim + dimT1];
20099 IF_CONSTEXPR(nDim == 3) T[last + 1 + s] += -ut2 * gradY[s * nDim + dimT2];
20100 }
20101}
20102
20103
20104template <MInt nDim, class SysEqn>
20106 TRACE();
20107
20108 MInt cbcId = m_cbcBndryCndIds[bcId];
20109 MInt dirN = m_cbcDir[cbcId][0];
20110
20111 MFloat localMeanPressure = F0;
20112
20113 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
20114 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
20115 MInt bndryId = m_solver->a_bndryId(cellId);
20116
20117 if(m_solver->a_isHalo(cellId)) continue;
20118 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
20119 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
20120
20121 MFloat area;
20122 if(bndryId > -1) {
20123 // identify the "boundary surface" between cutoff boundary cell
20124 // and neighboring layer cell if cell is a boundary cell
20125 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
20126 if(srfcId > -1) {
20127 area = m_solver->a_surfaceArea(srfcId);
20128 } else {
20129 mTerm(1, AT_, "something went wrong!");
20130 }
20131 } else {
20132 area = m_solver->c_cellLengthAtCell(cellId);
20133#ifdef DIM3
20134 area = POW2(m_solver->c_cellLengthAtCell(cellId));
20135#endif
20136 }
20137
20138 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20139
20140 localMeanPressure += p * area;
20141 }
20142
20143 MFloat globalMeanPressure = F0;
20144
20145 MPI_Allreduce(&localMeanPressure, &globalMeanPressure, 1, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
20146 AT_, "localMeanPressure", "globalMeanPressure");
20147
20148 const MFloat inflowArea = m_cbcInflowArea[cbcId];
20149
20150 globalMeanPressure /= inflowArea;
20151 pressure[0] = globalMeanPressure;
20152 return;
20153}
20154
20158template <MInt nDim, class SysEqn>
20159template <unsigned char vTerms>
20161 MFloat* gradVV, MInt* cutOffStencilCellIds, MFloat* V) {
20162 TRACE();
20163
20164 auto index = [&](MInt dim0, MInt dim1, MInt dim2) { return dim0 * (nDim * nDim) + dim1 * nDim + dim2; };
20165
20166 // if ( m_solver->m_noSpecies > 0 ) mTerm(1, AT_, "Species not yet supported!");
20167
20168 MInt coId = cutOffStencilCellIds[cellId];
20169
20170 MInt cbcId = m_cbcBndryCndIds[bcId];
20171
20172 MInt dimN = m_cbcDir[cbcId][1];
20173 MInt dimT1 = m_cbcDir[cbcId][2];
20174 MInt dimT2 = m_cbcDir[cbcId][nDim];
20175
20176 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20177 MInt last = CV->noVariables - 1 - m_solver->m_noSpecies;
20178 // MInt last = 4;
20179 if(last != 4) mTerm(1, AT_, "last is not four!");
20180
20181 if(vTerms & 2) {
20182 MFloat Sum_dtaun = gradTau[index(dimN, dimN, dimN)] + gradTau[index(dimN, dimT1, dimT1)];
20183 IF_CONSTEXPR(nDim == 3) { Sum_dtaun += gradTau[index(dimN, dimT2, dimT2)]; }
20184 V[1] = F1 / (sysEqn().m_Re0 * rho) * (Sum_dtaun);
20185 }
20186
20187 if(vTerms & 3) {
20188 MFloat Sum_dtaut = gradTau[index(dimT1, dimT1, dimT1)];
20189 IF_CONSTEXPR(nDim == 3) { Sum_dtaut += gradTau[index(dimT1, dimT2, +dimT2)]; }
20190 V[2] = F1 / (sysEqn().m_Re0 * rho) * (Sum_dtaut);
20191 }
20192
20193 IF_CONSTEXPR(nDim == 3) {
20194 if(vTerms & 4) {
20195 V[3] = F1 / (sysEqn().m_Re0 * rho) * (gradTau[index(dimT1, dimT2, dimT1)] + gradTau[index(dimT2, dimT2, dimT2)]);
20196 }
20197 }
20198
20199 if(vTerms & 5) {
20200 MFloat Sum_d_for_V5 =
20201 tau[index(coId, dimN, dimN)] * gradVV[index(0, dimN, dimN)]
20202 + tau[index(coId, dimN, dimT1)] * (gradVV[index(0, dimT1, dimN)] + gradVV[index(0, dimN, dimT1)])
20203 + tau[index(coId, dimT1, dimT1)] * gradVV[index(0, dimT1, dimT1)] + gradQ[index(0, dimT1, dimT1)];
20204
20205 IF_CONSTEXPR(nDim == 3) {
20206 Sum_d_for_V5 +=
20207 tau[index(coId, dimN, dimT2)] * (gradVV[index(0, dimT2, dimN)] + gradVV[index(0, dimN, dimT2)])
20208 + tau[index(coId, dimT2, dimT2)] * gradVV[index(0, dimT2, dimT2)]
20209 + tau[index(coId, dimT1, dimT2)] * (gradVV[index(0, dimT1, dimT2)] + gradVV[index(0, dimT2, dimT1)])
20210 + gradQ[index(0, dimT2, dimT2)];
20211 }
20212 V[last] = Sum_d_for_V5 / sysEqn().cp_Ref() / sysEqn().m_Re0;
20213 }
20214}
20215
20216
20220template <MInt nDim, class SysEqn>
20222 MString prescribedVariable) {
20223 TRACE();
20224
20225 MInt cbcId = m_cbcBndryCndIds[bcId];
20226 MInt dirN = m_cbcDir[cbcId][0];
20227 MInt last = CV->noVariables - 1 - m_solver->m_noSpecies;
20228
20229 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20230 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20231 MFloat a = sysEqn().speedOfSound(rho, p);
20232
20233 if(dirN % 2 == 0) {
20234 if(prescribedVariable == "velocity") {
20235 K[0] = m_cbcRelax[cbcId][0] * rho * a * a * (1 - maxM * maxM) / m_cbcLref[cbcId];
20236 } else if(prescribedVariable == "pressure") {
20237 K[0] = m_cbcRelax[cbcId][0] * rho * a * (1 - maxM * maxM) / m_cbcLref[cbcId];
20238 } else {
20239 TERMM(-1, "INFO: no prescribed variable set in cbcDampingInflow");
20240 }
20241 K[last] = m_cbcRelax[cbcId][last] * rho * a * a * (1 - maxM * maxM) / m_cbcLref[cbcId];
20242 } else {
20243 if(prescribedVariable == "velocity") {
20244 K[last] = m_cbcRelax[cbcId][last] * rho * a * a * (1 - maxM * maxM) / m_cbcLref[cbcId];
20245 } else if(prescribedVariable == "pressure") {
20246 K[last] = m_cbcRelax[cbcId][last] * rho * a * (1 - maxM * maxM) / m_cbcLref[cbcId];
20247 } else {
20248 TERMM(-1, "INFO: no prescribed variable set in cbcDampingInflow");
20249 }
20250 K[0] = m_cbcRelax[cbcId][0] * rho * a * a * (1 - maxM * maxM) / m_cbcLref[cbcId];
20251 }
20252
20253 K[1] = m_cbcRelax[cbcId][1] * rho * a / (m_cbcLref[cbcId]);
20254
20255 // needed because of non-dimensionalization (correction for detailed chemistry)
20256 IF_CONSTEXPR(isDetChem<SysEqn>)
20257 K[1] = m_cbcRelax[cbcId][1] * rho * a * m_solver->m_gasConstant
20258 / (m_cbcLref[cbcId] * m_solver->a_avariable(cellId, AV->W_MEAN));
20259
20260 K[2] = m_cbcRelax[cbcId][2] * a / m_cbcLref[cbcId];
20261 IF_CONSTEXPR(nDim == 3) { K[3] = m_cbcRelax[cbcId][3] * a / m_cbcLref[cbcId]; }
20262
20263 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
20264 K[last + 1 + s] = m_cbcRelax[cbcId][last + 1 + s] * a / m_cbcLref[cbcId];
20265 }
20266}
20267
20268
20272template <MInt nDim, class SysEqn>
20274 TRACE();
20275
20276 MInt cbcId = m_cbcBndryCndIds[bcId];
20277 MInt last = CV->noVariables - 1 - m_solver->m_noSpecies;
20278
20279 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20280 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20281 MFloat a = sysEqn().speedOfSound(rho, p);
20282
20283 K[0] = m_cbcRelax[cbcId][0] * a * (F1 - maxM * maxM) / m_cbcLref[cbcId];
20284 K[last] = K[0];
20285}
20286
20290template <MInt nDim, class SysEqn>
20292 TRACE();
20293
20294 MInt last = CV->noVariables - 1 - m_solver->m_noSpecies;
20295
20296 MInt cbcId = m_cbcBndryCndIds[bcId];
20297
20298 MInt dimN = m_cbcDir[cbcId][1];
20299 MInt dimT1 = m_cbcDir[cbcId][2];
20300
20301 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20302 MFloat un = F0;
20303 MFloat ut1 = F0;
20304
20305 un = m_solver->a_pvariable(cellId, PV->VV[dimN]) * m_dirNormal[cbcId][dimN]
20306 + m_solver->a_pvariable(cellId, PV->VV[dimT1]) * m_dirNormal[cbcId][dimT1];
20307 ut1 = m_solver->a_pvariable(cellId, PV->VV[dimN]) * m_dirTangent[cbcId][dimN]
20308 + m_solver->a_pvariable(cellId, PV->VV[dimT1]) * m_dirTangent[cbcId][dimT1];
20309
20310 MFloat ut2 = F0;
20311 IF_CONSTEXPR(nDim == 3) {
20312 MInt dimT2 = m_cbcDir[cbcId][nDim];
20313 un += m_solver->a_pvariable(cellId, PV->VV[dimT2]) * m_dirNormal[cbcId][dimT2];
20314 ut1 += m_solver->a_pvariable(cellId, PV->VV[dimT2]) * m_dirTangent[cbcId][dimT2];
20315 ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
20316 }
20317
20318 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20319 MFloat a = sysEqn().speedOfSound(rho, p);
20320
20321 MFloat sumOfVVSquared = POW2(un) + POW2(ut1);
20322 IF_CONSTEXPR(nDim == 3) sumOfVVSquared += POW2(ut2);
20323
20324 MFloat d1 = m_dirNormal[cbcId][dimN] * F1 / (a * a) * L[1] + m_dirNormal[cbcId][dimT1] * L[3]
20325 + F1B2 * F1 / (a * a) * (L[last] + L[0]);
20326 MFloat d2 = m_dirNormal[cbcId][dimN] * (F1B2 / (rho * a) * (L[last] - L[0])) - m_dirNormal[cbcId][dimT1] * L[2];
20327 MFloat d3 = m_dirNormal[cbcId][dimN] * L[2] + m_dirNormal[cbcId][dimT1] * (F1B2 / (rho * a) * (L[last] - L[0]));
20328 IF_CONSTEXPR(nDim == 3) {
20329 MInt dimT2 = m_cbcDir[cbcId][nDim];
20330 d1 -= m_dirNormal[cbcId][dimT2] * L[2];
20331 d2 -= m_dirNormal[cbcId][dimT2] * L[3];
20332 d3 += m_dirNormal[cbcId][dimT2] * F1 / (a * a) * L[1];
20333 }
20334 MFloat d5 = F1B2 * (L[last] + L[0]);
20335
20336 std::vector<MFloat> dSpecies;
20337 std::vector<MFloat> rhs_rhoY;
20338 dSpecies.resize(m_solver->m_noSpecies);
20339 rhs_rhoY.resize(m_solver->m_noSpecies);
20340
20341 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
20342 dSpecies[s] = L[last + 1 + s];
20343 }
20344
20345 MFloat rhs_rho = -d1 + T[0] + V[0];
20346 MFloat rhs_rhoun = un * (-d1 + T[0] + V[0]) + rho * (-d2 + T[1] + V[1]);
20347 MFloat rhs_rhout1 = ut1 * (-d1 + T[0] + V[0]) + rho * (-d3 + T[2] + V[2]);
20348 MFloat rhs_rhoe = F1B2 * sumOfVVSquared * (-d1 + T[0] + V[0]) + rho * un * (-d2 + T[1] + V[1])
20349 + rho * ut1 * (-d3 + T[2] + V[2]) + sysEqn().cp_Ref() * (-d5 + T[last] + V[last]);
20350
20351 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
20352 rhs_rhoY[s] = m_solver->a_pvariable(cellId, PV->Y[s]) * (-d1 + T[0]) + rho * (-dSpecies[s] + T[last + 1 + s]);
20353 }
20354
20355 IF_CONSTEXPR(nDim == 3) {
20356 MInt dimT2 = m_cbcDir[cbcId][nDim];
20357 MFloat d4 = m_dirNormal[cbcId][dimN] * L[3] + m_dirNormal[cbcId][dimT2] * (F1B2 / (rho * a) * (L[last] - L[0]))
20358 - m_dirNormal[cbcId][dimT1] * F1 / (a * a) * L[1];
20359 MFloat rhs_rhout2 = ut2 * (-d1 + T[0] + V[0]) + rho * (-d4 + T[3] + V[3]);
20360 rhs_rhoe += rho * ut2 * (-d4 + T[3] + V[3]);
20361
20362 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT2]) = -m_solver->a_cellVolume(cellId) * rhs_rhout2;
20363 }
20364
20365 m_solver->a_rightHandSide(cellId, CV->RHO) = -m_solver->a_cellVolume(cellId) * rhs_rho;
20366 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimN]) = -m_solver->a_cellVolume(cellId) * rhs_rhoun;
20367 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT1]) = -m_solver->a_cellVolume(cellId) * rhs_rhout1;
20368 m_solver->a_rightHandSide(cellId, CV->RHO_E) = -m_solver->a_cellVolume(cellId) * rhs_rhoe;
20369
20370 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
20371 m_solver->a_rightHandSide(cellId, CV->RHO_Y[s]) -= m_solver->a_cellVolume(cellId) * rhs_rhoY[s];
20372 }
20373}
20374
20375
20380template <MInt nDim, class SysEqn>
20381void FvBndryCndXD<nDim, SysEqn>::cbcTurbulenceInjection(MInt cellId, MFloat* L_turbulent, MInt sortedCutOffCellId) {
20382 TRACE();
20383
20384 IF_CONSTEXPR(nDim != 3) mTerm(1, AT_, "Only implemented for nDim = 3");
20385
20386 MFloat dummyTime;
20387 MFloat that, twopioverlb;
20388
20389 MFloat xhat, yhat, zhat;
20390 MFloat fluctChol[3];
20391
20392 // calculate fluctuation from time step previous to restart
20393 if(m_solver->m_restart && globalTimeStep == m_solver->m_restartTimeStep + 1) {
20394 dummyTime = (m_solver->m_time - m_solver->m_timeStep) / m_bc1601->m_tau_b;
20395 m_bc1601->checkRegeneration(dummyTime);
20396
20397 that = F2 * PI * dummyTime;
20398 twopioverlb = F2 * PI / m_bc1601->m_l_b;
20399
20400 xhat = twopioverlb * m_solver->a_coordinate(cellId, 0);
20401 yhat = twopioverlb * m_solver->a_coordinate(cellId, 1);
20402 zhat = twopioverlb * m_solver->a_coordinate(cellId, 2);
20403
20404 m_bc1601->calculateFlucts(that, xhat, yhat, zhat, fluctChol);
20405
20406 m_oldFluctChol[sortedCutOffCellId][0] = fluctChol[0];
20407 m_oldFluctChol[sortedCutOffCellId][1] = fluctChol[1];
20408 IF_CONSTEXPR(nDim == 3) m_oldFluctChol[sortedCutOffCellId][2] = fluctChol[2];
20409 }
20410
20411 dummyTime = m_solver->m_time / m_bc1601->m_tau_b;
20412 m_bc1601->checkRegeneration(dummyTime);
20413
20414 that = F2 * PI * dummyTime;
20415 twopioverlb = F2 * PI / m_bc1601->m_l_b;
20416
20417 xhat = twopioverlb * m_solver->a_coordinate(cellId, 0);
20418 yhat = twopioverlb * m_solver->a_coordinate(cellId, 1);
20419 zhat = twopioverlb * m_solver->a_coordinate(cellId, 2);
20420
20421 m_bc1601->calculateFlucts(that, xhat, yhat, zhat, fluctChol);
20422
20423 MFloat dFluctCholndn =
20424 (fluctChol[0] - m_oldFluctChol[sortedCutOffCellId][0]) / (m_solver->c_cellLengthAtCell(cellId));
20425 MFloat dFluctCholt1dn =
20426 (fluctChol[1] - m_oldFluctChol[sortedCutOffCellId][1]) / (m_solver->c_cellLengthAtCell(cellId));
20427
20428 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20429 MFloat a = sysEqn().speedOfSound(rho, m_solver->a_pvariable(cellId, PV->P));
20430
20431 L_turbulent[0] = rho * a * m_solver->m_UInfinity * dFluctCholndn;
20432 L_turbulent[1] = rho * a * m_solver->m_UInfinity * dFluctCholt1dn;
20433 IF_CONSTEXPR(nDim == 3) {
20434 MFloat dFluctCholt2dn =
20435 (fluctChol[2] - m_oldFluctChol[sortedCutOffCellId][2]) / (m_solver->c_cellLengthAtCell(cellId));
20436 L_turbulent[2] = rho * a * m_solver->m_UInfinity * dFluctCholt2dn;
20437 }
20438
20439 if(m_solver->m_RKStep == m_solver->m_noRKSteps - 1) {
20440 m_oldFluctChol[sortedCutOffCellId][0] = fluctChol[0];
20441 m_oldFluctChol[sortedCutOffCellId][1] = fluctChol[1];
20442 IF_CONSTEXPR(nDim == 3) m_oldFluctChol[sortedCutOffCellId][2] = fluctChol[2];
20443 }
20444
20445 return;
20446}
20447
20448
20456template <MInt nDim, class SysEqn>
20458 TRACE();
20459
20460 if(m_sortedCutOffCells[bcId]->size() == 0) {
20461 return;
20462 }
20463
20464 MInt cbcId = m_cbcBndryCndIds[bcId];
20465
20466 MInt dirN = m_cbcDir[cbcId][0];
20467 MInt dimN = m_cbcDir[cbcId][1];
20468 MInt dimT1 = m_cbcDir[cbcId][2];
20469 MInt dimT2 = m_cbcDir[cbcId][nDim];
20470
20471 MInt last = nDim + 1;
20472
20473 // Allocate meomry
20474 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
20475 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
20476 MFloatScratchSpace gradP(nDim, AT_, "gradP");
20477 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
20478 gradY.fill(F0);
20479
20480 MFloatScratchSpace L(PV->noVariables, AT_, "L");
20481 MFloatScratchSpace T(PV->noVariables, AT_, "T");
20482 MFloatScratchSpace V(PV->noVariables, AT_, "V");
20483 MFloatScratchSpace K(PV->noVariables, AT_, "K");
20484
20485 MFloat mach[2] = {F0, F0};
20486 cbcMachCo(bcId, mach);
20487 MFloat meanM = mach[0];
20488 MFloat maxM = mach[1];
20489 maxM = F0;
20490
20491 if(m_cbcTurbulence) m_cbcViscous = false;
20492
20493 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
20494 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
20495 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
20496 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
20497 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
20498
20499 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
20500 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
20501
20502 MFloat T_target = sysEqn().temperature_IR(meanM);
20503 IF_CONSTEXPR(isDetChem<SysEqn>) T_target = m_solver->m_detChem.infTemperature;
20504
20505 // BC specific start
20506 MBool solverProfile = false;
20507 solverProfile = Context::getSolverProperty<MBool>("solverProfile", m_solverId, AT_, &solverProfile);
20508 MFloat A = F0;
20509 IF_CONSTEXPR(nDim == 3) { A = sqrt(m_cbcInflowArea[cbcId] / PI); }
20510 else {
20511 A = m_cbcInflowArea[cbcId] * F1B2;
20512 }
20513 MFloat testSum2 = F0;
20514 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
20515 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
20516 if(m_solver->a_isHalo(cellId)) continue;
20517 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
20518 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
20519 MInt bndryId = m_solver->a_bndryId(cellId);
20520
20521 MFloat area;
20522 if(bndryId > -1) {
20523 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
20524 if(srfcId > -1) {
20525 area = m_solver->a_surfaceArea(srfcId);
20526 } else {
20527 mTerm(1, AT_, "something went wrong!");
20528 }
20529 } else {
20530 IF_CONSTEXPR(nDim == 2) area = m_solver->c_cellLengthAtCell(cellId);
20531 IF_CONSTEXPR(nDim == 3) area = POW2(m_solver->c_cellLengthAtCell(cellId));
20532 }
20533
20534 area *= m_dirTangent[cbcId][m_cbcDir[cbcId][2]];
20535
20536 MFloat rsquare;
20537 IF_CONSTEXPR(nDim == 2) {
20538 rsquare = POW2((m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]));
20539 }
20540 else {
20541 rsquare = POW2(m_solver->a_coordinate(cellId, 0) - m_cbcReferencePoint[cbcId][0])
20542 + POW2(m_solver->a_coordinate(cellId, 1) - m_cbcReferencePoint[cbcId][1])
20543 + POW2(m_solver->a_coordinate(cellId, 2) - m_cbcReferencePoint[cbcId][2]);
20544 }
20545 testSum2 += area * rsquare;
20546 }
20547
20548 MInt noExchangeData = 1;
20549 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
20550 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
20551 comm_buff[0] = testSum2;
20552
20553 if(noDomains() > 1) {
20554 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 1, MPI_DOUBLE, MPI_MAX, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
20555 AT_, "comm_buff[0]", "comm_buff_result[0]");
20556 }
20557
20558 testSum2 = comm_buff_result[0];
20559
20560 MFloat massflux_test;
20561 IF_CONSTEXPR(nDim == 2) { massflux_test = F3B4 / A * (m_cbcInflowArea[cbcId] - F1 / (A * A) * testSum2); }
20562 else {
20563 massflux_test = F2 * (F1 - testSum2 / (m_cbcInflowArea[cbcId] * A * A));
20564 }
20565 MFloat un_correctionFactor = F1;
20566 if(fabs(massflux_test) > m_solver->m_eps) {
20567 un_correctionFactor = F1 / massflux_test;
20568 }
20569
20570 MFloat massflux_target;
20571 IF_CONSTEXPR(nDim == 2) {
20572 massflux_target = m_solver->m_UInfinity * m_cbcInflowArea[cbcId]
20573 * sysEqn().density_ES(m_solver->m_PInfinity, m_solver->m_TInfinity);
20574 IF_CONSTEXPR(isDetChem<SysEqn>) {
20575 massflux_target = m_solver->m_VInfinity * m_cbcInflowArea[cbcId] * m_solver->m_rhoInfinity;
20576 }
20577 }
20578 // fvmbbndrycnd3d uses m_UInfinity instead!
20579 IF_CONSTEXPR(nDim == 3) {
20580 massflux_target = m_solver->m_VInfinity * m_cbcInflowArea[cbcId]
20581 * sysEqn().density_ES(m_solver->m_PInfinity, m_solver->m_TInfinity);
20582 }
20583 // BC specific end
20584
20585 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
20586 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
20587
20588 if(m_solver->a_isHalo(cellId)) continue;
20589 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
20590 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
20591
20592 MInt bndryId = m_solver->a_bndryId(cellId);
20593
20594 if(bndryId > -1) {
20595 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
20596 }
20597
20598 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
20599 V.fill(F0);
20600 if(m_cbcViscous) {
20601 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
20602 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
20603 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
20604 V.fill(F0);
20605 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
20606 &cutOffStencilCellIds[0], &V[0]);
20607 }
20608
20609 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
20610 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
20611 cbcDampingInflow(cellId, bcId, maxM, &K[0], "velocity");
20612
20613 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20614 MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
20615 MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
20616 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20617 MFloat temp = sysEqn().temperature_ES(rho, p);
20618
20619 IF_CONSTEXPR(isDetChem<SysEqn>) {
20620 MFloat fMeanMolarWeight = F0;
20621 for(MUint s = 0; s < PV->m_noSpecies; s++) {
20622 fMeanMolarWeight += m_solver->a_pvariable(cellId, PV->Y[s]) * m_solver->m_fMolarMass[s];
20623 }
20624 MFloat meanMolarWeight = F1 / fMeanMolarWeight;
20625 temp = p / rho * meanMolarWeight / m_solver->m_gasConstant;
20626 }
20627
20628 MFloat a = sysEqn().speedOfSound(rho, p);
20629 IF_CONSTEXPR(isDetChem<SysEqn>) a = sqrt(m_solver->a_avariable(cellId, m_solver->AV->GAMMA) * p / rho);
20630
20631 // BC specific start
20632 MFloat rsquare;
20633 MFloat un_target;
20634 IF_CONSTEXPR(nDim == 2) {
20635 rsquare = POW2((m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]));
20636 un_target = F3B4 * massflux_target / rho / A * (1 - rsquare / (A * A)) * un_correctionFactor;
20637 }
20638 else {
20639 rsquare = POW2(m_solver->a_coordinate(cellId, 0) - m_cbcReferencePoint[cbcId][0])
20640 + POW2(m_solver->a_coordinate(cellId, 1) - m_cbcReferencePoint[cbcId][1])
20641 + POW2(m_solver->a_coordinate(cellId, 2) - m_cbcReferencePoint[cbcId][2]);
20642 un_target = F2 * massflux_target / m_cbcInflowArea[cbcId] * (F1 - rsquare / (A * A)) / rho * un_correctionFactor;
20643 }
20644 if(solverProfile) {
20645 un_target = massflux_target / m_cbcInflowArea[cbcId] / rho;
20646 }
20647 // BC specific end
20648
20649 // detChem specific setting
20650 IF_CONSTEXPR(isDetChem<SysEqn>) un_target = m_solver->m_VInfinity;
20651 MFloat ut1_target = F0;
20652 MFloat y_target = F1;
20653
20654 MFloat L_turbulent[3] = {F0, F0, F0};
20655 if(m_cbcTurbulence) {
20656 cbcTurbulenceInjection(cellId, L_turbulent, id);
20657 }
20658
20659 if(dirN % 2 == 0) {
20660 L[0] = -F1 * K[0] * (un - un_target) + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
20661 } else {
20662 L[last] = K[last] * (un - un_target) - L_turbulent[0] + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
20663 }
20664
20665 L[1] = K[1] * (temp - T_target) + (a * a * T[0] - T[last]) - V[last];
20666 L[2] = K[2] * (ut1 - ut1_target) - L_turbulent[1] + T[2] + V[2];
20667
20668 IF_CONSTEXPR(nDim == 3) {
20669 MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
20670 MFloat ut2_target = F0;
20671 L[3] = K[3] * (ut2 - ut2_target) - L_turbulent[2] + T[3] + V[3];
20672 }
20673
20674 IF_CONSTEXPR(isDetChem<SysEqn>) {
20675 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
20676 MFloat y = m_solver->a_pvariable(cellId, sysEqn().PV->Y[s]);
20677 L[last + 1 + s] = K[last + 1 + s] * (y - m_solver->m_YInfinity[s]);
20678 }
20679 }
20680 else {
20681 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
20682 MFloat y = m_solver->a_pvariable(cellId, sysEqn().PV->Y[s]);
20683 L[last + 1 + s] = K[last + 1 + s] * (y - y_target);
20684 }
20685 }
20686 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
20687 }
20688}
20689
20694template <MInt nDim, class SysEqn>
20696 TRACE();
20697
20698 if(m_sortedCutOffCells[bcId]->size() == 0) {
20699 return;
20700 }
20701
20702 MInt cbcId = m_cbcBndryCndIds[bcId];
20703
20704 MInt dirN = m_cbcDir[cbcId][0];
20705 MInt dimN = m_cbcDir[cbcId][1];
20706 // MInt dimT1 = m_cbcDir[cbcId][2];
20707 MInt dimT2 = m_cbcDir[cbcId][nDim];
20708
20709 // MInt last = nDim + 1;
20710
20711 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
20712 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
20713 MFloatScratchSpace gradP(nDim, AT_, "gradP");
20714 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
20715 gradY.fill(F0);
20716
20717 MFloatScratchSpace L(PV->noVariables, AT_, "L");
20718 MFloatScratchSpace T(PV->noVariables, AT_, "T");
20719 MFloatScratchSpace V(PV->noVariables, AT_, "V");
20720 MFloatScratchSpace K(PV->noVariables, AT_, "K");
20721 L.fill(F0);
20722 T.fill(F0);
20723 V.fill(F0);
20724 K.fill(F0);
20725
20726 std::vector<MFloat> mach(2);
20727 cbcMachCo(bcId, &mach[0]);
20728 // MFloat meanM = mach[0];
20729 MFloat maxM = mach[1];
20730
20731 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
20732 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
20733 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
20734 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
20735 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
20736
20737 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
20738 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
20739
20740 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
20741 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
20742
20743 if(m_solver->a_isHalo(cellId)) continue;
20744
20745 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
20746 V.fill(F0);
20747 // if(m_cbcViscous) {
20748 // cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
20749 // gradQ[dimN * nDim + dimN] = F0;
20750 // gradTau[dimN * IPOW2[nDim] + dimT1 * nDim + dimN] = F0;
20751 // IF_CONSTEXPR(nDim == 3) gradTau[dimN * IPOW2[nDim] + dimT2 * nDim + dimN] = F0;
20752 // cbcViscousTerms<(unsigned char)11111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
20753 // &cutOffStencilCellIds[0], &V[0]);
20754 // }
20755
20756 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20757 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20758 MFloat a = sysEqn().speedOfSound(rho, p);
20759
20760 MFloat vn_N = 0;
20761
20762 // check neighbor active!
20763 if(m_solver->checkNeighborActive(cellId, dirN) && m_solver->a_hasNeighbor(cellId, dirN)) {
20764 const MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
20765 for(MInt n = 0; n < nDim; n++) {
20766 vn_N += m_solver->a_variable(nghbrN, CV->RHO_VV[n]) * m_dirNormal[cbcId][n];
20767 }
20768 }
20769
20770 MFloat x = m_solver->a_coordinate(cellId, 0);
20771 MFloat vn_target = m_solver->m_UInfinity;
20772 MInt length = m_vnTargetDataCount;
20773 for(MInt i = 1; i < length; i++) {
20774 if(m_vnTargetData[i].first > x && m_vnTargetData[i - 1].first <= x) {
20775 vn_target = m_vnTargetData[i - 1].second
20776 + (m_vnTargetData[i].second - m_vnTargetData[i - 1].second)
20777 / (m_vnTargetData[i].first - m_vnTargetData[i - 1].first) * (x - m_vnTargetData[i - 1].first);
20778 }
20779 }
20780
20781 MFloat un = m_solver->a_pvariable(cellId, PV->VV[0]);
20782 MFloat vn = m_solver->a_pvariable(cellId, PV->VV[1]);
20783 MFloat lambda1 = (un - a);
20784 MFloat lambda2 = un;
20785
20786 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
20787 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
20788 L[0] = lambda1 * (gradP[dimN] - rho * a * gradVV[dimN * nDim + dimN]);
20789 L[1] = lambda2 * (a * a * gradRho[dimN] - gradP[dimN]);
20790 L[2] = K[2] * (vn - vn_target);
20791 // L[2] = lambda2 * (gradVV[dimT1 * nDim + dimN]);
20792 IF_CONSTEXPR(nDim == 3) { L[3] = lambda2 * (gradVV[dimT2 * nDim + dimN]); }
20793
20794 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
20795 }
20796}
20797
20802template <MInt nDim, class SysEqn>
20804 TRACE();
20805
20806 if(m_sortedCutOffCells[bcId]->size() == 0) {
20807 return;
20808 }
20809
20810 MInt cbcId = m_cbcBndryCndIds[bcId];
20811
20812 MInt dirN = m_cbcDir[cbcId][0];
20813 MInt dimN = m_cbcDir[cbcId][1];
20814 MInt dimT1 = m_cbcDir[cbcId][2];
20815 MInt dimT2 = m_cbcDir[cbcId][nDim];
20816
20817 MInt last = nDim + 1;
20818
20819 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
20820 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
20821 MFloatScratchSpace gradP(nDim, AT_, "gradP");
20822 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
20823 gradY.fill(F0);
20824
20825 MFloatScratchSpace L(PV->noVariables, AT_, "L");
20826 MFloatScratchSpace T(PV->noVariables, AT_, "T");
20827 MFloatScratchSpace V(PV->noVariables, AT_, "V");
20828 MFloatScratchSpace K(PV->noVariables, AT_, "K");
20829 L.fill(F0);
20830 T.fill(F0);
20831 V.fill(F0);
20832 K.fill(F0);
20833
20834 std::vector<MFloat> mach(2);
20835 cbcMachCo(bcId, &mach[0]);
20836 MFloat meanM = mach[0];
20837 MFloat maxM = mach[1];
20838
20839 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
20840 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
20841 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
20842 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
20843 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
20844
20845 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
20846 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
20847
20848
20849 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
20850 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
20851
20852 if(m_solver->a_isHalo(cellId)) continue;
20853
20854 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
20855 V.fill(F0);
20856 // if(m_cbcViscous) {
20857 // cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
20858 // gradQ[dimN * nDim + dimN] = F0;
20859 // gradTau[dimN * IPOW2[nDim] + dimT1 * nDim + dimN] = F0;
20860 // IF_CONSTEXPR(nDim == 3) gradTau[dimN * IPOW2[nDim] + dimT2 * nDim + dimN] = F0;
20861 // cbcViscousTerms<(unsigned char)11111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
20862 // &cutOffStencilCellIds[0], &V[0]);
20863 // }
20864
20865 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20866 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20867 MFloat a = sysEqn().speedOfSound(rho, p);
20868
20869 MFloat beta = meanM;
20870
20871 // BC specific start
20872 MFloat targetPressure = m_solver->m_PInfinity;
20873 MFloat targetDensity = m_solver->m_rhoInfinity;
20874
20875 MFloat un_N = 0;
20876
20877 // check neighbor active!
20878 if(m_solver->checkNeighborActive(cellId, dirN) && m_solver->a_hasNeighbor(cellId, dirN)) {
20879 const MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
20880
20881 for(MInt n = 0; n < nDim; n++) {
20882 un_N += m_solver->a_variable(nghbrN, CV->RHO_VV[n]) * m_dirNormal[cbcId][n];
20883 }
20884 }
20885
20886 MFloat y = m_solver->a_coordinate(cellId, 1);
20887 MFloat un_target = m_solver->m_UInfinity;
20888 MInt length = m_unTargetDataCount; //(MInt)un_targetData.size();
20889 for(MInt i = 1; i < length; i++) {
20890 if(m_unTargetData[i].first > y && m_unTargetData[i - 1].first <= y) {
20891 un_target = m_unTargetData[i - 1].second
20892 + (m_unTargetData[i].second - m_unTargetData[i - 1].second)
20893 / (m_unTargetData[i].first - m_unTargetData[i - 1].first) * (y - m_unTargetData[i - 1].first);
20894 }
20895 }
20896
20897 MBool isInflow = false;
20898 if(dirN % 2 == 0) {
20899 if(un_N < F0 /*|| un_target < F0*/) {
20900 isInflow = true;
20901 }
20902 } else {
20903 if(un_N > F0 /*|| un_target > F0*/) {
20904 isInflow = true;
20905 }
20906 }
20907
20908 MFloat un = m_solver->a_pvariable(cellId, PV->VV[0]);
20909
20910 MFloat lambda2 = un;
20911
20912 isInflow = true;
20913
20914 std::ignore = targetDensity;
20915
20916 if(isInflow) {
20917 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
20918 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
20919 if(dirN % 2 == 0) {
20920 L[0] = -F1 * K[0] * (un - un_target) + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
20921 } else {
20922 L[last] = K[last] * (un - un_target) + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
20923 }
20924 L[1] = lambda2 * (a * a * gradRho[dimN] - gradP[dimN]);
20925 L[2] = lambda2 * (gradVV[dimT1 * nDim + dimN]);
20926 IF_CONSTEXPR(nDim == 3) { L[3] = lambda2 * (gradVV[dimT2 * nDim + dimN]); }
20927 } else {
20928 cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
20929 cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
20930 if(dirN % 2 == 0) {
20931 L[0] = K[0] * (p - targetPressure) + (F1 - beta) * (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
20932 } else {
20933 L[last] =
20934 K[last] * (p - targetPressure) + (F1 - beta) * (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
20935 }
20936 }
20937
20938 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
20939 }
20940}
20941
20946template <MInt nDim, class SysEqn>
20948 TRACE();
20949
20950 if(m_sortedCutOffCells[bcId]->size() == 0) {
20951 return;
20952 }
20953
20954 MInt cbcId = m_cbcBndryCndIds[bcId];
20955
20956 MInt dirN = m_cbcDir[cbcId][0];
20957 // MInt dimN = m_cbcDir[cbcId][1];
20958 // MInt dimT1 = m_cbcDir[cbcId][2];
20959 // MInt dimT2 = m_cbcDir[cbcId][nDim];
20960
20961 MInt last = nDim + 1;
20962
20963 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
20964 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
20965 MFloatScratchSpace gradP(nDim, AT_, "gradP");
20966 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
20967 // gradY.fill(F0);
20968
20969 MFloatScratchSpace L(PV->noVariables, AT_, "L");
20970 MFloatScratchSpace T(PV->noVariables, AT_, "T");
20971 MFloatScratchSpace V(PV->noVariables, AT_, "V");
20972 // MFloatScratchSpace K(PV->noVariables, AT_, "K");
20973 L.fill(F0);
20974 T.fill(F0);
20975 V.fill(F0);
20976 // K.fill(F0);
20977
20978 // MFloat mach[2];
20979 // cbcMachCo(bcId, mach);
20980 // MFloat meanM = mach[0];
20981 // MFloat maxM = mach[1];
20982
20983 // MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
20984 // MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
20985 // MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
20986
20987 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
20988 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
20989 MInt level = m_solver->a_level(cellId);
20990 MInt rDistance = 1 / m_solver->c_cellLengthAtLevel(level);
20991
20992 if(m_solver->a_isHalo(cellId)) continue;
20993
20994 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
20995
20996 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
20997 MFloat p = m_solver->a_pvariable(cellId, PV->P);
20998 MFloat u = m_solver->a_pvariable(cellId, PV->VV[0]);
20999 MFloat a = sysEqn().speedOfSound(rho, p);
21000
21001 // BC specific start
21002 MFloat targetPressure = m_solver->m_PInfinity;
21003 // MFloat targetDensity = m_solver->m_rhoInfinity;
21004
21005 MFloat y = m_solver->a_coordinate(cellId, 1);
21006 MFloat un_target = m_solver->m_UInfinity;
21007 MInt length = m_unTargetDataCount; //(MInt)un_targetData.size();
21008 for(MInt i = 1; i < length; i++) {
21009 if(m_unTargetData[i].first > y && m_unTargetData[i - 1].first <= y) {
21010 un_target = m_unTargetData[i - 1].second
21011 + (m_unTargetData[i].second - m_unTargetData[i - 1].second)
21012 / (m_unTargetData[i].first - m_unTargetData[i - 1].first) * (y - m_unTargetData[i - 1].first);
21013 }
21014 }
21015
21016 // MBool switchRelax = false;
21017
21018 // cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
21019 // cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
21020 if(dirN % 2 == 0) {
21021 L[0] = F0; // ToDo
21022 } else {
21023 L[last] = rDistance * ((u - a) * (targetPressure - p) - rho * a * (un_target - u));
21024 }
21025
21026 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
21027 }
21028}
21029
21037template <MInt nDim, class SysEqn>
21039 TRACE();
21040
21041 if(m_sortedCutOffCells[bcId]->size() == 0) {
21042 return;
21043 }
21044
21045 MInt cbcId = m_cbcBndryCndIds[bcId];
21046
21047 MInt dirN = m_cbcDir[cbcId][0];
21048 MInt dimN = m_cbcDir[cbcId][1];
21049 MInt dimT1 = m_cbcDir[cbcId][2];
21050 MInt dimT2 = m_cbcDir[cbcId][nDim];
21051
21052 MInt last = nDim + 1;
21053
21054 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
21055 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
21056 MFloatScratchSpace gradP(nDim, AT_, "gradP");
21057 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
21058 gradY.fill(F0);
21059
21060 MFloatScratchSpace L(PV->noVariables, AT_, "L");
21061 MFloatScratchSpace T(PV->noVariables, AT_, "T");
21062 MFloatScratchSpace V(PV->noVariables, AT_, "V");
21063 MFloatScratchSpace K(PV->noVariables, AT_, "K");
21064
21065 MFloat mach[2];
21066 cbcMachCo(bcId, mach);
21067 MFloat meanM = mach[0];
21068 MFloat maxM = mach[1];
21069
21070
21071 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
21072 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
21073 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
21074 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
21075 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
21076
21077 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
21078 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
21079
21080 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21081 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21082
21083 if(m_solver->a_isHalo(cellId)) continue;
21084
21085 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
21086 V.fill(F0);
21087 if(m_cbcViscous) {
21088 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
21089 gradQ[dimN * nDim + dimN] = F0;
21090 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
21091 IF_CONSTEXPR(nDim == 3) gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0;
21092 cbcViscousTerms<(unsigned char)11111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
21093 &cutOffStencilCellIds[0], &V[0]);
21094 }
21095
21096 cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
21097 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
21098 cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
21099
21100 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21101 MFloat p = m_solver->a_pvariable(cellId, PV->P);
21102 MFloat a = sysEqn().speedOfSound(rho, p);
21103
21104 MFloat beta = meanM;
21105
21106 // BC specific start
21107 MFloat targetPressure = m_solver->m_PInfinity - m_deltaPL;
21108 // BC specific end
21109 // targetPressure = m_solver->m_PInfinity;
21110 MFloat y_target = F0;
21111
21112 if(dirN % 2 == 0) {
21113 L[0] = K[0] * (p - targetPressure) + (F1 - beta) * (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
21114 } else {
21115 L[last] = K[last] * (p - targetPressure) + (F1 - beta) * (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
21116 }
21117 for(MInt s = 0; s < m_solver->m_noSpecies; s++) {
21118 MFloat y = m_solver->a_pvariable(cellId, sysEqn().PV->Y[s]);
21119 L[last + 1 + s] = K[last + 1 + s] * (y - y_target);
21120 }
21121
21122 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
21123 }
21124}
21125
21126
21133template <MInt nDim, class SysEqn>
21135 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function cbc2091a is untested for 3D!"); }
21136 TRACE();
21137
21138 if(m_sortedCutOffCells[bcId]->size() == 0) {
21139 return;
21140 }
21141
21142 MInt cbcId = m_cbcBndryCndIds[bcId];
21143
21144 MInt dirN = m_cbcDir[cbcId][0];
21145 MInt dimN = m_cbcDir[cbcId][1];
21146 MInt dimT1 = m_cbcDir[cbcId][2];
21147 MInt dimT2 = m_cbcDir[cbcId][nDim];
21148
21149 MBool solverProfile = Context::getSolverProperty<MBool>("solverProfile", m_solverId, AT_, &solverProfile);
21150 MFloat time = m_solver->m_time;
21151 MFloat St = m_solver->m_flameStrouhal;
21152 MFloat ampl = m_solver->m_forcingAmplitude;
21153
21154 MFloat inflowArea = m_cbcInflowArea[cbcId];
21155 // MFloat H = inflowArea * F1B2;
21156
21157 MInt last = nDim + 1;
21158
21159 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
21160 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
21161 MFloatScratchSpace gradP(nDim, AT_, "gradP");
21162 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
21163 gradY.fill(F0);
21164
21165 MFloatScratchSpace L(PV->noVariables, AT_, "L");
21166 MFloatScratchSpace T(PV->noVariables, AT_, "T");
21167 MFloatScratchSpace V(PV->noVariables, AT_, "V");
21168 MFloatScratchSpace K(PV->noVariables, AT_, "K");
21169
21170 MFloat mach[2] = {F0, F0};
21171 cbcMachCo(bcId, mach);
21172 MFloat maxM = mach[1];
21173
21174 MFloat massflux = F0;
21175 MFloat uInt = F0;
21176 MFloat testSum2 = F0;
21177
21178 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21179 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21180 MInt bndryId = m_solver->a_bndryId(cellId);
21181
21182 if(m_solver->a_isHalo(cellId)) continue;
21183 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21184 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21185
21186 MFloat area = F0;
21187 if(bndryId > -1) {
21188 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
21189 // cell
21190 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
21191 if(srfcId > -1)
21192 area = m_solver->a_surfaceArea(srfcId);
21193 else
21194 mTerm(1, AT_, "something went wrong!");
21195 } else {
21196 area = m_solver->c_cellLengthAtCell(cellId);
21197 }
21198
21199 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21200 const MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
21201 const MFloat y = (m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]);
21202 testSum2 += area * y * y;
21203 massflux += un * rho * area;
21204 uInt += un * area;
21205 }
21206
21207 MInt noExchangeData = 2;
21208 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
21209 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
21210 comm_buff[0] = massflux;
21211 comm_buff[1] = testSum2;
21212
21213 if(noDomains() > 1) {
21214 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 3, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
21215 AT_, "comm_buff[0]", "comm_buff_result[0]");
21216 MPI_Allreduce(MPI_IN_PLACE, &uInt, 1, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
21217 "MPI_IN_PLACE", "uInt");
21218 }
21219
21220 massflux = comm_buff_result[0];
21221 testSum2 = comm_buff_result[1];
21222 MFloat massflux_test = uInt / m_solver->m_analyticIntegralVelocity;
21223
21224 MFloat un_correctionFactor = F1;
21225 if(fabs(massflux_test) > m_solver->m_eps) un_correctionFactor = F1 / massflux_test;
21226
21227 const MFloat massflux_target = massflux * un_correctionFactor;
21228
21229 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
21230 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
21231 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
21232 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
21233 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
21234
21235 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
21236 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
21237
21238 MFloat T_target = sysEqn().temperature_ES(m_solver->m_rhoInfinity, m_solver->m_meanPressure);
21239
21240 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21241 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21242
21243 if(m_solver->a_isHalo(cellId)) continue;
21244 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21245 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21246
21247 MInt bndryId = m_solver->a_bndryId(cellId);
21248 if(bndryId > -1) {
21249 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
21250 }
21251
21252 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
21253 V.fill(F0);
21254 if(m_cbcViscous) {
21255 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
21256 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
21257 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
21258 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
21259 &cutOffStencilCellIds[0], &V[0]);
21260 }
21261
21262 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
21263 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
21264 cbcDampingInflow(cellId, bcId, maxM, &K[0], "velocity");
21265
21266 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21267 MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
21268 MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
21269
21270 MFloat p = m_solver->a_pvariable(cellId, PV->P);
21271 MFloat temp = sysEqn().temperature_ES(rho, p);
21272 MFloat a = sysEqn().speedOfSound(rho, p);
21273
21274 MFloat xPlus = (m_solver->a_coordinate(cellId, 0) + m_radiusVelFlameTube);
21275 xPlus *= m_shearLayerStrength;
21276 MFloat xNegative = m_solver->a_coordinate(cellId, 0) - m_radiusVelFlameTube;
21277 xNegative *= m_shearLayerStrength;
21278
21279 MFloat un_target = m_solver->m_VInfinity
21280 * (F1B2 * (F1 + tanh(xPlus)) * (F1 - tanh(xNegative))
21281 - F1); // F3B4 * massflux/H*(1-y*y/(H*H))*un_correctionFactor;
21282
21283 // F3B4 * massflux_target/rho/H*(1-y*y/(H*H))*un_correctionFactor;
21284 if(solverProfile) un_target = massflux_target / inflowArea / rho;
21285
21286 if(m_solver->m_forcing) {
21287 // dundt = un_target;
21288 // dundt *= St*ampl*cos(St*time);
21289 un_target *= (F1 + ampl * sin(St * time));
21290 }
21291
21292 MFloat ut1_target = F0;
21293
21294 if(dirN % 2 == 0) {
21295 L[0] = -F1 * K[0] * (un - un_target) + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
21296 } else {
21297 L[last] = K[last] * (un - un_target) + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
21298 }
21299
21300 L[1] = K[1] * (temp - T_target) + (a * a * T[0] - T[last]) - V[last];
21301 L[2] = K[2] * (ut1 - ut1_target) + T[2] + V[2];
21302
21303 IF_CONSTEXPR(nDim == 3) {
21304 MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
21305 MFloat ut2_target = F0;
21306 L[3] = K[3] * (ut2 - ut2_target) + T[3] + V[3];
21307 }
21308
21309 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
21310 for(MInt s = 0; s < m_solver->m_noSpecies; s++)
21311 m_solver->a_rightHandSide(cellId, CV->RHO_Y[s]) = F0;
21312 }
21313}
21314
21315
21322template <MInt nDim, class SysEqn>
21324 TRACE();
21325
21326 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function cbc2091a is untested for 3D!"); }
21327
21328 if(m_sortedCutOffCells[bcId]->size() == 0) {
21329 return;
21330 }
21331
21332 MInt cbcId = m_cbcBndryCndIds[bcId];
21333
21334 MInt dirN = m_cbcDir[cbcId][0];
21335 MInt dimN = m_cbcDir[cbcId][1];
21336 MInt dimT1 = m_cbcDir[cbcId][2];
21337 MInt dimT2 = m_cbcDir[cbcId][nDim];
21338
21339 MBool solverProfile = Context::getSolverProperty<MBool>("solverProfile", m_solverId, AT_, &solverProfile);
21340 MFloat time = m_solver->m_time;
21341 MFloat St = m_solver->m_flameStrouhal;
21342 MFloat ampl = m_solver->m_forcingAmplitude;
21343
21344 MFloat inflowArea = m_cbcInflowArea[cbcId];
21345 // MFloat H = m_cbcInflowArea[cbcId] * F1B2;
21346
21347 MInt last = nDim + 1;
21348
21349 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
21350 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
21351 MFloatScratchSpace gradP(nDim, AT_, "gradP");
21352 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
21353 gradY.fill(F0);
21354
21355 MFloatScratchSpace L(PV->noVariables, AT_, "L");
21356 MFloatScratchSpace T(PV->noVariables, AT_, "T");
21357 MFloatScratchSpace V(PV->noVariables, AT_, "V");
21358 MFloatScratchSpace K(PV->noVariables, AT_, "K");
21359
21360 MFloat mach[2] = {F0, F0};
21361 cbcMachCo(bcId, mach);
21362 MFloat maxM = mach[1];
21363
21364 MFloat massflux = F0;
21365 MFloat uInt = F0;
21366 MFloat testSum2 = F0;
21367
21368 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21369 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21370 MInt bndryId = m_solver->a_bndryId(cellId);
21371
21372 if(m_solver->a_isHalo(cellId)) continue;
21373 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21374 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21375
21376 MFloat area = F0;
21377 if(bndryId > -1) {
21378 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
21379 // cell
21380 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
21381 if(srfcId > -1)
21382 area = m_solver->a_surfaceArea(srfcId);
21383 else
21384 mTerm(1, AT_, "something went wrong!");
21385 } else {
21386 area = m_solver->c_cellLengthAtCell(cellId);
21387 }
21388
21389 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21390 const MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
21391 const MFloat y = (m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]);
21392 testSum2 += area * y * y;
21393 massflux += un * rho * area;
21394 uInt += un * area;
21395 }
21396
21397 MInt noExchangeData = 2;
21398 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
21399 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
21400 comm_buff[0] = massflux;
21401 comm_buff[1] = testSum2;
21402
21403 if(noDomains() > 1) {
21404 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 3, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
21405 AT_, "comm_buff[0]", "comm_buff_result[0]");
21406 MPI_Allreduce(MPI_IN_PLACE, &uInt, 1, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
21407 "MPI_IN_PLACE", "uInt");
21408 }
21409
21410 massflux = comm_buff_result[0];
21411 testSum2 = comm_buff_result[1];
21412 MFloat massflux_test = uInt / m_solver->m_analyticIntegralVelocity;
21413
21414 MFloat un_correctionFactor = F1;
21415 if(fabs(massflux_test) > m_solver->m_eps) un_correctionFactor = F1 / massflux_test;
21416
21417 const MFloat massflux_target = massflux * un_correctionFactor;
21418 const MFloat gammaMinusOne = m_solver->m_gamma - 1.0;
21419
21420 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
21421 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
21422 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
21423 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
21424 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
21425
21426 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
21427 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
21428
21429 MFloat T_target = sysEqn().temperature_IR(m_solver->m_Ma);
21430
21431 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21432 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21433
21434 if(m_solver->a_isHalo(cellId)) continue;
21435 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21436 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21437
21438 MInt bndryId = m_solver->a_bndryId(cellId);
21439 if(bndryId > -1) {
21440 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
21441 }
21442
21443 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
21444 V.fill(F0);
21445 if(m_cbcViscous) {
21446 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
21447 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
21448 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
21449 V.fill(F0);
21450 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
21451 &cutOffStencilCellIds[0], &V[0]);
21452 }
21453
21454 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
21455 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
21456 cbcDampingInflow(cellId, bcId, maxM, &K[0], "velocity");
21457
21458 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21459 MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
21460 MFloat p = m_solver->a_pvariable(cellId, PV->P);
21461 MFloat a = sysEqn().speedOfSound(rho, p);
21462
21463 MFloat xPlus = (m_solver->a_coordinate(cellId, 0) + m_radiusVelFlameTube);
21464 xPlus *= m_shearLayerStrength;
21465 MFloat xNegative = m_solver->a_coordinate(cellId, 0) - m_radiusVelFlameTube;
21466 xNegative *= m_shearLayerStrength;
21467
21468 MFloat un_target = m_solver->m_VInfinity
21469 * (F1B2 * (F1 + tanh(xPlus)) * (F1 - tanh(xNegative))
21470 - F1); // F3B4 * massflux/H*(1-y*y/(H*H))*un_correctionFactor;
21471
21472 // F3B4 * massflux_target/rho/H*(1-y*y/(H*H))*un_correctionFactor;
21473 if(solverProfile) un_target = massflux_target / inflowArea / rho;
21474
21475 MFloat ceta = F1;
21476 if(dirN % 2 == 0) // inflow on pos. coordinate direction
21477 ceta = -F1;
21478 else // inflow on neg. coordinate direction
21479 ceta = F1;
21480
21481 MFloat dundt = F0;
21482 if(m_solver->m_forcing) {
21483 dundt = un_target;
21484 dundt *= St * ampl * cos(St * time);
21485 un_target *= (F1 + ampl * sin(St * time));
21486 }
21487 MFloat ut1_target = F0;
21488
21489 if(dirN % 2 == 0) { // inflow on pos. coordinate direction (right) -> un < 0
21490 L[0] = L[last] + (T[last] + ceta * rho * a * T[1]) - ceta * F2 * rho * a * dundt;
21491 } else { // inflow on neg. coordinate direction (left) -> un > 0
21492 L[last] = L[0] + (T[last] + ceta * rho * a * T[1]) - ceta * F2 * rho * a * dundt;
21493 }
21494 L[1] = F1B2 * gammaMinusOne * (L[0] + L[last]) + (a * a * T[0] - T[last]);
21495
21496 MFloat d1 = F1 / (a * a) * (L[1] + F1B2 * (L[last] + L[0]));
21497
21498 MFloat dut1dt1 = m_solver->a_slope(cellId, PV->VV[dimT1], dimT1);
21499 MFloat drhodt1 = m_solver->a_slope(cellId, PV->RHO, dimT1);
21500
21501 MFloat rhs_rho = -d1 - rho * (dut1dt1)-ut1 * drhodt1;
21502
21503 m_solver->a_rightHandSide(cellId, CV->RHO) = -m_solver->a_cellVolume(cellId) * rhs_rho;
21504 for(MInt s = 0; s < m_solver->m_noSpecies; s++)
21505 m_solver->a_rightHandSide(cellId, CV->RHO_Y[s]) -=
21506 m_solver->a_cellVolume(cellId) * rhs_rho * m_solver->a_pvariable(cellId, PV->Y[s]);
21507 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimN]) = F0;
21508 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT1]) = F0;
21509 m_solver->a_rightHandSide(cellId, CV->RHO_E) = F0;
21510
21511 for(MInt s = 0; s < m_solver->m_noSpecies; s++)
21512 m_solver->a_pvariable(cellId, PV->Y[s]) = 0;
21513
21514 m_solver->a_pvariable(cellId, PV->VV[dimN]) = un_target;
21515 m_solver->a_pvariable(cellId, PV->VV[dimT1]) = ut1_target;
21516 m_solver->a_pvariable(cellId, PV->P) = T_target;
21517 }
21518}
21519
21520
21524template <MInt nDim, class SysEqn>
21526 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function cbc2091b_after is untested for 3D!"); }
21527 TRACE();
21528
21529 if(m_sortedCutOffCells[bcId]->size() == 0) return;
21530
21531 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21532 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21533
21534 if(m_solver->a_isHalo(cellId)) continue;
21535 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21536 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21537
21538 MInt bndryId = m_solver->a_bndryId(cellId);
21539
21540 if(bndryId > -1) {
21541 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
21542 }
21543
21544 // recompute the correct energy:
21545 MFloat rho = m_solver->a_variable(cellId, CV->RHO);
21546 MFloat u = m_solver->a_pvariable(cellId, PV->VV[0]);
21547 MFloat v = m_solver->a_pvariable(cellId, PV->VV[1]);
21548 MFloat T = m_solver->a_pvariable(cellId, PV->P);
21549 MFloat p = sysEqn().pressure_ES(T, rho);
21550 MFloat E = sysEqn().internalEnergy(p, rho, (u * u + v * v));
21551
21552 m_solver->a_variable(cellId, CV->RHO_VV[0]) = rho * u;
21553 m_solver->a_variable(cellId, CV->RHO_VV[1]) = rho * v;
21554 m_solver->a_variable(cellId, CV->RHO_E) = E;
21555 for(MInt s = 0; s < m_solver->m_noSpecies; s++)
21556 m_solver->a_variable(cellId, CV->RHO_Y[s]) = rho * m_solver->a_pvariable(cellId, PV->Y[s]);
21557 }
21558}
21565template <MInt nDim, class SysEqn>
21567 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function cbc2091a is untested for 3D!"); }
21568 TRACE();
21569
21570 if(m_sortedCutOffCells[bcId]->size() == 0) {
21571 return;
21572 }
21573
21574 MInt cbcId = m_cbcBndryCndIds[bcId];
21575
21576 MInt dirN = m_cbcDir[cbcId][0];
21577 MInt dimN = m_cbcDir[cbcId][1];
21578 MInt dimT1 = m_cbcDir[cbcId][2];
21579 MInt dimT2 = m_cbcDir[cbcId][nDim];
21580
21581 MFloat inflowArea = m_cbcInflowArea[cbcId];
21582 // MFloat H = m_cbcInflowArea[cbcId] * F1B2;
21583
21584 MInt last = nDim + 1;
21585
21586 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
21587 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
21588 MFloatScratchSpace gradP(nDim, AT_, "gradP");
21589 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
21590 gradY.fill(F0);
21591
21592 MFloatScratchSpace L(PV->noVariables, AT_, "L");
21593 MFloatScratchSpace T(PV->noVariables, AT_, "T");
21594 MFloatScratchSpace V(PV->noVariables, AT_, "V");
21595 MFloatScratchSpace K(PV->noVariables, AT_, "K");
21596
21597 MFloat mach[2] = {F0, F0};
21598 cbcMachCo(bcId, mach);
21599 MFloat maxM = mach[1];
21600
21601 MFloat massflux = F0;
21602 MFloat uInt = F0;
21603
21604 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21605 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21606 MInt bndryId = m_solver->a_bndryId(cellId);
21607 MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
21608
21609 if(m_solver->a_isHalo(cellId)) continue;
21610 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21611 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21612
21613 MFloat area = F0;
21614 if(bndryId > -1) {
21615 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
21616 // cell
21617 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
21618 if(srfcId > -1)
21619 area = m_solver->a_surfaceArea(srfcId);
21620 else
21621 mTerm(1, AT_, "something went wrong!");
21622 } else {
21623 area = m_solver->c_cellLengthAtCell(cellId);
21624 }
21625
21626 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21627 const MFloat un_N = m_solver->a_pvariable(nghbrN, PV->VV[dimN]);
21628 massflux += un_N * rho * area;
21629 uInt += un_N * area;
21630 }
21631
21632 MInt noExchangeData = 2;
21633 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
21634 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
21635 comm_buff[0] = massflux;
21636 comm_buff[1] = uInt;
21637
21638 if(noDomains() > 1) {
21639 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 3, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
21640 AT_, "comm_buff[0]", "comm_buff_result[0]");
21641 MPI_Allreduce(MPI_IN_PLACE, &uInt, 1, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
21642 "MPI_IN_PLACE", "uInt");
21643 }
21644
21645 massflux = comm_buff_result[0];
21646 MFloat massflux_test = uInt / m_solver->m_analyticIntegralVelocity;
21647
21648 MFloat un_correctionFactor = F1;
21649 if(fabs(massflux_test) > m_solver->m_eps) un_correctionFactor = F1 / massflux_test;
21650
21651 massflux = massflux * un_correctionFactor;
21652
21653 const MFloat gammaMinusOne = m_solver->m_gamma - 1.0;
21654
21655 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
21656 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
21657 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
21658 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
21659 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
21660
21661 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
21662 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
21663
21664 MFloat T_target = 1 - gammaMinusOne * F1B2 * (massflux * massflux / inflowArea / inflowArea);
21665 MFloat p_Target = sysEqn().pressure_IR(T_target);
21666 p_Target += m_solver->m_rhoInfinity * POW2(m_solver->m_flameSpeed) * (m_solver->m_burntUnburntTemperatureRatio - F1);
21667 p_Target += m_solver->m_rhoFlameTube * m_solver->m_targetDensityFactor * POW2(m_solver->m_velocityOutlet)
21668 * m_solver->m_flameOutletAreaRatio;
21669 p_Target -= m_solver->m_rhoFlameTube * POW2(m_solver->m_VInfinity);
21670
21671 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21672 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21673
21674 if(m_solver->a_isHalo(cellId)) continue;
21675 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21676 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21677
21678 MInt bndryId = m_solver->a_bndryId(cellId);
21679 if(bndryId > -1) {
21680 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
21681 }
21682
21683 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
21684 V.fill(F0);
21685 if(m_cbcViscous) {
21686 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
21687 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
21688 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
21689 V.fill(F0);
21690 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
21691 &cutOffStencilCellIds[0], &V[0]);
21692 }
21693
21694 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
21695 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
21696 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
21697
21698 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21699 MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
21700
21701 MFloat p = m_solver->a_pvariable(cellId, PV->P);
21702 MFloat temp = sysEqn().temperature_ES(rho, p);
21703 MFloat a = sysEqn().speedOfSound(rho, p);
21704
21705 MFloat xPlus = (m_solver->a_coordinate(cellId, 0) + m_radiusVelFlameTube);
21706 xPlus *= m_shearLayerStrength;
21707 MFloat xNegative = m_solver->a_coordinate(cellId, 0) - m_radiusVelFlameTube;
21708 xNegative *= m_shearLayerStrength;
21709
21710 MFloat un_target = m_solver->m_VInfinity
21711 * (F1B2 * (F1 + tanh(xPlus)) * (F1 - tanh(xNegative))
21712 - F1); // F3B4 * massflux/H*(1-y*y/(H*H))*un_correctionFactor;
21713
21714 MFloat ut1_target = F0;
21715
21716 if(dirN % 2 == 0) {
21717 L[0] = K[0] * (p - p_Target) + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
21718 } else {
21719 L[last] = K[last] * (p - p_Target) + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
21720 }
21721
21722 L[1] = K[1] * (temp - T_target) + (a * a * T[0] - T[last]) - V[last];
21723 L[2] = K[2] * (ut1 - ut1_target) + T[2] + V[2];
21724
21725 IF_CONSTEXPR(nDim == 3) {
21726 MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
21727 MFloat ut2_target = F0;
21728 L[3] = K[3] * (ut2 - ut2_target) + T[3] + V[3];
21729 }
21730
21731 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
21732
21733 // temporary fix until species is included in cbcRHS()
21734 MFloat d1 = F1 / (a * a) * (L[1] + F1B2 * (L[last] + L[0]));
21735 MFloat rhs_rho = -d1 + T[0] + V[0];
21736 for(MInt s = 0; s < m_solver->m_noSpecies; s++)
21737 m_solver->a_rightHandSide(cellId, CV->RHO_Y[s]) -=
21738 m_solver->a_cellVolume(cellId) * rhs_rho * m_solver->a_pvariable(cellId, PV->Y[s]);
21739 for(MInt s = 0; s < m_solver->m_noSpecies; s++)
21740 m_solver->a_rightHandSide(cellId, CV->RHO_Y[s]) = F0;
21741 m_solver->a_pvariable(cellId, PV->VV[dimN]) = un_target;
21742 }
21743}
21747template <MInt nDim, class SysEqn>
21749 TRACE();
21750
21751 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function cbc2091d_after is untested for 3D!"); }
21752
21753 const MInt otherDir[4] = {1, 0, 3, 2};
21754
21755 MBool& first = m_static_cbc2091d_after_first;
21756 MInt& dirN = m_static_cbc2091d_after_dirN;
21757 MInt& dimN = m_static_cbc2091d_after_dimN;
21758 MInt& dimT1 = m_static_cbc2091d_after_dimT1;
21759 if(first) {
21760 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
21761 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
21762 if(noCutOffDirections != noCutOffBndryIds)
21763 mTerm(1, AT_,
21764 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
21765 MInt cutOffBndryIdTmp, cutOffDirectionTmp;
21766 for(MInt i = 0; i < noCutOffBndryIds; i++) {
21767 cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
21768 cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
21769 if(cutOffBndryIdTmp == m_cutOffBndryCndIds[bcId]) {
21770 dirN = otherDir[cutOffDirectionTmp];
21771 break;
21772 }
21773 }
21774 dimN = (MInt)dirN / 2;
21775 dimT1 = (dimN + 1) % nDim;
21776
21777 first = false;
21778 }
21779
21780 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21781 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21782 if(m_solver->a_isHalo(cellId)) continue;
21783 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21784 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21785
21786 MInt bndryId = m_solver->a_bndryId(cellId);
21787
21788 if(bndryId > -1) {
21789 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
21790 }
21791
21792 // recompute the correct energy:
21793 MFloat rho = m_solver->a_variable(cellId, CV->RHO);
21794 MFloat u = m_solver->a_pvariable(cellId, PV->VV[dimN]);
21795 MFloat u_wrong = m_solver->a_variable(cellId, CV->RHO_VV[dimN]) / m_solver->a_variable(cellId, CV->RHO);
21796 MFloat v = m_solver->a_variable(cellId, CV->RHO_VV[dimT1]) / m_solver->a_variable(cellId, CV->RHO);
21797 MFloat p = sysEqn().pressure(rho, (u_wrong * u_wrong + v * v), m_solver->a_variable(cellId, CV->RHO_E));
21798 MFloat E = sysEqn().internalEnergy(p, rho, (u * u + v * v));
21799
21800 m_solver->a_variable(cellId, CV->RHO_VV[dimN]) = rho * u;
21801 for(MInt s = 0; s < m_solver->m_noSpecies; s++)
21802 m_solver->a_variable(cellId, CV->RHO_Y[s]) = rho * m_solver->a_pvariable(cellId, PV->Y[s]);
21803 m_solver->a_variable(cellId, CV->RHO_E) = E;
21804 }
21805}
21806
21813template <MInt nDim, class SysEqn>
21815 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function cbc2099_1091_local_comb is untested for 3D!"); }
21816 TRACE();
21817
21818 if(m_sortedCutOffCells[bcId]->size() == 0) {
21819 return;
21820 }
21821
21822 MInt cbcId = m_cbcBndryCndIds[bcId];
21823
21824 MInt dirN = m_cbcDir[cbcId][0];
21825 MInt dimN = m_cbcDir[cbcId][1];
21826 MInt dimT1 = m_cbcDir[cbcId][2];
21827 MInt dimT2 = m_cbcDir[cbcId][nDim];
21828
21829 MFloat outFlowArea = m_cbcInflowArea[cbcId];
21830
21831 MInt last = nDim + 1;
21832
21833 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
21834 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
21835 MFloatScratchSpace gradP(nDim, AT_, "gradP");
21836 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
21837 gradY.fill(F0);
21838
21839 MFloatScratchSpace L(PV->noVariables, AT_, "L");
21840 MFloatScratchSpace T(PV->noVariables, AT_, "T");
21841 MFloatScratchSpace V(PV->noVariables, AT_, "V");
21842 MFloatScratchSpace K(PV->noVariables, AT_, "K");
21843
21844 MFloat massflux = F0;
21845 MFloat T_mean = F0;
21846 MFloat rho_mean = F0;
21847
21848 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21849 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21850 MInt bndryId = m_solver->a_bndryId(cellId);
21851
21852 if(m_solver->a_isHalo(cellId)) continue;
21853 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21854 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21855
21856 MFloat area = F0;
21857 if(bndryId > -1) {
21858 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
21859 // cell
21860 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
21861 if(srfcId > -1)
21862 area = m_solver->a_surfaceArea(srfcId);
21863 else
21864 mTerm(1, AT_, "something went wrong!");
21865 } else {
21866 IF_CONSTEXPR(nDim == 2) { area = m_solver->c_cellLengthAtCell(cellId); }
21867 else {
21868 area = POW2(m_solver->c_cellLengthAtCell(cellId));
21869 }
21870 }
21871
21872 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21873 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
21874 const MFloat Temp = sysEqn().temperature_ES(rho, p);
21875 const MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
21876
21877 massflux += un * area * rho;
21878 T_mean += Temp * area;
21879 rho_mean += rho * area;
21880 }
21881
21882 MFloat mach[2] = {F0, F0};
21883 cbcMachCo(bcId, mach);
21884 MFloat maxM = mach[1];
21885
21886 MInt noExchangeData = 2;
21887 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
21888 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
21889 comm_buff[0] = massflux;
21890 comm_buff[2] = T_mean;
21891
21892 if(noDomains() > 1) {
21893 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 2, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
21894 AT_, "comm_buff[0]", "comm_buff_result[0]");
21895 }
21896
21897 massflux = comm_buff_result[0];
21898 T_mean = comm_buff_result[1];
21899 T_mean /= outFlowArea;
21900 rho_mean /= outFlowArea;
21901
21902 MFloat T_target = T_mean;
21903 MFloat p_Target = m_solver->m_PInfinity;
21904
21905 m_solver->m_jetPressure = m_solver->m_PInfinity;
21906 m_solver->m_jetDensity = rho_mean;
21907 m_solver->m_jetTemperature = T_target;
21908
21909 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
21910 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
21911 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
21912 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
21913 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
21914
21915 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
21916 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
21917
21918 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
21919 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
21920
21921 if(m_solver->a_isHalo(cellId)) continue;
21922 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21923 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21924
21925 MInt bndryId = m_solver->a_bndryId(cellId);
21926
21927 if(bndryId > -1) {
21928 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
21929 }
21930
21931 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
21932 V.fill(F0);
21933 if(m_cbcViscous) {
21934 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
21935 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
21936 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
21937 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
21938 &cutOffStencilCellIds[0], &V[0]);
21939 }
21940
21941 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
21942
21943 // This is where you differentiate between inflow and outflow
21944 MFloat un_mean = m_solver->a_pvariable(cellId, PV->VV[dimN]);
21945
21946 MBool isInflow = true;
21947 if(dirN % 2 == 0) {
21948 if(un_mean > F0) {
21949 isInflow = false;
21950 } else {
21951 // T_target_new = T_mean;
21952 }
21953 } else {
21954 if(un_mean < F0) {
21955 isInflow = false;
21956 } else {
21957 // T_target_new = T_mean;
21958 }
21959 }
21960
21961 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
21962 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
21963 const MFloat Temp = sysEqn().temperature_ES(rho, p);
21964 const MFloat a = sysEqn().speedOfSound(Temp);
21965
21966
21967 if(isInflow) {
21968 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
21969 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
21970
21971 MFloat ceta = F1;
21972 if(dirN % 2 == 0)
21973 ceta = -F1;
21974 else
21975 ceta = F1;
21976
21977 K[0] = K[0] / a * m_sigmaNonRefl;
21978 K[last] = K[0];
21979 MFloat beta = F0;
21980
21981 if(dirN % 2 == 0) {
21982 L[0] =
21983 K[0] * (p - p_Target) + (beta - 1) * (T[last] + ceta * rho * a * T[1]) + (V[last] + ceta * rho * a * V[1]);
21984 } else {
21985 L[last] = K[last] * (p - p_Target) + (beta - 1) * (T[last] + ceta * rho * a * T[1])
21986 + (V[last] + ceta * rho * a * V[1]);
21987 }
21988
21989 } else {
21990 cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
21991 cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
21992
21993 K[0] = K[0] * m_sigmaNonRefl;
21994 K[last] = K[0];
21995
21996 MFloat deltaP = (p - p_Target);
21997
21998 if(dirN % 2 == 0) { // outflow on pos. coordinate direction -> L1 has to be modeled
21999 L[0] = K[0] * deltaP;
22000 } else {
22001 L[last] = K[last] * deltaP;
22002 }
22003 }
22004 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
22005 }
22006}
22007
22008
22014template <MInt nDim, class SysEqn>
22016 TRACE();
22017 MInt direction = m_cutOffBndryCndIds[bcId] - 2720;
22018
22019 if(direction % 2) {
22020 direction--;
22021 } else {
22022 direction++;
22023 }
22024
22025 const MInt noPVars = PV->noVariables;
22026
22027 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
22028 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
22029 MLong nghbrId = m_solver->c_neighborId(cellId, direction);
22030
22031 if(nghbrId < 0) {
22032 continue;
22033 }
22034 if(m_solver->c_noChildren(nghbrId) > 0) {
22035 MFloat coCoord = m_solver->a_coordinate(cellId, direction / 2);
22036 MInt childCnt = 0;
22037 // reset cut off cell
22038 for(MInt varId = 0; varId < noPVars; varId++) {
22039 for(MInt i = 0; i < nDim; i++) {
22040 m_solver->a_slope(cellId, varId, i) = F0;
22041 }
22042 }
22043 for(MInt child = 0; child < IPOW2(nDim); child++) {
22044 MInt childId = m_solver->c_childId(nghbrId, child);
22045 if(childId < 0) {
22046 continue;
22047 }
22048 if(abs(m_solver->a_coordinate(childId, direction / 2) - coCoord) > m_solver->c_cellLengthAtCell(cellId)) {
22049 continue;
22050 }
22051 childCnt++;
22052 for(MInt varId = 0; varId < noPVars; varId++) {
22053 for(MInt i = 0; i < nDim; i++) {
22054 m_solver->a_slope(cellId, varId, i) += m_solver->a_slope(childId, varId, i);
22055 }
22056 }
22057 }
22058 for(MInt varId = 0; varId < noPVars; varId++) {
22059 for(MInt i = 0; i < nDim; i++) {
22060 m_solver->a_slope(cellId, varId, i) /= childCnt;
22061 }
22062 }
22063 } else {
22064 // copy the slopes
22065 for(MInt varId = 0; varId < noPVars; varId++) {
22066 for(MInt i = 0; i < nDim; i++) {
22067 m_solver->a_slope(cellId, varId, i) = m_solver->a_slope(nghbrId, varId, i);
22068 }
22069 }
22070 }
22071 }
22072}
22073
22080template <MInt nDim, class SysEqn>
22082 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function sbc2801x is untested for 3D!"); }
22083 TRACE();
22084
22085 MInt bndryId, cellId, ghostCellId;
22086 MFloat Frho, FrhoGhost, rhoU2;
22087 const MInt noPVars = PV->noVariables;
22088 ScratchSpace<MFloat> PVbndry(noPVars, AT_, "PVbndry");
22089 ScratchSpace<MFloat> PVghost(noPVars, AT_, "PVghost");
22090 //---
22091
22092 Frho = FrhoGhost = rhoU2 = 0.0;
22093
22094 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
22095 bndryId = m_sortedBndryCells->a[id];
22096 cellId = m_bndryCells->a[bndryId].m_cellId;
22097 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22098 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
22099
22100 for(MInt i = 0; i < nDim; i++) {
22101 PVbndry[i] = m_solver->a_variable(cellId, CV->RHO_VV[i]) * Frho;
22102 PVghost[i] = m_solver->a_variable(ghostCellId, CV->RHO_VV[i]) * FrhoGhost;
22103 }
22104
22105 // density
22106 PVbndry[PV->RHO] = m_solver->a_variable(cellId, CV->RHO);
22107 PVghost[PV->RHO] = m_solver->a_variable(ghostCellId, CV->RHO);
22108
22109 // pressure
22110 rhoU2 = F0;
22111 for(MInt i = 0; i < nDim; i++) {
22112 rhoU2 += POW2(m_solver->a_variable(cellId, CV->RHO_VV[i]));
22113 }
22114
22115 PVbndry[PV->P] = sysEqn().pressure(Frho, rhoU2, m_solver->a_variable(cellId, CV->RHO_E));
22116 rhoU2 = F0;
22117 for(MInt i = 0; i < nDim; i++) {
22118 rhoU2 += POW2(m_solver->a_variable(ghostCellId, CV->RHO_VV[i]));
22119 }
22120 PVbndry[PV->P] = sysEqn().pressure(FrhoGhost, rhoU2, m_solver->a_variable(ghostCellId, CV->RHO_E));
22121
22122 // species
22123 for(MInt k = 0; k < m_noSpecies; k++) {
22124 PVbndry[PV->Y[k]] = m_solver->a_variable(cellId, CV->RHO_Y[k]) * Frho;
22125 PVghost[PV->Y[k]] = m_solver->a_variable(ghostCellId, CV->RHO_Y[k]) * FrhoGhost;
22126 }
22127
22128 for(MInt var = 0; var < noPVars; var++) {
22129 m_solver->a_slope(ghostCellId, var, 0) =
22130 (PVbndry[var] - PVghost[var])
22131 / (m_solver->a_coordinate(cellId, 0) - m_solver->a_coordinate(ghostCellId, 0));
22132 m_solver->a_slope(ghostCellId, var, 1) = m_solver->a_slope(cellId, var, 1);
22133 }
22134
22135 // compute the slopes on the ghost cell
22136 for(MInt varId = 0; varId < noPVars; varId++) {
22137 for(MInt i = 0; i < nDim; i++) {
22138 m_solver->a_slope(ghostCellId, varId, i) =
22139 F2 * m_solver->a_slope(ghostCellId, varId, i) - m_solver->a_slope(cellId, varId, i);
22140 }
22141 }
22142 }
22143 }
22144}
22151template <MInt nDim, class SysEqn>
22153 IF_CONSTEXPR(!hasE<SysEqn>) {
22154 mTerm(1, AT_, "Not compatible with SysEqn without RHO_E!");
22155 return;
22156 }
22157 IF_CONSTEXPR(nDim == 3) { TERMM(-1, "INFO: function sbc2801x is untested for 3D!"); }
22158 TRACE();
22159
22160 MInt bndryId, cellId, ghostCellId;
22161 MFloat Frho, FrhoGhost, rhoU2;
22162 const MInt noPVars = PV->noVariables;
22163 ScratchSpace<MFloat> PVbndry(noPVars, AT_, "PVbndry");
22164 ScratchSpace<MFloat> PVghost(noPVars, AT_, "PVghost");
22165 //---
22166
22167 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
22168 bndryId = m_sortedBndryCells->a[id];
22169 cellId = m_bndryCells->a[bndryId].m_cellId;
22170 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22171 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
22172
22173 // determine the primitive variables on the boundary and on the ghost cell
22174 Frho = F1 / m_solver->a_variable(cellId, CV->RHO);
22175 FrhoGhost = F1 / m_solver->a_variable(ghostCellId, CV->RHO);
22176 // velocitites
22177 for(MInt i = 0; i < nDim; i++) {
22178 PVbndry[i] = m_solver->a_variable(cellId, CV->RHO_VV[i]) * Frho;
22179 PVghost[i] = m_solver->a_variable(ghostCellId, CV->RHO_VV[i]) * FrhoGhost;
22180 }
22181
22182 // density
22183 PVbndry[PV->RHO] = m_solver->a_variable(cellId, CV->RHO);
22184 PVghost[PV->RHO] = m_solver->a_variable(ghostCellId, CV->RHO);
22185
22186 // pressure
22187 rhoU2 = F0;
22188 for(MInt i = 0; i < nDim; i++) {
22189 rhoU2 += POW2(m_solver->a_variable(cellId, CV->RHO_VV[i]));
22190 }
22191 rhoU2 *= Frho;
22192 PVbndry[PV->P] = sysEqn().pressure(1.0, rhoU2, m_solver->a_variable(cellId, CV->RHO_E));
22193 rhoU2 = F0;
22194 for(MInt i = 0; i < nDim; i++) {
22195 rhoU2 += POW2(m_solver->a_variable(ghostCellId, CV->RHO_VV[i]));
22196 }
22197 rhoU2 *= FrhoGhost;
22198 PVghost[PV->P] = sysEqn().pressure(1.0, rhoU2, m_solver->a_variable(ghostCellId, CV->RHO_E));
22199
22200 // species
22201 for(MInt k = 0; k < m_noSpecies; k++) {
22202 PVbndry[PV->Y[k]] = m_solver->a_variable(cellId, CV->RHO_Y[k]) * Frho;
22203 PVghost[PV->Y[k]] = m_solver->a_variable(ghostCellId, CV->RHO_Y[k]) * FrhoGhost;
22204 }
22205
22206 for(MInt var = 0; var < noPVars; var++) {
22207 m_solver->a_slope(ghostCellId, var, 0) = m_solver->a_slope(cellId, var, 0);
22208 m_solver->a_slope(ghostCellId, var, 1) =
22209 (PVbndry[var] - PVghost[var])
22210 / (m_solver->a_coordinate(cellId, 1) - m_solver->a_coordinate(ghostCellId, 1));
22211 }
22212
22213 // compute the slopes on the ghost cell
22214 for(MInt varId = 0; varId < noPVars; varId++) {
22215 for(MInt i = 0; i < nDim; i++) {
22216 m_solver->a_slope(ghostCellId, varId, i) =
22217 F2 * m_solver->a_slope(ghostCellId, varId, i) - m_solver->a_slope(cellId, varId, i);
22218 }
22219 }
22220 }
22221 }
22222}
22223
22230template <MInt nDim, class SysEqn>
22232 IF_CONSTEXPR(nDim == 2) { TERMM(-1, "INFO: function cbc3091a is untested for 2D!"); }
22233 TRACE();
22234
22235 MFloat dummyTime;
22236 MFloat that, twopioverlb;
22237 MFloat factor1, factor2, b1, b2;
22238 MInt ghost1;
22239 MFloat xhat, yhat, zhat;
22240 MFloat fluctChol[3];
22241 MFloat velocity = F0;
22242 b1 = m_shearLayerThickness;
22243 b2 = m_shearLayerThickness;
22244 MFloat massfluxTest = F0, jetInflowArea = F0;
22245
22246 if(((globalTimeStep - m_solver->m_restartTimeStep) <= 1 || globalTimeStep == 0) && !m_solver->m_restart) {
22247 m_log << "computing mass flux " << endl;
22248
22249 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
22250 ghost1 = m_sortedCutOffCells[bcId]->a[id];
22251 if(m_solver->a_isHalo(ghost1)) continue;
22252
22253 MFloat jetArea = POW2(m_solver->grid().cellLengthAtCell(ghost1));
22254 factor1 = m_solver->a_coordinate(ghost1, 0);
22255 factor2 = m_solver->a_coordinate(ghost1, 2);
22256
22257 velocity = m_solver->m_Ma
22258 * (F1B2 * (1 + tanh(b1 * (factor1 + m_solver->m_jetHalfWidth)))
22259 * (1 - tanh(b1 * (factor1 - m_solver->m_jetHalfWidth)))
22260 - 1)
22261 * (F1B2 * (1 + tanh(b2 * (factor2 + m_solver->m_jetHalfLength)))
22262 * (1 - tanh(b2 * (factor2 - m_solver->m_jetHalfLength)))
22263 - 1);
22264 massfluxTest += m_solver->a_variable(ghost1, PV->RHO) * velocity * jetArea;
22265 jetInflowArea += jetArea;
22266 }
22267
22268 MPI_Allreduce(MPI_IN_PLACE, &massfluxTest, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "massfluxTest");
22269 MPI_Allreduce(MPI_IN_PLACE, &jetInflowArea, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
22270 "jetInflowArea");
22271
22272 // compute static pressure and density iteratively (see e.g. thesis of Ingolf Hoerschler)
22273 // compute massflux per unit area
22274 massfluxTest /= jetInflowArea;
22275
22276 m_solver->m_jetPressure = m_solver->m_PInfinity;
22277 m_solver->m_jetDensity = m_solver->m_rhoInfinity;
22278 m_solver->m_jetTemperature = sysEqn().temperature_ES(m_solver->m_jetDensity, m_solver->m_jetPressure);
22279 m_log << "calculated pressure" << m_solver->m_jetPressure << endl;
22280 m_log << "calculated density" << m_solver->m_jetDensity << endl;
22281 m_log << "calculated temperature at inflow " << m_solver->m_jetTemperature << endl;
22282 m_log << "calculated massflux" << massfluxTest << endl;
22283 }
22284
22285 if(m_sortedCutOffCells[bcId]->size() == 0) {
22286 return;
22287 }
22288
22289 dummyTime = m_solver->m_time / m_bc1601->m_tau_b;
22290
22291 m_bc1601->checkRegeneration(dummyTime);
22292
22293 that = 2.0 * PI * dummyTime;
22294 twopioverlb = 2.0 * PI / m_bc1601->m_l_b;
22295
22296
22297 MInt cbcId = m_cbcBndryCndIds[bcId];
22298
22299 MInt dirN = m_cbcDir[cbcId][0];
22300 MInt dimN = m_cbcDir[cbcId][1];
22301 MInt dimT1 = m_cbcDir[cbcId][2];
22302 MInt dimT2 = m_cbcDir[cbcId][nDim];
22303
22304 MBool solverProfile = Context::getSolverProperty<MBool>("solverProfile", m_solverId, AT_, &solverProfile);
22305 MFloat inflowArea = m_cbcInflowArea[cbcId];
22306 // MFloat R = sqrt(inflowArea / PI);
22307
22308 MInt last = nDim + 1;
22309
22310 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
22311 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
22312 MFloatScratchSpace gradP(nDim, AT_, "gradP");
22313 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
22314 gradY.fill(F0);
22315
22316 MFloatScratchSpace L(PV->noVariables, AT_, "L");
22317 MFloatScratchSpace T(PV->noVariables, AT_, "T");
22318 MFloatScratchSpace V(PV->noVariables, AT_, "V");
22319 MFloatScratchSpace K(PV->noVariables, AT_, "K");
22320
22321 MFloat mach[2] = {F0, F0};
22322 cbcMachCo(bcId, mach);
22323 MFloat maxM = mach[1];
22324
22325 MFloat massflux = F0;
22326 MFloat testSum2 = F0;
22327
22328 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
22329 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
22330 MInt bndryId = m_solver->a_bndryId(cellId);
22331
22332 if(m_solver->a_isHalo(cellId)) continue;
22333 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
22334 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
22335
22336 MFloat area = F0;
22337 if(bndryId > -1) {
22338 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
22339 // cell
22340 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
22341 if(srfcId > -1)
22342 area = m_solver->a_surfaceArea(srfcId);
22343 else
22344 mTerm(1, AT_, "something went wrong!");
22345 } else {
22346 area = m_solver->c_cellLengthAtCell(cellId);
22347 }
22348
22349 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
22350 const MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
22351 const MFloat y = (m_solver->a_coordinate(cellId, dimT1) - m_cbcReferencePoint[cbcId][dimT1]);
22352 testSum2 += area * y * y;
22353 massflux += un * rho * area;
22354 }
22355
22356 MInt noExchangeData = 2;
22357 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
22358 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
22359 comm_buff[0] = massflux;
22360 comm_buff[1] = testSum2;
22361
22362 if(noDomains() > 1) {
22363 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 3, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
22364 AT_, "comm_buff[0]", "comm_buff_result[0]");
22365 }
22366
22367 massflux = comm_buff_result[0];
22368 testSum2 = comm_buff_result[1];
22369
22370 const MFloat TInfinity = m_solver->m_TInfinity;
22371 const MFloat PInfinity = m_solver->m_PInfinity;
22372
22373 MFloat ut1_target = F0;
22374 const MFloat massflux_target = m_solver->m_VInfinity * inflowArea * sysEqn().density_ES(PInfinity, TInfinity);
22375 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
22376 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
22377 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
22378 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
22379 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
22380
22381 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
22382 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
22383
22384 MFloat T_target = sysEqn().temperature_IR(m_solver->m_Ma);
22385
22386 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
22387 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
22388
22389 if(m_solver->a_isHalo(cellId)) continue;
22390 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
22391 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
22392
22393 MInt bndryId = m_solver->a_bndryId(cellId);
22394 if(bndryId > -1) {
22395 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
22396 }
22397
22398 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
22399 V.fill(F0);
22400 if(m_cbcViscous) {
22401 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
22402 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
22403 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
22404 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
22405 &cutOffStencilCellIds[0], &V[0]);
22406 }
22407
22408 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
22409 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
22410 cbcDampingInflow(cellId, bcId, maxM, &K[0], "velocity");
22411
22412 MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
22413 MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
22414 MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
22415 MFloat p = m_solver->a_pvariable(cellId, PV->P);
22416 MFloat temp = sysEqn().temperature_ES(rho, p);
22417 MFloat a = sysEqn().speedOfSound(rho, p);
22418
22419 factor1 = m_solver->a_coordinate(cellId, dimT1);
22420 IF_CONSTEXPR(nDim == 3) { factor2 = m_solver->a_coordinate(cellId, dimT2); }
22421
22422 xhat = twopioverlb * m_solver->a_coordinate(cellId, dimN);
22423 yhat = twopioverlb * m_solver->a_coordinate(cellId, dimT1);
22424 IF_CONSTEXPR(nDim == 2) { zhat = F0; }
22425 IF_CONSTEXPR(nDim == 3) { zhat = twopioverlb * m_solver->a_coordinate(cellId, dimT2); }
22426 fluctChol[dimN] = 0;
22427 fluctChol[dimT1] = 0;
22428 fluctChol[dimT2] = 0;
22429
22430 m_bc1601->calculateFlucts(that, xhat, yhat, zhat, fluctChol);
22431
22432 fluctChol[dimT1] *= (F1B2 * (1 + tanh(b1 * (factor1 + m_solver->m_jetHalfWidth)))
22433 * (1 - tanh(b1 * (factor1 - m_solver->m_jetHalfWidth)))
22434 - 1);
22435 fluctChol[dimT1] *= (F1B2 * (1 + tanh(b2 * (factor2 + m_solver->m_jetHalfLength)))
22436 * (1 - tanh(b2 * (factor2 - m_solver->m_jetHalfLength)))
22437 - 1);
22438 IF_CONSTEXPR(nDim == 3) {
22439 fluctChol[dimT2] *= (F1B2 * (1 + tanh(b1 * (factor1 + m_solver->m_jetHalfWidth)))
22440 * (1 - tanh(b1 * (factor1 - m_solver->m_jetHalfWidth)))
22441 - 1);
22442 fluctChol[dimT2] *= (F1B2 * (1 + tanh(b2 * (factor2 + m_solver->m_jetHalfLength)))
22443 * (1 - tanh(b2 * (factor2 - m_solver->m_jetHalfLength)))
22444 - 1);
22445 }
22446
22447 ut1_target = fluctChol[dimT1];
22448 MFloat un_target = (velocity + fluctChol[1])
22449 * (F1B2 * (1 + tanh(b1 * (factor1 + m_solver->m_jetHalfWidth)))
22450 * (1 - tanh(b1 * (factor1 - m_solver->m_jetHalfWidth)))
22451 - 1)
22452 * (F1B2 * (1 + tanh(b2 * (factor2 + m_solver->m_jetHalfLength)))
22453 * (1 - tanh(b2 * (factor2 - m_solver->m_jetHalfLength)))
22454 - 1);
22455 // F2*massflux_target/inflowArea*(F1-rsquare/(R*R))/rho*un_correctionFactor;
22456
22457 if(solverProfile) un_target = massflux_target / inflowArea / rho;
22458
22459 if(dirN % 2 == 0) {
22460 L[0] = -F1 * K[0] * (un - un_target) + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
22461 } else {
22462 L[last] = K[last] * (un - un_target) + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
22463 }
22464
22465 L[1] = K[1] * (temp - T_target) + (a * a * T[0] - T[last]) - V[last];
22466 L[2] = K[2] * (ut1 - ut1_target) + T[2] + V[2];
22467 IF_CONSTEXPR(nDim == 3) {
22468 MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
22469 MFloat ut2_target = fluctChol[dimT2];
22470 L[3] = K[3] * (ut2 - ut2_target) + T[3] + V[3];
22471 }
22472
22473 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
22474 for(MInt s = 0; s < m_solver->m_noSpecies; s++)
22475 m_solver->a_rightHandSide(cellId, CV->RHO_Y[s]) = F0;
22476 }
22477}
22478
22496template <MInt nDim, class SysEqn>
22498 TRACE();
22499 IF_CONSTEXPR(nDim == 2) TERMM(1, "3D BC!");
22500
22501 if(m_bndryCndCells[bcId] == m_bndryCndCells[bcId + 1]) {
22502 return;
22503 }
22504
22505 MInt cellId, bndryId;
22506 MInt ghostCellId;
22507 MFloat R;
22508 MFloat massflux = F0;
22509 MFloat inflowArea = F0;
22510 MFloat meanPressure;
22511 MFloat localVelocity;
22512 MFloat meanDensity;
22513 MFloat referencePoint[3] = {0.0, 0.0, 0.0};
22514 MFloat normal[3] = {0.0, 0.0, 0.0};
22515 MFloat radius;
22516 MFloat meanVelocity;
22517 MFloat epsilon = 1e-15;
22518 MInt nghbrId;
22519 MInt minTimeSteps = m_static_bc1091MGC_minTimeSteps;
22520 MInt nghbrDir = m_static_bc1091MGC_nghbrDir;
22521 MFloatScratchSpace comm_buff_scratch(5, AT_, "comm_buff_scratch");
22522 MFloatScratchSpace comm_buff_result_scratch(5, AT_, "comm_buff_result_scratch");
22523 MFloat* comm_buff = comm_buff_scratch.getPointer();
22524 MFloat* comm_buff_result = comm_buff_result_scratch.getPointer();
22525 MInt noBndryCndCells = m_bndryCndCells[bcId + 1] - m_bndryCndCells[bcId];
22526 MIntScratchSpace edgeCells_scratch(noBndryCndCells, AT_, "edgeCells_scratch");
22527 MFloatScratchSpace edgeDistance_scratch(noBndryCndCells, AT_, "edgeDistance_scratch");
22528 MIntScratchSpace edgeSurface_scratch(noBndryCndCells, AT_, "edgeSurface_scratch");
22529 MInt edgeCellCounter = m_static_bc1091MGC_edgeCellCounter;
22530 MInt first = m_static_bc1091MGC_first;
22531 MInt first2 = m_static_bc1091MGC_first2;
22532 MFloat distCur;
22533
22534 // --- end of initialization
22535
22536
22537 if(first2) {
22538 // claudia vorsicht: Alte Testcases aendern!
22539 // SUZI_TC: minTimeSteps = 550
22540 // NOZZLE_TC: minTimeSteps = 260
22541 // TINA_TC: minTimeSteps = 520
22542 // spongeLayerType 49: minTimeSteps = 800
22543 // spongeLayerType 50: minTimeSteps = 750
22544 // special treatment for engine test cases: massflux accepted soonest after minTimeSteps time steps
22545 minTimeSteps = Context::getSolverProperty<MInt>("InflowMinTimeSteps", m_solverId, AT_, &minTimeSteps);
22546
22547 // SUZI_TC: nghbrDir = 0
22548 // ELBOW_TC: nghbrDir = 3
22549 // NOZZLE_TC: nghbrDir = 2
22550 // TINA_TC: nghbrDir = 1
22551 // else: nghbrDir = -1
22552 // special treatment: massflux is averaged over two layers
22553 nghbrDir = Context::getSolverProperty<MInt>("InflowNghbrDir", m_solverId, AT_, &nghbrDir);
22554
22555 first2 = false;
22556 }
22557 m_static_bc1091MGC_first2 = first2;
22558
22559 // compute current massflux, inflow area, reference Point and normal of the inflow area
22560 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
22561 cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
22562 bndryId = m_solver->a_bndryId(cellId);
22563 if(m_solver->a_hasProperty(cellId,
22564 SolverCell::IsNotGradient)) { // do not compute massflux of multisolver ghost cells!
22565 continue;
22566 }
22567 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22568 for(MInt srfc = 0; srfc < m_bndryCells->a[m_sortedBndryCells->a[id]].m_noSrfcs; srfc++) {
22569 // search for surfaces which belong to the respective boundary condition
22570 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
22571 // compute massflux through the first cell layer
22572 massflux -= (((m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->U])
22573 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
22574 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0]
22575 + (m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->V])
22576 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
22577 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1]
22578 + (m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->W])
22579 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
22580 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2])
22581 * (m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->RHO]));
22582
22583 if(nghbrDir > -1) {
22584 // compute massflux through the next cell layer
22585 // validity of nghbrId has to be guaranteed by the user! (only for special testcases!)
22586 // only valid if normal is parallel a coordinate axis
22587 nghbrId = m_solver->c_neighborId(cellId, nghbrDir);
22588 massflux -= (((m_solver->a_pvariable(nghbrId, PV->U)) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
22589 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0]
22590 + (m_solver->a_pvariable(nghbrId, PV->V)) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
22591 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1]
22592 + (m_solver->a_pvariable(nghbrId, PV->W)) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
22593 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2])
22594 * (m_solver->a_pvariable(nghbrId, PV->RHO)));
22595 }
22596 inflowArea += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
22597
22598 // compute midpoint of inflow boundary and mean normal
22599 for(MInt i = 0; i < 3; i++) {
22600 referencePoint[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]
22601 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
22602 normal[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
22603 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
22604 }
22605 }
22606 }
22607 }
22608 }
22609
22610 comm_buff[0] = inflowArea;
22611 comm_buff[1] = referencePoint[0];
22612 comm_buff[2] = referencePoint[1];
22613 comm_buff[3] = referencePoint[2];
22614 comm_buff[4] = massflux;
22615
22616 if(noDomains() > 1) {
22617 MPI_Allreduce(comm_buff, comm_buff_result, 5, MPI_DOUBLE, MPI_SUM, m_comm_bc[m_bc_comm_pointer[bcId]], AT_,
22618 "comm_buff", "comm_buff_result");
22619 }
22620
22621 inflowArea = comm_buff_result[0];
22622 referencePoint[0] = comm_buff_result[1];
22623 referencePoint[1] = comm_buff_result[2];
22624 referencePoint[2] = comm_buff_result[3];
22625 massflux = comm_buff_result[4];
22626
22627 for(MInt i = 0; i < 3; i++) {
22628 referencePoint[i] /= inflowArea;
22629 normal[i] /= inflowArea;
22630 }
22631
22632 // special treatment for nozzle testcase
22633 if(string2enum(m_solver->m_testCaseName) == NOZZLE_TC) {
22634 normal[0] = 0.0;
22635 normal[1] = -1.0;
22636 normal[2] = F0;
22637 referencePoint[0] = 0.0;
22638 referencePoint[2] = 0.0;
22639 }
22640
22641 // compute massflux per unit area
22642 if(nghbrDir > -1) {
22643 massflux /= (2.0 * inflowArea);
22644 } else {
22645 massflux /= (inflowArea);
22646 }
22647
22648 // correct massflux if necessary
22649 if(abs(massflux) < epsilon * inflowArea || globalTimeStep < minTimeSteps) {
22650 massflux = F0;
22651 }
22652
22653 // compute static pressure and density iteratively (see e.g. thesis of Ingolf Hoerschler)
22654 meanPressure = sysEqn().p_Ref();
22655 for(MInt i = 0; i < 20; i++) {
22656 meanPressure = sysEqn().pressure_IRit(meanPressure, massflux);
22657 }
22658 meanPressure = meanPressure * sysEqn().p_Ref();
22659 meanDensity = sysEqn().density_IR_P(meanPressure);
22660 meanVelocity = massflux / meanDensity;
22661
22662 R = sqrt(inflowArea / PI);
22663
22664 // "brute force" computation of boundary distance for TINA engine - non-circular inflow...
22665 if(string2enum(m_solver->m_testCaseName) == TINA_TC && first) {
22666 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
22667 cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
22668 bndryId = m_solver->a_bndryId(cellId);
22669 if(m_solver->a_hasProperty(cellId,
22670 SolverCell::IsNotGradient)) { // do not compute massflux of multisolver ghost cells!
22671 continue;
22672 }
22673 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22674 if(m_bndryCells->a[bndryId].m_noSrfcs > 1) {
22675 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
22676 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId != m_bndryCndIds[bcId]) {
22677 edgeCells_scratch[edgeCellCounter] = bndryId;
22678 edgeSurface_scratch[edgeCellCounter] = srfc;
22679 edgeCellCounter++;
22680 }
22681 }
22682 }
22683 }
22684 }
22685 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
22686 cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
22687 bndryId = m_solver->a_bndryId(cellId);
22688 if(m_solver->a_hasProperty(cellId,
22689 SolverCell::IsNotGradient)) { // do not compute massflux of multisolver ghost cells!
22690 continue;
22691 }
22692 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22693 for(MInt srfc = 0; srfc < m_bndryCells->a[m_sortedBndryCells->a[id]].m_noSrfcs; srfc++) {
22694 // search for surfaces which belong to the respective boundary condition
22695 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
22696 edgeDistance_scratch[id - m_bndryCndCells[bcId]] = F2 * R;
22697 for(MInt ec = 0; ec < edgeCellCounter; ec++) {
22698 distCur = F0;
22699 for(MInt d = 0; d < nDim; d++) {
22700 distCur +=
22701 (m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[d]
22702 - m_bndryCells->a[edgeCells_scratch[ec]].m_srfcs[srfc]->m_coordinates[d])
22703 * (m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[d]
22704 - m_bndryCells->a[edgeCells_scratch[ec]].m_srfcs[edgeSurface_scratch[ec]]->m_coordinates[d]);
22705 }
22706 distCur = sqrt(distCur);
22707 if(distCur < edgeDistance_scratch[id - m_bndryCndCells[bcId]]) {
22708 edgeDistance_scratch[id - m_bndryCndCells[bcId]] = distCur;
22709 }
22710 }
22711 }
22712 }
22713 }
22714 }
22715 first = false;
22716 }
22717
22718 m_static_bc1091MGC_first = first;
22719
22720 MFloat K = 1.0;
22721
22722 if(string2enum(m_solver->m_testCaseName) == TINA_TC) {
22723 MFloat Vdot = F0;
22724
22725 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
22726 cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
22727 bndryId = m_solver->a_bndryId(cellId);
22728 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22729 for(MInt srfc = 0; srfc < m_bndryCells->a[m_sortedBndryCells->a[id]].m_noSrfcs; srfc++) {
22730 // search for surfaces which belong to the respective boundary condition
22731 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
22732 // compute radius of the boundary surface and compute velocity according to parabolic profile
22733 radius = POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[0] - referencePoint[0])
22734 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[1] - referencePoint[1])
22735 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[2] - referencePoint[2]);
22736 Vdot += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area * 2.0 * meanVelocity
22737 * (1.0 - radius / POW2(edgeDistance_scratch[id - m_bndryCndCells[bcId]] + sqrt(radius)));
22738 }
22739 }
22740 }
22741 }
22742 if(abs(meanVelocity) > epsilon * inflowArea && abs(Vdot / inflowArea) > epsilon * inflowArea) {
22743 K = meanVelocity / Vdot * inflowArea;
22744 }
22745 }
22746
22747
22748 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
22749 cellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_cellId;
22750 bndryId = m_solver->a_bndryId(cellId);
22751 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22752 for(MInt srfc = 0; srfc < m_bndryCells->a[m_sortedBndryCells->a[id]].m_noSrfcs; srfc++) {
22753 // search for surfaces which belong to the respective boundary condition
22754 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == m_bndryCndIds[bcId]) {
22755 ghostCellId = m_bndryCells->a[m_sortedBndryCells->a[id]].m_srfcVariables[srfc]->m_ghostCellId;
22756
22757 // compute radius of the boundary surface and compute velocity according to parabolic profile
22758 radius = POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[0] - referencePoint[0])
22759 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[1] - referencePoint[1])
22760 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[2] - referencePoint[2]);
22761 localVelocity = 2.0 * meanVelocity * (1.0 - radius / POW2(R));
22762 if(string2enum(m_solver->m_testCaseName) == TINA_TC) {
22763 localVelocity = 2.0 * meanVelocity * K
22764 * (1.0 - radius / POW2(edgeDistance_scratch[id - m_bndryCndCells[bcId]] + sqrt(radius)));
22765 }
22766 if((string2enum(m_solver->m_testCaseName) == NOZZLE_TC) && globalTimeStep >= minTimeSteps) {
22767 localVelocity = -((m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->U])
22768 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0]
22769 + (m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->V])
22770 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1]
22771 + (m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->W])
22772 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2])
22773 * (m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->RHO]) / meanDensity;
22774 }
22775
22776 // set ghost cell variables such that p, rho, v_i are attained on the boundary surface; v is assumed to be
22777 // normal to the surface
22778 m_solver->a_pvariable(ghostCellId, PV->RHO) =
22779 F2 * meanDensity - m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->RHO];
22780 m_solver->a_pvariable(ghostCellId, PV->P) =
22781 F2 * meanPressure - m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->P];
22782 m_solver->a_pvariable(ghostCellId, PV->U) =
22783 -F2 * localVelocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0]
22784 - m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->U];
22785 m_solver->a_pvariable(ghostCellId, PV->V) =
22786 -F2 * localVelocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1]
22787 - m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->V];
22788 m_solver->a_pvariable(ghostCellId, PV->W) =
22789 -F2 * localVelocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2]
22790 - m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->W];
22791
22792 // if ghost cell is located on the surface, set values directly to the computed p, rho, v
22793 if(m_surfaceGhostCell) {
22794 m_solver->a_pvariable(ghostCellId, PV->RHO) = meanDensity;
22795 m_solver->a_pvariable(ghostCellId, PV->P) = meanPressure;
22796 m_solver->a_pvariable(ghostCellId, PV->U) =
22797 -localVelocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0];
22798 m_solver->a_pvariable(ghostCellId, PV->W) =
22799 -localVelocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2];
22800 m_solver->a_pvariable(ghostCellId, PV->V) =
22801 -localVelocity * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1];
22802 }
22803 }
22804 }
22805 }
22806 }
22807
22808 if(globalTimeStep % 10 == 0)
22809 cerr << " ReferencePoint, R, normal, Massflux, pressure, density, velocity: " << referencePoint[0] << " "
22810 << referencePoint[1] << " " << referencePoint[2] << ", " << R << ", " << normal[0] << " " << normal[1] << " "
22811 << normal[2] << ", " << massflux << ", " << meanPressure << ", " << meanDensity << ", " << meanVelocity
22812 << endl;
22813}
22814
22815
22832template <MInt nDim, class SysEqn>
22834 TRACE();
22835 IF_CONSTEXPR(nDim == 2) TERMM(1, "3D BC!");
22836
22837 MInt cellId, bndryId, ghostCellId;
22838 // TINA_TC: L = 400.0
22839 // SUZI_TC: L = 400.0
22840 // standard: L = 400.0
22841 // NOZZLE_TC: L = 300.0
22842 // Pdiff = L * m_deltaP
22843 // m_Ma = 1.0: Pdiff = 0.1
22844 // neu! vorsicht - alte Testfaelle umstellen!
22845 MFloat& timeOfMaxPdiff = m_static_bc1099MGC_timeOfMaxPdiff;
22846 MBool& first = m_static_bc1099MGC_first;
22847 if(first) {
22848 timeOfMaxPdiff = Context::getSolverProperty<MFloat>("timeOfMaxPdiff", m_solverId, AT_, &timeOfMaxPdiff);
22849 // Convert from freestream-based to stagnation-based non-dimensionalization
22850 timeOfMaxPdiff = timeOfMaxPdiff / m_solver->m_timeRef;
22851 first = false;
22852 }
22853 MFloat Pdiff = m_deltaPL;
22854 MFloat fac = 1.0;
22855 if(m_solver->m_time < timeOfMaxPdiff) fac = m_solver->m_time / timeOfMaxPdiff;
22856 const MFloat initialPressure = sysEqn().p_Ref() - Pdiff;
22857 const MFloat deltaPressure = m_solver->m_PInfinity - sysEqn().p_Ref();
22858
22859
22860 //---
22861
22862 for(MInt id = m_bndryCndCells[bcId]; id < m_bndryCndCells[bcId + 1]; id++) {
22863 bndryId = m_sortedBndryCells->a[id];
22864 cellId = m_bndryCells->a[bndryId].m_cellId;
22865
22866 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22867 // set the pressure
22868 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
22869 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId != m_bndryCndIds[bcId]) {
22870 continue;
22871 }
22872 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
22873 m_solver->a_pvariable(ghostCellId, PV->P) =
22874 F2 * (initialPressure + fac * deltaPressure)
22875 - m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->P];
22876
22877 // if ghost cell is located on the surface direct application of the surface pressure
22878 if(m_surfaceGhostCell) m_solver->a_pvariable(ghostCellId, PV->P) = (initialPressure + fac * deltaPressure);
22879
22880
22881 // apply the Neumann bc
22882 m_solver->a_pvariable(ghostCellId, PV->RHO) =
22883 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->RHO];
22884 m_solver->a_pvariable(ghostCellId, PV->U) =
22885 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->U];
22886 m_solver->a_pvariable(ghostCellId, PV->V) =
22887 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->V];
22888 m_solver->a_pvariable(ghostCellId, PV->W) =
22889 m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[PV->W];
22890 }
22891 }
22892 }
22893}
22894
22903// NEW
22904template <MInt nDim, class SysEqn>
22906 TRACE();
22907
22908 if(m_sortedCutOffCells[bcId]->size() == 0) {
22909 return;
22910 }
22911
22912 MInt cbcId = m_cbcBndryCndIds[bcId];
22913
22914 MInt dirN = m_cbcDir[cbcId][0];
22915 MInt dimN = m_cbcDir[cbcId][1];
22916 MInt dimT1 = m_cbcDir[cbcId][2];
22917 MInt dimT2 = m_cbcDir[cbcId][nDim];
22918
22919 MFloat inflowArea = m_cbcInflowArea[cbcId];
22920 MFloat targetPressure = sysEqn().p_Ref();
22921 MInt last = nDim + 1;
22922
22923 const MFloat R = sqrt(inflowArea / PI);
22924 const MFloat gammaMinusOne = m_solver->m_gamma - 1.0;
22925 const MFloat ut1_target = F0;
22926
22927 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
22928 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
22929 MFloatScratchSpace gradP(nDim, AT_, "gradP");
22930 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
22931 gradY.fill(F0);
22932
22933 MFloatScratchSpace L(PV->noVariables, AT_, "L");
22934 MFloatScratchSpace T(PV->noVariables, AT_, "T");
22935 MFloatScratchSpace V(PV->noVariables, AT_, "V");
22936 MFloatScratchSpace K(PV->noVariables, AT_, "K");
22937
22938 MFloat massflux = F0;
22939 MFloat testSum2 = F0;
22940 MFloat T_mean = F0;
22941 MFloat massflux_pos = F0;
22942 MFloat massflux_neg = F0;
22943
22944 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
22945 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
22946 MInt bndryId = m_solver->a_bndryId(cellId);
22947
22948 if(m_solver->a_isHalo(cellId)) continue;
22949 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
22950 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
22951
22952 MFloat area;
22953 if(bndryId > -1) {
22954 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
22955 // cell
22956 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
22957 if(srfcId > -1) {
22958 area = m_solver->a_surfaceArea(srfcId);
22959 } else {
22960 mTerm(1, AT_, "something went wrong!");
22961 }
22962 } else {
22963 area = POW2(m_solver->c_cellLengthAtCell(cellId));
22964 }
22965
22966 MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
22967 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
22968 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
22969 const MFloat un_N = m_solver->a_pvariable(nghbrN, PV->VV[dimN]);
22970 const MFloat Temp = sysEqn().temperature_ES(rho, p);
22971
22972 const MFloat rsquare = POW2(m_solver->a_coordinate(cellId, 0) - m_cbcReferencePoint[cbcId][0])
22973 + POW2(m_solver->a_coordinate(cellId, 1) - m_cbcReferencePoint[cbcId][1])
22974 + POW2(m_solver->a_coordinate(cellId, 2) - m_cbcReferencePoint[cbcId][2]);
22975
22976 testSum2 += area * rsquare;
22977 massflux += un_N * area;
22978 T_mean += Temp * area;
22979
22980 if(un_N > F0) {
22981 massflux_pos += un_N * area;
22982 } else {
22983 massflux_neg += un_N * area;
22984 }
22985 }
22986
22987 MFloat mach[2] = {F0, F0};
22988 cbcMachCo(bcId, mach);
22989 MFloat meanM = mach[0];
22990 MFloat maxM = mach[1];
22991
22992 MInt noExchangeData = 5;
22993 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
22994 MFloatScratchSpace comm_buff_result(noExchangeData, AT_, "comm_buff_result");
22995 comm_buff[0] = massflux;
22996 comm_buff[1] = testSum2;
22997 comm_buff[2] = T_mean;
22998 comm_buff[3] = massflux_pos;
22999 comm_buff[4] = massflux_neg;
23000
23001 if(noDomains() > 1) {
23002 MPI_Allreduce(&comm_buff[0], &comm_buff_result[0], 5, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]],
23003 AT_, "comm_buff[0]", "comm_buff_result[0]");
23004 }
23005
23006 massflux = comm_buff_result[0];
23007 testSum2 = comm_buff_result[2];
23008 T_mean = comm_buff_result[3];
23009 massflux_pos = comm_buff_result[4];
23010 massflux_neg = comm_buff_result[5];
23011 T_mean /= inflowArea;
23012 MFloat massflux_test = F2 * (F1 - testSum2 / (inflowArea * R * R));
23013 MFloat un_correctionFactor = F1;
23014 if(fabs(massflux_test) > m_solver->m_eps) un_correctionFactor = F1 / massflux_test;
23015
23016 MFloat T_target = 1 - gammaMinusOne * F1B2 * (massflux * massflux / inflowArea / inflowArea);
23017 MFloat p_Target = sysEqn().pressure_IR(T_target);
23018
23019 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
23020 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
23021 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
23022 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
23023 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
23024
23025 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
23026 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
23027
23028 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
23029 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
23030
23031 if(m_solver->a_isHalo(cellId)) continue;
23032 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
23033 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
23034
23035 MInt bndryId = m_solver->a_bndryId(cellId);
23036 if(bndryId > -1) {
23037 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
23038 }
23039
23040 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
23041 V.fill(F0);
23042 if(m_cbcViscous) {
23043 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
23044 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
23045 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
23046 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
23047 &cutOffStencilCellIds[0], &V[0]);
23048 }
23049
23050 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
23051
23052 const MFloat rsquare = POW2(m_solver->a_coordinate(cellId, 0) - m_cbcReferencePoint[cbcId][0])
23053 + POW2(m_solver->a_coordinate(cellId, 1) - m_cbcReferencePoint[cbcId][1])
23054 + POW2(m_solver->a_coordinate(cellId, 2) - m_cbcReferencePoint[cbcId][2]);
23055
23056 // This is where you differentiate between inflow and outflow
23057 MFloat un_mean = m_solver->a_pvariable(cellId, PV->VV[dimN]);
23058
23059 MBool isInflow = true;
23060 if(dirN % 2 == 0) {
23061 if(un_mean > F0) {
23062 isInflow = false;
23063 } else {
23064 T_target = abs(massflux_neg) / (abs(massflux_neg) + abs(massflux_pos)) * T_target
23065 + abs(massflux_pos) / (abs(massflux_neg) + abs(massflux_pos)) * T_mean;
23066 }
23067 } else {
23068 if(un_mean < F0) {
23069 isInflow = false;
23070 } else {
23071 T_target = abs(massflux_pos) / (abs(massflux_neg) + abs(massflux_pos)) * T_target
23072 + abs(massflux_neg) / (abs(massflux_neg) + abs(massflux_pos)) * T_mean;
23073 }
23074 }
23075
23076 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
23077 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
23078 MFloat a = sysEqn().speedOfSound(rho, p);
23079
23080 const MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
23081 const MFloat Temp = sysEqn().temperature_ES(rho, p);
23082
23083 targetPressure = p_Target;
23084
23085 if(isInflow) {
23086 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
23087 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
23088
23089 MFloat ceta = F1;
23090 if(dirN % 2 == 0)
23091 ceta = -F1;
23092 else
23093 ceta = F1;
23094
23095 if(dirN % 2 == 0) {
23096 L[0] = K[0] * (p - targetPressure) + (T[last] + ceta * rho * a * T[1]) + (V[last] + ceta * rho * a * V[1]);
23097 } else {
23098 L[last] =
23099 K[last] * (p - targetPressure) + (T[last] + ceta * rho * a * T[1]) + (V[last] + ceta * rho * a * V[1]);
23100 }
23101 L[1] = K[1] * (Temp - T_target) + (a * a * T[0] - T[last]) + (a * a * V[0] - V[last]);
23102 L[2] = K[2] * (ut1 - ut1_target) + T[2] + V[2];
23103 IF_CONSTEXPR(nDim == 3) {
23104 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
23105 const MFloat ut2_target = F0;
23106 L[3] = K[3] * (ut2 - ut2_target) + T[3] + V[3];
23107 }
23108 } else { // Outflow
23109 MFloat beta = meanM;
23110
23111 cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
23112 cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
23113
23114 MFloat ceta = F1;
23115 if(dirN % 2 == 0)
23116 ceta = -F1;
23117 else
23118 ceta = F1;
23119
23120 if(dirN % 2 == 0) // outflow on pos. coordinate direction -> L1 has to be modeled
23121 L[0] = K[0] * (p - targetPressure) + (F1 - beta) * (T[last] + ceta * rho * a * T[1])
23122 + (V[last] + ceta * rho * a * V[1]);
23123 else
23124 L[last] = K[last] * (p - targetPressure) + (F1 - beta) * (T[last] + ceta * rho * a * T[1])
23125 + (V[last] + ceta * rho * a * V[1]);
23126 }
23127 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
23128
23129 MFloat un_target = F2 * massflux / inflowArea * (F1 - rsquare / (R * R)) * un_correctionFactor;
23130 m_solver->a_pvariable(cellId, PV->VV[dimN]) = un_target;
23131 }
23132}
23133
23134
23144template <MInt nDim, class SysEqn>
23146 TRACE();
23147 IF_CONSTEXPR(nDim == 2) TERMM(1, "3D BC!");
23148
23149 if(m_sortedCutOffCells[bcId]->size() == 0) return;
23150
23151 const MInt otherDir[6] = {1, 0, 3, 2, 5, 4};
23152
23153 MBool& first = m_static_cbc1099_1091d_after_first;
23154 MInt& dirN = m_static_cbc1099_1091d_after_dirN;
23155 MInt& dimN = m_static_cbc1099_1091d_after_dimN;
23156 MFloat& interpolationFactor = m_static_cbc1099_1091d_after_interpolationFactor;
23157
23158 if(first) {
23159 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
23160 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
23161 if(noCutOffDirections != noCutOffBndryIds)
23162 mTerm(1, AT_,
23163 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
23164 MInt cutOffBndryIdTmp, cutOffDirectionTmp;
23165 for(MInt i = 0; i < noCutOffBndryIds; i++) {
23166 cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
23167 cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
23168 if(cutOffBndryIdTmp == m_cutOffBndryCndIds[bcId]) {
23169 dirN = otherDir[cutOffDirectionTmp];
23170 break;
23171 }
23172 }
23173 dimN = (MInt)dirN / 2;
23174
23186 interpolationFactor =
23187 Context::getSolverProperty<MFloat>("inOutInterpolationFactor", m_solverId, AT_, &interpolationFactor);
23188
23189 first = false;
23190 }
23191
23192
23193 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
23194 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
23195
23196 if(m_solver->a_isHalo(cellId)) continue;
23197 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
23198 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
23199
23200 // recompute the correct energy:
23201 MFloat rho = m_solver->a_variable(cellId, CV->RHO);
23202 MFloat u_target = m_solver->a_pvariable(cellId, PV->VV[dimN]);
23203 MFloat u_rungeKutta = m_solver->a_variable(cellId, CV->RHO_VV[dimN]) / m_solver->a_variable(cellId, CV->RHO);
23204 MFloat deltaU = u_target - u_rungeKutta;
23205 MFloat u_corrected = u_rungeKutta + deltaU * interpolationFactor;
23206
23207 m_solver->a_variable(cellId, CV->RHO_VV[dimN]) = rho * u_corrected;
23208 m_solver->a_pvariable(cellId, PV->VV[dimN]) = u_corrected;
23209 }
23210}
23211
23212
23218template <MInt nDim, class SysEqn>
23220 TRACE();
23221
23222 if(m_sortedCutOffCells[bcId]->size() == 0) {
23223 return;
23224 }
23225
23226// check cutOfCells:
23227#if !defined NDEBUG
23228 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
23229 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
23230
23231 ASSERT(fabs(m_solver->a_rightHandSide(cellId, CV->RHO)) < m_solver->m_eps, "");
23232 ASSERT(fabs(m_solver->a_rightHandSide(cellId, CV->RHO_VV[0])) < m_solver->m_eps, "");
23233 ASSERT(fabs(m_solver->a_rightHandSide(cellId, CV->RHO_VV[1])) < m_solver->m_eps, "");
23234 ASSERT(fabs(m_solver->a_rightHandSide(cellId, CV->RHO_E)) < m_solver->m_eps, "");
23235 IF_CONSTEXPR(nDim == 3)
23236 ASSERT(fabs(m_solver->a_rightHandSide(cellId, CV->RHO_VV[2])) < m_solver->m_eps, "");
23237 }
23238
23239 // check conservative variables on window and halo-cells:
23240 // uncomment the part below for further debug checks, remaining for documentary purposes
23241 /*
23242 const MInt noChecks = CV->noVariables;
23243 MFloatScratchSpace cellCheck(m_solver->a_noCells(), noChecks, AT_, "cellCheck");
23244 cellCheck.fill(std::numeric_limits<MFloat>::max());
23245
23246 for(MInt cellId = 0; cellId < m_solver->noInternalCells(); cellId++) {
23247 for(MInt v = 0; v < noChecks; v++) {
23248 cellCheck(cellId, v) = m_solver->a_variable(cellId, v);
23249 }
23250 }
23251 m_solver->exchangeData(&cellCheck(0), noChecks);
23252 for(MInt cellId = m_solver->noInternalCells(); cellId < m_solver->c_noCells(); cellId++) {
23253 if(!m_solver->c_isLeafCell(cellId)) continue;
23254 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
23255 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
23256
23257 for(MInt v = 0; v < noChecks; v++) {
23258 if(fabs(cellCheck(cellId, v) - m_solver->a_variable(cellId, v)) > m_solver->m_eps * 10) {
23259 cerr << "Incorrect value at halo-cell: " << m_solver->a_isHalo(cellId) << setprecision(14) << " "
23260 << m_solver->a_variable(cellId, v) << " " << cellCheck(cellId, v) << endl;
23261 }
23262 }
23263 }
23264 */
23265#endif
23266
23267 MInt cbcId = m_cbcBndryCndIds[bcId];
23268
23269 MInt dirN = m_cbcDir[cbcId][0];
23270 MInt dimN = m_cbcDir[cbcId][1];
23271 MInt dimT1 = m_cbcDir[cbcId][2];
23272 MInt dimT2 = m_cbcDir[cbcId][nDim];
23273
23274 MFloat inflowArea = m_cbcInflowArea[cbcId];
23275 inflowArea = inflowArea * m_dirTangent[cbcId][dimT1];
23276
23277 MInt last = nDim + 1;
23278
23279 MFloatScratchSpace gradRho(nDim, AT_, "gradRho");
23280 MFloatScratchSpace gradVV(nDim * nDim, AT_, "gradVV");
23281 MFloatScratchSpace gradP(nDim, AT_, "gradP");
23282 MFloatScratchSpace gradY(mMax(1, m_solver->m_noSpecies * nDim), AT_, "gradY");
23283 gradY.fill(F0);
23284
23285 MFloatScratchSpace L(PV->noVariables, AT_, "L");
23286 MFloatScratchSpace T(PV->noVariables, AT_, "T");
23287 MFloatScratchSpace V(PV->noVariables, AT_, "V");
23288 MFloatScratchSpace K(PV->noVariables, AT_, "K");
23289
23290 MFloat massflux = F0;
23291 MFloat T_mean = F0;
23292 MFloat rho_mean = F0;
23293 MFloat rho_max = F0;
23294 MFloat rho_min = 99;
23295
23296 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
23297 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
23298 MInt bndryId = m_solver->a_bndryId(cellId);
23299
23300 if(m_solver->a_isHalo(cellId)) continue;
23301 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
23302 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
23303
23304 MFloat area = -1;
23305 if(bndryId > -1) {
23306 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
23307 // cell
23308 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
23309 if(srfcId > -1) {
23310 area = m_solver->a_surfaceArea(srfcId);
23311 IF_CONSTEXPR(nDim == 3) ASSERT(area <= POW2(m_solver->c_cellLengthAtCell(cellId)), "");
23312 } else {
23313 for(MInt dir = 0; dir < m_noDirs; dir++) {
23314 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dir];
23315 if(srfcId > -1) break;
23316 }
23317 if(srfcId == -1) {
23318 mTerm(1, AT_, "something went wrong!");
23319 }
23320 area = m_solver->a_surfaceArea(srfcId);
23321 }
23322 } else {
23323 IF_CONSTEXPR(nDim == 2) area = m_solver->c_cellLengthAtCell(cellId);
23324 IF_CONSTEXPR(nDim == 3) area = POW2(m_solver->c_cellLengthAtCell(cellId));
23325 }
23326
23327 ASSERT(area > 0, "");
23328
23329 // recompute area
23330 area = area * m_dirTangent[cbcId][dimT1];
23331
23332 m_solver->setPrimitiveVariables(cellId);
23333
23334 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
23335 MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
23336
23337 MFloat un_N = 0;
23338 MFloat T_N = 1;
23339
23340 if(m_solver->checkNeighborActive(cellId, dirN) && m_solver->a_hasNeighbor(cellId, dirN)) {
23341 const MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
23342
23343 if(m_dirNormal[cbcId][0] > -2) {
23344 for(MInt n = 0; n < nDim; n++) {
23345 un_N += m_solver->a_variable(nghbrN, CV->RHO_VV[n]) / m_solver->a_variable(nghbrN, CV->RHO)
23346 * m_dirNormal[cbcId][n];
23347 }
23348 } else {
23349 un_N = m_solver->a_variable(nghbrN, CV->RHO_VV[dimN]) / m_solver->a_variable(nghbrN, CV->RHO);
23350 }
23351
23352 if(std::isnan(un_N)) {
23353 cerr << "NAN detected in cutOff-Neighbor! " << endl;
23354 }
23355
23356 T_N = sysEqn().temperature_ES(m_solver->a_variable(nghbrN, CV->RHO), m_solver->a_pvariable(nghbrN, PV->P));
23357 }
23358
23359 if(rho < F0 || std::isnan(rho) || std::isnan(un)) {
23360 cerr << "NAN detected in cutOff-Cell " << m_solver->c_globalId(cellId) << " " << m_solver->a_isHalo(cellId) << " "
23361 << m_solver->a_bndryId(cellId) << " " << rho << " " << bcId << endl;
23362 }
23363
23364 // massflux intentionally without rho
23365 massflux += un_N * area;
23366 T_mean += T_N * area;
23367 rho_mean += rho * area;
23368 rho_min = mMin(rho, rho_min);
23369 rho_max = mMax(rho, rho_max);
23370 }
23371
23372 MInt noExchangeData = 3;
23373 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
23374 comm_buff[0] = massflux;
23375 comm_buff[1] = T_mean;
23376 comm_buff[2] = rho_mean;
23377
23378 if(noDomains() > 1) {
23379 MPI_Allreduce(MPI_IN_PLACE, &comm_buff[0], noExchangeData, MPI_DOUBLE, MPI_SUM,
23380 m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_, "MPI_IN_PLACE", "comm_buff[0]");
23381 MPI_Allreduce(MPI_IN_PLACE, &rho_max, 1, MPI_DOUBLE, MPI_MAX, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
23382 "MPI_IN_PLACE", "rho_max");
23383 MPI_Allreduce(MPI_IN_PLACE, &rho_min, 1, MPI_DOUBLE, MPI_MIN, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
23384 "MPI_IN_PLACE", "rho_min");
23385 }
23386
23387 massflux = comm_buff[0];
23388 T_mean = comm_buff[1];
23389 rho_mean = comm_buff[2];
23390
23391 T_mean /= inflowArea;
23392 rho_mean /= inflowArea;
23393
23394 MFloat mach[2] = {F0, F0};
23395 cbcMachCo(bcId, mach);
23396 MFloat meanM = mach[0];
23397 MFloat maxM = mach[1];
23398
23399
23400 MFloat T_out = sysEqn().temperature_IR(massflux / inflowArea);
23401 MFloat p_out = sysEqn().pressure_IR(T_out);
23402 if(p_out / sysEqn().p_Ref() > 1) p_out = sysEqn().p_Ref();
23403 if(T_out > 1) T_out = 1;
23404 const MFloat p_target = p_out;
23405 MFloat T_target;
23406 if(dirN % 2 == 1) {
23407 T_target = T_out; // intake-side
23408 } else {
23409 T_target = T_mean; // exhaust side
23410 }
23411
23412 if(globalTimeStep % 10 == 0 && m_solver->m_RKStep == 0 && domainId() == m_cbcDomainMin[cbcId]) {
23413 cerr << globalTimeStep << " " << bcId << " " << (dirN % 2)
23414 << " M_mean, M_max, T_target, p_target, rho_mean, massflux, T_mean, rho_min, rho_max" << setprecision(9)
23415 << meanM << ", " << maxM << ", " << T_target << ", " << p_target << ", " << rho_mean << ", " << rho_min << ", "
23416 << rho_max << ", " << massflux << " " << T_mean << endl;
23417 // check engine inflow
23418 /*
23419 if(dirN % 2 == 1 && globalTimeStep % 10 == 0 && m_solver->m_engineSetup) {
23420 // compute isotropic inflowFlux for comparison:
23421 const MInt pistonBodyId = 1;
23422 const MInt pistonNormal = 1; // 0: x, 1: y, 2: z
23423 // const MFloat boreArea = PI / 4 / 2;
23424 // for circle with diameter 1 and 2 inflow ducts (TINA)
23425 const MFloat boreArea = PI / 4;
23426 // for circle with diameter 1 and 1 inflow duct ( HELEN)
23427 // const MFloat boreArea = PI / 4 / 4;
23428 // for quarter circle with diameter 1 and 1 inflow duct ( Inflow-test)
23429 const MFloat volFluxMean = fabs(m_solver->m_bodyVelocity[pistonBodyId * nDim + pistonNormal] * boreArea);
23430 const MFloat flux_iso = volFluxMean / inflowArea;
23431 const MFloat flux = massflux / inflowArea;
23432 const MFloat flux_pos = massflux_pos / area_pos;
23433 const MFloat flux_neg = massflux_neg / area_neg;
23434 const MFloat flux_dif = fabs(flux - flux_iso) / flux * 100;
23435 cerr << "Mean flux " << flux << " positive flux " << flux_pos << " negative flux " << flux_neg
23436 << " isotropic inlow flux " << flux_iso << " dif: " << flux_dif << endl;
23437 }
23438 */
23439 }
23440 ASSERT(!std::isnan(massflux), "ERROR: Mass-flux is nan!");
23441
23442 MInt noCutOffBCCells = m_cbcViscous ? m_sortedCutOffCells[bcId]->size() : 1;
23443 MFloatScratchSpace tau(3 * noCutOffBCCells * nDim * nDim, AT_, "tau");
23444 MFloatScratchSpace q(3 * noCutOffBCCells * nDim, AT_, "q");
23445 MFloatScratchSpace gradTau(m_cbcViscous ? (nDim * nDim * nDim) : 1, AT_, "gradTau");
23446 MFloatScratchSpace gradQ(m_cbcViscous ? (nDim * nDim) : 1, AT_, "gradQ");
23447
23448 MIntScratchSpace cutOffStencilCellIds(m_cbcViscous ? m_solver->a_noCells() : 1, AT_, "cutOffStencilCellIds");
23449 if(m_cbcViscous) cbcTauQ(bcId, &tau[0], &q[0], &cutOffStencilCellIds[0]);
23450
23451 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
23452 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
23453
23454 if(m_solver->a_isHalo(cellId)) continue;
23455 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
23456 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
23457
23458 // get neighbor for eddy calculation
23459 MFloat un_N = 0;
23460 MFloat ut_N[nDim - 1] = {0};
23461
23462 // check neighbor active!
23463 if(m_solver->checkNeighborActive(cellId, dirN) && m_solver->a_hasNeighbor(cellId, dirN)) {
23464 const MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
23465
23466 for(MInt n = 0; n < nDim; n++) {
23467 un_N += m_solver->a_variable(nghbrN, CV->RHO_VV[n]) * m_dirNormal[cbcId][n];
23468 ut_N[0] += m_solver->a_variable(nghbrN, CV->RHO_VV[n]) * m_dirTangent[cbcId][n];
23469 }
23470 IF_CONSTEXPR(nDim == 3) { ut_N[1] = m_solver->a_variable(nghbrN, CV->RHO_VV[dimT2]); }
23471 }
23472
23473 MInt bndryId = m_solver->a_bndryId(cellId);
23474 if(bndryId > -1) {
23475 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
23476 }
23477
23478 cbcGradients(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0]);
23479 V.fill(F0);
23480 if(m_cbcViscous) {
23481 cbcGradientsViscous(cellId, bcId, &tau[0], &q[0], &gradTau[0], &gradQ[0], &cutOffStencilCellIds[0]);
23482 gradTau[dimN * IPOW2(nDim) + dimT1 * nDim + dimN] = F0;
23483 IF_CONSTEXPR(nDim == 3) { gradTau[dimN * IPOW2(nDim) + dimT2 * nDim + dimN] = F0; }
23484 cbcViscousTerms<(unsigned char)01111>(cellId, bcId, &tau[0], &gradTau[0], &gradQ[0], &gradVV[0],
23485 &cutOffStencilCellIds[0], &V[0]);
23486 }
23487
23488 cbcTransversalTerms<(unsigned char)11111>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &T[0]);
23489
23490 // eddy detection:
23491 MFloat eddy = POW2(ut_N[0]) / POW2(un_N);
23492 IF_CONSTEXPR(nDim == 3) { eddy = (POW2(ut_N[0]) + POW2(ut_N[1])) / POW2(un_N); }
23493
23494 MBool isInflow = true;
23495 if(dirN % 2 == 0) {
23496 if(un_N > F0) {
23497 isInflow = false;
23498 }
23499 } else {
23500 if(un_N < F0) {
23501 isInflow = false;
23502 }
23503 }
23504
23505 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
23506 MFloat ut1 = F0;
23507
23508 for(MInt n = 0; n < nDim; n++) {
23509 ut1 += m_solver->a_pvariable(cellId, PV->VV[n]) * m_dirTangent[cbcId][n];
23510 }
23511
23512 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
23513 MFloat a = sysEqn().speedOfSound(rho, p);
23514 const MFloat Temp = sysEqn().temperature_ES(rho, p);
23515
23516 if(isInflow) {
23517 cbcOutgoingAmplitudeVariation<1>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
23518 cbcDampingInflow(cellId, bcId, maxM, &K[0], "pressure");
23519
23520 if(dirN % 2 == 0) {
23521 L[0] = K[0] * (p - p_target) + (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
23522 } else {
23523 L[last] = K[last] * (p - p_target) + (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
23524 }
23525
23526 L[1] = K[1] * (Temp - T_target) + (a * a * T[0] - T[last]) - V[last];
23527 L[2] = K[2] * ut1 + T[2] + V[2];
23528 IF_CONSTEXPR(nDim == 3) {
23529 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
23530 L[3] = K[3] * ut2 + T[3] + V[3];
23531 }
23532
23533 MBool limitVariable = false;
23534 if(m_solver->a_pvariable(cellId, PV->RHO) > 1.0000001) {
23535 m_solver->a_pvariable(cellId, PV->RHO) = 1;
23536 limitVariable = true;
23537 }
23538 if(m_solver->a_pvariable(cellId, PV->P) / sysEqn().p_Ref() > 1.0000001) {
23539 m_solver->a_pvariable(cellId, PV->P) = sysEqn().p_Ref();
23540 limitVariable = true;
23541 }
23542
23543 if(limitVariable) {
23544 m_solver->setConservativeVariables(cellId);
23545 }
23546
23547 } else {
23548 MFloat beta = meanM;
23549
23550 cbcOutgoingAmplitudeVariation<0>(cellId, bcId, &gradRho[0], &gradVV[0], &gradP[0], &gradY[0], &L[0]);
23551 cbcDampingOutflow(cellId, bcId, maxM, &K[0]);
23552
23553 if(eddy > 1) {
23554 // TODO labels:FV update testcase to new version!
23555 if(!m_solver->m_engineSetup) {
23556 K[0] = 0;
23557 } else {
23558 // update: only set K1 to zero for considerable mass-flux through the
23559 // boundary!
23560 if(fabs(massflux) > 0.05) {
23561 K[0] = 0;
23562 } else {
23563 // surpress fluctuations in transversal velocities (sponging)
23564 // const MFloat K3 = eta3 * 10 * a / LN;
23565 L[2] = K[2] * ut1 + T[2] + V[2];
23566 IF_CONSTEXPR(nDim == 3) {
23567 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
23568 L[3] = K[3] * ut2 + T[3] + V[3];
23569 }
23570 }
23571 }
23572 }
23573
23574 if(dirN % 2 == 0) {
23575 L[0] = K[0] * (p - p_target) + (F1 - beta) * (T[last] - rho * a * T[1]) + (V[last] - rho * a * V[1]);
23576 } else {
23577 L[last] = K[last] * (p - p_target) + (F1 - beta) * (T[last] + rho * a * T[1]) + (V[last] + rho * a * V[1]);
23578 }
23579
23580 // additional amplitude description for low mass-fluxes at outflow!
23581 if(dirN % 2 != 0 && fabs(massflux) < 0.05 && m_solver->m_engineSetup) {
23582 const MFloat K2_outflow = m_cbcRelax[cbcId][1] * rho * a / m_cbcLref[cbcId];
23583 L[1] = K2_outflow * (Temp - T_target) + (a * a * T[0] - T[last]) - V[last];
23584 }
23585 }
23586
23587 cbcRHS(cellId, bcId, &L[0], &T[0], &V[0]);
23588 }
23589}
23590
23591
23596template <MInt nDim, class SysEqn>
23598 TRACE();
23599
23600 for(auto it = m_sortedCutOffCells.begin(); it != m_sortedCutOffCells.end(); it++) {
23601 delete *it;
23602 }
23603
23604 m_sortedCutOffCells.clear();
23605 mDeallocate(m_bcCo_comm_pointer);
23606}
23607
23613template <MInt nDim, class SysEqn>
23615 TRACE();
23616
23617 m_static_cbc1099_first = true;
23618 m_static_cbc1091_first = true;
23619 m_static_cbc2091a_first = true;
23620 m_static_cbc1091b_first = true;
23621 m_static_cbc2091b_first = true;
23622 m_static_cbc1091c_first = true;
23623 m_static_cbc1091c_after_first = true;
23624 m_static_cbc1091d_first = true;
23625 m_static_cbc1091d_after_first = true;
23626 m_static_cbc2091d_first = true;
23627 m_static_cbc2091d_after_first = true;
23628 m_static_cbc1091e_first = true;
23629 m_static_cbc1099_1091_local_first = true;
23630 m_static_cbc1099_1091_local_comb_first = true;
23631 m_static_cbc2099_1091_local_comb_first = true;
23632 m_static_cbc3091a_first = true;
23633 m_static_cbc1099_1091_engine_first = true;
23634 IF_CONSTEXPR(nDim == 3) {
23635 m_static_cbc1099_1091d_first = true;
23636 m_static_cbc1099_1091d_after_first = true;
23637 }
23638}
23639
23640
23641template <MInt nDim, class SysEqn>
23643 TRACE();
23644 if(m_comm_bc_init > 0) {
23645 for(MInt i = 0; i < m_comm_bc_init; i++) {
23646 if(m_comm_bc[i] != MPI_COMM_NULL && m_comm_bc[i] != MPI_COMM_WORLD) {
23647 MPI_Comm_free(&m_comm_bc[i], AT_, "m_comm_bc[i]");
23648 }
23649 }
23650 }
23651
23652 if(m_comm_bcCo_init > 0) {
23653 for(MInt i = 0; i < m_comm_bcCo_init; i++) {
23654 if(m_comm_bcCo[i] != MPI_COMM_NULL && m_comm_bcCo[i] != MPI_COMM_WORLD) {
23655 MPI_Comm_free(&m_comm_bcCo[i], AT_, "m_comm_bcCo[]i");
23656 }
23657 }
23658 }
23659}
23660
23661
23689template <MInt nDim, class SysEqn>
23690template <class _, std::enable_if_t<nDim == 2, _*>>
23692 TRACE();
23693
23694 const MInt otherDir[2] = {1, 0};
23695 const MInt faceOrder[4] = {2, 1, 3, 0};
23696 const MFloat signCode[2][4] = {{-F1, F1, F1, -F1}, {-F1, -F1, F1, F1}};
23697
23698 //----------------------------------------------------------------------------
23699 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
23700 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
23701
23702 for(MInt f = 0; f < m_noDirs; f++) {
23703 m_bndryCells->a[bndryId].m_externalFaces[f] = false;
23704 }
23705
23706 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints != 2) {
23707 cerr << "** FvBndryCnd2D ERROR" << endl;
23708 cerr << "boundary cell " << bndryId << endl;
23709 cerr << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1) << endl;
23710 cerr << m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints
23711 << " -> number of cut points is not equal two - multiple body surfaces not implemented!" << endl;
23712 continue;
23713 }
23714
23715 const MFloat cellLength = m_solver->c_cellLengthAtCell(cellId);
23716 const MFloat cellHalfLength = F1B2 * cellLength;
23717
23718 if(!m_solver->c_isLeafCell(cellId) || (!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel))) {
23719 m_bndryCells->a[bndryId].m_volume = m_solver->grid().gridCellVolume(m_solver->a_level(cellId));
23720 for(MInt i = 0; i < nDim; i++) {
23721 m_bndryCells->a[bndryId].m_coordinates[i] = F0;
23722 }
23723 m_bndryCells->a[bndryId].m_noSrfcs = 0;
23724 continue;
23725 }
23726
23727 MInt noCutPoints = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
23728
23729 MInt cutPointIds[4] = {-1, -1, -1, -1};
23730 MInt edgeCutPointCounter[4] = {0, 0, 0, 0};
23731 for(MInt cp = 0; cp < noCutPoints; cp++) {
23732 MInt edge = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cp];
23733 ASSERT(edgeCutPointCounter[edge] == 0, "");
23734 cutPointIds[edge] = cp;
23735 edgeCutPointCounter[edge]++;
23736 }
23737
23738 // store relevant cut and corner point information in math. pos. sense of rotation (only convex cells are allowed)
23739 MFloat coords[16];
23740 MInt pointBodyId[8]; // -1: corner point; > -1: cut point with body Id
23741 MInt pointEdgeId[8];
23742 MInt noNodes = 0;
23743 for(MInt n = 0; n < 4; n++) {
23744 MFloat cornerPoint[2] = {F0, F0};
23745 for(MInt d = 0; d < nDim; d++)
23746 cornerPoint[d] = m_solver->a_coordinate(cellId, d) + signCode[d][n] * cellHalfLength;
23747 if(!m_solver->m_geometry->pointIsInside(cornerPoint)) {
23748 for(MInt d = 0; d < nDim; d++)
23749 coords[noNodes * 2 + d] = cornerPoint[d];
23750 pointBodyId[noNodes] = -1; // corner point
23751 pointEdgeId[noNodes] =
23752 faceOrder[n]; // holds the edge which starts in the respective point (math. pos. sense of rotation)
23753 noNodes++;
23754 }
23755 MInt cpId = cutPointIds[faceOrder[n]];
23756 if(cpId > -1) {
23757 for(MInt d = 0; d < nDim; d++)
23758 coords[noNodes * 2 + d] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cpId][d];
23759 pointBodyId[noNodes] = m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cpId]; // point is a cut point
23760 pointEdgeId[noNodes] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cpId]; // cut edge
23761 noNodes++;
23762 }
23763 }
23764 // after this, the original cut point storage can be deleted -> will be stored cut-surface-wise in correct order
23765 // from now on!
23766
23767 // compute cell "volume" and centroid
23768 MFloat volume = F0;
23769 MFloat centroid[2]{};
23770 computePolygon(coords, noNodes, centroid, &volume);
23771
23772 // set up data structure of line segments for easier processing
23773 MInt lineSegments[8][2]; // stores the point Ids of the points defining the different segments
23774 MInt lineTypes[8]; // -2: uncut cartesian face, -1: cut cartesian face, >=0: body segment
23775 MInt edgeLinePointer[4] = {
23776 -1, -1, -1, -1}; // stores segment Id for each (cut or uncut) Cartesian edge which is part of the polygonal
23777 // cell description, -1 if edge is nonFluidSide and thus not part of the polygon
23778 MInt bodyLinePointer[4] = {
23779 -1, -1, -1,
23780 -1}; // stores segment Id for each body surface = non-Cartesian edges in the polygonal cell description
23781 MInt bodyLineCounter = 0; // number of body surfaces
23782 for(MInt segment = 0; segment < noNodes; segment++) {
23783 MInt firstPoint = segment;
23784 MInt secondPoint = (segment + 1) % noNodes;
23785 lineSegments[segment][0] = firstPoint;
23786 lineSegments[segment][1] = secondPoint;
23787 if(pointBodyId[firstPoint] == -1 && pointBodyId[secondPoint] == -1) {
23788 // line segment is uncut cartesian segment
23789 edgeLinePointer[pointEdgeId[firstPoint]] = segment;
23790 lineTypes[segment] = -2; // uncut cartesian face
23791 } else if(pointBodyId[firstPoint] == -1 || pointBodyId[secondPoint] == -1) {
23792 // line segment is cut cartesian segment
23793 edgeLinePointer[pointEdgeId[firstPoint]] = segment;
23794 lineTypes[segment] = -1; // cut cartesian face
23795 } else {
23796 // line segment is body segment with pointBodyId
23797 bodyLinePointer[bodyLineCounter] = segment;
23798 lineTypes[segment] = bodyLineCounter++;
23799 }
23800 if(bodyLineCounter > 1) {
23801 cerr << to_string(m_solver->c_cellLengthAtCell(cellId)) << endl;
23802 cerr << to_string(m_solver->c_cellLengthAtCell(cellId)) << endl;
23803 // cerr << to_string(m_solver->a_surfaceCoordinate( cellId , 1) << endl;
23804 }
23805 }
23806
23807 MFloat cutFaceAreas[4];
23808 MFloat surfCoords[2];
23809 for(MInt dir = 0; dir < m_noDirs; dir++) {
23810 MInt edge = dir;
23811 MInt sideId = dir % 2;
23812 MInt spaceId = dir / 2;
23813 MInt tDir = otherDir[spaceId];
23814 for(MInt j = 0; j < nDim; j++) {
23815 surfCoords[j] = m_solver->a_coordinate(cellId, j);
23816 }
23817 surfCoords[spaceId] += signCode[0][sideId] * cellHalfLength;
23818
23819 MInt segmentId = edgeLinePointer[edge];
23820 if(segmentId == -1) {
23821 // non fluid side
23822 m_bndryCells->a[bndryId].m_externalFaces[dir] = true;
23823 cutFaceAreas[dir] = F0;
23824 } else {
23825 MInt lineType = lineTypes[segmentId];
23826 if(lineType == -2) {
23827 // uncut Cartesian face
23828 cutFaceAreas[dir] = cellLength;
23829 } else {
23830 // cut Cartesian face - compute segment area
23831 MInt point1 = lineSegments[segmentId][0];
23832 MInt point2 = lineSegments[segmentId][1];
23833 MFloat pointDiff = coords[point2 * 2 + tDir] - coords[point1 * 2 + tDir];
23834 cutFaceAreas[dir] = fabs(pointDiff);
23835 surfCoords[tDir] = coords[point1 * 2 + tDir] + F1B2 * pointDiff;
23836 }
23837 }
23838
23839 MBool createSrfc = true;
23840 MInt nghbrId = -1;
23841 if(m_solver->a_hasNeighbor(cellId, dir) > 0) {
23842 nghbrId = m_solver->c_neighborId(cellId, dir);
23843 } else {
23844 if(m_solver->c_parentId(cellId) > -1) {
23845 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId), dir) > 0)
23846 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId), dir);
23847 else
23848 createSrfc = false;
23849 } else
23850 createSrfc = false;
23851 }
23852 if(createSrfc)
23853 if(m_solver->c_noChildren(nghbrId) > 0) createSrfc = false;
23854 if(createSrfc) {
23855 MInt srfcId = m_solver->a_noSurfaces();
23856 m_surfaces.append();
23857 m_solver->a_surfaceOrientation(srfcId) = spaceId;
23858 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
23859 m_solver->a_surfaceNghbrCellId(srfcId, otherDir[sideId]) = cellId;
23860 m_solver->a_surfaceArea(srfcId) = cutFaceAreas[dir];
23861 for(MInt i = 0; i < nDim; i++) {
23862 m_solver->a_surfaceCoordinate(srfcId, i) = surfCoords[i];
23863 }
23864 m_bndryCells->a[bndryId].m_associatedSrfc[dir] = srfcId;
23865 }
23866 }
23867
23868 ASSERT(bodyLineCounter == 1, ""); // in a later version, multiply cut cells can be enabled!
23869 m_bndryCells->a[bndryId].m_noSrfcs = 1;
23870
23871 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
23872 MInt segmentId = bodyLinePointer[srfc];
23873 ASSERT(segmentId > -1, "");
23874 MInt point1 = lineSegments[segmentId][0];
23875 MInt point2 = lineSegments[segmentId][1];
23876
23877 // compute area and normal of body surface
23878 MFloat area = F0;
23879 MFloat normal[2];
23880 MFloat surfaceCoordinates[2];
23881 // compute body surfaces
23882 MFloat deltaX = coords[point2 * 2] - coords[point1 * 2];
23883 MFloat deltaY = coords[point2 * 2 + 1] - coords[point1 * 2 + 1];
23884 area = sqrt(deltaX * deltaX + deltaY * deltaY);
23885 normal[0] = -deltaY / mMax(m_solver->m_eps, area);
23886 normal[1] = deltaX / mMax(m_solver->m_eps, area);
23887 surfaceCoordinates[0] = coords[point1 * 2 + 0] + F1B2 * deltaX;
23888 surfaceCoordinates[1] = coords[point1 * 2 + 1] + F1B2 * deltaY;
23889
23890 // store cut point information
23891 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_noCutPoints = 2;
23892 for(MInt i = 0; i < nDim; i++) {
23893 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_cutCoordinates[0][i] = coords[point1 * 2 + i];
23894 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_cutCoordinates[1][i] = coords[point2 * 2 + i];
23895 }
23896 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_cutEdge[0] = pointEdgeId[point1];
23897 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_cutEdge[1] = pointEdgeId[point2];
23898 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0] = pointBodyId[point1];
23899 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[1] = pointBodyId[point2];
23900
23901 // store body surface information
23902 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area = area;
23903 for(MInt i = 0; i < nDim; i++) {
23904 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i] = normal[i];
23905 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i] = surfaceCoordinates[i];
23906 }
23907 }
23908
23909 m_bndryCells->a[bndryId].m_volume = volume;
23910 for(MInt i = 0; i < nDim; i++) {
23911 m_bndryCells->a[bndryId].m_coordinates[i] = centroid[i] - m_solver->a_coordinate(cellId, i);
23912 }
23913
23914 // for debug purpose: check cell areas:
23915 MFloat areaCheck[2] = {F0, F0};
23916 const MFloat checkEps = 1e-12;
23917 for(MInt i = 0; i < nDim; i++) {
23918 areaCheck[i] += (cutFaceAreas[2 * i] - cutFaceAreas[2 * i + 1]);
23919 }
23920 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
23921 for(MInt i = 0; i < nDim; i++) {
23922 areaCheck[i] +=
23923 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
23924 }
23925 }
23926 MBool checkPassed = ((fabs(areaCheck[0]) < checkEps) && (fabs(areaCheck[1]) < checkEps));
23927 if(!checkPassed) {
23928 cerr << "** FvBndryCnd2D WARNING" << endl;
23929 cerr << "boundary cell " << bndryId << endl;
23930 cerr << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1) << endl;
23931 cerr << " -> boundary cell check not passed! " << endl;
23932 cerr << " area check: " << areaCheck[0] << " " << areaCheck[1] << endl;
23933 continue;
23934 }
23935 }
23936}
23937
23938
23962template <MInt nDim, class SysEqn>
23963template <class _, std::enable_if_t<nDim == 3, _*>>
23965 TRACE();
23966
23967 static constexpr MInt edgeCode[24] = {8, 10, 0, 4, 9, 11, 1, 5, 2, 6, 8, 9, 3, 7, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7};
23968 static constexpr MInt faceCode[24] = {0, 4, 1, 4, 2, 4, 3, 4, 0, 5, 1, 5, 2, 5, 3, 5, 0, 2, 1, 2, 0, 3, 1, 3};
23969 MBoolScratchSpace cutFaces(m_noDirs, AT_, "cutFaces");
23970 MBoolScratchSpace cutEdgesAll(m_noEdges, AT_, "cutEdgesAll");
23971 MBoolScratchSpace faceGeometryIsTriangle(m_noDirs, AT_, "faceGeometryIsTriangle");
23972 MBoolScratchSpace nonFluidSideEdge(m_noEdges, AT_, "nonFluidSideEdge");
23973 MBoolScratchSpace shapeIsInside(m_noDirs, AT_, "shapeIsInside");
23974 MBool positiveSlope;
23975 MBool pointInside;
23976 MInt edgeCounter;
23977 MInt face0 = 0, face1 = 0;
23978 const MInt noCells = m_bndryCells->size();
23979 MIntScratchSpace cutPointOnEdge(m_noEdges, AT_, "cutPointOnEdge");
23980 MIntScratchSpace noNonFluidEdges(m_noDirs, AT_, "noNonFluidEdges");
23981 MIntScratchSpace cutEdges(4, AT_, "cutEdges");
23982 MIntScratchSpace cutPoint(4, AT_, "cutPoint");
23983 MFloatScratchSpace cc0(nDim, AT_, "cc0");
23984 MFloatScratchSpace cc1(nDim, AT_, "cc1");
23985 MFloatScratchSpace cutLineLength(m_noEdges, AT_, "cutLineLength");
23986 MFloatScratchSpace faceVolume(m_noDirs, AT_, "faceVolume");
23987 MFloatScratchSpace gridFaceVolume(m_noDirs, AT_, "gridFaceVolume");
23988 MFloatScratchSpace cutLineCentroid(m_noDirs * nDim, AT_, "cutLineCentroid");
23989 MFloat cutOutVolume;
23990 MFloatScratchSpace delta_scratch(m_noDirs * nDim, AT_, "delta_scratch");
23991 MFloat* delta = delta_scratch.getPointer();
23992 MFloat dfcc[2];
23993 MFloatScratchSpace faceCentroid(m_noDirs * nDim, AT_, "faceCentroid");
23994 MFloatScratchSpace triangleCentroid(m_noDirs * nDim, AT_, "triangleCentroid");
23995 MFloatScratchSpace normalVector(m_noDirs * nDim, AT_, "normalVector");
23996 MFloat negativePoint[3] = {0, 0, 0};
23997 MFloat oppositePoint[3] = {0, 0, 0};
23998 MFloat point[3] = {0, 0, 0};
23999 MFloat pointP[3] = {0, 0, 0};
24000 MFloat pointM[3] = {0, 0, 0};
24001 MFloat pointW[3] = {0, 0, 0};
24002 MFloat pointE[3] = {0, 0, 0};
24003 MFloat pointBR[3] = {0, 0, 0};
24004 MFloat pointTL[3] = {0, 0, 0};
24005 MFloat rectVolume, triVolume;
24006 MFloat trianglePoint[3] = {0, 0, 0};
24007 MFloat trianglePointP[3] = {0, 0, 0};
24008 MFloat trianglePointM[3] = {0, 0, 0};
24009 MFloat trianglePointW[3] = {0, 0, 0};
24010 MFloat trianglePointE[3] = {0, 0, 0};
24011 //---
24012
24013 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
24014 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
24015 MInt noCutFaces = 0;
24016 m_bndryCells->a[bndryId].m_noSrfcs = 1;
24017
24018 for(MInt f = 0; f < m_noDirs; f++) {
24019 m_bndryCells->a[bndryId].m_externalFaces[f] = false;
24020 }
24021
24022 // reset all local variables
24023 fill_n(&cutEdgesAll[0], m_noEdges, false);
24024 fill_n(&nonFluidSideEdge[0], m_noEdges, false);
24025 fill_n(&cutPointOnEdge[0], m_noEdges, -1);
24026 fill_n(&cutFaces[0], m_noDirs, false);
24027 fill_n(&faceGeometryIsTriangle[0], m_noDirs, false);
24028 fill_n(&shapeIsInside[0], m_noDirs, false);
24029
24030 const MFloat eps = m_solver->c_cellLengthAtCell(cellId) * 0.00001;
24031
24032 if(!m_solver->c_isLeafCell(cellId) || (!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel))) {
24033 m_bndryCells->a[bndryId].m_volume = m_solver->grid().gridCellVolume(m_solver->a_level(cellId));
24034 for(MInt i = 0; i < nDim; i++) {
24035 m_bndryCells->a[bndryId].m_coordinates[i] = F0;
24036 }
24037 m_bndryCells->a[bndryId].m_noSrfcs = 0;
24038 continue;
24039 }
24040
24041 // store all cut points in a separate array
24042 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
24043 cutPointOnEdge[m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cp]] = cp;
24044 }
24045
24046 // I.
24047 // --
24048 // determine the cut geometry for each face
24049 // assuming that each face has either 0 or 2 cut points
24050 for(MInt face = 0; face < m_noDirs; face++) {
24051 // assemble face edges and cut points
24052 MInt n = 0;
24053 for(MInt e = 0; e < 4; e++) {
24054 MInt cp = cutPointOnEdge[edgeCode[4 * face + e]];
24055 if(cp > -1) {
24056 cutPoint[n] = cp;
24057 cutEdges[n] = e;
24058 cutEdgesAll[edgeCode[4 * face + e]] = true;
24059 n++;
24060 }
24061 }
24062
24063 if(n > 0) {
24064 cutFaces[face] = true;
24065 noCutFaces++;
24066 }
24067
24068 if(n == 1 || n > 2) {
24069 cerr << "** ERROR create cut face: " << n << " cut points for face " << face << endl;
24070 stringstream errorMessage;
24071 errorMessage << "create cut face: " << n << " cut points for face " << face;
24072 cerr << "cell " << cellId << " cog " << m_solver->a_coordinate(cellId, 0) << " "
24073 << m_solver->a_coordinate(cellId, 1) << " " << m_solver->a_coordinate(cellId, 2) << endl;
24074 cerr << "level " << m_solver->a_level(cellId) << endl;
24075 cerr << "edges that get cut: " << endl;
24076 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
24077 cerr << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cp] << endl;
24078 }
24079
24080 stringstream fileName;
24081 fileName << "multipleCutCell_" << cellId << ".stl";
24082 cerr << "Writing stl-file of cell " << cellId << " to " << (fileName.str()) << endl;
24083 writeStlFileOfCell(cellId, (fileName.str()).c_str());
24084
24085 mTerm(1, AT_, errorMessage.str());
24086 }
24087
24088 const MInt spaceId = face / 2;
24089 const MInt sideId = face % 2;
24090 const MInt spaceId1 = (spaceId + 1) % nDim;
24091 const MInt spaceId2 = (spaceId1 + 1) % nDim;
24092
24093 const MInt nDimFaceSpaceId1 = nDim * face + spaceId1;
24094 const MInt nDimFaceSpaceId2 = nDim * face + spaceId2;
24095
24096 gridFaceVolume[face] = POW2(m_solver->c_cellLengthAtCell(cellId));
24097 faceVolume[face] = gridFaceVolume[face];
24098
24099 // set the reference points
24100 for(MInt i = 0; i < nDim; i++) {
24101 point[i] = m_solver->a_coordinate(cellId, i) - F1B2 * m_solver->c_cellLengthAtCell(cellId);
24102 negativePoint[i] = point[i];
24103 oppositePoint[i] = point[i] + m_solver->c_cellLengthAtCell(cellId);
24104 }
24105
24106 // set the secondary coordinate (spaceId) of the reference points
24107 point[spaceId] += (MFloat)sideId * m_solver->c_cellLengthAtCell(cellId);
24108 oppositePoint[spaceId] = point[spaceId];
24109 pointBR[spaceId] = point[spaceId];
24110 pointTL[spaceId] = point[spaceId];
24111
24112 pointBR[spaceId1] = oppositePoint[spaceId1];
24113 pointBR[spaceId2] = point[spaceId2];
24114 pointTL[spaceId1] = point[spaceId1];
24115 pointTL[spaceId2] = oppositePoint[spaceId2];
24116
24117 // inside / outside check for point
24118 for(MInt i = 0; i < nDim; i++) {
24119 pointP[i] = point[i];
24120 pointM[i] = point[i];
24121 pointW[i] = point[i];
24122 pointE[i] = point[i];
24123 }
24124 pointP[spaceId1] += eps;
24125 pointM[spaceId1] -= eps;
24126 pointW[spaceId2] += eps;
24127 pointE[spaceId2] -= eps;
24128
24129 pointInside = m_solver->m_geometry->pointIsInside2(point);
24130
24131 MBool pointBRInside_ = false;
24132 MBool pointTLInside_ = false;
24133
24134 // Note: this prevents costly pointIsInside2() calls if they are not required
24135 auto pointBRInside = [this, &pointBRInside_, &pointBR]() {
24136 static MFloat lastPoint[3] = {MFloatNaN, MFloatNaN, MFloatNaN};
24137 // Return the stored value if already computed for this point
24138 if(std::equal(&pointBR[0], &pointBR[0] + nDim, &lastPoint[0])) {
24139 return pointBRInside_;
24140 } else {
24141 // Determine if point is inside and store position
24142 pointBRInside_ = m_solver->m_geometry->pointIsInside2(pointBR);
24143 std::copy_n(&pointBR[0], nDim, &lastPoint[0]);
24144 return pointBRInside_;
24145 }
24146 };
24147
24148 auto pointTLInside = [this, &pointTLInside_, &pointTL]() {
24149 static MFloat lastPoint[3] = {MFloatNaN, MFloatNaN, MFloatNaN};
24150 if(std::equal(&pointTL[0], &pointTL[0] + nDim, &lastPoint[0])) {
24151 return pointTLInside_;
24152 } else {
24153 pointTLInside_ = m_solver->m_geometry->pointIsInside2(pointTL);
24154 std::copy_n(&pointTL[0], nDim, &lastPoint[0]);
24155 return pointTLInside_;
24156 }
24157 };
24158
24159
24160 //##start of bndryRfnJumpMethod part
24161
24162 // stencil to determin in which cell-corner the Point, BR or TL corner of the face is
24163 const MInt BRInCorner[6] = {2, 3, 4, 6, 1, 5};
24164 const MInt TLInCorner[6] = {4, 5, 1, 3, 2, 6};
24165 const MInt pointInCorner[6] = {0, 1, 0, 2, 0, 4};
24166 const MInt oppositeInCorner[6] = {6, 7, 5, 7, 3, 7};
24180 // TODO labels:FV move property to initialization
24181 MBool bndryRfnJump = false;
24182 bndryRfnJump = Context::getSolverProperty<MBool>("bndryRfnJump", m_solverId, AT_, &bndryRfnJump);
24183
24184 if(bndryRfnJump == 1) {
24185 // change if the point is inside or not
24186 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] == face
24187 || m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] == face
24188 || m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] == face) {
24189 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] == BRInCorner[face]) {
24190 if(pointBRInside() == false) {
24191 pointBRInside_ = true;
24192 } else {
24193 pointBRInside_ = false;
24194 }
24195 }
24196 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] == TLInCorner[face]) {
24197 if(pointTLInside() == false) {
24198 pointTLInside_ = true;
24199 } else {
24200 pointTLInside_ = false;
24201 }
24202 }
24203 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] == pointInCorner[face]) {
24204 if(pointInside == false) {
24205 pointInside = true;
24206 } else {
24207 pointInside = false;
24208 }
24209 }
24210 }
24211 }
24212 //##end of bndryRfnJumpMethodPart
24213
24214
24215 faceCentroid[face * nDim + spaceId] = point[spaceId];
24216
24217 if(n == 2) {
24218 // delta of cut point coordinates, sign of the cut line slope
24219 for(MInt i = 0; i < nDim; i++) {
24220 delta[face * nDim + i] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoint[0]][i]
24221 - m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoint[1]][i];
24222 }
24223 if(delta[nDimFaceSpaceId1] * delta[nDimFaceSpaceId2] > 0) {
24224 positiveSlope = true;
24225 } else {
24226 positiveSlope = false;
24227 }
24228
24229 for(MInt i = 0; i < nDim; i++) {
24230 delta[face * nDim + i] = fabs(delta[face * nDim + i]);
24231 }
24232
24233 // compute the length of the cut line
24234 cutLineLength[face] = sqrt(POW2(delta[nDimFaceSpaceId1]) + POW2(delta[nDimFaceSpaceId2]));
24235
24236 // compute the coordinates of the cut line centroid
24237 for(MInt i = 0; i < nDim; i++) {
24238 cutLineCentroid[face * nDim + i] =
24239 F1B2
24240 * (m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoint[0]][i]
24241 + m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoint[1]][i]);
24242 }
24243
24244 // compute the volume and the normal vector of the cut face
24245 // assuming 2 cut points!!! (checked above)
24246 // space0: space Id of the first cut edge
24247 // space1: space Id of the second cut edge
24248 // *Relative: in two-dimensional space0-space1 space, either 0 or 1
24249 const MInt space0Relative = cutEdges[0] / 2;
24250 const MInt space1Relative = cutEdges[1] / 2;
24251 const MInt space0 = (space0Relative + spaceId + 1) % nDim;
24252 const MInt side0 = cutEdges[0] % 2;
24253 const MInt space1 = (space1Relative + spaceId + 1) % nDim;
24254 const MInt side1 = cutEdges[1] % 2;
24255
24256 // compute the absolute values of the normal vector components
24257 normalVector[face * nDim + spaceId] = 0;
24258 normalVector[nDimFaceSpaceId1] = delta[nDimFaceSpaceId2] / cutLineLength[face];
24259 normalVector[nDimFaceSpaceId2] = delta[nDimFaceSpaceId1] / cutLineLength[face];
24260
24261
24262 // determine the cut geometry and compute
24263 // - the volume of the boundary cell
24264 // - the coordinate shift
24265 // - nonFluidSides
24266 if(space0 != space1) {
24267 // 1. the cut geometry is a triangle
24268 faceGeometryIsTriangle[face] = true;
24269 faceVolume[face] = F1B2 * (delta[nDimFaceSpaceId1] * delta[nDimFaceSpaceId2]);
24270
24271 trianglePoint[space0] = point[space0] + m_solver->c_cellLengthAtCell(cellId) * (MFloat)side0;
24272 trianglePoint[space1] = point[space1] + m_solver->c_cellLengthAtCell(cellId) * (MFloat)side1;
24273 trianglePoint[spaceId] = point[spaceId];
24274
24275 for(MInt i = 0; i < nDim; i++) {
24276 trianglePointP[i] = trianglePoint[i];
24277 trianglePointM[i] = trianglePoint[i];
24278 trianglePointW[i] = trianglePoint[i];
24279 trianglePointE[i] = trianglePoint[i];
24280 }
24281 trianglePointP[spaceId1] += eps;
24282 trianglePointM[spaceId1] -= eps;
24283 trianglePointW[spaceId2] += eps;
24284 trianglePointE[spaceId2] -= eps;
24285
24286 faceCentroid[face * nDim + space0] =
24287 trianglePoint[space0] + F2B3 * (F1B2 - (MFloat)side0) * delta[face * nDim + space0];
24288 faceCentroid[face * nDim + space1] =
24289 trianglePoint[space1] + F2B3 * (F1B2 - (MFloat)side1) * delta[face * nDim + space1];
24290
24291 for(MInt i = 0; i < nDim; i++) {
24292 triangleCentroid[face * nDim + i] = faceCentroid[face * nDim + i];
24293 }
24294
24295 //##start of bndryRfnJumpMethodPart
24296 MBool problemFace = false;
24297 if(bndryRfnJump == 1) {
24298 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 0] == face) {
24299 // cerr << "we are currently on a problem face: " << face << endl;
24300 // cerr << "cellId: " << cellId << endl;
24301 problemFace = true;
24302 }
24303 // in case of removed cut points
24304 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 2] == face) {
24305 // cerr << "we are currently on a problem face: " << face << endl;
24306 // cerr << "cellId: " << cellId << endl;
24307 problemFace = true;
24308 }
24309 // in case of new boundary cell
24310 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 3] == face) {
24311 // cerr << "we are currently on a problem face: " << face << endl;
24312 // cerr << "cellId: " << cellId << endl;
24313 problemFace = true;
24314 }
24315 }
24316 MInt triangleCase = -1;
24317 MBool trianglePointInside = false;
24318 if(bndryRfnJump == 1) {
24319 if(m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1] != -1) {
24320 if(trianglePoint[0] - point[0] < eps && trianglePoint[1] - point[1] < eps
24321 && trianglePoint[2] - point[2] < eps) {
24322 // cerr << "triangle point is the same as point" << endl;
24323 triangleCase = 0;
24324 trianglePointInside = pointInside;
24325 }
24326 if(trianglePoint[0] - pointBR[0] < eps && trianglePoint[1] - pointBR[1] < eps
24327 && trianglePoint[2] - pointBR[2] < eps && triangleCase == -1) {
24328 // cerr << "triangle point is the same as pointBR" << endl;
24329 triangleCase = 1;
24330 trianglePointInside = pointBRInside();
24331 }
24332 if(trianglePoint[0] - pointTL[0] < eps && trianglePoint[1] - pointTL[1] < eps
24333 && trianglePoint[2] - pointTL[2] < eps && triangleCase == -1) {
24334 // cerr << "triangle point is the same as point" << endl;
24335 triangleCase = 2;
24336 trianglePointInside = pointTLInside();
24337 }
24338 if(triangleCase == -1) {
24339 // cerr << "triangle point is different from the 3 other points" << endl;
24340 triangleCase = 3;
24341 trianglePointInside = m_solver->m_geometry->pointIsInside2(trianglePoint);
24342 // cerr << "before: " << trianglePointInside << endl;
24343 if(oppositeInCorner[face]
24344 == m_solver->m_bndryRfnJumpInformation[m_bndryCells->a[bndryId].m_cellId * 4 + 1]) {
24345 trianglePointInside = 1 - trianglePointInside;
24346 }
24347 // cerr << "after: " << trianglePointInside << endl;
24348 }
24349 }
24350 }
24351 if(problemFace == true) {
24352 // cerr << "triangle case: " << triangleCase << endl;
24353 // check if the third triangle point is inside or outside
24354 // if( m_solver->m_geometry->pointIsInside2( trianglePoint ) )
24355 if(trianglePointInside == false) {
24356 // computed volume is the boundary cell volume
24357 noNonFluidEdges[face] = 2;
24358 nonFluidSideEdge[edgeCode[4 * face + 2 * space0Relative + ((side0 + 1) % 2)]] = true;
24359 nonFluidSideEdge[edgeCode[4 * face + 2 * space1Relative + ((side1 + 1) % 2)]] = true;
24360
24361 } else {
24362 // computed volume is inside the geometry and cut out
24363 shapeIsInside[face] = true;
24364 cutOutVolume = faceVolume[face];
24365 faceVolume[face] = gridFaceVolume[face] - faceVolume[face];
24366 faceCentroid[face * nDim + space0] = F1 / faceVolume[face]
24367 * ((gridFaceVolume[face] * m_solver->a_coordinate(cellId, space0))
24368 - (cutOutVolume * faceCentroid[face * nDim + space0]));
24369 faceCentroid[face * nDim + space1] = F1 / faceVolume[face]
24370 * ((gridFaceVolume[face] * m_solver->a_coordinate(cellId, space1))
24371 - (cutOutVolume * faceCentroid[face * nDim + space1]));
24372
24373 // no non-fluid edge
24374 noNonFluidEdges[face] = 0;
24375 // DEBUG (not required)
24376 for(MInt e = 0; e < 4; e++) {
24377 if(nonFluidSideEdge[edgeCode[4 * face + e]]) {
24378 cerr << "triangle case: " << triangleCase << endl;
24379 for(MInt i = 0; i < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; i++) {
24380 cerr << "cut point: " << i << " cut edge: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[i]
24381 << endl;
24382 }
24383 cerr << cellId << " " << bndryId << endl;
24384 cerr << "Error non-fluid edge was true for edge " << edgeCode[4 * face + e] << " face " << face
24385 << endl;
24386 cerr << "All face data " << noNonFluidEdges[0] << noNonFluidEdges[1] << noNonFluidEdges[2]
24387 << noNonFluidEdges[3] << noNonFluidEdges[4] << noNonFluidEdges[5] << endl;
24388 cerr << "All edge data " << nonFluidSideEdge[edgeCode[0]] << nonFluidSideEdge[edgeCode[1]]
24389 << nonFluidSideEdge[edgeCode[2]] << nonFluidSideEdge[edgeCode[3]] << " "
24390 << nonFluidSideEdge[edgeCode[4]] << nonFluidSideEdge[edgeCode[5]]
24391 << nonFluidSideEdge[edgeCode[6]] << nonFluidSideEdge[edgeCode[7]] << " "
24392 << nonFluidSideEdge[edgeCode[8]] << nonFluidSideEdge[edgeCode[9]]
24393 << nonFluidSideEdge[edgeCode[10]] << nonFluidSideEdge[edgeCode[11]] << endl;
24394 cerr << "cell " << cellId << " domain " << domainId() << " "
24395 << "bndryId " << bndryId << " " << m_solver->a_coordinate(cellId, 0) << " "
24396 << m_solver->a_coordinate(cellId, 1) << " " << m_solver->a_coordinate(cellId, 2) << endl;
24397 cerr << " " << endl;
24398 }
24399 nonFluidSideEdge[edgeCode[4 * face + e]] = false;
24400 }
24401 }
24402 }
24403 if(problemFace == false) {
24404 //##end of bndryRfnJumpMethodPart
24405 // check if the third triangle point is inside or outside
24406 if(m_solver->m_geometry->pointIsInside2(trianglePoint)) {
24407 // computed volume is inside the geometry and cut out
24408 shapeIsInside[face] = true;
24409 cutOutVolume = faceVolume[face];
24410 faceVolume[face] = gridFaceVolume[face] - faceVolume[face];
24411 faceCentroid[face * nDim + space0] = F1 / faceVolume[face]
24412 * ((gridFaceVolume[face] * m_solver->a_coordinate(cellId, space0))
24413 - (cutOutVolume * faceCentroid[face * nDim + space0]));
24414 faceCentroid[face * nDim + space1] = F1 / faceVolume[face]
24415 * ((gridFaceVolume[face] * m_solver->a_coordinate(cellId, space1))
24416 - (cutOutVolume * faceCentroid[face * nDim + space1]));
24417
24418 // no non-fluid edge
24419 noNonFluidEdges[face] = 0;
24420 // DEBUG (not required)
24421 for(MInt e = 0; e < 4; e++) {
24422 if(nonFluidSideEdge[edgeCode[4 * face + e]]) {
24423 cerr << cellId << " " << bndryId << endl;
24424 cerr << "Error non-fluid edge was true for edge " << edgeCode[4 * face + e] << " face " << face
24425 << endl;
24426 cerr << "All face data " << noNonFluidEdges[0] << noNonFluidEdges[1] << noNonFluidEdges[2]
24427 << noNonFluidEdges[3] << noNonFluidEdges[4] << noNonFluidEdges[5] << endl;
24428 cerr << "All edge data " << nonFluidSideEdge[edgeCode[0]] << nonFluidSideEdge[edgeCode[1]]
24429 << nonFluidSideEdge[edgeCode[2]] << nonFluidSideEdge[edgeCode[3]] << " "
24430 << nonFluidSideEdge[edgeCode[4]] << nonFluidSideEdge[edgeCode[5]]
24431 << nonFluidSideEdge[edgeCode[6]] << nonFluidSideEdge[edgeCode[7]] << " "
24432 << nonFluidSideEdge[edgeCode[8]] << nonFluidSideEdge[edgeCode[9]]
24433 << nonFluidSideEdge[edgeCode[10]] << nonFluidSideEdge[edgeCode[11]] << endl;
24434 cerr << "cell " << cellId << " domain " << domainId() << " "
24435 << "bndryId " << bndryId << " " << m_solver->a_coordinate(cellId, 0) << " "
24436 << m_solver->a_coordinate(cellId, 1) << " " << m_solver->a_coordinate(cellId, 2) << endl;
24437 cerr << " " << endl;
24438 cerr << "triangle case: " << triangleCase << endl;
24439 for(MInt i = 0; i < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; i++) {
24440 cerr << "cut point: " << i << " cut edge: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[i]
24441 << endl;
24442 }
24443 }
24444 nonFluidSideEdge[edgeCode[4 * face + e]] = false;
24445 }
24446
24447 } else {
24448 // computed volume is the boundary cell volume
24449 noNonFluidEdges[face] = 2;
24450 nonFluidSideEdge[edgeCode[4 * face + 2 * space0Relative + ((side0 + 1) % 2)]] = true;
24451 nonFluidSideEdge[edgeCode[4 * face + 2 * space1Relative + ((side1 + 1) % 2)]] = true;
24452 }
24453 } // belongs to bndryRfnJumpMethodPart switch
24454 // determine the sign of the normal vector components
24455 if(!pointInside) {
24456 if(pointTLInside()) {
24457 if(pointBRInside()) {
24458 // bottom right corner is inside the geometry
24459 normalVector[nDimFaceSpaceId1] = -normalVector[nDimFaceSpaceId1];
24460 normalVector[nDimFaceSpaceId2] = -normalVector[nDimFaceSpaceId2];
24461 } else {
24462 // top left corner is inside the geometry
24463 normalVector[nDimFaceSpaceId2] = -normalVector[nDimFaceSpaceId2];
24464 }
24465 } else {
24466 if(pointBRInside()) {
24467 // bottom right corner is inside the geometry
24468 normalVector[nDimFaceSpaceId1] = -normalVector[nDimFaceSpaceId1];
24469 } else {
24470 // top right corner is inside the geometry
24471 normalVector[nDimFaceSpaceId1] = -normalVector[nDimFaceSpaceId1];
24472 normalVector[nDimFaceSpaceId2] = -normalVector[nDimFaceSpaceId2];
24473 }
24474 }
24475 } else {
24476 if(pointTLInside()) {
24477 if(pointBRInside()) {
24478 // top right corner is outside the geometry
24479 } else {
24480 // bottom right corner is outside the geometry
24481 normalVector[nDimFaceSpaceId2] = -normalVector[nDimFaceSpaceId2];
24482 }
24483 } else {
24484 if(pointBRInside()) {
24485 // top left corner is outside the geometry
24486 normalVector[nDimFaceSpaceId1] = -normalVector[nDimFaceSpaceId1];
24487 } else {
24488 // bottom left corner is inside the geometry
24489 }
24490 }
24491 }
24492 } else {
24493 // 2. the cut geometry is a trapezoid
24494 noNonFluidEdges[face] = 1;
24495 if(space0 == spaceId1) {
24496 // 2.a) the cut face is along the x_spaceId1 coordinate
24497 faceVolume[face] =
24498 m_solver->c_cellLengthAtCell(cellId) * (cutLineCentroid[nDimFaceSpaceId2] - point[spaceId2]);
24499
24500 // check if point is inside or outside
24501 if(pointInside) {
24502 faceVolume[face] = gridFaceVolume[face] - faceVolume[face];
24503 nonFluidSideEdge[edgeCode[4 * face + 2]] = true;
24504 // * compute boundary cell center
24505 // * set signs of the normal vector
24506 // - x_0 sign according to the slope (+/-,-/+)
24507 // - x_1 sign is positive
24508 const MFloat maxY = cutLineCentroid[nDimFaceSpaceId2] + F1B2 * delta[nDimFaceSpaceId2];
24509 cc0[0] = m_solver->a_coordinate(cellId, spaceId1);
24510 cc0[1] = F1B2 * (oppositePoint[spaceId2] + maxY);
24511 if(positiveSlope) {
24512 cc1[0] = point[spaceId1] + F1B3 * m_solver->c_cellLengthAtCell(cellId);
24513 normalVector[nDimFaceSpaceId1] = -normalVector[nDimFaceSpaceId1];
24514 } else {
24515 cc1[0] = point[spaceId1] + F2B3 * m_solver->c_cellLengthAtCell(cellId);
24516 }
24517 cc1[1] = maxY - F1B3 * delta[nDimFaceSpaceId2];
24518 rectVolume = (oppositePoint[spaceId2] - maxY) * m_solver->c_cellLengthAtCell(cellId);
24519 triVolume = faceVolume[face] - rectVolume;
24520 } else {
24521 nonFluidSideEdge[edgeCode[4 * face + 3]] = true;
24522 // * compute boundary cell center
24523 // * set signs of the normal vector
24524 // - x_0 sign according to the slope (+/+,-/-)
24525 // - x_1 sign is negative
24526 normalVector[nDimFaceSpaceId2] = -normalVector[nDimFaceSpaceId2];
24527 const MFloat minY = cutLineCentroid[nDimFaceSpaceId2] - F1B2 * delta[nDimFaceSpaceId2];
24528 cc0[0] = m_solver->a_coordinate(cellId, spaceId1);
24529 cc0[1] = F1B2 * (point[spaceId2] + minY);
24530 if(positiveSlope) {
24531 cc1[0] = point[spaceId1] + F2B3 * m_solver->c_cellLengthAtCell(cellId);
24532 } else {
24533 normalVector[nDimFaceSpaceId1] = -normalVector[nDimFaceSpaceId1];
24534 cc1[0] = point[spaceId1] + F1B3 * m_solver->c_cellLengthAtCell(cellId);
24535 }
24536 cc1[1] = minY + F1B3 * delta[nDimFaceSpaceId2];
24537 rectVolume = (minY - point[spaceId2]) * m_solver->c_cellLengthAtCell(cellId);
24538 triVolume = faceVolume[face] - rectVolume;
24539 }
24540 } else {
24541 // 2.b) the cut face is along the x_spaceId2 coordinate
24542 faceVolume[face] =
24543 m_solver->c_cellLengthAtCell(cellId) * (cutLineCentroid[nDimFaceSpaceId1] - point[spaceId1]);
24544
24545 // check if point is inside or outside
24546 if(pointInside) {
24547 faceVolume[face] = gridFaceVolume[face] - faceVolume[face];
24548 nonFluidSideEdge[edgeCode[4 * face]] = true;
24549 // * compute boundary cell center
24550 // * set signs of the normal vector
24551 // - x_0 sign is positive
24552 // - x_1 sign according to the slope (+/-,-/+)
24553 const MFloat maxX = cutLineCentroid[nDimFaceSpaceId1] + F1B2 * delta[nDimFaceSpaceId1];
24554 cc0[0] = F1B2 * (oppositePoint[spaceId1] + maxX);
24555 cc0[1] = m_solver->a_coordinate(cellId, spaceId2);
24556 cc1[0] = maxX - F1B3 * delta[nDimFaceSpaceId1];
24557 if(positiveSlope) {
24558 normalVector[nDimFaceSpaceId2] = -normalVector[nDimFaceSpaceId2];
24559 cc1[1] = point[spaceId2] + F1B3 * m_solver->c_cellLengthAtCell(cellId);
24560 } else {
24561 cc1[1] = point[spaceId2] + F2B3 * m_solver->c_cellLengthAtCell(cellId);
24562 }
24563 rectVolume = (oppositePoint[spaceId1] - maxX) * m_solver->c_cellLengthAtCell(cellId);
24564 triVolume = faceVolume[face] - rectVolume;
24565 } else {
24566 nonFluidSideEdge[edgeCode[4 * face + 1]] = true;
24567 // * compute boundary cell center
24568 // * set signs of the normal vector
24569 // - x_0 sign is negative
24570 // - x_1 sign according to the slope (+/+,-/-)
24571 normalVector[nDimFaceSpaceId1] = -normalVector[nDimFaceSpaceId1];
24572 const MFloat minX = cutLineCentroid[nDimFaceSpaceId1] - F1B2 * delta[nDimFaceSpaceId1];
24573 cc0[0] = F1B2 * (point[spaceId1] + minX);
24574 cc0[1] = m_solver->a_coordinate(cellId, spaceId2);
24575 cc1[0] = minX + F1B3 * delta[nDimFaceSpaceId1];
24576 if(positiveSlope) {
24577 cc1[1] = point[spaceId2] + F2B3 * m_solver->c_cellLengthAtCell(cellId);
24578 } else {
24579 normalVector[nDimFaceSpaceId2] = -normalVector[nDimFaceSpaceId2];
24580 cc1[1] = point[spaceId2] + F1B3 * m_solver->c_cellLengthAtCell(cellId);
24581 }
24582 rectVolume = (minX - point[spaceId1]) * m_solver->c_cellLengthAtCell(cellId);
24583 triVolume = faceVolume[face] - rectVolume;
24584 }
24585 }
24586
24587 faceCentroid[nDimFaceSpaceId1] = (rectVolume * cc0[0] + triVolume * cc1[0]) / faceVolume[face];
24588 faceCentroid[nDimFaceSpaceId2] = (rectVolume * cc0[1] + triVolume * cc1[1]) / faceVolume[face];
24589 }
24590
24591 // face data is assembled
24592 // create a surface for the cut face if a boundary cell neighbor exists
24593 MBool createSrfc = true;
24594
24595 MInt nghbrId = -1;
24596 if(m_solver->a_hasNeighbor(cellId, face) > 0) {
24597 nghbrId = m_solver->c_neighborId(cellId, face);
24598 } else {
24599 if(m_solver->c_parentId(cellId) > -1) {
24600 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId), face) > 0)
24601 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId), face);
24602 else
24603 createSrfc = false;
24604 } else
24605 createSrfc = false;
24606 }
24607 if(createSrfc)
24608 if(m_solver->c_noChildren(nghbrId) > 0) createSrfc = false;
24609 if(createSrfc) {
24610 const MInt otherSideId = (sideId + 1) % 2;
24611 const MInt srfcId = m_solver->a_noSurfaces();
24612 m_surfaces.append();
24613 m_solver->a_surfaceOrientation(srfcId) = spaceId;
24614 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
24615 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
24616 for(MInt i = 0; i < nDim; i++) {
24617 m_solver->a_surfaceCoordinate(srfcId, i) = faceCentroid[face * nDim + i];
24618 }
24619 m_solver->a_surfaceArea(srfcId) = faceVolume[face];
24620 m_bndryCells->a[bndryId].m_associatedSrfc[face] = srfcId;
24621 }
24622
24623 } else {
24624 // set the nonFluidSideEdge flag
24625 // none of the face edges is cut
24626 if(pointInside) {
24627 for(MInt e = 0; e < 4; e++) {
24628 nonFluidSideEdge[edgeCode[4 * face + e]] = true;
24629 }
24630 }
24631 }
24632 }
24633
24634
24635 // from here on the whole control volume is concerned
24636
24637 // II.
24638 // --
24639 // set the non fluid side Ids
24640 for(MInt face = 0; face < m_noDirs; face++) {
24641 MBool nonFluidSide = true;
24642 for(MInt e = 0; e < 4; e++) {
24643 if(!nonFluidSideEdge[edgeCode[4 * face + e]]) {
24644 nonFluidSide = false;
24645 break;
24646 }
24647 }
24648 if(nonFluidSide) {
24649 m_bndryCells->a[bndryId].m_externalFaces[face] = true;
24650 faceVolume[face] = F0;
24651 }
24652 }
24653
24654 // III.
24655 // --
24656 // determine the 3D cell geometry
24657 switch(noCutFaces) {
24658 case 0: {
24659 cerr << "case 0 " << endl;
24660 cerr << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1) << " "
24661 << m_solver->a_coordinate(cellId, 2) << " " << F1B2 * m_solver->c_cellLengthAtCell(cellId) << " "
24662 << m_solver->a_level(cellId) << endl;
24663 mTerm(1, AT_, "case 0");
24664 }
24665
24666 case 3: {
24667 // III. 1.
24668 // the cut geometry is a tetraeder
24669
24670 // find the cut sides
24671 face0 = -1;
24672 face1 = -1;
24673 for(MInt face = 0; face < m_noDirs; face++) {
24674 if(cutFaces[face]) {
24675 if(face0 == -1) {
24676 face0 = face;
24677 } else {
24678 if(face1 == -1) face1 = face;
24679 }
24680 }
24681 }
24682 edgeCounter = 0;
24683 // find the two cut edges of face0
24684 for(MInt e = 0; e < 4; e++) {
24685 cutEdges[e] = 0;
24686 if(cutEdgesAll[edgeCode[4 * face0 + e]]) {
24687 cutEdges[edgeCounter] = e;
24688 edgeCounter++;
24689 }
24690 }
24691
24692 // DEBUG
24693 if(edgeCounter != 2) cerr << "ERROR create cut face, tetraeter shape, not enough cut edges" << endl;
24694 // find the remaining cut edge (face1)
24695 for(MInt e = 0; e < 4; e++) {
24696 if(cutEdgesAll[edgeCode[4 * face1 + e]]) {
24697 if(faceCode[2 * edgeCode[4 * face1 + e]] != face0 && faceCode[2 * edgeCode[4 * face1 + e] + 1] != face0) {
24698 cutEdges[2] = e;
24699 }
24700 }
24701 }
24702
24703 // determine the cut point on the remaining cut edge
24704 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
24705 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cp] == edgeCode[4 * face1 + cutEdges[2]]) {
24706 cutPoint[0] = cp;
24707 }
24708 }
24709
24710 const MInt face0Space = face0 / 2;
24711 const MInt face0Side = face0 % 2;
24712
24713 // determine the center and the volume of the tetraeder
24714 // center of the triangle
24715 for(MInt i = 0; i < nDim; i++) {
24716 m_bndryCells->a[bndryId].m_coordinates[i] =
24717 F3B4 * triangleCentroid[face0 * nDim + i]
24718 + F1B4 * m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoint[0]][i];
24719 }
24720
24721 // volume
24722 const MFloat h = F2 * (F1B2 - (MFloat)face0Side)
24723 * (m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoint[0]][face0Space]
24724 - (negativePoint[face0Space] + (MFloat)face0Side * m_solver->c_cellLengthAtCell(cellId)));
24725 if(shapeIsInside[face0]) {
24726 m_bndryCells->a[bndryId].m_volume = F1B3 * (gridFaceVolume[face0] - faceVolume[face0]) * h;
24727 } else {
24728 m_bndryCells->a[bndryId].m_volume = F1B3 * faceVolume[face0] * h;
24729 }
24730
24731 // correct the volume and the cell center of the reshaped cell if the geometry is cut out
24732 if(shapeIsInside[face0]) {
24733 cutOutVolume = m_bndryCells->a[bndryId].m_volume;
24734 m_bndryCells->a[bndryId].m_volume =
24735 m_solver->grid().gridCellVolume(m_solver->a_level(cellId)) - m_bndryCells->a[bndryId].m_volume;
24736 for(MInt i = 0; i < nDim; i++) {
24737 m_bndryCells->a[bndryId].m_coordinates[i] =
24738 F1 / m_bndryCells->a[bndryId].m_volume
24739 * (m_solver->grid().gridCellVolume(m_solver->a_level(cellId)) * m_solver->a_coordinate(cellId, i)
24740 - cutOutVolume * m_bndryCells->a[bndryId].m_coordinates[i]);
24741 }
24742 }
24743 // compute the coordinate shift
24744 for(MInt i = 0; i < nDim; i++) {
24745 m_bndryCells->a[bndryId].m_coordinates[i] -= m_solver->a_coordinate(cellId, i);
24746 }
24747
24748 // compute the cut surface area (store surface components in the normal vector member)
24749 for(MInt i = 0; i < nDim; i++) {
24750 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] = faceVolume[2 * i + 1] - faceVolume[2 * i];
24751 }
24752 m_bndryCells->a[bndryId].m_srfcs[0]->m_area =
24753 sqrt(POW2(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0])
24754 + POW2(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[1])
24755 + POW2(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[2]));
24756
24757 // compute the normal vector
24758 for(MInt i = 0; i < nDim; i++) {
24759 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] =
24760 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] / m_bndryCells->a[bndryId].m_srfcs[0]->m_area;
24761 }
24762
24763 // compute the cut surface centroid
24764 for(MInt i = 0; i < nDim; i++) {
24765 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i] =
24766 F2B3 * cutLineCentroid[face0 * nDim + i]
24767 + F1B3 * m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoint[0]][i];
24768 }
24769 break;
24770 }
24771 case 4:
24772 case 5:
24773 case 6: {
24774 // III. 2.
24775
24776 // find a pair of opposite cut sides (the one with the largest area)
24777 cutLineLength[6] = F0;
24778 for(MInt face = 0; face < m_noDirs; face += 2) {
24779 if(cutFaces[face]) {
24780 if(cutFaces[face + 1]) {
24781 cutLineLength[7] = cutLineLength[face] + cutLineLength[face + 1];
24782 if(cutLineLength[7] > cutLineLength[6]) {
24783 face0 = face;
24784 face1 = face + 1;
24785 cutLineLength[6] = cutLineLength[7];
24786 }
24787 }
24788 }
24789 }
24790
24791 const MInt spaceId = face0 / 2;
24792 const MInt spaceId1 = (spaceId + 1) % nDim;
24793 const MInt spaceId2 = (spaceId1 + 1) % nDim;
24794
24795 // compute the new cell center
24796 // coordinate spaceId1 and Id2
24797 const MFloat Fvol = F1 / (faceVolume[face0] + faceVolume[face1]);
24798 const MFloat dA = faceVolume[face1] - faceVolume[face0];
24799 dfcc[0] = faceCentroid[face1 * nDim + spaceId1] - faceCentroid[face0 * nDim + spaceId1];
24800 dfcc[1] = faceCentroid[face1 * nDim + spaceId2] - faceCentroid[face0 * nDim + spaceId2];
24801
24802 m_bndryCells->a[bndryId].m_coordinates[spaceId] =
24803 faceCentroid[face0 * nDim + spaceId]
24804 + F1B3 * (F1 + Fvol * faceVolume[face1]) * m_solver->c_cellLengthAtCell(cellId);
24805 m_bndryCells->a[bndryId].m_coordinates[spaceId1] =
24806 F2 * Fvol
24807 * (faceVolume[face0] * faceCentroid[face0 * nDim + spaceId1]
24808 + F1B2 * (faceVolume[face0] * dfcc[0] + dA * faceCentroid[face0 * nDim + spaceId1])
24809 + F1B3 * dA * dfcc[0]);
24810 m_bndryCells->a[bndryId].m_coordinates[spaceId2] =
24811 F2 * Fvol
24812 * (faceVolume[face0] * faceCentroid[face0 * nDim + spaceId2]
24813 + F1B2 * (faceVolume[face0] * dfcc[1] + dA * faceCentroid[face0 * nDim + spaceId2])
24814 + F1B3 * dA * dfcc[1]);
24815
24816 for(MInt i = 0; i < nDim; i++) {
24817 m_bndryCells->a[bndryId].m_coordinates[i] -= m_solver->a_coordinate(cellId, i);
24818 }
24819
24820 // compute the cut surface area (store surface components in the normal vector member)
24821 for(MInt i = 0; i < nDim; i++) {
24822 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] = faceVolume[2 * i + 1] - faceVolume[2 * i];
24823 }
24824 m_bndryCells->a[bndryId].m_srfcs[0]->m_area =
24825 sqrt(POW2(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0])
24826 + POW2(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[1])
24827 + POW2(m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[2]));
24828
24829 // compute the normal vector
24830 for(MInt i = 0; i < nDim; i++) {
24831 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] =
24832 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] / m_bndryCells->a[bndryId].m_srfcs[0]->m_area;
24833 }
24834
24835 // compute the cut surface centroid
24836 for(MInt i = 0; i < nDim; i++) {
24837 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i] =
24838 F1B2 * (cutLineCentroid[face0 * nDim + i] + cutLineCentroid[face1 * nDim + i]);
24839 }
24840
24841 // compute the boundary cell volume using Gauss theorem
24842 m_bndryCells->a[bndryId].m_volume =
24843 -F1B3
24844 * (faceVolume[0] * faceCentroid[0 * nDim + 0] - faceVolume[1] * faceCentroid[1 * nDim + 0]
24845 + faceVolume[2] * faceCentroid[2 * nDim + 1] - faceVolume[3] * faceCentroid[3 * nDim + 1]
24846 + faceVolume[4] * faceCentroid[4 * nDim + 2] - faceVolume[5] * faceCentroid[5 * nDim + 2]
24847 + m_bndryCells->a[bndryId].m_srfcs[0]->m_area
24848 * (m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0]
24849 * m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[0]
24850 + m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[1]
24851 * m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[1]
24852 + m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[2]
24853 * m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[2]));
24854
24855
24856 break;
24857 }
24858 default: {
24859 cerr << "this case has not yet been implemented" << endl;
24860 cerr << "cell " << cellId << endl;
24861 cerr << "coordinates"
24862 << " " << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 1) << " "
24863 << m_solver->a_coordinate(cellId, 2) << endl;
24864 cerr << "number of cut faces: " << noCutFaces << endl;
24865 mTerm(1, AT_, "this case has not yet been implemented");
24866 }
24867 }
24868 }
24869}
24870
24871
24875
24897template <MInt nDim, class SysEqn>
24898template <class _, std::enable_if_t<nDim == 3, _*>>
24900 TRACE();
24901
24902 static constexpr MInt cornerIndices[8][3] = {{-1, -1, -1}, {1, -1, -1}, {-1, 1, -1}, {1, 1, -1},
24903 {-1, -1, 1}, {1, -1, 1}, {-1, 1, 1}, {1, 1, 1}};
24904 // the following variables describe the different corner/edge/face numbering in MAIA and MarchingCubes table
24905 static constexpr MInt cornersMCtoSOLVER[8] = {2, 0, 1, 3, 6, 4, 5, 7};
24906 static constexpr MInt cornersSOLVERtoMC[8] = {1, 2, 0, 3, 5, 6, 4, 7};
24907 static constexpr MInt edgesMCtoSOLVER[12] = {0, 2, 1, 3, 4, 6, 5, 7, 10, 8, 9, 11};
24908 static constexpr MInt facesMCtoSOLVER[6] = {0, 2, 1, 3, 4, 5};
24909 static constexpr MInt neighborCorner[6] = {1, -1, 2, -2, 4, -4};
24910 static constexpr MInt cornerFaceMapping[24] = {0, 2, 4, 1, 2, 4, 0, 3, 4, 1, 3, 4,
24911 0, 2, 5, 1, 2, 5, 0, 3, 5, 1, 3, 5};
24912 static constexpr MInt faceCornerMapping[24] = {0, 2, 4, 6, 1, 3, 5, 7, 0, 1, 4, 5,
24913 2, 3, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
24914
24915 unsigned char outcode_MC = 0;
24916 MInt noCells = m_bndryCells->size();
24917 MInt cellId;
24918 MFloat gridCellVolume;
24919 MFloat corner[8][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
24920 MInt currentCase;
24921 MInt presentCases[15] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
24922 MInt* presentSubCases[15];
24923 const MInt maxNoSubCases = 48;
24924 MIntScratchSpace presentSubCases_scratch(15 * maxNoSubCases, AT_, "presentSubCases_scratch");
24925 for(MInt i = 0; i < 15; i++)
24926 presentSubCases[i] = &presentSubCases_scratch.p[maxNoSubCases * i];
24927 for(MInt i = 0; i < 15; i++) {
24928 for(MInt j = 0; j < maxNoSubCases; j++) {
24929 presentSubCases[i][j] = 0;
24930 }
24931 }
24932 MBool currentOutcode = false;
24933 MInt nghbrId;
24934 MInt sideId;
24935 MInt otherSideId;
24936 MInt srfcId;
24937 MInt spaceId;
24938 MFloat* faceCentroid[6];
24939 MFloatScratchSpace faceCentroid_scratch(nDim * 6, AT_, "faceCentroid_scratch");
24940 for(MInt i = 0; i < 6; i++)
24941 faceCentroid[i] = &faceCentroid_scratch.p[i * nDim];
24942 MFloat* faceCentroid_0[6];
24943 MFloatScratchSpace faceCentroid_0_scratch(nDim * 6, AT_, "faceCentroid_0_scratch");
24944 for(MInt i = 0; i < 6; i++)
24945 faceCentroid_0[i] = &faceCentroid_0_scratch.p[i * nDim];
24946 MFloat* faceCentroid_00[6];
24947 MFloatScratchSpace faceCentroid_00_scratch(nDim * 6, AT_, "faceCentroid_00_scratch");
24948 for(MInt i = 0; i < 6; i++)
24949 faceCentroid_00[i] = &faceCentroid_00_scratch.p[i * nDim];
24950 MFloat* normal[6];
24951 MFloatScratchSpace normal_scratch(nDim * 6, AT_, "normal_scratch");
24952 for(MInt i = 0; i < 6; i++)
24953 normal[i] = &normal_scratch.p[i * nDim];
24954 const MInt maxNoPyramids = 13;
24955 MFloat* pyraCentroid[maxNoPyramids];
24956 MFloatScratchSpace pyraCentroid_scratch(nDim * maxNoPyramids, AT_, "pyraCentroid_scratch");
24957 for(MInt i = 0; i < maxNoPyramids; i++)
24958 pyraCentroid[i] = &pyraCentroid_scratch.p[i * nDim];
24959 MFloatScratchSpace faceVolume_scratch(F2 * m_noDirs, AT_, "faceVolume_scratch");
24960 MFloat* faceVolume = faceVolume_scratch.getPointer();
24961 MFloatScratchSpace pyraVolume_scratch(maxNoPyramids, AT_, "pyraVolume_scratch");
24962 MFloat* pyraVolume = pyraVolume_scratch.getPointer();
24963 MFloatScratchSpace faceVolume_0_scratch(F2 * m_noDirs, AT_, "faceVolume_0_scratch");
24964 MFloat* faceVolume_0 = faceVolume_0_scratch.getPointer();
24965 MFloatScratchSpace faceVolume_00_scratch(F2 * m_noDirs, AT_, "faceVolume_00_scratch");
24966 MFloat* faceVolume_00 = faceVolume_00_scratch.getPointer();
24967 MFloat cellVolume_0;
24968 MFloatScratchSpace cellCentroid_0_scratch(nDim, AT_, "cellCentroid_0_scratch");
24969 MFloat* cellCentroid_0 = cellCentroid_0_scratch.getPointer();
24970 MFloatScratchSpace cellCentroid_00_scratch(nDim, AT_, "cellCentroid_00_scratch");
24971 MInt currentSubCase;
24972 MInt subCaseDummy;
24973 MFloat* p_0;
24974 MFloat* p_1;
24975 MFloat* p_2;
24976 MFloat* p_3;
24977 MFloat* p_4;
24978 MFloat* p_5;
24979 MFloat* p_0s;
24980 MFloat* p_1s;
24981 MFloat* p_2s;
24982 MFloat* p_3s;
24983 MFloat* p_0ss;
24984 MFloat* p_1ss;
24985 MFloat* p_2ss;
24986 MFloat* p_3ss;
24987 MFloat* p_1sss;
24988 MFloat* p_2sss;
24989 MFloat* p_3sss;
24990
24991 MInt splitCorner1 = -1;
24992 MInt splitCorner2 = -1;
24993 MInt splitCorner12 = -1;
24994 MInt splitCorner22 = -1;
24995 MInt cutDummy;
24996 MInt face1;
24997 MInt face2;
24998 MInt face3;
24999 MInt face4;
25000 MInt face5;
25001 MInt face6;
25002 MInt* facepointers[6] = {&face1, &face2, &face3, &face4, &face5, &face6};
25003 MInt cutPoints[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
25004 MFloatScratchSpace normalVec_c_scratch(nDim, AT_, "normalVec_c_scratch");
25005 MFloat* normalVec_c = normalVec_c_scratch.getPointer();
25006 MFloat area_c;
25007 MFloatScratchSpace coordinates_c_scratch(nDim, AT_, "coordinates_c_scratch");
25008 MFloat* coordinates_c = coordinates_c_scratch.getPointer();
25009 MFloat volume_C;
25010 MFloatScratchSpace coordinatesCell_scratch(nDim, AT_, "coordinatesCell_scratch");
25011 MFloat* coordinates_Cell = coordinatesCell_scratch.getPointer();
25012 MFloat M[3] = {0, 0, 0};
25013 MFloat dummy_1[3] = {0, 0, 0};
25014 MBool nfs_cur[6] = {false, false, false, false, false, false};
25015 MBool nfs_cur_0[6] = {false, false, false, false, false, false};
25016 MBool nfs_cur_00[6] = {false, false, false, false, false, false};
25017 MBool faceCut[6] = {false, false, false, false, false, false};
25018 MBool faceCut_0[6] = {false, false, false, false, false, false};
25019 MBool faceCut_00[6] = {false, false, false, false, false, false};
25020 MInt noFaces;
25021 MFloat absA;
25022 MFloatScratchSpace faceDiff_scratch(2 * nDim, AT_, "faceDiff_scratch");
25023 MFloat* faceDiff = faceDiff_scratch.getPointer();
25024 // MInt maxNoNodes = 1000; // might be necessary to increase for extremely detailed .stl geometries! See error
25025 // output below
25026 static constexpr MInt opposite[6] = {1, 0, 3, 2, 5, 4};
25027 MInt bndryId2 = -1, bndryId3 = -1;
25028 MInt cellId2 = -1, cellId3 = -1;
25029 MIntScratchSpace splitFace_scratch(noCells, AT_, "splitFace_scratch");
25030 MIntScratchSpace splitCell_scratch(noCells, AT_, "splitCell_scratch");
25031 MIntScratchSpace disambiguation_scratch(noCells, AT_, "disambiguation_scratch");
25032 MIntScratchSpace ambIds_scratch(noCells, AT_, "ambIds_scratch");
25033 MIntScratchSpace ambiguousCells_scratch(noCells, AT_, "ambiguousCells_scratch");
25034 MIntScratchSpace subCases_scratch(noCells, AT_, "subCases_scratch");
25035 MIntScratchSpace mcCases_scratch(noCells, AT_, "mcCases_scratch");
25036 MInt* splitFace = splitFace_scratch.getPointer();
25037 MInt* splitCell = splitCell_scratch.getPointer();
25038 MInt* disambiguation = disambiguation_scratch.getPointer();
25039 MInt* ambIds = ambIds_scratch.getPointer();
25040 MInt* ambiguousCells = ambiguousCells_scratch.getPointer();
25041 MInt* subCases = subCases_scratch.getPointer();
25042 MInt* mcCases = mcCases_scratch.getPointer();
25043 for(MInt i = 0; i < m_bndryCells->size(); i++) {
25044 ambiguousCells[i] = -1;
25045 disambiguation[i] = -1;
25046 ambIds[i] = -1;
25047 splitCell[i] = 0;
25048 splitFace[i] = 0;
25049 }
25050 MInt noSplitCells = 0;
25051 MInt noSplitFaces = 0;
25052 MInt noAmbiguousCells = 0;
25053 MInt bdAmbId;
25054 MInt faceTMP;
25055 MInt nghbrCellId;
25056 MInt nghbrBndryId;
25057 stack<MInt> ambStack;
25058 MFloatScratchSpace splitFaceVolume_scratch(2, AT_, "splitFaceVolume_scratch");
25059 MFloat* splitFaceVolume = splitFaceVolume_scratch.getPointer();
25060 MFloat* splitFaceCentroid[2];
25061 MFloatScratchSpace splitFaceCentroid_scratch(nDim * 2, AT_, "splitFaceCentroid_scratch");
25062 for(MInt i = 0; i < 2; i++)
25063 splitFaceCentroid[i] = &splitFaceCentroid_scratch.p[i * nDim];
25064 MFloat* splitFaceNormal[2];
25065 MFloatScratchSpace splitFaceNormal_scratch(nDim * 2, AT_, "splitFaceNormal_scratch");
25066 for(MInt i = 0; i < 2; i++)
25067 splitFaceNormal[i] = &splitFaceNormal_scratch.p[i * nDim];
25068 MFloatScratchSpace splitFaceVolume2_scratch(2, AT_, "splitFaceVolume2_scratch");
25069 MFloat* splitFaceVolume2 = splitFaceVolume2_scratch.getPointer();
25070 MFloat* splitFaceCentroid2[2];
25071 MFloatScratchSpace splitFaceCentroid2_scratch(nDim * 2, AT_, "splitFaceCentroid2_scratch");
25072 for(MInt i = 0; i < 2; i++)
25073 splitFaceCentroid2[i] = &splitFaceCentroid2_scratch.p[i * nDim];
25074 MFloat* splitFaceNormal2[2];
25075 MFloatScratchSpace splitFaceNormal2_scratch(nDim * 2, AT_, "splitFaceNormal2_scratch");
25076 for(MInt i = 0; i < 2; i++)
25077 splitFaceNormal2[i] = &splitFaceNormal2_scratch.p[i * nDim];
25078 MInt splitFaceId = -1;
25079 MInt splitFaceId2 = -1;
25080 MInt splitSurfaceIndexCounter = 2;
25081 MInt mcCorner;
25082 MBool keepNghbrs = true;
25083 MInt disamb_tmp = 0;
25084 MInt disambPointer[16][21];
25085 const MInt* disambPointer_dummy = nullptr;
25086 MIntScratchSpace levelSetCornerSigns(8, AT_, "levelSetCornerSigns");
25087 //--- end of initialization
25088
25089 // preprocessing of each cell
25090 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
25091 cellId = m_bndryCells->a[bndryId].m_cellId;
25092 m_bndryCells->a[bndryId].m_noSrfcs = 0;
25093 outcode_MC = 0;
25094
25095 for(MInt f = 0; f < m_noDirs; f++) {
25096 m_bndryCells->a[bndryId].m_externalFaces[f] = false;
25097 }
25098
25099 if(m_solver->c_noChildren(cellId) > 0) {
25100 continue;
25101 }
25102 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
25103 m_bndryCells->a[bndryId].m_volume = F0;
25104 continue;
25105 }
25106
25107 // 1. Determine Case/Subcase of each bndry cell
25108 // get In/Outcode of the corners of the voxel
25109 // 0 -> Corner is outside Fluid Domain
25110 // 1 -> Corner is inside Fluid Domain or on Boundary
25111 for(MInt i = 0; i < 8; i++) {
25112 for(MInt dim = 0; dim < nDim; dim++) {
25113 corner[i][dim] =
25114 m_solver->a_coordinate(cellId, dim) + cornerIndices[i][dim] * F1B2 * m_solver->c_cellLengthAtCell(cellId);
25115 }
25116 currentOutcode = !((MBool)m_solver->m_geometry->pointIsInside2(corner[i]));
25117 if(currentOutcode) outcode_MC = outcode_MC | (1 << cornersSOLVERtoMC[i]);
25118 }
25119
25120 // Determine Case and check if case is implemented
25121 currentCase = (MInt)cases[outcode_MC][0];
25122 mcCases[bndryId] = currentCase;
25123 currentSubCase = (MInt)cases[outcode_MC][1];
25124 subCases[bndryId] = currentSubCase;
25125 if(!caseStatesSTL[currentCase][0]) {
25126 cerr << "Error in createCutFaceMGC: Case not implemented: " << currentCase << endl;
25127 continue;
25128 }
25129
25130 // 2.1 Determine ambiguous cells
25131 disambiguation[bndryId] = -1;
25132 if(!caseStatesSTL[mcCases[bndryId]][1]) { // ambiguous case
25133 ambIds[bndryId] = noAmbiguousCells;
25134 ambiguousCells[noAmbiguousCells++] = bndryId;
25135 }
25136 }
25137
25138
25139 // 2.2 Prepare corner cell mapping array
25140 MIntScratchSpace cornerCellMapping_scratch(8 * noAmbiguousCells, AT_, "cornerCellMapping_scratch");
25141 MInt* cornerCellMapping = cornerCellMapping_scratch.getPointer();
25142 for(MInt i = 0; i < noAmbiguousCells; i++) {
25143 bdAmbId = ambiguousCells[i];
25144 cellId = m_bndryCells->a[bdAmbId].m_cellId;
25145 outcode_MC = 0;
25146
25147 // redetermine outcode
25148 for(MInt j = 0; j < 8; j++) {
25149 for(MInt dim = 0; dim < nDim; dim++) {
25150 corner[j][dim] = m_solver->a_coordinate(cellId, dim)
25151 + cornerIndices[j][dim] * F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
25152 }
25153 currentOutcode = !((MBool)m_solver->m_geometry->pointIsInside2(corner[j]));
25154 if(currentOutcode) outcode_MC = outcode_MC | (1 << cornersSOLVERtoMC[j]);
25155 }
25156 for(MInt j = 0; j < 8; j++) {
25157 mcCorner = cornersSOLVERtoMC[j];
25158 if(!(outcode_MC & 1 << mcCorner))
25159 cornerCellMapping[i * 8 + j] = -1;
25160 else
25161 cornerCellMapping[i * 8 + j] = cellId;
25162 }
25163 }
25164
25165 // 3. Determine case of ambiguous cells by states of surface midpoints - new!
25166 for(MInt ambId = 0; ambId < noAmbiguousCells; ambId++) {
25167 bdAmbId = ambiguousCells[ambId];
25168 disambiguation[bdAmbId] = 0;
25169 cellId = m_bndryCells->a[bdAmbId].m_cellId;
25170 currentCase = mcCases[bdAmbId];
25171 currentSubCase = subCases[bdAmbId];
25172
25173 MInt faceMax = 0;
25174 switch(currentCase) {
25175 case 3:
25176 faceMax = 1;
25177 break;
25178 case 4:
25179 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
25180 continue;
25181 case 6:
25182 faceMax = 1;
25183 break;
25184 case 7:
25185 faceMax = 3;
25186 break;
25187 case 10:
25188 faceMax = 2;
25189 break;
25190 case 12:
25191 faceMax = 2;
25192 break;
25193 default: {
25194 stringstream errorMessage;
25195 errorMessage << " Error in FvBndryCnd3D::createCutFaceMGC: cell in ambigous cells does not have an "
25196 "ambiguous case... cellId: "
25197 << cellId << " case: " << currentCase << " bndryId: " << bdAmbId << endl;
25198 writeStlFileOfCell(cellId, "errorcell.stl");
25199 mTerm(1, AT_, errorMessage.str());
25200 }
25201 }
25202
25203 for(MInt i = 0; i < faceMax; i++) {
25204 // compute ambigous face centroid and check if it is fluid or solid. If fluid, choose connected, else choose
25205 // separated.
25206 switch(currentCase) {
25207 case 3:
25208 faceTMP = facesMCtoSOLVER[tiling3_1STL[currentSubCase][2 + i]];
25209 break;
25210
25211 case 6:
25212 faceTMP = facesMCtoSOLVER[tiling6_1STL[currentSubCase][2 + i]];
25213 break;
25214 case 7:
25215 faceTMP = facesMCtoSOLVER[tiling7_1STL[currentSubCase][3 + i]];
25216 break;
25217
25218 case 10:
25219 faceTMP = facesMCtoSOLVER[tiling10_1STL[currentSubCase][2 + i]];
25220 break;
25221
25222 case 12:
25223 faceTMP = facesMCtoSOLVER[tiling12_1STL[currentSubCase][2 + i]];
25224 break;
25225 default: {
25226 stringstream errorMessage;
25227 errorMessage << "ERROR: Switch variable 'currentCase' with value " << currentCase << " not matching any case."
25228 << endl;
25229 mTerm(1, AT_, errorMessage.str());
25230 }
25231 }
25232 nghbrCellId = m_solver->c_neighborId(cellId, faceTMP);
25233 if(nghbrCellId < 0 || !m_solver->a_hasNeighbor(cellId, faceTMP)) {
25234 stringstream errorMessage;
25235 errorMessage << " Error in FvBndryCnd3D::createCutFaceMGC: no neighbor in ambiguous direction... exiting."
25236 << endl;
25237 errorMessage << " cellId: " << cellId << ", ambiguous face: " << faceTMP << endl;
25238 writeStlFileOfCell(cellId, "errorcell.stl");
25239 mTerm(1, AT_, errorMessage.str());
25240 }
25241 // compute ambiguous face centroid
25242 for(MInt dim = 0; dim < nDim; dim++) {
25243 corner[0][dim] = (m_solver->a_coordinate(cellId, dim) + m_solver->a_coordinate(nghbrCellId, dim)) * F1B2;
25244 }
25245 currentOutcode = (MBool)m_solver->m_geometry->pointIsInside2(corner[0]);
25246
25247 // returns true if point is not located in fluid domain, false if it is located in the fluid domain
25248 if(currentOutcode) {
25249 disambiguation[bdAmbId] += IPOW2(faceMax - i - 1);
25250 }
25251 }
25252 }
25253
25254 // 3.2 Determine split cell and split surface cells & count them
25255 for(MInt ambId = 0; ambId < noAmbiguousCells; ambId++) {
25256 bdAmbId = ambiguousCells[ambId];
25257 cellId = m_bndryCells->a[bdAmbId].m_cellId;
25258 currentCase = mcCases[bdAmbId];
25259 currentSubCase = subCases[bdAmbId];
25260
25261 switch(currentCase) {
25262 case 3:
25263 if(currentSubCase < 12 && disambiguation[bdAmbId] == 1) {
25264 splitCell[bdAmbId] = true;
25265 noSplitCells++;
25266 } else if(currentSubCase >= 12 && disambiguation[bdAmbId] == 1) {
25267 splitFace[bdAmbId] = true;
25268 noSplitFaces++;
25269 }
25270 break;
25271 case 4:
25272 if(currentSubCase < 4) {
25273 splitCell[bdAmbId] = true;
25274 noSplitCells++;
25275 }
25276 break;
25277 case 6:
25278 if(currentSubCase < 24 && disambiguation[bdAmbId] == 1) {
25279 splitCell[bdAmbId] = true;
25280 noSplitCells++;
25281 } else if(currentSubCase >= 24 && disambiguation[bdAmbId] == 1) {
25282 splitFace[bdAmbId] = true;
25283 noSplitFaces++;
25284 }
25285 break;
25286 case 7:
25287 if(currentSubCase < 8) {
25288 switch(disambiguation[bdAmbId]) {
25289 case 0:
25290 // connected cell, no special cell
25291 break;
25292 case 1:
25293 case 2:
25294 case 4:
25295 splitFace[bdAmbId] = true;
25296 noSplitFaces++;
25297 break;
25298 case 3:
25299 case 5:
25300 case 6:
25301 splitCell[bdAmbId] = true;
25302 noSplitCells++;
25303 break;
25304 case 7:
25305 splitCell[bdAmbId] = true;
25306 noSplitCells++;
25307 noSplitCells++;
25308 break;
25309 default: {
25310 stringstream errorMessage;
25311 errorMessage << "ERROR: Switch variable 'disambiguation[bdAmbId]' with value " << disambiguation[bdAmbId]
25312 << " not matching any case." << endl;
25313 mTerm(1, AT_, errorMessage.str());
25314 }
25315 }
25316 } else {
25317 switch(disambiguation[bdAmbId]) {
25318 case 0:
25319 // connected cell, no special cell
25320 break;
25321 case 1:
25322 case 2:
25323 case 4:
25324 splitFace[bdAmbId] = true;
25325 noSplitFaces++;
25326 break;
25327 case 3:
25328 case 5:
25329 case 6:
25330 // Here: Check how to manage split faces for cells with 2 split faces!
25331 splitFace[bdAmbId] = true;
25332 noSplitFaces++;
25333 noSplitFaces++;
25334 break;
25335 case 7:
25336 splitCell[bdAmbId] = true;
25337 noSplitCells++;
25338 break;
25339 default: {
25340 stringstream errorMessage;
25341 errorMessage << "ERROR: Switch variable 'disambiguation[bdAmbId]' with value " << disambiguation[bdAmbId]
25342 << " not matching any case." << endl;
25343 mTerm(1, AT_, errorMessage.str());
25344 }
25345 }
25346 }
25347 break;
25348 case 10:
25349 if(disambiguation[bdAmbId] == 3) {
25350 splitCell[bdAmbId] = true;
25351 noSplitCells++;
25352 }
25353 if(disambiguation[bdAmbId] == 2 || disambiguation[bdAmbId] == 1) {
25354 stringstream errorMessage;
25355 errorMessage << " found case 10 cell with disambiguation " << disambiguation[bdAmbId] << " and cellId "
25356 << cellId << ". This means cell is a case 10.2 cell which is not implemented. Exiting..."
25357 << endl;
25358 mTerm(1, AT_, errorMessage.str());
25359 }
25360 break;
25361 case 12:
25362 if(disambiguation[bdAmbId] == 3) {
25363 splitCell[bdAmbId] = true;
25364 noSplitCells++;
25365 }
25366 if(disambiguation[bdAmbId] == 2 || disambiguation[bdAmbId] == 1) {
25367 stringstream errorMessage;
25368 errorMessage << " found case 12 cell with disambiguation " << disambiguation[bdAmbId] << " and cellId "
25369 << cellId << ". This means cell is a case 12.2 cell which is not implemented. Exiting..."
25370 << endl;
25371 mTerm(1, AT_, errorMessage.str());
25372 }
25373 break;
25374 default: {
25375 stringstream errorMessage;
25376 errorMessage << "ERROR: Switch variable 'currentCase' with value " << currentCase << " not matching any case."
25377 << endl;
25378 mTerm(1, AT_, errorMessage.str());
25379 }
25380 }
25381 }
25382
25383 // 3.3 Allocate space for split face information
25384 // index is (- m_associatedSurfaces[bndryId][face])*6 + ident for the first split surface
25385 // index is (- m_associatedSurfaces[bndryId][face])*6 + 3 + ident for the second split surface
25386 // ident = 1: srfcId in m_srfcs
25387 // ident = 2: corner left cell (in -dir)
25388 // ident = 3: corner right cell (in +dir)
25389 // indices 0 to 11 may not be used! First index to be stored in m_associatedSurfaces is -2!
25390 // split Cells: positive if cell is a split cell, link to split parent
25391 // split Cells: negative if cell is a split parent, -link to split child
25392 // split Cells: 0 if no split cell and no split parent. Check later, if cell 0 is either split cell or split parent ->
25393 // doof
25394 const MInt maxNoSplitChildrenPerCell = 3;
25395 mAlloc(m_splitSurfaces, (2 + noSplitFaces) * 2 * maxNoSplitChildrenPerCell, "m_splitSurfaces", -1, AT_);
25396 mAlloc(m_splitParents, noCells + noSplitCells, "m_splitPartents", -1, AT_);
25397 mAlloc(m_splitChildren, (noCells + noSplitCells) * maxNoSplitChildrenPerCell, "m_splitChildren", -1, AT_);
25398
25399 // 4. Compute cut cell information
25400 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
25401 noFaces = 0;
25402 cellId = m_bndryCells->a[bndryId].m_cellId;
25403 gridCellVolume = m_solver->grid().gridCellVolume(m_solver->a_level(cellId));
25404 outcode_MC = 0;
25405 volume_C = 0;
25406 coordinates_Cell[0] = 0;
25407 coordinates_Cell[1] = 0;
25408 coordinates_Cell[2] = 0;
25409
25410
25411 // store all cut points in a separate array
25412 for(MInt cutPoint = 0; cutPoint < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cutPoint++) {
25413 cutPoints[m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPoint]] = cutPoint;
25414 }
25415
25416 for(MInt i = 0; i < nDim; i++) {
25417 faceVolume[2 * i] = POW2(m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId)));
25418 faceVolume[2 * i + 1] = faceVolume[2 * i];
25419 for(MInt j = 0; j < 3; j++) {
25420 faceCentroid[2 * i][j] = m_solver->a_coordinate(cellId, j);
25421 faceCentroid[2 * i + 1][j] = m_solver->a_coordinate(cellId, j);
25422 }
25423 faceCentroid[2 * i][i] -= F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
25424 faceCentroid[2 * i + 1][i] += F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
25425 }
25426
25427 // if cell is no leaf cell do not compute it but set variables to dummy values.
25428 if(!m_solver->c_isLeafCell(cellId)) {
25429 m_bndryCells->a[bndryId].m_volume = gridCellVolume;
25430 for(MInt dim = 0; dim < 3; dim++) {
25431 m_bndryCells->a[bndryId].m_coordinates[dim] = m_solver->a_coordinate(cellId, dim);
25432 }
25433 m_bndryCells->a[bndryId].m_noSrfcs = 0;
25434 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = faceVolume[0];
25435 for(MInt dim = 0; dim < 3; dim++) {
25436 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = faceCentroid[0][dim];
25437 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = F1 / sqrt(F3);
25438 }
25439 for(MInt i = 0; i < nDim; i++) {
25440 m_bndryCells->a[bndryId].m_coordinates[i] -= m_solver->a_coordinate(cellId, i);
25441 }
25442 continue;
25443 }
25444
25445 // 1. Compute Voxel corners
25446 for(MInt i = 0; i < 8; i++) {
25447 for(MInt dim = 0; dim < nDim; dim++) {
25448 corner[i][dim] = m_solver->a_coordinate(cellId, dim)
25449 + cornerIndices[i][dim] * F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
25450 }
25451 }
25452 for(MInt i = 0; i < 6; i++) {
25453 faceCut[i] = false;
25454 faceCut_0[i] = false;
25455 }
25456
25457
25458 // 2. Determine Case and check if case is implemented and if case is unambiguous
25459 currentCase = mcCases[bndryId];
25460 presentCases[currentCase]++;
25461 currentSubCase = subCases[bndryId];
25462 presentSubCases[currentCase][currentSubCase]++;
25463
25464 if(!(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints == caseCutPoints[currentCase])) {
25465 cerr << "FvBndryCnd3D::createCutFaceMGC - Error: number of cut points not correct!" << endl;
25466 cerr << "Case: " << currentCase << " cutPointsTheory: " << caseCutPoints[currentCase]
25467 << " actual Cut Points: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints << endl;
25468 cerr << "Cell level: " << m_solver->a_level(cellId) << endl;
25469 stringstream fileName;
25470 fileName << cellId << ".stl";
25471 writeStlFileOfCell(cellId, (fileName.str()).c_str());
25472 cerr << "Wrote stl-file of cell. FileName: " << (fileName.str()) << endl;
25473 }
25474 if(!caseStatesSTL[currentCase][0]) {
25475 cerr << "FvBndryCnd3D::createCutFaceMGC - Error: Case not implemented: " << currentCase << endl;
25476 cerr << "Cell level: " << m_solver->a_level(cellId) << endl;
25477 stringstream fileName;
25478 fileName << cellId << ".stl";
25479 writeStlFileOfCell(cellId, (fileName.str()).c_str());
25480 cerr << "Wrote stl-file of cell. FileName: " << (fileName.str()) << endl;
25481 continue;
25482 }
25483
25484
25485 // compute cell depending on its case and disambiguation
25486 if(!caseStatesSTL[currentCase][1]) {
25487 switch(currentCase) {
25488 case 3: {
25489 for(MInt i = 0; i < 6; i++) {
25490 faceVolume_0[i] = faceVolume[i];
25491 for(MInt j = 0; j < 3; j++) {
25492 faceCentroid_0[i][j] = faceCentroid[i][j];
25493 }
25494 }
25495 cellVolume_0 = gridCellVolume;
25496 for(MInt i = 0; i < 3; i++) {
25497 cellCentroid_0[i] = m_solver->a_coordinate(cellId, i);
25498 }
25499
25500
25501 if((currentSubCase < 12 && disambiguation[bndryId] == 0)
25502 || (currentSubCase >= 12 && disambiguation[bndryId] == 1)) { // case 3.2, 1 surface
25503
25504 // compute cell without correction (no split surface, convex cell), correct later if subCase >= 12 (split
25505 // surface, concave cell)
25506 m_bndryCells->a[bndryId].m_noSrfcs = 1;
25507
25508 for(MInt face = 0; face < 6; face++) {
25509 nfs_cur[face] = nfs3_2[currentSubCase][face];
25510 }
25511 noFaces = 5;
25512 p_0 = corner[cornersMCtoSOLVER[tiling3_2STL[currentSubCase][0]]];
25513 p_0s = corner[cornersMCtoSOLVER[tiling3_2STL[currentSubCase][1]]];
25514
25515 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][2]];
25516 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25517 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][3]];
25518 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25519 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][4]];
25520 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25521 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][5]];
25522 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25523 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][6]];
25524 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25525 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][7]];
25526 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25527 face1 = facesMCtoSOLVER[tiling3_2STL[currentSubCase][8]];
25528 face2 = facesMCtoSOLVER[tiling3_2STL[currentSubCase][9]];
25529 face3 = facesMCtoSOLVER[tiling3_2STL[currentSubCase][10]];
25530 face4 = facesMCtoSOLVER[tiling3_2STL[currentSubCase][11]];
25531 face5 = facesMCtoSOLVER[tiling3_2STL[currentSubCase][12]];
25532
25533 computeTri(p_0, p_1, p_2, &faceVolume[face1], faceCentroid[face1], normal[face1]);
25534 computeTri(p_0, p_2, p_3, &faceVolume[face2], faceCentroid[face2], normal[face2]);
25535 computeTri(p_0s, p_2s, p_3s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
25536 computeTri(p_0s, p_1s, p_2s, &faceVolume[face4], faceCentroid[face4], normal[face4]);
25537 computePoly6(p_0, p_1, p_3s, p_0s, p_1s, p_3, &faceVolume[face5], faceCentroid[face5], normal[face5]);
25538
25539 computePoly6(p_1, p_2, p_3, p_1s, p_2s, p_3s, &area_c, coordinates_c, normalVec_c);
25540
25541 maia::math::vecAvg<3>(M, p_0, p_0s, p_1, p_1s, p_2, p_2s, p_3, p_3s);
25542
25543 for(MInt i = 0; i < 5; i++) {
25544 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
25545 &pyraVolume[i], pyraCentroid[i]);
25546 }
25547 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
25548
25549 for(MInt i = 0; i < 6; i++) {
25550 volume_C += pyraVolume[i];
25551 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
25552 }
25553 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
25554
25555 if(currentSubCase >= 12) { // correct cell
25556
25557 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
25558 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
25559 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
25560 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
25561 p_1ss = corner[cornersMCtoSOLVER[tiling3_2STL[currentSubCase][13]]];
25562 p_2ss = corner[cornersMCtoSOLVER[tiling3_2STL[currentSubCase][14]]];
25563 splitCorner1 = cornersMCtoSOLVER[tiling3_2STL[currentSubCase][13]];
25564 splitCorner2 = cornersMCtoSOLVER[tiling3_2STL[currentSubCase][14]];
25565 computeTri(p_1s, p_1ss, p_3, &splitFaceVolume[0], splitFaceCentroid[0], splitFaceNormal[0]);
25566 computeTri(p_1, p_2ss, p_3s, &splitFaceVolume[1], splitFaceCentroid[1], splitFaceNormal[1]);
25567 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
25568
25569 correctNormal(normalVec_c);
25570 splitFaceId = face5;
25571 }
25572
25573 m_bndryCells->a[bndryId].m_volume = volume_C;
25574 // create 1 Cut face
25575 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
25576 for(MInt dim = 0; dim < 3; dim++) {
25577 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
25578 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
25579 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
25580 }
25581
25582 faceCut[face1] = true;
25583 faceCut[face2] = true;
25584 faceCut[face3] = true;
25585 faceCut[face4] = true;
25586 faceCut[face5] = true;
25587
25588 absA = F0;
25589 for(MInt i = 0; i < nDim; i++) {
25590 if(!nfs_cur[2 * i + 1]) faceVolume[2 * i + 1] = 0;
25591 if(!nfs_cur[2 * i]) faceVolume[2 * i] = 0;
25592 faceDiff[i] = faceVolume[2 * i + 1] - faceVolume[2 * i];
25593 absA += POW2(faceDiff[i]);
25594 }
25595
25596 if(currentSubCase < 12) {
25597 for(MInt i = 0; i < nDim; i++) {
25598 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] = faceDiff[i] / sqrt(absA);
25599 }
25600 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = sqrt(absA);
25601 }
25602
25603 } else { // case 3.1 - two surfaces or split cell
25604
25605 if(currentSubCase < 12) {
25606 // split cell: add another boundary cell and a new cell:
25607 cellId2 = createSplitCell_MGC(cellId, 1);
25608 bndryId2 = m_solver->a_bndryId(cellId2);
25609 m_splitParents[bndryId2] = bndryId;
25610 m_splitChildren[bndryId * 3 + 0] = bndryId2;
25611 if(bndryId == 0)
25612 cerr << " problem in FvBndryCnd3D::createCutFaceMGC, assuming cell 0 is no split cell failed! " << endl;
25613 m_bndryCells->a[bndryId].m_noSrfcs = 1;
25614 m_bndryCells->a[bndryId2].m_noSrfcs = 1;
25615 } else {
25616 m_bndryCells->a[bndryId].m_noSrfcs = 2;
25617 }
25618
25619 for(MInt face = 0; face < 6; face++) {
25620 nfs_cur[face] = nfs3_1[currentSubCase][face];
25621 }
25622
25623 // 1st Pyramid + 1st cutFace
25624 subCaseDummy = tiling3_1STL[currentSubCase][0];
25625 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
25626 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
25627 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25628 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
25629 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25630 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
25631 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25632 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
25633 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
25634 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
25635
25636 faceCut[face1] = true;
25637 faceCut[face2] = true;
25638 faceCut[face3] = true;
25639
25640 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
25641 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
25642 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
25643
25644 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
25645
25646 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
25647
25648 if(currentSubCase >= 12) {
25649 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
25650 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
25651 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
25652
25653 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
25654
25655 correctNormal(normalVec_c);
25656 } else {
25657 for(MInt face = 0; face < 6; face++) {
25658 nfs_cur[face] = nfs1[subCaseDummy][face];
25659 }
25660 }
25661
25662 // create 1st Cut face and 1st cell
25663 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
25664 for(MInt dim = 0; dim < 3; dim++) {
25665 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
25666 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
25667 }
25668 m_bndryCells->a[bndryId].m_volume = volume_C;
25669 for(MInt dim = 0; dim < 3; dim++) {
25670 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
25671 }
25672
25673 if(currentSubCase >= 12) {
25674 faceVolume_0[face1] = faceVolume[face1];
25675 faceVolume_0[face2] = faceVolume[face2];
25676 faceVolume_0[face3] = faceVolume[face3];
25677 cellVolume_0 = volume_C;
25678 for(MInt i = 0; i < 3; i++) {
25679 cellCentroid_0[i] = coordinates_Cell[i];
25680 faceCentroid_0[face1][i] = faceCentroid[face1][i];
25681 faceCentroid_0[face2][i] = faceCentroid[face2][i];
25682 faceCentroid_0[face3][i] = faceCentroid[face3][i];
25683 }
25684 }
25685
25686 // 2nd Pyramid + 2nd cutFace
25687 subCaseDummy = tiling3_1STL[currentSubCase][1];
25688 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
25689 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
25690 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25691 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
25692 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25693 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
25694 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25695 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
25696 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
25697 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
25698
25699 if(currentSubCase < 12) {
25700 for(MInt face = 0; face < 6; face++) {
25701 nfs_cur_0[face] = nfs1[subCaseDummy][face];
25702 }
25703
25704 faceCut_0[face1] = true;
25705 faceCut_0[face2] = true;
25706 faceCut_0[face3] = true;
25707
25708 computeTri(p_0, p_1, p_3, &faceVolume_0[face1], faceCentroid_0[face1]);
25709 computeTri(p_0, p_3, p_2, &faceVolume_0[face2], faceCentroid_0[face2]);
25710 computeTri(p_0, p_2, p_1, &faceVolume_0[face3], faceCentroid_0[face3]);
25711
25712 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
25713
25714 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
25715
25716 // create 2nd Cut face & cell
25717 m_bndryCells->a[bndryId2].m_srfcs[0]->m_area = area_c;
25718 for(MInt dim = 0; dim < 3; dim++) {
25719 m_bndryCells->a[bndryId2].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
25720 m_bndryCells->a[bndryId2].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
25721 }
25722
25723 m_bndryCells->a[bndryId2].m_volume = volume_C;
25724 for(MInt dim = 0; dim < 3; dim++) {
25725 m_bndryCells->a[bndryId2].m_coordinates[dim] = coordinates_Cell[dim];
25726 }
25727
25728 // fill ambiguous corners array
25729 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]] = cellId2;
25730
25731 } else {
25732 faceCut[face1] = true;
25733 faceCut[face2] = true;
25734 faceCut[face3] = true;
25735
25736 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
25737 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
25738 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
25739
25740 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
25741
25742 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
25743
25744 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
25745 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
25746 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
25747
25748 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
25749
25750 correctNormal(normalVec_c);
25751
25752 // create 2nd Cut face
25753 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
25754 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
25755 for(MInt dim = 0; dim < 3; dim++) {
25756 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
25757 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
25758 }
25759
25760 m_bndryCells->a[bndryId].m_volume = volume_C;
25761 for(MInt dim = 0; dim < 3; dim++) {
25762 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
25763 }
25764 }
25765 }
25766 break;
25767 }
25768 case 4: {
25769 for(MInt i = 0; i < 6; i++) {
25770 faceVolume_0[i] = faceVolume[i];
25771 for(MInt j = 0; j < 3; j++) {
25772 faceCentroid_0[i][j] = faceCentroid[i][j];
25773 }
25774 }
25775 cellVolume_0 = gridCellVolume;
25776 for(MInt i = 0; i < 3; i++) {
25777 cellCentroid_0[i] = m_solver->a_coordinate(cellId, i);
25778 }
25779
25780 // cerr << "Case 4.1 detected. Starting Cutface computation..." << endl;
25781 if(currentSubCase < 4) {
25782 // split cell: add another boundary cell and a new cell:
25783 cellId2 = createSplitCell_MGC(cellId, 1);
25784 bndryId2 = m_solver->a_bndryId(cellId2);
25785 m_splitParents[bndryId2] = bndryId;
25786 m_splitChildren[bndryId * 3 + 0] = bndryId2;
25787 if(bndryId == 0)
25788 cerr << " problem in FvBndryCnd3D::createCutFaceMGC, assuming cell 0 is no split cell failed! " << endl;
25789
25790 // compute first cell:
25791 m_bndryCells->a[bndryId].m_noSrfcs = 1;
25792
25793 // first cell is a pyramid - case 1:
25794 subCaseDummy = tiling4_1STL[currentSubCase][0];
25795 for(MInt face = 0; face < 6; face++) {
25796 nfs_cur[face] = nfs1[subCaseDummy][face];
25797 }
25798 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
25799 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
25800 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25801 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
25802 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25803 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
25804 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25805 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
25806 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
25807 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
25808
25809 faceCut[face1] = true;
25810 faceCut[face2] = true;
25811 faceCut[face3] = true;
25812
25813 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
25814 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
25815 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
25816
25817 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
25818
25819 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
25820
25821 m_bndryCells->a[bndryId].m_volume = volume_C;
25822 for(MInt dim = 0; dim < 3; dim++) {
25823 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
25824 }
25825
25826 // create 1st Cut face
25827 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
25828 for(MInt dim = 0; dim < 3; dim++) {
25829 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
25830 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
25831 }
25832
25833 // compute 2nd cell:
25834
25835 m_bndryCells->a[bndryId2].m_noSrfcs = 1;
25836
25837 subCaseDummy = tiling4_1STL[currentSubCase][1];
25838 for(MInt face = 0; face < 6; face++) {
25839 nfs_cur_0[face] = nfs1[subCaseDummy][face];
25840 }
25841 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
25842 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
25843 p_1 = m_bndryCells->a[bndryId2].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25844 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
25845 p_2 = m_bndryCells->a[bndryId2].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25846 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
25847 p_3 = m_bndryCells->a[bndryId2].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25848 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
25849 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
25850 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
25851
25852 faceCut_0[face1] = true;
25853 faceCut_0[face2] = true;
25854 faceCut_0[face3] = true;
25855
25856 computeTri(p_0, p_1, p_3, &faceVolume_0[face1], faceCentroid_0[face1]);
25857 computeTri(p_0, p_3, p_2, &faceVolume_0[face2], faceCentroid_0[face2]);
25858 computeTri(p_0, p_2, p_1, &faceVolume_0[face3], faceCentroid_0[face3]);
25859
25860 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
25861
25862 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
25863
25864 m_bndryCells->a[bndryId2].m_volume = volume_C;
25865 for(MInt dim = 0; dim < 3; dim++) {
25866 m_bndryCells->a[bndryId2].m_coordinates[dim] = coordinates_Cell[dim];
25867 }
25868
25869 // create 2nd Cut face
25870 m_bndryCells->a[bndryId2].m_srfcs[0]->m_area = area_c;
25871 for(MInt dim = 0; dim < 3; dim++) {
25872 m_bndryCells->a[bndryId2].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
25873 m_bndryCells->a[bndryId2].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
25874 }
25875
25876 // fill ambiguous corners array
25877 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]] = cellId2;
25878
25879 } else {
25880 m_bndryCells->a[bndryId].m_noSrfcs = 2;
25881 for(MInt face = 0; face < 6; face++) {
25882 nfs_cur[face] = nfs4_1[currentSubCase][face];
25883 }
25884 // 1st Pyramid + 1st cutFace
25885 subCaseDummy = tiling4_1STL[currentSubCase][0];
25886 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
25887 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
25888 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25889 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
25890 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25891 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
25892 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25893 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
25894 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
25895 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
25896
25897 faceCut[face1] = true;
25898 faceCut[face2] = true;
25899 faceCut[face3] = true;
25900
25901 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
25902 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
25903 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
25904
25905 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
25906
25907 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
25908
25909 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
25910 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
25911 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
25912
25913 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
25914
25915 correctNormal(normalVec_c);
25916
25917 // create 1st Cut face
25918 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
25919 for(MInt dim = 0; dim < 3; dim++) {
25920 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
25921 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
25922 }
25923
25924 faceVolume_0[face1] = faceVolume[face1];
25925 faceVolume_0[face2] = faceVolume[face2];
25926 faceVolume_0[face3] = faceVolume[face3];
25927 cellVolume_0 = volume_C;
25928 for(MInt i = 0; i < 3; i++) {
25929 cellCentroid_0[i] = coordinates_Cell[i];
25930 faceCentroid_0[face1][i] = faceCentroid[face1][i];
25931 faceCentroid_0[face2][i] = faceCentroid[face2][i];
25932 faceCentroid_0[face3][i] = faceCentroid[face3][i];
25933 }
25934
25935 // 2nd Pyramid + 2nd cutFace
25936 subCaseDummy = tiling4_1STL[currentSubCase][1];
25937 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
25938 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
25939 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25940 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
25941 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25942 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
25943 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
25944 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
25945 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
25946 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
25947
25948 faceCut[face1] = true;
25949 faceCut[face2] = true;
25950 faceCut[face3] = true;
25951
25952 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
25953 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
25954 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
25955
25956 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
25957
25958 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
25959
25960 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
25961 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
25962 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
25963
25964 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
25965
25966 correctNormal(normalVec_c);
25967
25968 // create 2nd Cut face
25969 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
25970 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
25971 for(MInt dim = 0; dim < 3; dim++) {
25972 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
25973 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
25974 }
25975
25976 m_bndryCells->a[bndryId].m_volume = volume_C;
25977 for(MInt dim = 0; dim < 3; dim++) {
25978 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
25979 }
25980 }
25981 break;
25982 }
25983 case 6: {
25984 for(MInt i = 0; i < 6; i++) {
25985 faceVolume_0[i] = faceVolume[i];
25986 for(MInt j = 0; j < 3; j++) {
25987 faceCentroid_0[i][j] = faceCentroid[i][j];
25988 }
25989 }
25990 cellVolume_0 = gridCellVolume;
25991 for(MInt i = 0; i < 3; i++) {
25992 cellCentroid_0[i] = m_solver->a_coordinate(cellId, i);
25993 }
25994 if((currentSubCase < 24 && disambiguation[bndryId] == 1)
25995 || (currentSubCase >= 24 && disambiguation[bndryId] == 0)) {
25996 // case 6.1 - 2 surfaces or split cell
25997
25998 if(currentSubCase < 24) {
25999 // split cell: add another boundary cell and a new cell:
26000 cellId2 = createSplitCell_MGC(cellId, 1);
26001 bndryId2 = m_solver->a_bndryId(cellId2);
26002 m_splitParents[bndryId2] = bndryId;
26003 m_splitChildren[bndryId * 3 + 0] = bndryId2;
26004 if(bndryId == 0)
26005 cerr << " problem in FvBndryCnd3D::createCutFaceMGC, assuming cell 0 is no split cell failed! " << endl;
26006 m_bndryCells->a[bndryId].m_noSrfcs = 1;
26007 m_bndryCells->a[bndryId2].m_noSrfcs = 1;
26008 } else {
26009 m_bndryCells->a[bndryId].m_noSrfcs = 2;
26010 }
26011
26012 for(MInt face = 0; face < 6; face++) {
26013 nfs_cur[face] = nfs6_1[currentSubCase][face];
26014 }
26015
26016 // 1st prism & 1st cutFace
26017 subCaseDummy = tiling6_1STL[currentSubCase][0];
26018 p_0 = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][0]]];
26019 p_0s = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][1]]];
26020 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
26021 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26022 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
26023 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26024 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
26025 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26026 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
26027 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26028 face1 = facesMCtoSOLVER[tiling2STL[subCaseDummy][6]];
26029 face2 = facesMCtoSOLVER[tiling2STL[subCaseDummy][7]];
26030 face3 = facesMCtoSOLVER[tiling2STL[subCaseDummy][8]];
26031 face4 = facesMCtoSOLVER[tiling2STL[subCaseDummy][9]];
26032
26033 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2], normal[face2]);
26034 computeTri(p_0s, p_3s, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
26035 computeTrapez(p_0, p_0s, p_3s, p_3, &faceVolume[face1], faceCentroid[face1], normal[face1]);
26036 computeTrapez(p_2, p_2s, p_0s, p_0, &faceVolume[face4], faceCentroid[face4], normal[face4]);
26037
26038 computePoly4(p_3, p_3s, p_2s, p_2, &area_c, coordinates_c, normalVec_c);
26039
26040 maia::math::vecAvg<3>(M, p_0, p_0s, p_2, p_2s, p_3, p_3s);
26041
26042 for(MInt i = 0; i < 4; i++) {
26043 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
26044 &pyraVolume[i], pyraCentroid[i]);
26045 }
26046 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[4], pyraCentroid[4]);
26047 for(MInt i = 0; i < 5; i++) {
26048 volume_C += pyraVolume[i];
26049 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
26050 }
26051 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
26052
26053 if(currentSubCase >= 24) {
26054 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
26055 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
26056 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
26057 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
26058
26059 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
26060
26061 correctNormal(normalVec_c);
26062 } else {
26063 for(MInt face = 0; face < 6; face++) {
26064 nfs_cur[face] = nfs2[subCaseDummy][face];
26065 }
26066 }
26067
26068 faceCut[face1] = true;
26069 faceCut[face2] = true;
26070 faceCut[face3] = true;
26071 faceCut[face4] = true;
26072
26073 // create 1st Cut face & 1st cut cell
26074 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
26075 for(MInt dim = 0; dim < 3; dim++) {
26076 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26077 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26078 }
26079 m_bndryCells->a[bndryId].m_volume = volume_C;
26080 for(MInt dim = 0; dim < 3; dim++) {
26081 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
26082 }
26083
26084 if(currentSubCase >= 24) {
26085 faceVolume_0[face1] = faceVolume[face1];
26086 faceVolume_0[face2] = faceVolume[face2];
26087 faceVolume_0[face3] = faceVolume[face3];
26088 faceVolume_0[face4] = faceVolume[face4];
26089 cellVolume_0 = volume_C;
26090 volume_C = 0;
26091 for(MInt i = 0; i < 3; i++) {
26092 cellCentroid_0[i] = coordinates_Cell[i];
26093 faceCentroid_0[face1][i] = faceCentroid[face1][i];
26094 faceCentroid_0[face2][i] = faceCentroid[face2][i];
26095 faceCentroid_0[face3][i] = faceCentroid[face3][i];
26096 faceCentroid_0[face4][i] = faceCentroid[face4][i];
26097 coordinates_Cell[i] = 0;
26098 }
26099 }
26100
26101 // 2nd Pyramid + 2nd cutFace
26102 subCaseDummy = tiling6_1STL[currentSubCase][1];
26103 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
26104 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
26105 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26106 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
26107 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26108 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
26109 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26110 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
26111 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
26112 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
26113
26114 if(currentSubCase < 24) {
26115 for(MInt face = 0; face < 6; face++) {
26116 nfs_cur_0[face] = nfs1[subCaseDummy][face];
26117 }
26118
26119 faceCut_0[face1] = true;
26120 faceCut_0[face2] = true;
26121 faceCut_0[face3] = true;
26122
26123 computeTri(p_0, p_1, p_3, &faceVolume_0[face1], faceCentroid_0[face1]);
26124 computeTri(p_0, p_3, p_2, &faceVolume_0[face2], faceCentroid_0[face2]);
26125 computeTri(p_0, p_2, p_1, &faceVolume_0[face3], faceCentroid_0[face3]);
26126
26127 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
26128
26129 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
26130
26131 // create 2nd Cut face & cell
26132 m_bndryCells->a[bndryId2].m_srfcs[0]->m_area = area_c;
26133 for(MInt dim = 0; dim < 3; dim++) {
26134 m_bndryCells->a[bndryId2].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26135 m_bndryCells->a[bndryId2].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26136 }
26137
26138 m_bndryCells->a[bndryId2].m_volume = volume_C;
26139 for(MInt dim = 0; dim < 3; dim++) {
26140 m_bndryCells->a[bndryId2].m_coordinates[dim] = coordinates_Cell[dim];
26141 }
26142
26143 // fill ambiguous corners array
26144 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]] = cellId2;
26145 } else {
26146 faceCut[face1] = true;
26147 faceCut[face2] = true;
26148 faceCut[face3] = true;
26149
26150 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
26151 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
26152 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
26153
26154 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
26155
26156 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
26157
26158 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
26159 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
26160 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
26161
26162 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
26163
26164 correctNormal(normalVec_c);
26165
26166 // create 2nd Cut face
26167 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
26168 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
26169 for(MInt dim = 0; dim < 3; dim++) {
26170 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
26171 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
26172 }
26173
26174 m_bndryCells->a[bndryId].m_volume = volume_C;
26175 for(MInt dim = 0; dim < 3; dim++) {
26176 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
26177 }
26178 }
26179
26180 } else {
26181 // case 6.2 - 1 surface (computed as 3 connected surfaces)
26182
26183 // compute cell without correction (no split surface, convex cell), correct later if subCase >=24 (split
26184 // surface, concave cell)
26185 m_bndryCells->a[bndryId].m_noSrfcs = 3;
26186
26187 for(MInt face = 0; face < 6; face++) {
26188 nfs_cur[face] = nfs6_1[currentSubCase][face];
26189 }
26190 p_0 = corner[cornersMCtoSOLVER[tiling6_2STL[currentSubCase][0]]];
26191 p_1 = corner[cornersMCtoSOLVER[tiling6_2STL[currentSubCase][1]]];
26192 p_2 = corner[cornersMCtoSOLVER[tiling6_2STL[currentSubCase][2]]];
26193 p_4 = corner[cornersMCtoSOLVER[tiling6_2STL[currentSubCase][3]]];
26194 p_5 = corner[cornersMCtoSOLVER[tiling6_2STL[currentSubCase][4]]];
26195
26196 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][5]];
26197 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26198 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][6]];
26199 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26200 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][7]];
26201 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26202 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][8]];
26203 p_1ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26204 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][9]];
26205 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26206 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][10]];
26207 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26208 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][11]];
26209 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26210 face1 = facesMCtoSOLVER[tiling6_2STL[currentSubCase][12]];
26211 face2 = facesMCtoSOLVER[tiling6_2STL[currentSubCase][13]];
26212 face3 = facesMCtoSOLVER[tiling6_2STL[currentSubCase][14]];
26213 face4 = facesMCtoSOLVER[tiling6_2STL[currentSubCase][15]];
26214 face5 = facesMCtoSOLVER[tiling6_2STL[currentSubCase][16]];
26215 face6 = facesMCtoSOLVER[tiling6_2STL[currentSubCase][17]];
26216
26217 computePoly6(p_1, p_1s, p_2s, p_2, p_2ss, p_1ss, &faceVolume[face1], faceCentroid[face1], normal[face1]);
26218 computeTrapez(p_0, p_1, p_1s, p_0s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
26219 computeTrapez(p_0, p_1, p_1ss, p_0ss, &faceVolume[face3], faceCentroid[face3], normal[face3]);
26220 computeTri(p_2, p_3, p_2ss, &faceVolume[face4], faceCentroid[face4], normal[face4]);
26221 computeTri(p_2s, p_2, p_3, &faceVolume[face5], faceCentroid[face5], normal[face5]);
26222 computeTri(p_0, p_0s, p_0ss, &faceVolume[face6], faceCentroid[face6], normal[face6]);
26223
26224 maia::math::vecAvg<3>(M, p_0s, p_0ss, p_1s, p_1ss, p_2s, p_2ss, p_3, p_0, p_1, p_2);
26225
26226 for(MInt i = 0; i < 6; i++) {
26227 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
26228 &pyraVolume[i], pyraCentroid[i]);
26229 }
26230 // 1st cut surface
26231 computePoly4(p_0s, p_3, p_2s, p_1s, &area_c, coordinates_c, normalVec_c);
26232 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
26233 if(currentSubCase >= 24) correctNormal(normalVec_c);
26234 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
26235 for(MInt dim = 0; dim < 3; dim++) {
26236 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26237 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26238 }
26239 // 2nd cut surface
26240 computePoly4(p_0ss, p_1ss, p_2ss, p_3, &area_c, coordinates_c, normalVec_c);
26241 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[7], pyraCentroid[7]);
26242 if(currentSubCase >= 24) correctNormal(normalVec_c);
26243 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
26244 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
26245 for(MInt dim = 0; dim < 3; dim++) {
26246 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
26247 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
26248 }
26249 // 3rd cut surface
26250 computePoly3(p_0s, p_0ss, p_3, &area_c, coordinates_c, normalVec_c);
26251 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[8], pyraCentroid[8]);
26252 if(currentSubCase >= 24) correctNormal(normalVec_c);
26253 m_bndryCells->a[bndryId].m_srfcs[2]->m_area = area_c;
26254 m_bndryCells->a[bndryId].m_srfcs[2]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
26255 for(MInt dim = 0; dim < 3; dim++) {
26256 m_bndryCells->a[bndryId].m_srfcs[2]->m_coordinates[dim] = coordinates_c[dim];
26257 m_bndryCells->a[bndryId].m_srfcs[2]->m_normalVector[dim] = normalVec_c[dim];
26258 }
26259
26260 for(MInt i = 0; i < 9; i++) {
26261 volume_C += pyraVolume[i];
26262 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
26263 }
26264 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
26265
26266 if(currentSubCase >= 24) { // cell with split surface
26267
26268 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
26269 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
26270 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
26271 correctFace(&faceVolume[face5], faceCentroid[face5], &faceVolume_0[face5], faceCentroid_0[face5]);
26272 correctFace(&faceVolume[face6], faceCentroid[face6], &faceVolume_0[face6], faceCentroid_0[face6]);
26273 splitCorner1 = cornersMCtoSOLVER[tiling6_2STL[currentSubCase][3]];
26274 splitCorner2 = cornersMCtoSOLVER[tiling6_2STL[currentSubCase][4]];
26275 computeTri(p_4, p_2s, p_1s, &splitFaceVolume[0], splitFaceCentroid[0], splitFaceNormal[0]);
26276 computeTri(p_5, p_1ss, p_2ss, &splitFaceVolume[1], splitFaceCentroid[1], splitFaceNormal[1]);
26277
26278 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
26279
26280 splitFaceId = face1;
26281 }
26282
26283 m_bndryCells->a[bndryId].m_volume = volume_C;
26284 for(MInt dim = 0; dim < 3; dim++) {
26285 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
26286 }
26287
26288 faceCut[face1] = true;
26289 faceCut[face2] = true;
26290 faceCut[face3] = true;
26291 faceCut[face4] = true;
26292 faceCut[face5] = true;
26293 faceCut[face6] = true;
26294 }
26295
26296 break;
26297 }
26298 case 7: {
26299 disamb_tmp = disambiguation[bndryId];
26300 if(currentSubCase >= 8) disamb_tmp = 7 - disamb_tmp;
26301
26302 switch(disamb_tmp) {
26303 case 0: {
26304 // compute case 7.4.1
26305
26306 for(MInt i = 0; i < 6; i++) {
26307 faceVolume_0[i] = faceVolume[i];
26308 for(MInt j = 0; j < 3; j++) {
26309 faceCentroid_0[i][j] = faceCentroid[i][j];
26310 }
26311 }
26312 cellVolume_0 = gridCellVolume;
26313 for(MInt i = 0; i < 3; i++) {
26314 cellCentroid_0[i] = m_solver->a_coordinate(cellId, i);
26315 }
26316
26317 if(currentSubCase >= 8) {
26318 // split cell: add another boundary cell and a new cell:
26319 cellId2 = createSplitCell_MGC(cellId, 1);
26320 bndryId2 = m_solver->a_bndryId(cellId2);
26321 m_splitParents[bndryId2] = bndryId;
26322 m_splitChildren[bndryId * 3 + 0] = bndryId2;
26323 if(bndryId == 0)
26324 cerr << " problem in FvBndryCnd3D::createCutFaceMGC, assuming cell 0 is no split cell failed! "
26325 << endl;
26326 m_bndryCells->a[bndryId].m_noSrfcs = 1;
26327 m_bndryCells->a[bndryId2].m_noSrfcs = 1;
26328 } else {
26329 m_bndryCells->a[bndryId].m_noSrfcs = 2;
26330 }
26331
26332 for(MInt face = 0; face < 6; face++) {
26333 nfs_cur[face] = nfs7_1[currentSubCase][face];
26334 }
26335
26336 // 1st Pyramid + 1st cutFace
26337 subCaseDummy = tiling7_4_1STL[currentSubCase][0];
26338 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
26339 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
26340 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26341 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
26342 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26343 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
26344 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26345 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
26346 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
26347 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
26348
26349 faceCut[face1] = true;
26350 faceCut[face2] = true;
26351 faceCut[face3] = true;
26352
26353 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
26354 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
26355 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
26356
26357 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
26358
26359 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
26360
26361 if(currentSubCase < 8) {
26362 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
26363 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
26364 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
26365
26366 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
26367
26368 correctNormal(normalVec_c);
26369 } else {
26370 for(MInt face = 0; face < 6; face++) {
26371 nfs_cur[face] = nfs1[subCaseDummy][face];
26372 }
26373 }
26374
26375 // create 1st Cut face and 1st cell
26376 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
26377 for(MInt dim = 0; dim < 3; dim++) {
26378 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26379 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26380 }
26381 m_bndryCells->a[bndryId].m_volume = volume_C;
26382 for(MInt dim = 0; dim < 3; dim++) {
26383 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
26384 }
26385
26386 if(currentSubCase < 8) {
26387 faceVolume_0[face1] = faceVolume[face1];
26388 faceVolume_0[face2] = faceVolume[face2];
26389 faceVolume_0[face3] = faceVolume[face3];
26390 cellVolume_0 = volume_C;
26391 volume_C = 0;
26392 for(MInt i = 0; i < 3; i++) {
26393 cellCentroid_0[i] = coordinates_Cell[i];
26394 faceCentroid_0[face1][i] = faceCentroid[face1][i];
26395 faceCentroid_0[face2][i] = faceCentroid[face2][i];
26396 faceCentroid_0[face3][i] = faceCentroid[face3][i];
26397 coordinates_Cell[i] = 0;
26398 }
26399 } else {
26400 volume_C = 0;
26401 for(MInt i = 0; i < 3; i++) {
26402 coordinates_Cell[i] = 0;
26403 }
26404 }
26405
26406 // create 2nd part of cell
26407 subCaseDummy = tiling7_4_1STL[currentSubCase][1];
26408 noFaces = 6;
26409 p_0 = corner[cornersMCtoSOLVER[tiling9STL[subCaseDummy][0]]];
26410 p_1 = corner[cornersMCtoSOLVER[tiling9STL[subCaseDummy][1]]];
26411 p_2 = corner[cornersMCtoSOLVER[tiling9STL[subCaseDummy][2]]];
26412 p_3 = corner[cornersMCtoSOLVER[tiling9STL[subCaseDummy][3]]];
26413
26414 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][4]];
26415 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26416 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][5]];
26417 p_1ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26418 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][6]];
26419 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26420 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][7]];
26421 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26422 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][8]];
26423 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26424 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][9]];
26425 p_3ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26426 face1 = facesMCtoSOLVER[tiling9STL[subCaseDummy][10]];
26427 face2 = facesMCtoSOLVER[tiling9STL[subCaseDummy][11]];
26428 face3 = facesMCtoSOLVER[tiling9STL[subCaseDummy][12]];
26429 face4 = facesMCtoSOLVER[tiling9STL[subCaseDummy][13]];
26430 face5 = facesMCtoSOLVER[tiling9STL[subCaseDummy][14]];
26431 face6 = facesMCtoSOLVER[tiling9STL[subCaseDummy][15]];
26432
26433 if(currentSubCase >= 8) {
26434 for(MInt face = 0; face < 6; face++) {
26435 nfs_cur_0[face] = nfs9[subCaseDummy][face];
26436 faceCut_0[face] = true;
26437 }
26438
26439 computePoly5(p_0, p_3, p_3ss, p_2s, p_2, &faceVolume_0[face1], faceCentroid_0[face1], normal[face1]);
26440 computePoly5(p_0, p_1, p_1ss, p_3s, p_3, &faceVolume_0[face3], faceCentroid_0[face3], normal[face3]);
26441 computePoly5(p_0, p_2, p_2ss, p_1s, p_1, &faceVolume_0[face5], faceCentroid_0[face5], normal[face5]);
26442 computeTri(p_1, p_1s, p_1ss, &faceVolume_0[face2], faceCentroid_0[face2], normal[face2]);
26443 computeTri(p_2, p_2s, p_2ss, &faceVolume_0[face4], faceCentroid_0[face4], normal[face4]);
26444 computeTri(p_3, p_3s, p_3ss, &faceVolume_0[face6], faceCentroid_0[face6], normal[face6]);
26445
26446 computePoly6(p_1ss, p_1s, p_2ss, p_2s, p_3ss, p_3s, &area_c, coordinates_c, normalVec_c);
26447
26448 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3, p_1s, p_2s, p_3s, p_1ss, p_2ss, p_3ss);
26449
26450 for(MInt i = 0; i < 6; i++) {
26451 computePyra(&faceVolume_0[*facepointers[i]], faceCentroid_0[*facepointers[i]],
26452 normal[*facepointers[i]], M, &pyraVolume[i], pyraCentroid[i]);
26453 }
26454 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
26455 for(MInt i = 0; i < 7; i++) {
26456 volume_C += pyraVolume[i];
26457 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
26458 }
26459 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
26460
26461 // create 2nd Cut face & cell
26462 m_bndryCells->a[bndryId2].m_srfcs[0]->m_area = area_c;
26463 for(MInt dim = 0; dim < 3; dim++) {
26464 m_bndryCells->a[bndryId2].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26465 m_bndryCells->a[bndryId2].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26466 }
26467
26468 m_bndryCells->a[bndryId2].m_volume = volume_C;
26469 for(MInt dim = 0; dim < 3; dim++) {
26470 m_bndryCells->a[bndryId2].m_coordinates[dim] = coordinates_Cell[dim];
26471 }
26472
26473 // fill ambiguous corners array
26474 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling9STL[subCaseDummy][0]]] = cellId2;
26475 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling9STL[subCaseDummy][1]]] = cellId2;
26476 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling9STL[subCaseDummy][2]]] = cellId2;
26477 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling9STL[subCaseDummy][3]]] = cellId2;
26478
26479 } else {
26480 for(MInt face = 0; face < 6; face++) {
26481 faceCut[face] = true;
26482 }
26483
26484 computePoly5(p_0, p_3, p_3ss, p_2s, p_2, &faceVolume[face1], faceCentroid[face1], normal[face1]);
26485 computePoly5(p_0, p_1, p_1ss, p_3s, p_3, &faceVolume[face3], faceCentroid[face3], normal[face3]);
26486 computePoly5(p_0, p_2, p_2ss, p_1s, p_1, &faceVolume[face5], faceCentroid[face5], normal[face5]);
26487 computeTri(p_1, p_1s, p_1ss, &faceVolume[face2], faceCentroid[face2], normal[face2]);
26488 computeTri(p_2, p_2s, p_2ss, &faceVolume[face4], faceCentroid[face4], normal[face4]);
26489 computeTri(p_3, p_3s, p_3ss, &faceVolume[face6], faceCentroid[face6], normal[face6]);
26490
26491 computePoly6(p_1ss, p_1s, p_2ss, p_2s, p_3ss, p_3s, &area_c, coordinates_c, normalVec_c);
26492
26493 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3, p_1s, p_2s, p_3s, p_1ss, p_2ss, p_3ss);
26494
26495 for(MInt i = 0; i < 6; i++) {
26496 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]],
26497 M, &pyraVolume[i], pyraCentroid[i]);
26498 }
26499 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
26500 for(MInt i = 0; i < 7; i++) {
26501 volume_C += pyraVolume[i];
26502 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
26503 }
26504 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
26505
26506 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
26507 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
26508 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
26509 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
26510 correctFace(&faceVolume[face5], faceCentroid[face5], &faceVolume_0[face5], faceCentroid_0[face5]);
26511 correctFace(&faceVolume[face6], faceCentroid[face6], &faceVolume_0[face6], faceCentroid_0[face6]);
26512
26513 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
26514
26515 correctNormal(normalVec_c);
26516
26517 // create 2nd Cut face
26518 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
26519 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
26520 for(MInt dim = 0; dim < 3; dim++) {
26521 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
26522 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
26523 }
26524
26525 m_bndryCells->a[bndryId].m_volume = volume_C;
26526 for(MInt dim = 0; dim < 3; dim++) {
26527 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
26528 }
26529 }
26530
26531 break;
26532 }
26533 case 1:
26534 case 2:
26535 case 4: {
26536 for(MInt i = 0; i < 6; i++) {
26537 faceVolume_0[i] = faceVolume[i];
26538 faceVolume_00[i] = faceVolume[i];
26539 for(MInt j = 0; j < 3; j++) {
26540 faceCentroid_0[i][j] = faceCentroid[i][j];
26541 }
26542 }
26543 cellVolume_0 = gridCellVolume;
26544 for(MInt i = 0; i < 3; i++) {
26545 cellCentroid_0[i] = m_solver->a_coordinate(cellId, i);
26546 }
26547
26548 for(MInt face = 0; face < 6; face++) {
26549 nfs_cur[face] = nfs7_1[currentSubCase][face];
26550 }
26551
26552 if(disamb_tmp == 1) disambPointer_dummy = &tiling7_3_1STL[0][0];
26553 if(disamb_tmp == 2) disambPointer_dummy = &tiling7_3_2STL[0][0];
26554 if(disamb_tmp == 4) disambPointer_dummy = &tiling7_3_4STL[0][0];
26555
26556 for(MInt i = 0; i < 16; i++)
26557 for(MInt j = 0; j < 21; j++)
26558 disambPointer[i][j] = disambPointer_dummy[i * 21 + j];
26559
26560 p_0 = corner[cornersMCtoSOLVER[disambPointer[currentSubCase][0]]];
26561 p_1 = corner[cornersMCtoSOLVER[disambPointer[currentSubCase][1]]];
26562 p_2 = corner[cornersMCtoSOLVER[disambPointer[currentSubCase][2]]];
26563 p_3 = corner[cornersMCtoSOLVER[disambPointer[currentSubCase][3]]];
26564 p_4 = corner[cornersMCtoSOLVER[disambPointer[currentSubCase][4]]];
26565 p_5 = corner[cornersMCtoSOLVER[disambPointer[currentSubCase][5]]];
26566 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][6]];
26567 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26568 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][7]];
26569 p_1ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26570 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][8]];
26571 p_1sss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26572 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][9]];
26573 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26574 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][10]];
26575 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26576 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][11]];
26577 p_2sss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26578 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][12]];
26579 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26580 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][13]];
26581 p_3ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26582 cutDummy = edgesMCtoSOLVER[disambPointer[currentSubCase][14]];
26583 p_3sss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26584
26585 face1 = facesMCtoSOLVER[disambPointer[currentSubCase][15]];
26586 face2 = facesMCtoSOLVER[disambPointer[currentSubCase][16]];
26587 face3 = facesMCtoSOLVER[disambPointer[currentSubCase][17]];
26588 face4 = facesMCtoSOLVER[disambPointer[currentSubCase][18]];
26589 face5 = facesMCtoSOLVER[disambPointer[currentSubCase][19]];
26590 face6 = facesMCtoSOLVER[disambPointer[currentSubCase][20]];
26591 if(currentSubCase < 8) {
26592 // case 7.3 - 2 surfaces
26593 m_bndryCells->a[bndryId].m_noSrfcs = 2;
26594
26595 // case 7.3 - 1 surface (computed as 2 connected surfaces)
26596 computePoly6(p_1, p_1sss, p_3sss, p_3, p_3s, p_1ss, &faceVolume[face2], faceCentroid[face2],
26597 normal[face2]);
26598 computePoly6(p_1, p_1s, p_2ss, p_2, p_2sss, p_1sss, &faceVolume[face3], faceCentroid[face3],
26599 normal[face3]);
26600 computeTri(p_1, p_1ss, p_1s, &faceVolume[face4], faceCentroid[face4], normal[face4]);
26601 computeTri(p_2, p_2ss, p_2s, &faceVolume[face5], faceCentroid[face5], normal[face5]);
26602 computeTri(p_3, p_3ss, p_3s, &faceVolume[face6], faceCentroid[face6], normal[face6]);
26603 splitCorner1 = cornersMCtoSOLVER[disambPointer[currentSubCase][3]];
26604 splitCorner2 = cornersMCtoSOLVER[disambPointer[currentSubCase][2]];
26605 computeTri(p_3, p_3sss, p_3ss, &splitFaceVolume[0], splitFaceCentroid[0], splitFaceNormal[0]);
26606 computeTri(p_2, p_2s, p_2sss, &splitFaceVolume[1], splitFaceCentroid[1], splitFaceNormal[1]);
26607
26608 splitFaceId = face1;
26609 maia::math::vecAvg<3>(M, p_1s, p_1ss, p_1sss, p_2s, p_2ss, p_2sss, p_3s, p_3ss, p_3sss);
26610
26611 faceVolume[face1] = F0;
26612
26613 for(MInt i = 0; i < 6; i++) {
26614 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]],
26615 M, &pyraVolume[i], pyraCentroid[i]);
26616 }
26617 computePyra(&splitFaceVolume[0], splitFaceCentroid[0], splitFaceNormal[0], M, &pyraVolume[6],
26618 pyraCentroid[6]);
26619 computePyra(&splitFaceVolume[1], splitFaceCentroid[1], splitFaceNormal[1], M, &pyraVolume[7],
26620 pyraCentroid[7]);
26621
26622 // 1st cut surface
26623 computePoly5(p_1sss, p_2sss, p_2s, p_3ss, p_3sss, &area_c, coordinates_c, normalVec_c);
26624 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[8], pyraCentroid[8]);
26625 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
26626 for(MInt dim = 0; dim < 3; dim++) {
26627 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26628 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26629 }
26630 // 2nd cut surface
26631 computePoly6(p_1s, p_1ss, p_3s, p_3ss, p_2s, p_2ss, &area_c, coordinates_c, normalVec_c);
26632 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[9], pyraCentroid[9]);
26633 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
26634 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
26635 for(MInt dim = 0; dim < 3; dim++) {
26636 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
26637 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
26638 }
26639
26640 for(MInt i = 0; i < 10; i++) {
26641 volume_C += pyraVolume[i];
26642 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
26643 }
26644 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
26645
26646 m_bndryCells->a[bndryId].m_volume = volume_C;
26647 for(MInt dim = 0; dim < 3; dim++) {
26648 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
26649 }
26650
26651 faceCut[face1] = true;
26652 faceCut[face2] = true;
26653 faceCut[face3] = true;
26654 faceCut[face4] = true;
26655 faceCut[face5] = true;
26656 faceCut[face6] = true;
26657
26658 } else {
26659 // case 7.3 - 3 surfaces
26660 m_bndryCells->a[bndryId].m_noSrfcs = 3;
26661
26662 // case 7.3 - 1 surface (computed as 2 connected surfaces)
26663 computeTri(p_3, p_3sss, p_3ss, &faceVolume[face1], faceCentroid[face1], normal[face1]);
26664 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
26665 faceVolume_0[face1] = faceVolume[face1];
26666 computeTri(p_2, p_2s, p_2sss, &faceVolume[face1], faceCentroid[face1], normal[face1]);
26667 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
26668
26669 computeTri(p_4, p_1ss, p_3s, &splitFaceVolume[0], splitFaceCentroid[0], splitFaceNormal[0]);
26670 computeTri(p_0, p_3sss, p_1sss, &splitFaceVolume[1], splitFaceCentroid[1], splitFaceNormal[1]);
26671 splitCorner1 = cornersMCtoSOLVER[disambPointer[currentSubCase][4]];
26672 splitCorner2 = cornersMCtoSOLVER[disambPointer[currentSubCase][0]];
26673
26674 computeTri(p_5, p_2ss, p_1s, &splitFaceVolume2[0], splitFaceCentroid2[0], splitFaceNormal2[0]);
26675 computeTri(p_0, p_1sss, p_2sss, &splitFaceVolume2[1], splitFaceCentroid2[1], splitFaceNormal2[1]);
26676 splitCorner12 = cornersMCtoSOLVER[disambPointer[currentSubCase][5]];
26677 splitCorner22 = cornersMCtoSOLVER[disambPointer[currentSubCase][0]];
26678
26679 computeTri(p_1, p_1ss, p_1s, &faceVolume[face4], faceCentroid[face4], normal[face4]);
26680 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
26681 computeTri(p_2, p_2ss, p_2s, &faceVolume[face5], faceCentroid[face5], normal[face5]);
26682 correctFace(&faceVolume[face5], faceCentroid[face5], &faceVolume_0[face5], faceCentroid_0[face5]);
26683 computeTri(p_3, p_3ss, p_3s, &faceVolume[face6], faceCentroid[face6], normal[face6]);
26684 correctFace(&faceVolume[face6], faceCentroid[face6], &faceVolume_0[face6], faceCentroid_0[face6]);
26685
26686 splitFaceId = face2;
26687 splitFaceId2 = face3;
26688 maia::math::vecAvg<3>(M, p_1s, p_1ss, p_1sss, p_2s, p_2ss, p_2sss, p_3s, p_3ss, p_3sss);
26689
26690 faceVolume[face2] = F0;
26691 faceVolume[face3] = F0;
26692
26693 for(MInt i = 0; i < 6; i++) {
26694 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]],
26695 M, &pyraVolume[i], pyraCentroid[i]);
26696 }
26697 computePyra(&splitFaceVolume[0], splitFaceCentroid[0], splitFaceNormal[0], M, &pyraVolume[6],
26698 pyraCentroid[6]);
26699 computePyra(&splitFaceVolume[1], splitFaceCentroid[1], splitFaceNormal[1], M, &pyraVolume[7],
26700 pyraCentroid[7]);
26701 computePyra(&splitFaceVolume2[0], splitFaceCentroid2[0], splitFaceNormal2[0], M, &pyraVolume[8],
26702 pyraCentroid[8]);
26703 computePyra(&splitFaceVolume2[1], splitFaceCentroid2[1], splitFaceNormal2[1], M, &pyraVolume[9],
26704 pyraCentroid[9]);
26705 // 1st cut surface
26706 computePoly5(p_1ss, p_1sss, p_3sss, p_3ss, p_3s, &area_c, coordinates_c, normalVec_c);
26707 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[10], pyraCentroid[10]);
26708 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
26709 for(MInt dim = 0; dim < 3; dim++) {
26710 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26711 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26712 }
26713 // 2nd cut surface
26714 computePoly5(p_1sss, p_1s, p_2ss, p_2s, p_2sss, &area_c, coordinates_c, normalVec_c);
26715 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[11], pyraCentroid[11]);
26716 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
26717 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
26718 for(MInt dim = 0; dim < 3; dim++) {
26719 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
26720 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
26721 }
26722 // 3rd cut surface
26723 computePoly3(p_1s, p_1sss, p_1ss, &area_c, coordinates_c, normalVec_c);
26724 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[12], pyraCentroid[12]);
26725 m_bndryCells->a[bndryId].m_srfcs[2]->m_area = area_c;
26726 m_bndryCells->a[bndryId].m_srfcs[2]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
26727 for(MInt dim = 0; dim < 3; dim++) {
26728 m_bndryCells->a[bndryId].m_srfcs[2]->m_coordinates[dim] = coordinates_c[dim];
26729 m_bndryCells->a[bndryId].m_srfcs[2]->m_normalVector[dim] = normalVec_c[dim];
26730 }
26731
26732 for(MInt i = 0; i < 13; i++) {
26733 volume_C += pyraVolume[i];
26734 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
26735 }
26736 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
26737
26738 m_bndryCells->a[bndryId].m_volume = volume_C;
26739 for(MInt dim = 0; dim < 3; dim++) {
26740 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
26741 }
26742
26743 faceCut[face1] = true;
26744 faceCut[face2] = true;
26745 faceCut[face3] = true;
26746 faceCut[face4] = true;
26747 faceCut[face5] = true;
26748 faceCut[face6] = true;
26749 }
26750 break;
26751 }
26752 case 3:
26753 case 5:
26754 case 6: {
26755 // compute case 7.2
26756
26757 if(disamb_tmp == 3) disambPointer_dummy = &tiling7_2_3STL[0][0];
26758 if(disamb_tmp == 5) disambPointer_dummy = &tiling7_2_5STL[0][0];
26759 if(disamb_tmp == 6) disambPointer_dummy = &tiling7_2_6STL[0][0];
26760
26761 for(MInt i = 0; i < 16; i++)
26762 for(MInt j = 0; j < 2; j++)
26763 disambPointer[i][j] = disambPointer_dummy[i * 2 + j];
26764
26765 for(MInt i = 0; i < 6; i++) {
26766 faceVolume_0[i] = faceVolume[i];
26767 for(MInt j = 0; j < 3; j++) {
26768 faceCentroid_0[i][j] = faceCentroid[i][j];
26769 }
26770 }
26771 cellVolume_0 = gridCellVolume;
26772 for(MInt i = 0; i < 3; i++) {
26773 cellCentroid_0[i] = m_solver->a_coordinate(cellId, i);
26774 }
26775
26776 if(currentSubCase < 8) {
26777 // split cell: add another boundary cell and a new cell:
26778 cellId2 = createSplitCell_MGC(cellId, 1);
26779 bndryId2 = m_solver->a_bndryId(cellId2);
26780 m_splitParents[bndryId2] = bndryId;
26781 m_splitChildren[bndryId * 3 + 0] = bndryId2;
26782 if(bndryId == 0)
26783 cerr << " problem in FvBndryCnd3D::createCutFaceMGC, assuming cell 0 is no split cell failed! "
26784 << endl;
26785 m_bndryCells->a[bndryId].m_noSrfcs = 1;
26786 m_bndryCells->a[bndryId2].m_noSrfcs = 1;
26787 } else {
26788 m_bndryCells->a[bndryId].m_noSrfcs = 2;
26789 }
26790
26791 for(MInt face = 0; face < 6; face++) {
26792 nfs_cur[face] = nfs7_1[currentSubCase][face];
26793 }
26794
26795 // 1st Pyramid + 1st cutFace
26796 subCaseDummy = disambPointer[currentSubCase][0];
26797 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
26798 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
26799 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26800 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
26801 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26802 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
26803 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26804 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
26805 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
26806 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
26807
26808 faceCut[face1] = true;
26809 faceCut[face2] = true;
26810 faceCut[face3] = true;
26811
26812 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
26813 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
26814 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
26815
26816 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
26817
26818 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
26819
26820 if(currentSubCase >= 8) {
26821 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
26822 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
26823 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
26824
26825 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
26826
26827 correctNormal(normalVec_c);
26828 } else {
26829 for(MInt face = 0; face < 6; face++) {
26830 nfs_cur[face] = nfs1[subCaseDummy][face];
26831 }
26832 }
26833
26834 // create 1st Cut face and 1st cell
26835 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
26836 for(MInt dim = 0; dim < 3; dim++) {
26837 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26838 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26839 }
26840 m_bndryCells->a[bndryId].m_volume = volume_C;
26841 for(MInt dim = 0; dim < 3; dim++) {
26842 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
26843 }
26844
26845 if(currentSubCase >= 8) {
26846 faceVolume_0[face1] = faceVolume[face1];
26847 faceVolume_0[face2] = faceVolume[face2];
26848 faceVolume_0[face3] = faceVolume[face3];
26849 cellVolume_0 = volume_C;
26850 volume_C = 0;
26851 for(MInt i = 0; i < 3; i++) {
26852 cellCentroid_0[i] = coordinates_Cell[i];
26853 faceCentroid_0[face1][i] = faceCentroid[face1][i];
26854 faceCentroid_0[face2][i] = faceCentroid[face2][i];
26855 faceCentroid_0[face3][i] = faceCentroid[face3][i];
26856 coordinates_Cell[i] = 0;
26857 }
26858 } else {
26859 volume_C = 0;
26860 for(MInt i = 0; i < 3; i++) {
26861 coordinates_Cell[i] = 0;
26862 }
26863 }
26864
26865 // create 2nd part of cell
26866 subCaseDummy = disambPointer[currentSubCase][1];
26867
26868 // 3.2 case
26869 noFaces = 5;
26870
26871 p_0 = corner[cornersMCtoSOLVER[tiling3_2STL[subCaseDummy][0]]];
26872 p_0s = corner[cornersMCtoSOLVER[tiling3_2STL[subCaseDummy][1]]];
26873
26874 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][2]];
26875 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26876 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][3]];
26877 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26878 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][4]];
26879 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26880 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][5]];
26881 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26882 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][6]];
26883 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26884 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][7]];
26885 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
26886 face1 = facesMCtoSOLVER[tiling3_2STL[subCaseDummy][8]];
26887 face2 = facesMCtoSOLVER[tiling3_2STL[subCaseDummy][9]];
26888 face3 = facesMCtoSOLVER[tiling3_2STL[subCaseDummy][10]];
26889 face4 = facesMCtoSOLVER[tiling3_2STL[subCaseDummy][11]];
26890 face5 = facesMCtoSOLVER[tiling3_2STL[subCaseDummy][12]];
26891
26892 if(currentSubCase < 8) {
26893 for(MInt face = 0; face < 6; face++) {
26894 nfs_cur_0[face] = nfs3_2[subCaseDummy][face];
26895 }
26896 faceCut_0[face1] = true;
26897 faceCut_0[face2] = true;
26898 faceCut_0[face3] = true;
26899 faceCut_0[face4] = true;
26900 faceCut_0[face5] = true;
26901
26902 computeTri(p_0, p_1, p_2, &faceVolume_0[face1], faceCentroid_0[face1], normal[face1]);
26903 computeTri(p_0, p_2, p_3, &faceVolume_0[face2], faceCentroid_0[face2], normal[face2]);
26904 computeTri(p_0s, p_2s, p_3s, &faceVolume_0[face3], faceCentroid_0[face3], normal[face3]);
26905 computeTri(p_0s, p_1s, p_2s, &faceVolume_0[face4], faceCentroid_0[face4], normal[face4]);
26906 computePoly6(p_0, p_1, p_3s, p_0s, p_1s, p_3, &faceVolume_0[face5], faceCentroid_0[face5],
26907 normal[face5]);
26908
26909 computePoly6(p_1, p_2, p_3, p_1s, p_2s, p_3s, &area_c, coordinates_c, normalVec_c);
26910
26911 maia::math::vecAvg<3>(M, p_0, p_0s, p_1, p_1s, p_2, p_2s, p_3, p_3s);
26912
26913 for(MInt i = 0; i < 5; i++) {
26914 computePyra(&faceVolume_0[*facepointers[i]], faceCentroid_0[*facepointers[i]],
26915 normal[*facepointers[i]], M, &pyraVolume[i], pyraCentroid[i]);
26916 }
26917 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
26918
26919 for(MInt i = 0; i < 6; i++) {
26920 volume_C += pyraVolume[i];
26921 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
26922 }
26923 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
26924
26925 absA = F0;
26926 for(MInt i = 0; i < nDim; i++) {
26927 if(!nfs_cur_0[2 * i + 1]) faceVolume_0[2 * i + 1] = 0;
26928 if(!nfs_cur_0[2 * i]) faceVolume_0[2 * i] = 0;
26929 faceDiff[i] = faceVolume_0[2 * i + 1] - faceVolume_0[2 * i];
26930 absA += POW2(faceDiff[i]);
26931 }
26932
26933 for(MInt i = 0; i < nDim; i++) {
26934 normalVec_c[i] = faceDiff[i] / sqrt(absA);
26935 }
26936 area_c = sqrt(absA);
26937
26938 // create 2nd Cut face & cell
26939 // create 1 Cut face
26940 m_bndryCells->a[bndryId2].m_srfcs[0]->m_area = area_c;
26941 for(MInt dim = 0; dim < 3; dim++) {
26942 m_bndryCells->a[bndryId2].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
26943 m_bndryCells->a[bndryId2].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
26944 }
26945
26946 m_bndryCells->a[bndryId2].m_volume = volume_C;
26947 for(MInt dim = 0; dim < 3; dim++) {
26948 m_bndryCells->a[bndryId2].m_coordinates[dim] = coordinates_Cell[dim];
26949 }
26950
26951 // fill ambiguous corners array
26952 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling3_2STL[subCaseDummy][0]]] = cellId2;
26953 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling3_2STL[subCaseDummy][1]]] = cellId2;
26954 } else {
26955 faceCut[face1] = true;
26956 faceCut[face2] = true;
26957 faceCut[face3] = true;
26958 faceCut[face4] = true;
26959 faceCut[face5] = true;
26960
26961 computeTri(p_0, p_1, p_2, &faceVolume[face1], faceCentroid[face1], normal[face1]);
26962 computeTri(p_0, p_2, p_3, &faceVolume[face2], faceCentroid[face2], normal[face2]);
26963 computeTri(p_0s, p_2s, p_3s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
26964 computeTri(p_0s, p_1s, p_2s, &faceVolume[face4], faceCentroid[face4], normal[face4]);
26965 computePoly6(p_0, p_1, p_3s, p_0s, p_1s, p_3, &faceVolume[face5], faceCentroid[face5], normal[face5]);
26966
26967 computePoly6(p_1, p_2, p_3, p_1s, p_2s, p_3s, &area_c, coordinates_c, normalVec_c);
26968
26969 maia::math::vecAvg<3>(M, p_0, p_0s, p_1, p_1s, p_2, p_2s, p_3, p_3s);
26970
26971 for(MInt i = 0; i < 5; i++) {
26972 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]],
26973 M, &pyraVolume[i], pyraCentroid[i]);
26974 }
26975 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
26976
26977 for(MInt i = 0; i < 6; i++) {
26978 volume_C += pyraVolume[i];
26979 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
26980 }
26981 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
26982
26983 // correct cell
26984 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
26985 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
26986 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
26987 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
26988 p_1ss = corner[cornersMCtoSOLVER[tiling3_2STL[subCaseDummy][13]]];
26989 p_2ss = corner[cornersMCtoSOLVER[tiling3_2STL[subCaseDummy][14]]];
26990 splitCorner1 = cornersMCtoSOLVER[tiling3_2STL[subCaseDummy][13]];
26991 splitCorner2 = cornersMCtoSOLVER[tiling3_2STL[subCaseDummy][14]];
26992 computeTri(p_1s, p_1ss, p_3, &splitFaceVolume[0], splitFaceCentroid[0], splitFaceNormal[0]);
26993 computeTri(p_1, p_2ss, p_3s, &splitFaceVolume[1], splitFaceCentroid[1], splitFaceNormal[1]);
26994 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
26995
26996 correctNormal(normalVec_c);
26997 splitFaceId = face5;
26998
26999 // create 2nd Cut face
27000 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
27001 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
27002 for(MInt dim = 0; dim < 3; dim++) {
27003 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
27004 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
27005 }
27006
27007 m_bndryCells->a[bndryId].m_volume = volume_C;
27008 for(MInt dim = 0; dim < 3; dim++) {
27009 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
27010 }
27011 }
27012 break;
27013 }
27014 case 7: {
27015 if(currentSubCase < 8) {
27016 // split cell2: add 2 other boundary cells and 2 new cells:
27017 cellId2 = createSplitCell_MGC(cellId, 1);
27018 bndryId2 = m_solver->a_bndryId(cellId2);
27019 cellId3 = createSplitCell_MGC(cellId, 2);
27020 bndryId3 = m_solver->a_bndryId(cellId3);
27021 m_splitParents[bndryId2] = bndryId;
27022 m_splitParents[bndryId3] = bndryId;
27023 m_splitChildren[bndryId * 3 + 0] = bndryId2;
27024 m_splitChildren[bndryId * 3 + 1] = bndryId3;
27025 if(bndryId == 0)
27026 cerr << " problem in FvBndryCnd3D::createCutFaceMGC, assuming cell 0 is no split cell failed! "
27027 << endl;
27028 m_bndryCells->a[bndryId].m_noSrfcs = 1;
27029 m_bndryCells->a[bndryId2].m_noSrfcs = 1;
27030 m_bndryCells->a[bndryId3].m_noSrfcs = 1;
27031 } else {
27032 m_bndryCells->a[bndryId].m_noSrfcs = 3;
27033 }
27034
27035 for(MInt face = 0; face < 6; face++) {
27036 nfs_cur[face] = nfs7_1[currentSubCase][face];
27037 }
27038
27039 // 1st Pyramid + 1st cutFace
27040 subCaseDummy = tiling7_1STL[currentSubCase][0];
27041 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
27042 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
27043 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27044 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
27045 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27046 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
27047 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27048 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
27049 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
27050 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
27051
27052 faceCut[face1] = true;
27053 faceCut[face2] = true;
27054 faceCut[face3] = true;
27055
27056 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
27057 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
27058 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
27059
27060 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
27061
27062 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
27063
27064 if(currentSubCase >= 8) {
27065 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
27066 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
27067 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
27068
27069 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
27070
27071 correctNormal(normalVec_c);
27072 } else {
27073 for(MInt face = 0; face < 6; face++) {
27074 nfs_cur[face] = nfs1[subCaseDummy][face];
27075 }
27076 }
27077
27078 // create 1st Cut face and 1st cell
27079 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
27080 for(MInt dim = 0; dim < 3; dim++) {
27081 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27082 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27083 }
27084 m_bndryCells->a[bndryId].m_volume = volume_C;
27085 for(MInt dim = 0; dim < 3; dim++) {
27086 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
27087 }
27088
27089 if(currentSubCase >= 8) {
27090 faceVolume_0[face1] = faceVolume[face1];
27091 faceVolume_0[face2] = faceVolume[face2];
27092 faceVolume_0[face3] = faceVolume[face3];
27093 cellVolume_0 = volume_C;
27094 for(MInt i = 0; i < 3; i++) {
27095 cellCentroid_0[i] = coordinates_Cell[i];
27096 faceCentroid_0[face1][i] = faceCentroid[face1][i];
27097 faceCentroid_0[face2][i] = faceCentroid[face2][i];
27098 faceCentroid_0[face3][i] = faceCentroid[face3][i];
27099 }
27100 }
27101
27102 // 2nd Pyramid + 2nd cutFace
27103 subCaseDummy = tiling7_1STL[currentSubCase][1];
27104 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
27105 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
27106 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27107 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
27108 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27109 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
27110 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27111 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
27112 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
27113 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
27114
27115 if(currentSubCase < 8) {
27116 for(MInt face = 0; face < 6; face++) {
27117 nfs_cur_0[face] = nfs1[subCaseDummy][face];
27118 }
27119
27120 faceCut_0[face1] = true;
27121 faceCut_0[face2] = true;
27122 faceCut_0[face3] = true;
27123
27124 computeTri(p_0, p_1, p_3, &faceVolume_0[face1], faceCentroid_0[face1]);
27125 computeTri(p_0, p_3, p_2, &faceVolume_0[face2], faceCentroid_0[face2]);
27126 computeTri(p_0, p_2, p_1, &faceVolume_0[face3], faceCentroid_0[face3]);
27127
27128 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
27129
27130 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
27131
27132 // create 2nd Cut face & cell
27133 m_bndryCells->a[bndryId2].m_srfcs[0]->m_area = area_c;
27134 for(MInt dim = 0; dim < 3; dim++) {
27135 m_bndryCells->a[bndryId2].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27136 m_bndryCells->a[bndryId2].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27137 }
27138
27139 m_bndryCells->a[bndryId2].m_volume = volume_C;
27140 for(MInt dim = 0; dim < 3; dim++) {
27141 m_bndryCells->a[bndryId2].m_coordinates[dim] = coordinates_Cell[dim];
27142 }
27143 // fill ambiguous corners array
27144 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]] = cellId2;
27145 } else {
27146 faceCut[face1] = true;
27147 faceCut[face2] = true;
27148 faceCut[face3] = true;
27149
27150 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
27151 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
27152 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
27153
27154 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
27155
27156 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
27157
27158 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
27159 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
27160 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
27161
27162 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
27163
27164 correctNormal(normalVec_c);
27165
27166 // create 2nd Cut face
27167 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
27168 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
27169 for(MInt dim = 0; dim < 3; dim++) {
27170 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
27171 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
27172 }
27173
27174 m_bndryCells->a[bndryId].m_volume = volume_C;
27175 for(MInt dim = 0; dim < 3; dim++) {
27176 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
27177 }
27178 }
27179
27180 if(currentSubCase >= 8) {
27181 faceVolume_0[face1] = faceVolume[face1];
27182 faceVolume_0[face2] = faceVolume[face2];
27183 faceVolume_0[face3] = faceVolume[face3];
27184 cellVolume_0 = volume_C;
27185 for(MInt i = 0; i < 3; i++) {
27186 cellCentroid_0[i] = coordinates_Cell[i];
27187 faceCentroid_0[face1][i] = faceCentroid[face1][i];
27188 faceCentroid_0[face2][i] = faceCentroid[face2][i];
27189 faceCentroid_0[face3][i] = faceCentroid[face3][i];
27190 }
27191 }
27192
27193 // 3rd Pyramid + 3rd cutFace
27194 subCaseDummy = tiling7_1STL[currentSubCase][2];
27195 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
27196 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
27197 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27198 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
27199 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27200 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
27201 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27202 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
27203 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
27204 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
27205
27206 if(currentSubCase < 8) {
27207 for(MInt face = 0; face < 6; face++) {
27208 nfs_cur_00[face] = nfs1[subCaseDummy][face];
27209 }
27210
27211 faceCut_00[face1] = true;
27212 faceCut_00[face2] = true;
27213 faceCut_00[face3] = true;
27214
27215 computeTri(p_0, p_1, p_3, &faceVolume_00[face1], faceCentroid_00[face1]);
27216 computeTri(p_0, p_3, p_2, &faceVolume_00[face2], faceCentroid_00[face2]);
27217 computeTri(p_0, p_2, p_1, &faceVolume_00[face3], faceCentroid_00[face3]);
27218
27219 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
27220
27221 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
27222
27223 // create 3rd Cut face & cell
27224 m_bndryCells->a[bndryId3].m_srfcs[0]->m_area = area_c;
27225 for(MInt dim = 0; dim < 3; dim++) {
27226 m_bndryCells->a[bndryId3].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27227 m_bndryCells->a[bndryId3].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27228 }
27229
27230 m_bndryCells->a[bndryId3].m_volume = volume_C;
27231 for(MInt dim = 0; dim < 3; dim++) {
27232 m_bndryCells->a[bndryId3].m_coordinates[dim] = coordinates_Cell[dim];
27233 }
27234
27235 // fill ambiguous corners array
27236 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]] = cellId3;
27237
27238 } else {
27239 faceCut[face1] = true;
27240 faceCut[face2] = true;
27241 faceCut[face3] = true;
27242
27243 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
27244 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
27245 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
27246
27247 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
27248
27249 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
27250
27251 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
27252 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
27253 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
27254
27255 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
27256
27257 correctNormal(normalVec_c);
27258
27259 // create 2nd Cut face
27260 m_bndryCells->a[bndryId].m_srfcs[2]->m_area = area_c;
27261 m_bndryCells->a[bndryId].m_srfcs[2]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
27262 for(MInt dim = 0; dim < 3; dim++) {
27263 m_bndryCells->a[bndryId].m_srfcs[2]->m_coordinates[dim] = coordinates_c[dim];
27264 m_bndryCells->a[bndryId].m_srfcs[2]->m_normalVector[dim] = normalVec_c[dim];
27265 }
27266
27267 m_bndryCells->a[bndryId].m_volume = volume_C;
27268 for(MInt dim = 0; dim < 3; dim++) {
27269 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
27270 }
27271 }
27272 break;
27273 }
27274 default: {
27275 stringstream errorMessage;
27276 errorMessage << "ERROR: Switch variable 'disamb_tmp' with value " << disamb_tmp
27277 << " not matching any case." << endl;
27278 mTerm(1, AT_, errorMessage.str());
27279 }
27280 }
27281 break;
27282 }
27283 case 10: {
27284 for(MInt i = 0; i < 6; i++) {
27285 faceVolume_0[i] = faceVolume[i];
27286 for(MInt j = 0; j < 3; j++) {
27287 faceCentroid_0[i][j] = faceCentroid[i][j];
27288 }
27289 }
27290 cellVolume_0 = gridCellVolume;
27291 for(MInt i = 0; i < 3; i++) {
27292 cellCentroid_0[i] = m_solver->a_coordinate(cellId, i);
27293 }
27294
27295 if(disambiguation[bndryId] == 3) { // case 10.2, split cell
27296
27297 cellId2 = createSplitCell_MGC(cellId, 1);
27298 bndryId2 = m_solver->a_bndryId(cellId2);
27299 m_splitParents[bndryId2] = bndryId;
27300 m_splitChildren[bndryId * 3 + 0] = bndryId2;
27301 if(bndryId == 0)
27302 cerr << " problem in FvBndryCnd3D::createCutFaceMGC, assuming cell 0 is no split cell failed! " << endl;
27303 m_bndryCells->a[bndryId].m_noSrfcs = 1;
27304 m_bndryCells->a[bndryId2].m_noSrfcs = 1;
27305
27306 // 1st prism & 1st cutFace
27307 subCaseDummy = tiling10_2STL[currentSubCase][0];
27308 for(MInt face = 0; face < 6; face++) {
27309 nfs_cur[face] = nfs2[subCaseDummy][face];
27310 }
27311 p_0 = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][0]]];
27312 p_0s = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][1]]];
27313 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
27314 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27315 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
27316 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27317 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
27318 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27319 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
27320 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27321 face1 = facesMCtoSOLVER[tiling2STL[subCaseDummy][6]];
27322 face2 = facesMCtoSOLVER[tiling2STL[subCaseDummy][7]];
27323 face3 = facesMCtoSOLVER[tiling2STL[subCaseDummy][8]];
27324 face4 = facesMCtoSOLVER[tiling2STL[subCaseDummy][9]];
27325
27326 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2], normal[face2]);
27327 computeTri(p_0s, p_3s, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
27328 computeTrapez(p_0, p_0s, p_3s, p_3, &faceVolume[face1], faceCentroid[face1], normal[face1]);
27329 computeTrapez(p_2, p_2s, p_0s, p_0, &faceVolume[face4], faceCentroid[face4], normal[face4]);
27330
27331 computePoly4(p_3, p_3s, p_2s, p_2, &area_c, coordinates_c, normalVec_c);
27332
27333 maia::math::vecAvg<3>(M, p_0, p_0s, p_2, p_2s, p_3, p_3s);
27334
27335 for(MInt i = 0; i < 4; i++) {
27336 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
27337 &pyraVolume[i], pyraCentroid[i]);
27338 }
27339 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[4], pyraCentroid[4]);
27340 for(MInt i = 0; i < 5; i++) {
27341 volume_C += pyraVolume[i];
27342 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
27343 }
27344 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
27345
27346 faceCut[face1] = true;
27347 faceCut[face2] = true;
27348 faceCut[face3] = true;
27349 faceCut[face4] = true;
27350
27351 // create 1st Cut face and 1st cell
27352 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
27353 for(MInt dim = 0; dim < 3; dim++) {
27354 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27355 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27356 }
27357
27358 m_bndryCells->a[bndryId].m_volume = volume_C;
27359 volume_C = 0;
27360 for(MInt dim = 0; dim < 3; dim++) {
27361 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
27362 coordinates_Cell[dim] = F0;
27363 }
27364
27365 // 2nd Prism + 2nd cutFace = 2nd cell
27366 subCaseDummy = tiling10_2STL[currentSubCase][1];
27367 for(MInt face = 0; face < 6; face++) {
27368 nfs_cur_0[face] = nfs2[subCaseDummy][face];
27369 }
27370 p_0 = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][0]]];
27371 p_0s = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][1]]];
27372 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
27373 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27374 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
27375 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27376 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
27377 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27378 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
27379 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27380 face1 = facesMCtoSOLVER[tiling2STL[subCaseDummy][6]];
27381 face2 = facesMCtoSOLVER[tiling2STL[subCaseDummy][7]];
27382 face3 = facesMCtoSOLVER[tiling2STL[subCaseDummy][8]];
27383 face4 = facesMCtoSOLVER[tiling2STL[subCaseDummy][9]];
27384
27385 computeTri(p_0, p_3, p_2, &faceVolume_0[face2], faceCentroid_0[face2], normal[face2]);
27386 computeTri(p_0s, p_3s, p_2s, &faceVolume_0[face3], faceCentroid_0[face3], normal[face3]);
27387 computeTrapez(p_0, p_0s, p_3s, p_3, &faceVolume_0[face1], faceCentroid_0[face1], normal[face1]);
27388 computeTrapez(p_2, p_2s, p_0s, p_0, &faceVolume_0[face4], faceCentroid_0[face4], normal[face4]);
27389
27390 computePoly4(p_3, p_3s, p_2s, p_2, &area_c, coordinates_c, normalVec_c);
27391
27392 maia::math::vecAvg<3>(M, p_0, p_0s, p_2, p_2s, p_3, p_3s);
27393
27394 for(MInt i = 0; i < 4; i++) {
27395 computePyra(&faceVolume_0[*facepointers[i]], faceCentroid_0[*facepointers[i]], normal[*facepointers[i]],
27396 M, &pyraVolume[i], pyraCentroid[i]);
27397 }
27398 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[4], pyraCentroid[4]);
27399 for(MInt i = 0; i < 5; i++) {
27400 volume_C += pyraVolume[i];
27401 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
27402 }
27403 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
27404
27405 faceCut_0[face1] = true;
27406 faceCut_0[face2] = true;
27407 faceCut_0[face3] = true;
27408 faceCut_0[face4] = true;
27409
27410 // create 2nd Cut face
27411 m_bndryCells->a[bndryId2].m_srfcs[0]->m_area = area_c;
27412 for(MInt dim = 0; dim < 3; dim++) {
27413 m_bndryCells->a[bndryId2].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27414 m_bndryCells->a[bndryId2].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27415 }
27416
27417 m_bndryCells->a[bndryId2].m_volume = volume_C;
27418 for(MInt dim = 0; dim < 3; dim++) {
27419 m_bndryCells->a[bndryId2].m_coordinates[dim] = coordinates_Cell[dim];
27420 }
27421
27422 // fill ambiguous corner array
27423 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling2STL[subCaseDummy][0]]] = cellId2;
27424 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling2STL[subCaseDummy][1]]] = cellId2;
27425
27426 } else if(disambiguation[bndryId] == 0) {
27427 // case 10_1 - 2 surfaces, connected cell
27428
27429 m_bndryCells->a[bndryId].m_noSrfcs = 2;
27430 for(MInt face = 0; face < 6; face++) {
27431 nfs_cur[face] = nfs10[currentSubCase][face];
27432 }
27433
27434 // 1st prism & 1st cutFace
27435 subCaseDummy = tiling10_1STL[currentSubCase][0];
27436 p_0 = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][0]]];
27437 p_0s = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][1]]];
27438 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
27439 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27440 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
27441 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27442 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
27443 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27444 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
27445 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27446 face1 = facesMCtoSOLVER[tiling2STL[subCaseDummy][6]];
27447 face2 = facesMCtoSOLVER[tiling2STL[subCaseDummy][7]];
27448 face3 = facesMCtoSOLVER[tiling2STL[subCaseDummy][8]];
27449 face4 = facesMCtoSOLVER[tiling2STL[subCaseDummy][9]];
27450
27451 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2], normal[face2]);
27452 computeTri(p_0s, p_3s, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
27453 computeTrapez(p_0, p_0s, p_3s, p_3, &faceVolume[face1], faceCentroid[face1], normal[face1]);
27454 computeTrapez(p_2, p_2s, p_0s, p_0, &faceVolume[face4], faceCentroid[face4], normal[face4]);
27455
27456 computePoly4(p_3, p_3s, p_2s, p_2, &area_c, coordinates_c, normalVec_c);
27457
27458 maia::math::vecAvg<3>(M, p_0, p_0s, p_2, p_2s, p_3, p_3s);
27459
27460 for(MInt i = 0; i < 4; i++) {
27461 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
27462 &pyraVolume[i], pyraCentroid[i]);
27463 }
27464 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[4], pyraCentroid[4]);
27465 for(MInt i = 0; i < 5; i++) {
27466 volume_C += pyraVolume[i];
27467 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
27468 }
27469 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
27470
27471 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
27472 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
27473 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
27474 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
27475
27476 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
27477
27478 correctNormal(normalVec_c);
27479
27480 faceCut[face1] = true;
27481 faceCut[face2] = true;
27482 faceCut[face3] = true;
27483 faceCut[face4] = true;
27484
27485 // create 1st Cut face
27486 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
27487 for(MInt dim = 0; dim < 3; dim++) {
27488 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27489 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27490 }
27491
27492 faceVolume_0[face1] = faceVolume[face1];
27493 faceVolume_0[face2] = faceVolume[face2];
27494 faceVolume_0[face3] = faceVolume[face3];
27495 faceVolume_0[face4] = faceVolume[face4];
27496 cellVolume_0 = volume_C;
27497 volume_C = 0;
27498 for(MInt i = 0; i < 3; i++) {
27499 cellCentroid_0[i] = coordinates_Cell[i];
27500 faceCentroid_0[face1][i] = faceCentroid[face1][i];
27501 faceCentroid_0[face2][i] = faceCentroid[face2][i];
27502 faceCentroid_0[face3][i] = faceCentroid[face3][i];
27503 faceCentroid_0[face4][i] = faceCentroid[face4][i];
27504 coordinates_Cell[i] = 0;
27505 }
27506
27507 // 2nd Prism + 2nd cutFace
27508 subCaseDummy = tiling10_1STL[currentSubCase][1];
27509 p_0 = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][0]]];
27510 p_0s = corner[cornersMCtoSOLVER[tiling2STL[subCaseDummy][1]]];
27511 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
27512 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27513 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
27514 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27515 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
27516 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27517 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
27518 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27519 face1 = facesMCtoSOLVER[tiling2STL[subCaseDummy][6]];
27520 face2 = facesMCtoSOLVER[tiling2STL[subCaseDummy][7]];
27521 face3 = facesMCtoSOLVER[tiling2STL[subCaseDummy][8]];
27522 face4 = facesMCtoSOLVER[tiling2STL[subCaseDummy][9]];
27523
27524 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2], normal[face2]);
27525 computeTri(p_0s, p_3s, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
27526 computeTrapez(p_0, p_0s, p_3s, p_3, &faceVolume[face1], faceCentroid[face1], normal[face1]);
27527 computeTrapez(p_2, p_2s, p_0s, p_0, &faceVolume[face4], faceCentroid[face4], normal[face4]);
27528
27529 computePoly4(p_3, p_3s, p_2s, p_2, &area_c, coordinates_c, normalVec_c);
27530
27531 maia::math::vecAvg<3>(M, p_0, p_0s, p_2, p_2s, p_3, p_3s);
27532
27533 for(MInt i = 0; i < 4; i++) {
27534 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
27535 &pyraVolume[i], pyraCentroid[i]);
27536 }
27537 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[4], pyraCentroid[4]);
27538 for(MInt i = 0; i < 5; i++) {
27539 volume_C += pyraVolume[i];
27540 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
27541 }
27542 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
27543
27544 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
27545 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
27546 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
27547 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
27548
27549 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
27550
27551 correctNormal(normalVec_c);
27552
27553 faceCut[face1] = true;
27554 faceCut[face2] = true;
27555 faceCut[face3] = true;
27556 faceCut[face4] = true;
27557
27558 // create 2nd Cut face
27559 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
27560 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
27561 for(MInt dim = 0; dim < 3; dim++) {
27562 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
27563 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
27564 }
27565
27566 m_bndryCells->a[bndryId].m_volume = volume_C;
27567 for(MInt dim = 0; dim < 3; dim++) {
27568 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
27569 }
27570 }
27571 break;
27572 }
27573 case 12: {
27574 for(MInt i = 0; i < 6; i++) {
27575 faceVolume_0[i] = faceVolume[i];
27576 for(MInt j = 0; j < 3; j++) {
27577 faceCentroid_0[i][j] = faceCentroid[i][j];
27578 }
27579 }
27580 cellVolume_0 = gridCellVolume;
27581 for(MInt i = 0; i < 3; i++) {
27582 cellCentroid_0[i] = m_solver->a_coordinate(cellId, i);
27583 }
27584
27585 if(disambiguation[bndryId] == 3) { // case 12.1 disconnected, split cell
27586
27587 cellId2 = createSplitCell_MGC(cellId, 1);
27588 bndryId2 = m_solver->a_bndryId(cellId2);
27589 m_splitParents[bndryId2] = bndryId;
27590 m_splitChildren[bndryId * 3 + 0] = bndryId2;
27591 if(bndryId == 0)
27592 cerr << " problem in FvBndryCnd3D::createCutFaceMGC, assuming cell 0 is no split cell failed! " << endl;
27593 m_bndryCells->a[bndryId].m_noSrfcs = 1;
27594 m_bndryCells->a[bndryId2].m_noSrfcs = 1;
27595
27596 // 1st case 5 cell & 1st cutFace
27597 subCaseDummy = tiling12_1STL[23 - currentSubCase][0];
27598 for(MInt face = 0; face < 6; face++) {
27599 nfs_cur[face] = nfs5[subCaseDummy][face];
27600 }
27601 p_0 = corner[cornersMCtoSOLVER[tiling5STL[subCaseDummy][0]]];
27602 p_1 = corner[cornersMCtoSOLVER[tiling5STL[subCaseDummy][1]]];
27603 p_2 = corner[cornersMCtoSOLVER[tiling5STL[subCaseDummy][2]]];
27604 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][3]];
27605 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27606 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][4]];
27607 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27608 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][5]];
27609 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27610 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][6]];
27611 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27612 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][7]];
27613 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27614 face1 = facesMCtoSOLVER[tiling5STL[subCaseDummy][8]];
27615 face2 = facesMCtoSOLVER[tiling5STL[subCaseDummy][9]];
27616 face3 = facesMCtoSOLVER[tiling5STL[subCaseDummy][10]];
27617 face4 = facesMCtoSOLVER[tiling5STL[subCaseDummy][11]];
27618 face5 = facesMCtoSOLVER[tiling5STL[subCaseDummy][12]];
27619
27620 computePoly5(p_0, p_0ss, p_2ss, p_2, p_1, &faceVolume[face1], faceCentroid[face1], normal[face1]);
27621 computeTri(p_0ss, p_0, p_0s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
27622 computeTrapez(p_0, p_1, p_1s, p_0s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
27623 computeTrapez(p_1, p_1s, p_2s, p_2, &faceVolume[face4], faceCentroid[face4], normal[face4]);
27624 computeTri(p_2s, p_2, p_2ss, &faceVolume[face5], faceCentroid[face5], normal[face5]);
27625
27626 computePoly5(p_0s, p_1s, p_2s, p_2ss, p_0ss, &area_c, coordinates_c, normalVec_c);
27627
27628 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_0s, p_1s, p_2s, p_0ss, p_2ss);
27629
27630 for(MInt i = 0; i < 5; i++) {
27631 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
27632 &pyraVolume[i], pyraCentroid[i]);
27633 }
27634 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
27635 for(MInt i = 0; i < 6; i++) {
27636 volume_C += pyraVolume[i];
27637 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
27638 }
27639 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
27640
27641 faceCut[face1] = true;
27642 faceCut[face2] = true;
27643 faceCut[face3] = true;
27644 faceCut[face4] = true;
27645 faceCut[face5] = true;
27646
27647 // create 1st Cut face
27648 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
27649 for(MInt dim = 0; dim < 3; dim++) {
27650 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27651 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27652 }
27653
27654 m_bndryCells->a[bndryId].m_volume = volume_C;
27655 volume_C = 0;
27656 for(MInt dim = 0; dim < 3; dim++) {
27657 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
27658 coordinates_Cell[dim] = m_solver->a_coordinate(cellId, dim);
27659 }
27660
27661 // 2nd Pyramid + 2nd cutFace = 2nd cell
27662 subCaseDummy = tiling12_1STL[23 - currentSubCase][1];
27663 for(MInt face = 0; face < 6; face++) {
27664 nfs_cur_0[face] = nfs1[subCaseDummy][face];
27665 }
27666 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
27667 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
27668 p_1 = m_bndryCells->a[bndryId2].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27669 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
27670 p_2 = m_bndryCells->a[bndryId2].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27671 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
27672 p_3 = m_bndryCells->a[bndryId2].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27673 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
27674 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
27675 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
27676
27677 faceCut_0[face1] = true;
27678 faceCut_0[face2] = true;
27679 faceCut_0[face3] = true;
27680
27681 computeTri(p_0, p_1, p_3, &faceVolume_0[face1], faceCentroid_0[face1]);
27682 computeTri(p_0, p_3, p_2, &faceVolume_0[face2], faceCentroid_0[face2]);
27683 computeTri(p_0, p_2, p_1, &faceVolume_0[face3], faceCentroid_0[face3]);
27684
27685 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
27686
27687 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
27688
27689 m_bndryCells->a[bndryId2].m_volume = volume_C;
27690 for(MInt dim = 0; dim < 3; dim++) {
27691 m_bndryCells->a[bndryId2].m_coordinates[dim] = coordinates_Cell[dim];
27692 }
27693
27694 // create 2nd Cut face
27695 m_bndryCells->a[bndryId2].m_srfcs[0]->m_area = area_c;
27696 for(MInt dim = 0; dim < 3; dim++) {
27697 m_bndryCells->a[bndryId2].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27698 m_bndryCells->a[bndryId2].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27699 }
27700
27701 // fill ambiguous corner array
27702 cornerCellMapping[ambIds[bndryId] * 8 + cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]] = cellId2;
27703
27704 } else if(disambiguation[bndryId] == 0) {
27705 // case 12_1 - 2 surfaces, connected cell
27706
27707 m_bndryCells->a[bndryId].m_noSrfcs = 2;
27708 for(MInt face = 0; face < 6; face++) {
27709 nfs_cur[face] = nfs12_1[currentSubCase][face];
27710 }
27711
27712 // 1st case 5 cell & 1st cutFace
27713 subCaseDummy = tiling12_1STL[currentSubCase][0];
27714
27715 p_0 = corner[cornersMCtoSOLVER[tiling5STL[subCaseDummy][0]]];
27716 p_1 = corner[cornersMCtoSOLVER[tiling5STL[subCaseDummy][1]]];
27717 p_2 = corner[cornersMCtoSOLVER[tiling5STL[subCaseDummy][2]]];
27718 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][3]];
27719 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27720 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][4]];
27721 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27722 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][5]];
27723 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27724 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][6]];
27725 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27726 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][7]];
27727 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27728 face1 = facesMCtoSOLVER[tiling5STL[subCaseDummy][8]];
27729 face2 = facesMCtoSOLVER[tiling5STL[subCaseDummy][9]];
27730 face3 = facesMCtoSOLVER[tiling5STL[subCaseDummy][10]];
27731 face4 = facesMCtoSOLVER[tiling5STL[subCaseDummy][11]];
27732 face5 = facesMCtoSOLVER[tiling5STL[subCaseDummy][12]];
27733
27734 computePoly5(p_0, p_0ss, p_2ss, p_2, p_1, &faceVolume[face1], faceCentroid[face1], normal[face1]);
27735 computeTri(p_0ss, p_0, p_0s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
27736 computeTrapez(p_0, p_1, p_1s, p_0s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
27737 computeTrapez(p_1, p_1s, p_2s, p_2, &faceVolume[face4], faceCentroid[face4], normal[face4]);
27738 computeTri(p_2s, p_2, p_2ss, &faceVolume[face5], faceCentroid[face5], normal[face5]);
27739
27740 computePoly5(p_0s, p_1s, p_2s, p_2ss, p_0ss, &area_c, coordinates_c, normalVec_c);
27741
27742 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_0s, p_1s, p_2s, p_0ss, p_2ss);
27743
27744 for(MInt i = 0; i < 5; i++) {
27745 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
27746 &pyraVolume[i], pyraCentroid[i]);
27747 }
27748 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
27749 for(MInt i = 0; i < 6; i++) {
27750 volume_C += pyraVolume[i];
27751 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
27752 }
27753 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
27754
27755 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
27756 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
27757 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
27758 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
27759 correctFace(&faceVolume[face5], faceCentroid[face5], &faceVolume_0[face5], faceCentroid_0[face5]);
27760
27761 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
27762
27763 correctNormal(normalVec_c);
27764
27765 faceCut[face1] = true;
27766 faceCut[face2] = true;
27767 faceCut[face3] = true;
27768 faceCut[face4] = true;
27769 faceCut[face5] = true;
27770
27771 // create 1st Cut face
27772 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
27773 for(MInt dim = 0; dim < 3; dim++) {
27774 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
27775 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
27776 }
27777
27778 faceVolume_0[face1] = faceVolume[face1];
27779 faceVolume_0[face2] = faceVolume[face2];
27780 faceVolume_0[face3] = faceVolume[face3];
27781 faceVolume_0[face4] = faceVolume[face4];
27782 faceVolume_0[face5] = faceVolume[face5];
27783 cellVolume_0 = volume_C;
27784 volume_C = 0;
27785 for(MInt i = 0; i < 3; i++) {
27786 cellCentroid_0[i] = coordinates_Cell[i];
27787 faceCentroid_0[face1][i] = faceCentroid[face1][i];
27788 faceCentroid_0[face2][i] = faceCentroid[face2][i];
27789 faceCentroid_0[face3][i] = faceCentroid[face3][i];
27790 faceCentroid_0[face4][i] = faceCentroid[face4][i];
27791 faceCentroid_0[face5][i] = faceCentroid[face5][i];
27792 coordinates_Cell[i] = 0;
27793 }
27794
27795 // 2nd Pyramid + 2nd cutFace
27796 subCaseDummy = tiling12_1STL[currentSubCase][1];
27797 p_0 = corner[cornersMCtoSOLVER[tiling1STL[subCaseDummy][0]]];
27798 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
27799 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27800 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
27801 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27802 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
27803 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
27804 face1 = facesMCtoSOLVER[tiling1STL[subCaseDummy][4]];
27805 face2 = facesMCtoSOLVER[tiling1STL[subCaseDummy][5]];
27806 face3 = facesMCtoSOLVER[tiling1STL[subCaseDummy][6]];
27807
27808 faceCut[face1] = true;
27809 faceCut[face2] = true;
27810 faceCut[face3] = true;
27811
27812 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
27813 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
27814 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
27815
27816 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
27817
27818 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
27819
27820 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
27821 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
27822 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
27823
27824 correctCell(&volume_C, coordinates_Cell, &cellVolume_0, cellCentroid_0);
27825
27826 correctNormal(normalVec_c);
27827
27828 // create 2nd Cut face
27829 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area_c;
27830 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
27831 for(MInt dim = 0; dim < 3; dim++) {
27832 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = coordinates_c[dim];
27833 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normalVec_c[dim];
27834 }
27835
27836 m_bndryCells->a[bndryId].m_volume = volume_C;
27837 for(MInt dim = 0; dim < 3; dim++) {
27838 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
27839 }
27840 }
27841 break;
27842 }
27843 default: {
27844 mTerm(1, AT_, "Unknown case probably in disamb_tmp");
27845 }
27846 }
27847
27848 for(MInt i = 0; i < nDim; i++) {
27849 m_bndryCells->a[bndryId].m_coordinates[i] -= m_solver->a_coordinate(cellId, i);
27850 }
27851 if(splitCell[bndryId]) {
27852 for(MInt i = 0; i < nDim; i++) {
27853 m_bndryCells->a[bndryId2].m_coordinates[i] -= m_solver->a_coordinate(cellId2, i);
27854 }
27855 }
27856 if(currentCase == 7 && disamb_tmp == 7) {
27857 for(MInt i = 0; i < nDim; i++) {
27858 m_bndryCells->a[bndryId3].m_coordinates[i] -= m_solver->a_coordinate(cellId3, i);
27859 }
27860 }
27861
27862 // face data is assembled
27863 // create a surface for the cut face if a boundary cell neighbor exists
27864 if(!splitFace[bndryId]) { // cell can be split cell. here, the first cell is connected
27865 for(MInt face = 0; face < 6; face++) {
27866 m_bndryCells->a[bndryId].m_associatedSrfc[face] = -1;
27867 if(!faceCut[face]) continue;
27868 sideId = face % 2;
27869 spaceId = face / 2;
27870 if(nfs_cur[face]) {
27871 if(m_solver->a_hasNeighbor(cellId, face) > 0)
27872 nghbrId = m_solver->c_neighborId(cellId, face);
27873 else {
27874 if(m_solver->c_parentId(cellId) > -1) {
27875 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId), face) > 0)
27876 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId), face);
27877 else
27878 continue;
27879 } else
27880 continue;
27881 }
27882 if(m_solver->c_noChildren(nghbrId) > 0) continue;
27883 otherSideId = (sideId + 1) % 2;
27884 srfcId = m_solver->a_noSurfaces();
27885 m_surfaces.append();
27886 m_solver->a_surfaceOrientation(srfcId) = spaceId;
27887 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
27888 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
27889 for(MInt dim = 0; dim < nDim; dim++) {
27890 m_solver->a_surfaceCoordinate(srfcId, dim) = faceCentroid[face][dim];
27891 }
27892 m_solver->a_surfaceArea(srfcId) = faceVolume[face];
27893 m_bndryCells->a[bndryId].m_associatedSrfc[face] = srfcId;
27894 } else {
27895 stringstream errorMessage;
27896 errorMessage << "Error in FvBndryCnd3D::createCutFaceMGC - 1. Problem with face " << face << endl;
27897 errorMessage << "bndryId: " << bndryId << endl;
27898 errorMessage << "cellId: " << cellId << endl;
27899 errorMessage << "bndryCnd: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
27900 errorMessage << "case, subcase: " << currentCase << ", " << currentSubCase << endl;
27901 errorMessage << "disamb: " << disambiguation[bndryId] << endl;
27902 errorMessage << "face Volumes: " << faceVolume[0] << ", " << faceVolume[1] << ", " << faceVolume[2] << ", "
27903 << faceVolume[3] << ", " << faceVolume[4] << ", " << faceVolume[5] << endl;
27904 errorMessage << "faceCentroids: ";
27905 for(MInt i = 0; i < 6; i++) {
27906 errorMessage << faceCentroid[i][0] << ", " << faceCentroid[i][1] << ", " << faceCentroid[i][2] << "; "
27907 << endl;
27908 }
27909 errorMessage << "area_c = " << area_c << endl;
27910 errorMessage << "normalVec_c = " << normalVec_c[0] << ", " << normalVec_c[1] << ", " << normalVec_c[2]
27911 << endl;
27912 errorMessage << "coordinates_c = " << coordinates_c[0] << ", " << coordinates_c[1] << ", "
27913 << coordinates_c[2] << endl;
27914 errorMessage << "coordinates_Cell = " << coordinates_Cell[0] << ", " << coordinates_Cell[1] << ", "
27915 << coordinates_Cell[2] << endl;
27916 errorMessage << "volume_C = " << volume_C << endl;
27917 mTerm(1, AT_, errorMessage.str());
27918 }
27919 }
27920 }
27921 if(splitFace[bndryId]) { // cell is not a split cell. here, both split surfaces are created and connected
27922 for(MInt face = 0; face < 6; face++) {
27923 m_bndryCells->a[bndryId].m_associatedSrfc[face] = -1;
27924 if(!faceCut[face]) continue;
27925 sideId = face % 2;
27926 spaceId = face / 2;
27927 if(nfs_cur[face]) {
27928 if(m_solver->a_hasNeighbor(cellId, face) > 0)
27929 nghbrId = m_solver->c_neighborId(cellId, face);
27930 else {
27931 if(m_solver->c_parentId(cellId) > -1) {
27932 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId), face) > 0)
27933 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId), face);
27934 else
27935 continue;
27936 } else
27937 continue;
27938 }
27939 if(m_solver->c_noChildren(nghbrId) > 0) continue;
27940 otherSideId = (sideId + 1) % 2;
27941 if(face == splitFaceId) {
27942 // first surface
27943 srfcId = m_solver->a_noSurfaces();
27944 m_surfaces.append();
27945 m_solver->a_surfaceOrientation(srfcId) = spaceId;
27946 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
27947 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
27948 for(MInt dim = 0; dim < nDim; dim++) {
27949 m_solver->a_surfaceCoordinate(srfcId, dim) = splitFaceCentroid[0][dim];
27950 }
27951 m_solver->a_surfaceArea(srfcId) = splitFaceVolume[0];
27952 m_splitSurfaces[splitSurfaceIndexCounter * 6] = srfcId;
27953 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 1] = splitCorner1;
27954 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 2] = splitCorner1 + neighborCorner[face];
27955 // second surface
27956 srfcId = m_solver->a_noSurfaces();
27957 m_surfaces.append();
27958 m_solver->a_surfaceOrientation(srfcId) = spaceId;
27959 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
27960 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
27961 for(MInt dim = 0; dim < nDim; dim++) {
27962 m_solver->a_surfaceCoordinate(srfcId, dim) = splitFaceCentroid[1][dim];
27963 }
27964 m_solver->a_surfaceArea(srfcId) = splitFaceVolume[1];
27965 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 3] = srfcId;
27966 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 3 + 1] = splitCorner2;
27967 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 3 + 2] = splitCorner2 + neighborCorner[face];
27968 // set associated Srfc Pointer
27969 m_bndryCells->a[bndryId].m_associatedSrfc[face] = -splitSurfaceIndexCounter;
27970 splitSurfaceIndexCounter++;
27971 } else {
27972 srfcId = m_solver->a_noSurfaces();
27973 m_surfaces.append();
27974 m_solver->a_surfaceOrientation(srfcId) = spaceId;
27975 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
27976 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
27977 for(MInt dim = 0; dim < nDim; dim++) {
27978 m_solver->a_surfaceCoordinate(srfcId, dim) = faceCentroid[face][dim];
27979 }
27980 m_solver->a_surfaceArea(srfcId) = faceVolume[face];
27981 m_bndryCells->a[bndryId].m_associatedSrfc[face] = srfcId;
27982 }
27983 } else {
27984 stringstream errorMessage;
27985 errorMessage << "Error in FvBndryCnd3D::createCutFaceMGC - 2. Problem with face " << face << endl;
27986 errorMessage << "bndryId: " << bndryId << endl;
27987 errorMessage << "cellId: " << cellId << endl;
27988 errorMessage << "bndryCnd: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
27989 errorMessage << "case, subcase: " << currentCase << ", " << currentSubCase << endl;
27990 errorMessage << "disamb: " << disambiguation[bndryId] << endl;
27991 errorMessage << "face Volumes: " << faceVolume[0] << ", " << faceVolume[1] << ", " << faceVolume[2] << ", "
27992 << faceVolume[3] << ", " << faceVolume[4] << ", " << faceVolume[5] << endl;
27993 errorMessage << "faceCentroids: ";
27994 for(MInt i = 0; i < 6; i++) {
27995 errorMessage << faceCentroid[i][0] << ", " << faceCentroid[i][1] << ", " << faceCentroid[i][2] << "; "
27996 << endl;
27997 }
27998 errorMessage << "area_c = " << area_c << endl;
27999 errorMessage << "normalVec_c = " << normalVec_c[0] << ", " << normalVec_c[1] << ", " << normalVec_c[2]
28000 << endl;
28001 errorMessage << "coordinates_c = " << coordinates_c[0] << ", " << coordinates_c[1] << ", "
28002 << coordinates_c[2] << endl;
28003 errorMessage << "coordinates_Cell = " << coordinates_Cell[0] << ", " << coordinates_Cell[1] << ", "
28004 << coordinates_Cell[2] << endl;
28005 errorMessage << "volume_C = " << volume_C << endl;
28006 mTerm(1, AT_, errorMessage.str());
28007 }
28008 }
28009 }
28010 if(currentCase == 7 && currentSubCase >= 8
28011 && (disamb_tmp == 1 || disamb_tmp == 2
28012 || disamb_tmp == 4)) { // cell is not a split cell but a 7.3 cell. here, the additional split surfaces are
28013 // created and connected
28014 for(MInt face = 0; face < 6; face++) {
28015 if(face != splitFaceId2) continue;
28016 if(!faceCut[face]) continue;
28017 sideId = face % 2;
28018 spaceId = face / 2;
28019 if(nfs_cur[face]) {
28020 if(m_solver->a_hasNeighbor(cellId, face) > 0)
28021 nghbrId = m_solver->c_neighborId(cellId, face);
28022 else {
28023 if(m_solver->c_parentId(cellId) > -1) {
28024 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId), face) > 0)
28025 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId), face);
28026 else
28027 continue;
28028 } else
28029 continue;
28030 }
28031 if(m_solver->c_noChildren(nghbrId) > 0) continue;
28032 otherSideId = (sideId + 1) % 2;
28033 // first surface
28034 srfcId = m_solver->a_noSurfaces();
28035 m_surfaces.append();
28036 m_solver->a_surfaceOrientation(srfcId) = spaceId;
28037 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
28038 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
28039 for(MInt dim = 0; dim < nDim; dim++) {
28040 m_solver->a_surfaceCoordinate(srfcId, dim) = splitFaceCentroid2[0][dim];
28041 }
28042 m_solver->a_surfaceArea(srfcId) = splitFaceVolume2[0];
28043 m_splitSurfaces[splitSurfaceIndexCounter * 6] = srfcId;
28044 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 1] = splitCorner12;
28045 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 2] = splitCorner12 + neighborCorner[face];
28046 // second surface
28047 srfcId = m_solver->a_noSurfaces();
28048 m_surfaces.append();
28049 m_solver->a_surfaceOrientation(srfcId) = spaceId;
28050 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
28051 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
28052 for(MInt dim = 0; dim < nDim; dim++) {
28053 m_solver->a_surfaceCoordinate(srfcId, dim) = splitFaceCentroid2[1][dim];
28054 }
28055 m_solver->a_surfaceArea(srfcId) = splitFaceVolume2[1];
28056 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 3] = srfcId;
28057 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 3 + 1] = splitCorner22;
28058 m_splitSurfaces[splitSurfaceIndexCounter * 6 + 3 + 2] = splitCorner22 + neighborCorner[face];
28059 // set associated Srfc Pointer
28060 m_bndryCells->a[bndryId].m_associatedSrfc[face] = -splitSurfaceIndexCounter;
28061 splitSurfaceIndexCounter++;
28062 } else {
28063 stringstream errorMessage;
28064 errorMessage << "Error in FvBndryCnd3D::createCutFaceMGC - 3. Problem with face " << face << endl;
28065 errorMessage << "bndryId: " << bndryId << endl;
28066 errorMessage << "cellId: " << cellId << endl;
28067 errorMessage << "bndryCnd: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
28068 errorMessage << "case, subcase: " << currentCase << ", " << currentSubCase << endl;
28069 errorMessage << "disamb: " << disambiguation[bndryId] << endl;
28070 errorMessage << "face Volumes: " << faceVolume[0] << ", " << faceVolume[1] << ", " << faceVolume[2] << ", "
28071 << faceVolume[3] << ", " << faceVolume[4] << ", " << faceVolume[5] << endl;
28072 errorMessage << "faceCentroids: ";
28073 for(MInt i = 0; i < 6; i++) {
28074 errorMessage << faceCentroid[i][0] << ", " << faceCentroid[i][1] << ", " << faceCentroid[i][2] << "; "
28075 << endl;
28076 }
28077 errorMessage << "area_c = " << area_c << endl;
28078 errorMessage << "normalVec_c = " << normalVec_c[0] << ", " << normalVec_c[1] << ", " << normalVec_c[2]
28079 << endl;
28080 errorMessage << "coordinates_c = " << coordinates_c[0] << ", " << coordinates_c[1] << ", "
28081 << coordinates_c[2] << endl;
28082 errorMessage << "coordinates_Cell = " << coordinates_Cell[0] << ", " << coordinates_Cell[1] << ", "
28083 << coordinates_Cell[2] << endl;
28084 errorMessage << "volume_C = " << volume_C << endl;
28085 mTerm(1, AT_, errorMessage.str());
28086 }
28087 }
28088 }
28089 if(splitCell[bndryId]) { // first cell has been connected in standard routine above
28090 for(MInt face = 0; face < 6; face++) {
28091 m_bndryCells->a[bndryId2].m_associatedSrfc[face] = -1;
28092 if(!faceCut_0[face]) continue;
28093 sideId = face % 2;
28094 spaceId = face / 2;
28095 if(nfs_cur_0[face]) {
28096 // Timw: consider cellId2 as a SplitChild
28097 MInt splitChildId = cellId2;
28098 if(m_solver->a_hasProperty(cellId2, SolverCell::IsSplitClone))
28099 cellId2 = m_solver->m_splitChildToSplitCell.find(cellId2)->second;
28100 if(m_solver->a_hasNeighbor(cellId2, face) > 0)
28101 nghbrId = m_solver->c_neighborId(cellId2, face);
28102 else {
28103 if(m_solver->c_parentId(cellId2) > -1) {
28104 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId2), face) > 0)
28105 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId2), face);
28106 else
28107 continue;
28108 } else
28109 continue;
28110 }
28111 cellId2 = splitChildId;
28112 if(m_solver->c_noChildren(nghbrId) > 0) continue;
28113 otherSideId = (sideId + 1) % 2;
28114 srfcId = m_solver->a_noSurfaces();
28115 m_surfaces.append();
28116 m_solver->a_surfaceOrientation(srfcId) = spaceId;
28117 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
28118 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId2;
28119 for(MInt dim = 0; dim < nDim; dim++) {
28120 m_solver->a_surfaceCoordinate(srfcId, dim) = faceCentroid_0[face][dim];
28121 }
28122 m_solver->a_surfaceArea(srfcId) = faceVolume_0[face];
28123 m_bndryCells->a[bndryId2].m_associatedSrfc[face] = srfcId;
28124 } else {
28125 stringstream errorMessage;
28126 errorMessage << "Error in FvBndryCnd3D::createCutFaceMGC - 4. Problem with face " << face << endl;
28127 errorMessage << "bndryId: " << bndryId2 << endl;
28128 errorMessage << "cellId: " << cellId2 << endl;
28129 errorMessage << "split cell! Twin: " << bndryId << endl;
28130 errorMessage << "bndryCnd: " << m_bndryCells->a[bndryId2].m_srfcs[0]->m_bndryCndId;
28131 errorMessage << "case, subcase: " << currentCase << ", " << currentSubCase << endl;
28132 errorMessage << "disamb: " << disambiguation[bndryId] << endl;
28133 errorMessage << "face Volumes: " << faceVolume_0[0] << ", " << faceVolume_0[1] << ", " << faceVolume_0[2]
28134 << ", " << faceVolume_0[3] << ", " << faceVolume_0[4] << ", " << faceVolume_0[5] << endl;
28135 errorMessage << "faceCentroids: ";
28136 for(MInt i = 0; i < 6; i++) {
28137 errorMessage << faceCentroid_0[i][0] << ", " << faceCentroid_0[i][1] << ", " << faceCentroid_0[i][2]
28138 << "; " << endl;
28139 }
28140 errorMessage << "area_c = " << area_c << endl;
28141 errorMessage << "normalVec_c = " << normalVec_c[0] << ", " << normalVec_c[1] << ", " << normalVec_c[2]
28142 << endl;
28143 errorMessage << "coordinates_c = " << coordinates_c[0] << ", " << coordinates_c[1] << ", "
28144 << coordinates_c[2] << endl;
28145 errorMessage << "coordinates_Cell = " << coordinates_Cell[0] << ", " << coordinates_Cell[1] << ", "
28146 << coordinates_Cell[2] << endl;
28147 errorMessage << "volume_C = " << volume_C << endl;
28148 mTerm(1, AT_, errorMessage.str());
28149 }
28150 }
28151 }
28152 // split3 cell:
28153 if(currentCase == 7 && disamb_tmp == 7) {
28154 for(MInt face = 0; face < 6; face++) {
28155 m_bndryCells->a[bndryId3].m_associatedSrfc[face] = -1;
28156 if(!faceCut_00[face]) continue;
28157 sideId = face % 2;
28158 spaceId = face / 2;
28159 if(nfs_cur_00[face]) {
28160 // Timw: consider cellId3 as a SplitChild
28161 MInt splitChildId = cellId3;
28162 if(m_solver->a_hasProperty(cellId3, SolverCell::IsSplitClone))
28163 cellId3 = m_solver->m_splitChildToSplitCell.find(cellId3)->second;
28164 if(m_solver->a_hasNeighbor(cellId3, face) > 0)
28165 nghbrId = m_solver->c_neighborId(cellId3, face);
28166 else {
28167 if(m_solver->c_parentId(cellId3) > -1) {
28168 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId3), face) > 0)
28169 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId3), face);
28170 else
28171 continue;
28172 } else
28173 continue;
28174 }
28175 cellId3 = splitChildId;
28176 if(m_solver->c_noChildren(nghbrId) > 0) continue;
28177 otherSideId = (sideId + 1) % 2;
28178 srfcId = m_solver->a_noSurfaces();
28179 m_surfaces.append();
28180 m_solver->a_surfaceOrientation(srfcId) = spaceId;
28181 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
28182 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId3;
28183 for(MInt dim = 0; dim < nDim; dim++) {
28184 m_solver->a_surfaceCoordinate(srfcId, dim) = faceCentroid_00[face][dim];
28185 }
28186 m_solver->a_surfaceArea(srfcId) = faceVolume_00[face];
28187 m_bndryCells->a[bndryId3].m_associatedSrfc[face] = srfcId;
28188 } else {
28189 stringstream errorMessage;
28190 errorMessage << "Error in FvBndryCnd3D::createCutFaceMGC - 5. Problem with face " << face << endl;
28191 errorMessage << "bndryId: " << bndryId3 << endl;
28192 errorMessage << "cellId: " << cellId3 << endl;
28193 errorMessage << "split cell! Twin (triple): " << bndryId << endl;
28194 errorMessage << "bndryCnd: " << m_bndryCells->a[bndryId3].m_srfcs[0]->m_bndryCndId;
28195 errorMessage << "case, subcase: " << currentCase << ", " << currentSubCase << endl;
28196 errorMessage << "disamb: " << disambiguation[bndryId] << endl;
28197 errorMessage << "face Volumes: " << faceVolume_00[0] << ", " << faceVolume_00[1] << ", " << faceVolume_00[2]
28198 << ", " << faceVolume_00[3] << ", " << faceVolume_00[4] << ", " << faceVolume_00[5] << endl;
28199 errorMessage << "faceCentroids: ";
28200 for(MInt i = 0; i < 6; i++) {
28201 errorMessage << faceCentroid_00[i][0] << ", " << faceCentroid_00[i][1] << ", " << faceCentroid_00[i][2]
28202 << "; " << endl;
28203 }
28204 errorMessage << "area_c = " << area_c << endl;
28205 errorMessage << "normalVec_c = " << normalVec_c[0] << ", " << normalVec_c[1] << ", " << normalVec_c[2]
28206 << endl;
28207 errorMessage << "coordinates_c = " << coordinates_c[0] << ", " << coordinates_c[1] << ", "
28208 << coordinates_c[2] << endl;
28209 errorMessage << "coordinates_Cell = " << coordinates_Cell[0] << ", " << coordinates_Cell[1] << ", "
28210 << coordinates_Cell[2] << endl;
28211 mTerm(1, AT_, errorMessage.str());
28212 }
28213 }
28214 }
28215
28216 for(MInt face = 0; face < 6; face++) {
28217 if(!nfs_cur[face]) {
28218 m_bndryCells->a[bndryId].m_externalFaces[face] = true;
28219 }
28220 }
28221 if(splitCell[bndryId]) {
28222 for(MInt face = 0; face < 6; face++) {
28223 if(!nfs_cur_0[face]) {
28224 m_bndryCells->a[bndryId2].m_externalFaces[face] = true;
28225 }
28226 }
28227 }
28228 if(currentCase == 7 && disamb_tmp == 7) {
28229 for(MInt face = 0; face < 6; face++) {
28230 if(!nfs_cur_00[face]) {
28231 m_bndryCells->a[bndryId3].m_externalFaces[face] = true;
28232 }
28233 }
28234 }
28235 } else {
28236 m_bndryCells->a[bndryId].m_noSrfcs = 1;
28237 stringstream fileName;
28238 switch(currentCase) {
28239 case 0:
28240 cerr << "FvBndryCnd3D::createCutFaceMGC - Error: Cell is not a boundary cell!" << endl;
28241 cerr << "CellId: " << cellId << " BndryId: " << bndryId << endl;
28242 cerr << "Cell level: " << m_solver->a_level(cellId) << endl;
28243 fileName << cellId << ".stl";
28244 writeStlFileOfCell(cellId, (fileName.str()).c_str());
28245 cerr << "Wrote stl-file of cell. FileName: " << (fileName.str()) << endl;
28246 break;
28247 case 1: {
28248 // cerr << "Case 1 detected. Starting Cutface computation..." << endl;
28249 for(MInt face = 0; face < 6; face++) {
28250 nfs_cur[face] = nfs1[currentSubCase][face];
28251 }
28252 p_0 = corner[cornersMCtoSOLVER[tiling1STL[currentSubCase][0]]];
28253 noFaces = 3;
28254 if(currentSubCase < 8) { // 1 Point is inside, 5 Points are outside
28255 } else { // 1 Point is outside, 5 Points are inside
28256 for(MInt i = 0; i < 6; i++) {
28257 faceVolume_0[i] = faceVolume[i];
28258 for(MInt j = 0; j < 3; j++) {
28259 faceCentroid_0[i][j] = faceCentroid[i][j];
28260 }
28261 }
28262 }
28263 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][1]];
28264 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28265 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][2]];
28266 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28267 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][3]];
28268 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28269 face1 = facesMCtoSOLVER[tiling1STL[currentSubCase][4]];
28270 face2 = facesMCtoSOLVER[tiling1STL[currentSubCase][5]];
28271 face3 = facesMCtoSOLVER[tiling1STL[currentSubCase][6]];
28272
28273 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1]);
28274 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2]);
28275 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3]);
28276
28277 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
28278
28279 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
28280
28281 if(currentSubCase >= 8) {
28282 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
28283 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
28284 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
28285
28286 correctCell(&volume_C, coordinates_Cell, &gridCellVolume, &m_solver->a_coordinate(cellId, 0));
28287
28288 correctNormal(normalVec_c);
28289 }
28290
28291 m_bndryCells->a[bndryId].m_volume = volume_C;
28292 // create 1 Cut face
28293 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
28294 for(MInt dim = 0; dim < 3; dim++) {
28295 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
28296 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
28297 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
28298 }
28299 } break;
28300 case 2: {
28301 // cerr << "Case 2 detected. Starting Cutface computation..." << endl;
28302 for(MInt face = 0; face < 6; face++) {
28303 nfs_cur[face] = nfs2[currentSubCase][face];
28304 }
28305 noFaces = 4;
28306 p_0 = corner[cornersMCtoSOLVER[tiling2STL[currentSubCase][0]]];
28307 p_0s = corner[cornersMCtoSOLVER[tiling2STL[currentSubCase][1]]];
28308 if(currentSubCase < 12) { // 2 Points are inside, 4 Points are outside
28309 } else { // 2 Points are outside, 4 Points are inside
28310 for(MInt i = 0; i < 6; i++) {
28311 faceVolume_0[i] = faceVolume[i];
28312 for(MInt j = 0; j < 3; j++) {
28313 faceCentroid_0[i][j] = faceCentroid[i][j];
28314 }
28315 }
28316 }
28317
28318 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][2]];
28319 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28320 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][3]];
28321 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28322 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][4]];
28323 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28324 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][5]];
28325 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28326 face1 = facesMCtoSOLVER[tiling2STL[currentSubCase][6]];
28327 face2 = facesMCtoSOLVER[tiling2STL[currentSubCase][7]];
28328 face3 = facesMCtoSOLVER[tiling2STL[currentSubCase][8]];
28329 face4 = facesMCtoSOLVER[tiling2STL[currentSubCase][9]];
28330
28331 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2], normal[face2]);
28332 computeTri(p_0s, p_3s, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
28333 computeTrapez(p_0, p_0s, p_3s, p_3, &faceVolume[face1], faceCentroid[face1], normal[face1]);
28334 computeTrapez(p_2, p_2s, p_0s, p_0, &faceVolume[face4], faceCentroid[face4], normal[face4]);
28335
28336 computePoly4(p_3, p_3s, p_2s, p_2, &area_c, coordinates_c, normalVec_c);
28337
28338 maia::math::vecAvg<3>(M, p_0, p_0s, p_2, p_2s, p_3, p_3s);
28339
28340 for(MInt i = 0; i < 4; i++) {
28341 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
28342 &pyraVolume[i], pyraCentroid[i]);
28343 }
28344 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[4], pyraCentroid[4]);
28345 for(MInt i = 0; i < 5; i++) {
28346 volume_C += pyraVolume[i];
28347 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
28348 }
28349 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
28350
28351 if(currentSubCase >= 12) {
28352 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
28353 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
28354 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
28355 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
28356
28357 correctCell(&volume_C, coordinates_Cell, &gridCellVolume, &m_solver->a_coordinate(cellId, 0));
28358
28359 correctNormal(normalVec_c);
28360 }
28361
28362 m_bndryCells->a[bndryId].m_volume = volume_C;
28363 // create 1 Cut face
28364 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
28365 for(MInt dim = 0; dim < 3; dim++) {
28366 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
28367 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
28368 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
28369 }
28370 } break;
28371 case 5: {
28372 // cerr << "Case 5 detected. Starting Cutface computation..." << endl;
28373 for(MInt face = 0; face < 6; face++) {
28374 nfs_cur[face] = nfs5[currentSubCase][face];
28375 }
28376 noFaces = 5;
28377 p_0 = corner[cornersMCtoSOLVER[tiling5STL[currentSubCase][0]]];
28378 p_1 = corner[cornersMCtoSOLVER[tiling5STL[currentSubCase][1]]];
28379 p_2 = corner[cornersMCtoSOLVER[tiling5STL[currentSubCase][2]]];
28380 if(currentSubCase < 24) { // 3 Points are inside, 5 Points are outside
28381 } else { // 3 Points are outside, 5 Points are inside
28382 for(MInt i = 0; i < 6; i++) {
28383 faceVolume_0[i] = faceVolume[i];
28384 for(MInt j = 0; j < 3; j++) {
28385 faceCentroid_0[i][j] = faceCentroid[i][j];
28386 }
28387 }
28388 }
28389
28390 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][3]];
28391 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28392 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][4]];
28393 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28394 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][5]];
28395 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28396 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][6]];
28397 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28398 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][7]];
28399 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28400 face1 = facesMCtoSOLVER[tiling5STL[currentSubCase][8]];
28401 face2 = facesMCtoSOLVER[tiling5STL[currentSubCase][9]];
28402 face3 = facesMCtoSOLVER[tiling5STL[currentSubCase][10]];
28403 face4 = facesMCtoSOLVER[tiling5STL[currentSubCase][11]];
28404 face5 = facesMCtoSOLVER[tiling5STL[currentSubCase][12]];
28405
28406 computePoly5(p_0, p_0ss, p_2ss, p_2, p_1, &faceVolume[face1], faceCentroid[face1], normal[face1]);
28407 computeTri(p_0ss, p_0, p_0s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
28408 computeTrapez(p_0, p_1, p_1s, p_0s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
28409 computeTrapez(p_1, p_1s, p_2s, p_2, &faceVolume[face4], faceCentroid[face4], normal[face4]);
28410 computeTri(p_2s, p_2, p_2ss, &faceVolume[face5], faceCentroid[face5], normal[face5]);
28411
28412 computePoly5(p_0s, p_1s, p_2s, p_2ss, p_0ss, &area_c, coordinates_c, normalVec_c);
28413
28414 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_0s, p_1s, p_2s, p_0ss, p_2ss);
28415
28416 for(MInt i = 0; i < 5; i++) {
28417 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
28418 &pyraVolume[i], pyraCentroid[i]);
28419 }
28420 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
28421 for(MInt i = 0; i < 6; i++) {
28422 volume_C += pyraVolume[i];
28423 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
28424 }
28425 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
28426
28427 if(currentSubCase >= 24) {
28428 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
28429 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
28430 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
28431 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
28432 correctFace(&faceVolume[face5], faceCentroid[face5], &faceVolume_0[face5], faceCentroid_0[face5]);
28433
28434 correctCell(&volume_C, coordinates_Cell, &gridCellVolume, &m_solver->a_coordinate(cellId, 0));
28435
28436 correctNormal(normalVec_c);
28437 }
28438
28439 m_bndryCells->a[bndryId].m_volume = volume_C;
28440 // create 1 Cut face
28441 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
28442 for(MInt dim = 0; dim < 3; dim++) {
28443 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
28444 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
28445 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
28446 }
28447 } break;
28448 case 8: {
28449 // cerr << "Case 8 detected. Starting Cutface computation..." << endl;
28450 for(MInt face = 0; face < 6; face++) {
28451 nfs_cur[face] = nfs8[currentSubCase][face];
28452 }
28453 noFaces = 4;
28454 p_0 = corner[cornersMCtoSOLVER[tiling8STL[currentSubCase][0]]];
28455 p_1 = corner[cornersMCtoSOLVER[tiling8STL[currentSubCase][1]]];
28456 p_2 = corner[cornersMCtoSOLVER[tiling8STL[currentSubCase][2]]];
28457 p_3 = corner[cornersMCtoSOLVER[tiling8STL[currentSubCase][3]]];
28458
28459 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][4]];
28460 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28461 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][5]];
28462 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28463 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][6]];
28464 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28465 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][7]];
28466 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28467 face5 = facesMCtoSOLVER[tiling8STL[currentSubCase][8]];
28468 face1 = facesMCtoSOLVER[tiling8STL[currentSubCase][9]];
28469 face2 = facesMCtoSOLVER[tiling8STL[currentSubCase][10]];
28470 face3 = facesMCtoSOLVER[tiling8STL[currentSubCase][11]];
28471 face4 = facesMCtoSOLVER[tiling8STL[currentSubCase][12]];
28472
28473 computeTrapez(p_0, p_1, p_1s, p_0s, &faceVolume[face1], faceCentroid[face1], normal[face1]);
28474 computeTrapez(p_1, p_2, p_2s, p_1s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
28475 computeTrapez(p_2, p_3, p_3s, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
28476 computeTrapez(p_3, p_0, p_0s, p_3s, &faceVolume[face4], faceCentroid[face4], normal[face4]);
28477
28478 computeTrapez(p_0, p_3, p_2, p_1, &faceVolume[face5], faceCentroid[face5], normal[face5]);
28479
28480 computePoly4(p_0s, p_1s, p_2s, p_3s, &area_c, coordinates_c, normalVec_c);
28481
28482 maia::math::vecAvg<3>(M, p_0, p_0s, p_1, p_1s, p_2, p_2s, p_3, p_3s);
28483
28484 for(MInt i = 0; i < 5; i++) {
28485 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
28486 &pyraVolume[i], pyraCentroid[i]);
28487 }
28488 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
28489 for(MInt i = 0; i < 6; i++) {
28490 volume_C += pyraVolume[i];
28491 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
28492 }
28493 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
28494
28495 m_bndryCells->a[bndryId].m_volume = volume_C;
28496 // create 1 Cut face
28497 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
28498 for(MInt dim = 0; dim < 3; dim++) {
28499 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
28500 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
28501 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
28502 }
28503 } break;
28504 case 9: {
28505 // cerr << "Case 9 detected. Starting Cutface computation..." << endl;
28506 for(MInt face = 0; face < 6; face++) {
28507 nfs_cur[face] = nfs9[currentSubCase][face];
28508 }
28509 noFaces = 6;
28510 p_0 = corner[cornersMCtoSOLVER[tiling9STL[currentSubCase][0]]];
28511 p_1 = corner[cornersMCtoSOLVER[tiling9STL[currentSubCase][1]]];
28512 p_2 = corner[cornersMCtoSOLVER[tiling9STL[currentSubCase][2]]];
28513 p_3 = corner[cornersMCtoSOLVER[tiling9STL[currentSubCase][3]]];
28514
28515 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][4]];
28516 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28517 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][5]];
28518 p_1ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28519 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][6]];
28520 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28521 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][7]];
28522 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28523 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][8]];
28524 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28525 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][9]];
28526 p_3ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28527 face1 = facesMCtoSOLVER[tiling9STL[currentSubCase][10]];
28528 face2 = facesMCtoSOLVER[tiling9STL[currentSubCase][11]];
28529 face3 = facesMCtoSOLVER[tiling9STL[currentSubCase][12]];
28530 face4 = facesMCtoSOLVER[tiling9STL[currentSubCase][13]];
28531 face5 = facesMCtoSOLVER[tiling9STL[currentSubCase][14]];
28532 face6 = facesMCtoSOLVER[tiling9STL[currentSubCase][15]];
28533
28534 computePoly5(p_0, p_3, p_3ss, p_2s, p_2, &faceVolume[face1], faceCentroid[face1], normal[face1]);
28535 computePoly5(p_0, p_1, p_1ss, p_3s, p_3, &faceVolume[face3], faceCentroid[face3], normal[face3]);
28536 computePoly5(p_0, p_2, p_2ss, p_1s, p_1, &faceVolume[face5], faceCentroid[face5], normal[face5]);
28537 computeTri(p_1, p_1s, p_1ss, &faceVolume[face2], faceCentroid[face2], normal[face2]);
28538 computeTri(p_2, p_2s, p_2ss, &faceVolume[face4], faceCentroid[face4], normal[face4]);
28539 computeTri(p_3, p_3s, p_3ss, &faceVolume[face6], faceCentroid[face6], normal[face6]);
28540
28541 computePoly6(p_1ss, p_1s, p_2ss, p_2s, p_3ss, p_3s, &area_c, coordinates_c, normalVec_c);
28542
28543 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3, p_1s, p_2s, p_3s, p_1ss, p_2ss, p_3ss);
28544
28545 for(MInt i = 0; i < 6; i++) {
28546 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
28547 &pyraVolume[i], pyraCentroid[i]);
28548 }
28549 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
28550 for(MInt i = 0; i < 7; i++) {
28551 volume_C += pyraVolume[i];
28552 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
28553 }
28554 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
28555
28556 m_bndryCells->a[bndryId].m_volume = volume_C;
28557 // create 1 Cut face
28558 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
28559 for(MInt dim = 0; dim < 3; dim++) {
28560 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
28561 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
28562 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
28563 }
28564 }
28565
28566 break;
28567 case 11: {
28568 // cerr << "Case 11 detected. Starting Cutface computation..." << endl;
28569 for(MInt face = 0; face < 6; face++) {
28570 nfs_cur[face] = nfs11[currentSubCase][face];
28571 }
28572 noFaces = 6;
28573 p_0 = corner[cornersMCtoSOLVER[tiling11STL[currentSubCase][0]]];
28574 p_1 = corner[cornersMCtoSOLVER[tiling11STL[currentSubCase][1]]];
28575 p_2 = corner[cornersMCtoSOLVER[tiling11STL[currentSubCase][2]]];
28576 p_3 = corner[cornersMCtoSOLVER[tiling11STL[currentSubCase][3]]];
28577
28578 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][4]];
28579 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28580 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][5]];
28581 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28582 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][6]];
28583 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28584 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][7]];
28585 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28586 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][8]];
28587 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28588 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][9]];
28589 p_3ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28590 face1 = facesMCtoSOLVER[tiling11STL[currentSubCase][10]];
28591 face2 = facesMCtoSOLVER[tiling11STL[currentSubCase][11]];
28592 face3 = facesMCtoSOLVER[tiling11STL[currentSubCase][12]];
28593 face4 = facesMCtoSOLVER[tiling11STL[currentSubCase][13]];
28594 face5 = facesMCtoSOLVER[tiling11STL[currentSubCase][14]];
28595 face6 = facesMCtoSOLVER[tiling11STL[currentSubCase][15]];
28596
28597 computeTri(p_0, p_0s, p_0ss, &faceVolume[face1], faceCentroid[face1], normal[face1]);
28598 computePoly5(p_3s, p_3, p_2, p_1, p_1s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
28599 computeTrapez(p_2, p_3, p_3ss, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
28600 computeTrapez(p_1, p_0, p_0ss, p_1s, &faceVolume[face4], faceCentroid[face4], normal[face4]);
28601 computePoly5(p_1, p_2, p_2s, p_0s, p_0, &faceVolume[face5], faceCentroid[face5], normal[face5]);
28602 computeTri(p_3, p_3s, p_3ss, &faceVolume[face6], faceCentroid[face6], normal[face6]);
28603
28604 computePoly6(p_0ss, p_0s, p_2s, p_3ss, p_3s, p_1s, &area_c, coordinates_c, normalVec_c);
28605
28606 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3, p_0s, p_1s, p_2s, p_3s, p_0ss, p_3ss);
28607
28608 for(MInt i = 0; i < 6; i++) {
28609 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
28610 &pyraVolume[i], pyraCentroid[i]);
28611 }
28612 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
28613 for(MInt i = 0; i < 7; i++) {
28614 volume_C += pyraVolume[i];
28615 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
28616 }
28617 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
28618
28619 m_bndryCells->a[bndryId].m_volume = volume_C;
28620 // create 1 Cut face
28621 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
28622 for(MInt dim = 0; dim < 3; dim++) {
28623 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
28624 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
28625 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
28626 }
28627 break;
28628 }
28629 case 14: {
28630 // cerr << "Case 14 detected. Starting Cutface computation..." << endl;
28631 for(MInt face = 0; face < 6; face++) {
28632 nfs_cur[face] = nfs14[currentSubCase][face];
28633 }
28634 noFaces = 6;
28635 p_0 = corner[cornersMCtoSOLVER[tiling14STL[currentSubCase][0]]];
28636 p_1 = corner[cornersMCtoSOLVER[tiling14STL[currentSubCase][1]]];
28637 p_2 = corner[cornersMCtoSOLVER[tiling14STL[currentSubCase][2]]];
28638 p_3 = corner[cornersMCtoSOLVER[tiling14STL[currentSubCase][3]]];
28639
28640 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][4]];
28641 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28642 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][5]];
28643 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28644 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][6]];
28645 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28646 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][7]];
28647 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28648 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][8]];
28649 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28650 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][9]];
28651 p_3ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
28652 face1 = facesMCtoSOLVER[tiling14STL[currentSubCase][10]];
28653 face2 = facesMCtoSOLVER[tiling14STL[currentSubCase][11]];
28654 face3 = facesMCtoSOLVER[tiling14STL[currentSubCase][12]];
28655 face4 = facesMCtoSOLVER[tiling14STL[currentSubCase][13]];
28656 face5 = facesMCtoSOLVER[tiling14STL[currentSubCase][14]];
28657 face6 = facesMCtoSOLVER[tiling14STL[currentSubCase][15]];
28658
28659 computeTri(p_0, p_0s, p_0ss, &faceVolume[face1], faceCentroid[face1], normal[face1]);
28660 computePoly5(p_2, p_3, p_3ss, p_1s, p_1, &faceVolume[face2], faceCentroid[face2], normal[face2]);
28661 computeTrapez(p_2s, p_3s, p_3, p_2, &faceVolume[face3], faceCentroid[face3], normal[face3]);
28662 computeTrapez(p_1s, p_0s, p_0, p_1, &faceVolume[face4], faceCentroid[face4], normal[face4]);
28663 computePoly5(p_2, p_1, p_0, p_0ss, p_2s, &faceVolume[face5], faceCentroid[face5], normal[face5]);
28664 computeTri(p_3, p_3s, p_3ss, &faceVolume[face6], faceCentroid[face6], normal[face6]);
28665
28666 computePoly6(p_0ss, p_0s, p_1s, p_3ss, p_3s, p_2s, &area_c, coordinates_c, normalVec_c);
28667
28668 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3, p_0s, p_1s, p_2s, p_3s, p_0ss, p_3ss);
28669
28670 for(MInt i = 0; i < 6; i++) {
28671 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
28672 &pyraVolume[i], pyraCentroid[i]);
28673 }
28674 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
28675 for(MInt i = 0; i < 7; i++) {
28676 volume_C += pyraVolume[i];
28677 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
28678 }
28679 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
28680
28681 m_bndryCells->a[bndryId].m_volume = volume_C;
28682 // create 1 Cut face
28683 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
28684 for(MInt dim = 0; dim < 3; dim++) {
28685 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
28686 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
28687 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
28688 }
28689
28690 break;
28691 }
28692 default: {
28693 stringstream errorMessage;
28694 errorMessage << "FvBndryCnd3D::createCutFaceMGC - Error: Inconsistent type implementation." << endl;
28695 mTerm(1, AT_, errorMessage.str());
28696 }
28697 }
28698
28699 absA = F0;
28700 for(MInt i = 0; i < nDim; i++) {
28701 // make sure faceVolume of non fluid sides is zero
28702 if(!nfs_cur[2 * i + 1]) faceVolume[2 * i + 1] = 0;
28703 if(!nfs_cur[2 * i]) faceVolume[2 * i] = 0;
28704 // correct coordinates - bndrycell coordinates are stored relative to cell coordinates
28705 m_bndryCells->a[bndryId].m_coordinates[i] -= m_solver->a_coordinate(cellId, i);
28706 // implicitly recompute the correct area and normal of the cut surface
28707 faceDiff[i] = faceVolume[2 * i + 1] - faceVolume[2 * i];
28708 absA += POW2(faceDiff[i]);
28709 }
28710 // This is only unique if the cut surface is planar. Otherwise, this is nevertheless a reasonnable choice.
28711 for(MInt i = 0; i < nDim; i++) {
28712 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] = faceDiff[i] / sqrt(absA);
28713 }
28714 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = sqrt(absA);
28715
28716 // face data is assembled
28717 // create a surface for the cut face if a boundary cell neighbor exists
28718 for(MInt face = 0; face < 6; face++) {
28719 m_bndryCells->a[bndryId].m_associatedSrfc[face] = -1;
28720 for(MInt i = 0; i < noFaces; i++) {
28721 if(!(*facepointers[i] == face)) continue;
28722 sideId = face % 2;
28723 spaceId = face / 2;
28724 if(nfs_cur[face]) {
28725 if(m_solver->a_hasNeighbor(cellId, face) > 0) {
28726 nghbrId = m_solver->c_neighborId(cellId, face);
28727 } else {
28728 if(m_solver->c_parentId(cellId) > -1) {
28729 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId), face) > 0)
28730 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId), face);
28731 else
28732 continue;
28733 } else
28734 continue;
28735 }
28736 if(m_solver->c_noChildren(nghbrId) > 0) continue;
28737 otherSideId = (sideId + 1) % 2;
28738 srfcId = m_solver->a_noSurfaces();
28739 m_surfaces.append();
28740 m_solver->a_surfaceOrientation(srfcId) = spaceId;
28741 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
28742 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
28743 for(MInt dim = 0; dim < nDim; dim++) {
28744 m_solver->a_surfaceCoordinate(srfcId, dim) = faceCentroid[face][dim];
28745 }
28746 m_solver->a_surfaceArea(srfcId) = faceVolume[face];
28747 m_bndryCells->a[bndryId].m_associatedSrfc[face] = srfcId;
28748 break;
28749 } else {
28750 stringstream errorMessage;
28751 errorMessage << " Error in FvBndryCnd3D::createCutFaceMGC - 6. Problem with face " << face << endl;
28752 errorMessage << "bndryId: " << bndryId << endl;
28753 errorMessage << "cellId: " << cellId << endl;
28754 errorMessage << "bndryCnd: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
28755 errorMessage << "case, subcase: " << currentCase << ", " << currentSubCase << endl;
28756 errorMessage << "face Volumes: " << faceVolume[0] << ", " << faceVolume[1] << ", " << faceVolume[2] << ", "
28757 << faceVolume[3] << ", " << faceVolume[4] << ", " << faceVolume[5] << endl;
28758 errorMessage << "faceCentroids: ";
28759 for(MInt j = 0; j < 6; j++) {
28760 errorMessage << faceCentroid[j][0] << ", " << faceCentroid[j][1] << ", " << faceCentroid[j][2] << "; "
28761 << endl;
28762 }
28763 errorMessage << "area_c = " << area_c << endl;
28764 errorMessage << "normalVec_c = " << normalVec_c[0] << ", " << normalVec_c[1] << ", " << normalVec_c[2]
28765 << endl;
28766 errorMessage << "coordinates_c = " << coordinates_c[0] << ", " << coordinates_c[1] << ", "
28767 << coordinates_c[2] << endl;
28768 errorMessage << "coordinates_Cell = " << coordinates_Cell[0] << ", " << coordinates_Cell[1] << ", "
28769 << coordinates_Cell[2] << endl;
28770 errorMessage << "volume_C = " << volume_C << endl;
28771 mTerm(1, AT_, errorMessage.str());
28772 }
28773 }
28774 }
28775 // set nonFluidSideIds
28776 for(MInt face = 0; face < 6; face++) {
28777 if(!nfs_cur[face]) {
28778 m_bndryCells->a[bndryId].m_externalFaces[face] = true;
28779 }
28780 }
28781 }
28782 }
28783
28784 // initialize bndryNghbrs array
28785 if(keepNghbrs) {
28786 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
28787 cellId = m_bndryCells->a[bndryId].m_cellId;
28788 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitClone)) {
28789 cellId = m_solver->m_splitChildToSplitCell.find(cellId)->second;
28790 m_solver->assertValidGridCellId(cellId);
28791 }
28792 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
28793 m_bndryNghbrs[bndryId * m_noDirs * 2 + dirId * 2] = -1;
28794 if(m_solver->a_hasNeighbor(cellId, dirId) > 0)
28795 m_bndryNghbrs[bndryId * m_noDirs * 2 + dirId * 2] = m_solver->c_neighborId(cellId, dirId);
28796 m_bndryNghbrs[bndryId * m_noDirs * 2 + dirId * 2 + 1] = -1;
28797 }
28798 }
28799 }
28800
28801 // 5. Compute neighbor information for ambiguous cells
28802
28803 if(!keepNghbrs) {
28804 for(MInt ambId = 0; ambId < noAmbiguousCells; ambId++) {
28805 MInt bndryId = ambiguousCells[ambId];
28806 cellId = m_bndryCells->a[bndryId].m_cellId;
28807
28808 // a) Check cells which are splitCells without split surface
28809 if(splitCell[bndryId] && !splitFace[bndryId]) {
28810 // first update connections split relative cell
28811 for(MInt child = 0; child < 3; child++) {
28812 bndryId2 = m_splitChildren[bndryId * 3 + child];
28813 if(bndryId2 == -1) break;
28814 cellId2 = m_bndryCells->a[bndryId2].m_cellId;
28815 // cellId2 = splitRelatives[ambId];
28816 // bndryId2 = m_solver->a_bndryId(cellId2);
28817 for(MInt corn = 0; corn < 8; corn++) {
28818 if(cornerCellMapping[ambId * 8 + corn] == cellId2) { // this corner belongs to split relative cell!
28819 for(MInt f = 0; f < 3; f++) {
28820 faceTMP = cornerFaceMapping[corn * 3 + f];
28821 nghbrCellId = m_solver->c_neighborId(cellId2, faceTMP);
28822 nghbrBndryId = m_solver->a_bndryId(nghbrCellId);
28823 if(nghbrBndryId < 0) mTerm(1, AT_, "strange split cell neighbor");
28824 if(!splitCell[nghbrBndryId] && !splitFace[nghbrBndryId]) {
28825 // neighbor is not ambigous or not split/split surface -> forward and backward connections
28826 // forward connection is already alright, establish backward connection:
28827 // m_solver->c_neighborId(nghbrCellId, opposite[faceTMP]) = cellId2;
28828 srfcId = m_bndryCells->a[nghbrBndryId].m_associatedSrfc[opposite[faceTMP]];
28829 if(m_solver->a_surfaceNghbrCellId(srfcId, 0) == nghbrCellId) {
28830 m_solver->a_surfaceNghbrCellId(srfcId, 1) = cellId2;
28831 } else {
28832 m_solver->a_surfaceNghbrCellId(srfcId, 0) = cellId2;
28833 }
28834 } else { // establish forward connection. backward connection will be established by neighboring cell
28835 if(splitCell[nghbrBndryId]) {
28836 // connect to correct split relative of neighbor cell, both neighbor and surface neighbors
28837 // m_solver->c_neighborId(cellId2, faceTMP) = cornerCellMapping[ambIds[nghbrBndryId] * 8 + corn +
28838 // neighborCorner[faceTMP]];
28839 srfcId = m_bndryCells->a[bndryId2].m_associatedSrfc[faceTMP];
28840 if(m_solver->a_surfaceNghbrCellId(srfcId, 0) == cellId2) {
28841 m_solver->a_surfaceNghbrCellId(srfcId, 1) = m_solver->c_neighborId(cellId2, faceTMP);
28842 } else {
28843 m_solver->a_surfaceNghbrCellId(srfcId, 0) = m_solver->c_neighborId(cellId2, faceTMP);
28844 }
28845 } else if(splitFace[nghbrBndryId]) {
28846 // nothing has to be done (neighbor is already correct, surface neighbors too)
28847 }
28848 }
28849 }
28850 } else {
28851 // non fluid corner, do nothing
28852 }
28853 }
28854 // correct neighbors on non-fluid sides
28855 // for(MInt f = 0; f < m_noDirs; f++ ){
28856 // if( m_bndryCells->a[bndryId2].m_externalFaces[f]){
28857 // m_solver->c_neighborId(cellId2, f) = -1;
28858 // }
28859 // }
28860 }
28861
28862 // second update connections cell
28863 for(MInt corn = 0; corn < 8; corn++) {
28864 if(cornerCellMapping[ambId * 8 + corn] == cellId) { // this corner belongs to split relative cell!
28865 for(MInt f = 0; f < 3; f++) {
28866 faceTMP = cornerFaceMapping[corn * 3 + f];
28867 nghbrCellId = m_solver->c_neighborId(cellId, faceTMP);
28868 nghbrBndryId = m_solver->a_bndryId(nghbrCellId);
28869 if(!splitCell[nghbrBndryId] && !splitFace[nghbrBndryId]) {
28870 // neighbor is not ambigous or not split/split surface -> forward and backward connections
28871 // forward connection is already alright, establish backward connection:
28872 // should already be ok as nghbr cell and srfc are connected to base cell
28873 } else { // establish forward connection. backward connection will be established by neighboring cell
28874 if(splitCell[nghbrBndryId]) {
28875 // connect to correct split relative of neighbor cell, both neighbor and surface neighbors
28876 // m_solver->c_neighborId(cellId, faceTMP) = cornerCellMapping[ambIds[nghbrBndryId] * 8
28877 //+ corn + neighborCorner[faceTMP]];
28878 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[faceTMP];
28879 if(m_solver->a_surfaceNghbrCellId(srfcId, 0) == cellId) {
28880 m_solver->a_surfaceNghbrCellId(srfcId, 1) = m_solver->c_neighborId(cellId, faceTMP);
28881 } else {
28882 m_solver->a_surfaceNghbrCellId(srfcId, 0) = m_solver->c_neighborId(cellId, faceTMP);
28883 }
28884 } else if(splitFace[nghbrBndryId]) {
28885 // nothing has to be done (neighbor is already correct, surface neighbors too)
28886 }
28887 }
28888 }
28889 } else {
28890 // non fluid corner, do nothing
28891 }
28892 }
28893 // // correct neighbors on non-fluid sides
28894 // for(MInt f = 0; f < m_noDirs; f++ ){
28895 // if( m_bndryCells->a[bndryId].m_externalFaces[f]){
28896 // m_solver->c_neighborId(cellId, f) = -1;
28897 // }
28898 // }
28899 }
28900
28901
28902 // b) Check cells which are no splitCells but with split surface
28903 if(!splitCell[bndryId] && splitFace[bndryId]) {
28904 for(MInt face = 0; face < 6; face++) {
28905 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[face];
28906 // srfcId < -1: split surface, srfcId = -1: non fluid side or non cut surface -> do nothing. srfcId >= 0:
28907 // normal cut surface, check neighbor
28908 if(srfcId < -1) {
28909 // split surface
28910 nghbrCellId = m_solver->c_neighborId(cellId, face);
28911 nghbrBndryId = m_solver->a_bndryId(nghbrCellId);
28912 // connect first surface
28913 splitCorner1 = m_splitSurfaces[-srfcId * 6 + 1];
28914 splitCorner2 = m_splitSurfaces[-srfcId * 6 + 2];
28915 if(splitCell[nghbrBndryId]) {
28916 if(m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6], 0) == cellId)
28917 m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6], 1) =
28918 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
28919 else
28920 m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6], 0) =
28921 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
28922 } else if(splitFace[nghbrBndryId]) {
28923 // nothing has to be done (neighbor is already correct, surface neighbors too)
28924 } else {
28925 // should not happen
28926 stringstream errorMessage;
28927 errorMessage << " Error in FvBndryCnd3D::createCutFaceMGC::this should not happen! ";
28928 mTerm(1, AT_, errorMessage.str());
28929 }
28930
28931 // connect second surface
28932 splitCorner1 = m_splitSurfaces[-srfcId * 6 + 3 + 1];
28933 splitCorner2 = m_splitSurfaces[-srfcId * 6 + 3 + 2];
28934 if(splitCell[nghbrBndryId]) {
28935 if(m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6 + 3], 0) == cellId)
28936 m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6 + 3], 1) =
28937 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
28938 else
28939 m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6 + 3], 0) =
28940 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
28941 } else if(splitFace[nghbrBndryId]) {
28942 // nothing has to be done (neighbor is already correct, surface neighbors too)
28943 } else {
28944 // should not happen
28945 }
28946 } else if(srfcId >= 0) {
28947 // regular surface, check neighboring cells!
28948 nghbrCellId = m_solver->c_neighborId(cellId, face);
28949 nghbrBndryId = m_solver->a_bndryId(nghbrCellId);
28950 if(splitCell[nghbrBndryId]) {
28951 for(MInt i = 0; i < 4; i++) {
28952 if(cornerCellMapping[ambIds[nghbrBndryId] * 8 + faceCornerMapping[face * 6 + i]] == -1) {
28953 // non fluid corner, do nothing!
28954 } else {
28955 // set face neighbor and srfc neighbors
28956 // m_solver->c_neighborId(cellId, face) = cornerCellMapping[ambIds[nghbrBndryId]*8 +
28957 // faceCornerMapping[ face * 6 + i]];
28958 if(m_solver->a_surfaceNghbrCellId(srfcId, 0) == cellId)
28959 m_solver->a_surfaceNghbrCellId(srfcId, 1) = m_solver->c_neighborId(cellId, face);
28960 else
28961 m_solver->a_surfaceNghbrCellId(srfcId, 0) = m_solver->c_neighborId(cellId, face);
28962 break;
28963 }
28964 }
28965 } else if(splitFace[nghbrBndryId]) {
28966 // nothing has to be done (neighbor is already correct, surface neighbors too)
28967 } else {
28968 // everything alright, nothing has to be done.
28969 }
28970 }
28971 }
28972 }
28973 }
28974
28975
28976 } else {
28977 for(MInt ambId = 0; ambId < noAmbiguousCells; ambId++) {
28978 MInt bndryId = ambiguousCells[ambId];
28979 cellId = m_bndryCells->a[bndryId].m_cellId;
28980
28981 // a) Check cells which are splitCells without split surface
28982 if(splitCell[bndryId] && !splitFace[bndryId]) {
28983 // first update connections split relative cell
28984 for(MInt child = 0; child < 3; child++) {
28985 bndryId2 = m_splitChildren[bndryId * 3 + child];
28986 if(bndryId2 == -1) break;
28987 cellId2 = m_bndryCells->a[bndryId2].m_cellId;
28988 MInt splitCellId = cellId2;
28989 for(MInt corn = 0; corn < 8; corn++) {
28990 if(cornerCellMapping[ambId * 8 + corn] == cellId2) { // this corner belongs to split relative cell!
28991 for(MInt f = 0; f < 3; f++) {
28992 faceTMP = cornerFaceMapping[corn * 3 + f];
28993 if(m_solver->a_hasProperty(cellId2, SolverCell::IsSplitClone)) {
28994 cellId2 = m_solver->m_splitChildToSplitCell.find(cellId2)->second;
28995 }
28996 nghbrCellId = m_solver->c_neighborId(cellId2, faceTMP);
28997 if(!m_solver->a_hasNeighbor(cellId2, faceTMP) || nghbrCellId < 0) continue;
28998 nghbrBndryId = m_solver->a_bndryId(nghbrCellId);
28999 if(!splitCell[nghbrBndryId] && !splitFace[nghbrBndryId]) {
29000 // neighbor is not ambigous or not split/split surface -> forward and backward connections
29001 // forward connection is already alright (in m_nghbrIds), update m_bndryNghbrs, establish backward
29002 // connection:
29003 m_bndryNghbrs[nghbrBndryId * m_noDirs * 2 + opposite[faceTMP] * 2] = splitCellId;
29004 m_bndryNghbrs[bndryId2 * m_noDirs * 2 + faceTMP * 2] = nghbrCellId;
29005 srfcId = m_bndryCells->a[nghbrBndryId].m_associatedSrfc[opposite[faceTMP]];
29006 if(srfcId > -1) {
29007 if(m_solver->a_surfaceNghbrCellId(srfcId, 0) == nghbrCellId) {
29008 m_solver->a_surfaceNghbrCellId(srfcId, 1) = splitCellId;
29009 } else {
29010 m_solver->a_surfaceNghbrCellId(srfcId, 0) = splitCellId;
29011 }
29012 } else
29013 cerr << "no surf found " << m_solver->a_isHalo(splitCellId) << " "
29014 << m_solver->a_isHalo(nghbrCellId) << endl;
29015 } else { // establish forward connection. backward connection will be established by neighboring cell
29016 if(splitCell[nghbrBndryId]) {
29017 // connect to correct split relative of neighbor cell, both neighbor and surface neighbors
29018 m_bndryNghbrs[bndryId2 * m_noDirs * 2 + faceTMP * 2] =
29019 cornerCellMapping[ambIds[nghbrBndryId] * 8 + corn + neighborCorner[faceTMP]];
29020 srfcId = m_bndryCells->a[bndryId2].m_associatedSrfc[faceTMP];
29021 if(srfcId > -1) {
29022 if(m_solver->a_surfaceNghbrCellId(srfcId, 0) == splitCellId) {
29023 m_solver->a_surfaceNghbrCellId(srfcId, 1) =
29024 m_bndryNghbrs[bndryId2 * m_noDirs * 2 + faceTMP * 2];
29025 } else {
29026 m_solver->a_surfaceNghbrCellId(srfcId, 0) =
29027 m_bndryNghbrs[bndryId2 * m_noDirs * 2 + faceTMP * 2];
29028 }
29029 }
29030 } else if(splitFace[nghbrBndryId]) {
29031 // nothing has to be done (neighbor is already correct, surface neighbors too) -> update
29032 // m_bndryNghbrs, backward connection will be established by neighboring cell
29033 m_bndryNghbrs[bndryId2 * m_noDirs * 2 + faceTMP * 2] = nghbrCellId;
29034 }
29035 }
29036 }
29037 } else {
29038 // non fluid corner, do nothing
29039 }
29040 }
29041 // correct neighbors on non-fluid sides
29042 for(MInt f = 0; f < m_noDirs; f++) {
29043 if(m_bndryCells->a[bndryId2].m_externalFaces[f]) m_bndryNghbrs[bndryId2 * m_noDirs * 2 + f * 2] = -1;
29044 }
29045 }
29046
29047 // second update connections cell
29048 for(MInt corn = 0; corn < 8; corn++) {
29049 if(cornerCellMapping[ambId * 8 + corn] == cellId) { // this corner belongs to split cell!
29050 for(MInt f = 0; f < 3; f++) {
29051 faceTMP = cornerFaceMapping[corn * 3 + f];
29052 nghbrCellId = m_solver->c_neighborId(cellId, faceTMP);
29053 nghbrBndryId = m_solver->a_bndryId(nghbrCellId);
29054 if(!splitCell[nghbrBndryId] && !splitFace[nghbrBndryId]) {
29055 // neighbor is not ambigous or not split/split surface -> forward and backward connections
29056 // forward connection is already alright, establish backward connection:
29057 // should already be ok as nghbr cell and srfc are connected to base cell
29058 // update m_bndryNghbrs
29059 m_bndryNghbrs[bndryId * m_noDirs * 2 + faceTMP * 2] = nghbrCellId;
29060 m_bndryNghbrs[nghbrBndryId * m_noDirs * 2 + opposite[faceTMP] * 2] = cellId;
29061 } else { // establish forward connection. backward connection will be established by neighboring cell
29062 if(splitCell[nghbrBndryId]) {
29063 // connect to correct split relative of neighbor cell, both neighbor and surface neighbors
29064 m_bndryNghbrs[bndryId * m_noDirs * 2 + faceTMP * 2] =
29065 cornerCellMapping[ambIds[nghbrBndryId] * 8 + corn + neighborCorner[faceTMP]];
29066 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[faceTMP];
29067 if(m_solver->a_surfaceNghbrCellId(srfcId, 0) == cellId) {
29068 m_solver->a_surfaceNghbrCellId(srfcId, 1) = m_bndryNghbrs[bndryId * m_noDirs * 2 + faceTMP * 2];
29069 } else {
29070 m_solver->a_surfaceNghbrCellId(srfcId, 0) = m_bndryNghbrs[bndryId * m_noDirs * 2 + faceTMP * 2];
29071 }
29072 } else if(splitFace[nghbrBndryId]) {
29073 m_bndryNghbrs[bndryId * m_noDirs * 2 + faceTMP * 2] = nghbrCellId;
29074 // nothing has to be done (neighbor is already correct, surface neighbors too)
29075 }
29076 }
29077 }
29078 } else {
29079 // non fluid corner, do nothing
29080 }
29081 }
29082 // correct neighbors on non-fluid sides
29083 for(MInt f = 0; f < m_noDirs; f++) {
29084 if(m_bndryCells->a[bndryId].m_externalFaces[f]) m_bndryNghbrs[bndryId * m_noDirs * 2 + f * 2] = -1;
29085 }
29086 }
29087
29088
29089 // b) Check cells which are no splitCells but with split surface
29090 if(!splitCell[bndryId] && splitFace[bndryId]) {
29091 for(MInt face = 0; face < 6; face++) {
29092 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[face];
29093 // srfcId < -1: split surface, srfcId = -1: non fluid side or non cut surface -> do nothing. srfcId >= 0:
29094 // normal cut surface, check neighbor
29095 if(srfcId < -1) {
29096 // split surface
29097 nghbrCellId = m_solver->c_neighborId(cellId, face);
29098 nghbrBndryId = m_solver->a_bndryId(nghbrCellId);
29099 // connect first surface
29100 splitCorner1 = m_splitSurfaces[-srfcId * 6 + 1];
29101 splitCorner2 = m_splitSurfaces[-srfcId * 6 + 2];
29102 if(splitCell[nghbrBndryId]) {
29103 m_bndryNghbrs[bndryId * m_noDirs * 2 + face * 2] =
29104 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
29105 if(m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6], 0) == cellId)
29106 m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6], 1) =
29107 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
29108 else
29109 m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6], 0) =
29110 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
29111 } else if(splitFace[nghbrBndryId]) {
29112 // nothing has to be done (neighbor is already correct, surface neighbors too)
29113 m_bndryNghbrs[bndryId * m_noDirs * 2 + face * 2] = nghbrCellId;
29114 } else {
29115 // should not happen
29116 stringstream errorMessage;
29117 errorMessage << " Error in FvBndryCnd3D::createCutFaceMGC::this should not happen! ";
29118 mTerm(1, AT_, errorMessage.str());
29119 }
29120
29121 // connect second surface
29122 splitCorner1 = m_splitSurfaces[-srfcId * 6 + 3 + 1];
29123 splitCorner2 = m_splitSurfaces[-srfcId * 6 + 3 + 2];
29124 if(splitCell[nghbrBndryId]) {
29125 // add second split neighbor as neighbor
29126 m_bndryNghbrs[bndryId * m_noDirs * 2 + face * 2 + 1] =
29127 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
29128 if(m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6 + 3], 0) == cellId)
29129 m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6 + 3], 1) =
29130 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
29131 else
29132 m_solver->a_surfaceNghbrCellId(m_splitSurfaces[-srfcId * 6 + 3], 0) =
29133 cornerCellMapping[ambIds[nghbrBndryId] * 8 + splitCorner2];
29134 } else if(splitFace[nghbrBndryId]) {
29135 // nothing has to be done (neighbor is already correct, surface neighbors too)
29136 m_bndryNghbrs[bndryId * m_noDirs * 2 + face * 2 + 1] = nghbrCellId;
29137 } else {
29138 // should not happen
29139 stringstream errorMessage;
29140 errorMessage << " Error in FvBndryCnd3D::createCutFaceMGC::this should not happen! ";
29141 mTerm(1, AT_, errorMessage.str());
29142 }
29143 } else if(srfcId >= 0) {
29144 // regular surface, check neighboring cells!
29145 nghbrCellId = m_solver->c_neighborId(cellId, face);
29146 nghbrBndryId = m_solver->a_bndryId(nghbrCellId);
29147 if(splitCell[nghbrBndryId]) {
29148 for(MInt i = 0; i < 4; i++) {
29149 if(cornerCellMapping[ambIds[nghbrBndryId] * 8 + faceCornerMapping[face * 6 + i]] == -1) {
29150 // non fluid corner, do nothing!
29151 } else {
29152 // set face neighbor and srfc neighbors
29153 m_bndryNghbrs[bndryId * m_noDirs * 2 + face * 2] =
29154 cornerCellMapping[ambIds[nghbrBndryId] * 8 + faceCornerMapping[face * 6 + i]];
29155 if(m_solver->a_surfaceNghbrCellId(srfcId, 0) == cellId)
29156 m_solver->a_surfaceNghbrCellId(srfcId, 1) = m_bndryNghbrs[bndryId * m_noDirs * 2 + face * 2];
29157 else
29158 m_solver->a_surfaceNghbrCellId(srfcId, 0) = m_bndryNghbrs[bndryId * m_noDirs * 2 + face * 2];
29159 break;
29160 }
29161 }
29162 } else {
29163 // everything alright, nothing has to be done.
29164 m_bndryNghbrs[bndryId * m_noDirs * 2 + face * 2] = nghbrCellId;
29165 }
29166 }
29167 }
29168 }
29169 }
29170
29171 // correct nonFluidSide neighbors
29172 if(keepNghbrs) {
29173 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
29174 cellId = m_bndryCells->a[bndryId].m_cellId;
29175 for(MInt f = 0; f < m_noDirs; f++) {
29176 if(m_bndryCells->a[bndryId].m_externalFaces[f]) {
29177 m_bndryNghbrs[bndryId * m_noDirs * 2 + f * 2] = -1;
29178 m_bndryNghbrs[bndryId * m_noDirs * 2 + f * 2 + 1] = -1;
29179 }
29180 }
29181 }
29182 }
29183 }
29184
29185#ifndef NDEBUG
29186 for(MInt i = 0; i < 15; i++) {
29187 cerr << "Occurences case " << i << " : " << presentCases[i] << " times" << endl;
29188 }
29189 cerr << "---------------------------------------------------------------" << endl << endl << endl;
29190 cerr << "Number Surfaces: " << m_solver->a_noSurfaces() << endl;
29191#endif
29192}
29193
29204template <MInt nDim, class SysEqn>
29205template <class _, std::enable_if_t<nDim == 3, _*>>
29207 TRACE();
29208
29209 MInt bndryId2, cellId2, bndryId;
29210 //-----------------------------------------
29211 MInt splitId = m_solver->m_splitCells.size();
29212 if(noSplitChilds > 1) {
29213 splitId = splitId - 1;
29214 m_solver->m_splitChilds[splitId].resize(noSplitChilds);
29215 } else {
29216 m_solver->m_splitCells.push_back(cellId);
29217 m_solver->m_splitChilds.resize(m_solver->m_splitCells.size());
29218 m_solver->m_splitChilds[splitId].resize(noSplitChilds);
29219 }
29220
29221 bndryId = m_solver->a_bndryId(cellId);
29222 bndryId2 = m_bndryCells->size();
29223 cellId2 = m_solver->a_noCells();
29224
29225 m_bndryCells->append();
29226 m_cells.append();
29227 m_solver->m_totalnosplitchilds++;
29228 ASSERT(cellId2 == m_solver->a_noCells() - 1, "Error in the cell-count, for splitchilds!");
29229
29230 m_solver->m_splitChilds[splitId][noSplitChilds - 1] = cellId2;
29231 m_solver->m_splitChildToSplitCell.insert(pair<MInt, MInt>(cellId2, cellId));
29232
29233 m_bndryCells->a[bndryId2].m_cellId = cellId2;
29234 m_solver->a_bndryId(cellId2) = bndryId2;
29235 m_solver->a_bndryId(cellId2) = bndryId2;
29236
29237 for(MInt face = 0; face < 6; face++) {
29238 m_bndryCells->a[bndryId2].m_associatedSrfc[face] = -1;
29239 m_bndryCells->a[bndryId2].m_externalFaces[face] = false;
29240 }
29241
29242 m_bndryCells->a[bndryId2].m_srfcs[0]->m_bndryCndId = m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
29243 m_bndryCells->a[bndryId2].m_srfcs[0]->m_noCutPoints = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
29244
29245 for(MInt i = 0; i < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; i++) {
29246 m_bndryCells->a[bndryId2].m_srfcs[0]->m_cutEdge[i] = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[i];
29247 m_bndryCells->a[bndryId2].m_srfcs[0]->m_bodyId[i] = m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[i];
29248 for(MInt j = 0; j < nDim; j++)
29249 m_bndryCells->a[bndryId2].m_srfcs[0]->m_cutCoordinates[i][j] =
29250 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[i][j];
29251 }
29252
29253 for(MInt i = 0; i < nDim; i++) {
29254 m_solver->a_coordinate(cellId2, i) = m_solver->a_coordinate(cellId, i);
29255 }
29256 m_solver->a_isInterface(cellId2) = m_solver->a_isInterface(cellId);
29257
29258 m_solver->a_level(cellId2) = m_solver->a_level(cellId);
29259
29260 m_solver->a_copyPropertiesSolver(cellId, cellId2);
29261
29262 m_solver->a_hasProperty(cellId2, SolverCell::IsSplitCell) = false;
29263 m_solver->a_hasProperty(cellId2, SolverCell::IsSplitChild) = false;
29264 m_solver->a_hasProperty(cellId2, SolverCell::IsSplitClone) = true;
29265
29266 m_solver->a_hasProperty(cellId, SolverCell::IsSplitCell) = false;
29267 m_solver->a_hasProperty(cellId, SolverCell::IsSplitChild) = false;
29268 m_solver->a_hasProperty(cellId, SolverCell::IsSplitClone) = false;
29269
29270
29271 return cellId2;
29272}
29273
29274#define plotall
29275
29276// ---------------------------------------------------------------------------------
29277// --------------- output routines to check the cut cell generation --------------
29278// ---------------------------------------------------------------------------------
29279
29280/*
29281 * \author Daniel Hartmann, July 2007
29282 *
29283 */
29284template <MInt nDim, class SysEqn>
29285template <class _, std::enable_if_t<nDim == 3, _*>>
29286void FvBndryCndXD<nDim, SysEqn>::writeStlFileOfCell(MInt cellId, const MChar* fileName) {
29287 TRACE();
29288
29289 MInt spaceId, spaceId1, spaceId2, sideId;
29290 MFloat cellLength = m_solver->grid().cellLengthAtCell(cellId);
29291 MFloat point1[3] = {0, 0, 0};
29292 MFloat point2[3] = {0, 0, 0};
29293 MFloat point3[3] = {0, 0, 0};
29294 MFloat point4[3] = {0, 0, 0};
29295 ofstream ofl;
29296 ofl.open(fileName);
29297
29298 if(ofl) {
29299 // set fixed floating point output
29300 ofl.setf(ios::fixed);
29301 ofl.precision(7);
29302
29303 ofl << "solid amazonas cell " << cellId << endl;
29304 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
29305 spaceId = dirId / 2;
29306 sideId = dirId % 2;
29307 spaceId1 = (spaceId + 1) % nDim;
29308 spaceId2 = (spaceId1 + 1) % nDim;
29309 point1[spaceId] = m_solver->a_coordinate(cellId, spaceId) + ((MFloat)sideId - F1B2) * cellLength;
29310 point2[spaceId] = point1[spaceId];
29311 point3[spaceId] = point1[spaceId];
29312 point4[spaceId] = point1[spaceId];
29313 point1[spaceId1] = m_solver->a_coordinate(cellId, spaceId1) - F1B2 * cellLength;
29314 point2[spaceId1] = m_solver->a_coordinate(cellId, spaceId1) - F1B2 * cellLength;
29315 point3[spaceId1] = m_solver->a_coordinate(cellId, spaceId1) + F1B2 * cellLength;
29316 point4[spaceId1] = m_solver->a_coordinate(cellId, spaceId1) + F1B2 * cellLength;
29317 point1[spaceId2] = m_solver->a_coordinate(cellId, spaceId2) - F1B2 * cellLength;
29318 point2[spaceId2] = m_solver->a_coordinate(cellId, spaceId2) + F1B2 * cellLength;
29319 point3[spaceId2] = m_solver->a_coordinate(cellId, spaceId2) - F1B2 * cellLength;
29320 point4[spaceId2] = m_solver->a_coordinate(cellId, spaceId2) + F1B2 * cellLength;
29321 if(dirId == 0) ofl << " facet normal -1.0 0.0 0.0 " << endl;
29322 if(dirId == 1) ofl << " facet normal 1.0 0.0 0.0 " << endl;
29323 if(dirId == 2) ofl << " facet normal 0.0 -1.0 0.0 " << endl;
29324 if(dirId == 3) ofl << " facet normal 0.0 1.0 0.0 " << endl;
29325 if(dirId == 4) ofl << " facet normal 0.0 0.0 -1.0 " << endl;
29326 if(dirId == 5) ofl << " facet normal 0.0 0.0 1.0 " << endl;
29327 ofl << " outer loop" << endl;
29328 ofl << " vertex " << point1[0] << " " << point1[1] << " " << point1[2] << endl;
29329 ofl << " vertex " << point2[0] << " " << point2[1] << " " << point2[2] << endl;
29330 ofl << " vertex " << point3[0] << " " << point3[1] << " " << point3[2] << endl;
29331 ofl << " endloop" << endl;
29332 ofl << " endfacet" << endl;
29333 if(dirId == 0) ofl << " facet normal -1.0 0.0 0.0 " << endl;
29334 if(dirId == 1) ofl << " facet normal 1.0 0.0 0.0 " << endl;
29335 if(dirId == 2) ofl << " facet normal 0.0 -1.0 0.0 " << endl;
29336 if(dirId == 3) ofl << " facet normal 0.0 1.0 0.0 " << endl;
29337 if(dirId == 4) ofl << " facet normal 0.0 0.0 -1.0 " << endl;
29338 if(dirId == 5) ofl << " facet normal 0.0 0.0 1.0 " << endl;
29339 ofl << " outer loop" << endl;
29340 ofl << " vertex " << point4[0] << " " << point4[1] << " " << point4[2] << endl;
29341 ofl << " vertex " << point2[0] << " " << point2[1] << " " << point2[2] << endl;
29342 ofl << " vertex " << point3[0] << " " << point3[1] << " " << point3[2] << endl;
29343 ofl << " endloop" << endl;
29344 ofl << " endfacet" << endl;
29345 }
29346 ofl << "endsolid amazonas cell " << cellId << endl;
29347 }
29348}
29349
29350//----------------------------------------------------------------------------
29351
29366template <MInt nDim, class SysEqn>
29367template <class _, std::enable_if_t<nDim == 3, _*>>
29369 TRACE();
29370
29371 static constexpr MInt cornerIndices[8][3] = {{-1, -1, -1}, {1, -1, -1}, {-1, 1, -1}, {1, 1, -1},
29372 {-1, -1, 1}, {1, -1, 1}, {-1, 1, 1}, {1, 1, 1}};
29373 static constexpr MInt cornersSOLVERtoMC[8] = {1, 2, 0, 3, 5, 6, 4, 7};
29374 static constexpr MInt edgesMCtoSOLVER[12] = {0, 2, 1, 3, 4, 6, 5, 7, 10, 8, 9, 11};
29375
29376 unsigned char outcode_MC = 0;
29377 MInt noCells = m_bndryCells->size();
29378 MInt cellId;
29379 MFloat corner[8][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
29380 MInt currentCase;
29381 MBool currentOutcode = false;
29382 MInt currentSubCase;
29383 MInt subCaseDummy;
29384 MInt p_1;
29385 MInt p_2;
29386 MInt p_3;
29387 MInt p_0s;
29388 MInt p_1s;
29389 MInt p_2s;
29390 MInt p_3s;
29391 MInt p_0ss;
29392 MInt p_1ss;
29393 MInt p_2ss;
29394 MInt p_3ss;
29395 MInt p_1sss;
29396 MInt p_2sss;
29397 MInt p_3sss;
29398 MInt pP[7];
29399 MInt cutDummy;
29400 MInt cutPoints[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
29401 MInt noCutPoints = 0;
29402 MInt noPlotCells = 0;
29403 const MChar* fileName = "cutSurface_";
29404 stringstream fileName2;
29405 fileName2 << fileName << domainId() << ".vtk";
29406 ofstream ofl;
29407 MInt pointsCount = 0;
29408 MIntScratchSpace mcCases_scratch(noCells, AT_, "mcCases_scratch");
29409 MIntScratchSpace subCases_scratch(noCells, AT_, "subCases_scratch");
29410 MInt* mcCases = mcCases_scratch.getPointer();
29411 MInt* subCases = subCases_scratch.getPointer();
29412 for(MInt i = 0; i < m_bndryCells->size(); i++) {
29413 mcCases[i] = -1;
29414 subCases[i] = -1;
29415 }
29416 MIntScratchSpace ambiguousCells_scratch(noCells, AT_, "ambiguousCells_scratch");
29417 MIntScratchSpace disambiguation_scratch(noCells, AT_, "disambiguation_scratch");
29418 MInt* ambiguousCells = ambiguousCells_scratch.getPointer();
29419 MInt* disambiguation = disambiguation_scratch.getPointer();
29420 MInt noAmbiguousCells = 0;
29421 MInt bdAmbId;
29422 MInt faceTMP = std::numeric_limits<MInt>::min();
29423 static constexpr MInt facesMCtoSOLVER[6] = {0, 2, 1, 3, 4, 5};
29424 MInt nghbrCellId;
29425 stack<MInt> ambStack;
29426 MInt case6_2_counter = 0;
29427 MInt case7_3l_counter = 0;
29428 MInt case7_3h_counter = 0;
29429 MInt case3_2_counter = 0;
29430 MInt disamb_tmp;
29431 MIntScratchSpace levelSetCornerSigns(8, AT_, "levelSetCornerSigns");
29432
29433
29434 //-----------------------------------------
29435 cerr << " begin of plot routine! " << endl;
29436
29437 // 1. Determine Case/Subcase of each bndry cell
29438 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
29439 cellId = m_bndryCells->a[bndryId].m_cellId;
29440 m_bndryCells->a[bndryId].m_noSrfcs = 1;
29441 outcode_MC = 0;
29442
29443 if(m_solver->c_noChildren(cellId) > 0) {
29444 continue;
29445 }
29446 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
29447
29448 // get In/Outcode of the corners of the voxel
29449 // 0 -> Corner is outside Fluid Domain
29450 // 1 -> Corner is inside Fluid Domain or on Boundary
29451 for(MInt j = 0; j < 8; j++) {
29452 for(MInt dim = 0; dim < nDim; dim++) {
29453 corner[j][dim] = m_solver->a_coordinate(cellId, dim)
29454 + cornerIndices[j][dim] * F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
29455 }
29456 currentOutcode = !((MBool)m_solver->m_geometry->pointIsInside2(corner[j]));
29457 if(currentOutcode) outcode_MC = outcode_MC | (1 << cornersSOLVERtoMC[j]);
29458 }
29459
29460 // Determine Case and check if case is implemented
29461 currentCase = (MInt)cases[outcode_MC][0];
29462 cerr << " cell " << cellId << " bndryId " << bndryId << " currentCase " << currentCase << endl;
29463 mcCases[bndryId] = currentCase;
29464 currentSubCase = (MInt)cases[outcode_MC][1];
29465 subCases[bndryId] = currentSubCase;
29466 if(!caseStatesSTL[currentCase][0]) {
29467 cerr << "Error in plotSurface: Case not implemented: " << currentCase << endl;
29468 continue;
29469 }
29470 }
29471
29472 // 2. Determine ambiguous cells
29473 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
29474 disambiguation[bndryId] = -1;
29475 cellId = m_bndryCells->a[bndryId].m_cellId;
29476 if(m_solver->c_noChildren(cellId) > 0) {
29477 continue;
29478 }
29479 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
29480 if(!caseStatesSTL[mcCases[bndryId]][0]) {
29481 continue;
29482 }
29483 if(!caseStatesSTL[mcCases[bndryId]][1]) { // ambiguous case
29484 ambiguousCells[noAmbiguousCells++] = bndryId;
29485 cerr << " cell " << bndryId << " is ambiguous " << endl;
29486 }
29487 }
29488
29489 // 3. Determine case of ambiguous cells by states of surface midpoints - new!
29490 for(MInt ambId = 0; ambId < noAmbiguousCells; ambId++) {
29491 bdAmbId = ambiguousCells[ambId];
29492 disambiguation[bdAmbId] = 0;
29493 cellId = m_bndryCells->a[bdAmbId].m_cellId;
29494 currentCase = mcCases[bdAmbId];
29495 currentSubCase = subCases[bdAmbId];
29496
29497 MInt faceMax = 0;
29498 switch(currentCase) {
29499 case 3:
29500 faceMax = 1;
29501 break;
29502 case 4:
29503 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29504 continue;
29505 case 6:
29506 faceMax = 1;
29507 break;
29508 case 7:
29509 faceMax = 3;
29510 break;
29511 case 10:
29512 faceMax = 2;
29513 break;
29514 case 12:
29515 faceMax = 2;
29516 break;
29517 default: {
29518 stringstream errorMessage;
29519 errorMessage << " Error in FvBndryCndXD::plotSurface: cell in ambigous cells does not have an ambiguous "
29520 "case... cellId: "
29521 << cellId << " case: " << currentCase << " bndryId: " << bdAmbId << endl;
29522 writeStlFileOfCell(cellId, "errorcell.stl");
29523 mTerm(1, AT_, errorMessage.str());
29524 }
29525 }
29526
29527 for(MInt i = 0; i < faceMax; i++) {
29528 // compute ambigous face centroid and check if it is fluid or solid. If fluid, choose connected, else choose
29529 // separated.
29530 switch(currentCase) {
29531 case 3:
29532 faceTMP = facesMCtoSOLVER[tiling3_1STL[currentSubCase][2 + i]];
29533 break;
29534 case 6:
29535 faceTMP = facesMCtoSOLVER[tiling6_1STL[currentSubCase][2 + i]];
29536 break;
29537 case 7:
29538 faceTMP = facesMCtoSOLVER[tiling7_1STL[currentSubCase][3 + i]];
29539 break;
29540 case 10:
29541 faceTMP = facesMCtoSOLVER[tiling10_1STL[currentSubCase][2 + i]];
29542 break;
29543 case 12:
29544 faceTMP = facesMCtoSOLVER[tiling12_1STL[currentSubCase][2 + i]];
29545 break;
29546 default: {
29547 stringstream errorMessage;
29548 errorMessage << " Error in FvBndryCndXD::plotSurface: cell in ambigous cells does not have an ambiguous "
29549 "case... cellId: "
29550 << cellId << " case: " << currentCase << " bndryId: " << bdAmbId << endl;
29551 mTerm(1, AT_, errorMessage.str());
29552 }
29553 }
29554 nghbrCellId = m_solver->c_neighborId(cellId, faceTMP);
29555 if(nghbrCellId < 0) {
29556 stringstream errorMessage;
29557 errorMessage << " Error in FvBndryCndXD::plotSurface: no neighbor in ambiguous direction... exiting." << endl;
29558 errorMessage << " cellId: " << cellId << ", ambiguous face: " << faceTMP << endl;
29559 writeStlFileOfCell(cellId, "errorcell.stl");
29560 mTerm(1, AT_, errorMessage.str());
29561 }
29562
29563 // compute ambiguous face centroid
29564 // returns true if point is not located in fluid domain, false if it is located in the fluid domain
29565 for(MInt dim = 0; dim < nDim; dim++) {
29566 corner[0][dim] = (m_solver->a_coordinate(cellId, dim) + m_solver->a_coordinate(nghbrCellId, dim)) * F1B2;
29567 }
29568 currentOutcode = (MBool)m_solver->m_geometry->pointIsInside2(corner[0]);
29569
29570 if(currentOutcode) {
29571 disambiguation[bdAmbId] += IPOW2(faceMax - i - 1);
29572 }
29573 }
29574
29575 // find correct number of surfaces etc.
29576 switch(currentCase) {
29577 case 3: {
29578 if(disambiguation[bdAmbId] == 0) {
29579 if(currentSubCase < 12) {
29580 m_bndryCells->a[bdAmbId].m_noSrfcs = 1;
29581 // m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29582 // case3_2_counter++;
29583 } else {
29584 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29585 }
29586 }
29587 if(disambiguation[bdAmbId] == 1) {
29588 if(currentSubCase < 12) {
29589 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29590 } else {
29591 m_bndryCells->a[bdAmbId].m_noSrfcs = 1;
29592 // m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29593 // case3_2_counter++;
29594 }
29595 }
29596 break;
29597 }
29598 case 6: {
29599 if(disambiguation[bdAmbId] == 0) {
29600 if(currentSubCase < 24) {
29601 m_bndryCells->a[bdAmbId].m_noSrfcs = 3;
29602 case6_2_counter++;
29603 } else {
29604 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29605 }
29606 }
29607 if(disambiguation[bdAmbId] == 1) {
29608 if(currentSubCase < 24) {
29609 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29610 } else {
29611 m_bndryCells->a[bdAmbId].m_noSrfcs = 3;
29612 case6_2_counter++;
29613 }
29614 }
29615 break;
29616 }
29617 case 7: {
29618 // find correct cell type for myself
29619 if(currentSubCase < 8) {
29620 switch(disambiguation[bdAmbId]) {
29621 case 0:
29622 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29623 break;
29624 case 1:
29625 case 2:
29626 case 4:
29627 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29628 case7_3l_counter++;
29629 break;
29630 case 3:
29631 case 5:
29632 case 6:
29633 m_bndryCells->a[bdAmbId].m_noSrfcs = 2; // eig. 2 x 1
29634 break;
29635 case 7:
29636 m_bndryCells->a[bdAmbId].m_noSrfcs = 3; // eig. 3 x 1
29637 break;
29638 default: {
29639 stringstream errorMessage;
29640 errorMessage << "ERROR: Switch variable 'disambiguation[bdAmbId]' with value " << disambiguation[bdAmbId]
29641 << " not matching any case." << endl;
29642 mTerm(1, AT_, errorMessage.str());
29643 }
29644 }
29645 } else {
29646 switch(disambiguation[bdAmbId]) {
29647 case 0:
29648 m_bndryCells->a[bdAmbId].m_noSrfcs = 3;
29649 break;
29650 case 1:
29651 case 2:
29652 case 4:
29653 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29654 break;
29655 case 3:
29656 case 5:
29657 case 6:
29658 m_bndryCells->a[bdAmbId].m_noSrfcs = 3;
29659 case7_3h_counter++;
29660 break;
29661 case 7:
29662 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29663 break;
29664 default: {
29665 stringstream errorMessage;
29666 errorMessage << "ERROR: Switch variable 'disambiguation[bdAmbId]' with value " << disambiguation[bdAmbId]
29667 << " not matching any case." << endl;
29668 mTerm(1, AT_, errorMessage.str());
29669 }
29670 }
29671 }
29672 break;
29673 }
29674 case 10: {
29675 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29676 break;
29677 }
29678 case 12: {
29679 m_bndryCells->a[bdAmbId].m_noSrfcs = 2;
29680 break;
29681 }
29682 default: {
29683 stringstream errorMessage;
29684 errorMessage << " Error in FvBndryCndXD::plotSurface: cell in ambigous cells does not have an ambiguous "
29685 "case... cellId: "
29686 << cellId << " case: " << currentCase << " bndryId: " << bdAmbId << endl;
29687 writeStlFileOfCell(cellId, "errorcell.stl");
29688 mTerm(1, AT_, errorMessage.str());
29689 }
29690 }
29691 }
29692
29693 // 6. Count cut points and surfaces
29694#ifdef plotall
29695 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
29696#else
29697 for(MInt ambId = 0; ambId < noAmbiguousCells; ambId++) {
29698 MInt bndryId = ambiguousCells[ambId];
29699#endif
29700 cellId = m_bndryCells->a[bndryId].m_cellId;
29701 if(m_solver->c_noChildren(cellId) > 0) continue;
29702 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
29703 noCutPoints += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
29704 noPlotCells += m_bndryCells->a[bndryId].m_noSrfcs;
29705 }
29706
29707 // 7. Plot cut surfaces
29708 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
29709
29710 if(ofl) {
29711 // set fixed floating point output
29712 ofl.setf(ios::fixed);
29713 ofl.precision(7);
29714
29715 ofl << "# vtk DataFile Version 3.0" << endl
29716 << "MAIAD cutsurface file" << endl
29717 << "ASCII" << endl
29718 << endl
29719 << "DATASET UNSTRUCTURED_GRID" << endl
29720 << endl;
29721
29722 ofl << "POINTS " << noCutPoints << " float" << endl;
29723
29724 // write out cut coordiates of all boundary cells
29725#ifdef plotall
29726 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
29727#else
29728 for(MInt ambId = 0; ambId < noAmbiguousCells; ambId++) {
29729 MInt bndryId = ambiguousCells[ambId];
29730#endif
29731
29732 cellId = m_bndryCells->a[bndryId].m_cellId;
29733 outcode_MC = 0;
29734
29735 if(m_solver->c_noChildren(cellId) > 0) {
29736 continue;
29737 }
29738 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
29739
29740 for(MInt cutPoint = 0; cutPoint < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cutPoint++) {
29741 for(MInt i = 0; i < 3; i++)
29742 ofl << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoint][i] << " ";
29743 ofl << endl;
29744 }
29745 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints != caseCutPoints[mcCases[bndryId]]) {
29746 stringstream errorMessage;
29747 errorMessage << "Problem in FvBndryCndXD::plotSurface: "
29748 << " cell " << bndryId << " case " << mcCases[bndryId] << endl;
29749 errorMessage << " cell with subcase " << subCases[bndryId] << " has "
29750 << m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints << " cutpoints instead of "
29751 << caseCutPoints[mcCases[bndryId]] << endl;
29752 writeStlFileOfCell(cellId, "problemacell.stl");
29753 mTerm(1, AT_, errorMessage.str());
29754 }
29755
29756 ofl << endl;
29757 }
29758
29759 ofl << endl;
29760 ofl << "CELLS " << noPlotCells << " "
29761 << noPlotCells + noCutPoints + case6_2_counter * 4 + case7_3l_counter * 2 + case7_3h_counter * 4
29762 + case3_2_counter * 2
29763 << endl;
29764
29765
29766 // determine polygonal structure of the cut faces and write polygons defined by point indices out
29767#ifdef plotall
29768 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
29769#else
29770 for(MInt ambId = 0; ambId < noAmbiguousCells; ambId++) {
29771 MInt bndryId = ambiguousCells[ambId];
29772#endif
29773 cellId = m_bndryCells->a[bndryId].m_cellId;
29774
29775 if(m_solver->c_noChildren(cellId) > 0) {
29776 continue;
29777 }
29778 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
29779
29780 for(MInt cutPoint = 0; cutPoint < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cutPoint++) {
29781 cutPoints[m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPoint]] = cutPoint;
29782 }
29783
29784 for(MInt i = 0; i < 8; i++) {
29785 for(MInt dim = 0; dim < nDim; dim++) {
29786 corner[i][dim] = m_solver->a_coordinate(cellId, dim)
29787 + cornerIndices[i][dim] * F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
29788 }
29789 }
29790
29791 currentCase = mcCases[bndryId];
29792 currentSubCase = subCases[bndryId];
29793
29794 if(!caseStatesSTL[currentCase][0]) {
29795 cerr << "Error in plotSurface: Case not implemented: " << currentCase << endl;
29796 continue;
29797 }
29798
29799 if(!caseStatesSTL[currentCase][1]) {
29800 switch(currentCase) {
29801 case 3: {
29802 if(disambiguation[bndryId] == -1) {
29803 stringstream errorMessage;
29804 errorMessage << "Error in plotSurface: case 3 cell not disambiguated! cell: " << cellId << ", exiting!"
29805 << endl;
29806 mTerm(1, AT_, errorMessage.str());
29807 }
29808 if((currentSubCase < 12 && disambiguation[bndryId] == 0)
29809 || (currentSubCase >= 12 && disambiguation[bndryId] == 1)) { // case 3.2
29810 cerr << " plotting case 3.2 - 1 surface " << endl;
29811 // continue;
29812 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][2]];
29813 p_1 = cutPoints[cutDummy];
29814 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][3]];
29815 p_2 = cutPoints[cutDummy];
29816 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][4]];
29817 p_3 = cutPoints[cutDummy];
29818 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][5]];
29819 p_1s = cutPoints[cutDummy];
29820 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][6]];
29821 p_2s = cutPoints[cutDummy];
29822 cutDummy = edgesMCtoSOLVER[tiling3_2STL[currentSubCase][7]];
29823 p_3s = cutPoints[cutDummy];
29824
29825 pP[0] = p_1;
29826 pP[1] = p_2;
29827 pP[2] = p_3;
29828 pP[3] = p_1s;
29829 pP[4] = p_2s;
29830 pP[5] = p_3s;
29831 pP[6] = p_1;
29832
29833 ofl << 6 << " ";
29834
29835 for(MInt i = 0; i < 6; i++) {
29836 ofl << pP[i] + pointsCount << " ";
29837 }
29838 ofl << endl;
29839
29840 // pP[0] = p_2;
29841 // pP[1] = p_3;
29842 // pP[2] = p_1s;
29843 // pP[3] = p_2s;
29844 //
29845 // ofl << 4 << " ";
29846 //
29847 // for(MInt i = 0; i < 4; i++){
29848 // ofl << pP[i] + pointsCount << " ";
29849 // }
29850 // ofl << endl;
29851 //
29852 // pP[0] = p_2s;
29853 // pP[1] = p_3s;
29854 // pP[2] = p_1;
29855 // pP[3] = p_2;
29856 //
29857 // ofl << 4 << " ";
29858 //
29859 // for(MInt i = 0; i < 4; i++){
29860 // ofl << pP[i] + pointsCount << " ";
29861 // }
29862 // ofl << endl;
29863 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
29864
29865 } else if((currentSubCase < 12 && disambiguation[bndryId] == 1)
29866 || (currentSubCase >= 12 && disambiguation[bndryId] == 0)) {
29867 cerr << " plotting case 3.1 - 2 surfaces " << endl;
29868 // 1st Pyramid + 1st cutFace
29869 subCaseDummy = tiling3_1STL[currentSubCase][0];
29870 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
29871 pP[0] = cutPoints[cutDummy];
29872 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
29873 pP[1] = cutPoints[cutDummy];
29874 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
29875 pP[2] = cutPoints[cutDummy];
29876
29877 ofl << 3 << " ";
29878
29879 for(MInt i = 0; i < 3; i++) {
29880 ofl << pP[i] + pointsCount << " ";
29881 }
29882 ofl << endl;
29883
29884 // 2nd Pyramid + 2nd cutFace
29885 subCaseDummy = tiling3_1STL[currentSubCase][1];
29886 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
29887 pP[0] = cutPoints[cutDummy];
29888 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
29889 pP[1] = cutPoints[cutDummy];
29890 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
29891 pP[2] = cutPoints[cutDummy];
29892
29893 ofl << 3 << " ";
29894
29895 for(MInt i = 0; i < 3; i++) {
29896 ofl << pP[i] + pointsCount << " ";
29897 }
29898 ofl << endl;
29899 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
29900 }
29901 break;
29902 }
29903 case 4: {
29904 cerr << " plotting case 4 - 2 surfaces " << endl;
29905 // 1st Pyramid + 1st cutFace
29906 subCaseDummy = tiling4_1STL[currentSubCase][0];
29907 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
29908 pP[0] = cutPoints[cutDummy];
29909 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
29910 pP[1] = cutPoints[cutDummy];
29911 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
29912 pP[2] = cutPoints[cutDummy];
29913
29914 ofl << 3 << " ";
29915
29916 for(MInt i = 0; i < 3; i++) {
29917 ofl << pP[i] + pointsCount << " ";
29918 }
29919 ofl << endl;
29920
29921 // 2nd Pyramid + 2nd cutFace
29922 subCaseDummy = tiling4_1STL[currentSubCase][1];
29923 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
29924 pP[0] = cutPoints[cutDummy];
29925 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
29926 pP[1] = cutPoints[cutDummy];
29927 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
29928 pP[2] = cutPoints[cutDummy];
29929
29930 ofl << 3 << " ";
29931
29932 for(MInt i = 0; i < 3; i++) {
29933 ofl << pP[i] + pointsCount << " ";
29934 }
29935 ofl << endl;
29936 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
29937
29938 break;
29939 }
29940 case 6: {
29941 if((currentSubCase < 24 && disambiguation[bndryId] == 0)
29942 || (currentSubCase >= 24 && disambiguation[bndryId] == 1)) { // case 3.2
29943 cerr << " plotting case 6.2 - 3 surfaces " << endl;
29944 // continue;
29945 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][5]];
29946 p_0s = cutPoints[cutDummy];
29947 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][6]];
29948 p_0ss = cutPoints[cutDummy];
29949 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][7]];
29950 p_1s = cutPoints[cutDummy];
29951 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][8]];
29952 p_1ss = cutPoints[cutDummy];
29953 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][9]];
29954 p_2s = cutPoints[cutDummy];
29955 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][10]];
29956 p_2ss = cutPoints[cutDummy];
29957 cutDummy = edgesMCtoSOLVER[tiling6_2STL[currentSubCase][11]];
29958 p_3 = cutPoints[cutDummy];
29959
29960 pP[0] = p_0s;
29961 pP[1] = p_3;
29962 pP[2] = p_2s;
29963 pP[3] = p_1s;
29964
29965 ofl << 4 << " ";
29966
29967 for(MInt i = 0; i < 4; i++) {
29968 ofl << pP[i] + pointsCount << " ";
29969 }
29970 ofl << endl;
29971
29972 pP[0] = p_0ss;
29973 pP[1] = p_1ss;
29974 pP[2] = p_2ss;
29975 pP[3] = p_3;
29976
29977 ofl << 4 << " ";
29978
29979 for(MInt i = 0; i < 4; i++) {
29980 ofl << pP[i] + pointsCount << " ";
29981 }
29982 ofl << endl;
29983
29984 pP[0] = p_0s;
29985 pP[1] = p_0ss;
29986 pP[2] = p_3;
29987
29988 ofl << 3 << " ";
29989
29990 for(MInt i = 0; i < 3; i++) {
29991 ofl << pP[i] + pointsCount << " ";
29992 }
29993 ofl << endl;
29994 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
29995
29996 } else if((currentSubCase < 24 && disambiguation[bndryId] == 1)
29997 || (currentSubCase >= 24 && disambiguation[bndryId] == 0)) {
29998 cerr << " plotting case 6.1 - 2 surfaces " << endl;
29999 // 1st prism & 1st cutFace
30000 subCaseDummy = tiling6_1STL[currentSubCase][0];
30001 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
30002 p_3 = cutPoints[cutDummy];
30003 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
30004 p_2 = cutPoints[cutDummy];
30005 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
30006 p_3s = cutPoints[cutDummy];
30007 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
30008 p_2s = cutPoints[cutDummy];
30009
30010 pP[0] = p_3;
30011 pP[1] = p_3s;
30012 pP[2] = p_2s;
30013 pP[3] = p_2;
30014 pP[4] = p_3;
30015
30016 ofl << 4 << " ";
30017
30018 for(MInt i = 0; i < 4; i++) {
30019 ofl << pP[i] + pointsCount << " ";
30020 }
30021 ofl << endl;
30022
30023
30024 // 2nd Pyramid + 2nd cutFace
30025 subCaseDummy = tiling6_1STL[currentSubCase][1];
30026 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30027 pP[0] = cutPoints[cutDummy];
30028 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30029 pP[1] = cutPoints[cutDummy];
30030 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30031 pP[2] = cutPoints[cutDummy];
30032
30033 ofl << 3 << " ";
30034
30035 for(MInt i = 0; i < 3; i++) {
30036 ofl << pP[i] + pointsCount << " ";
30037 }
30038 ofl << endl;
30039 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30040 }
30041 break;
30042 }
30043 case 7: {
30044 disamb_tmp = disambiguation[bndryId];
30045 if(currentSubCase >= 8) disamb_tmp = 7 - disamb_tmp;
30046 switch(disamb_tmp) {
30047 case 0: { // case 7.4.1
30048
30049 cerr << " plotting case 7.4.1 - 2 surfaces " << endl;
30050 // 1st Pyramid + 1st cutFace
30051 subCaseDummy = tiling7_4_1STL[currentSubCase][0];
30052 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30053 pP[0] = cutPoints[cutDummy];
30054 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30055 pP[1] = cutPoints[cutDummy];
30056 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30057 pP[2] = cutPoints[cutDummy];
30058
30059 ofl << 3 << " ";
30060
30061 for(MInt i = 0; i < 3; i++) {
30062 ofl << pP[i] + pointsCount << " ";
30063 }
30064 ofl << endl;
30065
30066 subCaseDummy = tiling7_4_1STL[currentSubCase][1];
30067
30068 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][4]];
30069 p_1s = cutPoints[cutDummy];
30070 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][5]];
30071 p_1ss = cutPoints[cutDummy];
30072 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][6]];
30073 p_2s = cutPoints[cutDummy];
30074 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][7]];
30075 p_2ss = cutPoints[cutDummy];
30076 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][8]];
30077 p_3s = cutPoints[cutDummy];
30078 cutDummy = edgesMCtoSOLVER[tiling9STL[subCaseDummy][9]];
30079 p_3ss = cutPoints[cutDummy];
30080
30081 pP[0] = p_1ss;
30082 pP[1] = p_1s;
30083 pP[2] = p_2ss;
30084 pP[3] = p_2s;
30085 pP[4] = p_3ss;
30086 pP[5] = p_3s;
30087 pP[6] = p_1ss;
30088
30089 ofl << 6 << " ";
30090
30091 for(MInt i = 0; i < 6; i++) {
30092 ofl << pP[i] + pointsCount << " ";
30093 }
30094 ofl << endl;
30095 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30096
30097 break;
30098 }
30099 case 1: { // case 7.3, disamb 1
30100 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][6]];
30101 p_1s = cutPoints[cutDummy];
30102 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][7]];
30103 p_1ss = cutPoints[cutDummy];
30104 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][8]];
30105 p_1sss = cutPoints[cutDummy];
30106 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][9]];
30107 p_2s = cutPoints[cutDummy];
30108 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][10]];
30109 p_2ss = cutPoints[cutDummy];
30110 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][11]];
30111 p_2sss = cutPoints[cutDummy];
30112 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][12]];
30113 p_3s = cutPoints[cutDummy];
30114 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][13]];
30115 p_3ss = cutPoints[cutDummy];
30116 cutDummy = edgesMCtoSOLVER[tiling7_3_1STL[currentSubCase][14]];
30117 p_3sss = cutPoints[cutDummy];
30118
30119 if(currentSubCase < 8) {
30120 cerr << " plotting case 7.3 - 2 surfaces, disamb 1, low SC " << endl;
30121
30122 pP[0] = p_1sss;
30123 pP[1] = p_2sss;
30124 pP[2] = p_2s;
30125 pP[3] = p_3ss;
30126 pP[4] = p_3sss;
30127
30128 ofl << 5 << " ";
30129
30130 for(MInt i = 0; i < 5; i++) {
30131 ofl << pP[i] + pointsCount << " ";
30132 }
30133 ofl << endl;
30134
30135 pP[0] = p_1s;
30136 pP[1] = p_1ss;
30137 pP[2] = p_3s;
30138 pP[3] = p_3ss;
30139 pP[4] = p_2s;
30140 pP[5] = p_2ss;
30141
30142 ofl << 6 << " ";
30143
30144 for(MInt i = 0; i < 6; i++) {
30145 ofl << pP[i] + pointsCount << " ";
30146 }
30147 ofl << endl;
30148 } else {
30149 cerr << " plotting case 7.3 - 3 surfaces, disamb 1, high SC " << endl;
30150
30151 pP[0] = p_1ss;
30152 pP[1] = p_1sss;
30153 pP[2] = p_3sss;
30154 pP[3] = p_3ss;
30155 pP[4] = p_3s;
30156
30157 ofl << 5 << " ";
30158
30159 for(MInt i = 0; i < 5; i++) {
30160 ofl << pP[i] + pointsCount << " ";
30161 }
30162 ofl << endl;
30163
30164 pP[0] = p_1sss;
30165 pP[1] = p_1s;
30166 pP[2] = p_2ss;
30167 pP[3] = p_2s;
30168 pP[4] = p_2sss;
30169
30170 ofl << 5 << " ";
30171
30172 for(MInt i = 0; i < 5; i++) {
30173 ofl << pP[i] + pointsCount << " ";
30174 }
30175 ofl << endl;
30176
30177 pP[0] = p_1s;
30178 pP[1] = p_1sss;
30179 pP[2] = p_1ss;
30180
30181 ofl << 3 << " ";
30182
30183 for(MInt i = 0; i < 3; i++) {
30184 ofl << pP[i] + pointsCount << " ";
30185 }
30186 ofl << endl;
30187 }
30188 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30189
30190 break;
30191 }
30192 case 2: { // case 7.3, disamb 2
30193 cerr << " plotting case 7.3 - 3 surfaces, disamb 2 " << endl;
30194
30195 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][6]];
30196 p_1s = cutPoints[cutDummy];
30197 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][7]];
30198 p_1ss = cutPoints[cutDummy];
30199 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][8]];
30200 p_1sss = cutPoints[cutDummy];
30201 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][9]];
30202 p_2s = cutPoints[cutDummy];
30203 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][10]];
30204 p_2ss = cutPoints[cutDummy];
30205 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][11]];
30206 p_2sss = cutPoints[cutDummy];
30207 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][12]];
30208 p_3s = cutPoints[cutDummy];
30209 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][13]];
30210 p_3ss = cutPoints[cutDummy];
30211 cutDummy = edgesMCtoSOLVER[tiling7_3_2STL[currentSubCase][14]];
30212 p_3sss = cutPoints[cutDummy];
30213
30214 if(currentSubCase < 8) {
30215 cerr << " plotting case 7.3 - 2 surfaces, disamb 2, low SC " << endl;
30216
30217 pP[0] = p_1sss;
30218 pP[1] = p_2sss;
30219 pP[2] = p_2s;
30220 pP[3] = p_3ss;
30221 pP[4] = p_3sss;
30222
30223 ofl << 5 << " ";
30224
30225 for(MInt i = 0; i < 5; i++) {
30226 ofl << pP[i] + pointsCount << " ";
30227 }
30228 ofl << endl;
30229
30230 pP[0] = p_1s;
30231 pP[1] = p_1ss;
30232 pP[2] = p_3s;
30233 pP[3] = p_3ss;
30234 pP[4] = p_2s;
30235 pP[5] = p_2ss;
30236
30237 ofl << 6 << " ";
30238
30239 for(MInt i = 0; i < 6; i++) {
30240 ofl << pP[i] + pointsCount << " ";
30241 }
30242 ofl << endl;
30243 } else {
30244 cerr << " plotting case 7.3 - 3 surfaces, disamb 2, high SC " << endl;
30245
30246 pP[0] = p_1ss;
30247 pP[1] = p_1sss;
30248 pP[2] = p_3sss;
30249 pP[3] = p_3ss;
30250 pP[4] = p_3s;
30251
30252 ofl << 5 << " ";
30253
30254 for(MInt i = 0; i < 5; i++) {
30255 ofl << pP[i] + pointsCount << " ";
30256 }
30257 ofl << endl;
30258
30259 pP[0] = p_1sss;
30260 pP[1] = p_1s;
30261 pP[2] = p_2ss;
30262 pP[3] = p_2s;
30263 pP[4] = p_2sss;
30264
30265 ofl << 5 << " ";
30266
30267 for(MInt i = 0; i < 5; i++) {
30268 ofl << pP[i] + pointsCount << " ";
30269 }
30270 ofl << endl;
30271
30272 pP[0] = p_1s;
30273 pP[1] = p_1sss;
30274 pP[2] = p_1ss;
30275
30276 ofl << 3 << " ";
30277
30278 for(MInt i = 0; i < 3; i++) {
30279 ofl << pP[i] + pointsCount << " ";
30280 }
30281 ofl << endl;
30282 }
30283 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30284
30285 break;
30286 }
30287 case 4: { // case 7.3, disamb 4
30288 cerr << " plotting case 7.3 - 3 surfaces, disamb 4 " << endl;
30289
30290 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][6]];
30291 p_1s = cutPoints[cutDummy];
30292 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][7]];
30293 p_1ss = cutPoints[cutDummy];
30294 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][8]];
30295 p_1sss = cutPoints[cutDummy];
30296 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][9]];
30297 p_2s = cutPoints[cutDummy];
30298 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][10]];
30299 p_2ss = cutPoints[cutDummy];
30300 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][11]];
30301 p_2sss = cutPoints[cutDummy];
30302 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][12]];
30303 p_3s = cutPoints[cutDummy];
30304 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][13]];
30305 p_3ss = cutPoints[cutDummy];
30306 cutDummy = edgesMCtoSOLVER[tiling7_3_4STL[currentSubCase][14]];
30307 p_3sss = cutPoints[cutDummy];
30308
30309 if(currentSubCase < 8) {
30310 cerr << " plotting case 7.3 - 2 surfaces, disamb 4, low SC " << endl;
30311
30312 pP[0] = p_1sss;
30313 pP[1] = p_2sss;
30314 pP[2] = p_2s;
30315 pP[3] = p_3ss;
30316 pP[4] = p_3sss;
30317
30318 ofl << 5 << " ";
30319
30320 for(MInt i = 0; i < 5; i++) {
30321 ofl << pP[i] + pointsCount << " ";
30322 }
30323 ofl << endl;
30324
30325 pP[0] = p_1s;
30326 pP[1] = p_1ss;
30327 pP[2] = p_3s;
30328 pP[3] = p_3ss;
30329 pP[4] = p_2s;
30330 pP[5] = p_2ss;
30331
30332 ofl << 6 << " ";
30333
30334 for(MInt i = 0; i < 6; i++) {
30335 ofl << pP[i] + pointsCount << " ";
30336 }
30337 ofl << endl;
30338 } else {
30339 cerr << " plotting case 7.3 - 3 surfaces, disamb 4, high SC " << endl;
30340
30341 pP[0] = p_1ss;
30342 pP[1] = p_1sss;
30343 pP[2] = p_3sss;
30344 pP[3] = p_3ss;
30345 pP[4] = p_3s;
30346
30347 ofl << 5 << " ";
30348
30349 for(MInt i = 0; i < 5; i++) {
30350 ofl << pP[i] + pointsCount << " ";
30351 }
30352 ofl << endl;
30353
30354 pP[0] = p_1sss;
30355 pP[1] = p_1s;
30356 pP[2] = p_2ss;
30357 pP[3] = p_2s;
30358 pP[4] = p_2sss;
30359
30360 ofl << 5 << " ";
30361
30362 for(MInt i = 0; i < 5; i++) {
30363 ofl << pP[i] + pointsCount << " ";
30364 }
30365 ofl << endl;
30366
30367 pP[0] = p_1s;
30368 pP[1] = p_1sss;
30369 pP[2] = p_1ss;
30370
30371 ofl << 3 << " ";
30372
30373 for(MInt i = 0; i < 3; i++) {
30374 ofl << pP[i] + pointsCount << " ";
30375 }
30376 ofl << endl;
30377 }
30378 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30379
30380 break;
30381 }
30382 case 3: { // case 7.2, disamb 3
30383
30384 cerr << " plotting case 7.2 - 2 surfaces, disamb 3 " << endl;
30385 // 1st Pyramid + 1st cutFace
30386 subCaseDummy = tiling7_2_3STL[currentSubCase][0];
30387 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30388 pP[0] = cutPoints[cutDummy];
30389 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30390 pP[1] = cutPoints[cutDummy];
30391 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30392 pP[2] = cutPoints[cutDummy];
30393
30394 ofl << 3 << " ";
30395
30396 for(MInt i = 0; i < 3; i++) {
30397 ofl << pP[i] + pointsCount << " ";
30398 }
30399 ofl << endl;
30400
30401 subCaseDummy = tiling7_2_3STL[currentSubCase][1];
30402 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][2]];
30403 p_1 = cutPoints[cutDummy];
30404 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][3]];
30405 p_2 = cutPoints[cutDummy];
30406 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][4]];
30407 p_3 = cutPoints[cutDummy];
30408 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][5]];
30409 p_1s = cutPoints[cutDummy];
30410 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][6]];
30411 p_2s = cutPoints[cutDummy];
30412 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][7]];
30413 p_3s = cutPoints[cutDummy];
30414
30415 pP[0] = p_1;
30416 pP[1] = p_2;
30417 pP[2] = p_3;
30418 pP[3] = p_1s;
30419 pP[4] = p_2s;
30420 pP[5] = p_3s;
30421 pP[6] = p_1;
30422
30423 ofl << 6 << " ";
30424
30425 for(MInt i = 0; i < 6; i++) {
30426 ofl << pP[i] + pointsCount << " ";
30427 }
30428 ofl << endl;
30429 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30430
30431 break;
30432 }
30433 case 5: { // case 7.2, disamb 5
30434 cerr << " plotting case 7.2 - 2 surfaces, disamb 5 " << endl;
30435 // 1st Pyramid + 1st cutFace
30436 subCaseDummy = tiling7_2_5STL[currentSubCase][0];
30437 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30438 pP[0] = cutPoints[cutDummy];
30439 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30440 pP[1] = cutPoints[cutDummy];
30441 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30442 pP[2] = cutPoints[cutDummy];
30443
30444 ofl << 3 << " ";
30445
30446 for(MInt i = 0; i < 3; i++) {
30447 ofl << pP[i] + pointsCount << " ";
30448 }
30449 ofl << endl;
30450
30451 subCaseDummy = tiling7_2_5STL[currentSubCase][1];
30452 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][2]];
30453 p_1 = cutPoints[cutDummy];
30454 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][3]];
30455 p_2 = cutPoints[cutDummy];
30456 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][4]];
30457 p_3 = cutPoints[cutDummy];
30458 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][5]];
30459 p_1s = cutPoints[cutDummy];
30460 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][6]];
30461 p_2s = cutPoints[cutDummy];
30462 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][7]];
30463 p_3s = cutPoints[cutDummy];
30464
30465 pP[0] = p_1;
30466 pP[1] = p_2;
30467 pP[2] = p_3;
30468 pP[3] = p_1s;
30469 pP[4] = p_2s;
30470 pP[5] = p_3s;
30471 pP[6] = p_1;
30472
30473 ofl << 6 << " ";
30474
30475 for(MInt i = 0; i < 6; i++) {
30476 ofl << pP[i] + pointsCount << " ";
30477 }
30478 ofl << endl;
30479 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30480
30481 break;
30482 }
30483 case 6: { // case 7.2, disamb 6
30484 cerr << " plotting case 7.2 - 2 surfaces, disamb 6 " << endl;
30485 // 1st Pyramid + 1st cutFace
30486 subCaseDummy = tiling7_2_6STL[currentSubCase][0];
30487 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30488 pP[0] = cutPoints[cutDummy];
30489 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30490 pP[1] = cutPoints[cutDummy];
30491 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30492 pP[2] = cutPoints[cutDummy];
30493
30494 ofl << 3 << " ";
30495
30496 for(MInt i = 0; i < 3; i++) {
30497 ofl << pP[i] + pointsCount << " ";
30498 }
30499 ofl << endl;
30500
30501 subCaseDummy = tiling7_2_6STL[currentSubCase][1];
30502 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][2]];
30503 p_1 = cutPoints[cutDummy];
30504 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][3]];
30505 p_2 = cutPoints[cutDummy];
30506 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][4]];
30507 p_3 = cutPoints[cutDummy];
30508 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][5]];
30509 p_1s = cutPoints[cutDummy];
30510 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][6]];
30511 p_2s = cutPoints[cutDummy];
30512 cutDummy = edgesMCtoSOLVER[tiling3_2STL[subCaseDummy][7]];
30513 p_3s = cutPoints[cutDummy];
30514
30515 pP[0] = p_1;
30516 pP[1] = p_2;
30517 pP[2] = p_3;
30518 pP[3] = p_1s;
30519 pP[4] = p_2s;
30520 pP[5] = p_3s;
30521 pP[6] = p_1;
30522
30523 ofl << 6 << " ";
30524
30525 for(MInt i = 0; i < 6; i++) {
30526 ofl << pP[i] + pointsCount << " ";
30527 }
30528 ofl << endl;
30529 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30530
30531 break;
30532 }
30533 case 7: {
30534 cerr << " plotting case 7.1 - 3 surfaces " << endl;
30535 // 1st Pyramid + 1st cutFace
30536 subCaseDummy = tiling7_1STL[currentSubCase][0];
30537 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30538 pP[0] = cutPoints[cutDummy];
30539 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30540 pP[1] = cutPoints[cutDummy];
30541 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30542 pP[2] = cutPoints[cutDummy];
30543
30544 ofl << 3 << " ";
30545
30546 for(MInt i = 0; i < 3; i++) {
30547 ofl << pP[i] + pointsCount << " ";
30548 }
30549 ofl << endl;
30550
30551
30552 // 2nd Pyramid + 2nd cutFace
30553 subCaseDummy = tiling7_1STL[currentSubCase][1];
30554 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30555 pP[0] = cutPoints[cutDummy];
30556 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30557 pP[1] = cutPoints[cutDummy];
30558 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30559 pP[2] = cutPoints[cutDummy];
30560
30561 ofl << 3 << " ";
30562
30563 for(MInt i = 0; i < 3; i++) {
30564 ofl << pP[i] + pointsCount << " ";
30565 }
30566 ofl << endl;
30567
30568 // 3rd Pyramid + 3rd cutFace
30569 subCaseDummy = tiling7_1STL[currentSubCase][2];
30570 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30571 pP[0] = cutPoints[cutDummy];
30572 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30573 pP[1] = cutPoints[cutDummy];
30574 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30575 pP[2] = cutPoints[cutDummy];
30576
30577 ofl << 3 << " ";
30578
30579 for(MInt i = 0; i < 3; i++) {
30580 ofl << pP[i] + pointsCount << " ";
30581 }
30582 ofl << endl;
30583
30584 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30585 break;
30586 }
30587 default: {
30588 stringstream errorMessage;
30589 errorMessage << "ERROR: Switch variable 'disamb_tmp' with value " << disamb_tmp
30590 << " not matching any case." << endl;
30591 mTerm(1, AT_, errorMessage.str());
30592 }
30593 }
30594
30595
30596 break;
30597 }
30598 case 10: {
30599 if(disambiguation[bndryId] == 3) { // case 10.2
30600 cerr << " plotting case 10.2 (really 10.1.1 split) - 2 surfaces " << endl;
30601 // 1st prism & 1st cutFace
30602 subCaseDummy = tiling10_2STL[currentSubCase][0];
30603 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
30604 p_3 = cutPoints[cutDummy];
30605 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
30606 p_2 = cutPoints[cutDummy];
30607 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
30608 p_3s = cutPoints[cutDummy];
30609 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
30610 p_2s = cutPoints[cutDummy];
30611
30612 pP[0] = p_3;
30613 pP[1] = p_3s;
30614 pP[2] = p_2s;
30615 pP[3] = p_2;
30616 pP[4] = p_3;
30617
30618 ofl << 4 << " ";
30619
30620 for(MInt i = 0; i < 4; i++) {
30621 ofl << pP[i] + pointsCount << " ";
30622 }
30623 ofl << endl;
30624
30625 // 2nd prism & 2nd cutFace
30626 subCaseDummy = tiling10_2STL[currentSubCase][1];
30627 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
30628 p_3 = cutPoints[cutDummy];
30629 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
30630 p_2 = cutPoints[cutDummy];
30631 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
30632 p_3s = cutPoints[cutDummy];
30633 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
30634 p_2s = cutPoints[cutDummy];
30635
30636 pP[0] = p_3;
30637 pP[1] = p_3s;
30638 pP[2] = p_2s;
30639 pP[3] = p_2;
30640 pP[4] = p_3;
30641
30642 ofl << 4 << " ";
30643
30644 for(MInt i = 0; i < 4; i++) {
30645 ofl << pP[i] + pointsCount << " ";
30646 }
30647 ofl << endl;
30648
30649 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30650
30651
30652 } else if(disambiguation[bndryId] == 0) {
30653 cerr << " plotting case 10.1 - 2 surfaces " << endl;
30654 // 1st prism & 1st cutFace
30655 subCaseDummy = tiling10_1STL[currentSubCase][0];
30656 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
30657 p_3 = cutPoints[cutDummy];
30658 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
30659 p_2 = cutPoints[cutDummy];
30660 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
30661 p_3s = cutPoints[cutDummy];
30662 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
30663 p_2s = cutPoints[cutDummy];
30664
30665 pP[0] = p_3;
30666 pP[1] = p_3s;
30667 pP[2] = p_2s;
30668 pP[3] = p_2;
30669 pP[4] = p_3;
30670
30671 ofl << 4 << " ";
30672
30673 for(MInt i = 0; i < 4; i++) {
30674 ofl << pP[i] + pointsCount << " ";
30675 }
30676 ofl << endl;
30677
30678 // 2nd prism & 2nd cutFace
30679 subCaseDummy = tiling10_1STL[currentSubCase][1];
30680 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
30681 p_3 = cutPoints[cutDummy];
30682 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
30683 p_2 = cutPoints[cutDummy];
30684 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
30685 p_3s = cutPoints[cutDummy];
30686 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
30687 p_2s = cutPoints[cutDummy];
30688
30689 pP[0] = p_3;
30690 pP[1] = p_3s;
30691 pP[2] = p_2s;
30692 pP[3] = p_2;
30693 pP[4] = p_3;
30694
30695 ofl << 4 << " ";
30696
30697 for(MInt i = 0; i < 4; i++) {
30698 ofl << pP[i] + pointsCount << " ";
30699 }
30700 ofl << endl;
30701
30702 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30703
30704 } else {
30705 cerr << "Error in plotSurface: Type 10.2 (real 10.2) detected, but not implemented."
30706 << " cell " << cellId << " with bndryId " << bndryId << " and disambiguation "
30707 << disambiguation[bndryId] << endl;
30708 writeStlFileOfCell(cellId, "10_2_cell.stl");
30709 cerr << " plotting cell as 10.1 cell... " << endl;
30710 // 1st prism & 1st cutFace
30711
30712 subCaseDummy = tiling10_1STL[currentSubCase][0];
30713 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
30714 p_3 = cutPoints[cutDummy];
30715 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
30716 p_2 = cutPoints[cutDummy];
30717 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
30718 p_3s = cutPoints[cutDummy];
30719 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
30720 p_2s = cutPoints[cutDummy];
30721
30722 pP[0] = p_3;
30723 pP[1] = p_3s;
30724 pP[2] = p_2s;
30725 pP[3] = p_2;
30726 pP[4] = p_3;
30727
30728 ofl << 4 << " ";
30729
30730 for(MInt i = 0; i < 4; i++) {
30731 ofl << pP[i] + pointsCount << " ";
30732 }
30733 ofl << endl;
30734
30735 // 2nd prism & 2nd cutFace
30736 subCaseDummy = tiling10_1STL[currentSubCase][1];
30737 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][2]];
30738 p_3 = cutPoints[cutDummy];
30739 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][3]];
30740 p_2 = cutPoints[cutDummy];
30741 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][4]];
30742 p_3s = cutPoints[cutDummy];
30743 cutDummy = edgesMCtoSOLVER[tiling2STL[subCaseDummy][5]];
30744 p_2s = cutPoints[cutDummy];
30745
30746 pP[0] = p_3;
30747 pP[1] = p_3s;
30748 pP[2] = p_2s;
30749 pP[3] = p_2;
30750 pP[4] = p_3;
30751
30752 ofl << 4 << " ";
30753
30754 for(MInt i = 0; i < 4; i++) {
30755 ofl << pP[i] + pointsCount << " ";
30756 }
30757 ofl << endl;
30758
30759 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30760 }
30761
30762 break;
30763 }
30764 case 12: {
30765 if(disambiguation[bndryId] == 0) {
30766 cerr << " plotting case 12.1 - 2 surfaces - connected" << endl;
30767 // 1st case 5 part & 1st cutFace
30768 subCaseDummy = tiling12_1STL[currentSubCase][0];
30769
30770 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][3]];
30771 p_0s = cutPoints[cutDummy];
30772 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][4]];
30773 p_0ss = cutPoints[cutDummy];
30774 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][5]];
30775 p_1s = cutPoints[cutDummy];
30776 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][6]];
30777 p_2s = cutPoints[cutDummy];
30778 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][7]];
30779 p_2ss = cutPoints[cutDummy];
30780
30781 pP[0] = p_0s;
30782 pP[1] = p_1s;
30783 pP[2] = p_2s;
30784 pP[3] = p_2ss;
30785 pP[4] = p_0ss;
30786 pP[5] = p_0s;
30787
30788 ofl << 5 << " ";
30789
30790 for(MInt i = 0; i < 5; i++) {
30791 ofl << pP[i] + pointsCount << " ";
30792 }
30793 ofl << endl;
30794
30795 // 2nd Pyramid + 2nd cutFace
30796 subCaseDummy = tiling12_1STL[currentSubCase][1];
30797 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30798 pP[0] = cutPoints[cutDummy];
30799 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30800 pP[1] = cutPoints[cutDummy];
30801 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30802 pP[2] = cutPoints[cutDummy];
30803
30804 ofl << 3 << " ";
30805
30806 for(MInt i = 0; i < 3; i++) {
30807 ofl << pP[i] + pointsCount << " ";
30808 }
30809 ofl << endl;
30810 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30811 } else if(disambiguation[bndryId] == 3) {
30812 cerr << " plotting case 12.1 - 2 surfaces - separated" << endl;
30813 // 1st case 5 part & 1st cutFace
30814 subCaseDummy = tiling12_1STL[23 - currentSubCase][0];
30815
30816 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][3]];
30817 p_0s = cutPoints[cutDummy];
30818 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][4]];
30819 p_0ss = cutPoints[cutDummy];
30820 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][5]];
30821 p_1s = cutPoints[cutDummy];
30822 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][6]];
30823 p_2s = cutPoints[cutDummy];
30824 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][7]];
30825 p_2ss = cutPoints[cutDummy];
30826
30827 pP[0] = p_0s;
30828 pP[1] = p_1s;
30829 pP[2] = p_2s;
30830 pP[3] = p_2ss;
30831 pP[4] = p_0ss;
30832 pP[5] = p_0s;
30833
30834 ofl << 5 << " ";
30835
30836 for(MInt i = 0; i < 5; i++) {
30837 ofl << pP[i] + pointsCount << " ";
30838 }
30839 ofl << endl;
30840
30841 // 2nd Pyramid + 2nd cutFace
30842 subCaseDummy = tiling12_1STL[23 - currentSubCase][1];
30843 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30844 pP[0] = cutPoints[cutDummy];
30845 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30846 pP[1] = cutPoints[cutDummy];
30847 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30848 pP[2] = cutPoints[cutDummy];
30849
30850 ofl << 3 << " ";
30851
30852 for(MInt i = 0; i < 3; i++) {
30853 ofl << pP[i] + pointsCount << " ";
30854 }
30855 ofl << endl;
30856 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30857 } else {
30858 cerr << "Error in plotSurface: Type 12.2 or 12.3 detected, but not implemented."
30859 << " cell " << cellId << " with bndryId " << bndryId << " and disambiguation "
30860 << disambiguation[bndryId] << endl;
30861 cerr << " plotting as 12.1 cell... " << endl;
30862 writeStlFileOfCell(cellId, "12.2_12.3_cell.stl");
30863
30864 // 1st case 5 part & 1st cutFace
30865 subCaseDummy = tiling12_1STL[23 - currentSubCase][0];
30866
30867 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][3]];
30868 p_0s = cutPoints[cutDummy];
30869 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][4]];
30870 p_0ss = cutPoints[cutDummy];
30871 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][5]];
30872 p_1s = cutPoints[cutDummy];
30873 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][6]];
30874 p_2s = cutPoints[cutDummy];
30875 cutDummy = edgesMCtoSOLVER[tiling5STL[subCaseDummy][7]];
30876 p_2ss = cutPoints[cutDummy];
30877
30878 pP[0] = p_0s;
30879 pP[1] = p_1s;
30880 pP[2] = p_2s;
30881 pP[3] = p_2ss;
30882 pP[4] = p_0ss;
30883 pP[5] = p_0s;
30884
30885 ofl << 5 << " ";
30886
30887 for(MInt i = 0; i < 5; i++) {
30888 ofl << pP[i] + pointsCount << " ";
30889 }
30890 ofl << endl;
30891
30892 // 2nd Pyramid + 2nd cutFace
30893 subCaseDummy = tiling12_1STL[23 - currentSubCase][1];
30894 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][1]];
30895 pP[0] = cutPoints[cutDummy];
30896 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][2]];
30897 pP[1] = cutPoints[cutDummy];
30898 cutDummy = edgesMCtoSOLVER[tiling1STL[subCaseDummy][3]];
30899 pP[2] = cutPoints[cutDummy];
30900
30901 ofl << 3 << " ";
30902
30903 for(MInt i = 0; i < 3; i++) {
30904 ofl << pP[i] + pointsCount << " ";
30905 }
30906 ofl << endl;
30907 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30908 }
30909
30910 break;
30911 }
30912 default: {
30913 stringstream errorMessage;
30914 errorMessage << "Error in plotSurface: Inconsistent type implementation." << endl;
30915 mTerm(1, AT_, errorMessage.str());
30916 }
30917 }
30918 } else {
30919 switch(currentCase) {
30920 case 0: {
30921 cerr << "Error in plotSurface: Cell is not a boundary cell!" << endl;
30922 cerr << "CellId: " << cellId << " BndryId: " << bndryId << endl;
30923 break;
30924 }
30925 case 1: {
30926 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][1]];
30927 pP[0] = cutPoints[cutDummy];
30928 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][2]];
30929 pP[1] = cutPoints[cutDummy];
30930 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][3]];
30931 pP[2] = cutPoints[cutDummy];
30932
30933 ofl << 3 << " ";
30934
30935 for(MInt i = 0; i < 3; i++) {
30936 ofl << pP[i] + pointsCount << " ";
30937 }
30938 ofl << endl;
30939 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30940 break;
30941 }
30942 case 2: {
30943 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][2]];
30944 p_3 = cutPoints[cutDummy];
30945 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][3]];
30946 p_2 = cutPoints[cutDummy];
30947 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][4]];
30948 p_3s = cutPoints[cutDummy];
30949 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][5]];
30950 p_2s = cutPoints[cutDummy];
30951 pP[0] = p_3;
30952 pP[1] = p_3s;
30953 pP[2] = p_2s;
30954 pP[3] = p_2;
30955 pP[4] = p_3;
30956
30957 ofl << 4 << " ";
30958
30959 for(MInt i = 0; i < 4; i++) {
30960 ofl << pP[i] + pointsCount << " ";
30961 }
30962 ofl << endl;
30963 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30964
30965
30966 break;
30967 }
30968 case 5: {
30969 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][3]];
30970 p_0s = cutPoints[cutDummy];
30971 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][4]];
30972 p_0ss = cutPoints[cutDummy];
30973 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][5]];
30974 p_1s = cutPoints[cutDummy];
30975 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][6]];
30976 p_2s = cutPoints[cutDummy];
30977 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][7]];
30978 p_2ss = cutPoints[cutDummy];
30979
30980 pP[0] = p_0s;
30981 pP[1] = p_1s;
30982 pP[2] = p_2s;
30983 pP[3] = p_2ss;
30984 pP[4] = p_0ss;
30985 pP[5] = p_0s;
30986
30987 ofl << 5 << " ";
30988
30989 for(MInt i = 0; i < 5; i++) {
30990 ofl << pP[i] + pointsCount << " ";
30991 }
30992 ofl << endl;
30993 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
30994
30995 break;
30996 }
30997 case 8: {
30998 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][4]];
30999 p_0s = cutPoints[cutDummy];
31000 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][5]];
31001 p_1s = cutPoints[cutDummy];
31002 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][6]];
31003 p_2s = cutPoints[cutDummy];
31004 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][7]];
31005 p_3s = cutPoints[cutDummy];
31006
31007 pP[0] = p_0s;
31008 pP[1] = p_1s;
31009 pP[2] = p_2s;
31010 pP[3] = p_3s;
31011 pP[4] = p_0s;
31012
31013 ofl << 4 << " ";
31014
31015 for(MInt i = 0; i < 4; i++) {
31016 ofl << pP[i] + pointsCount << " ";
31017 }
31018 ofl << endl;
31019 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
31020
31021
31022 break;
31023 }
31024 case 9: {
31025 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][4]];
31026 p_1s = cutPoints[cutDummy];
31027 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][5]];
31028 p_1ss = cutPoints[cutDummy];
31029 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][6]];
31030 p_2s = cutPoints[cutDummy];
31031 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][7]];
31032 p_2ss = cutPoints[cutDummy];
31033 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][8]];
31034 p_3s = cutPoints[cutDummy];
31035 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][9]];
31036 p_3ss = cutPoints[cutDummy];
31037
31038 pP[0] = p_1ss;
31039 pP[1] = p_1s;
31040 pP[2] = p_2ss;
31041 pP[3] = p_2s;
31042 pP[4] = p_3ss;
31043 pP[5] = p_3s;
31044 pP[6] = p_1ss;
31045
31046 ofl << 6 << " ";
31047
31048 for(MInt i = 0; i < 6; i++) {
31049 ofl << pP[i] + pointsCount << " ";
31050 }
31051 ofl << endl;
31052 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
31053
31054 break;
31055 }
31056 case 11: {
31057 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][4]];
31058 p_0s = cutPoints[cutDummy];
31059 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][5]];
31060 p_0ss = cutPoints[cutDummy];
31061 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][6]];
31062 p_1s = cutPoints[cutDummy];
31063 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][7]];
31064 p_2s = cutPoints[cutDummy];
31065 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][8]];
31066 p_3s = cutPoints[cutDummy];
31067 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][9]];
31068 p_3ss = cutPoints[cutDummy];
31069
31070 pP[0] = p_0ss;
31071 pP[1] = p_0s;
31072 pP[2] = p_2s;
31073 pP[3] = p_3ss;
31074 pP[4] = p_3s;
31075 pP[5] = p_1s;
31076 pP[6] = p_0ss;
31077
31078 ofl << 6 << " ";
31079
31080 for(MInt i = 0; i < 6; i++) {
31081 ofl << pP[i] + pointsCount << " ";
31082 }
31083 ofl << endl;
31084 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
31085
31086
31087 break;
31088 }
31089 case 14: {
31090 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][4]];
31091 p_0s = cutPoints[cutDummy];
31092 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][5]];
31093 p_0ss = cutPoints[cutDummy];
31094 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][6]];
31095 p_1s = cutPoints[cutDummy];
31096 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][7]];
31097 p_2s = cutPoints[cutDummy];
31098 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][8]];
31099 p_3s = cutPoints[cutDummy];
31100 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][9]];
31101 p_3ss = cutPoints[cutDummy];
31102
31103 pP[0] = p_0ss;
31104 pP[1] = p_0s;
31105 pP[2] = p_1s;
31106 pP[3] = p_3ss;
31107 pP[4] = p_3s;
31108 pP[5] = p_2s;
31109 pP[6] = p_0ss;
31110
31111 ofl << 6 << " ";
31112
31113 for(MInt i = 0; i < 6; i++) {
31114 ofl << pP[i] + pointsCount << " ";
31115 }
31116 ofl << endl;
31117
31118 pointsCount += m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
31119
31120 break;
31121 }
31122 default: {
31123 // mTerm(1, AT_, "Error in plotSurface: Inconsistent type implementation.");
31124 break;
31125 }
31126 }
31127 }
31128 }
31129
31130 ofl << "CELL_TYPES " << noPlotCells << endl;
31131 for(MInt i = 0; i < noPlotCells; i++) {
31132 ofl << 7 << endl;
31133 }
31134
31135 ofl.close();
31136 }
31137}
31138
31139//---------------------------------------------------------------------------.
31140
31147template <MInt nDim, class SysEqn>
31148template <class _, std::enable_if_t<nDim == 3, _*>>
31149void FvBndryCndXD<nDim, SysEqn>::plotEdges(MInt& noFeatureEdges, MFloat**& featureEdges) {
31150 TRACE();
31151
31152 MInt& iter = m_static_plotEdges_iter;
31153 stringstream fileName;
31154 fileName << "FeatureEdges" << domainId() << "_" << iter++ << ".vtk";
31155
31156 ofstream ofl;
31157 ofl.open((fileName.str()).c_str(), ofstream::trunc);
31158
31159 if(ofl) {
31160 ofl.setf(ios::fixed);
31161 ofl.precision(7);
31162
31163 ofl << "# vtk DataFile Version 3.0" << endl
31164 << "MAIAD featureEdge file" << endl
31165 << "ASCII" << endl
31166 << "DATASET POLYDATA" << endl
31167 << "POINTS " << noFeatureEdges * 2 << " float" << endl;
31168
31169 for(MInt i = 0; i < noFeatureEdges; i++) {
31170 for(MInt j = 0; j < 2; j++) {
31171 for(MInt k = 0; k < 3; k++) {
31172 ofl << featureEdges[2 * i + j][k] << " ";
31173 }
31174 ofl << endl;
31175 }
31176 }
31177
31178 ofl << "LINES " << noFeatureEdges << " " << noFeatureEdges * 3 << endl;
31179 for(MInt i = 0; i < noFeatureEdges; i++) {
31180 ofl << "2 " << 2 * i << " " << 2 * i + 1 << endl;
31181 }
31182 }
31183
31184 ofl.close();
31185}
31186
31187
31188// ---------------------------------------------------------------------------------
31189
31198template <MInt nDim, class SysEqn>
31199template <class _, std::enable_if_t<nDim == 3, _*>>
31200void FvBndryCndXD<nDim, SysEqn>::plotIntersectionPoints(MInt* noIntersectionPoints, MFloat***& intersectionPoints) {
31201 TRACE();
31202
31203 MInt& iter = m_static_plotIntersectionPoints_iter;
31204 stringstream fileName;
31205 fileName << "IntersectionPoints" << domainId() << "_" << iter++ << ".vtk";
31206
31207 ofstream ofl;
31208 ofl.open((fileName.str()).c_str(), ofstream::trunc);
31209 MInt totalPoints = 0;
31210
31211 for(MInt i = 0; i < 6; i++) {
31212 totalPoints += noIntersectionPoints[i];
31213 }
31214
31215 if(ofl) {
31216 ofl.setf(ios::fixed);
31217 ofl.precision(7);
31218
31219 ofl << "# vtk DataFile Version 3.0" << endl
31220 << "MAIAD intersectionPoints file" << endl
31221 << "ASCII" << endl
31222 << "DATASET POLYDATA" << endl
31223 << "POINTS " << totalPoints << " float" << endl;
31224
31225 for(MInt face = 0; face < 6; face++) {
31226 for(MInt i = 0; i < noIntersectionPoints[face]; i++) {
31227 for(MInt k = 0; k < 3; k++) {
31228 ofl << intersectionPoints[face][i][k] << " ";
31229 }
31230 ofl << endl;
31231 }
31232 }
31233
31234 ofl << "VERTICES " << totalPoints << " " << totalPoints * 2 << endl;
31235 for(MInt i = 0; i < totalPoints; i++) {
31236 ofl << "1 " << i << endl;
31237 }
31238 }
31239
31240 ofl.close();
31241}
31242
31243// ---------------------------------------------------------------------------------
31244
31249template <MInt nDim, class SysEqn>
31250template <class _, std::enable_if_t<nDim == 3, _*>>
31251void FvBndryCndXD<nDim, SysEqn>::writeStlOfNodes(MInt noNodes, MInt*& nodeList, const MChar* filename) {
31252 TRACE();
31253
31254 MFloat* point1;
31255 MFloat* point2;
31256 MFloat* point3;
31257 MFloat normal[3] = {0.0, 0.0, 0.0};
31258 MFloat dummy_1[3] = {0, 0, 0};
31259 MFloat dummy_2[3] = {0, 0, 0};
31260 MFloat dummy_3[3] = {0, 0, 0};
31261 MFloat area;
31262 MInt& iter = m_static_writeStlOfNodes_iter;
31263 stringstream fileName2;
31264 fileName2 << filename << domainId() << "_" << iter++ << ".stl";
31265
31266 ofstream ofl;
31267 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
31268
31269 if(ofl) {
31270 // set fixed floating point output
31271 ofl.setf(ios::fixed);
31272 ofl.precision(7);
31273
31274 ofl << " solid feature triangles " << endl;
31275
31276 for(MInt i = 0; i < noNodes; i++) {
31277 point1 = m_solver->m_geometry->elements[nodeList[i]].m_vertices[0];
31278 point2 = m_solver->m_geometry->elements[nodeList[i]].m_vertices[1];
31279 point3 = m_solver->m_geometry->elements[nodeList[i]].m_vertices[2];
31280
31281 vecSub(point2, point1, dummy_1);
31282 vecSub(point3, point1, dummy_2);
31283 maia::math::cross(dummy_1, dummy_2, dummy_3);
31284 area = maia::math::norm(dummy_3, 3);
31285 vecScalarMul(-1.0 / area, dummy_3, normal);
31286
31287 ofl << " facet normal " << normal[0] << " " << normal[1] << " " << normal[2] << endl;
31288 ofl << " outer loop" << endl;
31289 ofl << " vertex " << point1[0] << " " << point1[1] << " " << point1[2] << endl;
31290 ofl << " vertex " << point2[0] << " " << point2[1] << " " << point2[2] << endl;
31291 ofl << " vertex " << point3[0] << " " << point3[1] << " " << point3[2] << endl;
31292 ofl << " endloop" << endl;
31293 ofl << " endfacet" << endl;
31294 }
31295
31296 ofl << " endsolid feature triangles " << endl;
31297 }
31298
31299 ofl.close();
31300}
31301
31302// ---------------------------------------------------------------------------------------------
31303
31308template <MInt nDim, class SysEqn>
31309template <class _, std::enable_if_t<nDim == 3, _*>>
31310void FvBndryCndXD<nDim, SysEqn>::plotTriangle(ofstream& ofl, MFloat* A, MFloat* B, MFloat* C, MFloat* normal) {
31311 TRACE();
31312
31313 ofl << " facet normal " << normal[0] << " " << normal[1] << " " << normal[2] << endl;
31314 ofl << " outer loop" << endl;
31315 ofl << " vertex " << A[0] << " " << A[1] << " " << A[2] << endl;
31316 ofl << " vertex " << B[0] << " " << B[1] << " " << B[2] << endl;
31317 ofl << " vertex " << C[0] << " " << C[1] << " " << C[2] << endl;
31318 ofl << " endloop" << endl;
31319 ofl << " endfacet" << endl;
31320}
31321
31322
31323// ---------------------------------------------------------------------------------
31324// ---------------------------- geometric help routines ---------------------------
31325// ---------------------------------------------------------------------------------
31326
31327
31332template <MInt nDim, class SysEqn>
31333template <class _, std::enable_if_t<nDim == 3, _*>>
31335 TRACE();
31336
31337 for(MInt dim = 0; dim < nDim; dim++) {
31338 res[dim] = a[dim] - b[dim];
31339 }
31340 return res;
31341}
31342
31343// -------------------------------------------------------------------------------
31344
31349template <MInt nDim, class SysEqn>
31350template <class _, std::enable_if_t<nDim == 3, _*>>
31352 TRACE();
31353
31354 for(MInt dim = 0; dim < nDim; dim++) {
31355 res[dim] = s * a[dim];
31356 }
31357 return res;
31358}
31359
31360// -------------------------------------------------------------------------------
31361
31366template <MInt nDim, class SysEqn>
31367template <class _, std::enable_if_t<nDim == 3, _*>>
31369 TRACE();
31370
31371 MFloat dummy_1[3] = {0, 0, 0};
31372 MFloat dummy_2[3] = {0, 0, 0};
31373 MFloat dummy_3[3] = {0, 0, 0};
31374
31375 vecSub(b, a, dummy_1);
31376 vecSub(c, a, dummy_2);
31377 maia::math::cross(dummy_1, dummy_2, dummy_3);
31378 *area = 0.5 * maia::math::norm(dummy_3, 3);
31379 std::fill(dummy_1, dummy_1 + 3, 0.0);
31380 centroid = vecScalarMul(F1B3, maia::math::vecAdd<3>(dummy_1, a, b, c), centroid);
31381 return;
31382}
31383
31384// -------------------------------------------------------------------------------
31385
31392template <MInt nDim, class SysEqn>
31393template <class _, std::enable_if_t<nDim == 3, _*>>
31395 MFloat* normal) {
31396 TRACE();
31397
31398 computePoly3(a, b, c, area, centroid, normal);
31399 return;
31400}
31401
31402// -----------------------------------------------------------------------------
31403
31413template <MInt nDim, class SysEqn>
31414template <class _, std::enable_if_t<nDim == 3, _*>>
31416 MFloat* centroid, MFloat* normal) {
31417 TRACE();
31418
31419 MFloat dummy_1[3] = {0, 0, 0};
31420 MFloat dummy_2[3] = {0, 0, 0};
31421 MFloat A1, A2;
31422
31423 computeTri(a, b, c, &A1, dummy_1, normal);
31424 computeTri(c, d, a, &A2, dummy_2);
31425 *area = A1 + A2;
31426 std::fill_n(centroid, 3, 0.0);
31427 maia::math::vecAdd<3>(centroid, vecScalarMul(A1, dummy_1, dummy_1), vecScalarMul(A2, dummy_2, dummy_2));
31428 centroid = vecScalarMul(F1 / *area, centroid, centroid);
31429 return;
31430}
31431
31432// -------------------------------------------------------------------------------
31433
31443template <MInt nDim, class SysEqn>
31444template <class _, std::enable_if_t<nDim == 3, _*>>
31446 MFloat* normal) {
31447 TRACE();
31448
31449 MFloat dummy_1[3] = {0, 0, 0};
31450 MFloat dummy_2[3] = {0, 0, 0};
31451 MFloat dummy_3[3] = {0, 0, 0};
31452
31453 vecSub(b, a, dummy_1);
31454 vecSub(c, a, dummy_2);
31455 maia::math::cross(dummy_1, dummy_2, dummy_3);
31456 *area = 0.5 * maia::math::norm(dummy_3, 3);
31457 normal = vecScalarMul(-F1B2 / *area, dummy_3, normal);
31458 std::fill_n(dummy_1, 3, 0.0);
31459 centroid = vecScalarMul(F1B3, maia::math::vecAdd<3>(dummy_1, a, b, c), centroid);
31460 return;
31461}
31462
31463// -------------------------------------------------------------------------------
31464
31474template <MInt nDim, class SysEqn>
31475template <class _, std::enable_if_t<nDim == 3, _*>>
31477 MFloat* centroid, MFloat* normal) {
31478 TRACE();
31479
31480 MFloat c_1[3] = {0, 0, 0};
31481 MFloat c_2[3] = {0, 0, 0};
31482 MFloat c_3[3] = {0, 0, 0};
31483 MFloat c_4[3] = {0, 0, 0};
31484 MFloat n_1[3] = {0, 0, 0};
31485 MFloat n_2[3] = {0, 0, 0};
31486 MFloat n_3[3] = {0, 0, 0};
31487 MFloat n_4[3] = {0, 0, 0};
31488 MFloat M[3] = {0, 0, 0};
31489 MFloat A1, A2, A3, A4;
31490
31491 maia::math::vecAvg<3>(M, a, b, c, d);
31492 computePoly3(a, b, M, &A1, c_1, n_1);
31493 computePoly3(b, c, M, &A2, c_2, n_2);
31494 computePoly3(c, d, M, &A3, c_3, n_3);
31495 computePoly3(d, a, M, &A4, c_4, n_4);
31496
31497 *area = A1 + A2 + A3 + A4;
31498 vecScalarMul(A1, c_1, c_1);
31499 vecScalarMul(A2, c_2, c_2);
31500 vecScalarMul(A3, c_3, c_3);
31501 vecScalarMul(A4, c_4, c_4);
31502 std::fill_n(centroid, 3, 0.0);
31503 centroid = vecScalarMul(F1 / *area, maia::math::vecAdd<3>(centroid, c_1, c_2, c_3, c_4), centroid);
31504
31505 vecScalarMul(A1, n_1, n_1);
31506 vecScalarMul(A2, n_2, n_2);
31507 vecScalarMul(A3, n_3, n_3);
31508 vecScalarMul(A4, n_4, n_4);
31509 std::fill_n(normal, 3, 0.0);
31510 normal = vecScalarMul(F1 / *area, maia::math::vecAdd<3>(normal, n_1, n_2, n_3, n_4), normal);
31511 return;
31512}
31513
31514// -------------------------------------------------------------------------------
31515
31525template <MInt nDim, class SysEqn>
31526template <class _, std::enable_if_t<nDim == 3, _*>>
31528 MFloat* centroid, MFloat* normal) {
31529 TRACE();
31530
31531 MFloat c_1[3] = {0, 0, 0};
31532 MFloat c_2[3] = {0, 0, 0};
31533 MFloat c_3[3] = {0, 0, 0};
31534 MFloat c_4[3] = {0, 0, 0};
31535 MFloat c_5[3] = {0, 0, 0};
31536 MFloat n_1[3] = {0, 0, 0};
31537 MFloat n_2[3] = {0, 0, 0};
31538 MFloat n_3[3] = {0, 0, 0};
31539 MFloat n_4[3] = {0, 0, 0};
31540 MFloat n_5[3] = {0, 0, 0};
31541 MFloat M[3] = {0, 0, 0};
31542 MFloat A1, A2, A3, A4, A5;
31543
31544 maia::math::vecAvg<3>(M, a, b, c, d, e);
31545 computePoly3(a, b, M, &A1, c_1, n_1);
31546 computePoly3(b, c, M, &A2, c_2, n_2);
31547 computePoly3(c, d, M, &A3, c_3, n_3);
31548 computePoly3(d, e, M, &A4, c_4, n_4);
31549 computePoly3(e, a, M, &A5, c_5, n_5);
31550
31551 *area = A1 + A2 + A3 + A4 + A5;
31552 vecScalarMul(A1, c_1, c_1);
31553 vecScalarMul(A2, c_2, c_2);
31554 vecScalarMul(A3, c_3, c_3);
31555 vecScalarMul(A4, c_4, c_4);
31556 vecScalarMul(A5, c_5, c_5);
31557 std::fill_n(centroid, 3, 0.0);
31558 centroid = vecScalarMul(F1 / *area, maia::math::vecAdd<3>(centroid, c_1, c_2, c_3, c_4, c_5), centroid);
31559
31560 vecScalarMul(A1, n_1, n_1);
31561 vecScalarMul(A2, n_2, n_2);
31562 vecScalarMul(A3, n_3, n_3);
31563 vecScalarMul(A4, n_4, n_4);
31564 vecScalarMul(A5, n_5, n_5);
31565 std::fill_n(normal, 3, 0.0);
31566 normal = vecScalarMul(F1 / *area, maia::math::vecAdd<3>(normal, n_1, n_2, n_3, n_4, n_5), normal);
31567 return;
31568}
31569
31570
31571// -------------------------------------------------------------------------------
31572
31582template <MInt nDim, class SysEqn>
31583template <class _, std::enable_if_t<nDim == 3, _*>>
31585 MFloat* area, MFloat* centroid, MFloat* normal) {
31586 TRACE();
31587
31588 MFloat c_1[3] = {0, 0, 0};
31589 MFloat c_2[3] = {0, 0, 0};
31590 MFloat c_3[3] = {0, 0, 0};
31591 MFloat c_4[3] = {0, 0, 0};
31592 MFloat c_5[3] = {0, 0, 0};
31593 MFloat c_6[3] = {0, 0, 0};
31594 MFloat n_1[3] = {0, 0, 0};
31595 MFloat n_2[3] = {0, 0, 0};
31596 MFloat n_3[3] = {0, 0, 0};
31597 MFloat n_4[3] = {0, 0, 0};
31598 MFloat n_5[3] = {0, 0, 0};
31599 MFloat n_6[3] = {0, 0, 0};
31600 MFloat M[3] = {0, 0, 0};
31601 MFloat A1, A2, A3, A4, A5, A6;
31602
31603 maia::math::vecAvg<3>(M, a, b, c, d, e, f);
31604 computePoly3(a, b, M, &A1, c_1, n_1);
31605 computePoly3(b, c, M, &A2, c_2, n_2);
31606 computePoly3(c, d, M, &A3, c_3, n_3);
31607 computePoly3(d, e, M, &A4, c_4, n_4);
31608 computePoly3(e, f, M, &A5, c_5, n_5);
31609 computePoly3(f, a, M, &A6, c_6, n_6);
31610
31611 *area = A1 + A2 + A3 + A4 + A5 + A6;
31612 vecScalarMul(A1, c_1, c_1);
31613 vecScalarMul(A2, c_2, c_2);
31614 vecScalarMul(A3, c_3, c_3);
31615 vecScalarMul(A4, c_4, c_4);
31616 vecScalarMul(A5, c_5, c_5);
31617 vecScalarMul(A6, c_6, c_6);
31618 std::fill_n(centroid, 3, 0.0);
31619 centroid = vecScalarMul(F1 / *area, maia::math::vecAdd<3>(centroid, c_1, c_2, c_3, c_4, c_5, c_6), centroid);
31620
31621 vecScalarMul(A1, n_1, n_1);
31622 vecScalarMul(A2, n_2, n_2);
31623 vecScalarMul(A3, n_3, n_3);
31624 vecScalarMul(A4, n_4, n_4);
31625 vecScalarMul(A5, n_5, n_5);
31626 vecScalarMul(A6, n_6, n_6);
31627 std::fill_n(normal, 3, 0.0);
31628 normal = vecScalarMul(F1 / *area, maia::math::vecAdd<3>(normal, n_1, n_2, n_3, n_4, n_5, n_6), normal);
31629 return;
31630}
31631
31632// -------------------------------------------------------------------------------
31633
31638template <MInt nDim, class SysEqn>
31639template <class _, std::enable_if_t<nDim == 3, _*>>
31641 MFloat* centroid) {
31642 TRACE();
31643
31644 MFloat dummy_1[3] = {0, 0, 0};
31645 MFloat dummy_2[3] = {0, 0, 0};
31646 MFloat dummy_3[3] = {0, 0, 0};
31647 MFloat dummy_4[3] = {0, 0, 0};
31648
31649 vecSub(b, a, dummy_1);
31650 vecSub(c, a, dummy_2);
31651 vecSub(d, a, dummy_3);
31652
31653 maia::math::cross(dummy_1, dummy_2, dummy_4);
31654 *volume = F1B6 * abs(inner_product(dummy_4, dummy_4 + 3, dummy_3, 0.0));
31655 std::fill_n(dummy_4, 3, 0.0);
31656 centroid = vecScalarMul(F1B4, maia::math::vecAdd<3>(dummy_4, a, b, c, d), centroid);
31657 return;
31658}
31659
31660// -------------------------------------------------------------------------------
31661
31666template <MInt nDim, class SysEqn>
31667template <class _, std::enable_if_t<nDim == 3, _*>>
31668void FvBndryCndXD<nDim, SysEqn>::computePyra(MFloat* area, MFloat* base_centroid, MFloat* normal, MFloat* M,
31669 MFloat* volume, MFloat* centroid) {
31670 TRACE();
31671
31672 MFloat h_vec[3] = {0, 0, 0};
31673 MFloat dummy_2[3] = {0, 0, 0};
31674
31675 vecSub(M, base_centroid, h_vec);
31676 std::fill_n(centroid, 3, 0.0);
31677 centroid = maia::math::vecAdd<3>(centroid, vecScalarMul(F1B4, h_vec, dummy_2), base_centroid);
31678 *volume = F1B3 * (*area) * abs(inner_product(h_vec, h_vec + 3, normal, 0.0));
31679 return;
31680}
31681
31682// -------------------------------------------------------------------------------
31683
31693template <MInt nDim, class SysEqn>
31694template <class _, std::enable_if_t<nDim == 3, _*>>
31695void FvBndryCndXD<nDim, SysEqn>::correctFace(MFloat* area, MFloat* centroid, MFloat* area_0, MFloat* centroid_0) {
31696 TRACE();
31697
31698 MFloat dummy_1[3] = {0, 0, 0};
31699 MFloat dummy_2[3] = {0, 0, 0};
31700 vecSub(vecScalarMul(*area_0, centroid_0, dummy_1), vecScalarMul(*area, centroid, dummy_2), centroid);
31701 *area = *area_0 - *area;
31702 vecScalarMul(F1 / *area, centroid, centroid);
31703 return;
31704}
31705
31706// -------------------------------------------------------------------------------
31707
31717template <MInt nDim, class SysEqn>
31718template <class _, std::enable_if_t<nDim == 3, _*>>
31719void FvBndryCndXD<nDim, SysEqn>::correctCell(MFloat* volume, MFloat* centroid, MFloat* volume_0, MFloat* centroid_0) {
31720 TRACE();
31721
31722 MFloat dummy_1[3] = {0, 0, 0};
31723 MFloat dummy_2[3] = {0, 0, 0};
31724 vecSub(vecScalarMul(*volume_0, centroid_0, dummy_1), vecScalarMul(*volume, centroid, dummy_2), centroid);
31725 *volume = *volume_0 - *volume;
31726 vecScalarMul(F1 / *volume, centroid, centroid);
31727 return;
31728}
31729
31730// -------------------------------------------------------------------------------
31731
31736template <MInt nDim, class SysEqn>
31737template <class _, std::enable_if_t<nDim == 3, _*>>
31739 TRACE();
31740
31741 vecScalarMul(-F1, normal, normal);
31742 return;
31743}
31744
31745// ---------------------------------------------------------------------------------
31746// ----------------- other help routines for cut cell generation -----------------
31747// ---------------------------------------------------------------------------------
31748
31761template <MInt nDim, class SysEqn>
31762template <class _, std::enable_if_t<nDim == 3, _*>>
31763void FvBndryCndXD<nDim, SysEqn>::correctInflowBoundary(MInt bcId, MFloat*& meanNormal, MFloat*& basePoint) {
31764 TRACE();
31765
31766 static constexpr MInt edgeCode[24] = {8, 10, 0, 4, 9, 11, 1, 5, 2, 6, 8, 9, 3, 7, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7};
31767 static constexpr MInt faceCode[24] = {0, 4, 1, 4, 2, 4, 3, 4, 0, 5, 1, 5, 2, 5, 3, 5, 0, 2, 1, 2, 0, 3, 1, 3};
31768 static constexpr MInt cornerIndices[8][3] = {{-1, -1, -1}, {1, -1, -1}, {-1, 1, -1}, {1, 1, -1},
31769 {-1, -1, 1}, {1, -1, 1}, {-1, 1, 1}, {1, 1, 1}};
31770 static constexpr MInt cornersMCtoSOLVER[8] = {2, 0, 1, 3, 6, 4, 5, 7};
31771 static constexpr MInt cornersSOLVERtoMC[8] = {1, 2, 0, 3, 5, 6, 4, 7};
31772 static constexpr MInt edgesMCtoSOLVER[12] = {0, 2, 1, 3, 4, 6, 5, 7, 10, 8, 9, 11};
31773 static constexpr MInt facesMCtoSOLVER[6] = {0, 2, 1, 3, 4, 5};
31774 MFloat target[6] = {0, 0, 0, 0, 0, 0};
31775 unsigned char outcode_MC = 0;
31776 MInt noCells = m_bndryCells->size();
31777 MInt cellId;
31778 MFloat gridCellVolume;
31779 MFloat corner[8][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
31780 MInt currentCase;
31781 MBool currentOutcode = false;
31782 MInt nghbrId;
31783 MInt sideId;
31784 MInt otherSideId;
31785 MInt srfcId;
31786 MInt spaceId;
31787 MFloat* faceCentroid[6];
31788 MFloatScratchSpace faceCentroid_scratch(nDim * 6, AT_, "faceCentroid_scratch");
31789 for(MInt i = 0; i < 6; i++)
31790 faceCentroid[i] = &faceCentroid_scratch.p[i * nDim];
31791 MFloat* faceCentroid_0[6];
31792 MFloatScratchSpace faceCentroid_0_scratch(nDim * 6, AT_, "faceCentroid_0_scratch");
31793 for(MInt i = 0; i < 6; i++)
31794 faceCentroid_0[i] = &faceCentroid_0_scratch.p[i * nDim];
31795 MFloat* normal[6];
31796 MFloatScratchSpace normal_scratch(nDim * 6, AT_, "normal_scratch");
31797 for(MInt i = 0; i < 6; i++)
31798 normal[i] = &normal_scratch.p[i * nDim];
31799 const MInt maxNoPyramids = 8;
31800 MFloat* pyraCentroid[maxNoPyramids];
31801 MFloatScratchSpace pyraCentroid_scratch(nDim * maxNoPyramids, AT_, "pyraCentroid_scratch");
31802 for(MInt i = 0; i < maxNoPyramids; i++)
31803 pyraCentroid[i] = &pyraCentroid_scratch.p[i * nDim];
31804 MFloatScratchSpace faceVolume_scratch(F2 * m_noDirs, AT_, "faceVolume_scratch");
31805 MFloatScratchSpace pyraVolume_scratch(2 * m_noDirs + 2, AT_, "pyraVolume_scratch");
31806 MFloatScratchSpace faceVolume_0_scratch(F2 * m_noDirs, AT_, "faceVolume_0_scratch");
31807 MFloat* faceVolume = faceVolume_scratch.getPointer();
31808 MFloat* pyraVolume = pyraVolume_scratch.getPointer();
31809 MFloat* faceVolume_0 = faceVolume_0_scratch.getPointer();
31810 MInt currentSubCase;
31811 MFloat* p_0;
31812 MFloat* p_1;
31813 MFloat* p_2;
31814 MFloat* p_3;
31815 MFloat* p_0s;
31816 MFloat* p_1s;
31817 MFloat* p_2s;
31818 MFloat* p_3s;
31819 MFloat* p_0ss;
31820 MFloat* p_1ss;
31821 MFloat* p_2ss;
31822 MFloat* p_3ss;
31823 MInt cutDummy;
31824 MInt face1;
31825 MInt face2;
31826 MInt face3;
31827 MInt face4;
31828 MInt face5;
31829 MInt face6;
31830 MInt* facepointers[6] = {&face1, &face2, &face3, &face4, &face5, &face6};
31831 MInt cutPoints[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
31832 MFloatScratchSpace normalVec_c_scratch(nDim, AT_, "normalVec_c_scratch");
31833 MFloat* normalVec_c = normalVec_c_scratch.getPointer();
31834 MFloat area_c;
31835 MFloatScratchSpace coordinates_c_scratch(nDim, AT_, "coordinates_c_scratch");
31836 MFloat* coordinates_c = coordinates_c_scratch.getPointer();
31837 MFloat volume_C;
31838 MFloatScratchSpace coordinates_Cell_scratch(nDim, AT_, "coordinates_Cell_scratch");
31839 MFloat* coordinates_Cell = coordinates_Cell_scratch.getPointer();
31840 MFloat M[3] = {0, 0, 0};
31841 MFloat dummy_1[3] = {0, 0, 0};
31842 MFloat dummy_2[3] = {0, 0, 0};
31843 MFloat dummy_3[3] = {0, 0, 0};
31844 MBool nfs_cur[6] = {false, false, false, false, false, false};
31845 MInt noFaces;
31846 MBool cornerCell = false;
31847 MFloat normalDiff = F0;
31848 MFloat normalEps = 1e-4; // works, but is no sophisticated value :)
31849 const MInt maxNoEdges = 800;
31850 MFloatPointerScratchSpace featureEdges_scratch(maxNoEdges, AT_, "featureEdges_scratch");
31851 MFloat** featureEdges = featureEdges_scratch.getPointer();
31852 const MInt maxNoIntersectPointsPerFace = 10;
31853 MFloatPointerPointerScratchSpace intersectionPoints_scratchPP(2 * nDim, AT_, "intersectionPoints_scratchPP");
31854 MFloatPointerScratchSpace intersectionPoints_scratchP(2 * nDim * maxNoIntersectPointsPerFace, AT_,
31855 "intersectionPoints_scratchP");
31856 MFloatScratchSpace intersectionPoints_scratch(2 * nDim * maxNoIntersectPointsPerFace * nDim, AT_,
31857 "intersectionPoints_scratch");
31858 MFloat*** intersectionPoints = intersectionPoints_scratchPP.getPointer();
31859 for(MInt i = 0; i < 2 * nDim; i++) {
31860 intersectionPoints[i] = &intersectionPoints_scratchP.p[i * maxNoIntersectPointsPerFace];
31861 for(MInt j = 0; j < maxNoIntersectPointsPerFace; j++) {
31862 intersectionPoints[i][j] = &intersectionPoints_scratch.p[i * maxNoIntersectPointsPerFace * nDim + j * nDim];
31863 }
31864 }
31865 MInt noWallNodes, noInflowNodes, noFeatureEdges;
31866 MInt noIntersectionPoints[6] = {0, 0, 0, 0, 0, 0};
31867 const MInt maxNoNodes =
31868 1000; // might be necessary to increase for extremely detailed .stl geometries! See error output below
31869 MIntScratchSpace wallNodes_scratch(maxNoNodes, AT_, "wallNodes_scratch");
31870 MIntScratchSpace inflowNodes_scratch(maxNoNodes, AT_, "inflowNodes_scratch");
31871 MInt* wallNodes = wallNodes_scratch.getPointer();
31872 MInt* inflowNodes = inflowNodes_scratch.getPointer();
31873 MFloatPointerScratchSpace target2_scratchP(nDim, AT_, "target2_scratchP");
31874 MFloat** target2 = target2_scratchP.getPointer();
31875 MFloatScratchSpace target2_scratch(nDim * nDim, AT_, "target2_scratch");
31876 for(MInt i = 0; i < nDim; i++)
31877 target2[i] = &target2_scratch.p[i * nDim];
31878 MInt index1, index2, index3;
31879 MInt pointCount;
31880 MInt pointIndices[2] = {0, 0};
31881 MInt faceStart;
31882 MFloat newArea;
31883 MFloat* points1[8];
31884 MInt noPoints1;
31885 MFloat* points2[8];
31886 MInt noPoints2;
31887 noPoints1 = 0;
31888 noPoints2 = 0;
31889 MIntScratchSpace facePoints_scratch(12, AT_, "facePoints_scratch");
31890 MInt* facePoints = facePoints_scratch.getPointer();
31891 MFloat* points[6];
31892 MFloatScratchSpace points_scratch(6 * nDim, AT_, "points_scratch");
31893 for(MInt i = 0; i < 6; i++) {
31894 points[i] = &points_scratch.p[i * nDim];
31895 }
31896 MIntScratchSpace nextFaces_scratch(2 * nDim, AT_, "nextFaces_scratch");
31897 MInt* nextFaces = nextFaces_scratch.getPointer();
31898 MFloat area1, area2;
31899 MFloatScratchSpace normal1_scratch(nDim, AT_, "normal1_scratch");
31900 MFloatScratchSpace normal2_scratch(nDim, AT_, "normal2_scratch");
31901 MFloatScratchSpace centroid1_scratch(nDim, AT_, "centroid1_scratch");
31902 MFloatScratchSpace centroid2_scratch(nDim, AT_, "centroid2_scratch");
31903 MFloat* normal1 = normal1_scratch.getPointer();
31904 MFloat* normal2 = normal2_scratch.getPointer();
31905 MFloat* centroid1 = centroid1_scratch.getPointer();
31906 MFloat* centroid2 = centroid2_scratch.getPointer();
31907 MInt bcId1 = 0;
31908 MInt bcId2 = 0;
31909 MInt bcWall = 0;
31910 MInt bcInlet = 0;
31911 MInt noUnusedCutPoints;
31912 MIntScratchSpace unusedCutPoints_scratch(2, AT_, "unusedCutPoints_scratch");
31913 MInt* unusedCutPoints = unusedCutPoints_scratch.getPointer();
31914 MInt& iter = m_static_correctInflowBoundary_iter;
31915 stringstream fileName2;
31916 fileName2 << "cutSurface_newParts" << domainId() << "_" << iter++ << ".stl";
31917 ofstream ofl;
31918 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
31919 MBool secondHalf = false;
31920 MInt cutEdge, cutEdgeNghbr;
31921 MInt cutFace1, cutFace2, cutFaceNghbr1, cutFaceNghbr2;
31922 MFloat delta_IP;
31923 MIntScratchSpace levelSetCornerSigns(8, AT_, "levelSetCornerSigns");
31924 MBool inside = true;
31925 if(bcId < 3000) // special treatment for bc30040 (cube testcase)
31926 inside = false;
31927
31928 if(ofl) {
31929 // set fixed floating point output
31930 ofl.setf(ios::fixed);
31931 ofl.precision(7);
31932
31933 ofl << "solid cutsurface " << endl;
31934
31935 //-----------------------------------------
31936
31937 // 1) find cornerCells (normal differs from mean normal, inflow BC)
31938 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
31939 noUnusedCutPoints = 0;
31940 cornerCell = false;
31941 cellId = m_bndryCells->a[bndryId].m_cellId;
31942 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
31943 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
31944 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == bcId) {
31945 normalDiff = POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0] - meanNormal[0])
31946 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1] - meanNormal[1])
31947 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2] - meanNormal[2]);
31948 if(normalDiff > normalEps) {
31949 cornerCell = true;
31950 }
31951 }
31952 }
31953 }
31954
31955 // process Corner Cells
31956 if(cornerCell) {
31957 gridCellVolume = m_solver->grid().gridCellVolume(m_solver->a_level(cellId));
31958 outcode_MC = 0;
31959 volume_C = 0;
31960 coordinates_Cell[0] = 0;
31961 coordinates_Cell[1] = 0;
31962 coordinates_Cell[2] = 0;
31963 noFaces = 0;
31964
31965 for(MInt cutPoint = 0; cutPoint < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cutPoint++) {
31966 cutPoints[m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutPoint]] = cutPoint;
31967 }
31968
31969 for(MInt i = 0; i < nDim; i++) {
31970 target[i] = m_solver->a_coordinate(cellId, i)
31971 - F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId)) * 1.05;
31972 target[i + nDim] = m_solver->a_coordinate(cellId, i)
31973 + F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId)) * 1.05;
31974 faceVolume[2 * i] = POW2(m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId)));
31975 faceVolume[2 * i + 1] = faceVolume[2 * i];
31976 for(MInt j = 0; j < 3; j++) {
31977 faceCentroid[2 * i][j] = m_solver->a_coordinate(cellId, j);
31978 faceCentroid[2 * i + 1][j] = m_solver->a_coordinate(cellId, j);
31979 }
31980 faceCentroid[2 * i][i] -= F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
31981 faceCentroid[2 * i + 1][i] += F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
31982 }
31983
31984 // 1. get all triangles in currentCell (target)
31985 std::vector<MInt> nodeList;
31986 m_solver->m_geometry->getIntersectionElements(target, nodeList);
31987 const MInt noNodes = nodeList.size();
31988 if(noNodes > maxNoNodes) {
31989 stringstream errorMessage;
31990 errorMessage << "Error in FvBndryCndXD::correctInflowBoundary - noNodes = " << noNodes
31991 << " > maxNoNodes = " << maxNoNodes << ". Please increase maxNoNodes! ";
31992 mTerm(1, AT_, errorMessage.str());
31993 }
31994
31995 // 2. get In/Outcode of the corners of the voxel
31996 // 0 -> Corner is outside Fluid Domain
31997 // 1 -> Corner is inside Fluid Domain or on Boundary
31998 for(MInt j = 0; j < 8; j++) {
31999 for(MInt dim = 0; dim < nDim; dim++) {
32000 corner[j][dim] = m_solver->a_coordinate(cellId, dim)
32001 + cornerIndices[j][dim] * F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
32002 }
32003 currentOutcode = !((MBool)m_solver->m_geometry->pointIsInside2(corner[j]));
32004 if(currentOutcode) outcode_MC = outcode_MC | (1 << cornersSOLVERtoMC[j]);
32005 }
32006
32007 // 3. Determine Case and check if case is implemented and if case is unambiguous
32008 currentCase = (MInt)cases[outcode_MC][0];
32009 currentSubCase = (MInt)cases[outcode_MC][1];
32010 if(!(m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints == caseCutPoints[currentCase])) {
32011 cerr << "FvBndryCndXD::correctInflowBoundary: Detected special inlet correction cell! cellId " << cellId
32012 << ", bndryId: " << bndryId << " cutPointsTheory: " << caseCutPoints[currentCase]
32013 << " actual Cut Points: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints
32014 << " case: " << currentCase << endl;
32015 }
32016 if(!caseStatesSTL[currentCase][0]) {
32017 cerr << "FvBndryCndXD::correctInflowBoundary - Error: Case not implemented: " << currentCase << endl;
32018 continue;
32019 }
32020
32021
32022 // 2) Make a list of Wall-triangles and one of Inflow-triangles
32023 getSortedElements(nodeList, noWallNodes, wallNodes, noInflowNodes, inflowNodes, bcId);
32024 if(noWallNodes > 0)
32025 bcWall = m_solver->m_geometry->elements[wallNodes[0]].m_bndCndId;
32026 else {
32027 stringstream fileName;
32028 fileName << cellId << ".stl";
32029 writeStlFileOfCell(cellId, (fileName.str()).c_str());
32030 plotEdges(noFeatureEdges, featureEdges);
32031 plotIntersectionPoints(noIntersectionPoints, intersectionPoints);
32032 stringstream errorMessage;
32033 errorMessage << "cell " << cellId << " has no wall nodes!";
32034 mTerm(1, AT_, errorMessage.str());
32035 }
32036
32037 if(noInflowNodes > 0)
32038 bcInlet = m_solver->m_geometry->elements[inflowNodes[0]].m_bndCndId;
32039 else {
32040 stringstream errorMessage;
32041 errorMessage << " cell " << cellId << " has no inflow nodes!";
32042 mTerm(1, AT_, errorMessage.str());
32043 }
32044
32045 // 3) Get feature Edges (Edges between Wall triangles and Inflow triangles) as a list of start/endpoints
32046 getFeatureEdges(noFeatureEdges, featureEdges, noWallNodes, wallNodes, meanNormal, basePoint);
32047
32048 // 4) Get Intersection points of featureEdges with Voxel faces and store them
32049 for(MInt face = 0; face < 6; face++) {
32050 index1 = face / 2;
32051 index2 = (index1 + 1) % 3;
32052 index3 = (index2 + 1) % 3;
32053 for(MInt i = 0; i < 3; i++)
32054 for(MInt j = 0; j < 3; j++)
32055 target2[i][j] = faceCentroid[face][j];
32056
32057 target2[0][index2] -= F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
32058 target2[0][index3] -= F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
32059 target2[1][index2] += F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
32060 target2[1][index3] -= F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
32061 target2[2][index2] -= F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
32062 target2[2][index3] += F1B2 * m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId));
32063
32064
32065 getIntersectionPoints(target2, featureEdges, noFeatureEdges, (MInt)(face / 2), intersectionPoints[face],
32066 noIntersectionPoints[face]);
32067 }
32068
32069 // 5) Compute cornerCells as usual - cells with multiple cut faces can not be corrected!
32070 if(!caseStatesSTL[currentCase][1]) {
32071 stringstream errorMessage;
32072 errorMessage << " Case " << currentCase << " not allowed for Inflow/Outflow boundary correction!";
32073 mTerm(1, AT_, errorMessage.str());
32074 } else {
32075 m_bndryCells->a[bndryId].m_noSrfcs = 1;
32076 secondHalf = false;
32077 switch(currentCase) {
32078 case 0:
32079 cerr << "FvBndryCndXD::correctInflowBoundary - Error: Cell is not a boundary cell!" << endl;
32080 cerr << "CellId: " << cellId << " BndryId: " << bndryId << endl;
32081 break;
32082 case 1: {
32083 // cerr << "Case 1 detected. Starting Cutface computation..." << endl;
32084 for(MInt face = 0; face < 6; face++) {
32085 nfs_cur[face] = nfs1[currentSubCase][face];
32086 }
32087 p_0 = corner[cornersMCtoSOLVER[tiling1STL[currentSubCase][0]]];
32088 noFaces = 3;
32089 if(currentSubCase < 8) { // 1 Point is inside, 5 Points are outside
32090 } else { // 1 Point is outside, 5 Points are inside
32091 for(MInt i = 0; i < 6; i++) {
32092 faceVolume_0[i] = faceVolume[i];
32093 for(MInt j = 0; j < 3; j++) {
32094 faceCentroid_0[i][j] = faceCentroid[i][j];
32095 }
32096 }
32097 }
32098 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][1]];
32099 p_1 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32100 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][2]];
32101 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32102 cutDummy = edgesMCtoSOLVER[tiling1STL[currentSubCase][3]];
32103 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32104 face1 = facesMCtoSOLVER[tiling1STL[currentSubCase][4]];
32105 face2 = facesMCtoSOLVER[tiling1STL[currentSubCase][5]];
32106 face3 = facesMCtoSOLVER[tiling1STL[currentSubCase][6]];
32107
32108 // identify unused (=special) cut points
32109 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
32110 if(p_1 == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32111 || p_2 == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32112 || p_3 == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]) {
32113 continue;
32114 } else {
32115 unusedCutPoints[noUnusedCutPoints++] = cp;
32116 }
32117 }
32118
32119 for(MInt face = 0; face < noFaces; face++) {
32120 facePoints[face] = -1;
32121 facePoints[2 * face] = -1;
32122 nextFaces[face] = -1;
32123 }
32124 nextFaces[face1] = face3;
32125 nextFaces[face2] = face1;
32126 nextFaces[face3] = face2;
32127 facePoints[2 * face1] = 2;
32128 facePoints[2 * face1 + 1] = 0;
32129 facePoints[2 * face2] = 1;
32130 facePoints[2 * face2 + 1] = 2;
32131 facePoints[2 * face3] = 0;
32132 facePoints[2 * face3 + 1] = 1;
32133 for(MInt i = 0; i < 3; i++) {
32134 points[0][i] = p_1[i];
32135 points[1][i] = p_2[i];
32136 points[2][i] = p_3[i];
32137 }
32138
32139 computeTri(p_0, p_1, p_3, &faceVolume[face1], faceCentroid[face1], normal[face1]);
32140 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2], normal[face2]);
32141 computeTri(p_0, p_2, p_1, &faceVolume[face3], faceCentroid[face3], normal[face3]);
32142
32143 computePoly3(p_1, p_2, p_3, &area_c, coordinates_c, normalVec_c);
32144
32145 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3);
32146
32147 computeTetra(p_0, p_1, p_2, p_3, &volume_C, coordinates_Cell);
32148
32149 if(currentSubCase >= 8) {
32150 secondHalf = true;
32151 }
32152
32153 m_bndryCells->a[bndryId].m_volume = volume_C;
32154 // create 1 Cut face
32155 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
32156 for(MInt dim = 0; dim < 3; dim++) {
32157 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
32158 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
32159 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
32160 }
32161 } break;
32162 case 2: {
32163 // cerr << "Case 2 detected. Starting Cutface computation..." << endl;
32164 for(MInt face = 0; face < 6; face++) {
32165 nfs_cur[face] = nfs2[currentSubCase][face];
32166 }
32167 noFaces = 4;
32168 p_0 = corner[cornersMCtoSOLVER[tiling2STL[currentSubCase][0]]];
32169 p_0s = corner[cornersMCtoSOLVER[tiling2STL[currentSubCase][1]]];
32170 if(currentSubCase < 12) { // 2 Points are inside, 4 Points are outside
32171 } else { // 2 Points are outside, 4 Points are inside
32172 for(MInt i = 0; i < 6; i++) {
32173 faceVolume_0[i] = faceVolume[i];
32174 for(MInt j = 0; j < 3; j++) {
32175 faceCentroid_0[i][j] = faceCentroid[i][j];
32176 }
32177 }
32178 }
32179
32180 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][2]];
32181 p_3 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32182 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][3]];
32183 p_2 = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32184 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][4]];
32185 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32186 cutDummy = edgesMCtoSOLVER[tiling2STL[currentSubCase][5]];
32187 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32188 face1 = facesMCtoSOLVER[tiling2STL[currentSubCase][6]];
32189 face2 = facesMCtoSOLVER[tiling2STL[currentSubCase][7]];
32190 face3 = facesMCtoSOLVER[tiling2STL[currentSubCase][8]];
32191 face4 = facesMCtoSOLVER[tiling2STL[currentSubCase][9]];
32192
32193 // identify unused (=special) cut points
32194 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
32195 if(p_3 == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32196 || p_2 == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32197 || p_3s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32198 || p_2s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]) {
32199 continue;
32200 } else {
32201 unusedCutPoints[noUnusedCutPoints++] = cp;
32202 }
32203 }
32204
32205 for(MInt face = 0; face < noFaces; face++) {
32206 facePoints[face] = -1;
32207 facePoints[2 * face] = -1;
32208 nextFaces[face] = -1;
32209 }
32210 nextFaces[face1] = face3;
32211 nextFaces[face2] = face1;
32212 nextFaces[face3] = face4;
32213 nextFaces[face4] = face2;
32214 facePoints[2 * face1] = 0;
32215 facePoints[2 * face1 + 1] = 1;
32216 facePoints[2 * face2] = 3;
32217 facePoints[2 * face2 + 1] = 0;
32218 facePoints[2 * face3] = 1;
32219 facePoints[2 * face3 + 1] = 2;
32220 facePoints[2 * face4] = 2;
32221 facePoints[2 * face4 + 1] = 3;
32222 for(MInt i = 0; i < 3; i++) {
32223 points[0][i] = p_3[i];
32224 points[1][i] = p_3s[i];
32225 points[2][i] = p_2s[i];
32226 points[3][i] = p_2[i];
32227 }
32228
32229 computeTri(p_0, p_3, p_2, &faceVolume[face2], faceCentroid[face2], normal[face2]);
32230 computeTri(p_0s, p_3s, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
32231 computeTrapez(p_0, p_0s, p_3s, p_3, &faceVolume[face1], faceCentroid[face1], normal[face1]);
32232 computeTrapez(p_2, p_2s, p_0s, p_0, &faceVolume[face4], faceCentroid[face4], normal[face4]);
32233
32234 computePoly4(p_3, p_3s, p_2s, p_2, &area_c, coordinates_c, normalVec_c);
32235
32236 maia::math::vecAvg<3>(M, p_0, p_0s, p_2, p_2s, p_3, p_3s);
32237
32238 for(MInt i = 0; i < 4; i++) {
32239 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
32240 &pyraVolume[i], pyraCentroid[i]);
32241 }
32242 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[4], pyraCentroid[4]);
32243 for(MInt i = 0; i < 5; i++) {
32244 volume_C += pyraVolume[i];
32245 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
32246 }
32247 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
32248
32249 if(currentSubCase >= 12) {
32250 secondHalf = true;
32251 }
32252
32253 m_bndryCells->a[bndryId].m_volume = volume_C;
32254 // create 1 Cut face
32255 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
32256 for(MInt dim = 0; dim < 3; dim++) {
32257 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
32258 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
32259 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
32260 }
32261 } break;
32262 case 5: {
32263 // cerr << "Case 5 detected. Starting Cutface computation..." << endl;
32264 for(MInt face = 0; face < 6; face++) {
32265 nfs_cur[face] = nfs5[currentSubCase][face];
32266 }
32267 noFaces = 5;
32268 p_0 = corner[cornersMCtoSOLVER[tiling5STL[currentSubCase][0]]];
32269 p_1 = corner[cornersMCtoSOLVER[tiling5STL[currentSubCase][1]]];
32270 p_2 = corner[cornersMCtoSOLVER[tiling5STL[currentSubCase][2]]];
32271 if(currentSubCase < 24) { // 3 Points are inside, 5 Points are outside
32272 } else { // 3 Points are outside, 5 Points are inside
32273 for(MInt i = 0; i < 6; i++) {
32274 faceVolume_0[i] = faceVolume[i];
32275 for(MInt j = 0; j < 3; j++) {
32276 faceCentroid_0[i][j] = faceCentroid[i][j];
32277 }
32278 }
32279 }
32280
32281 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][3]];
32282 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32283 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][4]];
32284 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32285 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][5]];
32286 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32287 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][6]];
32288 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32289 cutDummy = edgesMCtoSOLVER[tiling5STL[currentSubCase][7]];
32290 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32291 face1 = facesMCtoSOLVER[tiling5STL[currentSubCase][8]];
32292 face2 = facesMCtoSOLVER[tiling5STL[currentSubCase][9]];
32293 face3 = facesMCtoSOLVER[tiling5STL[currentSubCase][10]];
32294 face4 = facesMCtoSOLVER[tiling5STL[currentSubCase][11]];
32295 face5 = facesMCtoSOLVER[tiling5STL[currentSubCase][12]];
32296
32297 // identify unused (=special) cut points
32298 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
32299 if(p_0s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32300 || p_0ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32301 || p_1s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32302 || p_2s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32303 || p_2ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]) {
32304 continue;
32305 } else {
32306 unusedCutPoints[noUnusedCutPoints++] = cp;
32307 }
32308 }
32309
32310 for(MInt face = 0; face < noFaces; face++) {
32311 facePoints[face] = -1;
32312 facePoints[2 * face] = -1;
32313 nextFaces[face] = -1;
32314 }
32315 nextFaces[face1] = face2;
32316 nextFaces[face2] = face3;
32317 nextFaces[face3] = face4;
32318 nextFaces[face4] = face5;
32319 nextFaces[face5] = face1;
32320 facePoints[2 * face1] = 3;
32321 facePoints[2 * face1 + 1] = 4;
32322 facePoints[2 * face2] = 4;
32323 facePoints[2 * face2 + 1] = 0;
32324 facePoints[2 * face3] = 0;
32325 facePoints[2 * face3 + 1] = 1;
32326 facePoints[2 * face4] = 1;
32327 facePoints[2 * face4 + 1] = 2;
32328 facePoints[2 * face5] = 2;
32329 facePoints[2 * face5 + 1] = 3;
32330 for(MInt i = 0; i < 3; i++) {
32331 points[0][i] = p_0s[i];
32332 points[1][i] = p_1s[i];
32333 points[2][i] = p_2s[i];
32334 points[3][i] = p_2ss[i];
32335 points[4][i] = p_0ss[i];
32336 }
32337
32338 computePoly5(p_0, p_0ss, p_2ss, p_2, p_1, &faceVolume[face1], faceCentroid[face1], normal[face1]);
32339 computeTri(p_0ss, p_0, p_0s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
32340 computeTrapez(p_0, p_1, p_1s, p_0s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
32341 computeTrapez(p_1, p_1s, p_2s, p_2, &faceVolume[face4], faceCentroid[face4], normal[face4]);
32342 computeTri(p_2s, p_2, p_2ss, &faceVolume[face5], faceCentroid[face5], normal[face5]);
32343
32344 computePoly5(p_0s, p_1s, p_2s, p_2ss, p_0ss, &area_c, coordinates_c, normalVec_c);
32345
32346 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_0s, p_1s, p_2s, p_0ss, p_2ss);
32347
32348 for(MInt i = 0; i < 5; i++) {
32349 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
32350 &pyraVolume[i], pyraCentroid[i]);
32351 }
32352 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
32353 for(MInt i = 0; i < 6; i++) {
32354 volume_C += pyraVolume[i];
32355 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
32356 }
32357 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
32358
32359 if(currentSubCase >= 24) {
32360 secondHalf = true;
32361 }
32362
32363 m_bndryCells->a[bndryId].m_volume = volume_C;
32364 // create 1 Cut face
32365 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
32366 for(MInt dim = 0; dim < 3; dim++) {
32367 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
32368 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
32369 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
32370 }
32371 } break;
32372 case 8: {
32373 // cerr << "Case 8 detected. Starting Cutface computation..." << endl;
32374 for(MInt face = 0; face < 6; face++) {
32375 nfs_cur[face] = nfs8[currentSubCase][face];
32376 }
32377 noFaces = 4;
32378 p_0 = corner[cornersMCtoSOLVER[tiling8STL[currentSubCase][0]]];
32379 p_1 = corner[cornersMCtoSOLVER[tiling8STL[currentSubCase][1]]];
32380 p_2 = corner[cornersMCtoSOLVER[tiling8STL[currentSubCase][2]]];
32381 p_3 = corner[cornersMCtoSOLVER[tiling8STL[currentSubCase][3]]];
32382
32383 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][4]];
32384 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32385 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][5]];
32386 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32387 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][6]];
32388 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32389 cutDummy = edgesMCtoSOLVER[tiling8STL[currentSubCase][7]];
32390 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32391 face5 = facesMCtoSOLVER[tiling8STL[currentSubCase][8]];
32392 face1 = facesMCtoSOLVER[tiling8STL[currentSubCase][9]];
32393 face2 = facesMCtoSOLVER[tiling8STL[currentSubCase][10]];
32394 face3 = facesMCtoSOLVER[tiling8STL[currentSubCase][11]];
32395 face4 = facesMCtoSOLVER[tiling8STL[currentSubCase][12]];
32396
32397 // identify unused (=special) cut points
32398 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
32399 if(p_0s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32400 || p_1s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32401 || p_2s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32402 || p_3s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]) {
32403 continue;
32404 } else {
32405 unusedCutPoints[noUnusedCutPoints++] = cp;
32406 }
32407 }
32408
32409 for(MInt face = 0; face < noFaces; face++) {
32410 facePoints[face] = -1;
32411 facePoints[2 * face] = -1;
32412 nextFaces[face] = -1;
32413 }
32414 nextFaces[face1] = face2;
32415 nextFaces[face2] = face3;
32416 nextFaces[face3] = face4;
32417 nextFaces[face4] = face1;
32418 facePoints[2 * face1] = 0;
32419 facePoints[2 * face1 + 1] = 1;
32420 facePoints[2 * face2] = 1;
32421 facePoints[2 * face2 + 1] = 2;
32422 facePoints[2 * face3] = 2;
32423 facePoints[2 * face3 + 1] = 3;
32424 facePoints[2 * face4] = 3;
32425 facePoints[2 * face4 + 1] = 0;
32426 for(MInt i = 0; i < 3; i++) {
32427 points[0][i] = p_0s[i];
32428 points[1][i] = p_1s[i];
32429 points[2][i] = p_2s[i];
32430 points[3][i] = p_3s[i];
32431 }
32432
32433 computeTrapez(p_0, p_1, p_1s, p_0s, &faceVolume[face1], faceCentroid[face1], normal[face1]);
32434 computeTrapez(p_1, p_2, p_2s, p_1s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
32435 computeTrapez(p_2, p_3, p_3s, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
32436 computeTrapez(p_3, p_0, p_0s, p_3s, &faceVolume[face4], faceCentroid[face4], normal[face4]);
32437
32438 computeTrapez(p_0, p_3, p_2, p_1, &faceVolume[face5], faceCentroid[face5], normal[face5]);
32439
32440 computePoly4(p_0s, p_1s, p_2s, p_3s, &area_c, coordinates_c, normalVec_c);
32441
32442 maia::math::vecAvg<3>(M, p_0, p_0s, p_1, p_1s, p_2, p_2s, p_3, p_3s);
32443
32444 for(MInt i = 0; i < 5; i++) {
32445 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
32446 &pyraVolume[i], pyraCentroid[i]);
32447 }
32448 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[5], pyraCentroid[5]);
32449 for(MInt i = 0; i < 6; i++) {
32450 volume_C += pyraVolume[i];
32451 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
32452 }
32453 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
32454
32455 m_bndryCells->a[bndryId].m_volume = volume_C;
32456
32457 // create 1 Cut face
32458 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
32459 for(MInt dim = 0; dim < 3; dim++) {
32460 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
32461 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
32462 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
32463 }
32464 } break;
32465 case 9: {
32466 // cerr << "Case 9 detected. Starting Cutface computation..." << endl;
32467 for(MInt face = 0; face < 6; face++) {
32468 nfs_cur[face] = nfs9[currentSubCase][face];
32469 }
32470 noFaces = 6;
32471 p_0 = corner[cornersMCtoSOLVER[tiling9STL[currentSubCase][0]]];
32472 p_1 = corner[cornersMCtoSOLVER[tiling9STL[currentSubCase][1]]];
32473 p_2 = corner[cornersMCtoSOLVER[tiling9STL[currentSubCase][2]]];
32474 p_3 = corner[cornersMCtoSOLVER[tiling9STL[currentSubCase][3]]];
32475
32476 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][4]];
32477 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32478 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][5]];
32479 p_1ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32480 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][6]];
32481 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32482 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][7]];
32483 p_2ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32484 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][8]];
32485 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32486 cutDummy = edgesMCtoSOLVER[tiling9STL[currentSubCase][9]];
32487 p_3ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32488
32489 // identify unused (=special) cut points
32490 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
32491 if(p_1ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32492 || p_1s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32493 || p_2s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32494 || p_2ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32495 || p_3s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32496 || p_3ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]) {
32497 continue;
32498 } else {
32499 unusedCutPoints[noUnusedCutPoints++] = cp;
32500 }
32501 }
32502 face1 = facesMCtoSOLVER[tiling9STL[currentSubCase][10]];
32503 face2 = facesMCtoSOLVER[tiling9STL[currentSubCase][11]];
32504 face3 = facesMCtoSOLVER[tiling9STL[currentSubCase][12]];
32505 face4 = facesMCtoSOLVER[tiling9STL[currentSubCase][13]];
32506 face5 = facesMCtoSOLVER[tiling9STL[currentSubCase][14]];
32507 face6 = facesMCtoSOLVER[tiling9STL[currentSubCase][15]];
32508
32509 for(MInt face = 0; face < noFaces; face++) {
32510 facePoints[face] = -1;
32511 facePoints[2 * face] = -1;
32512 nextFaces[face] = -1;
32513 }
32514 nextFaces[face1] = face6;
32515 nextFaces[face2] = face5;
32516 nextFaces[face3] = face2;
32517 nextFaces[face4] = face1;
32518 nextFaces[face5] = face4;
32519 nextFaces[face6] = face3;
32520 facePoints[2 * face1] = 3;
32521 facePoints[2 * face1 + 1] = 4;
32522 facePoints[2 * face2] = 0;
32523 facePoints[2 * face2 + 1] = 1;
32524 facePoints[2 * face3] = 5;
32525 facePoints[2 * face3 + 1] = 0;
32526 facePoints[2 * face4] = 2;
32527 facePoints[2 * face4 + 1] = 3;
32528 facePoints[2 * face5] = 1;
32529 facePoints[2 * face5 + 1] = 2;
32530 facePoints[2 * face6] = 4;
32531 facePoints[2 * face6 + 1] = 5;
32532 for(MInt i = 0; i < 3; i++) {
32533 points[0][i] = p_1ss[i];
32534 points[1][i] = p_1s[i];
32535 points[2][i] = p_2ss[i];
32536 points[3][i] = p_2s[i];
32537 points[4][i] = p_3ss[i];
32538 points[5][i] = p_3s[i];
32539 }
32540
32541 computePoly5(p_0, p_3, p_3ss, p_2s, p_2, &faceVolume[face1], faceCentroid[face1], normal[face1]);
32542 computePoly5(p_0, p_1, p_1ss, p_3s, p_3, &faceVolume[face3], faceCentroid[face3], normal[face3]);
32543 computePoly5(p_0, p_2, p_2ss, p_1s, p_1, &faceVolume[face5], faceCentroid[face5], normal[face5]);
32544 computeTri(p_1, p_1s, p_1ss, &faceVolume[face2], faceCentroid[face2], normal[face2]);
32545 computeTri(p_2, p_2s, p_2ss, &faceVolume[face4], faceCentroid[face4], normal[face4]);
32546 computeTri(p_3, p_3s, p_3ss, &faceVolume[face6], faceCentroid[face6], normal[face6]);
32547
32548 computePoly6(p_1ss, p_1s, p_2ss, p_2s, p_3ss, p_3s, &area_c, coordinates_c, normalVec_c);
32549
32550 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3, p_1s, p_2s, p_3s, p_1ss, p_2ss, p_3ss);
32551
32552 for(MInt i = 0; i < 6; i++) {
32553 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
32554 &pyraVolume[i], pyraCentroid[i]);
32555 }
32556 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
32557 for(MInt i = 0; i < 7; i++) {
32558 volume_C += pyraVolume[i];
32559 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
32560 }
32561 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
32562
32563 m_bndryCells->a[bndryId].m_volume = volume_C;
32564 // create 1 Cut face
32565 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
32566 for(MInt dim = 0; dim < 3; dim++) {
32567 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
32568 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
32569 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
32570 }
32571 }
32572
32573 break;
32574 case 11: {
32575 // cerr << "Case 11 detected. Starting Cutface computation..." << endl;
32576 for(MInt face = 0; face < 6; face++) {
32577 nfs_cur[face] = nfs11[currentSubCase][face];
32578 }
32579 noFaces = 6;
32580 p_0 = corner[cornersMCtoSOLVER[tiling11STL[currentSubCase][0]]];
32581 p_1 = corner[cornersMCtoSOLVER[tiling11STL[currentSubCase][1]]];
32582 p_2 = corner[cornersMCtoSOLVER[tiling11STL[currentSubCase][2]]];
32583 p_3 = corner[cornersMCtoSOLVER[tiling11STL[currentSubCase][3]]];
32584
32585 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][4]];
32586 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32587 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][5]];
32588 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32589 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][6]];
32590 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32591 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][7]];
32592 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32593 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][8]];
32594 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32595 cutDummy = edgesMCtoSOLVER[tiling11STL[currentSubCase][9]];
32596 p_3ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32597 face1 = facesMCtoSOLVER[tiling11STL[currentSubCase][10]];
32598 face2 = facesMCtoSOLVER[tiling11STL[currentSubCase][11]];
32599 face3 = facesMCtoSOLVER[tiling11STL[currentSubCase][12]];
32600 face4 = facesMCtoSOLVER[tiling11STL[currentSubCase][13]];
32601 face5 = facesMCtoSOLVER[tiling11STL[currentSubCase][14]];
32602 face6 = facesMCtoSOLVER[tiling11STL[currentSubCase][15]];
32603
32604 // identify unused (=special) cut points
32605 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
32606 if(p_0ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32607 || p_0s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32608 || p_1s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32609 || p_2s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32610 || p_3s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32611 || p_3ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]) {
32612 continue;
32613 } else {
32614 unusedCutPoints[noUnusedCutPoints++] = cp;
32615 }
32616 }
32617
32618 for(MInt face = 0; face < noFaces; face++) {
32619 facePoints[face] = -1;
32620 facePoints[2 * face] = -1;
32621 nextFaces[face] = -1;
32622 }
32623 nextFaces[face1] = face5;
32624 nextFaces[face2] = face4;
32625 nextFaces[face3] = face6;
32626 nextFaces[face4] = face1;
32627 nextFaces[face5] = face3;
32628 nextFaces[face6] = face2;
32629 facePoints[2 * face1] = 0;
32630 facePoints[2 * face1 + 1] = 1;
32631 facePoints[2 * face2] = 4;
32632 facePoints[2 * face2 + 1] = 5;
32633 facePoints[2 * face3] = 2;
32634 facePoints[2 * face3 + 1] = 3;
32635 facePoints[2 * face4] = 5;
32636 facePoints[2 * face4 + 1] = 0;
32637 facePoints[2 * face5] = 1;
32638 facePoints[2 * face5 + 1] = 2;
32639 facePoints[2 * face6] = 3;
32640 facePoints[2 * face6 + 1] = 4;
32641 for(MInt i = 0; i < 3; i++) {
32642 points[0][i] = p_0ss[i];
32643 points[1][i] = p_0s[i];
32644 points[2][i] = p_2s[i];
32645 points[3][i] = p_3ss[i];
32646 points[4][i] = p_3s[i];
32647 points[5][i] = p_1s[i];
32648 }
32649
32650 computeTri(p_0, p_0s, p_0ss, &faceVolume[face1], faceCentroid[face1], normal[face1]);
32651 computePoly5(p_3s, p_3, p_2, p_1, p_1s, &faceVolume[face2], faceCentroid[face2], normal[face2]);
32652 computeTrapez(p_2, p_3, p_3ss, p_2s, &faceVolume[face3], faceCentroid[face3], normal[face3]);
32653 computeTrapez(p_1, p_0, p_0ss, p_1s, &faceVolume[face4], faceCentroid[face4], normal[face4]);
32654 computePoly5(p_1, p_2, p_2s, p_0s, p_0, &faceVolume[face5], faceCentroid[face5], normal[face5]);
32655 computeTri(p_3, p_3s, p_3ss, &faceVolume[face6], faceCentroid[face6], normal[face6]);
32656
32657 computePoly6(p_0ss, p_0s, p_2s, p_3ss, p_3s, p_1s, &area_c, coordinates_c, normalVec_c);
32658
32659 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3, p_0s, p_1s, p_2s, p_3s, p_0ss, p_3ss);
32660
32661 for(MInt i = 0; i < 6; i++) {
32662 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
32663 &pyraVolume[i], pyraCentroid[i]);
32664 }
32665 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
32666 for(MInt i = 0; i < 7; i++) {
32667 volume_C += pyraVolume[i];
32668 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
32669 }
32670 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
32671
32672 m_bndryCells->a[bndryId].m_volume = volume_C;
32673 // create 1 Cut face
32674 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
32675 for(MInt dim = 0; dim < 3; dim++) {
32676 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
32677 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
32678 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
32679 }
32680 break;
32681 }
32682 case 14: {
32683 // cerr << "Case 14 detected. Starting Cutface computation..." << endl;
32684 for(MInt face = 0; face < 6; face++) {
32685 nfs_cur[face] = nfs14[currentSubCase][face];
32686 }
32687 noFaces = 6;
32688 p_0 = corner[cornersMCtoSOLVER[tiling14STL[currentSubCase][0]]];
32689 p_1 = corner[cornersMCtoSOLVER[tiling14STL[currentSubCase][1]]];
32690 p_2 = corner[cornersMCtoSOLVER[tiling14STL[currentSubCase][2]]];
32691 p_3 = corner[cornersMCtoSOLVER[tiling14STL[currentSubCase][3]]];
32692
32693 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][4]];
32694 p_0s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32695 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][5]];
32696 p_0ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32697 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][6]];
32698 p_1s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32699 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][7]];
32700 p_2s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32701 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][8]];
32702 p_3s = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32703 cutDummy = edgesMCtoSOLVER[tiling14STL[currentSubCase][9]];
32704 p_3ss = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutPoints[cutDummy]];
32705 face1 = facesMCtoSOLVER[tiling14STL[currentSubCase][10]];
32706 face2 = facesMCtoSOLVER[tiling14STL[currentSubCase][11]];
32707 face3 = facesMCtoSOLVER[tiling14STL[currentSubCase][12]];
32708 face4 = facesMCtoSOLVER[tiling14STL[currentSubCase][13]];
32709 face5 = facesMCtoSOLVER[tiling14STL[currentSubCase][14]];
32710 face6 = facesMCtoSOLVER[tiling14STL[currentSubCase][15]];
32711
32712 // identify unused (=special) cut points
32713 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
32714 if(p_0ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32715 || p_0s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32716 || p_1s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32717 || p_2s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32718 || p_3s == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]
32719 || p_3ss == m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp]) {
32720 continue;
32721 } else {
32722 unusedCutPoints[noUnusedCutPoints++] = cp;
32723 }
32724 }
32725
32726 for(MInt face = 0; face < noFaces; face++) {
32727 facePoints[face] = -1;
32728 facePoints[2 * face] = -1;
32729 nextFaces[face] = -1;
32730 }
32731 nextFaces[face1] = face4;
32732 nextFaces[face2] = face6;
32733 nextFaces[face3] = face5;
32734 nextFaces[face4] = face2;
32735 nextFaces[face5] = face1;
32736 nextFaces[face6] = face3;
32737 facePoints[2 * face1] = 0;
32738 facePoints[2 * face1 + 1] = 1;
32739 facePoints[2 * face2] = 2;
32740 facePoints[2 * face2 + 1] = 3;
32741 facePoints[2 * face3] = 4;
32742 facePoints[2 * face3 + 1] = 5;
32743 facePoints[2 * face4] = 1;
32744 facePoints[2 * face4 + 1] = 2;
32745 facePoints[2 * face5] = 5;
32746 facePoints[2 * face5 + 1] = 0;
32747 facePoints[2 * face6] = 3;
32748 facePoints[2 * face6 + 1] = 4;
32749 for(MInt i = 0; i < 3; i++) {
32750 points[0][i] = p_0ss[i];
32751 points[1][i] = p_0s[i];
32752 points[2][i] = p_1s[i];
32753 points[3][i] = p_3ss[i];
32754 points[4][i] = p_3s[i];
32755 points[5][i] = p_2s[i];
32756 }
32757
32758 computeTri(p_0, p_0s, p_0ss, &faceVolume[face1], faceCentroid[face1], normal[face1]);
32759 computePoly5(p_2, p_3, p_3ss, p_1s, p_1, &faceVolume[face2], faceCentroid[face2], normal[face2]);
32760 computeTrapez(p_2s, p_3s, p_3, p_2, &faceVolume[face3], faceCentroid[face3], normal[face3]);
32761 computeTrapez(p_1s, p_0s, p_0, p_1, &faceVolume[face4], faceCentroid[face4], normal[face4]);
32762 computePoly5(p_2, p_1, p_0, p_0ss, p_2s, &faceVolume[face5], faceCentroid[face5], normal[face5]);
32763 computeTri(p_3, p_3s, p_3ss, &faceVolume[face6], faceCentroid[face6], normal[face6]);
32764
32765 computePoly6(p_0ss, p_0s, p_1s, p_3ss, p_3s, p_2s, &area_c, coordinates_c, normalVec_c);
32766
32767 maia::math::vecAvg<3>(M, p_0, p_1, p_2, p_3, p_0s, p_1s, p_2s, p_3s, p_0ss, p_3ss);
32768
32769 for(MInt i = 0; i < 6; i++) {
32770 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
32771 &pyraVolume[i], pyraCentroid[i]);
32772 }
32773 computePyra(&area_c, coordinates_c, normalVec_c, M, &pyraVolume[6], pyraCentroid[6]);
32774 for(MInt i = 0; i < 7; i++) {
32775 volume_C += pyraVolume[i];
32776 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
32777 }
32778 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
32779
32780 m_bndryCells->a[bndryId].m_volume = volume_C;
32781 // create 1 Cut face
32782 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area_c;
32783 for(MInt dim = 0; dim < 3; dim++) {
32784 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = coordinates_c[dim];
32785 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normalVec_c[dim];
32786 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
32787 }
32788
32789 break;
32790 }
32791 default: {
32792 mTerm(1, AT_, "Inconsistent type implementation.");
32793 }
32794 }
32795 }
32796
32797 // 5a) Check if cell contains one additional cut Point
32798 if(noUnusedCutPoints > 2) {
32799 mTerm(1, AT_, "FvBndryCndXD::correctInflowBoundary - Error: Too many unused CutPoints!");
32800 }
32801 // cell contains special cut points and needs special treatment - 1 special cut point
32802 // relevant cut points are identified, cut points which must be treated as intersectionPoints are stored
32803 if(noUnusedCutPoints < 2) {
32804 for(MInt cp = 0; cp < noUnusedCutPoints; cp++) {
32805 cutEdge = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[unusedCutPoints[cp]];
32806 cutFace1 = faceCode[2 * cutEdge];
32807 cutFace2 = faceCode[2 * cutEdge + 1];
32808 // simple case: move IntersectionPoint to cutPoint, exchange cutFace
32809 if(noIntersectionPoints[cutFace1] == 1 && noIntersectionPoints[cutFace2] == 0) {
32810 for(MInt dir = 0; dir < 3; dir++) {
32811 intersectionPoints[cutFace2][0][dir] =
32812 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[cp]][dir];
32813 intersectionPoints[cutFace1][0][dir] = F0;
32814 }
32815 noIntersectionPoints[cutFace1] = 0;
32816 noIntersectionPoints[cutFace2] = 1;
32817 } // simple case: move IntersectionPoint to cutPoint, exchange cutFace
32818 else if(noIntersectionPoints[cutFace2] == 1 && noIntersectionPoints[cutFace1] == 0) {
32819 for(MInt dir = 0; dir < 3; dir++) {
32820 intersectionPoints[cutFace1][0][dir] =
32821 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[cp]][dir];
32822 intersectionPoints[cutFace2][0][dir] = F0;
32823 }
32824 noIntersectionPoints[cutFace2] = 0;
32825 noIntersectionPoints[cutFace1] = 1;
32826 } // special case: move IntersectionPoint to cutPoint, both faces are cutFaces
32827 else if(noIntersectionPoints[cutFace2] == 0 && noIntersectionPoints[cutFace1] == 0) {
32828 for(MInt dir = 0; dir < 3; dir++) {
32829 intersectionPoints[cutFace1][0][dir] =
32830 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[cp]][dir];
32831 intersectionPoints[cutFace2][0][dir] =
32832 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[cp]][dir];
32833 }
32834 noIntersectionPoints[cutFace2] = 1;
32835 noIntersectionPoints[cutFace1] = 1;
32836 }
32837 }
32838 }
32839 // cell contains special cut points and needs special treatment - 2 special cut points
32840 // relevant cut points are identified, cut points which must be treated as intersectionPoints are stored
32841 if(noUnusedCutPoints == 2) {
32842 cutEdge = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[unusedCutPoints[0]];
32843 cutFace1 = faceCode[2 * cutEdge];
32844 cutFace2 = faceCode[2 * cutEdge + 1];
32845 cutEdgeNghbr = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[unusedCutPoints[1]];
32846 cutFaceNghbr1 = faceCode[2 * cutEdgeNghbr];
32847 cutFaceNghbr2 = faceCode[2 * cutEdgeNghbr + 1];
32848 // difficult case, first consider the possibility that no cutPoints exist
32849 if(noIntersectionPoints[cutFace2] == 0 && noIntersectionPoints[cutFace1] == 0
32850 && noIntersectionPoints[cutFaceNghbr2] == 0 && noIntersectionPoints[cutFaceNghbr1] == 0) {
32851 // left cut face of the other cut point == left cut face of this cut point
32852 if(cutFaceNghbr1 == cutFace1) {
32853 for(MInt dir = 0; dir < 3; dir++) {
32854 intersectionPoints[cutFace2][0][dir] =
32855 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[0]][dir];
32856 intersectionPoints[cutFaceNghbr2][0][dir] =
32857 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[1]][dir];
32858 }
32859 noIntersectionPoints[cutFace2]++;
32860 noIntersectionPoints[cutFaceNghbr2]++;
32861 }
32862 // right cut face of the other cut point == left cut face of this cut point
32863 if(cutFaceNghbr2 == cutFace1) {
32864 for(MInt dir = 0; dir < 3; dir++) {
32865 intersectionPoints[cutFace2][0][dir] =
32866 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[0]][dir];
32867 intersectionPoints[cutFaceNghbr1][0][dir] =
32868 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[1]][dir];
32869 }
32870 noIntersectionPoints[cutFace2]++;
32871 noIntersectionPoints[cutFaceNghbr1]++;
32872 }
32873 // left cut face of the other cut point == right cut face of this cut point
32874 if(cutFaceNghbr1 == cutFace2) {
32875 for(MInt dir = 0; dir < 3; dir++) {
32876 intersectionPoints[cutFace1][0][dir] =
32877 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[0]][dir];
32878 intersectionPoints[cutFaceNghbr2][0][dir] =
32879 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[1]][dir];
32880 }
32881 noIntersectionPoints[cutFace1]++;
32882 noIntersectionPoints[cutFaceNghbr2]++;
32883 }
32884 // right cut face of the other cut point == right cut face of this cut point
32885 if(cutFaceNghbr2 == cutFace2) {
32886 for(MInt dir = 0; dir < 3; dir++) {
32887 intersectionPoints[cutFace1][0][dir] =
32888 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[0]][dir];
32889 intersectionPoints[cutFaceNghbr1][0][dir] =
32890 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[unusedCutPoints[1]][dir];
32891 }
32892 noIntersectionPoints[cutFace1]++;
32893 noIntersectionPoints[cutFaceNghbr1]++;
32894 }
32895 } else {
32896 stringstream fileName;
32897 fileName << cellId << ".stl";
32898 writeStlFileOfCell(cellId, (fileName.str()).c_str());
32899 plotEdges(noFeatureEdges, featureEdges);
32900 plotIntersectionPoints(noIntersectionPoints, intersectionPoints);
32901 writeStlOfNodes(noWallNodes, wallNodes, "WallNodes.stl");
32902 cerr << "Wrote stl-file of cell and wall nodes. Cell-file: " << fileName.str()
32903 << ", Node-file: WallNodes.stl" << endl;
32904 mTerm(1, AT_, "Unhandled exception in special cell handling!");
32905 }
32906 }
32907
32908 // delete the special (nonused) cut points and resort the remaining cut points - only regular cut points should
32909 // be used in the following
32910 for(MInt cpCount = noUnusedCutPoints - 1; cpCount >= 0; cpCount--) {
32911 m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints--;
32912 for(MInt count = unusedCutPoints[cpCount]; count < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
32913 count++) {
32914 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[count] =
32915 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[count + 1];
32916 for(MInt dir = 0; dir < 3; dir++)
32917 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[count][dir] =
32918 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[count + 1][dir];
32919 }
32920 }
32921
32922 // check if number of intersectionPoints on each face is ok and prepare array of all intersection points
32923 for(MInt face = 0; face < 6; face++) {
32924 if(noIntersectionPoints[face] == 2) {
32925 noIntersectionPoints[face] = 0;
32926 } else if(noIntersectionPoints[face] > 1) {
32927 cerr << "FvBndryCndXD::correctInflowBoundary - Error: More than 1 intersection Point!"
32928 << " cellId: " << cellId << endl;
32929 stringstream fileName;
32930 fileName << cellId << ".stl";
32931 writeStlFileOfCell(cellId, (fileName.str()).c_str());
32932 plotEdges(noFeatureEdges, featureEdges);
32933 plotIntersectionPoints(noIntersectionPoints, intersectionPoints);
32934 writeStlOfNodes(noWallNodes, wallNodes, "WallNodes.stl");
32935 stringstream errorMessage;
32936 errorMessage << "Wrote stl-file of cell and wall nodes. Cell-file: " << fileName.str()
32937 << ", Node-file: WallNodes.stl";
32938 mTerm(1, AT_, errorMessage.str());
32939 }
32940 // if(noIntersectionPoints[face] == 1){
32941 // for(MInt k=0; k < 3; k++){
32942 // allIntersectionPoints[noAllIntersectionPoints][k] =
32943 // intersectionPoints[face][0][k];
32944 // }
32945 // noAllIntersectionPoints++;
32946 // }
32947 }
32948
32949
32950 // 6) Recompute voxel face parameters - only if noIntersectionPoints[face] > 0
32951 if(!caseStatesSTL[currentCase][1]) {
32952 mTerm(1, AT_, "Case not resolved for Inlet Correction!");
32953 }
32954
32955 faceStart = -1;
32956 for(MInt face = 0; face < 6; face++) {
32957 pointCount = 0;
32958 if(!(noIntersectionPoints[face] == 1)) {
32959 continue;
32960 }
32961 for(MInt cP = 0; cP < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cP++) {
32962 for(MInt edge = 0; edge < 4; edge++) {
32963 if(m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cP] == edgeCode[face * 4 + edge]) {
32964 if(pointCount < 2) {
32965 pointIndices[pointCount++] = cP;
32966 } else {
32967 mTerm(1, AT_, "Too many cut Points!");
32968 }
32969 }
32970 }
32971 }
32972 if(!(pointCount == 2)) {
32973 cerr << "FvBndryCndXD::correctInflowBoundary - Error: Not two Cut points..."
32974 << " face: " << face << "faceNormal: " << normal[face][0] << " " << normal[face][1] << " "
32975 << normal[face][2] << endl;
32976 plotIntersectionPoints(noIntersectionPoints, intersectionPoints);
32977 plotEdges(noFeatureEdges, featureEdges);
32978 writeStlOfNodes(noWallNodes, wallNodes, "WallNodes.stl");
32979 stringstream fileName;
32980 fileName << cellId << ".stl";
32981 writeStlFileOfCell(cellId, (fileName.str()).c_str());
32982 stringstream errorMessage;
32983 errorMessage << "Wrote stl-file of cell, wall nodes, feature edges and intersection points. Cell-file: "
32984 << fileName.str();
32985 mTerm(1, AT_, errorMessage.str());
32986 }
32987
32988 // store the face on which to start collecting the points for the resulting boundary cut surfaces
32989 faceStart = face;
32990 // compute and plot the new part resulting from the consideration of the cut point
32991 computeTri(m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[pointIndices[0]],
32992 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[pointIndices[1]],
32993 intersectionPoints[face][0], &newArea, dummy_1);
32994 plotTriangle(ofl, m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[pointIndices[0]],
32995 m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[pointIndices[1]],
32996 intersectionPoints[face][0], normal[face]);
32997
32998 // regularly, the cell volume should grow by boundary correction, if this should be otherwise "inside" must be
32999 // specified (e.g. cube testcase)
33000 if(inside) {
33001 if(secondHalf)
33002 secondHalf = false;
33003 else
33004 secondHalf = true;
33005 }
33006 // decide if the new triangle increases or decreases the face area
33007 if(secondHalf) {
33008 newArea = -newArea;
33009 }
33010 vecScalarMul(faceVolume[face], faceCentroid[face], dummy_2);
33011 vecScalarMul(newArea, dummy_1, dummy_3);
33012 std::fill_n(faceCentroid[face], 3, 0.0);
33013 maia::math::vecAdd<3>(faceCentroid[face], dummy_2, dummy_3);
33014 faceVolume[face] = faceVolume[face] + newArea;
33015 vecScalarMul(1. / (faceVolume[face]), faceCentroid[face], faceCentroid[face]);
33016
33017 if(inside) {
33018 if(secondHalf)
33019 secondHalf = false;
33020 else
33021 secondHalf = true;
33022 }
33023 }
33024
33025 // 7.) compute Cut Faces
33026 if(faceStart == -1) {
33027 plotIntersectionPoints(noIntersectionPoints, intersectionPoints);
33028 plotEdges(noFeatureEdges, featureEdges);
33029 writeStlOfNodes(noWallNodes, wallNodes, "WallNodes.stl");
33030 stringstream fileName;
33031 fileName << cellId << ".stl";
33032 writeStlFileOfCell(cellId, (fileName.str()).c_str());
33033 cerr << "Wrote stl-file of cell, wall nodes, feature edges and intersection points. Cell-file: "
33034 << fileName.str() << endl;
33035
33036 stringstream errorMessage;
33037 errorMessage << "No suitable start face found on cell " << cellId << "!";
33038 mTerm(1, AT_, errorMessage.str());
33039 }
33040 noPoints1 = 0;
33041 noPoints2 = 0;
33042 points1[noPoints1++] = intersectionPoints[faceStart][0];
33043 // collect points of first new cut face
33044 do {
33045 points1[noPoints1++] = points[facePoints[2 * faceStart + 1]];
33046 faceStart = nextFaces[faceStart];
33047 } while(noIntersectionPoints[faceStart] == 0);
33048 delta_IP = sqrt(POW2(intersectionPoints[faceStart][0][0] - points1[0][0])
33049 + POW2(intersectionPoints[faceStart][0][1] - points1[0][1])
33050 + POW2(intersectionPoints[faceStart][0][2] - points1[0][2]));
33051 if(delta_IP > 1e-5) {
33052 points1[noPoints1++] = intersectionPoints[faceStart][0];
33053 } else {
33054 }
33055
33056 points2[noPoints2++] = intersectionPoints[faceStart][0];
33057 // collect points of second new cut face
33058 do {
33059 points2[noPoints2++] = points[facePoints[2 * faceStart + 1]];
33060 faceStart = nextFaces[faceStart];
33061 } while(noIntersectionPoints[faceStart] == 0);
33062 delta_IP = sqrt(POW2(intersectionPoints[faceStart][0][0] - points2[0][0])
33063 + POW2(intersectionPoints[faceStart][0][1] - points2[0][1])
33064 + POW2(intersectionPoints[faceStart][0][2] - points2[0][2]));
33065 if(delta_IP > 1e-5) {
33066 points2[noPoints2++] = intersectionPoints[faceStart][0];
33067 }
33068
33069 switch(noPoints1) {
33070 case 1:
33071 case 2: {
33072 cerr << "FvBndryCndXD::correctInflowBoundaryCondition - Error 1: Not enough Points to create a cut face"
33073 << endl;
33074 plotIntersectionPoints(noIntersectionPoints, intersectionPoints);
33075 plotEdges(noFeatureEdges, featureEdges);
33076 writeStlOfNodes(noWallNodes, wallNodes, "WallNodes.stl");
33077 stringstream fileName;
33078 fileName << cellId << ".stl";
33079 writeStlFileOfCell(cellId, (fileName.str()).c_str());
33080 cerr << " cut Points: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints << " : ";
33081 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++)
33082 cerr << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][0] << " "
33083 << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][1] << " "
33084 << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][2] << "; ";
33085 cerr << endl;
33086 stringstream errorMessage;
33087 errorMessage << "Wrote stl-file of cell, wall nodes, feature edges and intersection points. Cell-file: "
33088 << fileName.str();
33089 mTerm(1, AT_, errorMessage.str());
33090 } break;
33091 case 3:
33092 computePoly3(points1[0], points1[1], points1[2], &area1, centroid1, normal1);
33093 plotTriangle(ofl, points1[0], points1[1], points1[2], normal1);
33094 break;
33095 case 4:
33096 computePoly4(points1[0], points1[1], points1[2], points1[3], &area1, centroid1, normal1);
33097 plotTriangle(ofl, points1[0], points1[1], points1[2], normal1);
33098 plotTriangle(ofl, points1[2], points1[3], points1[0], normal1);
33099 break;
33100 case 5:
33101 computePoly5(points1[0], points1[1], points1[2], points1[3], points1[4], &area1, centroid1, normal1);
33102 plotTriangle(ofl, points1[0], points1[1], points1[2], normal1);
33103 plotTriangle(ofl, points1[2], points1[3], points1[4], normal1);
33104 plotTriangle(ofl, points1[2], points1[4], points1[0], normal1);
33105 break;
33106 case 6:
33107 computePoly6(points1[0], points1[1], points1[2], points1[3], points1[4], points1[5], &area1, centroid1,
33108 normal1);
33109 plotTriangle(ofl, points1[0], points1[1], points1[2], normal1);
33110 plotTriangle(ofl, points1[2], points1[3], points1[4], normal1);
33111 plotTriangle(ofl, points1[2], points1[4], points1[5], normal1);
33112 plotTriangle(ofl, points1[2], points1[5], points1[0], normal1);
33113 break;
33114 default: {
33115 stringstream errorMessage;
33116 errorMessage << "ERROR: Switch variable 'noPoints1' with value " << noPoints1 << " not matching any case."
33117 << endl;
33118 mTerm(1, AT_, errorMessage.str());
33119 }
33120 }
33121 switch(noPoints2) {
33122 case 1:
33123 case 2: {
33124 cerr << "FvBndryCndXD::correctInflowBoundaryCondition - Error 2: Not enough Points to create a cut face"
33125 << endl;
33126 plotIntersectionPoints(noIntersectionPoints, intersectionPoints);
33127 plotEdges(noFeatureEdges, featureEdges);
33128 writeStlOfNodes(noWallNodes, wallNodes, "WallNodes.stl");
33129 stringstream fileName;
33130 fileName << cellId << ".stl";
33131 writeStlFileOfCell(cellId, (fileName.str()).c_str());
33132 stringstream errorMessage;
33133 errorMessage << "Wrote stl-file of cell, wall nodes, feature edges and intersection points. Cell-file: "
33134 << fileName.str();
33135 cerr << " cut Points: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints << " : ";
33136 for(MInt cp = 0; cp < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++)
33137 cerr << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][0] << " "
33138 << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][1] << " "
33139 << m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][2] << "; ";
33140 cerr << endl;
33141 mTerm(1, AT_, errorMessage.str());
33142 } break;
33143 case 3:
33144 computePoly3(points2[0], points2[1], points2[2], &area2, centroid2, normal2);
33145 plotTriangle(ofl, points2[0], points2[1], points2[2], normal2);
33146 break;
33147 case 4:
33148 computePoly4(points2[0], points2[1], points2[2], points2[3], &area2, centroid2, normal2);
33149 plotTriangle(ofl, points2[0], points2[1], points2[2], normal2);
33150 plotTriangle(ofl, points2[2], points2[3], points2[0], normal2);
33151 break;
33152 case 5:
33153 computePoly5(points2[0], points2[1], points2[2], points2[3], points2[4], &area2, centroid2, normal2);
33154 plotTriangle(ofl, points2[0], points2[1], points2[2], normal2);
33155 plotTriangle(ofl, points2[2], points2[3], points2[4], normal2);
33156 plotTriangle(ofl, points2[2], points2[4], points2[0], normal2);
33157 break;
33158 case 6:
33159 computePoly6(points2[0], points2[1], points2[2], points2[3], points2[4], points2[5], &area2, centroid2,
33160 normal2);
33161 plotTriangle(ofl, points2[0], points2[1], points2[2], normal2);
33162 plotTriangle(ofl, points2[2], points2[3], points2[4], normal2);
33163 plotTriangle(ofl, points2[2], points2[4], points2[5], normal2);
33164 plotTriangle(ofl, points2[2], points2[5], points2[0], normal2);
33165 break;
33166 default: {
33167 stringstream errorMessage;
33168 errorMessage << "ERROR: Switch variable 'noPoints2' with value " << noPoints2 << " not matching any case."
33169 << endl;
33170 mTerm(1, AT_, errorMessage.str());
33171 }
33172 }
33173
33174 // recompute the cell volume and centroid
33175 volume_C = F0;
33176 coordinates_Cell[0] = F0;
33177 coordinates_Cell[1] = F0;
33178 coordinates_Cell[2] = F0;
33179 for(MInt i = 0; i < noFaces; i++) {
33180 computePyra(&faceVolume[*facepointers[i]], faceCentroid[*facepointers[i]], normal[*facepointers[i]], M,
33181 &pyraVolume[i], pyraCentroid[i]);
33182 }
33183 computePyra(&area1, centroid1, normal1, M, &pyraVolume[noFaces], pyraCentroid[noFaces]);
33184 computePyra(&area2, centroid2, normal2, M, &pyraVolume[noFaces + 1], pyraCentroid[noFaces + 1]);
33185 for(MInt i = 0; i < noFaces + 2; i++) {
33186 volume_C += pyraVolume[i];
33187 maia::math::vecAdd<3>(coordinates_Cell, vecScalarMul(pyraVolume[i], pyraCentroid[i], dummy_1));
33188 }
33189 vecScalarMul(F1 / volume_C, coordinates_Cell, coordinates_Cell);
33190
33191 normalDiff =
33192 POW2(normal1[0] - meanNormal[0]) + POW2(normal1[1] - meanNormal[1]) + POW2(normal1[2] - meanNormal[2]);
33193 if(normalDiff < normalEps) {
33194 bcId1 = bcInlet;
33195 bcId2 = bcWall;
33196 } else {
33197 bcId1 = bcWall;
33198 bcId2 = bcInlet;
33199 }
33200
33201 if(secondHalf) {
33202 switch(currentCase) {
33203 case 1: {
33204 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
33205 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
33206 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
33207
33208 correctCell(&volume_C, coordinates_Cell, &gridCellVolume, &m_solver->a_coordinate(cellId, 0));
33209
33210 correctNormal(normalVec_c);
33211 if(inside) {
33212 correctNormal(normal1);
33213 correctNormal(normal2);
33214 }
33215 break;
33216 }
33217 case 2: {
33218 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
33219 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
33220 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
33221 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
33222
33223 correctCell(&volume_C, coordinates_Cell, &gridCellVolume, &m_solver->a_coordinate(cellId, 0));
33224
33225 correctNormal(normalVec_c);
33226 if(inside) {
33227 correctNormal(normal1);
33228 correctNormal(normal2);
33229 }
33230 break;
33231 }
33232 case 5: {
33233 correctFace(&faceVolume[face1], faceCentroid[face1], &faceVolume_0[face1], faceCentroid_0[face1]);
33234 correctFace(&faceVolume[face2], faceCentroid[face2], &faceVolume_0[face2], faceCentroid_0[face2]);
33235 correctFace(&faceVolume[face3], faceCentroid[face3], &faceVolume_0[face3], faceCentroid_0[face3]);
33236 correctFace(&faceVolume[face4], faceCentroid[face4], &faceVolume_0[face4], faceCentroid_0[face4]);
33237 correctFace(&faceVolume[face5], faceCentroid[face5], &faceVolume_0[face5], faceCentroid_0[face5]);
33238
33239 correctCell(&volume_C, coordinates_Cell, &gridCellVolume, &m_solver->a_coordinate(cellId, 0));
33240
33241 correctNormal(normal1);
33242 correctNormal(normal2);
33243
33244 break;
33245 }
33246 default: {
33247 mTerm(1, AT_, "Inconsistent type implementation.");
33248 }
33249 }
33250 }
33251
33252 MFloat faceDiff[3];
33253 MFloat absA = F0;
33254 // compute differences in cell surface areas
33255 for(MInt i = 0; i < nDim; i++) {
33256 if(!nfs_cur[2 * i + 1]) faceVolume[2 * i + 1] = 0;
33257 if(!nfs_cur[2 * i]) faceVolume[2 * i] = 0;
33258 faceDiff[i] = faceVolume[2 * i + 1] - faceVolume[2 * i];
33259 absA += POW2(faceDiff[i]);
33260 }
33261
33262 // correct values such that cell is closed!
33263 // (if 1 indicates inlet face -> normal1 should keep direction)
33264 if(bcInlet == bcId1) {
33265 for(MInt dim = 0; dim < 3; dim++)
33266 normal1[dim] = meanNormal[dim];
33267 // normalize inlet normal
33268 absA = F0;
33269 for(MInt dim = 0; dim < 3; dim++)
33270 absA += normal1[dim] * normal1[dim];
33271 absA = sqrt(absA);
33272 for(MInt dim = 0; dim < 3; dim++)
33273 normal1[dim] /= absA;
33274
33275 // compute area1
33276 area1 = F0;
33277 for(MInt dim = 0; dim < 3; dim++)
33278 area1 += faceDiff[dim] * normal1[dim];
33279
33280 // update FaceDiff:
33281 absA = F0;
33282 for(MInt i = 0; i < nDim; i++) {
33283 faceDiff[i] -= area1 * normal1[i];
33284 absA += POW2(faceDiff[i]);
33285 }
33286
33287 // compute normal2, area2 such that cell is closed
33288 for(MInt i = 0; i < nDim; i++)
33289 normal2[i] = faceDiff[i] / sqrt(absA);
33290 area2 = sqrt(absA);
33291 } else {
33292 for(MInt dim = 0; dim < 3; dim++)
33293 normal2[dim] = meanNormal[dim];
33294 // normalize inlet normal
33295 absA = F0;
33296 for(MInt dim = 0; dim < 3; dim++)
33297 absA += normal2[dim] * normal2[dim];
33298 absA = sqrt(absA);
33299 for(MInt dim = 0; dim < 3; dim++)
33300 normal2[dim] /= absA;
33301
33302 // compute area1
33303 area2 = F0;
33304 for(MInt dim = 0; dim < 3; dim++)
33305 area2 += faceDiff[dim] * normal2[dim];
33306
33307 // update FaceDiff:
33308 absA = F0;
33309 for(MInt i = 0; i < nDim; i++) {
33310 faceDiff[i] -= area2 * normal2[i];
33311 absA += POW2(faceDiff[i]);
33312 }
33313
33314 // compute normal2, area2 such that cell is closed
33315 for(MInt i = 0; i < nDim; i++)
33316 normal1[i] = faceDiff[i] / sqrt(absA);
33317 area1 = sqrt(absA);
33318 }
33319
33320 // // correct values such that cell is closed!
33321 // // first: create orthonormalbasis (if 1 indicates inlet face -> normal1 should keep direction)
33322 // // then correct srfcs
33323 // if(bcInlet == bcId1){
33324 //
33325 // //test take meanNormal
33326 // for(MInt dim = 0; dim < 3; dim++)
33327 // normal1[dim] = meanNormal[dim];
33328 //
33329 // // normalize inlet normal
33330 // absA = F0;
33331 // for(MInt dim = 0; dim < 3; dim++)
33332 // absA += normal1[dim] * normal1[dim];
33333 // absA = sqrt(absA);
33334 // for(MInt dim = 0; dim < 3; dim++)
33335 // normal1[dim] /= absA;
33336 //
33337 // // compute direction of wall normal
33338 // absA = F0;
33339 // for(MInt dim = 0; dim < 3; dim++)
33340 // absA += normal1[dim] * normal2[dim];
33341 // for(MInt dim = 0; dim < 3; dim++)
33342 // normal2[dim] = normal2[dim] - absA * normal1[dim];
33343 //
33344 // // normalize wall normal
33345 // absA = F0;
33346 // for(MInt dim = 0; dim < 3; dim++)
33347 // absA += normal2[dim] * normal2[dim];
33348 // for(MInt dim = 0; dim < 3; dim++)
33349 // normal2[dim] /= absA;
33350 //
33351 // area1 = F0;
33352 // for(MInt dim = 0; dim < 3; dim++)
33353 // area1 += faceDiff[dim] * normal1[dim];
33354 // area2 = F0;
33355 // for(MInt dim = 0; dim < 3; dim++)
33356 // area2 += faceDiff[dim] * normal2[dim];
33357 // }
33358 // else{ // first: create orthonormalbasis (if 2 indicates inlet face -> normal2 should keep direction)
33359 // // then correct srfcs
33360 // // normalize inlet normal
33361 // for(MInt dim = 0; dim < 3; dim++)
33362 // normal2[dim] = meanNormal[dim];
33363 //
33364 // absA = F0;
33365 // for(MInt dim = 0; dim < 3; dim++)
33366 // absA += normal2[dim] * normal2[dim];
33367 // absA = sqrt(absA);
33368 // for(MInt dim = 0; dim < 3; dim++)
33369 // normal2[dim] /= absA;
33370 //
33371 // // compute direction of wall normal
33372 // absA = F0;
33373 // for(MInt dim = 0; dim < 3; dim++)
33374 // absA += normal2[dim] * normal1[dim];
33375 // for(MInt dim = 0; dim < 3; dim++)
33376 // normal1[dim] = normal1[dim] - absA * normal2[dim];
33377 //
33378 // // normalize wall normal
33379 // absA = F0;
33380 // for(MInt dim = 0; dim < 3; dim++)
33381 // absA += normal1[dim] * normal1[dim];
33382 // for(MInt dim = 0; dim < 3; dim++)
33383 // normal1[dim] /= absA;
33384 //
33385 // area1 = F0;
33386 // for(MInt dim = 0; dim < 3; dim++)
33387 // area1 += faceDiff[dim] * normal1[dim];
33388 // area2 = F0;
33389 // for(MInt dim = 0; dim < 3; dim++)
33390 // area2 += faceDiff[dim] * normal2[dim];
33391 // }
33392
33393 m_bndryCells->a[bndryId].m_noSrfcs = 2;
33394 m_bndryCells->a[bndryId].m_volume = volume_C;
33395
33396 if(bcInlet == bcId1) { // make sure srfc 0 is the inlet bndry srfc
33397 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area1;
33398 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area2;
33399 m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId = bcId1;
33400 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = bcId2;
33401 for(MInt dim = 0; dim < 3; dim++) {
33402 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = centroid1[dim];
33403 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = centroid2[dim];
33404 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normal1[dim];
33405 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normal2[dim];
33406 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
33407 }
33408 } else {
33409 m_bndryCells->a[bndryId].m_srfcs[0]->m_area = area2;
33410 m_bndryCells->a[bndryId].m_srfcs[1]->m_area = area1;
33411 m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId = bcId2;
33412 m_bndryCells->a[bndryId].m_srfcs[1]->m_bndryCndId = bcId1;
33413 for(MInt dim = 0; dim < 3; dim++) {
33414 m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[dim] = centroid2[dim];
33415 m_bndryCells->a[bndryId].m_srfcs[1]->m_coordinates[dim] = centroid1[dim];
33416 m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[dim] = normal2[dim];
33417 m_bndryCells->a[bndryId].m_srfcs[1]->m_normalVector[dim] = normal1[dim];
33418 m_bndryCells->a[bndryId].m_coordinates[dim] = coordinates_Cell[dim];
33419 }
33420 }
33421
33422 for(MInt i = 0; i < nDim; i++) {
33423 m_bndryCells->a[bndryId].m_coordinates[i] -= m_solver->a_coordinate(cellId, i);
33424 }
33425
33426 for(MInt face = 0; face < 6; face++) {
33427 for(MInt i = 0; i < noFaces; i++) {
33428 if(!(*facepointers[i] == face)) continue;
33429 sideId = face % 2;
33430 spaceId = face / 2;
33431 if(nfs_cur[face]) {
33432 if(m_solver->a_hasNeighbor(cellId, face) > 0)
33433 nghbrId = m_solver->c_neighborId(cellId, face);
33434 else {
33435 if(m_solver->c_parentId(cellId) > -1) {
33436 if(m_solver->a_hasNeighbor(m_solver->c_parentId(cellId), face) > 0)
33437 nghbrId = m_solver->c_neighborId(m_solver->c_parentId(cellId), face);
33438 else
33439 continue;
33440 } else
33441 continue;
33442 }
33443 if(m_solver->c_noChildren(nghbrId) > 0) continue;
33444 otherSideId = (sideId + 1) % 2;
33445 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[face];
33446 m_solver->a_surfaceOrientation(srfcId) = spaceId;
33447 m_solver->a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
33448 m_solver->a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
33449 for(MInt dim = 0; dim < nDim; dim++) {
33450 m_solver->a_surfaceCoordinate(srfcId, dim) = faceCentroid[face][dim];
33451 }
33452 m_solver->a_surfaceArea(srfcId) = faceVolume[face];
33453 m_bndryCells->a[bndryId].m_associatedSrfc[face] = srfcId;
33454 } else {
33455 cerr << "FvBndryCndXD::correctInflowBoundary - Error for face: " << face << endl;
33456 cerr << "bndryId: " << bndryId << endl;
33457 cerr << "cellId: " << cellId << endl;
33458 cerr << "bndryCnd: " << m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId;
33459 cerr << "case, subcase: " << currentCase << ", " << currentSubCase << endl;
33460 cerr << "face Volumes: " << faceVolume[0] << ", " << faceVolume[1] << ", " << faceVolume[2] << ", "
33461 << faceVolume[3] << ", " << faceVolume[4] << ", " << faceVolume[5] << endl;
33462 cerr << "faceCentroids: ";
33463 for(MInt j = 0; j < 6; j++) {
33464 cerr << faceCentroid[j][0] << ", " << faceCentroid[j][1] << ", " << faceCentroid[j][2] << "; " << endl;
33465 }
33466 cerr << "area_c = " << area_c << endl;
33467 cerr << "normalVec_c = " << normalVec_c[0] << ", " << normalVec_c[1] << ", " << normalVec_c[2] << endl;
33468 cerr << "coordinates_c = " << coordinates_c[0] << ", " << coordinates_c[1] << ", " << coordinates_c[2]
33469 << endl;
33470 cerr << "coordinates_Cell = " << coordinates_Cell[0] << ", " << coordinates_Cell[1] << ", "
33471 << coordinates_Cell[2] << endl;
33472 cerr << "volume_C = " << volume_C << endl;
33473 mTerm(1, AT_, "error in face");
33474 }
33475 }
33476 }
33477 }
33478 }
33479
33480 ofl << "endsolid cutsurface " << endl;
33481 }
33482 ofl.close();
33483}
33484
33485// ---------------------------------------------------------------------------------------------
33486
33496template <MInt nDim, class SysEqn>
33497template <class _, std::enable_if_t<nDim == 3, _*>>
33499 TRACE();
33500
33501 MFloatScratchSpace meanNormal_scratch(nDim, AT_, "meanNormal_scratch");
33502 MFloat* meanNormal = meanNormal_scratch.getPointer();
33503 MFloatScratchSpace basePoint_scratch(nDim, AT_, "basePoint_scratch");
33504 MFloat* basePoint = basePoint_scratch.getPointer();
33505 for(MInt i = 0; i < 3; i++) {
33506 meanNormal[i] = F0;
33507 basePoint[i] = F0;
33508 }
33509 MInt noBcCells = 0;
33510 MFloat radius = F0;
33511 MFloat R = F0;
33512 MFloat referencePoint2[3] = {0.0, 0.0, 0.0};
33513 MFloat referencePoint[3] = {0.0, 0.0, 0.0};
33514 MInt noCells = m_bndryCells->size();
33515 MInt cellId;
33516 MFloat newArea = F0;
33517 MFloatScratchSpace comm_buff_scratch(5, AT_, "comm_buff_scratch");
33518 MFloatScratchSpace comm_buff_result_scratch(5, AT_, "comm_buff_result_scratch");
33519 MFloat* comm_buff = comm_buff_scratch.getPointer();
33520 MFloat* comm_buff_result = comm_buff_result_scratch.getPointer();
33521
33522 // 0) compute referencePoint (a point located in the plane of bcId, preferably midpoint) and radius R of boundary
33523 // surface with bcId
33524
33525 // first guess - take all cut surfaces with this bcId into account
33526 referencePoint2[0] = F0;
33527 referencePoint2[1] = F0;
33528 referencePoint2[2] = F0;
33529 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
33530 cellId = m_bndryCells->a[bndryId].m_cellId;
33531 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
33532 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
33533 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == bcId) {
33534 noBcCells++;
33535 newArea += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
33536 for(MInt i = 0; i < 3; i++) {
33537 referencePoint2[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i];
33538 }
33539 }
33540 }
33541 }
33542 }
33543
33544 comm_buff[0] = newArea;
33545 comm_buff[1] = referencePoint2[0];
33546 comm_buff[2] = referencePoint2[1];
33547 comm_buff[3] = referencePoint2[2];
33548 comm_buff[4] = noBcCells;
33549
33550 MPI_Allreduce(comm_buff, comm_buff_result, 5, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "comm_buff", "comm_buff_result");
33551
33552 newArea = comm_buff_result[0];
33553 referencePoint2[0] = comm_buff_result[1];
33554 referencePoint2[1] = comm_buff_result[2];
33555 referencePoint2[2] = comm_buff_result[3];
33556 noBcCells = (MInt)comm_buff_result[4];
33557
33558 for(MInt i = 0; i < 3; i++) {
33559 referencePoint2[i] /= noBcCells;
33560 }
33561 // take a smaller radius to generate a "trusted region" for the more precise computation
33562 R = 0.7 * sqrt(newArea / PI);
33563
33564 // second run - only on trusted region surfaces
33565 newArea = F0;
33566 noBcCells = 0;
33567 referencePoint[0] = F0;
33568 referencePoint[1] = F0;
33569 referencePoint[2] = F0;
33570 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
33571 cellId = m_bndryCells->a[bndryId].m_cellId;
33572 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
33573 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
33574 radius = sqrt(POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[0] - referencePoint2[0])
33575 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[1] - referencePoint2[1])
33576 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[2] - referencePoint2[2]));
33577 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == bcId && radius < R) {
33578 noBcCells++;
33579 newArea += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
33580 for(MInt i = 0; i < 3; i++) {
33581 referencePoint[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i];
33582 }
33583 }
33584 }
33585 }
33586 }
33587 comm_buff[0] = newArea;
33588 comm_buff[1] = referencePoint[0];
33589 comm_buff[2] = referencePoint[1];
33590 comm_buff[3] = referencePoint[2];
33591 comm_buff[4] = noBcCells;
33592
33593 MPI_Allreduce(comm_buff, comm_buff_result, 5, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "comm_buff", "comm_buff_result");
33594
33595 newArea = comm_buff_result[0];
33596 referencePoint[0] = comm_buff_result[1];
33597 referencePoint[1] = comm_buff_result[2];
33598 referencePoint[2] = comm_buff_result[3];
33599 noBcCells = (MInt)comm_buff_result[4];
33600 for(MInt i = 0; i < 3; i++) {
33601 referencePoint[i] /= noBcCells;
33602 }
33603 noBcCells = 0;
33604 // cerr << "bcId, referencePoint, R: " << bcId << ", " << referencePoint[0] << " "<< referencePoint[1] << " "<<
33605 // referencePoint[2] << ", " << R << endl;
33606
33607 // 1) compute mean normal of inflow boundary with correct referencePoint
33608 meanNormal[0] = F0;
33609 meanNormal[1] = F0;
33610 meanNormal[2] = F0;
33611 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
33612 cellId = m_bndryCells->a[bndryId].m_cellId;
33613 if(m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
33614 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
33615 radius = sqrt(POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[0] - referencePoint[0])
33616 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[1] - referencePoint[1])
33617 + POW2(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[2] - referencePoint[2]));
33618 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId == bcId && radius < R) {
33619 noBcCells++;
33620 for(MInt i = 0; i < 3; i++) {
33621 meanNormal[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
33622 }
33623 }
33624 }
33625 }
33626 }
33627 comm_buff[0] = meanNormal[0];
33628 comm_buff[1] = meanNormal[1];
33629 comm_buff[2] = meanNormal[2];
33630
33631 MPI_Allreduce(comm_buff, comm_buff_result, 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "comm_buff", "comm_buff_result");
33632
33633 meanNormal[0] = comm_buff_result[0];
33634 meanNormal[1] = comm_buff_result[1];
33635 meanNormal[2] = comm_buff_result[2];
33636 for(MInt i = 0; i < 3; i++) {
33637 meanNormal[i] /= noBcCells;
33638 basePoint[i] = referencePoint[i];
33639 }
33640
33641 // call "real" correctInflowBoundary routine
33642 cerr << " computed base point and normal of bcId " << bcId << " as: normal: " << meanNormal[0] << " " << meanNormal[1]
33643 << " " << meanNormal[2] << ". base point: " << basePoint[0] << " " << basePoint[1] << " " << basePoint[2]
33644 << endl;
33645 correctInflowBoundary(bcId, meanNormal, basePoint);
33646}
33647
33648// ---------------------------------------------------------------------------------------------
33649
33661template <MInt nDim, class SysEqn>
33662template <class _, std::enable_if_t<nDim == 3, _*>>
33663void FvBndryCndXD<nDim, SysEqn>::getIntersectionPoints(MFloat**& target, MFloat**& featureEdges, MInt noFeatureEdges,
33664 MInt dir, MFloat**& intersectionPoints,
33665 MInt& noIntersectionPoints) {
33666 TRACE();
33667 MFloat* a; // 1. Corner
33668 MFloat* b; // 2. Corner
33669 MFloat* c; // 3. Corner
33670 MFloat* d; // Start Feature Edge
33671 MFloat* e; // End Feature Edge
33672 MFloat pP[3] = {0.0, 0.0, 0.0};
33673 MFloat gamma, s;
33674 MBool rejected = false;
33675 MBool accepted = false;
33676 MBool identical;
33677 MInt spaceId1, spaceId2;
33678 MFloat diff;
33679 MFloat eps;
33680 noIntersectionPoints = 0;
33681
33682 a = target[0];
33683 b = target[1];
33684 c = target[2];
33685
33686 spaceId1 = (dir + 1) % 3;
33687 spaceId2 = (dir + 2) % 3;
33688
33689 eps = abs(a[spaceId1] - b[spaceId1]) / 100;
33690
33691 for(MInt i = 0; i < noFeatureEdges; i++) {
33692 d = featureEdges[2 * i];
33693 e = featureEdges[2 * i + 1];
33694
33695 rejected = false;
33696 accepted = false;
33697
33698 if(d[dir] < a[dir] && e[dir] < a[dir])
33699 rejected = true;
33700 else if(d[dir] > a[dir] && e[dir] > a[dir])
33701 rejected = true;
33702 else if(d[dir] <= a[dir] && e[dir] >= a[dir])
33703 accepted = true;
33704 else if(d[dir] >= a[dir] && e[dir] <= a[dir])
33705 accepted = true;
33706
33707 if(rejected == false && accepted == false) {
33708 cerr << "no trivial rejection, no trivial acception, continue..." << endl;
33709 continue;
33710 } else if(rejected) {
33711 continue;
33712 }
33713
33714 gamma = ((e[0] - d[0]) * ((a[2] - c[2]) * (c[1] - b[1]) - (a[1] - c[1]) * (c[2] - b[2]))
33715 - (e[1] - d[1]) * ((a[2] - c[2]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[2] - b[2]))
33716 + (e[2] - d[2]) * ((a[1] - c[1]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[1] - b[1])));
33717
33718 s = ((c[0] - d[0]) * ((a[2] - c[2]) * (c[1] - b[1]) - (a[1] - c[1]) * (c[2] - b[2]))
33719 - (c[1] - d[1]) * ((a[2] - c[2]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[2] - b[2]))
33720 + (c[2] - d[2]) * ((a[1] - c[1]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[1] - b[1])))
33721 / gamma;
33722
33723 // 1. b Pierce point pP in plane j:
33724 for(MInt k = 0; k < 3; k++) {
33725 pP[k] = d[k] + s * (e[k] - d[k]);
33726 }
33727
33728 // check if Pierce point is located in target => must be really in target, otherwise cutPoint
33729 if(mMin(a[spaceId1], b[spaceId1]) <= pP[spaceId1] && pP[spaceId1] <= mMax(a[spaceId1], b[spaceId1])) {
33730 if(mMin(a[spaceId2], c[spaceId2]) <= pP[spaceId2] && pP[spaceId2] <= mMax(a[spaceId2], c[spaceId2])) {
33731 identical = false;
33732 for(MInt j = 0; j < noIntersectionPoints; j++) {
33733 diff = sqrt(POW2(pP[0] - intersectionPoints[j][0]) + POW2(pP[1] - intersectionPoints[j][1])
33734 + POW2(pP[2] - intersectionPoints[j][2]));
33735 if(diff < eps) {
33736 identical = true;
33737 break;
33738 }
33739 }
33740 if(!identical && noIntersectionPoints < 10) {
33741 for(MInt j = 0; j < 3; j++) {
33742 intersectionPoints[noIntersectionPoints][j] = pP[j];
33743 }
33744 noIntersectionPoints++;
33745 } else if(noIntersectionPoints == 10)
33746 cerr << "FvBndryCndXD::getIntersectionPoints - Error: Too many intersection points, array too small.."
33747 << endl;
33748 }
33749 }
33750 }
33751}
33752
33753// ---------------------------------------------------------------------------------------------
33754
33771template <MInt nDim, class SysEqn>
33772template <class _, std::enable_if_t<nDim == 3, _*>>
33773void FvBndryCndXD<nDim, SysEqn>::getFeatureEdges(MInt& noFeatureEdges, MFloat**& featureEdges, MInt noWallNodes,
33774 MInt*& wallNodes, MFloat*& meanNormal, MFloat*& basePoint) {
33775 TRACE();
33776
33777 MFloat* edgeStart;
33778 MFloat* edgeEnd;
33779 MFloatScratchSpace edgeVec_scratch(nDim, AT_, "edgeVec_scratch");
33780 MFloat* edgeVec = edgeVec_scratch.getPointer();
33781 MInt index1;
33782 MInt index2;
33783 MFloat normalEps = 1e-3;
33784 MFloat planeEps = 1e-4;
33785 MBool normalTest;
33786 MBool planeTest1;
33787 MBool planeTest2;
33788 MFloat eps, diff;
33789
33790 noFeatureEdges = 0;
33791 eps = 1e-5;
33792
33793 for(MInt i = 0; i < noWallNodes; i++) {
33794 for(MInt j = 0; j < nDim; j++) {
33795 index1 = j;
33796 index2 = (j + 1) % nDim;
33797
33798 edgeStart = m_solver->m_geometry->elements[wallNodes[i]].m_vertices[index1];
33799 edgeEnd = m_solver->m_geometry->elements[wallNodes[i]].m_vertices[index2];
33800
33801 diff = sqrt(POW2(edgeStart[0] - edgeEnd[0]) + POW2(edgeStart[1] - edgeEnd[1]) + POW2(edgeStart[2] - edgeEnd[2]));
33802 if(diff < eps) {
33803 // cerr << "Warning - small Edge!" << endl;
33804 continue;
33805 }
33806
33807 vecSub(edgeEnd, edgeStart, edgeVec);
33808 normalTest = (abs(inner_product(edgeVec, edgeVec + 3, meanNormal, 0.0)) < normalEps);
33809
33810 vecSub(edgeStart, basePoint, edgeVec);
33811 planeTest1 = (abs(inner_product(edgeVec, edgeVec + 3, meanNormal, 0.0)) < planeEps);
33812
33813 vecSub(edgeEnd, basePoint, edgeVec);
33814 planeTest2 = (abs(inner_product(edgeVec, edgeVec + 3, meanNormal, 0.0)) < planeEps);
33815
33816 if(normalTest && (planeTest1 || planeTest2)) {
33817 featureEdges[2 * noFeatureEdges] = edgeStart;
33818 featureEdges[2 * noFeatureEdges + 1] = edgeEnd;
33819
33820 noFeatureEdges++;
33821 }
33822 }
33823 }
33824}
33825
33826// ---------------------------------------------------------------------------------------------
33827
33843template <MInt nDim, class SysEqn>
33844template <class _, std::enable_if_t<nDim == 3, _*>>
33845void FvBndryCndXD<nDim, SysEqn>::getSortedElements(const std::vector<MInt>& nodeList, MInt& noWallNodes,
33846 MInt*& wallNodes, MInt& noInflowNodes, MInt*& inflowNodes,
33847 MInt bcId) {
33848 TRACE();
33849
33850 noInflowNodes = 0;
33851 noWallNodes = 0;
33852 for(MInt i = 0; i < (signed)nodeList.size(); i++) {
33853 if(m_solver->m_geometry->elements[nodeList[i]].m_bndCndId == bcId) {
33854 inflowNodes[(noInflowNodes)++] = nodeList[i];
33855 } else {
33856 wallNodes[(noWallNodes)++] = nodeList[i];
33857 }
33858 }
33859}
33860
33861// ---------------------------------------------------------------------------------
33862
33876template <MInt nDim, class SysEqn>
33877// template <class _, std::enable_if_t<nDim == 3, _*>>
33879 TRACE();
33880
33881 const MInt noSmallCells = m_smallBndryCells->size();
33882 const MInt noBndryCells = m_bndryCells->size();
33883 MInt bndryId, nghbrId, cellId, noNghbrIds, id;
33884 MInt noUnknowns = nDim;
33885 MFloatScratchSpace x_scratch(nDim, AT_, "x_scratch");
33886 MFloat* x = x_scratch.getPointer();
33887 //---
33888
33889
33890 // to make errors visible (if reconstruction constants are not set for certain cells)
33891 // initialize with non-sense number which will produce non-sense solutions
33892 for(bndryId = 0; bndryId < noBndryCells; bndryId++) {
33893 for(MInt n = 0; n < nDim * m_solver->m_cells.noRecNghbrs(); n++)
33894 m_reconstructionConstants[bndryId][n] = -9999;
33895 }
33896
33897 // cell-center reconstruction
33898 for(bndryId = 0; bndryId < noBndryCells; bndryId++) {
33899 cellId = m_bndryCells->a[bndryId].m_cellId;
33900 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
33901 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
33902 if(m_bndryCells->a[bndryId].m_linkedCellId > -1) continue;
33903
33904 noNghbrIds = m_solver->a_noReconstructionNeighbors(cellId);
33905
33906 // loop over least-squares cell cluster
33907 for(MInt cell = 0; cell < noNghbrIds; cell++) {
33908 id = m_solver->a_reconstructionNeighborId(cellId, cell);
33909 if(!m_solver->a_isBndryGhostCell(id)) {
33910 for(MInt i = 0; i < nDim; i++) {
33911 x[i] = m_solver->a_coordinate(id, i);
33912 }
33913 } else {
33914 // do not take ghost cell s into account
33915 for(MInt i = 0; i < nDim; i++)
33916 x[i] = m_solver->a_coordinate(cellId, i);
33917 }
33918
33919 for(MInt i = 0; i < nDim; i++)
33920 m_solver->m_A[cell][i] = x[i] - m_solver->a_coordinate(cellId, i);
33921 }
33922
33923 // compute ATA
33924 for(MInt i = 0; i < noUnknowns; i++) {
33925 for(MInt j = 0; j < noUnknowns; j++) {
33926 m_solver->m_ATA[i][j] = F0;
33927 for(MInt k = 0; k < noNghbrIds; k++) {
33928 m_solver->m_ATA[i][j] += m_solver->m_A[k][i] * m_solver->m_A[k][j];
33929 }
33930 }
33931 }
33932
33933 // invert ATA
33934 const MFloat epsilon = POW3(m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel()) / (1000.0));
33935 maia::math::inverse(m_solver->m_ATA, m_solver->m_ATAi, noUnknowns, epsilon);
33936
33937 // compute (ATA)^(-1) * AT
33938 for(MInt i = 0; i < noUnknowns; i++) {
33939 for(MInt j = 0; j < noNghbrIds; j++) {
33940 m_solver->m_ATA[i][j] = F0;
33941 for(MInt k = 0; k < noUnknowns; k++) {
33942 m_solver->m_ATA[i][j] += m_solver->m_ATAi[i][k] * m_solver->m_A[j][k];
33943 }
33944 }
33945 }
33946
33947 // loop over least-squares cell cluster
33948 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
33949 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
33950
33951 // compute the constants
33952 if(!m_solver->a_isBndryGhostCell(nghbrId))
33953 for(MInt i = 0; i < nDim; i++)
33954 m_reconstructionConstants[bndryId][nDim * nghbr + i] = m_solver->m_ATA[i][nghbr];
33955 else
33956 for(MInt i = 0; i < nDim; i++)
33957 m_reconstructionConstants[bndryId][nDim * nghbr + i] = F0;
33958 }
33959 }
33960
33961 // loop over all slave cells which are regular computing cells on the current level
33962 for(MInt sid = 0; sid < noSmallCells; sid++) {
33963 bndryId = m_smallBndryCells->a[sid];
33964 cellId = m_bndryCells->a[bndryId].m_linkedCellId;
33965 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
33966 if(!m_solver->a_hasProperty(m_bndryCells->a[bndryId].m_cellId, SolverCell::IsOnCurrentMGLevel)) continue;
33967 if(!m_solver->a_hasProperty(cellId, SolverCell::IsFlux)) continue;
33968 if(m_solver->a_isBndryGhostCell(cellId)) continue;
33969 if(m_solver->a_isBndryGhostCell(m_bndryCells->a[bndryId].m_cellId)) continue;
33970 // if( m_solver->a_hasProperty( cellId , SolverCell::IsCutOff) )
33971 // continue;
33972 // if( m_solver->a_hasProperty( m_bndryCells->a[bndryId].m_cellId , SolverCell::IsCutOff) )
33973 // continue;
33974 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
33975 if(m_solver->a_hasProperty(m_bndryCells->a[bndryId].m_cellId, SolverCell::IsNotGradient)) continue;
33976
33977 // take all neighbors of the master cell
33978 noNghbrIds = m_solver->a_noReconstructionNeighbors(cellId);
33979
33980 // loop over least-squares cell cluster
33981 for(MInt cell = 0; cell < noNghbrIds; cell++) {
33982 id = m_solver->a_reconstructionNeighborId(cellId, cell);
33983 if(!m_solver->a_isBndryGhostCell(id)) {
33984 for(MInt i = 0; i < nDim; i++) {
33985 x[i] = m_solver->a_coordinate(id, i);
33986 }
33987 } else {
33988 // do not take ghost cells into account
33989 for(MInt i = 0; i < nDim; i++)
33990 x[i] = m_solver->a_coordinate(cellId, i);
33991 }
33992
33993 for(MInt i = 0; i < nDim; i++)
33994 m_solver->m_A[cell][i] = x[i] - m_solver->a_coordinate(cellId, i);
33995 }
33996
33997 // compute ATA
33998 for(MInt i = 0; i < noUnknowns; i++) {
33999 for(MInt j = 0; j < noUnknowns; j++) {
34000 m_solver->m_ATA[i][j] = F0;
34001 for(MInt k = 0; k < noNghbrIds; k++) {
34002 m_solver->m_ATA[i][j] += m_solver->m_A[k][i] * m_solver->m_A[k][j];
34003 }
34004 }
34005 }
34006
34007 // invert ATA
34008 const MFloat epsilon = POW3(m_solver->c_cellLengthAtLevel(m_solver->maxRefinementLevel()) / (1000.0));
34009 maia::math::inverse(m_solver->m_ATA, m_solver->m_ATAi, noUnknowns, epsilon);
34010
34011 // compute (ATA)^(-1) * AT
34012 for(MInt i = 0; i < noUnknowns; i++) {
34013 for(MInt j = 0; j < noNghbrIds; j++) {
34014 m_solver->m_ATA[i][j] = F0;
34015 for(MInt k = 0; k < noUnknowns; k++) {
34016 m_solver->m_ATA[i][j] += m_solver->m_ATAi[i][k] * m_solver->m_A[j][k];
34017 }
34018 }
34019 }
34020
34021 // loop over least-squares cell cluster
34022 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
34023 nghbrId = m_solver->a_reconstructionNeighborId(cellId, nghbr);
34024
34025 // compute the constants
34026 if(!m_solver->a_isBndryGhostCell(nghbrId))
34027 for(MInt i = 0; i < nDim; i++)
34028 m_reconstructionConstants[bndryId][nDim * nghbr + i] = m_solver->m_ATA[i][nghbr];
34029 else
34030 for(MInt i = 0; i < nDim; i++)
34031 m_reconstructionConstants[bndryId][nDim * nghbr + i] = F0;
34032 }
34033 }
34034}
34035// template void FvBndryCndXD<3, FvSysEqnRANS<3>>::computeReconstructionConstants_interpolation();
34036// template void FvBndryCndXD<3, FvSysEqnNS<3>>::computeReconstructionConstants_interpolation();
34037#undef plotall
34038
34042
34046template <MInt nDim, class SysEqn>
34047template <class _, std::enable_if_t<nDim == 2, _*>>
34048void FvBndryCndXD<nDim, SysEqn>::computePolygon(MFloat* x, const MInt N, MFloat* centroid, MFloat* area) {
34049 TRACE();
34050 MFloat tmp = F0;
34051 if(N < 3) {
34052 cerr << "Warning: Insufficient amount of points provided in FvBndryCndXD::computePolygon(...)." << endl;
34053 } else if(N == 3) {
34054 centroid[0] = F1B3 * (x[0] + x[2] + x[4]);
34055 centroid[1] = F1B3 * (x[1] + x[3] + x[5]);
34056 *area = F1B2 * fabs(((x[0] - x[4]) * (x[3] - x[1])) - ((x[0] - x[2]) * (x[5] - x[1])));
34057 } else {
34058 centroid[0] = F0;
34059 centroid[1] = F0;
34060 *area = F0;
34061 for(MInt i = 0; i < N; i++) {
34062 tmp = x[i * 2] * x[((i + 1) % N) * 2 + 1] - x[i * 2 + 1] * x[((i + 1) % N) * 2];
34063 *area += tmp;
34064 centroid[0] += tmp * (x[i * 2] + x[((i + 1) % N) * 2]);
34065 centroid[1] += tmp * (x[i * 2 + 1] + x[((i + 1) % N) * 2 + 1]);
34066 }
34067 centroid[0] /= (F3 * (*area));
34068 centroid[1] /= (F3 * (*area));
34069 *area = F1B2 * fabs((*area));
34070 }
34071}
34072
34077template <MInt nDim, class SysEqn>
34079 TRACE();
34080 TERMM_IF_COND(m_solver->m_reConstSVDWeightMode == 3 || m_solver->m_reConstSVDWeightMode == 4,
34081 "Possibly not yet implemented!");
34082
34083 MInt cbcId = m_cbcBndryCndIds[bcId];
34084 // Store the cbc flow directions
34085 MInt otherDir[2 * nDim];
34086 for(MInt dim = 0; dim < nDim; dim++) {
34087 otherDir[2 * dim] = 2 * dim + 1;
34088 otherDir[2 * dim + 1] = 2 * dim;
34089 }
34090 MInt direction = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, cbcId);
34091 std::vector<MInt> dirs;
34092 dirs.resize(nDim + 1);
34093 dirs[0] = otherDir[direction];
34094 dirs[1] = (MInt)dirs[0] / 2;
34095 dirs[2] = (dirs[1] + 1) % nDim;
34096 IF_CONSTEXPR(nDim == 3) { dirs[nDim] = (dirs[2] + 1) % nDim; }
34097 m_cbcDir[cbcId] = dirs;
34098
34099 // Store the cbc relaxation coefficients
34100 std::vector<MFloat> relaxCoef;
34101 relaxCoef.resize(CV->noVariables);
34102 for(MInt var = 0; var < CV->noVariables; var++) {
34103 MInt ind = var + CV->noVariables * cbcId;
34104 relaxCoef[var] = Context::getSolverProperty<MFloat>("cbcRelaxation", m_solverId, AT_, ind);
34105 }
34106 m_cbcRelax[cbcId] = relaxCoef;
34107 // Store the cbc reference length
34108 MInt dimN = dirs[1];
34109 MFloat tmp[nDim * 2];
34110 if(m_solver->m_geometry->GetNoElements() < 1) {
34111 m_solver->m_geometry->getBoundingBoxMB(tmp);
34112 } else {
34113 m_solver->m_geometry->getBoundingBox(tmp);
34114 }
34115 m_cbcLref[cbcId] = (tmp[dimN + nDim] - tmp[dimN]);
34116 // new cbcLref calculation based on cutOff rather than Bounding box from stl
34117 if(Context::propertyExists("cutOffCoordinates", m_solverId) && Context::propertyExists("cutOffMethod", m_solverId)
34118 && Context::getSolverProperty<MString>("cutOffMethod", m_solverId, AT_) == "B") {
34119 std::vector<MFloat> cutOffCoordinates;
34120 cutOffCoordinates.resize(2 * nDim);
34121 for(MInt i = 0; i < (2 * nDim); i++) {
34122 cutOffCoordinates[i] = Context::getSolverProperty<MFloat>("cutOffCoordinates", m_solverId, AT_, i);
34123 }
34124 if(cutOffCoordinates[dimN + nDim] - cutOffCoordinates[dimN] < m_cbcLref[cbcId]) {
34125 m_cbcLref[cbcId] = cutOffCoordinates[dimN + nDim] - cutOffCoordinates[dimN];
34126 }
34127 }
34128
34129 // needed for turbulence injection, always on (set stresses in property file to 0.0 if unwanted)
34130 m_cbcTurbulence = false;
34131 m_cbcTurbulence = Context::getSolverProperty<MBool>("cbcTurbulenceGeneration", m_solverId, AT_, &m_cbcTurbulence);
34132 if(m_cbcTurbulence) {
34133 bcInit1601(bcId);
34134 if(m_sortedCutOffCells[bcId]->size() > 0) {
34135 mDeallocate(m_oldFluctChol);
34136 mAlloc(m_oldFluctChol, m_sortedCutOffCells[bcId]->size(), nDim, "m_oldFluctChol", F0, AT_);
34137 }
34138 }
34139 if(m_sortedCutOffCells[bcId]->size() < 1) return;
34140 // Compute cbc inflow area
34141 MInt dirN = dirs[0];
34142 std::vector<MFloat> refPoint;
34143 refPoint.resize(nDim);
34144 m_cbcInflowArea[cbcId] = computeCutoffBoundaryGeometry(bcId, dirN, &refPoint[0]);
34145
34146 // Store cbc reference point
34147 m_cbcReferencePoint[cbcId] = refPoint;
34148
34149 // set default direction values;
34150 m_dirNormal[cbcId].resize(nDim);
34151 m_dirTangent[cbcId].resize(nDim);
34152
34153 m_dirNormal[cbcId][m_cbcDir[cbcId][1]] = 1.0;
34154 m_dirNormal[cbcId][m_cbcDir[cbcId][2]] = 0.0;
34155 IF_CONSTEXPR(nDim == 3) { m_dirNormal[cbcId][m_cbcDir[cbcId][3]] = 0.0; }
34156
34157 m_dirTangent[cbcId][m_cbcDir[cbcId][1]] = 0.0;
34158 m_dirTangent[cbcId][m_cbcDir[cbcId][2]] = 1.0;
34159 IF_CONSTEXPR(nDim == 3) { m_dirTangent[cbcId][m_cbcDir[cbcId][3]] = 0.0; }
34160
34161 // Calculate tangential directions
34162 if(Context::propertyExists("cbcNormalDir")) {
34163 for(MInt n = 0; n < nDim; n++) {
34164 m_dirNormal[cbcId][n] = Context::getSolverProperty<MFloat>("cbcNormalDir", m_solverId, AT_, nDim * cbcId + n);
34165 }
34166 m_dirTangent[cbcId][m_cbcDir[cbcId][1]] =
34167 sqrt(POW2(m_dirNormal[cbcId][m_cbcDir[cbcId][2]] / m_dirNormal[cbcId][m_cbcDir[cbcId][1]])
34168 / (1 + POW2(m_dirNormal[cbcId][m_cbcDir[cbcId][2]] / m_dirNormal[cbcId][m_cbcDir[cbcId][1]])));
34169 m_dirTangent[cbcId][m_cbcDir[cbcId][2]] = sqrt(1 - POW2(m_dirTangent[cbcId][m_cbcDir[cbcId][1]]));
34170 IF_CONSTEXPR(nDim == 3) { m_dirTangent[cbcId][m_cbcDir[cbcId][3]] = 0; }
34171 }
34172 // Activate viscous terms
34173 m_cbcViscous = false;
34174 m_cbcViscous = Context::getSolverProperty<MBool>("cbcViscous", m_solverId, AT_, &m_cbcViscous);
34175
34176 MInt domainMin = domainId();
34177 if(noDomains() > 1) {
34178 MPI_Allreduce(MPI_IN_PLACE, &domainMin, 1, MPI_INT, MPI_MIN, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
34179 "MPI_IN_PLACE", "domainMin");
34180 }
34181 m_cbcDomainMin[cbcId] = domainMin;
34182
34183 if(domainId() == m_cbcDomainMin[cbcId]) {
34184 cerr << " Characteristic length is " << m_cbcLref[cbcId] << endl;
34185 cerr << bcId << " Normal vector is : " << m_dirNormal[cbcId][0] << " " << m_dirNormal[cbcId][1] << endl;
34186 IF_CONSTEXPR(nDim == 3) { cerr << " " << m_dirNormal[cbcId][2] << endl; }
34187 cerr << bcId << " Tangential vector is : " << m_dirTangent[cbcId][0] << " " << m_dirTangent[cbcId][1] << endl;
34188 IF_CONSTEXPR(nDim == 3) { cerr << " " << m_dirTangent[cbcId][2] << endl; }
34189 cerr << bcId << " Inflow normal Area is: " << m_cbcInflowArea[cbcId] << endl;
34190 }
34191
34192 if(m_cutOffBndryCndIds[bcId] == 109910 || m_cutOffBndryCndIds[bcId] == 109911) {
34193 // Read BC data
34194 stringstream fn;
34195 fn.clear();
34196 fn << "bc109910.txt";
34197 MString fname = fn.str();
34198 if(domainId() == m_cbcDomainMin[cbcId]) cerr << "loading BC data from " << fname << "...";
34199
34200 ifstream unData;
34201 unData.open(fname);
34202 vector<MFloat> data;
34203 MFloat num;
34204 string line;
34205
34206 while(unData >> num) {
34207 data.push_back(num);
34208 }
34209
34210 // MInt count = 0;
34211 MInt unDataVarCount = Context::getSolverProperty<MInt>("bc109910DataCount", m_solverId, AT_, &unDataVarCount); // 14
34212 m_unTargetDataCount = data.size() / unDataVarCount;
34213 mAlloc(m_unTargetData, m_unTargetDataCount, "m_unTargetData", AT_);
34214
34215 for(MInt d = 0; d < m_unTargetDataCount; d++) {
34216 MInt index = unDataVarCount * d;
34217 MFloat y = data[index];
34218 MFloat un = data[index + 1];
34219 m_unTargetData[d] = make_pair(y, un);
34220 }
34221
34222 unData.close();
34223 }
34224
34225 if(m_cutOffBndryCndIds[bcId] == 109921) {
34226 // Read BC data
34227 stringstream fn;
34228 fn.clear();
34229 fn << "bc109921.txt";
34230 MString fname = fn.str();
34231 if(m_solver->domainId() == 0) cerr << "loading BC data from " << fname << "...";
34232
34233 ifstream vnData;
34234 vnData.open(fname);
34235 vector<MFloat> data;
34236 MFloat num;
34237 string line;
34238
34239 while(vnData >> num) {
34240 data.push_back(num);
34241 }
34242
34243 // MInt count = 0;
34244 MInt vnDataVarCount = 13;
34245 m_vnTargetDataCount = data.size() / vnDataVarCount;
34246 mAlloc(m_vnTargetData, m_vnTargetDataCount, "m_vnTargetData", AT_);
34247
34248 for(MInt d = 0; d < m_vnTargetDataCount; d++) {
34249 MInt index = vnDataVarCount * d;
34250 MFloat y = data[index];
34251 MFloat vn = data[index + 2];
34252 m_vnTargetData[d] = make_pair(y, vn);
34253 }
34254
34255 vnData.close();
34256 }
34257}
34258
34270template <MInt nDim, class SysEqn>
34272 TRACE();
34273
34274 const MInt minRecDim = nDim + 1;
34275 const MInt medRecDim = 2 * nDim + 1;
34276 const MInt maxRecDim = m_secondOrderRec ? (IPOW2(nDim) + 2) : minRecDim;
34277 const MInt noBndryCells = m_bndryCells->size();
34278 const MInt maxNoSrfcs = 14;
34279 const MInt volFactor = nDim == 3 ? 4 : 2;
34281 mTerm(1, AT_, "Increase maxNoSrfcs. " + to_string(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces));
34282 }
34283 const MInt maxNoNghbrs = 200;
34284 const MFloat condNumThreshold = 1e7;
34285 if(updateOnlyBndryCndId < 0) {
34286 m_log << "Initializing small cell RHS treatment." << endl;
34287 }
34288
34290 MFloatScratchSpace deltaXSurf(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, nDim, AT_, "deltaXSurf");
34291 MFloatScratchSpace deltaXSurfProj(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, nDim, AT_, "deltaXSurfProj");
34293 MFloatScratchSpace backup(FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces, maxRecDim, AT_, "backup");
34294 MFloatScratchSpace mat(maxNoNghbrs, maxRecDim, AT_, "mat_smallCells");
34295 MFloatScratchSpace matInv(maxRecDim, maxNoNghbrs, AT_, "matInv");
34296 MFloatScratchSpace weights(maxNoNghbrs, AT_, "weights");
34297
34298 MFloat maxCondNum0 = F0;
34299 MFloat maxCondNum1 = F0;
34300 MFloat avgCondNum0 = F0;
34301 MFloat avgCondNum1 = F0;
34302 MFloat condCnt0 = F0;
34303 MFloat condCnt1 = F0;
34304
34305 m_smallCutCells.clear();
34306 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
34307 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
34308 const MInt noSrfcs = m_bndryCells->a[bndryId].m_noSrfcs;
34309 MInt gridcellId = cellId;
34310 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitClone)) {
34311 gridcellId = m_solver->m_splitChildToSplitCell.find(cellId)->second;
34312 }
34313
34314 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
34315 continue;
34316 }
34317 if(m_solver->a_hasProperty(cellId, SolverCell::IsNotGradient)) {
34318 continue;
34319 }
34320 if(!m_solver->a_hasProperty(cellId, SolverCell::IsSplitChild) && m_solver->c_noChildren(gridcellId) > 0) {
34321 continue;
34322 }
34323 if(m_solver->a_hasProperty(cellId, SolverCell::IsSplitCell)) {
34324 continue;
34325 }
34326 if(m_solver->a_isPeriodic(cellId)) {
34327 continue;
34328 }
34329 if(m_solver->a_isHalo(cellId)) {
34330 continue;
34331 }
34332
34333 // commented version also applies smallCellCorrection for cutCells on lower levels, however
34334 // they only need to be stabilised if their volume falls below the threshold of the fines cells!
34335 // maxLevelChange
34336 MFloat vfrac = m_solver->a_cellVolume(cellId) / m_solver->grid().gridCellVolume(m_solver->maxLevel());
34337 if(m_solver->m_localTS) {
34338 vfrac = m_solver->a_cellVolume(cellId) / m_solver->grid().gridCellVolume(m_solver->a_level(cellId));
34339 }
34340
34341 MBool atWall = false;
34342 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
34343 if(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId / 1000 == 3) {
34344 atWall = true;
34345 }
34346 }
34347 MFloat volumeLimit = atWall ? m_volumeLimitWall : m_volumeLimitOther;
34348
34349 if(m_solver->a_level(cellId) < m_solver->maxLevel() && m_solver->m_bndryLevelJumps) {
34350 volumeLimit = volumeLimit * volFactor * (m_solver->maxLevel() - m_solver->a_level(cellId));
34351 }
34352
34353 if(vfrac < volumeLimit) {
34354 m_smallCutCells.push_back(bndryId);
34355 }
34356
34357 MBool skip = false;
34358 if(updateOnlyBndryCndId > -1) {
34359 skip = true;
34360 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
34361 if(m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId == updateOnlyBndryCndId) {
34362 skip = false;
34363 }
34364 }
34365 }
34366#ifndef NDEBUG
34367 if(skip && vfrac < volumeLimit
34368 && m_bndryCell[bndryId].m_cellVarsRecConst.size()
34369 != IPOW2(noSrfcs) * m_bndryCell[bndryId].m_recNghbrIds.size()) {
34370 cerr << domainId() << ": strange skip " << cellId << " " << m_solver->c_globalId(cellId) << endl;
34371 }
34372#endif
34373 if(skip) {
34374 continue;
34375 }
34376
34377
34378 const MFloat normalizationFactor = FPOW2(m_solver->a_level(cellId)) / m_solver->c_cellLengthAtLevel(0);
34379 // scaling factor to reduce the condition number of the resulting eq. sys.
34380 const MInt recSize = m_bndryCell[bndryId].m_recNghbrIds.size();
34381 ASSERT(recSize > 0, "");
34382
34383 mat.fill(F0);
34384 weights.fill(F0);
34385
34386 const MInt recDim = maxRecDim;
34387 ASSERT(minRecDim, "");
34388 ASSERT(medRecDim, "");
34389
34390 for(MInt k = noSrfcs + 1; k < recSize; k++) { // Srfcs and smallCell itself not used
34391 MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[k];
34392 MFloat* nghbrCoord = &(m_solver->a_coordinate(nghbrId, 0));
34393 MInt nghbrLevel = m_solver->a_level(nghbrId);
34394 MFloat volume = m_solver->a_cellVolume(nghbrId);
34395 array<MFloat, nDim> deltaX;
34396 MFloat dx = F0;
34397 for(MInt i = 0; i < nDim; i++) {
34398 deltaX[i] = (nghbrCoord[i] - m_solver->a_coordinate(cellId, i)) * normalizationFactor;
34399 dx += POW2(nghbrCoord[i] - m_solver->a_coordinate(cellId, i));
34400 }
34401
34402 MFloat vfracNghbr = volume / m_solver->grid().gridCellVolume(nghbrLevel);
34403 weights(k) = maia::math::RBF(dx, POW2(m_solver->c_cellLengthAtLevel(m_solver->a_level(cellId))))
34404 * maia::math::deltaFun(vfracNghbr, 1e-8, 1.0);
34405
34406 MInt cnt = 0;
34407 mat(k, cnt) = F1;
34408 cnt++;
34409 for(MInt i = 0; i < nDim; i++) {
34410 mat(k, cnt) = deltaX[i];
34411 cnt++;
34412 }
34413 for(MInt i = 0; i < nDim; i++) {
34414 if(cnt >= recDim) {
34415 continue;
34416 }
34417 mat(k, cnt) = F1B2 * POW2(deltaX[i]);
34418 cnt++;
34419 }
34420 for(MInt i = 0; i < nDim; i++) {
34421 for(MInt j = i + 1; j < nDim; j++) {
34422 if(cnt >= recDim) {
34423 continue;
34424 }
34425 mat(k, cnt) = deltaX[i] * deltaX[j];
34426 cnt++;
34427 }
34428 }
34429 }
34430
34431 maia::math::invert(mat, weights, matInv, recSize, recDim);
34432 const MFloat condNum = maia::math::frobeniusMatrixNormSquared(mat, recSize, recDim);
34433
34434 maxCondNum0 = mMax(maxCondNum0, condNum);
34435 avgCondNum0 += condNum;
34436 condCnt0 += F1;
34437 if(condNum < F0 || condNum > condNumThreshold) {
34438 cerr << "(1) Warning: SVD failed (" << condNum << ") cell " << cellId << " (" << m_solver->c_globalId(cellId)
34439 << ") "
34440 << ", " << recSize << "x" << recDim << " vfrac " << setprecision(14)
34441 << m_bndryCells->a[bndryId].m_volume / m_solver->grid().gridCellVolume(m_solver->a_level(cellId))
34442 << setprecision(6) << ", p13: " << m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)
34443 << ", p15: " << m_solver->a_isHalo(cellId) << " at timestep " << globalTimeStep
34444 << ", coords: " << m_solver->a_coordinate(cellId, 0) << " " << m_solver->a_coordinate(cellId, 10) << " "
34445 << m_solver->a_coordinate(cellId, mMin(nDim - 1, 2)) << endl;
34446 const MFloat rank = maia::math::invertR(mat, weights, matInv, recSize, minRecDim);
34447 if(rank >= min(recSize, minRecDim)) {
34448 cerr << "Succeeded using reduced-order reconstruction." << endl;
34449 } else {
34450 cerr << "Failed also with reduced-order reconstruction, using fallback solution." << endl;
34451 }
34452 }
34453
34454 for(MInt k = 0; k < recSize; k++) {
34455 MInt cnt = 1;
34456 for(MInt i = 0; i < nDim; i++) {
34457 matInv(cnt, k) *= normalizationFactor;
34458 cnt++;
34459 }
34460 for(cnt = nDim + 1; cnt < recDim; cnt++) {
34461 matInv(cnt, k) *= POW2(normalizationFactor);
34462 }
34463 }
34464
34465 // for single boundary surface there is a Dirichlet and a Neumann stencil for the different
34466 // boundary conditions for multiple boundary surfaces, there can be combinations of
34467 // Neumann-Dirichlet or Dirichlet-Neumann boundary conditions, e.g., when a solid wall and an
34468 // outflow boundary intersect the cell, therefore IPOW2[noSrfcs] combinations
34469 m_bndryCell[bndryId].m_cellVarsRecConst.resize(recSize * IPOW2(noSrfcs));
34470 for(MInt p = 0; p < recSize; p++) {
34471 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * p] = matInv(0, p);
34472 }
34473
34474 if(condNum < F0 || condNum > condNumThreshold) {
34475 MFloat sumcnt = F0;
34476 for(MInt k = 0; k < recSize; k++) {
34477 const MInt nghbrId = m_bndryCell[bndryId].m_recNghbrIds[k];
34478 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k] = F0;
34479 if(k < noSrfcs + 1) {
34480 continue;
34481 }
34482 if(nghbrId == cellId) {
34483 continue;
34484 }
34485 MFloat dx = F0;
34486 MFloat volume = F0;
34487 MInt level = -1;
34488 volume = m_solver->a_cellVolume(nghbrId);
34489 for(MInt i = 0; i < nDim; i++) {
34490 dx += POW2(m_solver->a_coordinate(nghbrId, i) - m_solver->a_coordinate(cellId, i));
34491 }
34492 level = m_solver->a_level(nghbrId);
34493 MFloat fac = maia::math::deltaFun(volume / m_solver->grid().gridCellVolume(level), 1e-8, 1.0);
34494 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k] = fac / mMax(1e-14, sqrt(dx));
34495 sumcnt += m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k];
34496 }
34497 for(MInt k = 0; k < recSize; k++) {
34498 m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * k] /= sumcnt;
34499 }
34500 cerr << m_solver->c_globalId(cellId) << " has special con.Numer treatment" << endl;
34501 }
34502 }
34503
34504 if(updateOnlyBndryCndId < 0 || globalTimeStep % 100 == 0) {
34505 m_log << "Small cell treatment average (maximum) condition numbers == Dirichlet stencil: " << avgCondNum0 / condCnt0
34506 << " (" << maxCondNum0 << "), Neumann stencil: " << avgCondNum1 / condCnt1 << " (" << maxCondNum1 << ")."
34507 << endl;
34508 MInt noSmallCells = m_smallCutCells.size();
34509 if(updateOnlyBndryCndId < 0 || globalTimeStep <= 0) {
34510 MPI_Allreduce(MPI_IN_PLACE, &noSmallCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noSmallCells");
34511 }
34512 m_log << "Number of small cut cells for flux redistribution: " << noSmallCells << " in solver " << m_solverId
34513 << endl;
34514 }
34515}
34516
34517template <MInt nDim, class SysEqn>
34518template <class _, std::enable_if_t<nDim == 3, _*>>
34520 TRACE();
34521 ASSERT(m_cbcCutOff, "");
34522
34523 if(m_sortedCutOffCells[bcId]->size() == 0) {
34524 return;
34525 }
34526
34527 // debug, should be true
34528 const MBool transversal = false;
34529
34530 const MInt otherDir[6] = {1, 0, 3, 2, 5, 4};
34531
34532 MBool& first = m_static_cbc1099_1091_engine_first;
34533 MInt& dirN = m_static_cbc1099_1091_engine_dirN;
34534 MInt& dimN = m_static_cbc1099_1091_engine_dimN;
34535 MInt& dimT1 = m_static_cbc1099_1091_engine_dimT1;
34536 MFloat& inflowArea = m_static_cbc1099_1091_engine_inflowArea;
34537 MInt& domainMin = m_static_cbc1099_1091_engine_domainMin;
34538
34539 MFloat(&dirNormal)[3] = m_static_cbc1099_1091_engine_normal;
34540 MFloat(&dirTangent)[3] = m_static_cbc1099_1091_engine_tangent;
34541
34542 MInt& dimT2 = m_static_cbc1099_1091_engine_dimT2;
34543
34544 if(first) {
34545 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
34546 MInt noCutOffDirections = Context::propertyLength("cutOffDirections", m_solverId);
34547 if(noCutOffDirections != noCutOffBndryIds) {
34548 mTerm(1, AT_,
34549 "Wrong number of cut off directions. Must be identical to number of cut off bndryIds! Please check!");
34550 }
34551 MInt cutOffBndryIdTmp, cutOffDirectionTmp;
34552 for(MInt i = 0; i < noCutOffBndryIds; i++) {
34553 cutOffBndryIdTmp = Context::getSolverProperty<MInt>("cutOffBndryIds", m_solverId, AT_, i);
34554 cutOffDirectionTmp = Context::getSolverProperty<MInt>("cutOffDirections", m_solverId, AT_, i);
34555 if(cutOffBndryIdTmp == m_cutOffBndryCndIds[bcId]) {
34556 dirN = otherDir[cutOffDirectionTmp];
34557 break;
34558 }
34559 }
34560 dimN = (MInt)dirN / 2;
34561 dimT1 = (dimN + 1) % nDim;
34562
34563 MFloatScratchSpace referencePoint_Scratch(3, AT_, "referencePoint_Scratch");
34564 MFloat* referencePoint = referencePoint_Scratch.getPointer();
34565
34566 inflowArea = computeCutoffBoundaryGeometry(bcId, dirN, referencePoint);
34567
34568 dimT2 = (dimT1 + 1) % nDim;
34569
34570 domainMin = domainId();
34571 if(noDomains() > 1) {
34572 MPI_Allreduce(MPI_IN_PLACE, &domainMin, 1, MPI_INT, MPI_MIN, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
34573 "MPI_IN_PLACE", "domainMin");
34574 }
34575
34576 first = false;
34577
34578 MFloat tmp1[2 * nDim];
34579 m_solver->m_geometry->getBoundingBox(tmp1);
34580 // xmin, ymin, zmin, xmax, ymax, zmax
34581 // full domain-size!
34582 MFloat LN1 = (tmp1[dimN + nDim] - tmp1[dimN]);
34583
34584 if(LN1 < m_solver->m_eps || std::isnan(LN1)) {
34585 m_solver->m_geometry->getBoundingBoxMB(tmp1);
34586 LN1 = (tmp1[dimN + nDim] - tmp1[dimN]);
34587 }
34588
34589 if(domainId() == domainMin) {
34590 cerr << " Characteristic length is " << LN1 << endl;
34591 }
34592
34593 for(MInt n = 0; n < 3; n++) {
34594 dirNormal[n] = -2;
34595 dirTangent[n] = -2;
34596 }
34597
34610 if(Context::propertyExists("cbcNormalDir")) {
34611 for(MInt n = 0; n < nDim; n++) {
34612 dirNormal[n] = Context::getSolverProperty<MFloat>("cbcNormalDir", m_solverId, AT_, nDim * bcId + n);
34613 }
34614
34615 dirTangent[0] = sqrt(POW2(dirNormal[1] / dirNormal[0]) / (1 + POW2(dirNormal[1] / dirNormal[0])));
34616 dirTangent[1] = sqrt(1 - POW2(dirTangent[0]));
34617 dirTangent[2] = 0;
34618
34619 if(dirNormal[0] > -2) {
34620 inflowArea = inflowArea * dirTangent[1];
34621 }
34622 }
34623
34624 if(domainId() == domainMin && dirNormal[0] > -2) {
34625 cerr << bcId << " Normal vector is : " << dirNormal[0] << " " << dirNormal[1] << " " << dirNormal[2] << endl;
34626 cerr << bcId << " Tangential vector is : " << dirTangent[0] << " " << dirTangent[1] << " " << dirTangent[2]
34627 << endl;
34628 cerr << bcId << " Inflow normal Area is: " << inflowArea << endl;
34629 }
34630 }
34631
34632 ASSERT(dimN >= 0 && dimT1 >= 0, "No initialisation for this rank!");
34633
34634 MFloat eta2 = -0.28;
34635 MFloat eta3 = 0.28;
34636 MFloat sigma = 3.5;
34637
34638 // reducing sigma at inflow and outflow globally to hanlde incoming eddies is not working!
34639 // trying global sigma increase!
34640 // trying local sigma reduction for eddy detection!
34641
34642 // increase sigma at outflow!
34643 if(dirN % 2 == 0 && m_solver->m_engineSetup) {
34644 sigma = 6.5;
34645 eta2 = -4.5;
34646 }
34647
34648 // for diagonal in/out-flow the sponging values need to have the same magnitude!
34649 if(dirNormal[0] > -2) {
34650 sigma = 4.5;
34651 eta2 = -4.5;
34652 eta3 = 4.5;
34653 }
34654
34655 const MFloat sigma_Inflow = sigma;
34656 const MFloat sigma_Outflow = sigma;
34657
34658 // literature values:
34659 // for stationary variable: +-0.278
34660 // for instationary values: 3-5
34661 // for outflow when coupled with inflow: sigma_Outflow = 0
34662
34663 MFloat tmp[2 * nDim];
34664 m_solver->m_geometry->getBoundingBox(tmp); // xmin, ymin, zmin, xmax, ymax, zmax
34665 // full domain-size!
34666 MFloat LN = (tmp[dimN + nDim] - tmp[dimN]);
34667
34668 if(LN < m_solver->m_eps || std::isnan(LN)) {
34669 m_solver->m_geometry->getBoundingBoxMB(tmp);
34670 LN = (tmp[dimN + nDim] - tmp[dimN]);
34671 }
34672 // reduce LN at outflow (possibly only when the valve is closed!)
34673 if(dirN % 2 == 0) {
34674 LN = LN / 2;
34675 } else {
34676 }
34677 // for closed vales the value should be halfed => sigma doubled!
34678
34679 //---
34680
34681 MFloat massflux = F0;
34682 MFloat M_max = MFloatEps;
34683 MFloat M_mean = F0;
34684 MFloat T_mean = F0;
34685 MFloat rho_mean = F0;
34686 MFloat rho_max = F0;
34687 MFloat rho_min = 99;
34688
34689 MFloat massflux_pos = F0;
34690 MFloat massflux_neg = F0;
34691 MFloat area_pos = F0;
34692 MFloat area_neg = F0;
34693
34694 // first: compute maximum and average mach number over boundary surface
34695 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
34696 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
34697
34698 if(m_solver->a_isHalo(cellId)) continue;
34699 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
34700 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
34701
34702 const MInt bndryId = m_solver->a_bndryId(cellId);
34703 MFloat area = -1;
34704 if(bndryId > -1) {
34705 // identify the "boundary surface" between cutoff boundary cell and neighboring layer cell if cell is a boundary
34706 // cell
34707 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
34708 if(srfcId > -1) {
34709 area = m_solver->a_surfaceArea(srfcId);
34710 ASSERT(area <= POW2(m_solver->c_cellLengthAtCell(cellId)), "");
34711
34712 } else {
34713 for(MInt dir = 0; dir < m_noDirs; dir++) {
34714 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dir];
34715 if(srfcId > -1) break;
34716 }
34717 if(srfcId == -1) {
34718 mTerm(1, AT_, "something went wrong!");
34719 }
34720 area = m_solver->a_surfaceArea(srfcId);
34721 }
34722 } else {
34723 area = POW2(m_solver->c_cellLengthAtCell(cellId));
34724 }
34725
34726 ASSERT(area > 0, "");
34727
34728 // recompute area
34729 if(dirNormal[0] > -2) {
34730 area = area * dirTangent[1];
34731 }
34732
34733 // NOTE: update primary Variables for all used cutOff cells!
34734 m_solver->setPrimitiveVariables(cellId);
34735
34736 // cell properties and cell normal velocity
34737 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
34738 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
34739 const MFloat T = sysEqn().temperature_ES(rho, p);
34740 const MFloat a = sysEqn().speedOfSound(T);
34741
34742 MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
34743 // recompute un
34744 if(dirNormal[0] > -2) {
34745 un = 0;
34746 for(MInt n = 0; n < nDim; n++) {
34747 un += m_solver->a_pvariable(cellId, PV->VV[n]) * dirNormal[n];
34748 }
34749 }
34750
34751 const MFloat M = fabs(un) / a;
34752
34753 // get and neighbor normal velocity
34754 MFloat un_N = 0;
34755 MFloat T_N = 1;
34756 if(m_solver->checkNeighborActive(cellId, dirN) && m_solver->a_hasNeighbor(cellId, dirN)) {
34757 const MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
34758
34759 if(dirNormal[0] > -2) {
34760 for(MInt n = 0; n < nDim; n++) {
34761 un_N += m_solver->a_variable(nghbrN, CV->RHO_VV[n]) / m_solver->a_variable(nghbrN, CV->RHO) * dirNormal[n];
34762 }
34763 } else {
34764 un_N = m_solver->a_variable(nghbrN, CV->RHO_VV[dimN]) / m_solver->a_variable(nghbrN, CV->RHO);
34765 }
34766
34767 if(std::isnan(un_N)) {
34768 cerr << "NAN detected in cutOff-Neighbor! " << endl;
34769 }
34770
34771 T_N = sysEqn().temperature_ES(m_solver->a_variable(nghbrN, CV->RHO), m_solver->a_pvariable(nghbrN, PV->P));
34772 }
34773
34774 if(rho < F0 || std::isnan(rho) || std::isnan(un)) {
34775 cerr << "NAN detected in cutOff-Cell " << m_solver->c_globalId(cellId) << " " << m_solver->a_isHalo(cellId) << " "
34776 << m_solver->a_bndryId(cellId) << " " << rho << " " << bcId << endl;
34777 }
34778
34779 if(un_N > F0) {
34780 massflux_pos += un_N * area;
34781 area_pos += area;
34782 } else {
34783 massflux_neg += un_N * area;
34784 area_neg += area;
34785 }
34786
34787 M_max = mMax(M_max, M);
34788 M_mean += fabs(M) * area;
34789 // NOTE: intentionally without density!
34790 massflux += un_N * area;
34791 T_mean += T_N * area;
34792 rho_mean += rho * area;
34793 rho_min = mMin(rho, rho_min);
34794 rho_max = mMax(rho, rho_max);
34795 }
34796
34797 if(noDomains() > 1) {
34798 const MInt noExchangeData = 8;
34799 MFloatScratchSpace comm_buff(noExchangeData, AT_, "comm_buff");
34800
34801 comm_buff[0] = massflux;
34802 comm_buff[1] = M_mean;
34803 comm_buff[2] = T_mean;
34804 comm_buff[3] = massflux_pos;
34805 comm_buff[4] = massflux_neg;
34806 comm_buff[5] = rho_mean;
34807 comm_buff[6] = area_pos;
34808 comm_buff[7] = area_neg;
34809
34810 if(noDomains() > 1) {
34811 MPI_Allreduce(MPI_IN_PLACE, &comm_buff[0], noExchangeData, MPI_DOUBLE, MPI_SUM,
34812 m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_, "MPI_IN_PLACE", "comm_buff[0]");
34813 MPI_Allreduce(MPI_IN_PLACE, &M_max, 1, MPI_DOUBLE, MPI_MAX, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
34814 "MPI_IN_PLACE", "M_max");
34815 MPI_Allreduce(MPI_IN_PLACE, &rho_max, 1, MPI_DOUBLE, MPI_MAX, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
34816 "MPI_IN_PLACE", "rho_max");
34817 MPI_Allreduce(MPI_IN_PLACE, &rho_min, 1, MPI_DOUBLE, MPI_MIN, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
34818 "MPI_IN_PLACE", "rho_min");
34819 }
34820
34821 massflux = comm_buff[0];
34822 M_mean = comm_buff[1];
34823 T_mean = comm_buff[2];
34824 massflux_pos = comm_buff[3];
34825 massflux_neg = comm_buff[4];
34826 rho_mean = comm_buff[5];
34827 area_pos = comm_buff[6];
34828 area_neg = comm_buff[7];
34829 }
34830
34831 M_mean /= inflowArea;
34832 T_mean /= inflowArea;
34833 rho_mean /= inflowArea;
34834 const MFloat p_mean = sysEqn().pressure_ES(T_mean, rho_mean);
34835
34836 // originally claudias version, with slight error!
34837 // MFloat T_out = 1 - gammaMinusOne * F1B2 *
34838 // (massflux * massflux / inflowArea / inflowArea);
34839
34840 // isentropic acceleration from T0/p0 to the area averaged Ma-number in the plane
34841 // of the domain next to the bndry!
34842 MFloat T_out = sysEqn().temperature_IR(massflux / inflowArea);
34843 MFloat p_out = sysEqn().pressure_IR(T_out);
34844
34845 // limiting isentropically calculated temperature and pressure
34846 // for any inconsistencies/errors!
34847 if(p_out / sysEqn().p_Ref() > 1) p_out = sysEqn().p_Ref();
34848 if(T_out > 1) T_out = 1;
34849 // const MFloat deltaPLoss = 0.0588;
34850
34851 const MFloat p_target = p_out;
34852 MFloat T_target = T_out;
34853 if(dirN % 2 == 0) {
34854 T_target = T_mean; // exhaust side
34855 }
34856
34857 // other available options:
34858 // T_target = T_mix, T_out, T_mean
34859 // p_target = p_out, p_out-deltaPLoss, 1/gamma
34860
34861 if(/*globalTimeStep % 10 == 0 && */ m_solver->m_RKStep == 0 && domainId() == domainMin) {
34862 cerr << globalTimeStep << " " << bcId << " " << (dirN % 2)
34863 << " M_mean, M_max, T_target, p_target, rho_mean, massflux, T_mean, rho_min, rho_max" << setprecision(9)
34864 << M_mean << ", " << M_max << ", " << T_target << ", " << p_target << ", " << rho_mean << ", " << rho_min
34865 << ", " << rho_max << ", " << massflux << " " << T_mean << endl;
34866 // check engine inflow
34867 if(dirN % 2 == 1 && globalTimeStep % 10 == 0) {
34868 const MFloat flux = massflux / inflowArea;
34869 const MFloat flux_pos = area_pos > 0 ? massflux_pos / area_pos : F0;
34870 const MFloat flux_neg = area_neg > 0 ? massflux_neg / area_neg : F0;
34871 cerr << "Mean flux " << flux << " positive flux " << flux_pos << " negative flux " << flux_neg << endl;
34872 }
34873 }
34874
34875 ASSERT(!std::isnan(massflux), "ERROR: Mass-flux is nan!");
34876
34877 // debug!
34878 // limit M_max to 0.3!
34879 // M_max = mMin(M_max, 0.3);
34880
34881 MFloat pTotal = F0;
34882 MInt noInflowCells = 0;
34883 MInt totalNoCutOffCell = 0;
34884
34885 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
34886 const MInt cellId = m_sortedCutOffCells[bcId]->a[id];
34887
34888 if(m_solver->a_isHalo(cellId)) continue;
34889 if(!m_solver->a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
34890 if(m_solver->a_hasProperty(cellId, SolverCell::IsInactive)) continue;
34891
34892 // get the velocity from the next inward neighbor!
34893 MFloat un_N = 0;
34894 MFloat ut_N = 0;
34895 MFloat ut2_N = 0;
34896 MFloat un_N2 = 0;
34897
34898 // check neighbor active!
34899 if(m_solver->checkNeighborActive(cellId, dirN) && m_solver->a_hasNeighbor(cellId, dirN)) {
34900 const MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
34901
34902 if(dirNormal[0] > -2) {
34903 for(MInt n = 0; n < nDim; n++) {
34904 un_N += m_solver->a_variable(nghbrN, CV->RHO_VV[n]) * dirNormal[n];
34905 ut_N += m_solver->a_variable(nghbrN, CV->RHO_VV[n]) * dirTangent[n];
34906 }
34907 ut2_N = m_solver->a_variable(nghbrN, CV->RHO_VV[dimT2]);
34908
34909 } else {
34910 un_N = m_solver->a_variable(nghbrN, CV->RHO_VV[dimN]);
34911 ut_N = m_solver->a_variable(nghbrN, CV->RHO_VV[dimT1]);
34912 ut2_N = m_solver->a_variable(nghbrN, CV->RHO_VV[dimT2]);
34913 }
34914 // inflow/outflow switch based on cartesian velocity!
34915 un_N2 = m_solver->a_variable(nghbrN, CV->RHO_VV[dimN]);
34916 // if the cell is a bndryCell, always apply inflow-cbc
34917 // this is wokring for TINA, but not for the diaginal inflow!
34918 // in this case the intake flux needs to be reduced for
34919 // bndry-cells for 0 < cad < 183!
34920 // see special inflow treatment below!
34921 // if(m_solver->a_bndryId(cellId) > -1 ) {
34922 // un_N2 = 0;
34923 //}
34924 }
34925 // at corners, where no neighbor exists (u_N = 0 => inflow-cbc)
34926
34927 const MFloat p = m_solver->a_pvariable(cellId, PV->P);
34928 const MFloat rho = m_solver->a_pvariable(cellId, PV->RHO);
34929 const MFloat T = sysEqn().temperature_ES(rho, p);
34930 const MFloat a = sysEqn().speedOfSound(T);
34931
34932 MFloat un = m_solver->a_pvariable(cellId, PV->VV[dimN]);
34933 MFloat ut1 = m_solver->a_pvariable(cellId, PV->VV[dimT1]);
34934
34935 MFloat dpdn = m_solver->a_slope(cellId, PV->P, dimN);
34936 MFloat dpdt1 = m_solver->a_slope(cellId, PV->P, dimT1);
34937
34938 MFloat drhodn = m_solver->a_slope(cellId, PV->RHO, dimN);
34939 MFloat drhodt1 = m_solver->a_slope(cellId, PV->RHO, dimT1);
34940
34941 MFloat dundn = m_solver->a_slope(cellId, PV->VV[dimN], dimN);
34942 MFloat dundt1 = m_solver->a_slope(cellId, PV->VV[dimN], dimT1);
34943
34944 MFloat dut1dn = m_solver->a_slope(cellId, PV->VV[dimT1], dimN);
34945 MFloat dut1dt1 = m_solver->a_slope(cellId, PV->VV[dimT1], dimT1);
34946
34947 const MFloat ut2 = m_solver->a_pvariable(cellId, PV->VV[dimT2]);
34948
34949 MFloat dpdt2 = m_solver->a_slope(cellId, PV->P, dimT2);
34950 MFloat drhodt2 = m_solver->a_slope(cellId, PV->RHO, dimT2);
34951 MFloat dut2dt2 = m_solver->a_slope(cellId, PV->VV[dimT2], dimT2);
34952
34953 MFloat dut2dn = m_solver->a_slope(cellId, PV->VV[dimT2], dimN);
34954
34955 MFloat dundt2 = m_solver->a_slope(cellId, PV->VV[dimN], dimT2);
34956 MFloat dut1dt2 = m_solver->a_slope(cellId, PV->VV[dimT1], dimT2);
34957
34958 MFloat dut2dt1 = m_solver->a_slope(cellId, PV->VV[dimT2], dimT1);
34959
34960
34961 // correction when the flow normal does not align with the cartesian normals!
34962 // =>re-compute slopes!
34963 if(dirNormal[0] > -2) {
34964 un = 0;
34965 ut1 = 0;
34966 dpdn = 0;
34967 drhodn = 0;
34968 dpdt1 = 0;
34969 drhodt1 = 0;
34970 dundn = 0;
34971 dut1dn = 0;
34972 dundt1 = 0;
34973 dut1dt1 = 0;
34974
34975 dut2dt1 = 0;
34976 dut2dn = 0;
34977
34978 for(MInt n = 0; n < nDim; n++) {
34979 un += m_solver->a_pvariable(cellId, PV->VV[n]) * dirNormal[n];
34980 ut1 += m_solver->a_pvariable(cellId, PV->VV[n]) * dirTangent[n];
34981 }
34982
34983 // compute slopes in normal-direction, but use the slopes from inside-cells when possible!
34984 if(m_solver->checkNeighborActive(cellId, dirN) && m_solver->a_hasNeighbor(cellId, dirN)) {
34985 const MInt nghbrN = m_solver->c_neighborId(cellId, dirN);
34986
34987 dpdn = m_solver->a_slope(cellId, PV->P, dimN) * dirNormal[dimN];
34988 drhodn = m_solver->a_slope(cellId, PV->RHO, dimN) * dirNormal[dimN];
34989 dundn = m_solver->a_slope(cellId, PV->VV[dimN], dimN) * dirNormal[dimN];
34990 dut1dn = m_solver->a_slope(cellId, PV->VV[dimT1], dimN) * dirNormal[dimN];
34991 dut2dn += m_solver->a_slope(cellId, PV->VV[dimT2], dimN) * dirNormal[dimN];
34992
34993 for(MInt n = 0; n < nDim; n++) {
34994 if(n == dimN) continue;
34995 un += m_solver->a_pvariable(nghbrN, PV->VV[n]) * dirNormal[n];
34996 dpdn += m_solver->a_slope(nghbrN, PV->P, n) * dirNormal[n];
34997 drhodn += m_solver->a_slope(nghbrN, PV->RHO, n) * dirNormal[n];
34998 dundn += m_solver->a_slope(nghbrN, PV->VV[dimN], n) * dirNormal[n];
34999 dut1dn += m_solver->a_slope(nghbrN, PV->VV[dimT1], n) * dirNormal[n];
35000 dut2dn += m_solver->a_slope(nghbrN, PV->VV[dimT2], n) * dirNormal[n];
35001 }
35002
35003 } else {
35004 for(MInt n = 0; n < nDim; n++) {
35005 dpdn += m_solver->a_slope(cellId, PV->P, n) * dirNormal[n];
35006 drhodn += m_solver->a_slope(cellId, PV->RHO, n) * dirNormal[n];
35007
35008 dpdt1 += m_solver->a_slope(cellId, PV->P, n) * dirTangent[n];
35009 drhodt1 += m_solver->a_slope(cellId, PV->RHO, n) * dirTangent[n];
35010
35011 dundn += m_solver->a_slope(cellId, PV->VV[dimN], n) * dirNormal[n];
35012 dut1dn += m_solver->a_slope(cellId, PV->VV[dimT1], n) * dirNormal[n];
35013
35014 dundt1 += m_solver->a_slope(cellId, PV->VV[dimN], n) * dirTangent[n];
35015 dut1dt1 += m_solver->a_slope(cellId, PV->VV[dimT1], n) * dirTangent[n];
35016
35017 dut2dn += m_solver->a_slope(cellId, PV->VV[dimT2], n) * dirNormal[n];
35018 dut2dt1 += m_solver->a_slope(cellId, PV->VV[dimT2], n) * dirTangent[n];
35019 }
35020 }
35021 }
35022
35023 MBool upperBndry = false;
35024 for(MInt n = m_solver->a_noReconstructionNeighbors(cellId); n--;) {
35025 MInt recNghbr = m_solver->a_reconstructionNeighborId(cellId, n);
35026 if(m_solver->a_isBndryGhostCell(recNghbr)
35027 //|| m_bndryCellIds->a[recNghbr] > -1)
35029 // that the inflow does not align with the tube!
35030 ) {
35031 upperBndry = true;
35032 break;
35033 }
35034 }
35035
35036 MFloat Sum_u = un * un + ut1 * ut1;
35037
35038
35039 Sum_u = Sum_u + ut2 * ut2;
35040
35041
35042 const MFloat E = sysEqn().internalEnergy(p, rho, Sum_u);
35043
35044 MFloat Sum_du = un * dundt1 + ut1 * dut1dt1;
35045 Sum_du = Sum_du + ut2 * dut2dt1;
35046
35047 MFloat dEdt1 = sysEqn().cp_Ref() * (F1 / rho * dpdt1 - p / POW2(rho) * drhodt1) + (Sum_du);
35048 MFloat dEdt2 = sysEqn().cp_Ref() * (F1 / rho * dpdt2 - p / POW2(rho) * drhodt2)
35049 + (un * dundt2 + ut1 * dut1dt2 + ut2 * dut2dt2);
35050
35051 // compute engine pressure loss statistics:
35052 if(globalTimeStep % 10 == 0 && m_solver->m_RKStep == 0) {
35053 MFloat area;
35054 const MInt bndryId = m_solver->a_bndryId(cellId);
35055 if(bndryId > -1) {
35056 // identify the "boundary surface" between cutoff boundary cell and
35057 // neighboring layer cell if cell is a boundary cell
35058 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dirN];
35059 if(srfcId > -1) {
35060 area = m_solver->a_surfaceArea(srfcId);
35061 } else {
35062 for(MInt dir = 0; dir < m_noDirs; dir++) {
35063 srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[dir];
35064 if(srfcId > -1) {
35065 break;
35066 }
35067 }
35068 if(srfcId == -1) {
35069 mTerm(1, AT_, "something went wrong!");
35070 }
35071 area = m_solver->a_surfaceArea(srfcId);
35072 }
35073 } else {
35074 area = POW2(m_solver->c_cellLengthAtCell(cellId));
35075 }
35076
35077 // recompute area
35078 if(dirNormal[0] > -2) {
35079 area = area * dirTangent[1];
35080 }
35081
35082 pTotal += area * (p / sysEqn().p_Ref() + F1B2 * rho * sqrt(Sum_u));
35083 }
35084
35085 // compute all Ls using the one-sided dervatives given above
35086 const MFloat lambda1 = (un - a);
35087 const MFloat lambda2 = un;
35088 const MFloat lambda5 = (un + a);
35089 MFloat L1 = lambda1 * (dpdn - rho * a * dundn);
35090 MFloat L2 = lambda2 * (a * a * drhodn - dpdn);
35091 MFloat L3 = lambda2 * (dut1dn);
35092 MFloat L5 = lambda5 * (dpdn + rho * a * dundn);
35093 MFloat L4 = lambda2 * (dut2dn);
35094
35095 // tangential correction terms
35096 MFloat T1 = -rho * (dut1dt1)-ut1 * drhodt1;
35097 MFloat T2 = -ut1 * dundt1;
35098 MFloat T3 = -ut1 * dut1dt1 - F1 / rho * dpdt1;
35099 MFloat T5 = -ut1 * dpdt1 - p / sysEqn().p_Ref() * dut1dt1;
35100
35101 T1 += -rho * dut2dt2 - ut2 * drhodt2;
35102 T2 += -ut2 * dundt2;
35103 T3 += -ut2 * dut1dt2;
35104 MFloat T4 = -ut1 * dut2dt1 - ut2 * dut2dt2 - F1 / rho * dpdt2;
35105 T5 += -ut2 * dpdt2 - p / sysEqn().p_Ref() * dut2dt2;
35106
35107
35108 // eddy detection:
35109 const MFloat eddy = (POW2(ut_N) + POW2(ut2_N)) / POW2(un_N);
35110
35111 /*
35112 MBool nearBndry = false;
35113 if(m_solver->a_bndryId(cellId) > -1 ) {
35114 nearBndry = true;
35115 } else {
35116 for(MInt idN = 0; idN < m_solver->a_noReconstructionNeighbors(cellId); idN++) {
35117 MInt recNghbr = m_solver->a_reconstructionNeighborId(cellId, idN);
35118 if(m_bndryCellIds->a[recNghbr] > -1){
35119 nearBndry = true;
35120 break;
35121 }
35122 }
35123 }
35124 */
35125
35126 if(dirNormal[0] > -2 /*|| nearBndry */ || !transversal) {
35127 T1 = 0;
35128 T2 = 0;
35129 T3 = 0;
35130 T5 = 0;
35131 T4 = 0;
35132 }
35133
35134 MBool isInflow = true;
35135 totalNoCutOffCell++;
35136
35137 if(dirN % 2 == 0) {
35138 if(un_N2 > F0) {
35139 isInflow = false;
35140 }
35141 } else {
35142 if(un_N2 < F0) {
35143 isInflow = false;
35144 }
35145 }
35146
35147 if(isInflow) { // inflow
35148
35149 noInflowCells++;
35150
35151 // damping coefficients
35152 const MFloat K1 = sigma_Inflow * a * (1 - M_max * M_max) / LN;
35153 const MFloat K2 = eta2 * rho * a / LN;
35154 const MFloat K3 = eta3 * a / LN;
35155
35156 if(dirN % 2 == 0) { // inflow on pos. coordinate direction (right) -> un < 0
35157 L1 = K1 * (p - p_target) + (T5 - rho * a * T2);
35158 } else { // inflow on neg. coordinate direction (left) -> un > 0
35159 L5 = K1 * (p - p_target) + (T5 + rho * a * T2);
35160 }
35161 L2 = K2 * (T - T_target) + (a * a * T1 - T5);
35162 L3 = K3 * ut1 + T3;
35163 L4 = K3 * ut2 + T4;
35164
35165 MBool limitVariable = false;
35166 if(m_solver->a_pvariable(cellId, PV->RHO) > 1.0000001) {
35167 m_solver->a_pvariable(cellId, PV->RHO) = 1;
35168 limitVariable = true;
35169 }
35170 if(m_solver->a_pvariable(cellId, PV->P) / sysEqn().p_Ref() > 1.0000001) {
35171 m_solver->a_pvariable(cellId, PV->P) = sysEqn().p_Ref();
35172 limitVariable = true;
35173 }
35174
35175 if(limitVariable) {
35176 m_solver->setConservativeVariables(cellId);
35177 }
35178
35179 } else { // outflow
35180
35181 MFloat K1 = sigma_Outflow * a * (1 - M_max * M_max) / LN;
35182 const MFloat beta = M_mean;
35183 // possibly set beta to zero, which increases transversal damping!
35184
35185 // const MFloat K3 = eta3 * a / LN;
35186
35187 // eddy correction as non-reflecting!
35188 if(eddy > 1) {
35189 // TODO: update testcase to new version!
35190 if(!m_solver->m_engineSetup) {
35191 K1 = 0;
35192 } else {
35193 // update: only set K1 to zero for considerable mass-flux through the
35194 // boundary!
35195 // if(fabs(massflux) > 0.05 ) {
35196 if(fabs(un_N2) > 0.05 && fabs(massflux) > 0.05) {
35197 K1 = 0;
35198 } else {
35199 // surpress fluctuations in transversal velocities (sponging)
35200 // const MFloat K3 = eta3 * a / LN;
35201 // possibly to large, when eta3 is already increased at the inflow-side!
35202 // const MFloat K3 = (dirN % 2 == 0 ) ? eta3 * 10 * a / LN : eta3 * a / LN;
35203 const MFloat K3 = eta3 * a * 10 / LN;
35204 L3 = K3 * ut1 + T3;
35205 L4 = K3 * ut2 + T4;
35206 }
35207 }
35208 }
35209
35210
35211 // correct L1/L5 (depends on outflow direction) by boundary condition
35212 if(dirN % 2 == 0) {
35213 // outflow on pos. coordinate direction -> L1 has to be modeled
35214 L1 = K1 * (p - p_target) + (F1 - beta) * (T5 - rho * a * T2);
35215 } else { // outflow on neg. coordinate direction -> L5 has to be modeled
35216 L5 = K1 * (p - p_target) + (F1 - beta) * (T5 + rho * a * T2);
35217 }
35218
35219 // instead of the L1 prescription at engine outflow with large eddies
35220 // L2 is presribed with T_target interpolated from the domain!
35221 MBool walllike = false;
35222 if(eddy > 1 && dirN % 2 == 0) walllike = true;
35223 // if global and local velocities are low, set additional sponge on
35224 // density/temperature to stabilise the inflow!
35225 if(fabs(un_N2) < 0.005 /*&& fabs(massflux) < 0.005*/) {
35226 walllike = true;
35227 }
35228
35229 // prescribe additioan L2 amplitude just as for a wall
35230 if(walllike && m_solver->m_engineSetup) {
35231 const MFloat K2_outflow = -sigma * rho * a / LN;
35232 L2 = K2_outflow * (T - T_target) + (a * a * T1 - T5);
35233 // from time to time necessary to resolve problems at the exhaust-outflow!
35234 if(dirN % 2 == 0 && eddy < 1) {
35235 const MFloat K3 = eta3 * a / LN;
35236 L3 = K3 * ut1 + T3;
35237 L4 = K3 * ut2 + T4;
35238 }
35239 }
35240 }
35241
35242 // if(m_solver->crankAngle(m_solver->m_physicalTime,0) < 185 &&
35243 // m_solver->a_pvariable(cellId, PV->U) < 0 ) {
35244
35245 // if(abs(m_solver->a_pvariable(cellId, PV->W)) > 0.005 &&
35246 // m_solver->crankAngle(m_solver->m_physicalTime,0) < 170
35247 // && m_solver->a_coordinate(cellId ,0) < 0
35248 // ) {
35249 if((abs(m_solver->a_pvariable(cellId, PV->W)) > 0.005 || abs(m_solver->a_pvariable(cellId, PV->U)) > 0.3)
35250 && m_solver->crankAngle(m_solver->m_physicalTime, 0) > 240) {
35251 // globalTimeStep > 1443600 && globalTimeStep < 1444000 ) {
35252 // globalTimeStep > 1474000 ) {
35253
35254 if(globalTimeStep % 10 == 0 && m_solver->m_RKStep == 0) {
35255 cerr << "Limiting-cell " << m_solver->a_coordinate(cellId, 1) << " " << m_solver->a_coordinate(cellId, nDim - 1)
35256 << " " << upperBndry << " " << m_solver->a_pvariable(cellId, PV->U) << endl;
35257 }
35258
35259
35260 m_solver->a_pvariable(cellId, PV->P) = 0.71428;
35261 m_solver->a_pvariable(cellId, PV->RHO) = 1;
35262 m_solver->a_pvariable(cellId, PV->VV[2]) = 0;
35263 m_solver->a_pvariable(cellId, PV->VV[0]) = 0.01 * dirNormal[0];
35264 m_solver->a_pvariable(cellId, PV->VV[1]) = 0.01 * dirNormal[1];
35265
35266 L1 = 0;
35267 L2 = 0;
35268 L3 = 0;
35269 L4 = 0;
35270 L5 = 0;
35271
35272 m_solver->setConservativeVariables(cellId);
35273 }
35274
35275 if(abs(m_solver->a_pvariable(cellId, PV->W)) > 0.005) {
35276 m_solver->a_pvariable(cellId, PV->P) = p_mean;
35277 m_solver->a_pvariable(cellId, PV->RHO) = rho_mean;
35278 m_solver->a_pvariable(cellId, PV->VV[2]) = 0;
35279 if(m_solver->crankAngle(m_solver->m_physicalTime, 0) < 170) {
35280 m_solver->a_pvariable(cellId, PV->VV[0]) = 0.01 * dirNormal[0];
35281 m_solver->a_pvariable(cellId, PV->VV[1]) = 0.01 * dirNormal[1];
35282 }
35283
35284 L1 = 0;
35285 L2 = 0;
35286 L3 = 0;
35287 L4 = 0;
35288 L5 = 0;
35289 if(globalTimeStep % 10 == 0 && m_solver->m_RKStep == 0) {
35290 cerr << "Limiting-cell " << m_solver->a_coordinate(cellId, 1) << " " << m_solver->a_coordinate(cellId, nDim - 1)
35291 << " " << upperBndry << endl;
35292 }
35293 m_solver->setConservativeVariables(cellId);
35294 }
35295
35296
35297 // stronger wall affect
35298 // treated as normal inflow with dirNormal[1] = 0!
35299 if(upperBndry && dirNormal[0] > -2) {
35300 // wall bndry-cnd or also stationary subsonic inflow
35301 if(/*m_solver->crankAngle(m_solver->m_physicalTime,0) < 185 && */ isInflow) {
35302 if(dirN % 2 == 0) {
35303 L1 = L5;
35304 } else {
35305 L5 = L1;
35306 }
35307 } else {
35308 // stationary reflecting subsonic outflow! (not working!)
35309 /*
35310 if(m_solver->crankAngle(m_solver->m_physicalTime,0) > 191) {
35311 if(dirN % 2 == 0) {
35312 L1 = -L5;
35313 } else {
35314 L5 = -L1;
35315 }
35316 }
35317 */
35318 /*
35319 if(m_solver->crankAngle(m_solver->m_physicalTime,0) < 110 ) {
35320 m_solver->a_pvariable(cellId, PV->U) = 0.0001;
35321 m_solver->a_pvariable(cellId, PV->V) = 0;
35322 m_solver->a_pvariable(cellId, PV->W) = 0;
35323 m_solver->a_pvariable(cellId, PV->RHO) = 1;
35324 m_solver->a_pvariable(cellId, PV->P) = 0.71428;
35325
35326 m_solver->setConservativeVariables(cellId);
35327
35328 }
35329 */
35330
35331 // stronger sponge towards zero tangential/wall-normal velocity
35332 const MFloat K3 = sigma * a / LN;
35333 L3 = K3 * ut1 + T3;
35334 L4 = K3 * ut2 + T4;
35335
35336 // stronger sponging towards stagnation temperature
35337 const MFloat K2_outflow = -sigma * rho * a / LN;
35338 L2 = K2_outflow * (T - T_target) + (a * a * T1 - T5);
35339 }
35340 // also prescribe L1/L5 based on zero velocity instead of pressure
35341 // nice try, but diverging quickly!
35342 /*
35343 const MFloat K1 = sigma_Outflow * a * (1 - M_max * M_max) / LN * a * rho;
35344 if(dirN % 2 == 0) {
35345 L1 = K1 * un_N;
35346 } else {
35347 L5 = K1 * un_N;
35348 }
35349 */
35350 // reduced order of slopes increase order of sponging instead!
35351 // This is definitely contra-productive!
35352 /*
35353 if(dirN % 2 == 0) {
35354 //L5 = lambda5 * (dpdn + rho * a * dundn);
35355 L5 = L5 /100;
35356 L1 = L1 * 10;
35357 } else {
35358 //L1 = lambda1 * (dpdn - rho * a * dundn);
35359 L1 = L1 /100;
35360 L5 = L5 * 10;
35361 }
35362 */
35363 }
35364
35365 /*
35366 if(abs(m_solver->a_pvariable(cellId, PV->W) > 0.015) ||
35367 m_solver->a_pvariable(cellId, PV->RHO) > 1 ) {
35368 m_solver->a_pvariable(cellId, PV->U) = 0.1;
35369 m_solver->a_pvariable(cellId, PV->V) = -0.0512;
35370 m_solver->a_pvariable(cellId, PV->W) = 0;
35371 m_solver->a_pvariable(cellId, PV->RHO) = 0.9924;
35372 m_solver->a_pvariable(cellId, PV->P) = 0.710;
35373
35374 m_solver->setConservativeVariables(cellId);
35375 L1 = 0;
35376 L2 = 0;
35377 L3 = 0;
35378 L4 = 0;
35379 L5 = 0;
35380
35381 }
35382 */
35383
35384
35385 MFloat d1 = F1 / (a * a) * (L2 + F1B2 * (L5 + L1));
35386 MFloat d2 = F1B2 * (L5 + L1);
35387 MFloat d3 = F1B2 / (rho * a) * (L5 - L1);
35388 MFloat d4 = L3;
35389
35390 MFloat d5 = L4;
35391
35392 // correct ds for normlar vectors
35393 if(dirNormal[0] > -2) {
35394 d1 = dirNormal[0] * F1 / (a * a) * L2 + dirNormal[1] * L4 - dirNormal[2] * L3 + F1B2 * F1 / (a * a) * (L5 + L1);
35395 // d2 = d2 no correction necessary in d2!
35396 const MFloat d3_old = d3;
35397 d3 = dirNormal[0] * d3_old - dirNormal[2] * L4 - dirNormal[1] * L3;
35398 d4 = dirNormal[0] * L3 + dirNormal[1] * d3_old + dirNormal[2] * F1 / (a * a) * L2;
35399 d5 = dirNormal[0] * L4 + dirNormal[2] * d3_old - dirNormal[1] * F1 / (a * a) * L2;
35400 }
35401
35402 // compute corrected RHS for cut off cell:
35403 MFloat rhs_rho = -d1 - rho * (dut1dt1)-ut1 * drhodt1;
35404
35405 MFloat rhs_rhoun = -un * d1 - rho * (d3 + un * dut1dt1 + ut1 * dundt1) - un * (ut1 * drhodt1);
35406
35407 MFloat rhs_rhout1 = -ut1 * d1 - rho * (d4 + F2 * ut1 * dut1dt1) - ut1 * (ut1 * drhodt1) - dpdt1;
35408
35409 MFloat rhs_rhoe = -F1B2 * (POW2(un) + POW2(ut1)) * d1 - d2 * sysEqn().cp_Ref() - rho * (un * d3 + ut1 * d4)
35410 - ut1 * (rho * dEdt1 + E * drhodt1 + dpdt1) - (rho * E + p) * dut1dt1;
35411
35412 rhs_rho += -rho * dut2dt2 - ut2 * drhodt2;
35413
35414
35415 rhs_rhoun += -rho * (un * dut2dt2 + ut2 * dundt2) - un * ut2 * drhodt2;
35416
35417
35418 rhs_rhout1 += -rho * (ut1 * dut2dt2 + ut2 * dut1dt2) - ut1 * ut2 * drhodt2;
35419
35420
35421 MFloat rhs_rhout2 = -ut2 * d1 - rho * (d5 + ut2 * dut1dt1 + ut1 * dut2dt1 + F2 * ut2 * dut2dt2)
35422 - ut2 * (ut1 * drhodt1 + ut2 * drhodt2) - dpdt2;
35423
35424
35425 rhs_rhoe +=
35426 -F1B2 * (POW2(ut2)) * d1 - rho * ut2 * d5 - ut2 * (rho * dEdt2 + E * drhodt2 + dpdt2) - (rho * E + p) * dut2dt2;
35427
35428
35429 // compute rightHandside without transversal terms!
35430 if(dirNormal[0] > -2 /*|| nearBndry */ || !transversal) {
35431 rhs_rho = -d1;
35432 rhs_rhoun = -un * d1 - rho * d3;
35433 rhs_rhout1 = -ut1 * d1 - rho * d4;
35434 rhs_rhoe = -F1B2 * (POW2(un) + POW2(ut1)) * d1 - d2 * sysEqn().cp_Ref() - rho * (un * d3 + ut1 * d4);
35435 rhs_rhout2 = -ut2 * d1 - rho * d5;
35436 rhs_rhoe += -F1B2 * POW2(ut2) * d1 - rho * ut2 * d5;
35437 }
35438
35439
35440 m_solver->a_rightHandSide(cellId, CV->RHO) = -m_solver->a_cellVolume(cellId) * rhs_rho;
35441 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimN]) = -m_solver->a_cellVolume(cellId) * rhs_rhoun;
35442 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT1]) = -m_solver->a_cellVolume(cellId) * rhs_rhout1;
35443 m_solver->a_rightHandSide(cellId, CV->RHO_E) = -m_solver->a_cellVolume(cellId) * rhs_rhoe;
35444 m_solver->a_rightHandSide(cellId, CV->RHO_VV[dimT2]) = -m_solver->a_cellVolume(cellId) * rhs_rhout2;
35445 }
35446
35447 if(globalTimeStep % 10 == 0 && m_solver->m_RKStep == 0) {
35448 if(noDomains() > 1) {
35449 MPI_Allreduce(MPI_IN_PLACE, &pTotal, 1, MPI_DOUBLE, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
35450 "MPI_IN_PLACE", "pTotal");
35451
35452 MPI_Allreduce(MPI_IN_PLACE, &noInflowCells, 1, MPI_INT, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
35453 "MPI_IN_PLACE", "noInflowCells");
35454
35455 MPI_Allreduce(MPI_IN_PLACE, &totalNoCutOffCell, 1, MPI_INT, MPI_SUM, m_comm_bcCo[m_bcCo_comm_pointer[bcId]], AT_,
35456 "MPI_IN_PLACE", "totalNoCutOffCell");
35457 }
35458
35459 pTotal /= inflowArea;
35460
35461 if(dirN % 2 == 0 && domainId() == domainMin) {
35462 cerr << "Average total pressure at outlet is: " << pTotal << endl;
35463 } else if(domainId() == domainMin) {
35464 cerr << "Average total pressure at inlet is: " << pTotal << endl;
35465 }
35466
35467 const MFloat ratio = (MFloat)noInflowCells / ((MFloat)totalNoCutOffCell);
35468 if(dirN % 2 == 1 && domainId() == domainMin) {
35469 cerr << "Inflow cell percentage: " << ratio << " at inlet!" << endl;
35470 } else if(domainId() == domainMin) {
35471 cerr << "Inflow cell percentage: " << ratio << " at outlet!" << endl;
35472 }
35473 }
35474}
35475
35476template <MInt nDim, class SysEqn>
35478 TRACE();
35479
35480 // Read BC data
35481 stringstream fn;
35482 fn.clear();
35483 fn << "bc30022.txt";
35484 MString fname = fn.str();
35485 if(m_solver->domainId() == 0) cerr << "loading BC data from " << fname << "...";
35486
35487 ifstream vnData;
35488 vnData.open(fname);
35489 vector<MFloat> data;
35490 MFloat num;
35491 string line;
35492
35493 while(vnData >> num) {
35494 data.push_back(num);
35495 }
35496
35497 vnData.close();
35498
35499 MInt horDataVarCount = Context::getSolverProperty<MInt>("bc30022DataCount", m_solverId, AT_, &horDataVarCount); // 14
35500 MInt horTargetDataCount = data.size() / horDataVarCount;
35501
35502 mAlloc(m_horTargetData, m_sortedCutOffCells[bcId]->size(), 3, "m_horTargetData", F0, AT_);
35503
35504 for(MInt d = 0; d < horTargetDataCount - 1; d++) {
35505 MInt index1 = horDataVarCount * d;
35506 MInt index2 = horDataVarCount * (d + 1);
35507 MFloat xTarget1 = data[index1];
35508 MFloat xTarget2 = data[index2];
35509 MFloat uTarget1 = data[index1 + 1];
35510 MFloat uTarget2 = data[index2 + 1];
35511 MFloat vTarget1 = data[index1 + 2];
35512 MFloat vTarget2 = data[index2 + 2];
35513 MFloat rhoTarget1 = data[index1 + 3];
35514 MFloat rhoTarget2 = data[index2 + 3];
35515
35516 for(MInt id = 0; id < m_sortedCutOffCells[bcId]->size(); id++) {
35517 MInt cellId = m_sortedCutOffCells[bcId]->a[id];
35518 MFloat x = m_solver->a_coordinate(cellId, 0);
35519 if(xTarget2 > x && xTarget1 <= x) {
35520 m_horTargetData[id][0] = uTarget1 + (uTarget2 - uTarget1) / (xTarget2 - xTarget1) * (x - xTarget1);
35521 m_horTargetData[id][1] = vTarget1 + (vTarget2 - vTarget1) / (xTarget2 - xTarget1) * (x - xTarget1);
35522 m_horTargetData[id][2] = rhoTarget1 + (rhoTarget2 - rhoTarget1) / (xTarget2 - xTarget1) * (x - xTarget1);
35523 }
35524 }
35525 }
35526}
MLong allocatedBytes()
Return the number of allocated bytes.
Definition: alloc.cpp:121
void mAlloc(T *&a, const MLong N, const MString &objectName, MString function)
allocates memory for one-dimensional array 'a' of size N
Definition: alloc.h:173
MBool mDeallocate(T *&a)
deallocates the memory previously allocated for element 'a'
Definition: alloc.h:544
void checkRegeneration(const MFloat time)
Bc1601Class(MPI_Comm &communicator, const MInt m_solverId, const MInt domainId, MFloat &u_total, MFloat &invSigmaSponge)
const MInt m_domainId
void generateAndCommRandomNumbers()
Bc1601Class functions:
void calculateFlucts(const MFloat that, const MFloat xhat, const MFloat yhat, const MFloat zhat, MFloat *fluctChol)
MFloat eigvec[3][3]
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
static MInt staticElementSize()
BodySurface ** m_srfcs
virtual void generateBndryCells()
generate finite-volume boundary cells
void cbc1099_1091_local_comb(MInt)
void cbc1091b_after(MInt)
Subsonic fully reflecting characteristic inflow condition - cut off - sets T0,u,v to prescribed value...
void allocateCutOffMemory()
allocates the cut off list memory
void cbcRHS(MInt, MInt, MFloat *, MFloat *, MFloat *)
Calculates the right hand side.
virtual void bc19520(MInt)
void sbc2801y(MInt)
Solid wall Navier-Stokes boundary condition Computes ghost cell slopes for the viscous flux computati...
void sbc1000co(const MInt)
Cut off condition for the slopes.
void sbc00co(const MInt)
Cut off condition for the slopes.
void computeTetra(MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
void cbc1091e_after(MInt)
Subsonic fully reflecting characteristic inflow condition - cut off - sets T0,u,v to prescribed value...
void cbc1099a_after(MInt)
Subsonic fully reflecting characteristic outflow condition - cut off - sets pstat to prescribed value...
void calcBesselFractions(const MFloat, const MFloat, const MFloat, MFloat &, MFloat &)
void plotAllCutPoints()
writes a .vtk file containing all cut points stored on the cut cells
void sbc2720co(MInt)
Cut off condition for the slopes copys the slopes, and sets pressure slope to sero NOTIMPLEMENTED ver...
void cbcDampingOutflow(MInt, MInt, MFloat, MFloat *)
Calculates the outflow damping terms.
void cbc1099_1091d_after(MInt)
void bcNeumannMb(MInt)
Moving boundary Neumann condition.
void cbc109911(MInt)
Characteristic boundary condition. Outflow. Prescribed: p. Partially Refelecting.
virtual void bc2001(MInt)
void initBesselModes(MInt)
void bcNeumannIsothermalUnburntProfileH(MInt)
Computes the p and rho slopes on boundary cells using the least-squares method and setting implicitel...
virtual void bc1801(MInt)
void sbc2001(MInt)
Solid wall Navier-Stokes boundary condition Computes ghost cell slopes for the viscous flux computati...
void bcInit2700(MInt)
init for the acoustic and entropy waves
virtual void sbc2710co(MInt)
void initSmallCellCorrection(MInt updateOnlyBndryCndId=-1)
Initialize the small-cell correction for the flux-redistribution method The cell vars are computed us...
virtual void bc1901(MInt)
void cbcViscousTerms(MInt, MInt, MFloat *, MFloat *, MFloat *, MFloat *, MInt *, MFloat *)
Calculates the outgoing viscous terms V.
void setGapGhostCellVariables(MInt bcId)
update ghostCell variables for gap-Cells
void bcInit0004(MInt)
Sets up the reconstruction stencil for boundary cells (quadratic least-squares reconstruction)
void deleteBndryCell(MInt)
Deletes a boundary cell (without collector fragmentation)
void cbcGradients(MInt, MInt, MFloat *, MFloat *, MFloat *, MFloat *)
Calculates the gradients of the cbcCell.
void cbc2099_1091_local_comb(MInt)
void bcNeumannIsothermalUnburntProfile(MInt)
Computes the p and rho slopes on boundary cells using the least-squares method and setting implicitel...
void bcNeumannIsothermalBurntProfileH(MInt)
Computes the p and rho slopes on boundary cells using the least-squares method and setting implicitel...
MFloat * vecScalarMul(MFloat, MFloat *, MFloat *)
virtual void bc2770(MInt)
virtual void bc1003(MInt)
void computeTri(MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
void cbcMeanPressureCo(MInt, MFloat *)
void detectSmallBndryCells()
Detects small cells and identifies a master cell Calls mergeCell to merge master and small cell.
void markCutOff(MIntScratchSpace &cutOffCells)
void computePlaneVectors()
uses Gram-Schmidt to compute orthonormal vectors in the cut plane
void createCutFace()
computes the geometry of each the cut cells (2D version) 2 cut points are assumed for each boundary c...
FvBndryCndXD(FvCartesianSolverXD< nDim, SysEqn > *solver)
MBool checkInside(MInt)
checks if all corners of a cell are located in the computational domain
void bcInit0002(MInt)
Sets up the reconstruction stencil for boundary cells.
void cbcTurbulenceInjection(MInt, MFloat *, MInt)
Turbulence injection (identical to bc1601) adjusted for Taylor's Hypothesis for cbc.
void computeCutPoints()
computes the cut points where a boundary cell intersects with the geometry computes the following bou...
void computeReconstructionConstants_interpolation()
void cbc1099_1091_engineOld(MInt)
void exchangeCutOffBoundaryCells()
exchanges the cut off boundary cells and adds them to the accordings cut off boundary lists
void cbcGradientsViscous(MInt, MInt, MFloat *, MFloat *, MFloat *, MFloat *, MInt *)
Calculates the viscous gradients of the cbcCell.
void correctBoundarySurfaceVariablesMGC()
corrects the left and right variables values on the boundary surface
MFloat computeCutoffBoundaryGeometry(const MInt, const MInt, MFloat *)
computes centroid and radius (return parameter) of a cut-off boundary surface assumes that the surfac...
void correctBoundarySurfaceVariablesMGCSurface()
corrects the left and right variables values on the boundary surface
void computePoly5(MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
void correctMasterSlaveSurfaces()
Removes surfaces between master-slave pairs and reassigns slave cell surfaces.
virtual void bc3037MGC(MInt)
void computeImagePointRecConst(MInt updateOnlyBndryCndId=-1)
virtual void bc2003(MInt)
virtual void bc10990(MInt)
void correctNormal(MFloat *)
void writeStlOfNodes(MInt, MInt *&, const char *)
void bc11110(MInt)
void getFeatureEdges(MInt &, MFloat **&, MInt, MInt *&, MFloat *&, MFloat *&)
void correctCell(MFloat *, MFloat *, MFloat *, MFloat *)
void computeMirrorCoordinates(MInt, MFloat *, MInt)
void addBoundarySurfacesMGC()
adds a surface for the ghost-boundary cell intersections
void cbc109921(MInt)
Characteristic boundary condition. Outflow. Prescribed: p. Partially Refelecting.
void getIntersectionPoints(MFloat **&, MFloat **&, MInt, MInt, MFloat **&, MInt &)
MFloat updateImagePointVariables(MInt)
Updates the image point variables used with multiple ghost cell formulation.
void bcNeumannIsothermal(MInt)
Computes the p and rho slopes on boundary cells using the least-squares method and setting implicitel...
void plotIntersectionPoints(MInt *, MFloat ***&)
void createCutFaceMGC()
ONLY 3D VERSIONS.
void correctFace(MFloat *, MFloat *, MFloat *, MFloat *)
void bcNeumannIsothermalBurntProfile(MInt)
Computes the p and rho slopes on boundary cells using the least-squares method and setting implicitel...
virtual void bc1401(MInt)
void correctInflowBoundary(MInt)
MFloat * vecSub(MFloat *, MFloat *, MFloat *)
void resetCutOffFirst()
reset first for cutOffBndryCnd, this is necessary after a balance!
void plotTriangle(std::ofstream &, MFloat *, MFloat *, MFloat *, MFloat *)
void cbc1091c_after(MInt)
Subsonic fully reflecting characteristic inflow condition - cut off - sets T0,u,v to prescribed value...
void checkCutPointsValidity()
checks the validity of a boundary cell
void plotEdges(MInt &, MFloat **&)
void addModes(MInt)
supersonic inflow with imposed onlique shock wave version: cut-off boundary condition author: Thomas ...
void computeNeumannLSConstants(MInt)
Sets up the reconstruction stencil for boundary cells.
void cbcTransversalTerms(MInt, MInt, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
Calculates the transversal correction terms T.
void computePoly4(MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
void plotSurface()
virtual void bc2002(MInt)
void computePoly6(MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
void detectSmallBndryCellsMGC()
Detects small cells and identifies a master cell Calls mergeCell to merge master and small cell.
MInt createSplitCell_MGC(MInt, MInt)
produces an exact copy of a fvcell and the respective boundary cell
void cbcOutgoingAmplitudeVariation(MInt, MInt, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
Calculates the outgoing terms wave amplitude variation L.
void setBCTypes(MInt updateOnlyBndryCndId=-1)
void cbcDampingInflow(MInt, MInt, MFloat, MFloat *, MString)
Calculates the inflow damping terms.
void createBndryCndHandler()
creates pointers to the boundary conditions
void checkCutPointsValidityParGeom()
checks the validity of a boundary cell using parallel geometry
void sbc2801x(MInt)
Solid wall Navier-Stokes boundary condition Computes ghost cell slopes for the viscous flux computati...
void cbc1091d_after(MInt)
Subsonic fully reflecting characteristic inflow condition - cut off - sets un to prescribed value aft...
void addBoundarySurfaces()
adds a surface for the ghost-boundary cell intersections
void cbcMachCo(MInt, MFloat *)
Returns the mean and maximum Mach number of the cut off cells.
void computePolygon(MFloat *x, const MInt N, MFloat *centroid, MFloat *area)
void setNearBoundaryRecNghbrs(MInt updateOnlyBndryCndId=-1)
virtual void bc1001coflowY(MInt)
void bcInit30022(MInt)
void bcInit1601(MInt)
Initialize bc1601.
MInt isCutOffInterface(MInt cellId)
void createBoundaryAtCutoff()
void applyNonReflectingBCAfterTreatmentCutOff()
void createSpongeAtSpongeBndryCnds()
creates Sponge Cells at spongeBndryCnds
void mergeCellsMGC()
merges master and small cells - for multiple ghost cells formulation
void resetCutOff()
reset sorterdCutOff Cells and cutOff communicator before balancing and adaptation!
void computeGhostCellsMGC()
Computes one ghost cell for each boundary surface.
void precomputeBesselTrigonometry(MInt)
void initModes(MInt)
void getSortedElements(const std::vector< MInt > &, MInt &, MInt *&, MInt &, MInt *&, MInt)
void sbc1002(MInt)
Symmetry boundary condition about x-axis (slopes)
void cbc2091b_after(MInt)
Subsonic fully reflecting characteristic inflow condition - cut off - sets T0,u,v to prescribed value...
virtual void bc1791(MInt)
virtual void writeStlFileOfCell(MInt, const MChar *)
void bcInit2770(MInt)
supersonic inflow with imposed onlique shock wave and linear waves version: cut-off boundary conditio...
void cbc2091d_after(MInt)
Subsonic fully reflecting characteristic inflow condition - cut off - sets un to prescribed value aft...
void bcInitCbc(MInt)
virtual void bc10910(MInt)
void cbc109910(MInt)
Characteristic boundary condition. Outflow. Prescribed: p. Partially Refelecting.
void cbcTauQ(MInt, MFloat *, MFloat *, MInt *)
Calculates the stress tensor tau and the heat flux q and the mean velocity on the construction stenci...
virtual void bc1005(MInt)
virtual void bc1004(MInt)
void bc1952(MInt)
Subsonic outflow boundary condition (applied directly to the (boundary) cell). Set of variables: Stan...
void initSmallCellRHSCorrection(MInt updateOnlyBndryCndId=-1)
void cutOffBcMissingNeighbor(const MInt cellId, const MString bcName)
void bcNeumannIsothermalUnburnt(MInt)
Computes the p and rho slopes on boundary cells using the least-squares method, and setting implicite...
void computeReverseMap()
Creates a mapping (boundary cell id) -> (cell id) in m_bndryCellIds.
void bcNeumann3600(MInt)
Simple and fast fixed adiabatic wall boundary condition for use with the flux-redistribution method.
void initBndryCommunications()
inits the commnicators for the boundaries
void computeTrapez(MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
void bcInit0001(MInt)
Sets up the reconstruction stencil for boundary cells.
void computePyra(MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
void computePoly3(MFloat *, MFloat *, MFloat *, MFloat *, MFloat *, MFloat *)
Collector< FvBndryCell< nDim, SysEqn > > * m_bndryCells
MPI_Comm globalMpiComm() const
Return the global MPI communicator used by the grid.
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
Definition: list.h:16
Definition: fvstg.h:609
void init(MInt commStgRoot)
Definition: fvstg.cpp:505
This class is a ScratchSpace.
Definition: scratch.h:758
size_type size() const
Definition: scratch.h:302
T * getPointer() const
Deprecated: use begin() instead!
Definition: scratch.h:316
void fill(T val)
fill the scratch with a given value
Definition: scratch.h:311
pointer p
Deprecated: use [] instead!
Definition: scratch.h:315
iterator begin()
Definition: scratch.h:273
void prepareInterpolationField(MInt *noReceiverCells, MFloat **receiverCoordinates)
Prepares interpolation for field For a given 3D coordinate field the method computes the transformed ...
void interpolateField(MString, MFloat *)
interpolates a field interpolates a given varName and varF
Checks if the primitive variable C exists.
Checks if the primitive variable N exists.
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ VTP
Definition: enums.h:18
@ NOZZLE_TC
Definition: enums.h:178
@ TINA_TC
Definition: enums.h:178
@ RANS_SA_DV
Definition: enums.h:54
@ RANS_SST
Definition: enums.h:57
@ RANS_FS
Definition: enums.h:55
@ RANS_KOMEGA
Definition: enums.h:56
@ MAIA_FINITE_VOLUME
Definition: enums.h:23
@ MAIA_STRUCTURED
Definition: enums.h:40
@ BC_ROBIN
Definition: enums.h:334
@ BC_UNSET
Definition: enums.h:334
@ BC_NEUMANN
Definition: enums.h:334
@ BC_ISOTHERMAL
Definition: enums.h:334
@ BC_DIRICHLET
Definition: enums.h:334
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW3(const Real x)
Definition: functions.h:123
constexpr Real POW2(const Real x)
Definition: functions.h:119
Real ABS(const Real x)
Definition: functions.h:85
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
double doubleSwap(double f)
Definition: functions.h:379
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
MInt globalTimeStep
void printAllocatedMemory(const MLong oldAllocatedBytes, const MString &solverName, const MPI_Comm comm)
Prints currently allocated memory.
MInt globalNoDomains()
Return global number of domains.
MBool g_multiSolverGrid
InfoOutFile m_log
std::ostream cerr0
constexpr MLong IPOW2(MInt x)
constexpr MFloat FPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
uint32_t MUint
Definition: maiatypes.h:63
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
char MChar
Definition: maiatypes.h:56
MInt id
Definition: maiatypes.h:71
int MPI_Comm_free(MPI_Comm *comm, const MString &name, const MString &varname)
same as MPI_Comm_free, but updates the number of MPI communicators
int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_create, but updates the number of MPI communicators
int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup, const MString &name)
same as MPI_Group_incl
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group, const MString &name, const MString &varname)
same as MPI_Comm_group
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
int MPI_Group_free(MPI_Group *group, const MString &name)
same as MPI_Group_free
void const MInt cellId
Definition: collector.h:239
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.
T cos(const T a, const T b, const T x)
Cosine slope filter.
Definition: filter.h:125
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
void cross(const T *const u, const T *const v, T *const c)
Definition: maiamath.h:101
MFloat RBF(const MFloat R, const MFloat R0)
radial base function
Definition: maiamath.h:873
MFloat besselJ0(MFloat x)
Definition: maiamath.h:343
MInt removeDoubleEntries(MInt *a, MInt size)
Definition: maiamath.h:722
void invert(MFloat *A, const MInt m, const MInt n)
Definition: maiamath.cpp:171
MFloat besselJ1(MFloat x)
Definition: maiamath.h:380
MFloat frobeniusMatrixNormSquared(MFloatScratchSpace &m, MInt dim1, MInt dim2)
Definition: maiamath.h:328
MFloat deltaFun(const MFloat r, const MFloat r0, const MFloat r1)
Definition: maiamath.h:885
void calcEigenVectors(MFloat A[3][3], MFloat Q[3][3], MFloat w[3])
Definition: maiamath.cpp:503
void quickSort(MInt *a, MInt start, MInt end)
Definition: maiamath.h:716
MFloat norm(const std::array< T, N > &u)
Definition: maiamath.h:148
MFloat lincos(MFloat arg)
Definition: maiamath.h:426
MInt inverse(MFloat **a, MFloat **ainv, MInt n, const MFloat epsilon)
Definition: maiamath.h:587
MInt invertR(T &A, T &weights, T &AInv, const MInt m, const MInt n)
Definition: maiamath.cpp:280
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
Definition: contexttypes.h:19
define array structures