Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
grid.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
23#include "common.h"
24#include <cstdlib>
25#include <iostream>
26#include <iomanip> // for setprecision()
27#include <cmath>
28#include <vector>
29#include <sstream>
30#include <ctime>
31#ifdef _OPENMP
32 #include <omp.h>
33#endif
34#include "grid.h"
36#include "definitions.h"
37#include "mpiconversion.h"
38#include "logger.h"
39#include "parameters.h"
46#include "projects/project.h"
47#include "iowrite.h"
48#include "ioread.h"
49#include "object_wrapper.h"
50#include "memory_report.h"
51
52#ifdef PAPI_MEM
53#include "papi.h"
54#endif
55
57#ifdef USE_GPU
58#include "arch/gpu_base.hpp"
59#endif
60
61#ifdef DEBUG_VLASIATOR
62#define DEBUG_GRID
63#endif
64
65using namespace std;
66
67extern Logger logFile;
68
69void initVelocityGridGeometry(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid);
70void initSpatialCellCoordinates(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid);
71void initializeStencils(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid);
72
73void writeVelMesh(const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
74 const vector<CellID>& cells = getLocalCells();
75
76 static int counter = 0;
77
78 stringstream fname;
79 fname << "VelMesh.";
80 fname.width(3);
81 fname.fill(0);
82 fname << counter << ".vlsv";
83
84 vlsv::Writer vlsvWriter;
85 vlsvWriter.open(fname.str(), MPI_COMM_WORLD, 0, MPI_INFO_NULL);
86 writeVelocityDistributionData(vlsvWriter, mpiGrid, cells, MPI_COMM_WORLD);
87 vlsvWriter.close();
88
89 ++counter;
90}
91
93 int argn,
94 char **argc,
95 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
96 fsgrid::FsData<std::array<Real, fsgrids::bfield::N_BFIELD>>& perb,
97 fsgrid::FsData<std::array<Real, fsgrids::bgbfield::N_BGB>>& bgb,
98 fsgrid::FsData<std::array<Real, fsgrids::moments::N_MOMENTS>>& moments,
99 fsgrid::FsData<std::array<Real, fsgrids::moments::N_MOMENTS>>& momentsdt2,
100 fsgrid::FsData<std::array<Real, fsgrids::dmoments::N_DMOMENTS>>& dmoments,
101 fsgrid::FsData<std::array<Real, fsgrids::efield::N_EFIELD>>& e,
102 fsgrid::FsData<std::array<Real, fsgrids::egradpe::N_EGRADPE>>& egradpe,
103 fsgrid::FsData<std::array<Real, fsgrids::volfields::N_VOL>>& vol,
104 fsgrid::FsData<fsgrids::technical>& technical, FieldSolverGrid& fsgrid,
105 SysBoundary& sysBoundaries,
106 Project& project
107) {
108 int myRank;
109 MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
110
111 // Init Zoltan:
112 float zoltanVersion;
113 if (Zoltan_Initialize(argn, argc, &zoltanVersion) != ZOLTAN_OK) {
114 if (myRank == MASTER_RANK) cerr << "\t ERROR: Zoltan initialization failed." << endl;
115 exit(1);
116 } else {
117 logFile << "\t Zoltan " << zoltanVersion << " initialized successfully" << std::endl << writeVerbose;
118 }
119
120 MPI_Comm comm = MPI_COMM_WORLD;
121 int neighborhood_size = VLASOV_STENCIL_WIDTH;
123 // One extra layer for translation of ghost cells
124 neighborhood_size++;
125 }
126
127 const std::array<uint64_t, 3> grid_length = {{P::xcells_ini, P::ycells_ini, P::zcells_ini}};
128 dccrg::Cartesian_Geometry::Parameters geom_params;
129 geom_params.start[0] = P::xmin;
130 geom_params.start[1] = P::ymin;
131 geom_params.start[2] = P::zmin;
132 geom_params.level_0_cell_length[0] = P::dx_ini;
133 geom_params.level_0_cell_length[1] = P::dy_ini;
134 geom_params.level_0_cell_length[2] = P::dz_ini;
135
136 phiprof::Timer dccrgTimer {"Initialize DCCRG grid"};
137 mpiGrid.set_initial_length(grid_length)
138 .set_load_balancing_method(&P::loadBalanceAlgorithm[0])
139 .set_neighborhood_length(neighborhood_size)
140 .set_maximum_refinement_level(P::amrMaxSpatialRefLevel)
141 .set_periodic(sysBoundaries.isPeriodic(0),
142 sysBoundaries.isPeriodic(1),
143 sysBoundaries.isPeriodic(2))
144 .initialize(comm)
145 .set_geometry(geom_params);
146 dccrgTimer.stop();
147
148 phiprof::Timer refineTimer {"Refine spatial cells"};
149 // We need this first as well
151 if (!P::isRestart) {
152 // Note call to project.refineSpatialCells below
153 if (P::amrMaxSpatialRefLevel > 0 && project.refineSpatialCells(mpiGrid)) {
154 mpiGrid.balance_load();
156 mapRefinement(mpiGrid, technical.view(), fsgrid);
157 }
158 } else {
159 if (myRank == MASTER_RANK) logFile << "(INIT): Reading grid structure from " << P::restartFileName << endl << writeVerbose;
160 bool restartSuccess = readFileCells(mpiGrid, P::restartFileName);
161 if (myRank == MASTER_RANK) logFile << " ...done." << endl << writeVerbose;
162 if (restartSuccess) {
163 mpiGrid.balance_load();
165 mapRefinement(mpiGrid, technical.view(), fsgrid);
166 }
167 }
168 refineTimer.stop();
169 initializeStencils(mpiGrid);
170
171 for (const auto& [key, value] : P::loadBalanceOptions) {
172 mpiGrid.set_partitioning_option(key, value);
173 }
174 phiprof::Timer initialLBTimer {"Initial load-balancing"};
175 if (myRank == MASTER_RANK) logFile << "(INIT): Starting initial load balance." << endl << writeVerbose;
176 mpiGrid.balance_load(); // Direct DCCRG call, recalculate cache afterwards
178
180 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::NEAREST);
181
183 setFaceNeighborRanks(mpiGrid); // Only needed for remote contribution in translation
184 }
185 const vector<CellID>& cells = getLocalCells();
186 initialLBTimer.stop();
187
188 if (myRank == MASTER_RANK) {
189 logFile << "(INIT): Set initial state." << endl << writeVerbose;
190 }
191
192 phiprof::Timer initialStateTimer {"Set initial state"};
193
194 phiprof::Timer setCoordsTimer {"Set spatial cell coordinates"};
196 setCoordsTimer.stop();
197
198 phiprof::Timer initBoundaryTimer {"Initialize system boundary conditions"};
199 sysBoundaries.initSysBoundaries(project, P::t_min);
200 initBoundaryTimer.stop();
201
203 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SYSBOUNDARIES);
204
205 computeCoupling(mpiGrid, cells, fsgrid, technical.view());
206
207 // We want this before restart refinement
208 phiprof::Timer classifyTimer {"Classify cells (sys boundary conditions)"};
209 sysBoundaries.classifyCells(mpiGrid,technical.view(), fsgrid);
210 classifyTimer.stop();
211
212 if (P::isRestart) {
213 logFile << "Restart from "<< P::restartFileName << std::endl << writeVerbose;
214 phiprof::Timer restartReadTimer {"Read restart"};
215 if (readGrid(mpiGrid, perb.view(), e.view(), technical.view(), fsgrid, P::restartFileName) == false) {
216 logFile << "(MAIN) ERROR: restarting failed" << endl;
217 exit(1);
218 }
219 restartReadTimer.stop();
220
221 if (P::forceRefinement) {
222 // Adapt refinement to match new static refinement parameters
223 phiprof::Timer timer {"Restart refinement"};
224 for (int i = 0; i < P::amrMaxSpatialRefLevel; ++i) {
225 // (un)Refinement is done one level at a time so we don't blow up memory
226 if (!adaptRefinement(mpiGrid, technical.view(), fsgrid, sysBoundaries, project, i)) {
227 cerr << "(MAIN) ERROR: Forcing refinement takes too much memory" << endl;
228 exit(1);
229 }
230 balanceLoad(mpiGrid, sysBoundaries, technical.view(), fsgrid);
231 }
232 } else if (P::refineOnRestart) {
233 // Considered deprecated
234 phiprof::Timer timer {"Restart refinement"};
235 // Get good load balancing for refinement
236 balanceLoad(mpiGrid, sysBoundaries, technical.view(), fsgrid);
237 adaptRefinement(mpiGrid, technical.view(), fsgrid, sysBoundaries, project);
238 balanceLoad(mpiGrid, sysBoundaries, technical.view(), fsgrid);
239 }
240 }
241
242 // Check refined cells do not touch boundary cells
243 phiprof::Timer boundaryCheckTimer {"Check boundary refinement"};
244 sysBoundaries.checkRefinement(mpiGrid);
245 boundaryCheckTimer.stop();
246
247 if (P::isRestart) {
248 // initial state for sys-boundary cells, will skip those not set to be reapplied at restart
249 sysBoundaries.applyInitialState(mpiGrid, technical.view(), fsgrid, perb.view(), bgb.view(), project);
250 }
251
252 // Update fsgrid (e.g. sysboundary flags)
253 fsgrid.updateGhostCells(technical.view());
254
255 if (!P::isRestart && !P::writeFullBGB) {
256 // If we are starting a new regular simulation, we need to prepare all cells with their initial state.
257 // If we're only after writing out the full BGB we don't need all this shebang EXCEPT the weights!
258
259 // Initial state based on project, background field in all cells
260 // and other initial values in non-sysboundary cells
261 phiprof::Timer applyInitialTimer {"Apply initial state"};
262 // Go through every cell on this node and initialize the
263 // -Background field on all cells
264 // -Perturbed fields and ion distribution function in non-sysboundary cells
265 // Each initialization has to be independent to avoid threading problems
266
267 // Allow the project to set up data structures for it's setCell calls
268 project.setupBeforeSetCell(cells);
269
270 phiprof::Timer setCellTimer {"setCell"};
271 #pragma omp parallel for schedule(dynamic)
272 for (size_t i = 0; i < cells.size(); ++i) {
273 SpatialCell* cell = mpiGrid[cells[i]];
275 project.setCell(cell);
276 }
277 }
278 setCellTimer.stop();
279
280 // Initial state for sys-boundary cells
281 sysBoundaries.applyInitialState(mpiGrid, technical.view(), fsgrid, perb.view(), bgb.view(), project);
282
283 #pragma omp parallel for schedule(static)
284 for (size_t i = 0; i < cells.size(); ++i) {
285 mpiGrid[cells[i]]->parameters[CellParams::LBWEIGHTCOUNTER] = 0;
286 }
287
288 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
289 adjustVelocityBlocks(mpiGrid, cells, true, popID);
290 // set initial LB metric based on number of blocks
291 #pragma omp parallel for schedule(static)
292 for (size_t i = 0; i < cells.size(); ++i) {
293 SpatialCell* SC = mpiGrid[cells[i]];
297 // Set sysb cells to a small weight
299 } else {
301 }
302 }
303 }
304
305 shrink_to_fit_grid_data(mpiGrid); // get rid of excess data already here
306
307 /*
308 // Apply boundary conditions so that we get correct initial moments
309 sysBoundaries.applySysBoundaryVlasovConditions(mpiGrid,Parameters::t);
310 //compute moments, and set them in RHO* and RHO_*_DT2. If restart, they are already read in
311 phiprof::Timer initMomentsTimer {"Init moments"};
312 calculateInitialVelocityMoments(mpiGrid);
313 initMomentsTimer.stop();
314 */
315
316 } else if (P::writeFullBGB) {
317 // If, instead of starting a regular simulation, we are only writing out the background field, it is enough to set a dummy load balance value of 1 here.
318 for (size_t i = 0; i < cells.size(); ++i) {
319 mpiGrid[cells[i]]->parameters[CellParams::LBWEIGHTCOUNTER] = 1;
320 }
321 }
322
323 // Balance load before we transfer all data below
324 balanceLoad(mpiGrid, sysBoundaries, technical.view(), fsgrid, false);
325 // Function includes re-calculation of local cells cache, but
326 // setting third parameter to false skips preparation of
327 // translation cell lists and building of pencils.
328
329 phiprof::Timer fetchNeighbourTimer {"Fetch Neighbour data", {"MPI"}};
330 // update complete cell spatial data for full stencil
332 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::FULL);
333 fetchNeighbourTimer.stop();
334
335 phiprof::Timer setBTimer {"project.setProjectBField"};
336 project.setProjectBField(perb.view(), bgb.view(), technical.view(), fsgrid);
337 setBTimer.stop();
338 if (P::isRestart) {
339 // There are projects that have non-uniform and non-zero perturbed B, e.g. Magnetosphere with dipole type 4.
340 // If restarting with reapplyUponRestart active, we need to set PerB again
341 // in boundary cells after setProjectBField has populated the BGBXVDCORR etc. terms
342 sysBoundaries.applyInitialState(mpiGrid, technical.view(), fsgrid, perb.view(), bgb.view(), project);
343 }
344 phiprof::Timer fsGridGhostTimer {"fsgrid-ghost-updates"};
345 fsgrid.updateGhostCells(perb.view());
346 fsgrid.updateGhostCells(bgb.view());
347 fsgrid.updateGhostCells(e.view());
348
349 // This will only have the BGB set up properly at this stage but we need the BGBvol for the Vlasov boundaries below.
350 fsgrid.updateGhostCells(vol.view());
351 fsGridGhostTimer.stop();
352 phiprof::Timer getFieldsTimer {"getFieldsFromFsGrid"};
353 getFieldsFromFsGrid(vol.view(), bgb.view(), egradpe.view(), dmoments.view(), technical.view(), fsgrid, mpiGrid, cells);
354 getFieldsTimer.stop();
355
356 setBTimer.stop();
357
358 // If we only want the full BGB for writeout, we have it now and we can return early.
359 if (P::writeFullBGB == true) {
360 return;
361 }
362
363 if (P::isRestart == false) {
364 // Apply boundary conditions so that we get correct initial moments
365 sysBoundaries.applySysBoundaryVlasovConditions(mpiGrid,Parameters::t, true); // It doesn't matter here whether we put _R or _V moments
366
367 //compute moments, and set them in RHO* and RHO_*_DT2. If restart, they are already read in
368 phiprof::Timer timer {"Init moments"};
370 } else {
371 phiprof::Timer timer {"Init moments"};
372 #pragma omp parallel for schedule(guided,1)
373 for (size_t i = 0; i < cells.size(); ++i) {
374 // easier to skip here than adding one more bool flag to calculateCellMoments - handles L2 outflow cells without VDF
375 if (mpiGrid[cells[i]]->sysBoundaryFlag == sysboundarytype::OUTFLOW && mpiGrid[cells[i]]->sysBoundaryLayer != 1) {
376 continue;
377 }
378 calculateCellMoments(mpiGrid[cells[i]], true, true);
379 }
380 }
381
382
383 phiprof::Timer finishFSGridTimer {"Finish fsgrid setup"};
384 feedMomentsIntoFsGrid(mpiGrid, cells, moments, technical.view(), fsgrid, false);
385 if (!P::isRestart) {
386 // WARNING this means moments and dt2 moments are the same here at t=0, which is a feature so far.
387 feedMomentsIntoFsGrid(mpiGrid, cells, momentsdt2, technical.view(), fsgrid, false);
388 } else {
389 feedMomentsIntoFsGrid(mpiGrid, cells, momentsdt2, technical.view(), fsgrid, true);
390 }
391 fsgrid.updateGhostCells(moments.view());
392 fsgrid.updateGhostCells(momentsdt2.view());
393 finishFSGridTimer.stop();
394
395 // Set this so CFL doesn't break
396 if (P::refineOnRestart) {
397 // Half-step acceleration
399 calculateAcceleration(mpiGrid, -0.5*P::dt + 0.5*P::bailout_min_dt);
400 } else {
401 calculateAcceleration(mpiGrid, 0.0);
402 }
404 }
405
406 // With all cell data in place, make preparations for translation
407 prepareAMRLists(mpiGrid);
408 initialStateTimer.stop();
409}
410
411void initSpatialCellCoordinates(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
412 vector<CellID> cells = mpiGrid.get_cells();
413 #pragma omp parallel for
414 for (size_t i = 0; i < cells.size(); ++i) {
415 std::array<double, 3> cell_min = mpiGrid.geometry.get_min(cells[i]);
416 std::array<double, 3> cell_length = mpiGrid.geometry.get_length(cells[i]);
417
418 mpiGrid[cells[i]]->parameters[CellParams::XCRD] = cell_min[0];
419 mpiGrid[cells[i]]->parameters[CellParams::YCRD] = cell_min[1];
420 mpiGrid[cells[i]]->parameters[CellParams::ZCRD] = cell_min[2];
421 mpiGrid[cells[i]]->parameters[CellParams::DX ] = cell_length[0];
422 mpiGrid[cells[i]]->parameters[CellParams::DY ] = cell_length[1];
423 mpiGrid[cells[i]]->parameters[CellParams::DZ ] = cell_length[2];
424
425 mpiGrid[cells[i]]->parameters[CellParams::CELLID] = cells[i];
426 mpiGrid[cells[i]]->parameters[CellParams::REFINEMENT_LEVEL] = mpiGrid.get_refinement_level(cells[i]);
427 }
428}
429
430/*
431Record for each cell which processes own one or more of its face neighbors
432 */
433void setFaceNeighborRanks(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
434
435 const vector<CellID>& cells = getLocalCells();
436 // TODO: Try a #pragma omp parallel for
437 for (const auto& cellid : cells) {
438
439 if (cellid == INVALID_CELLID) continue;
440
441 SpatialCell* cell = mpiGrid[cellid];
442
443 if (!cell) continue;
444
445 cell->face_neighbor_ranks.clear();
446
447 for (const auto& [neighbor, dir] : mpiGrid.get_face_neighbors_of(cellid)) {
448
449 int neighborhood;
450
451 // We store rank numbers into a map that has neighborhood ids as its key values.
452
453 switch (dir) {
454 case -3:
455 neighborhood = Neighborhoods::SHIFT_M_Z;
456 break;
457 case -2:
458 neighborhood = Neighborhoods::SHIFT_M_Y;
459 break;
460 case -1:
461 neighborhood = Neighborhoods::SHIFT_M_X;
462 break;
463 case +1:
464 neighborhood = Neighborhoods::SHIFT_P_X;
465 break;
466 case +2:
467 neighborhood = Neighborhoods::SHIFT_P_Y;
468 break;
469 case +3:
470 neighborhood = Neighborhoods::SHIFT_P_Z;
471 break;
472 default:
473 cerr << "Invalid face neighbor dimension: " << dir << " in " << __FILE__ << ":" << __LINE__ << std::endl;
474 abort();
475 }
476
477 cell->face_neighbor_ranks[neighborhood].insert(mpiGrid.get_process(neighbor));
478
479 }
480 }
481}
482
483inline uint64_t get_transfer_part(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid, uint64_t num_part_transfers, CellID cell)
484{
485 // Siblings transfer in same part
486 return (mpiGrid.mapping.get_refinement_level(cell) ? mpiGrid.mapping.get_parent(cell) : cell) % num_part_transfers;
487}
488
489// TODO bool here is kinda stupid but less janky than function pointer
490void transferInParts(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid, std::vector<CellID>& incoming_cells_list, std::vector<CellID>& outgoing_cells_list, bool refinement = false)
491{
492 phiprof::Timer transfersTimer {"Data transfers"};
493 const vector<CellID>& cells = getLocalCells();
494
495 // Idea: do as many cell sending passes hereafter so that there's not more than transfer_block_fraction_limit
496 // blocks of this task's total block count that gets sent. Helps in reducing memory peaks during load balancing.
497 creal transfer_block_fraction_limit = 0.1;
498 uint64_t num_part_transfers_local = 1, num_part_transfers, outgoing_block_count = 0, total_block_count = 0;
499 bool count_determined = false;
500 Real outgoing_block_fraction;
501
502 // count blocks
503 for (unsigned int i = 0; i < outgoing_cells_list.size(); i++) {
504 CellID cell_id=outgoing_cells_list[i];
505 SpatialCell* cell = mpiGrid[cell_id];
506 outgoing_block_count += cell->get_number_of_all_velocity_blocks();
507 }
508 for (unsigned int i = 0; i < cells.size(); i++) {
509 CellID cell_id=cells[i];
510 SpatialCell* cell = mpiGrid[cell_id];
511 total_block_count += cell->get_number_of_all_velocity_blocks();
512 }
513 outgoing_block_fraction = (Real)outgoing_block_count / ((Real)total_block_count + 1);
514 // if we're not exceeding transfer_block_fraction_limit we're good
515 if (outgoing_block_fraction < transfer_block_fraction_limit) {
516 count_determined = true;
517 }
518 // otherwise we increase the number of chunks until all chunks are below transfer_block_fraction_limit
519 while(!count_determined) {
520 uint64_t transfer_part; // we use this in the logic after the for
521 for (transfer_part=0; transfer_part<num_part_transfers_local; transfer_part++) {
522 uint64_t transfer_part_block_count=0;
523 for (unsigned int i = 0; i < outgoing_cells_list.size();i++){
524 CellID cell_id=outgoing_cells_list[i];
525 if (get_transfer_part(mpiGrid, num_part_transfers_local, cell_id) == transfer_part) {
526 transfer_part_block_count += mpiGrid[cell_id]->get_number_of_all_velocity_blocks();
527 }
528 }
529 outgoing_block_fraction = (Real)transfer_part_block_count / ((Real)total_block_count + 1);
530 if (outgoing_block_fraction > transfer_block_fraction_limit) {
531 num_part_transfers_local *= 2;
532 break; // out of for
533 }
534 }
535 if ((transfer_part == num_part_transfers_local // either the loop ended or we hit that number with the *= 2
536 && outgoing_block_fraction <= transfer_block_fraction_limit) // so cross-check with this
537 || num_part_transfers_local >= cells.size()) {
538 count_determined = true; // we got a break out if any chunk was still too big
539 }
540 }
541 // ...and finally we reduce this across all tasks of course.
542 MPI_Allreduce(&num_part_transfers_local, &num_part_transfers, 1, MPI_UINT64_T, MPI_MAX, MPI_COMM_WORLD);
543
544 for (uint64_t transfer_part=0; transfer_part<num_part_transfers; transfer_part++) {
545 //Set transfers on/off for the incoming cells in this transfer set and prepare for receive
546 for (const CellID& cell_id : incoming_cells_list) {
547 SpatialCell* cell = mpiGrid[cell_id];
548 if (get_transfer_part(mpiGrid, num_part_transfers, cell_id) != transfer_part) {
549 cell->set_mpi_transfer_enabled(false);
550 } else {
551 cell->set_mpi_transfer_enabled(true);
552 }
553 }
554
555 //Set transfers on/off for the outgoing cells in this transfer set
556 for (const CellID cell_id : outgoing_cells_list) {
557 SpatialCell* cell = mpiGrid[cell_id];
558 if (get_transfer_part(mpiGrid, num_part_transfers, cell_id) != transfer_part) {
559 cell->set_mpi_transfer_enabled(false);
560 } else {
561 cell->set_mpi_transfer_enabled(true);
562 }
563 }
564
565 for (size_t popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
566 // Set active population
568
569 // Transfer velocity block lists. On-device GPU mesh preparation tasks require
570 // device synchronization between transfer phases.
572 if (!refinement) {
573 mpiGrid.continue_balance_load();
574 } else {
575 mpiGrid.continue_refining();
576 }
577 #ifdef USE_GPU
579 #endif
581 if (!refinement) {
582 mpiGrid.continue_balance_load();
583 } else {
584 mpiGrid.continue_refining();
585 }
586 #ifdef USE_GPU
588 #endif
589
590 int prepareReceives {phiprof::initializeTimer("Preparing receives")};
591 int receives = 0;
592 #pragma omp parallel for schedule(guided)
593 for (const CellID cell_id : incoming_cells_list) {
594 SpatialCell* cell = mpiGrid[cell_id];
595 if (get_transfer_part(mpiGrid, num_part_transfers, cell_id) == transfer_part) {
596 receives++;
597 // reserve space for velocity block data in arriving remote cells
598 phiprof::Timer timer {prepareReceives};
599 cell->prepare_to_receive_blocks(popID);
600 timer.stop(1, "Spatial cells");
601 }
602 }
603 if (receives == 0) {
604 //empty phiprof timer, to avoid unneccessary divergence in unique
605 //profiles (keep order same)
606 phiprof::Timer timer {prepareReceives};
607 timer.stop(0, "Spatial cells");
608 }
609
610 //do the actual transfer of data for the set of cells to be transferred
611 phiprof::Timer transferTimer {"transfer_all_data"};
613 if (!refinement) {
614 mpiGrid.continue_balance_load();
615 } else {
616 mpiGrid.continue_refining();
617 }
618 transferTimer.stop();
619
620 // Free memory for cells that have been sent (the block data)
621 for (const CellID cell_id : outgoing_cells_list){
622 SpatialCell* cell = mpiGrid[cell_id];
623
624 // Free memory of this cell as it has already been transferred,
625 // it will not be used anymore. NOTE: Only clears memory allocated
626 // to the active population.
627 if (get_transfer_part(mpiGrid, num_part_transfers, cell_id) == transfer_part) {
628 cell->clear(popID, true);
629 }
630 }
631
632 if (refinement) {
633 // Old cells removed by refinement
634 phiprof::Timer copyParentsTimer {"copy to parents"};
635 std::set<CellID> processed;
636 for (CellID id : mpiGrid.get_removed_cells()) {
637 if (get_transfer_part(mpiGrid, num_part_transfers, id) == transfer_part) {
638 CellID parent = mpiGrid.get_existing_cell(mpiGrid.get_center(id));
639 if (!processed.count(parent)) {
640 std::vector<CellID> children = mpiGrid.get_all_children(parent);
641 // Make sure cell contents aren't garbage
642 *mpiGrid[parent] = *mpiGrid[id];
643
644 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
645 SBC::averageCellData(mpiGrid, children, mpiGrid[parent], popID, 1);
646 }
647
648 // Averaging moments
649 calculateCellMoments(mpiGrid[parent], true, false);
650
651 processed.insert(parent);
652
653 for (const CellID child : children) {
654 mpiGrid[child]->clear(popID, true);
655 }
656 }
657 }
658 }
659 copyParentsTimer.stop(processed.size(), "Spatial cells");
660 }
661
662 memory_purge(); // Purge jemalloc allocator to actually release memory
663 } // for-loop over populations
664 } // for-loop over transfer parts
665
666 // Re-enable transfer for received cells
667 for (const CellID cell_id : incoming_cells_list) {
668 mpiGrid[cell_id]->set_mpi_transfer_enabled(true);
669 }
670}
671
672void balanceLoad(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid, SysBoundary& sysBoundaries, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, bool doTranslationLists) {
673 // Invalidate cached cell lists
675
676 // tell other processes which velocity blocks exist in remote spatial cells
677 phiprof::Timer balanceLoadTimer {"Balancing load", {"Load balance"}};
678
679 phiprof::Timer deallocTimer {"deallocate boundary data"};
680 //deallocate blocks in remote cells to decrease memory load
682 deallocTimer.stop();
683
684 // set weights based on each cells LB weight counter
685 const vector<CellID>& cells = getLocalCells();
686 for (size_t i = 0; i < cells.size(); ++i){
687 // Set cell weight. We could use different counters or number of blocks if different solvers are active.
688 // if (P::propagateVlasovAcceleration)
689 // When using the FS-SPLIT functionality, Jaro Hokkanen reported issues with using the regular
690 // CellParams::LBWEIGHTCOUNTER, so use of blockscounts + 1 might be required.
691 mpiGrid.set_cell_weight(cells[i], (Real)1 + mpiGrid[cells[i]]->parameters[CellParams::LBWEIGHTCOUNTER]);
692 }
693
694 phiprof::Timer initLBTimer {"dccrg.initialize_balance_load"};
695 mpiGrid.initialize_balance_load(true);
696 initLBTimer.stop();
697
698 const std::unordered_set<CellID>& incoming_cells = mpiGrid.get_cells_added_by_balance_load();
699 std::vector<CellID> incoming_cells_list (incoming_cells.begin(),incoming_cells.end());
700
701 const std::unordered_set<CellID>& outgoing_cells = mpiGrid.get_cells_removed_by_balance_load();
702 std::vector<CellID> outgoing_cells_list (outgoing_cells.begin(),outgoing_cells.end());
703
704 /*transfer cells in parts to preserve memory*/
705 transferInParts(mpiGrid, incoming_cells_list, outgoing_cells_list);
706
707 //finish up load balancing
708 phiprof::Timer finishLBTimer {"dccrg.finish_balance_load"};
709 mpiGrid.finish_balance_load();
710 finishLBTimer.stop();
711
712 // TODO might not be required with transferInParts changes
713 // Make sure transfers are enabled for all cells
715 #pragma omp parallel for
716 for (uint i = 0; i < cells.size(); ++i) {
717 mpiGrid[cells[i]]->set_mpi_transfer_enabled(true);
718 }
719
720 // recompute coupling of grids after load balance
721 computeCoupling(mpiGrid, cells, fsgrid, technical);
722
723 // Communicate all spatial data for FULL neighborhood, which
724 // includes all data with the exception of dist function data
726 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::FULL);
727
728 phiprof::Timer updateBlocksTimer {"update block lists"};
729 // new partition, re/initialize blocklists of remote cells.
730 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
733 } else {
734 updateRemoteVelocityBlockLists(mpiGrid, popID);
735 }
736 }
737 updateBlocksTimer.stop();
738
739 phiprof::Timer updateBoundariesTimer {"update sysboundaries"};
740 sysBoundaries.updateSysBoundariesAfterLoadBalance(mpiGrid);
741 updateBoundariesTimer.stop();
742
743 // Prepare ghost translation cell lists and build pencils for translation.
744 if (doTranslationLists) {
745 prepareAMRLists(mpiGrid);
746 }
747
748 // Record ranks of face neighbors for translation remote neighbor contribution
750 phiprof::Timer timer {"set face neighbor ranks"};
751 setFaceNeighborRanks(mpiGrid);
752 }
753
754#ifdef USE_GPU
755 phiprof::Timer gpuReservationsTimer("GPU LB set cell reservations");
756 uint gpuMaxBlockCount = 0;
757 vmesh::LocalID gpuBlockCount = 0;
758 // Not parallelized
759 const vector<CellID>& newCells = getLocalCells();
760 const uint newCellsSize = newCells.size();
761 const std::vector<CellID>& remote_cells = mpiGrid.get_remote_cells_on_process_boundary(Neighborhoods::FULL);
762 for (uint i = 0; i < newCellsSize+remote_cells.size(); ++i) {
763 SpatialCell* SC;
764 if (i < newCells.size()) {
765 SC = mpiGrid[newCells[i]];
766 } else {
767 SC = mpiGrid[remote_cells[i - newCells.size()]];
768 }
769 for (size_t popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
770 const vmesh::VelocityMesh* vmesh = SC->get_velocity_mesh(popID);
771 vmesh::VelocityBlockContainer* blockContainer = SC->get_velocity_blocks(popID);
772 gpuBlockCount = vmesh->size();
773 if (gpuBlockCount > gpuMaxBlockCount) {
774 gpuMaxBlockCount = gpuBlockCount;
775 }
776 // Ensure cell has sufficient reservation, then apply it
777 SC->setReservation(popID,gpuBlockCount);
778 SC->applyReservation(popID);
779 SC->dev_upload_population(popID);
780 }
781 }
783 gpuReservationsTimer.stop();
784 // Call GPU routines for memory allocation for Vlasov solvers
785 // deallocates first if necessary
786 phiprof::Timer gpuAllocationsTimer("GPU LB set buffer allocations");
787 gpu_vlasov_allocate(gpuMaxBlockCount);
788 gpu_calculateProbeAllocation(gpuMaxBlockCount);
789 gpu_acc_allocate(gpuMaxBlockCount);
790 gpuAllocationsTimer.stop();
791#endif // end USE_GPU
792
793}
794
795/* helper for calculating AMR cell lists and building pencils
796 */
797void prepareAMRLists(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
798 // AMR translation lists are used also for non-AMR simulations in GPU mode
800 phiprof::Timer ghostTimer {"prepare_ghost_translation_lists"};
801
802 // Update (face and other) neighbor information for remote cells on boundary
803 phiprof::Timer updateRemoteNeighborsTimer {"update neighbor lists of remote cells"};
804 const vector<CellID> remote_cells = mpiGrid.get_remote_cells_on_process_boundary(Neighborhoods::VLASOV_SOLVER_GHOST_REQNEIGH);
805 // const vector<CellID> remote_cells = mpiGrid.get_remote_cells_on_process_boundary(Neighborhoods::VLASOV_SOLVER_GHOST);
806 mpiGrid.force_update_cell_neighborhoods(remote_cells);
807 updateRemoteNeighborsTimer.stop();
808
809 phiprof::Timer ghostListsTimer {"update active cell lists for ghost translation"};
810 const vector<CellID>& localCells = getLocalCells();
811 prepareGhostTranslationCellLists(mpiGrid, localCells);
812 ghostListsTimer.stop();
813
814 phiprof::Timer barrierTimer {"MPI barrier"};
815 MPI_Barrier(MPI_COMM_WORLD);
816 barrierTimer.stop();
817
818 ghostTimer.stop();
819 }
820
821 // Prepare cellIDs and pencils for AMR translation
823}
824
825/*
826 Adjust sparse velocity space to make it consistent in all 6 dimensions.
827
828 Further documentation in grid.h
829*/
830bool adjustVelocityBlocks(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
831 const vector<CellID>& cellsToAdjust,
832 bool doPrepareToReceiveBlocks,
833 const uint popID) {
834 phiprof::Timer readjustBlocksTimer {"re-adjust blocks", {"Block adjustment"}};
836
837 // Only adjust simulation cells
838 vector<CellID> validCells;
839 for (CellID cid: cellsToAdjust) {
840 SpatialCell *SC = mpiGrid[cid];
842 validCells.push_back(cid);
843 }
844 }
845
846 // Batch call
847 update_velocity_block_content_lists(mpiGrid,validCells, popID);
848
849 // Get updated lists for blocks with content in spatial neighbours
850 phiprof::Timer transferTimer {"Transfer with_content_list", {"MPI"}};
852 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::NEAREST);
854 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::NEAREST);
855 transferTimer.stop();
856
857 // Batch adjusts velocity blocks in local spatial cells, doesn't adjust velocity blocks in remote cells.
858 adjust_velocity_blocks_in_cells(mpiGrid, validCells, popID);
859
860 // prepare to receive full block data for all cells (irrespective of list of cells to adjust)
861 if (doPrepareToReceiveBlocks) {
864 } else {
865 updateRemoteVelocityBlockLists(mpiGrid, popID);
866 }
867 }
868 return true;
869}
870
874void shrink_to_fit_grid_data(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
875 const std::vector<CellID>& cells = getLocalCells();
876 const std::vector<CellID>& remote_cells = mpiGrid.get_remote_cells_on_process_boundary();
877 #pragma omp parallel for
878 for (size_t i = 0; i < cells.size() + remote_cells.size(); ++i) {
879 if (i < cells.size()) {
880 SpatialCell* target = mpiGrid[cells[i]];
881 if (target != nullptr) {
882 target->shrink_to_fit();
883 }
884 } else {
885 SpatialCell* target= mpiGrid[remote_cells[i - cells.size()]];
886 if (target != nullptr) {
887 target->shrink_to_fit();
888 }
889 }
890 }
891 // #ifdef USE_GPU
892 // // Synchronize all streams, if shrink_to_fit was called and updated populations have been uploaded
893 // CHK_ERR( gpuDeviceSynchronize() );
894 // #endif
895 memory_purge(); // Purge jemalloc allocator to actually release memory
896}
897
902void deallocateRemoteCellBlocks(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
903 const std::vector<uint64_t> incoming_cells = mpiGrid.get_remote_cells_on_process_boundary();
904 for(unsigned int i = 0; i < incoming_cells.size();i++){
905 uint64_t cell_id=incoming_cells[i];
906 SpatialCell* cell = mpiGrid[cell_id];
907 if (cell != NULL) {
908 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID)
909 cell->clear(popID, true); // flag true shrinks allocation
910 }
911 }
912 memory_purge(); // Purge jemalloc allocator to actually release memory
913}
914
915/*
916Updates velocity block lists between remote neighbors and prepares local
917copies of remote neighbors for receiving velocity block data.
918*/
920 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
921 const uint popID,
922 const uint neighborhood/*=Neighborhoods::DIST_FUNC default*/
923)
924{
926
927 // update velocity block lists For small velocity spaces it is
928 // faster to do it in one operation, and not by first sending size,
929 // then list. For large we do it in two steps
930 phiprof::Timer updateTimer {"Velocity block list update", {"MPI"}};
932 mpiGrid.update_copies_of_remote_neighbors(neighborhood);
934 mpiGrid.update_copies_of_remote_neighbors(neighborhood);
935 updateTimer.stop();
936
937 // Prepare spatial cells for receiving velocity block data
938 phiprof::Timer receivesTimer {"Preparing receives"};
939 const std::vector<uint64_t> incoming_cells = mpiGrid.get_remote_cells_on_process_boundary(neighborhood);
940
941#ifndef USE_GPU
942 // TODO: using #pragma omp parallel for sometimes causes a deadlock somewhere
943 // inside this loop on GPUs. Underlying cause yet to be identified.
944 #pragma omp parallel for
945#endif
946 for (unsigned int i = 0; i < incoming_cells.size(); ++i) {
947 uint64_t cell_id = incoming_cells[i];
948 SpatialCell* cell = mpiGrid[cell_id];
949 if (cell == NULL) {
950 #ifdef DEBUG_VLASIATOR
951 for (const auto& cell: mpiGrid.local_cells) {
952 if (cell.id == cell_id) {
953 cerr << __FILE__ << ":" << __LINE__ << std::endl;
954 abort();
955 }
956 for (const auto& neighbor: cell.neighbors_of) {
957 if (neighbor.id == cell_id) {
958 cerr << __FILE__ << ":" << __LINE__ << std::endl;
959 abort();
960 }
961 }
962 }
963 #endif
964 continue;
965 }
966 cell->prepare_to_receive_blocks(popID);
967 }
968
969 receivesTimer.stop(incoming_cells.size(), "SpatialCells");
970}
971
972/*
973 Set stencils. These are the stencils (in 2D, real ones in 3D of
974 course). x are stencil neighbor to cell local cell o:
975
976NEAREST SYSBOUNDARIES (nearest neighbor)
977-----------
978 xxx
979 xox
980 xxx
981-----------
982
983EXTENDED_SYSBOUNDARIES (second nearest neighbor, also in diagonal)
984-----------
985 xxxxx
986 xxxxx
987 xxoxx
988 xxxxx
989 xxxxx
990-----------
991
992VLASOV
993-----------
994 x
995 x
996 xxoxx
997 x
998 x
999-----------
1000
1001VLASOV_{XYZ}
1002-----------
1003 xxoxxx
1004-----------
1005
1006VLASOV_TARGET_{XYZ}
1007-----------
1008 xox
1009
1010-----------
1011
1012DIST_FUNC (Includes all cells which should know about each others blocks and have space for them. VLASOV + SYSBOUNDARIES.
1013-----------
1014 x
1015 xxx
1016 xxoxx
1017 xxx
1018 x
1019
1020-----------
1021
1022
1023FULL (Includes all possible communication)
1024-----------
1025 xxxxx
1026 xxxxx
1027 xxoxx
1028 xxxxx
1029 xxxxx
1030-----------
1031
1032SHIFT_M_X ox
1033SHIFT_P_X xo
1034 Y, Z in the same way
1035*/
1036
1037void initializeStencils(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid){
1038 // set reduced neighborhoods
1039 typedef dccrg::Types<3>::neighborhood_item_t neigh_t;
1040
1041 // set a reduced neighborhood for nearest neighbours
1042 std::vector<neigh_t> neighborhood;
1043 for (int z = -1; z <= 1; z++) {
1044 for (int y = -1; y <= 1; y++) {
1045 for (int x = -1; x <= 1; x++) {
1046 if (x == 0 && y == 0 && z == 0) {
1047 continue;
1048 }
1049 neigh_t offsets = {{x, y, z}};
1050 neighborhood.push_back(offsets);
1051 }
1052 }
1053 }
1054 if (!mpiGrid.add_neighborhood(Neighborhoods::NEAREST, neighborhood)){
1055 std::cerr << "Failed to add neighborhood Neighborhoods::NEAREST \n";
1056 abort();
1057 }
1058 if (!mpiGrid.add_neighborhood(Neighborhoods::SYSBOUNDARIES, neighborhood)){
1059 std::cerr << "Failed to add neighborhood Neighborhoods::SYSBOUNDARIES \n";
1060 abort();
1061 }
1062
1063 neighborhood.clear();
1064 for (int z = -2; z <= 2; z++) {
1065 for (int y = -2; y <= 2; y++) {
1066 for (int x = -2; x <= 2; x++) {
1067 if (x == 0 && y == 0 && z == 0) {
1068 continue;
1069 }
1070 neigh_t offsets = {{x, y, z}};
1071 neighborhood.push_back(offsets);
1072 }
1073 }
1074 }
1075 if (!mpiGrid.add_neighborhood(Neighborhoods::SYSBOUNDARIES_EXTENDED, neighborhood)){
1076 std::cerr << "Failed to add neighborhood Neighborhoods::SYSBOUNDARIES_EXTENDED \n";
1077 abort();
1078 }
1079
1080 int full_neighborhood_size = max(2, VLASOV_STENCIL_WIDTH);
1082 // One extra layer for translation of ghost cells
1083 full_neighborhood_size++;
1084 }
1085 neighborhood.clear();
1086 for (int z = -full_neighborhood_size; z <= full_neighborhood_size; z++) {
1087 for (int y = -full_neighborhood_size; y <= full_neighborhood_size; y++) {
1088 for (int x = -full_neighborhood_size; x <= full_neighborhood_size; x++) {
1089 if (x == 0 && y == 0 && z == 0) {
1090 continue;
1091 }
1092 neigh_t offsets = {{x, y, z}};
1093 neighborhood.push_back(offsets);
1094 }
1095 }
1096 }
1097 /*all possible communication pairs*/
1098 if (!mpiGrid.add_neighborhood(Neighborhoods::FULL, neighborhood)){
1099 std::cerr << "Failed to add neighborhood Neighborhoods::FULL \n";
1100 abort();
1101 }
1102
1103 /*stencils for semilagrangian propagators*/
1104 neighborhood.clear();
1105 for (int d = -VLASOV_STENCIL_WIDTH; d <= VLASOV_STENCIL_WIDTH; d++) {
1106 if (d != 0) {
1107 neighborhood.push_back({{d, 0, 0}});
1108 neighborhood.push_back({{0, d, 0}});
1109 neighborhood.push_back({{0, 0, d}});
1110 }
1111 }
1112 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER, neighborhood)){
1113 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER \n";
1114 abort();
1115 }
1116
1117 // add remaining nearest neighbors for DIST_FUNC neighborhood
1118 for (int z = -1; z <= 1; z++) {
1119 for (int y = -1; y <= 1; y++) {
1120 for (int x = -1; x <= 1; x++) {
1121 //do not add cells already in neighborhood (vlasov solver)
1122 if (x == 0 && y == 0) continue;
1123 if (x == 0 && z == 0) continue;
1124 if (y == 0 && z == 0) continue;
1125 neigh_t offsets = {{x, y, z}};
1126 neighborhood.push_back(offsets);
1127 }
1128 }
1129 }
1130 if (!mpiGrid.add_neighborhood(Neighborhoods::DIST_FUNC, neighborhood)){
1131 std::cerr << "Failed to add neighborhood Neighborhoods::DIST_FUNC \n";
1132 abort();
1133 }
1134
1135 neighborhood.clear();
1136 for (int d = -VLASOV_STENCIL_WIDTH; d <= VLASOV_STENCIL_WIDTH; d++) {
1137 if (d != 0) {
1138 neighborhood.push_back({{d, 0, 0}});
1139 }
1140 }
1141 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_X, neighborhood)){
1142 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_X \n";
1143 abort();
1144 }
1145
1146 neighborhood.clear();
1147 for (int d = -VLASOV_STENCIL_WIDTH; d <= VLASOV_STENCIL_WIDTH; d++) {
1148 if (d != 0) {
1149 neighborhood.push_back({{0, d, 0}});
1150 }
1151 }
1152 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_Y, neighborhood)){
1153 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_Y \n";
1154 abort();
1155 }
1156
1157 neighborhood.clear();
1158 for (int d = -VLASOV_STENCIL_WIDTH; d <= VLASOV_STENCIL_WIDTH; d++) {
1159 if (d != 0) {
1160 neighborhood.push_back({{0, 0, d}});
1161 }
1162 }
1163 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_Z, neighborhood)){
1164 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_Z \n";
1165 abort();
1166 }
1167
1169 neighborhood.clear();
1170 for (int d = -VLASOV_STENCIL_WIDTH-1; d <= VLASOV_STENCIL_WIDTH+1; d++) {
1171 if (d != 0) {
1172 neighborhood.push_back({{d, 0, 0}});
1173 }
1174 }
1175 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_X_GHOST, neighborhood)){
1176 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_X_GHOST \n";
1177 abort();
1178 }
1179
1180 neighborhood.clear();
1181 for (int d = -VLASOV_STENCIL_WIDTH-1; d <= VLASOV_STENCIL_WIDTH+1; d++) {
1182 if (d != 0) {
1183 neighborhood.push_back({{0, d, 0}});
1184 }
1185 }
1186 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_Y_GHOST, neighborhood)){
1187 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_Y_GHOST \n";
1188 abort();
1189 }
1190
1191 neighborhood.clear();
1192 for (int d = -VLASOV_STENCIL_WIDTH-1; d <= VLASOV_STENCIL_WIDTH+1; d++) {
1193 if (d != 0) {
1194 neighborhood.push_back({{0, 0, d}});
1195 }
1196 }
1197 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_Z_GHOST, neighborhood)){
1198 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_Z_GHOST \n";
1199 abort();
1200 }
1201
1202 // Ghost translation required stencils
1203 neighborhood.clear();
1204 // First: full +GT stencil in Y (last direction to be translated)
1205 for (int dy = -VLASOV_STENCIL_WIDTH-1; dy <= VLASOV_STENCIL_WIDTH+1; dy++){
1206 if (dy != 0) {
1207 neighborhood.push_back({{0, dy, 0}});
1208 }
1209 }
1210 // Then: full + GT extensions in X from Y-translated cells
1212 for (int dx = -VLASOV_STENCIL_WIDTH-1; dx <= VLASOV_STENCIL_WIDTH+1; dx++){
1213 if (dx != 0) {
1214 neighborhood.push_back({{dx, dy, 0}});
1215 }
1216 }
1217 }
1218 // Then: full + GT extensions in Z from Y->X translated cells
1221 for (int dz = -VLASOV_STENCIL_WIDTH-1; dz <= VLASOV_STENCIL_WIDTH+1; dz++){
1222 if (dz != 0) {
1223 neighborhood.push_back({{dx, dy, dz}});
1224 }
1225 }
1226 }
1227 }
1228 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_GHOST, neighborhood)){
1229 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_GHOST \n";
1230 abort();
1231 }
1232
1233 // Ghost translation neighbourhood where we need to have neighbour information
1234 neighborhood.clear();
1235 for (int dy = -(int)P::vlasovSolverGhostTranslateExtent; dy <= (int)P::vlasovSolverGhostTranslateExtent; dy++){
1237 for (int dz = -(int)P::vlasovSolverGhostTranslateExtent; dz <= (int)P::vlasovSolverGhostTranslateExtent; dz++){
1238 if ((dz==0) && (dy==0) && (dx==0)) {
1239 continue;
1240 }
1241 neighborhood.push_back({{dx, dy, dz}});
1242 }
1243 }
1244 }
1245 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_GHOST_REQNEIGH, neighborhood)){
1246 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_GHOST_REQNEIGH \n";
1247 abort();
1248 }
1249 }
1250
1251 neighborhood.clear();
1252 for (int d = -1; d <= 1; d++) {
1253 if (d != 0) {
1254 neighborhood.push_back({{d, 0, 0}});
1255 }
1256 }
1257 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_TARGET_X, neighborhood)){
1258 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_TARGET_X \n";
1259 abort();
1260 }
1261
1262 neighborhood.clear();
1263 for (int d = -1; d <= 1; d++) {
1264 if (d != 0) {
1265 neighborhood.push_back({{0, d, 0}});
1266 }
1267 }
1268 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_TARGET_Y, neighborhood)){
1269 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_TARGET_Y \n";
1270 abort();
1271 }
1272
1273 neighborhood.clear();
1274 for (int d = -1; d <= 1; d++) {
1275 if (d != 0) {
1276 neighborhood.push_back({{0, 0, d}});
1277 }
1278 }
1279 if (!mpiGrid.add_neighborhood(Neighborhoods::VLASOV_SOLVER_TARGET_Z, neighborhood)){
1280 std::cerr << "Failed to add neighborhood Neighborhoods::VLASOV_SOLVER_TARGET_Z \n";
1281 abort();
1282 }
1283
1284 neighborhood.clear();
1285 neighborhood.push_back({{1, 0, 0}});
1286 if (!mpiGrid.add_neighborhood(Neighborhoods::SHIFT_M_X, neighborhood)){
1287 std::cerr << "Failed to add neighborhood Neighborhoods::SHIFT_M_X \n";
1288 abort();
1289 }
1290 neighborhood.clear();
1291 neighborhood.push_back({{0, 1, 0}});
1292 if (!mpiGrid.add_neighborhood(Neighborhoods::SHIFT_M_Y, neighborhood)){
1293 std::cerr << "Failed to add neighborhood Neighborhoods::SHIFT_M_Y \n";
1294 abort();
1295 }
1296 neighborhood.clear();
1297 neighborhood.push_back({{0, 0, 1}});
1298 if (!mpiGrid.add_neighborhood(Neighborhoods::SHIFT_M_Z, neighborhood)){
1299 std::cerr << "Failed to add neighborhood Neighborhoods::SHIFT_M_Z \n";
1300 abort();
1301 }
1302 neighborhood.clear();
1303 neighborhood.push_back({{-1, 0, 0}});
1304 if (!mpiGrid.add_neighborhood(Neighborhoods::SHIFT_P_X, neighborhood)){
1305 std::cerr << "Failed to add neighborhood Neighborhoods::SHIFT_P_X \n";
1306 abort();
1307 }
1308 neighborhood.clear();
1309 neighborhood.push_back({{0, -1, 0}});
1310 if (!mpiGrid.add_neighborhood(Neighborhoods::SHIFT_P_Y, neighborhood)){
1311 std::cerr << "Failed to add neighborhood Neighborhoods::SHIFT_P_Y \n";
1312 abort();
1313 }
1314 neighborhood.clear();
1315 neighborhood.push_back({{0, 0, -1}});
1316 if (!mpiGrid.add_neighborhood(Neighborhoods::SHIFT_P_Z, neighborhood)){
1317 std::cerr << "Failed to add neighborhood Neighborhoods::SHIFT_P_Z \n";
1318 abort();
1319 }
1320}
1321
1322void mapRefinement(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid) {
1323 const auto maxRefLevel = mpiGrid.mapping.get_maximum_refinement_level();
1324 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
1325 phiprof::initializeTimer("Map Refinement Level to FsGrid"), technical,
1326 [=, &mpiGrid](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
1327 const std::array<fsgrid::FsSize_t, 3> mapIndices = coordinates.localToGlobal(stencil.i, stencil.j, stencil.k);
1328 const dccrg::Types<3>::indices_t indices = {
1329 {(uint64_t)mapIndices[0], (uint64_t)mapIndices[1], (uint64_t)mapIndices[2]}}; // cast to avoid warnings
1330 const CellID dccrgCellID2 =
1331 mpiGrid.get_existing_cell(indices, 0, maxRefLevel);
1332 const int amrLevel = mpiGrid.get_refinement_level(dccrgCellID2);
1333 technical[stencil.ooo()].refLevel = amrLevel;
1334 });
1335}
1336
1337bool adaptRefinement(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, SysBoundary& sysBoundaries, Project& project, int useStatic) {
1338 phiprof::Timer amrTimer {"Re-refine spatial cells"};
1339 uint64_t refines {0};
1340 if (useStatic > -1) {
1341 project.forceRefinement(mpiGrid, useStatic);
1342 } else {
1343 // Restarts don't have all the data needed to calculate indices so they are read directly
1344 if (P::tstep != P::tstep_min) {
1346 }
1348 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::NEAREST);
1349
1350 refines = project.adaptRefinement(mpiGrid);
1351 }
1352
1353 uint64_t cells {getLocalCells().size()};
1354 MPI_Allreduce(MPI_IN_PLACE, &refines, 1, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD);
1355 MPI_Allreduce(MPI_IN_PLACE, &cells, 1, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD);
1356 double ratio_refines = static_cast<double>(refines) / static_cast<double>(cells);
1357 logFile << "(AMR) Refining " << refines << " cells, " << 100.0 * ratio_refines << "% of grid" << std::endl;
1358
1359 phiprof::Timer dccrgTimer {"dccrg refinement"};
1360
1361 phiprof::Timer initTimer {"initialize refines"};
1362 mpiGrid.initialize_refines();
1363 initTimer.stop();
1364
1365 refines = mpiGrid.get_cells_to_refine_count();
1366 uint64_t coarsens {mpiGrid.get_cells_to_unrefine_count()};
1367 ratio_refines = static_cast<double>(refines) / static_cast<double>(cells);
1368 double ratio_coarsens = static_cast<double>(coarsens) / static_cast<double>(cells);
1369 logFile << "(AMR) Refining " << refines << " cells to " << refines*8 << " children after induces, " << 100.0 * ratio_refines << "% of grid" << std::endl;
1370 logFile << "(AMR) Coarsening " << coarsens << " cells to " << coarsens/8 << " parents after induces, " << 100.0 * ratio_coarsens << "% of grid" << std::endl;
1371
1372 double newBytes{0};
1373 phiprof::Timer estimateMemoryTimer {"Estimate memory usage"};
1374 for (auto id : mpiGrid.get_local_cells_to_refine()) {
1375 newBytes += 8 * mpiGrid[id]->get_cell_memory_capacity();
1376 }
1377
1378 // Rougher estimate than above
1379 // Unrefined cells have a transitive memory footprint since parent and children exist at same time
1380 for (auto id : mpiGrid.get_local_cells_to_unrefine()) {
1381 newBytes += mpiGrid[id]->get_cell_memory_capacity();
1382 }
1383
1384 report_memory_consumption(mpiGrid, newBytes);
1385 estimateMemoryTimer.stop();
1386
1387 logFile.flush(false);
1388
1389 // Bailout from estimate
1390 // clunky...
1391 int bailout {0};
1392 phiprof::Timer bailoutAllreduceTimer {"Bailout-allreduce"};
1393 MPI_Allreduce(&(globalflags::bailingOut), &bailout, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
1394 bailoutAllreduceTimer.stop();
1395
1396 if (bailout) {
1397 return false;
1398 }
1399
1400 // New cells created by refinement
1401 phiprof::Timer executeTimer {"execute refines"};
1402 auto newChildren = mpiGrid.execute_refines();
1403 executeTimer.stop();
1404
1405 // TODO surely this doesn't need a for loop
1406 std::vector<CellID> incoming_cells_list;
1407 for (auto const& [key, val] : mpiGrid.get_cells_to_receive()) {
1408 for (auto i : val) {
1409 incoming_cells_list.push_back(i.first);
1410 }
1411 }
1412
1413 std::vector<CellID> outgoing_cells_list;
1414 for (auto const& [key, val] : mpiGrid.get_cells_to_send()) {
1415 for (auto i : val) {
1416 outgoing_cells_list.push_back(i.first);
1417 }
1418 }
1419
1420 transferInParts(mpiGrid, incoming_cells_list, outgoing_cells_list, true);
1421
1422 phiprof::Timer copyChildrenTimer {"copy to children"};
1423 for (CellID id : newChildren) {
1424 *mpiGrid[id] = *mpiGrid[mpiGrid.get_parent(id)];
1425 // Irrelevant?
1426 mpiGrid[id]->parameters[CellParams::AMR_ALPHA1] /= 2.0;
1427 mpiGrid[id]->parameters[CellParams::AMR_ALPHA2] /= 2.0;
1428 mpiGrid[id]->parameters[CellParams::RECENTLY_REFINED] = 1;
1429 #ifdef USE_GPU
1430 for (size_t popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
1431 mpiGrid[id]->setReservation(popID,mpiGrid[id]->get_velocity_mesh(popID)->size());
1432 mpiGrid[id]->applyReservation(popID);
1433 }
1434 #endif
1435 }
1436 copyChildrenTimer.stop(newChildren.size(), "Spatial cells");
1437
1438 phiprof::Timer finishTimer {"finish refining"};
1439 mpiGrid.finish_refining();
1440 finishTimer.stop();
1441 dccrgTimer.stop();
1442
1443 memory_purge(); // Purge jemalloc allocator to actually release memory
1444
1447
1449 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::SYSBOUNDARIES);
1450
1451 mapRefinement(mpiGrid, technical, fsgrid);
1452
1453 const vector<CellID>& cellsVec = getLocalCells();
1454
1455 computeCoupling(mpiGrid, cellsVec, fsgrid, technical);
1456
1457 // Initialise system boundary conditions (they need the initialised positions!!)
1458 // This needs to be done before LB
1459 sysBoundaries.classifyCells(mpiGrid, technical, fsgrid);
1460
1463 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::VLASOV_SOLVER_GHOST);
1465 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::VLASOV_SOLVER_GHOST);
1466 } else {
1468 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::NEAREST);
1469 }
1470
1471 // Update as ghost cell refLevels may have changed
1472 fsgrid.updateGhostCells(technical);
1473 for (size_t popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
1475 }
1476
1477 if (P::shouldFilter) {
1478 project.filterRefined(mpiGrid);
1479 }
1480
1481 // ghost translation cell lists, build pencils
1482 prepareAMRLists(mpiGrid);
1483 return true;
1484}
1485
1486void recalculateLocalCellsCache(const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
1487 // Clear-and-minimize idiom for minimizing capacity
1488 // TODO: consider shrink_to_fit() or alternatively benchmark just copy assigning
1489 std::vector<CellID>().swap(Parameters::localCells);
1490 Parameters::localCells = mpiGrid.get_cells();
1491}
for i
Definition Dispersion.m:24
dx
Definition Dispersion.m:38
#define CHK_ERR(err)
#define gpuDeviceSynchronize
void calculateCellMoments(spatial_cell::SpatialCell *cell, const bool &computeSecond, const bool &computePopulationMomentsOnly, const bool &doNotSkip)
SysBoundary contains the SysBoundaryConditions used in the simulation.
Definition sysboundary.h:54
void initSysBoundaries(Project &project, creal &t)
Initialise all system boundary conditions actually used.
bool isPeriodic(uint direction) const
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)
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...
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)
virtual void setupBeforeSetCell(const std::vector< CellID > &cells)
Definition project.cpp:142
virtual bool forceRefinement(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, int n) const
Refine/unrefine spatial cells one level to the static criteria in the config.
Definition project.cpp:591
virtual uint64_t adaptRefinement(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid) const
Adapts refinement by one level according to the project. Returns true if any cells were refined,...
Definition project.cpp:516
virtual void setProjectBField(fsgrids::perbspan perb, fsgrids::bgbspan bgb, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid)
Definition project.cpp:127
virtual bool refineSpatialCells(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid) const
Definition project.cpp:354
virtual bool filterRefined(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid) const
Boxcar filters spatial cells that were recently refined.
Definition project.cpp:601
void setCell(spatial_cell::SpatialCell *cell)
Set the perturbed fields and distribution of a cell according to the default simulation settings....
Definition project.cpp:150
vmesh::LocalID get_number_of_velocity_blocks(const uint popID) const
vmesh::VelocityMesh * get_velocity_mesh(const size_t &popID)
vmesh::VelocityBlockContainer * get_velocity_blocks(const size_t &popID)
void dev_upload_population(const uint popID)
void set_mpi_transfer_enabled(bool transferEnabled)
static bool setCommunicatedSpecies(const uint popID)
void clear(const uint popID, bool shrink=false)
void prepare_to_receive_blocks(const uint popID)
vmesh::LocalID get_number_of_all_velocity_blocks() const
static void set_mpi_transfer_type(const uint64_t type, bool atSysBoundaries=false)
void applyReservation(const uint popID)
std::array< Real, CellParams::N_SPATIAL_CELL_PARAMS > parameters
void setReservation(const uint popID, const vmesh::LocalID reservationsize, bool force=false)
std::map< int, std::set< int > > face_neighbor_ranks
void bailout(const bool condition, const std::string &message, const char *const file, const int line)
A function to stop the simulation if the boolean condition is true. Raises a flag which gets MPI_Redu...
Definition common.cpp:36
const std::vector< CellID > & getLocalCells()
Definition main.cpp:39
#define MASTER_RANK
Definition common.h:67
void prepareGhostTranslationCellLists(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > &localPropagatedCells)
void prepareSeedIdsAndPencils(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
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
void calculateScaledDeltasSimple(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
High-level scaled gradient calculation wrapper function.
__host__ void gpu_acc_allocate(uint maxBlockCount)
Definition gpu_base.cpp:537
int myRank
Definition gpu_base.cpp:48
Logger logFile
Definition main.cpp:25
__host__ void gpu_calculateProbeAllocation(const uint maxBlockCount)
Definition gpu_base.cpp:359
__host__ void gpu_vlasov_allocate(const uint maxBlockCount)
Definition gpu_base.cpp:335
void deallocateRemoteCellBlocks(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:902
void initializeStencils(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:1037
void recalculateLocalCellsCache(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:1486
void initSpatialCellCoordinates(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:411
void writeVelMesh(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:73
bool adjustVelocityBlocks(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > &cellsToAdjust, bool doPrepareToReceiveBlocks, const uint popID)
Definition grid.cpp:830
bool adaptRefinement(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, SysBoundary &sysBoundaries, Project &project, int useStatic)
Definition grid.cpp:1337
void shrink_to_fit_grid_data(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:874
void initializeGrids(int argn, char **argc, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrid::FsData< std::array< Real, fsgrids::bfield::N_BFIELD > > &perb, fsgrid::FsData< std::array< Real, fsgrids::bgbfield::N_BGB > > &bgb, fsgrid::FsData< std::array< Real, fsgrids::moments::N_MOMENTS > > &moments, fsgrid::FsData< std::array< Real, fsgrids::moments::N_MOMENTS > > &momentsdt2, fsgrid::FsData< std::array< Real, fsgrids::dmoments::N_DMOMENTS > > &dmoments, fsgrid::FsData< std::array< Real, fsgrids::efield::N_EFIELD > > &e, fsgrid::FsData< std::array< Real, fsgrids::egradpe::N_EGRADPE > > &egradpe, fsgrid::FsData< std::array< Real, fsgrids::volfields::N_VOL > > &vol, fsgrid::FsData< fsgrids::technical > &technical, FieldSolverGrid &fsgrid, SysBoundary &sysBoundaries, Project &project)
Initialize DCCRG and fsgrids.
Definition grid.cpp:92
void transferInParts(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, std::vector< CellID > &incoming_cells_list, std::vector< CellID > &outgoing_cells_list, bool refinement=false)
Definition grid.cpp:490
void initVelocityGridGeometry(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
void mapRefinement(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid)
Definition grid.cpp:1322
void prepareAMRLists(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:797
void updateRemoteVelocityBlockLists(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const uint popID, const uint neighborhood)
Definition grid.cpp:919
void balanceLoad(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, SysBoundary &sysBoundaries, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, bool doTranslationLists)
Balance load.
Definition grid.cpp:672
void setFaceNeighborRanks(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:433
uint64_t get_transfer_part(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, uint64_t num_part_transfers, CellID cell)
Definition grid.cpp:483
void feedMomentsIntoFsGrid(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, fsgrid::FsData< std::array< Real, fsgrids::moments::N_MOMENTS > > &moments, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, bool dt2)
Definition gridGlue.cpp:165
void getFieldsFromFsGrid(fsgrids::constvolspan volumefields, fsgrids::constbgbspan bgb, fsgrids::constegradpespan egradpe, fsgrids::constdmomentsspan dmoments, fsgrids::consttechnicalspan technical, FieldSolverGrid &fsgrid, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells)
Definition gridGlue.cpp:257
void computeCoupling(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, fsgrid::FsGrid< STENCIL > &fsgrid, fsgrids::technicalspan technical)
Definition gridGlue.hpp:122
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
bool readFileCells(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::string &name)
Refine the grid to be identical to the file's.
Definition ioread.cpp:1964
bool readGrid(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::perbspan perb, fsgrids::efieldspan e, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, const std::string &name)
Read in state from a vlsv file in order to restart simulations.
Definition ioread.cpp:1951
bool writeVelocityDistributionData(const uint popID, Writer &vlsvWriter, const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, MPI_Comm comm)
Definition iowrite.cpp:161
Logger & writeVerbose(Logger &logger)
Definition logger.cpp:177
void report_memory_consumption(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, double extra_bytes)
void memory_purge()
@ REFINEMENT_LEVEL
Definition common.h:203
@ RECENTLY_REFINED
Definition common.h:224
@ AMR_ALPHA2
Definition common.h:221
@ AMR_ALPHA1
Definition common.h:220
@ LBWEIGHTCOUNTER
Definition common.h:198
@ SYSBOUNDARIES
Definition common.h:84
@ VLASOV_SOLVER_Z
Definition common.h:80
@ VLASOV_SOLVER_TARGET_X
Definition common.h:81
@ VLASOV_SOLVER_X
Definition common.h:78
@ VLASOV_SOLVER
Definition common.h:77
@ SYSBOUNDARIES_EXTENDED
Definition common.h:85
@ VLASOV_SOLVER_TARGET_Z
Definition common.h:83
@ VLASOV_SOLVER_Y_GHOST
Definition common.h:96
@ VLASOV_SOLVER_GHOST_REQNEIGH
Definition common.h:99
@ VLASOV_SOLVER_TARGET_Y
Definition common.h:82
@ VLASOV_SOLVER_Y
Definition common.h:79
@ VLASOV_SOLVER_GHOST
Definition common.h:98
@ VLASOV_SOLVER_X_GHOST
Definition common.h:95
@ VLASOV_SOLVER_Z_GHOST
Definition common.h:97
void averageCellData(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > cellList, SpatialCell *to, const uint popID, const creal fluffiness)
std::span< technical > technicalspan
Definition common.h:452
static const uint64_t REFINEMENT_PARAMETERS
static const uint64_t CELL_SYSBOUNDARYFLAG
static const uint64_t ALL_DATA
static const uint64_t VEL_BLOCK_LIST_STAGE2
static const uint64_t VEL_BLOCK_LIST_STAGE1
static const uint64_t VEL_BLOCK_WITH_CONTENT_STAGE1
static const uint64_t ALL_SPATIAL_DATA
static const uint64_t VEL_BLOCK_DATA
static const uint64_t VEL_BLOCK_WITH_CONTENT_STAGE2
static const uint64_t CELL_PARAMETERS
static const uint64_t CELL_DIMENSIONS
void adjust_velocity_blocks_in_cells(dccrg::Dccrg< spatial_cell::SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > &cellsToAdjust, const uint popID)
void update_velocity_block_content_lists(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< CellID > &cells, const uint popID)
uint32_t LocalID
Definition definitions.h:60
const uint64_t INVALID_CELLID
Definition parameters.h:35
std::vector< species::Species > particleSpecies
static Real t_min
Definition parameters.h:53
static Real dz_ini
Definition parameters.h:46
static Real dx_ini
Definition parameters.h:44
static bool shouldFilter
Definition parameters.h:195
static bool writeFullBGB
Definition parameters.h:118
static std::vector< CellID > localCells
Definition parameters.h:76
static uint zcells_ini
Definition parameters.h:50
static bool vlasovSolverGhostTranslate
Definition parameters.h:63
static int amrMaxSpatialRefLevel
Definition parameters.h:190
static bool refineOnRestart
Definition parameters.h:193
static std::map< std::string, std::string > loadBalanceOptions
Definition parameters.h:165
static Real ymin
Definition parameters.h:40
static std::string loadBalanceAlgorithm
Definition parameters.h:164
static bool meshRepartitioned
Definition parameters.h:75
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 std::string restartFileName
Definition parameters.h:175
static Real t
Definition parameters.h:52
static bool forceRefinement
Definition parameters.h:194
static uint tstep
Definition parameters.h:73
static bool isRestart
Definition parameters.h:176
static bool propagateVlasovAcceleration
Definition parameters.h:134
static uint vlasovSolverGhostTranslateExtent
Definition parameters.h:64
static Real zmin
Definition parameters.h:42
static Real bailout_min_dt
Definition parameters.h:186
static Real dy_ini
Definition parameters.h:45
static Real dt
Definition parameters.h:55
static int bailingOut
Definition common.h:538
static ARCH_HOSTDEV VecSimple< T > max(VecSimple< T > const &l, VecSimple< T > const &r)
void calculateAcceleration(const uint popID, const uint globalMaxSubcycles, const uint step, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &acceleratedCells, const Real dt)
void calculateInitialVelocityMoments(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Compute 0th, 1st and 2nd velocity moments (RHO,VX,VY,VZ,P_11,P_22,P_33 and *_DT2) for all cells in th...