Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
sysboundary.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2016 Finnish Meteorological Institute
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
26
27#include <cstdlib>
28#include <iostream>
29
30#include "../grid.h"
31#include "../object_wrapper.h"
33
34#include "donotcompute.h"
35#include "ionosphere.h"
36#include "copysphere.h"
37#include "outflow.h"
38#include "setmaxwellian.h"
39#include "sysboundary.h"
41
42using namespace std;
43using namespace spatial_cell;
44
46 if (first->getPrecedence() < second->getPrecedence()) {
47 return true;
48 } else {
49 return false;
50 }
51}
52
53// ************************************************************
54// ***** DEFINITIONS FOR BOUNDARY CLASS *****
55// ************************************************************
56
57SysBoundary::SysBoundary() : anyDynamic(false) {}
58
65 // Call delete for each SysBoundaryCondition:
66 for (list<SBC::SysBoundaryCondition*>::iterator it = sysBoundaries.begin(); it != sysBoundaries.end(); it++) {
67 delete *it;
68 *it = NULL;
69 }
70}
71
81 "boundaries.boundary",
82 "List of boundary condition (BC) types to be used. Each boundary condition to be used has to be on a new line "
83 "boundary = YYY. Available options are: Outflow, Ionosphere, Copysphere, Maxwellian.");
84 Readparameters::add("boundaries.periodic_x", "Set the grid periodicity in x-direction. 'yes'(default)/'no'.", "yes");
85 Readparameters::add("boundaries.periodic_y", "Set the grid periodicity in y-direction. 'yes'(default)/'no'.", "yes");
86 Readparameters::add("boundaries.periodic_z", "Set the grid periodicity in z-direction. 'yes'(default)/'no'.", "yes");
87
88 // call static addParameter functions in all bc's
94}
95
104 string periodic_x, periodic_y, periodic_z;
105
106 Readparameters::get("boundaries.boundary", sysBoundaryCondList);
107 Readparameters::get("boundaries.periodic_x", periodic_x);
108 Readparameters::get("boundaries.periodic_y", periodic_y);
109 Readparameters::get("boundaries.periodic_z", periodic_z);
110
111 periodic[0] = (periodic_x == "yes");
112 periodic[1] = (periodic_y == "yes");
113 periodic[2] = (periodic_z == "yes");
114}
115
125 // Initialize the boundary condition
126 stringstream timername;
127 timername << "Initialize system boundary condition " << bc->getName();
128 phiprof::Timer timer{timername.str()};
129 bc->initSysBoundary(t, project);
130 timer.stop();
131
132 sysBoundaries.push_back(bc);
133 if (sysBoundaries.size() > 1) {
135 }
136
137 // This assumes that only one instance of each type is created.
138 indexToSysBoundary[bc->getIndex()] = bc;
139}
140
154 int myRank;
155 MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
156 vector<string>::const_iterator it;
157
158 if (sysBoundaryCondList.size() == 0) {
160 abort_mpi("Non-periodic in x but no boundary condtion loaded!");
161 }
163 abort_mpi("Non-periodic in y but no boundary condtion loaded!");
164 }
166 abort_mpi("Non-periodic in z but no boundary condtion loaded!");
167 }
168 }
169
170 for (it = sysBoundaryCondList.begin(); it != sysBoundaryCondList.end(); it++) {
171 if (*it == "Outflow" || *it == "outflow") {
172 this->addSysBoundary(::new SBC::Outflow, project, t);
173
175 bool faces[6];
177
178 if ((faces[0] || faces[1]) && periodic[0]) {
179 abort_mpi("Conflict: x boundaries set to periodic but found Outflow conditions!");
180 }
181
182 if ((faces[2] || faces[3]) && periodic[1]) {
183 abort_mpi("Conflict: y boundaries set to periodic but found Outflow conditions!");
184 }
185
186 if ((faces[4] || faces[5]) && periodic[2]) {
187 abort_mpi("Conflict: z boundaries set to periodic but found Outflow conditions!");
188 }
189 if ((faces[0] || faces[1]) && P::xcells_ini < 5) {
190 abort_mpi("Outflow condition loaded on x- or x+ face but not enough cells in x!");
191 }
192 if ((faces[2] || faces[3]) && P::ycells_ini < 5) {
193 abort_mpi("Outflow condition loaded on y- or y+ face but not enough cells in y!");
194 }
195
196 if ((faces[4] || faces[5]) && P::zcells_ini < 5) {
197 abort_mpi("Outflow condition loaded on z- or z+ face but not enough cells in z!");
198 }
199
200 } else if (*it == "Ionosphere" || *it == "ionosphere") {
201 this->addSysBoundary(::new SBC::Ionosphere, project, t);
202 this->addSysBoundary(::new SBC::DoNotCompute, project, t);
204 } else if (*it == "Copysphere" || *it == "copysphere") {
205 this->addSysBoundary(::new SBC::Copysphere, project, t);
206 this->addSysBoundary(::new SBC::DoNotCompute, project, t);
208 } else if (*it == "Maxwellian" || *it == "maxwellian") {
209 this->addSysBoundary(::new SBC::Maxwellian, project, t);
211 bool faces[6];
213 if ((faces[0] || faces[1]) && periodic[0]) {
214 abort_mpi("Conflict: x boundaries set to periodic but found Maxwellian also!");
215 }
216 if ((faces[2] || faces[3]) && periodic[1]) {
217 abort_mpi("Conflict: y boundaries set to periodic but found Maxwellian also!");
218 }
219 if ((faces[4] || faces[5]) && periodic[2]) {
220 abort_mpi("Conflict: z boundaries set to periodic but found Maxwellian also!");
221 }
222 if ((faces[0] || faces[1]) && P::xcells_ini < 5) {
223 abort_mpi("Maxwellian condition loaded on x- or x+ face but not enough cells in x!");
224 }
225 if ((faces[2] || faces[3]) && P::ycells_ini < 5) {
226 abort_mpi("Maxwellian condition loaded on y- or y+ face but not enough cells in y!");
227 }
228 if ((faces[4] || faces[5]) && P::zcells_ini < 5) {
229 abort_mpi("Maxwellian condition loaded on z- or z+ face but not enough cells in z!");
230 }
231 } else {
232 std::ostringstream msg;
233 msg << "Unknown type of boundary read: " << *it;
234 abort_mpi(msg.str());
235 }
236 }
237
238 for (auto& b : sysBoundaries) {
239 b->setPeriodicity(periodic);
240 }
241}
242
252bool SysBoundary::existSysBoundary(std::string name) {
253 vector<string>::const_iterator it;
254 for (it = sysBoundaryCondList.begin(); it != sysBoundaryCondList.end(); it++) {
255 if ((*it) == name) {
256 return true;
257 }
258 }
259 return false;
260}
261
262void SysBoundary::checkRefinement(dccrg::Dccrg<spatial_cell::SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
263 // Verifies that all cells within Neighborhoods::FULL of L1 boundary cells are on the same refinement
264 // level (one group for inner boundary, another for outer boundary)
265
266 // Set is used to avoid storing duplicates - each cell only needs to be checked once
267 set<CellID> innerBoundaryCells;
268 set<CellID> outerBoundaryCells;
269
270 int innerBoundaryRefLvl = -1;
271 int outerBoundaryRefLvl = -1;
272
273 const vector<CellID>& local_cells = getLocalCells();
274 // Collect cells by sysboundarytype
275 for (auto cellId : local_cells) {
276 SpatialCell* cell = mpiGrid[cellId];
277 if (cell) {
280 innerBoundaryCells.insert(cellId);
281 innerBoundaryRefLvl = mpiGrid.get_refinement_level(cellId);
282 if (cell->sysBoundaryLayer == 1) {
283 // Add all stencil neighbors of layer 1 cells
284 auto* nbrPairVector = mpiGrid.get_neighbors_of(cellId, Neighborhoods::SYSBOUNDARIES);
285 for (auto nbrPair : *nbrPairVector) {
286 if (nbrPair.first != INVALID_CELLID) {
287 innerBoundaryCells.insert(nbrPair.first);
288 }
289 }
290 }
293 outerBoundaryCells.insert(cellId);
294 outerBoundaryRefLvl = mpiGrid.get_refinement_level(cellId);
295 // Add all stencil neighbors of outer boundary cells
296 auto* nbrPairVector = mpiGrid.get_neighbors_of(cellId, Neighborhoods::SYSBOUNDARIES);
297 for (auto nbrPair : *nbrPairVector) {
298 if (nbrPair.first != INVALID_CELLID) {
299 outerBoundaryCells.insert(nbrPair.first);
300 }
301 }
302 }
303 }
304 }
305
306 for (auto cellId : innerBoundaryCells) {
307 if (cellId != INVALID_CELLID && mpiGrid.get_refinement_level(cellId) != innerBoundaryRefLvl) {
308 abort_mpi("ERROR: inner boundary cells must have identical refinement level!");
309 }
310 }
311
312 for (auto cellId : outerBoundaryCells) {
313 if (cellId != INVALID_CELLID && mpiGrid.get_refinement_level(cellId) != outerBoundaryRefLvl) {
314 abort_mpi("ERROR: outer boundary cells must have identical refinement level!");
315 }
316 }
317}
318
319bool belongsToLayer(const int layer, const int x, const int y, const int z,
320 fsgrids::technicalspan technical, const fsgrid::FsStencil& stencil) {
321
322 bool belongs = false;
323
324 // loop through all neighbors (including diagonals)
325 for (int iz = -1; iz <= 1; ++iz) {
326 for (int iy = -1; iy <= 1; ++iy) {
327 for (int ix = -1; ix <= 1; ++ix) {
328 // not strictly necessary but logically we should not consider the cell itself
329 // among its neighbors.
330 if ((ix == 0 && iy == 0 && iz == 0) || not stencil.cellExists(ix, iy, iz)) {
331 continue;
332 }
333
334 const auto& tech = technical[stencil.indexFromOffset(ix, iy, iz)];
335 if (layer == 1 && tech.sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
336 // in the first layer, boundary cell belongs if it has a non-boundary neighbor
337 belongs = true;
338 return belongs;
339
340 } else if (layer > 1 && tech.sysBoundaryLayer == layer - 1) {
341 // in all other layers, boundary cell belongs if it has a neighbor in the previous layer
342 belongs = true;
343 return belongs;
344 }
345 }
346 }
347 }
348
349 return belongs;
350}
351
359void SysBoundary::classifyCells(dccrg::Dccrg<spatial_cell::SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
361 const vector<CellID>& cells = getLocalCells();
362 const auto rank = fsgrid.getRank();
363
364 /*set all cells to default value, not_sysboundary */
365 #pragma omp parallel for
366 for (uint i = 0; i < cells.size(); i++) {
367 mpiGrid[cells[i]]->sysBoundaryFlag = sysboundarytype::NOT_SYSBOUNDARY;
368 }
369
370 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
371 phiprof::initializeTimer("classifyCells-init"), technical,
372 [=](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
373 auto& tech = technical[stencil.ooo()];
374 // Here for debugging since boundarytype should be fed from MPIGrid
375 tech.sysBoundaryFlag = sysboundarytype::N_SYSBOUNDARY_CONDITIONS;
376 tech.sysBoundaryLayer = 0;
377 // Function called on every refinement, we only want to reset dt on simulation start
378 if (P::tstep == P::tstep_min) {
379 tech.maxFsDt = numeric_limits<Real>::max();
380 }
381 // Set the fsgrid rank in the technical grid
382 tech.fsGridRank = rank;
383 });
384
385
386 /*
387 loop through sysboundaries and let all sysboundaries set in local
388 cells if they are part of which sysboundary (cell location needs to
389 be updated by now. No remote data needed/available, so assignement
390 has to be based individually on each cells location
391 */
392 for (auto& b : sysBoundaries) {
393 b->assignSysBoundary(mpiGrid, technical, fsgrid);
394 }
395
397 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SYSBOUNDARIES);
398
399 feedBoundaryIntoFsGrid(mpiGrid, cells, technical, fsgrid);
400
401 // set distance 1 cells to boundary cells, that have neighbors which are normal cells
402 for (CellID cell : cells) {
403 mpiGrid[cell]->sysBoundaryLayer = 0; /*Initial value*/
404
405 std::array<double, 3> dx = mpiGrid.geometry.get_length(cell);
406 std::array<double, 3> x = mpiGrid.get_center(cell);
407 if (!isPeriodic(0) && (x[0] > Parameters::xmax - dx[0] || x[0] < Parameters::xmin + dx[0])) {
408 continue;
409 } else if (!isPeriodic(1) && (x[1] > Parameters::ymax - dx[1] || x[1] < Parameters::ymin + dx[1])) {
410 continue;
411 } else if (!isPeriodic(2) && (x[2] > Parameters::zmax - dx[2] || x[2] < Parameters::zmin + dx[2])) {
412 continue;
413 }
414
415 if (mpiGrid[cell]->sysBoundaryFlag != sysboundarytype::NOT_SYSBOUNDARY) {
416 // Cornerwise neighbor, i.e. cell must be in both neighbors_of and neighbors_to
417 for (auto i : *mpiGrid.get_neighbors_of(cell, Neighborhoods::SYSBOUNDARIES)) {
418 CellID neighbor = i.first;
419 if (neighbor && mpiGrid[neighbor]->sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
420 for (auto j : *mpiGrid.get_neighbors_to(cell, Neighborhoods::SYSBOUNDARIES)) {
421 if (j.first == neighbor) {
422 mpiGrid[cell]->sysBoundaryLayer = 1;
423 }
424 }
425 }
426 }
427 }
428 }
429
430 /*communicate which cells have Layer 1 set above for local cells (sysBoundaryFlag
431 * and sysBoundaryLayer communicated)*/
433
434 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SYSBOUNDARIES);
435
436 /*Compute distances*/
437 uint maxLayers = 3; // max(max(P::xcells_ini, P::ycells_ini), P::zcells_ini);
438 for (uint layer = 1; layer < maxLayers; layer++) {
439 for (CellID cell : cells) {
440 if (mpiGrid[cell]->sysBoundaryLayer == 0) {
441 // Note: this distance calculation will be non-plateau monotonic only assuming that
442 // SysBoundary::checkRefinement has been applied correctly and there are no refinement
443 // level changes within Neighborhoods::SYSBOUNDARIES.
444 for (auto i : *mpiGrid.get_neighbors_of(cell, Neighborhoods::SYSBOUNDARIES)) {
445 CellID neighbor = i.first;
446 if (neighbor && mpiGrid[neighbor]->sysBoundaryLayer == layer) {
447 for (auto j : *mpiGrid.get_neighbors_to(cell, Neighborhoods::SYSBOUNDARIES)) {
448 if (j.first == neighbor) {
449 mpiGrid[cell]->sysBoundaryLayer = layer + 1;
450 }
451 }
452 }
453 }
454 }
455 }
456
458 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SYSBOUNDARIES);
459 }
460
461 /*set cells to DO_NOT_COMPUTE if they are on boundary, and are not
462 * in the first two layers of the boundary*/
463 for (uint i = 0; i < cells.size(); i++) {
464 if (mpiGrid[cells[i]]->sysBoundaryFlag != sysboundarytype::NOT_SYSBOUNDARY &&
465 mpiGrid[cells[i]]->sysBoundaryLayer != 1 && mpiGrid[cells[i]]->sysBoundaryLayer != 2) {
466 mpiGrid[cells[i]]->sysBoundaryFlag = sysboundarytype::DO_NOT_COMPUTE;
467 }
468 }
469
470 // The following is done so that everyone knows their neighbour's
471 // layer flags. This is needed for the correct use of the system
472 // boundary local communication patterns.
474 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::FULL);
475
476 SysBoundary& sysBoundaryContainer = getObjectWrapper().sysBoundaryContainer;
477 Real ionosphereDownmapRadius = 0;
478 if (sysBoundaryContainer.existSysBoundary("Ionosphere")) {
479 Readparameters::get("ionosphere.downmapRadius", ionosphereDownmapRadius);
480 }
481 if (ionosphereDownmapRadius < 1000) {
482 ionosphereDownmapRadius *= physicalconstants::R_E;
483 }
484
485 // Now the layers need to be set on fsgrid too
486 // In dccrg initialization the max number of boundary layers is set to 3.
487 const uint MAX_NUMBER_OF_BOUNDARY_LAYERS = 3 * pow(2, mpiGrid.get_maximum_refinement_level());
488
489 fsgrid.updateGhostCells(technical);
490
491 // loop through max number of layers
492 for (uint layer = 1; layer <= MAX_NUMBER_OF_BOUNDARY_LAYERS; ++layer) {
493
494 // loop through all cells in grid
495 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
496 phiprof::initializeTimer("classifyCells-pass-1"), technical,
497 [=](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
498 auto& tech = technical[stencil.ooo()];
499
500 // for the first layer, consider all cells that belong to a boundary, for other layers
501 // consider all cells that have not yet been labeled.
502 if ((layer == 1 && tech.sysBoundaryFlag != sysboundarytype::NOT_SYSBOUNDARY) ||
503 (layer > 1 && tech.sysBoundaryLayer == 0)) {
504
505 if (belongsToLayer(layer, stencil.i, stencil.j, stencil.k, technical, stencil)) {
506
507 tech.sysBoundaryLayer = layer;
508
509 if (layer > 2 && (tech.sysBoundaryFlag == sysboundarytype::IONOSPHERE ||
510 tech.sysBoundaryFlag == sysboundarytype::COPYSPHERE)) {
511 tech.sysBoundaryFlag = sysboundarytype::DO_NOT_COMPUTE;
512 } else if (layer > 2 && tech.sysBoundaryFlag != sysboundarytype::NOT_SYSBOUNDARY) {
513 tech.sysBoundaryFlag = sysboundarytype::OUTER_BOUNDARY_PADDING;
514 }
515 }
516 }
517 });
518 // This needs an update every iteration as belongsToLayer() needs up to date data.
519 fsgrid.updateGhostCells(technical);
520 }
521
522 // One more pass to make sure, in particular if the ionosphere is wide enough
523 // there is remaining cells of IONOSPHERE type inside the max layers gone through previously.
524 // This last pass now gets rid of them.
525 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
526 phiprof::initializeTimer("classifyCells-pass-2"), technical,
527 [=](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
528 auto& tech = technical[stencil.ooo()];
529 if (tech.sysBoundaryLayer == 0 && (tech.sysBoundaryFlag == sysboundarytype::IONOSPHERE ||
530 tech.sysBoundaryFlag == sysboundarytype::COPYSPHERE)) {
531 tech.sysBoundaryFlag = sysboundarytype::DO_NOT_COMPUTE;
532 }
533 });
534
535 fsgrid.updateGhostCells(technical);
536
537 const array<fsgrid::FsSize_t, 3> fsGridDimensions = fsgrid.getGlobalSize();
538 const std::array<bool, 3> periodic_l = this->periodic;
539
540 // One pass to setup the bit field to know which components the field solver should propagate.
541 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
542 phiprof::initializeTimer("classifyCells-pass-3"), technical,
543 [=](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
544 const auto gid = coordinates.localToGlobal(stencil.i, stencil.j, stencil.k);
545 auto& tech = technical[stencil.ooo()];
546 tech.SOLVE = 0;
547
548 if (((gid[0] == 0 || gid[0] == fsGridDimensions[0] - 1) && !periodic_l[0]) ||
549 ((gid[1] == 0 || gid[1] == fsGridDimensions[1] - 1) && !periodic_l[1]) ||
550 ((gid[2] == 0 || gid[2] == fsGridDimensions[2] - 1) && !periodic_l[2])) {
551 return; // was continue in non-lambda version
552 }
553
554 if (tech.sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
555 tech.SOLVE = tech.SOLVE | compute::BX;
556 tech.SOLVE = tech.SOLVE | compute::BY;
557 tech.SOLVE = tech.SOLVE | compute::BZ;
558 tech.SOLVE = tech.SOLVE | compute::EX;
559 tech.SOLVE = tech.SOLVE | compute::EY;
560 tech.SOLVE = tech.SOLVE | compute::EZ;
561 } else {
562 if (technical[stencil.moo()].sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
563 tech.SOLVE = tech.SOLVE | compute::BX;
564 tech.SOLVE = tech.SOLVE | compute::EY;
565 tech.SOLVE = tech.SOLVE | compute::EZ;
566 }
567 if (technical[stencil.omo()].sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
568 tech.SOLVE = tech.SOLVE | compute::BY;
569 tech.SOLVE = tech.SOLVE | compute::EX;
570 tech.SOLVE = tech.SOLVE | compute::EZ;
571 }
572 if (technical[stencil.oom()].sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
573 tech.SOLVE = tech.SOLVE | compute::BZ;
574 tech.SOLVE = tech.SOLVE | compute::EX;
575 tech.SOLVE = tech.SOLVE | compute::EY;
576 }
577 if (technical[stencil.mmo()].sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
578 tech.SOLVE = tech.SOLVE | compute::EZ;
579 }
580 if (technical[stencil.mom()].sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
581 tech.SOLVE = tech.SOLVE | compute::EY;
582 }
583 if (technical[stencil.omm()].sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
584 tech.SOLVE = tech.SOLVE | compute::EX;
585 }
586 }
587 });
588
589 fsgrid.updateGhostCells(technical);
590}
591
599void SysBoundary::applyInitialState(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
602 fsgrids::bgbspan bgb, Project& project) {
603
604 list<SBC::SysBoundaryCondition*>::iterator it;
605 for (it = sysBoundaries.begin(); it != sysBoundaries.end(); it++) {
606 if ( // This is to skip the reapplication
607 Parameters::isRestart // When not restarting
608 && !(*it)->doApplyUponRestart() // When reapplicaiton is not requested
609 ) {
610 continue;
611 }
612 stringstream timername;
613 timername << "Apply system boundary condition " << (*it)->getName() << " initial state";
614 phiprof::Timer timer{timername.str()};
615 (*it)->applyInitialState(mpiGrid, technical, fsgrid, perb, bgb, project);
616 }
617}
618
619void SysBoundary::updateState(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
622 fsgrids::bgbspan bgb, creal t) {
623 if (isAnyDynamic()) {
624 for (auto& b : sysBoundaries) {
625 if (b->isDynamic()) {
626 b->updateState(mpiGrid, technical, fsgrid, perb, bgb, t);
627 }
628 }
629 }
630}
631
632
633void SysBoundary::setupL2OutflowAtRestart(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
634 list<SBC::SysBoundaryCondition*>::iterator it;
635 for (it = sysBoundaries.begin(); it != sysBoundaries.end(); it++) {
636 if (Parameters::isRestart // When restarting
637 && !(*it)->doApplyUponRestart() // When reapplication is not requested
638 && (*it)->getIndex() == sysboundarytype::OUTFLOW
639 ) {
640 (*it)->setupL2OutflowAtRestart(mpiGrid);
641 }
642 }
643 // Needed after copying VDFs in L1 Outflow cells or LUMI (and our communications) breaks.
644 for (uint popID=0; popID<getObjectWrapper().particleSpecies.size(); ++popID) {
645 updateRemoteVelocityBlockLists(mpiGrid, popID);
646 }
647}
648
649
663void SysBoundary::applySysBoundaryVlasovConditions(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
664 creal& t, const bool calculate_V_moments) {
665
666 if (sysBoundaries.size() == 0) {
667 return; // no system boundaries
668 }
669
670/*Transfer along boundaries*/
671// First the small stuff without overlapping in an extended neighbourhood:
673 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SYSBOUNDARIES_EXTENDED);
674
675 // Loop over existing particle species
676 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
678 // update lists in neighborhood
680
681 // Then the block data in the reduced neighbourhood:
682 phiprof::Timer commTimer{"Start comm of cell and block data", {"MPI"}};
684 mpiGrid.start_remote_neighbor_copy_updates(Neighborhoods::SYSBOUNDARIES);
685 commTimer.stop();
686
687 phiprof::Timer computeInnerTimer{"Compute process inner cells"};
688 // Compute Vlasov boundary condition on system boundary/process inner cells
689 vector<CellID> localCells;
690 getBoundaryCellList(mpiGrid, mpiGrid.get_local_cells_not_on_process_boundary(Neighborhoods::SYSBOUNDARIES), localCells);
691
692 #pragma omp parallel for
693 for (uint i = 0; i < localCells.size(); i++) {
694 cuint sysBoundaryType = mpiGrid[localCells[i]]->sysBoundaryFlag;
695 this->getSysBoundary(sysBoundaryType)
696 ->vlasovBoundaryCondition(mpiGrid, localCells[i], popID, calculate_V_moments);
697 }
698 if (popID == getObjectWrapper().particleSpecies.size() - 1) {
699 // Only calculate moments when handling last population
700 if (calculate_V_moments) {
701 calculateMoments_V(mpiGrid, localCells, true);
702 } else {
703 calculateMoments_R(mpiGrid, localCells, true);
704 }
705 }
706 computeInnerTimer.stop();
707
708 phiprof::Timer waitimer {"Wait for receives", {"MPI", "Wait"}};
709 mpiGrid.wait_remote_neighbor_copy_updates(Neighborhoods::SYSBOUNDARIES);
710 waitimer.stop();
711
712 // Compute vlasov boundary on system boundary/process boundary cells
713 phiprof::Timer computeBoundaryTimer{"Compute process boundary cells"};
714 vector<CellID> boundaryCells;
715 getBoundaryCellList(mpiGrid, mpiGrid.get_local_cells_on_process_boundary(Neighborhoods::SYSBOUNDARIES), boundaryCells);
716 #pragma omp parallel for
717 for (uint i = 0; i < boundaryCells.size(); i++) {
718 cuint sysBoundaryType = mpiGrid[boundaryCells[i]]->sysBoundaryFlag;
719 this->getSysBoundary(sysBoundaryType)
720 ->vlasovBoundaryCondition(mpiGrid, boundaryCells[i], popID, calculate_V_moments);
721 }
722 if (popID == getObjectWrapper().particleSpecies.size() - 1) {
723 // Only calculate moments when handling last population
724 if (calculate_V_moments) {
725 calculateMoments_V(mpiGrid, boundaryCells, true);
726 } else {
727 calculateMoments_R(mpiGrid, boundaryCells, true);
728 }
729 }
730 computeBoundaryTimer.stop();
731
732 // WARNING Blocks are changed but lists not updated now, if you need to use/communicate them before the next
733 // update is done, add an update here. reset lists in smaller default neighborhood
734 updateRemoteVelocityBlockLists(mpiGrid, popID);
735
736 } // for-loop over populations
737}
738
744 auto it = indexToSysBoundary.find(sysBoundaryType);
745 if (it != indexToSysBoundary.end()) {
746 return it->second;
747 } else {
748 abort_mpi("ERROR: Boundary " + to_string(sysBoundaryType) + " is invalid", 1);
749 }
750}
751
755unsigned int SysBoundary::size() const { return sysBoundaries.size(); }
756
760bool SysBoundary::isAnyDynamic() const { return anyDynamic; }
761
766bool SysBoundary::isPeriodic(uint direction) const { return periodic[direction]; }
767
775void getBoundaryCellList(const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
776 const vector<uint64_t>& cellList, vector<uint64_t>& boundaryCellList) {
777 boundaryCellList.clear();
778 for (size_t cell = 0; cell < cellList.size(); ++cell) {
779 const CellID cellID = cellList[cell];
780 if (mpiGrid[cellID]->sysBoundaryFlag == sysboundarytype::DO_NOT_COMPUTE ||
781 mpiGrid[cellID]->sysBoundaryFlag == sysboundarytype::NOT_SYSBOUNDARY) {
782 continue;
783 }
784 boundaryCellList.push_back(cellID);
785 }
786}
787
791void SysBoundary::updateSysBoundariesAfterLoadBalance(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
792 phiprof::Timer timer{"updateSysBoundariesAfterLoadBalance"};
793 vector<uint64_t> local_cells_on_boundary;
794 getBoundaryCellList(mpiGrid, mpiGrid.get_cells(), local_cells_on_boundary);
795 // Loop over sysboundaries:
796 for (list<SBC::SysBoundaryCondition*>::iterator it = sysBoundaries.begin(); it != sysBoundaries.end(); ++it) {
797 (*it)->updateSysBoundaryConditionsAfterLoadBalance(mpiGrid, local_cells_on_boundary);
798 }
799}
for i
Definition Dispersion.m:24
dx
Definition Dispersion.m:38
set(gca, 'YDir', 'normal')
void calculateMoments_R(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, const bool &computeSecond, const bool initialCompute)
void calculateMoments_V(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, const bool &computeSecond, const bool initialCompute)
static void addComposing(const std::string &name, const std::string &desc)
static bool helpRequested
static void get(const std::string &name, std::string &value)
static void add(const std::string &name, const std::string &desc, const std::string &defValue)
Copysphere is a class applying an ionosphere-ish boundary conditions.
Definition copysphere.h:55
static void addParameters()
DoNotCompute is a class handling cells not to be computed.
static void addParameters()
Ionosphere is a class applying ionospheric boundary conditions.
Definition ionosphere.h:572
static void addParameters()
Maxwellian is a class applying fixed Maxwellian conditions according to parameters read from an input...
static void addParameters()
Outflow is a class applying copy/outflow boundary conditions.
Definition outflow.h:54
static void addParameters()
Definition outflow.cpp:52
SBC::SysBoundaryCondition is the base class for system boundary conditions.
virtual void vlasovBoundaryCondition(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellID, const uint popID, const bool calculate_V_moments)=0
virtual std::string getName() const
virtual uint getIndex() const =0
virtual void initSysBoundary(creal &t, Project &project)=0
virtual void getFaces(bool *faces)=0
void initSysBoundaries(Project &project, creal &t)
Initialise all system boundary conditions actually used.
SysBoundary()
Definition main.cpp:43
std::array< bool, 3 > periodic
bool isPeriodic(uint direction) const
SBC::SysBoundaryCondition * getSysBoundary(cuint sysBoundaryType) const
void updateState(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, fsgrids::perbspan perb, fsgrids::bgbspan bgb, creal t)
std::vector< std::string > sysBoundaryCondList
void classifyCells(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid)
Classify all simulation cells with respect to the system boundary conditions.
void checkRefinement(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
bool existSysBoundary(std::string name)
Boolean check if queried sysboundarycondition exists Note: this queries against the parsed list of na...
void getParameters()
Get this class' parameters.
void addSysBoundary(SBC::SysBoundaryCondition *sbc, Project &project, creal &t)
~SysBoundary()
Destructor for class SysBoundary.
Definition main.cpp:44
void addParameters()
Add its own and all existing SysBoundaryConditions' parameters.
std::list< SBC::SysBoundaryCondition * > sysBoundaries
void applyInitialState(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, fsgrids::perbspan perb, fsgrids::bgbspan bgb, Project &project)
Apply the initial state to all system boundary cells. Loops through all SysBoundaryConditions and cal...
std::map< uint, SBC::SysBoundaryCondition * > indexToSysBoundary
unsigned int size() const
void setupL2OutflowAtRestart(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
bool isAnyDynamic() const
void applySysBoundaryVlasovConditions(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, creal &t, const bool calculate_V_moments)
Apply the Vlasov system boundary conditions to all system boundary cells at time t.
void updateSysBoundariesAfterLoadBalance(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
static bool setCommunicatedSpecies(const uint popID)
static void set_mpi_transfer_type(const uint64_t type, bool atSysBoundaries=false)
void abort_mpi(const std::string str, const int err_type)
Definition common.cpp:90
const std::vector< CellID > & getLocalCells()
Definition main.cpp:39
const uint32_t cuint
Definition definitions.h:50
float Real
Definition definitions.h:41
uint64_t CellID
Definition definitions.h:54
fsgrid::FsGrid< FS_STENCIL_WIDTH > FieldSolverGrid
Definition definitions.h:78
const float creal
Definition definitions.h:42
int myRank
Definition gpu_base.cpp:48
const int j
void updateRemoteVelocityBlockLists(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const uint popID, const uint neighborhood)
Definition grid.cpp:919
void feedBoundaryIntoFsGrid(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid)
Definition gridGlue.cpp:516
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
@ SYSBOUNDARIES
Definition common.h:84
@ SYSBOUNDARIES_EXTENDED
Definition common.h:85
const uint EZ
Definition common.h:504
const uint EY
Definition common.h:503
const uint EX
Definition common.h:502
const uint BZ
Definition common.h:501
const uint BX
Definition common.h:499
const uint BY
Definition common.h:500
std::span< std::array< Real, fsgrids::bfield::N_BFIELD > > perbspan
Definition common.h:434
std::span< technical > technicalspan
Definition common.h:452
std::span< std::array< Real, bgbfield::N_BGB > > bgbspan
Definition common.h:444
const Real R_E
Definition common.h:575
static const uint64_t CELL_SYSBOUNDARYFLAG
static const uint64_t POP_METADATA
static const uint64_t VEL_BLOCK_DATA
static const uint64_t CELL_PARAMETERS
@ N_SYSBOUNDARY_CONDITIONS
Definition common.h:494
@ OUTER_BOUNDARY_PADDING
Definition common.h:493
const uint64_t INVALID_CELLID
Definition parameters.h:35
SysBoundary sysBoundaryContainer
std::vector< species::Species > particleSpecies
static Real ymax
Definition parameters.h:41
static Real xmax
Definition parameters.h:39
static uint zcells_ini
Definition parameters.h:50
static Real zmax
Definition parameters.h:43
static Real ymin
Definition parameters.h:40
static uint ycells_ini
Definition parameters.h:49
static uint xcells_ini
Definition parameters.h:48
static uint tstep_min
Definition parameters.h:71
static Real xmin
Definition parameters.h:38
static uint tstep
Definition parameters.h:73
static bool isRestart
Definition parameters.h:176
static Real zmin
Definition parameters.h:42
bool belongsToLayer(const int layer, const int x, const int y, const int z, fsgrids::technicalspan technical, const fsgrid::FsStencil &stencil)
bool precedenceSort(const SBC::SysBoundaryCondition *first, const SBC::SysBoundaryCondition *second)
void getBoundaryCellList(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< uint64_t > &cellList, vector< uint64_t > &boundaryCellList)
void getBoundaryCellList(const dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cellList, std::vector< CellID > &boundaryCellList)
bool precedenceSort(const SBC::SysBoundaryCondition *first, const SBC::SysBoundaryCondition *second)