Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
ioread.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 <cstdint>
24#include <numeric>
25#include <cstdlib>
26#include <iostream>
27#include <iomanip> // for setprecision()
28#include <cmath>
29#include <stdexcept>
30#include <vector>
31#include <sstream>
32#include <ctime>
33#include <array>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <span>
37#include <unordered_map>
38#include <unordered_set>
39
40#include "definitions.h"
41#include "mpi.h"
44#include "common.h"
45#include "ioread.h"
46#include "phiprof.hpp"
47#include "parameters.h"
48#include "logger.h"
50#include "vlsv_reader_parallel.h"
52#include "object_wrapper.h"
54#include "grid.h"
55
56using namespace std;
57using namespace phiprof;
58
60
61typedef Parameters P;
62
73 struct stat tempStat;
74 if (stat("STOP", &tempStat) == 0) {
75 bailout(true, "Received an external STOP command. Setting bailout.write_restart to true.");
77 char newName[80];
78 // Get the current time.
79 const time_t rawTime = time(NULL);
80 const struct tm* timeInfo = localtime(&rawTime);
81 strftime(newName, 80, "STOP_%F_%H-%M-%S", timeInfo);
82 rename("STOP", newName);
83 return;
84 }
85 if (stat("KILL", &tempStat) == 0) {
86 bailout(true, "Received an external KILL command. Setting bailout.write_restart to false.");
88 char newName[80];
89 // Get the current time.
90 const time_t rawTime = time(NULL);
91 const struct tm* timeInfo = localtime(&rawTime);
92 strftime(newName, 80, "KILL_%F_%H-%M-%S", timeInfo);
93 rename("KILL", newName);
94 return;
95 }
96 if(stat("SAVE", &tempStat) == 0) {
97 logFile << "Received an external SAVE command. Writing a restart file." << endl;
99 char newName[80];
100 // Get the current time.
101 const time_t rawTime = time(NULL);
102 const struct tm* timeInfo = localtime(&rawTime);
103 strftime(newName, 80, "SAVE_%F_%H-%M-%S", timeInfo);
104 rename("SAVE", newName);
105 return;
106 }
107 if(stat("DORC", &tempStat) == 0) {
108 logFile << "Received an external DORC command. Writing a recover file." << endl;
110 char newName[80];
111 // Get the current time.
112 const time_t rawTime = time(NULL);
113 const struct tm * timeInfo = localtime(&rawTime);
114 strftime(newName, 80, "DORC_%F_%H-%M-%S", timeInfo);
115 rename("DORC", newName);
116 return;
117 }
118 if(stat("DOLB", &tempStat) == 0) {
119 logFile << "Received an external DOLB command. Balancing load." << endl;
121 char newName[80];
122 // Get the current time.
123 const time_t rawTime = time(NULL);
124 const struct tm* timeInfo = localtime(&rawTime);
125 strftime(newName, 80, "DOLB_%F_%H-%M-%S", timeInfo);
126 rename("DOLB", newName);
127 return;
128 }
129 if(stat("DOMR", &tempStat) == 0) {
130 logFile << "Received an external DOMR command. Refining grid." << endl;
132 char newName[80];
133 // Get the current time.
134 const time_t rawTime = time(NULL);
135 const struct tm* timeInfo = localtime(&rawTime);
136 strftime(newName, 80, "DOMR_%F_%H-%M-%S", timeInfo);
137 rename("DOMR", newName);
138 return;
139 }
140}
141
152bool exitOnError(bool success, const string& message, MPI_Comm comm) {
153 int successInt;
154 int globalSuccessInt;
155 if (success)
156 successInt = 1;
157 else
158 successInt = 0;
159
160 MPI_Allreduce(&successInt, &globalSuccessInt, 1, MPI_INT, MPI_MIN, comm);
161
162 if (globalSuccessInt == 1) {
163 return true;
164 } else {
165 logFile << message << endl << write;
166 exit(1);
167 }
168}
169
178bool readCellIds(vlsv::ParallelReader& file, vector<CellID>& fileCells, const int masterRank, MPI_Comm comm) {
179 // Get info on array containing cell Ids:
180 uint64_t arraySize = 0;
181 uint64_t vectorSize;
182 vlsv::datatype::type dataType;
183 uint64_t byteSize;
184 list<pair<string, string>> attribs;
185 bool success = true;
186 int rank;
187 MPI_Comm_rank(comm, &rank);
188 if (rank == masterRank) {
189 const short int readFromFirstIndex = 0;
190 // let's let master read cellId's, we anyway have at max ~1e6 cells
191 attribs.push_back(make_pair("name", "CellID"));
192 attribs.push_back(make_pair("mesh", "SpatialGrid"));
193 if (file.getArrayInfoMaster("VARIABLE", attribs, arraySize, vectorSize, dataType, byteSize) == false) {
194 logFile << "(RESTART) ERROR: Failed to read cell ID array info!" << endl << write;
195 return false;
196 }
197
198 // Make a routine error check:
199 if (vectorSize != 1) {
200 logFile << "(RESTART) ERROR: Bad vectorsize at " << __FILE__ << " " << __LINE__ << endl << write;
201 return false;
202 }
203
204 // Read cell Ids:
205 char* IDbuffer = new char[arraySize * vectorSize * byteSize];
206 if (file.readArrayMaster("VARIABLE", attribs, readFromFirstIndex, arraySize, IDbuffer) == false) {
207 logFile << "(RESTART) ERROR: Failed to read cell Ids!" << endl << write;
208 success = false;
209 }
210
211 // Convert global Ids into our local DCCRG 64 bit uints
212 const uint64_t& numberOfCells = arraySize;
213 fileCells.resize(numberOfCells);
214 if (dataType == vlsv::datatype::type::UINT && byteSize == 4) {
215 uint32_t* ptr = reinterpret_cast<uint32_t*>(IDbuffer);
216 // Input cell ids
217 for (uint64_t i = 0; i < numberOfCells; ++i) {
218 const CellID cellID = ptr[i];
219 fileCells[i] = cellID;
220 }
221 } else if (dataType == vlsv::datatype::type::UINT && byteSize == 8) {
222 uint64_t* ptr = reinterpret_cast<uint64_t*>(IDbuffer);
223 for (uint64_t i = 0; i < numberOfCells; ++i) {
224 const CellID cellID = ptr[i];
225 fileCells[i] = cellID;
226 }
227 } else {
228 logFile << "(RESTART) ERROR: ParallelReader returned an unsupported datatype for cell Ids!" << endl << write;
229 success = false;
230 }
231 delete[] IDbuffer;
232 }
233
234 // broadcast cellId's to everybody
235 MPI_Bcast(&arraySize, 1, MPI_UINT64_T, masterRank, comm);
236 fileCells.resize(arraySize);
237 MPI_Bcast(&(fileCells[0]), arraySize, MPI_UINT64_T, masterRank, comm);
238
239 return success;
240}
241
242/* Read the total number of velocity blocks per spatial cell in the spatial mesh.
243 * The returned value for each cell is a sum of the velocity blocks associated in each particle species.
244 * The value is used to calculate an initial load balance after restart.
245 * @param file Some vlsv reader with a file open (can be old or new vlsv reader)
246 * @param nBlocks Vector for holding information on cells and the number of blocks in them -- this function saves data here
247 * @param masterRank The master rank of this process (Vlasiator uses masterRank = 0 and so it should be the default)
248 * @param comm MPI comm
249 * @return Returns true if the operation was successful
250 @ @see exec_readGrid
251*/
252bool readNBlocks(vlsv::ParallelReader& file, const std::string& meshName,
253 std::vector<size_t>& nBlocks, int masterRank, MPI_Comm comm) {
254 bool success = true;
255
256 // Get info on array containing cell IDs:
257 uint64_t arraySize;
258 uint64_t vectorSize;
259 vlsv::datatype::type dataType;
260 uint64_t byteSize;
261
262 // Read mesh bounding box to all processes, the info in bbox contains
263 // the number of spatial cells in the mesh.
264 // (This is *not* the physical coordinate bounding box.)
265 list<pair<string, string>> attribsIn;
266 map<string, string> attribsOut;
267 attribsIn.push_back(make_pair("mesh", meshName));
268
269 // Read number of domains and domain sizes
270 uint64_t N_domains;
271 file.getArrayAttributes("MESH_DOMAIN_SIZES", attribsIn, attribsOut);
272 auto it = attribsOut.find("arraysize");
273 if (it == attribsOut.end()) {
274 cerr << "VLSV\t\t ERROR: Array 'MESH_DOMAIN_SIZES' XML tag does not have attribute 'arraysize'" << endl;
275 return false;
276 } else {
277 N_domains = atoi(it->second.c_str());
278 }
279
280 uint64_t N_spatialCells = 0;
281 int64_t* domainInfo = NULL;
282 if (file.read("MESH_DOMAIN_SIZES", attribsIn, 0, N_domains, domainInfo) == false) return false;
283
284 for (uint i_domain = 0; i_domain < N_domains; ++i_domain) {
285 N_spatialCells += domainInfo[2 * i_domain];
286 }
287 nBlocks.resize(N_spatialCells);
288
289 #pragma omp parallel for
290 for (size_t i = 0; i < nBlocks.size(); ++i) nBlocks[i] = 0;
291
292 // Note: the input file contains N particle species, which are also
293 // defined in the configuration file. We need to read the BLOCKSPERCELL
294 // array for each species, and sum the values for each spatial cell.
295 set<string> speciesNames;
296 if (file.getUniqueAttributeValues("BLOCKSPERCELL", "name", speciesNames) == false) return false;
297
298 // Iterate over all particle species and read in BLOCKSPERCELL array
299 // to all processes, and add the values to nBlocks
300 uint64_t* buffer = new uint64_t[N_spatialCells];
301 for (set<string>::const_iterator s = speciesNames.begin(); s != speciesNames.end(); ++s) {
302 attribsIn.clear();
303 attribsIn.push_back(make_pair("mesh", meshName));
304 attribsIn.push_back(make_pair("name", *s));
305 if (file.getArrayInfo("BLOCKSPERCELL", attribsIn, arraySize, vectorSize, dataType, byteSize) == false) return false;
306
307 if (file.read("BLOCKSPERCELL", attribsIn, 0, arraySize, buffer) == false) {
308 delete[] buffer;
309 buffer = NULL;
310 return false;
311 }
312
313 #pragma omp parallel for
314 for (size_t i = 0; i < N_spatialCells; ++i) {
315 nBlocks[i] += buffer[i];
316 }
317 }
318 delete[] buffer;
319 buffer = NULL;
320 return success;
321}
322
330template <typename T>
331bool readScalarParameter(vlsv::ParallelReader& file, string name, T& value, int masterRank, MPI_Comm comm) {
332 if (file.readParameter(name, value) == false) {
333 logFile << "(RESTART) ERROR: Failed to read parameter '" << name << "' value in ";
334 logFile << __FILE__ << ":" << __LINE__ << endl << write;
335 return false;
336 }
337 return true;
338}
339
348
349template <typename T>
350bool checkScalarParameter(vlsv::ParallelReader& file, const string& name, T correctValue, int masterRank, MPI_Comm comm) {
351 T value;
352 if (readScalarParameter(file, name, value, masterRank, comm) == false) {
353 ostringstream s;
354 s << "(RESTART) ERROR: Failed to read parameter '" << name << "' value in " << __FILE__ << ":" << __LINE__ << endl;
355 exitOnError(false, s.str(), MPI_COMM_WORLD);
356 return false;
357 }
358 if (value != correctValue) {
359 ostringstream s;
360 s << "(RESTART) Parameter " << name << " has mismatching value.";
361 s << " CFG value = " << correctValue;
362 s << " Restart file value = " << value;
363 exitOnError(false, s.str(), MPI_COMM_WORLD);
364 return false;
365 } else {
366 return true;
367 }
368}
369
370template <typename fileReal>
371bool _readBlockDataCompressionNone(vlsv::ParallelReader & file,
372 const std::string& spatMeshName,
373 const std::vector<uint64_t>& fileCells,
374 const uint64_t localCellStartOffset,
375 const uint64_t localCells,
376 const vmesh::LocalID* blocksPerCell,
377 const std::vector<uint64_t>& blockSumOffsets,
378 const uint64_t localBlockStartOffset,
379 const uint64_t localBlocks,
380 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
381 std::function<vmesh::GlobalID(vmesh::GlobalID)> blockIDremapper,
382 const uint popID
383) {
384 uint64_t arraySize;
385 uint64_t avgVectorSize;
386 vlsv::datatype::type dataType;
387 uint64_t byteSize;
388 list<pair<string, string>> avgAttribs;
389 bool success = true;
390 const string popName = getObjectWrapper().particleSpecies[popID].name;
391 const string tagName = "BLOCKIDS";
392
393 avgAttribs.push_back(make_pair("mesh", spatMeshName));
394 avgAttribs.push_back(make_pair("name", popName));
395
396 // Get block id array info and store them into blockIdAttribs, lockIdByteSize, blockIdDataType, blockIdVectorSize
397 list<pair<string, string>> blockIdAttribs;
398 uint64_t blockIdVectorSize, blockIdByteSize;
399 vlsv::datatype::type blockIdDataType;
400 blockIdAttribs.push_back(make_pair("mesh", spatMeshName));
401 blockIdAttribs.push_back(make_pair("name", popName));
402 if (file.getArrayInfo("BLOCKIDS", blockIdAttribs, arraySize, blockIdVectorSize, blockIdDataType, blockIdByteSize) == false) {
403 logFile << "(RESTART) ERROR: Failed to read BLOCKCOORDINATES array info " << endl << write;
404 return false;
405 }
406 if (file.getArrayInfo("BLOCKVARIABLE", avgAttribs, arraySize, avgVectorSize, dataType, byteSize) == false) {
407 logFile << "(RESTART) ERROR: Failed to read BLOCKVARIABLE array info " << endl << write;
408 return false;
409 }
410
411 // Some routine error checks:
412 if (avgVectorSize != WID3) {
413 logFile << "(RESTART) ERROR: Blocksize does not match in restart file " << endl << write;
414 return false;
415 }
416 if (byteSize != sizeof(fileReal)) {
417 logFile << "(RESTART) ERROR: Bad avgs bytesize at " << __FILE__ << " " << __LINE__ << endl << write;
418 return false;
419 }
420
421 if (blockIdByteSize != sizeof(vmesh::GlobalID)) {
422 logFile << "(RESTART) ERROR: BlockID data size does not match " << __FILE__ << " " << __LINE__ << endl << write;
423 return false;
424 }
425
426 vmesh::GlobalID* blockIdBuffer;
427 fileReal* avgBuffer;
428#ifdef USE_GPU
429 CHK_ERR(gpuMallocHost((void**)&avgBuffer, avgVectorSize * localBlocks * sizeof(Realf))); // Pinned memory
430 blockIdBuffer = ::new vmesh::GlobalID[blockIdVectorSize * localBlocks]; // blockids of all cells
431#else
432 avgBuffer = new fileReal[avgVectorSize * localBlocks]; // avgs data for all cells
433 blockIdBuffer = new vmesh::GlobalID[blockIdVectorSize * localBlocks]; // blockids of all cells
434#endif
435
436 // Read block ids and data
437 if (file.readArray("BLOCKIDS", blockIdAttribs, localBlockStartOffset, localBlocks, (char*)blockIdBuffer) == false) {
438 cerr << "ERROR, failed to read BLOCKIDS in " << __FILE__ << ":" << __LINE__ << endl;
439 success = false;
440 }
441 if (file.readArray("BLOCKVARIABLE", avgAttribs, localBlockStartOffset, localBlocks, (char*)avgBuffer) == false) {
442 cerr << "ERROR, failed to read BLOCKVARIABLE in " << __FILE__ << ":" << __LINE__ << endl;
443 success = false;
444 }
445
446 // Go through all spatial cells
447 #pragma omp parallel for schedule(dynamic, 1)
448 for (uint64_t i = 0; i < localCells; i++) {
449 CellID cell = fileCells[localCellStartOffset + i]; // spatial cell id
450 uint64_t blockBufferOffset = blockSumOffsets[i];
451 vmesh::LocalID nBlocksInCell = blocksPerCell[i];
452 // copy blocks in this cell to vector blockIdsInCell, size of read in data has been checked earlier
453 vector<vmesh::GlobalID> blockIdsInCell; // blockIds in a particular cell, temporary usage
454 blockIdsInCell.reserve(nBlocksInCell);
455 blockIdsInCell.assign(blockIdBuffer + blockBufferOffset, blockIdBuffer + blockBufferOffset + nBlocksInCell);
456 for (auto& id : blockIdsInCell) {
457 id = blockIDremapper(id);
458 }
459 // allocate space for all blocks and create them and fill them
460 // a conversion may happen between float and double
461 mpiGrid[cell]->add_velocity_blocks(popID, blockIdsInCell, &avgBuffer[blockBufferOffset * WID3]);
462#if defined(USE_GPU) && defined(DEBUG_VLASIATOR)
463 mpiGrid[cell]->checkMesh(popID);
464#endif
465 }
466#ifdef USE_GPU
467 if (avgBuffer) {
468 CHK_ERR(gpuFreeHost(avgBuffer));
469 avgBuffer = 0;
470 }
471#else
472 delete[] avgBuffer;
473#endif
474 delete[] blockIdBuffer;
475 return success;
476}
477#ifdef ASTERIX_ZFP
478
479template <typename fileReal>
480bool _readBlockDataCompressionZFP(vlsv::ParallelReader & file,
481 const std::string& spatMeshName,
482 const std::vector<uint64_t>& fileCells,
483 const uint64_t localCellStartOffset,
484 const uint64_t localCells,
485 const vmesh::LocalID* blocksPerCell,
486 const uint64_t localBlockStartOffset,
487 const uint64_t localBlocks,
488 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
489 std::function<vmesh::GlobalID(vmesh::GlobalID)> blockIDremapper,
490 const uint popID){
491
492 uint64_t arraySize;
493 uint64_t avgVectorSize;
494 vlsv::datatype::type dataType;
495 uint64_t byteSize;
496 list<pair<string,string> > avgAttribs;
497 bool success=true;
498 const string popName = getObjectWrapper().particleSpecies[popID].name;
499 const string tagName = "BLOCKIDS";
500
501 avgAttribs.push_back(make_pair("mesh",spatMeshName));
502 avgAttribs.push_back(make_pair("name",popName));
503
504 //Get block id array info and store them into blockIdAttribs, lockIdByteSize, blockIdDataType, blockIdVectorSize
505 list<pair<string,string> > blockIdAttribs,bytesPerCellAttribs;
506 uint64_t blockIdVectorSize, blockIdByteSize;
507 vlsv::datatype::type blockIdDataType;
508 blockIdAttribs.push_back( make_pair("mesh", spatMeshName));
509 blockIdAttribs.push_back( make_pair("name", popName));
510 bytesPerCellAttribs.push_back( make_pair("mesh", spatMeshName));
511 bytesPerCellAttribs.push_back( make_pair("name", popName));
512
513 uint64_t bytesPerCellArraySize;
514 uint64_t bytesPerCellVectorSize;
515 uint64_t bytesPerCellByteSize;
516
517 if (file.getArrayInfo("BYTESPERCELL",blockIdAttribs,bytesPerCellArraySize,bytesPerCellVectorSize,dataType,bytesPerCellByteSize) == false ){
518 logFile << "(RESTART) ERROR: Failed to read BLOCKCOORDINATES array info " << endl << write;
519 return false;
520 }
521
522 if (file.getArrayInfo("BLOCKIDS",blockIdAttribs,arraySize,blockIdVectorSize,blockIdDataType,blockIdByteSize) == false ){
523 logFile << "(RESTART) ERROR: Failed to read BLOCKCOORDINATES array info " << endl << write;
524 return false;
525 }
526 if(file.getArrayInfo("BLOCKVARIABLE",avgAttribs,arraySize,avgVectorSize,dataType,byteSize) == false ){
527 logFile << "(RESTART) ERROR: Failed to read BLOCKVARIABLE array info " << endl << write;
528 return false;
529 }
530
531 if (!file.readParameter("VDF_BYTE_SIZE",byteSize )){
532 logFile<<"ERROR: Failed to read parameter VDF_BYTE_SIZE"<<std::endl<<write;
533 return false;
534 }
535
536 //Some routine error checks:
537 if( avgVectorSize!=1 ){
538 logFile << "(RESTART) ERROR: ZFP VectorSize should be 1." << endl << write;
539 return false;
540 }
541 if( byteSize != sizeof(fileReal) ) {
542 logFile << "(RESTART) ERROR: Bad avgs bytesize at " << __FILE__ << " " << __LINE__ << endl << write;
543 return false;
544 }
545
546 std::vector<std::size_t> bytesPerCell(fileCells.size(),{0});
547 vmesh::GlobalID * blockIdBuffer = new vmesh::GlobalID[blockIdVectorSize * localBlocks]; //blockids of all cells
548
549 //Read bytes per cells. Every taks reads the whole array becasue it is needed for offsets and such later on
550 if (file.readArray("BYTESPERCELL", bytesPerCellAttribs, 0, fileCells.size(), reinterpret_cast<char*>(bytesPerCell.data()) ) == false) {
551 cerr << "ERROR, failed to read BYTESPERCELL in " << __FILE__ << ":" << __LINE__ << endl;
552 success = false;
553 }
554
555 std::vector<std::size_t> scanBytesPerCell(fileCells.size(),{0});
556 std::vector<std::size_t> localScanBytesPerCell(localCells,{0});
557 std::exclusive_scan(bytesPerCell.begin(), bytesPerCell.end(),scanBytesPerCell.begin(),0ull);
558 std::exclusive_scan(bytesPerCell.begin()+localCellStartOffset,bytesPerCell.begin()+localCellStartOffset+localCells ,localScanBytesPerCell.begin(),0ull);
559 std::size_t n_compressed_bytes=std::accumulate(&bytesPerCell[localCellStartOffset],&bytesPerCell[localCellStartOffset+localCells],0ull);
560 std::vector<char>compressed_bytes(n_compressed_bytes);
561
562
563 if (file.readArray("BLOCKIDS", blockIdAttribs, localBlockStartOffset, localBlocks, (char*)blockIdBuffer ) == false) {
564 cerr << "ERROR, failed to read BLOCKIDS in " << __FILE__ << ":" << __LINE__ << endl;
565 success = false;
566 }
567 std::cout<<"REading n bytres"<<n_compressed_bytes<<std::endl;
568
569 if (file.readArray("BLOCKVARIABLE", avgAttribs, scanBytesPerCell[localCellStartOffset], n_compressed_bytes, compressed_bytes.data()) == false) {
570 cerr << "ERROR, failed to read BLOCKVARIABLE in " << __FILE__ << ":" << __LINE__ << endl;
571 success = false;
572 }
573
574 uint64_t blockBufferOffset=0;
575 //Go through all spatial cells
576 vector<vmesh::GlobalID> blockIdsInCell; //blockIds in a particular cell, temporary usage
577 Real sparse = getObjectWrapper().particleSpecies[popID].sparseMinValue;
578 for(uint64_t i=0; i<localCells; i++) {
579 CellID cell = fileCells[localCellStartOffset + i]; //spatial cell id
580 if (mpiGrid[cell]->sysBoundaryFlag == sysboundarytype::DO_NOT_COMPUTE) {
581 continue;
582 }
583 vmesh::LocalID nBlocksInCell = blocksPerCell[i];
584 //copy blocks in this cell to vector blockIdsInCell, size of read in data has been checked earlier
585 blockIdsInCell.reserve(nBlocksInCell);
586 blockIdsInCell.assign(blockIdBuffer + blockBufferOffset, blockIdBuffer + blockBufferOffset + nBlocksInCell);
587 for(auto& id : blockIdsInCell) {
588 id = blockIDremapper(id);
589 }
590 mpiGrid[cell]->add_velocity_blocks<float>(popID,blockIdsInCell,NULL); //allocate space for all blocks and create them
591 Realf *cellBlockData=mpiGrid[cell]->get_data(popID);
592 fileReal* data = new fileReal[nBlocksInCell*WID3];
593 if (!data){
594 std::runtime_error("ERROR: failed to allocate memory for reading in compressed VDFs.");
595 }
596 if constexpr (sizeof(fileReal) == sizeof(float)) {
597 std::vector<float> vdf_vals =
598 ASTERIX::decompressArrayFloat(compressed_bytes.data() + (localScanBytesPerCell[i]),
599 bytesPerCell[localCellStartOffset + i], nBlocksInCell * WID3, sparse);
600 std::memcpy(data, vdf_vals.data(), vdf_vals.size() * sizeof(float));
601 } else if constexpr (sizeof(fileReal) == sizeof(double)) {
602 std::vector<double> vdf_vals =
603 ASTERIX::decompressArrayDouble(compressed_bytes.data() + (localScanBytesPerCell[i]),
604 bytesPerCell[localCellStartOffset + i], nBlocksInCell * WID3, sparse);
605 std::memcpy(data, vdf_vals.data(), vdf_vals.size() * sizeof(double));
606 } else {
607 std::runtime_error("ERROR: failed to read in VDFs for type fileReal. ");
608 }
609 for(uint64_t i = 0; i< WID3 * nBlocksInCell ; i++){
610 cellBlockData[i] = static_cast<Realf>(data[i]);
611 }
612 delete[] data;
613 blockBufferOffset += nBlocksInCell; //jump to location of next local cell
614 }
615
616 delete[] blockIdBuffer;
617 return success;
618}
619#endif //ASTERIX_ZFP
620
621#ifdef ASTERIX_OCTREE
622template <typename fileReal>
623bool _readBlockDataCompressionOCTREE(vlsv::ParallelReader & file,
624 const std::string& spatMeshName,
625 const std::vector<uint64_t>& fileCells,
626 const uint64_t localCellStartOffset,
627 const uint64_t localCells,
628 const vmesh::LocalID* blocksPerCell,
629 const uint64_t localBlockStartOffset,
630 const uint64_t localBlocks,
631 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
632 std::function<vmesh::GlobalID(vmesh::GlobalID)> blockIDremapper,
633 const uint popID){
634
635 uint64_t arraySize;
636 uint64_t avgVectorSize;
637 vlsv::datatype::type dataType;
638 uint64_t byteSize;
639 list<pair<string,string> > avgAttribs;
640 bool success=true;
641 const string popName = getObjectWrapper().particleSpecies[popID].name;
642 const string tagName = "BLOCKIDS";
643
644 avgAttribs.push_back(make_pair("mesh",spatMeshName));
645 avgAttribs.push_back(make_pair("name",popName));
646
647 //Get block id array info and store them into blockIdAttribs, lockIdByteSize, blockIdDataType, blockIdVectorSize
648 list<pair<string,string> > blockIdAttribs,bytesPerCellAttribs;
649 uint64_t blockIdVectorSize, blockIdByteSize;
650 vlsv::datatype::type blockIdDataType;
651 blockIdAttribs.push_back( make_pair("mesh", spatMeshName));
652 blockIdAttribs.push_back( make_pair("name", popName));
653 bytesPerCellAttribs.push_back( make_pair("mesh", spatMeshName));
654 bytesPerCellAttribs.push_back( make_pair("name", popName));
655
656 uint64_t bytesPerCellArraySize;
657 uint64_t bytesPerCellVectorSize;
658 uint64_t bytesPerCellByteSize;
659
660 if (file.getArrayInfo("BYTESPERCELL",blockIdAttribs,bytesPerCellArraySize,bytesPerCellVectorSize,dataType,bytesPerCellByteSize) == false ){
661 logFile << "(RESTART) ERROR: Failed to read BLOCKCOORDINATES array info " << endl << write;
662 return false;
663 }
664
665 if(file.getArrayInfo("BLOCKVARIABLE",avgAttribs,arraySize,avgVectorSize,dataType,byteSize) == false ){
666 logFile << "(RESTART) ERROR: Failed to read BLOCKVARIABLE array info " << endl << write;
667 return false;
668 }
669 if (!file.readParameter("VDF_BYTE_SIZE",byteSize )){
670 logFile<<"ERROR: Failed to read parameter VDF_BYTE_SIZE"<<std::endl<<write;
671 return false;
672 }
673
674 //Some routine error checks:
675 if( avgVectorSize!=1 ){
676 logFile << "(RESTART) ERROR: ZFP VectorSize should be 1." << endl << write;
677 return false;
678 }
679 if( byteSize != sizeof(fileReal) ) {
680 logFile << "(RESTART) ERROR: Bad avgs bytesize at " << __FILE__ << " " << __LINE__ << endl << write;
681 return false;
682 }
683
684 std::vector<std::size_t> bytesPerCell(fileCells.size(),{0});
685 //Read bytes per cells. Every taks reads the whole array becasue it is needed for offsets and such later on
686 if (file.readArray("BYTESPERCELL", bytesPerCellAttribs, 0, fileCells.size(), reinterpret_cast<char*>(bytesPerCell.data()) ) == false) {
687 cerr << "ERROR, failed to read BYTESPERCELL in " << __FILE__ << ":" << __LINE__ << endl;
688 success = false;
689 }
690
691 std::vector<std::size_t> scanBytesPerCell(fileCells.size(),{0});
692 std::vector<std::size_t> localScanBytesPerCell(localCells,{0});
693 std::exclusive_scan(bytesPerCell.begin(), bytesPerCell.end(),scanBytesPerCell.begin(),0ull);
694 std::exclusive_scan(bytesPerCell.begin()+localCellStartOffset,bytesPerCell.begin()+localCellStartOffset+localCells ,localScanBytesPerCell.begin(),0ull);
695 std::size_t n_compressed_bytes=std::accumulate(&bytesPerCell[localCellStartOffset],&bytesPerCell[localCellStartOffset+localCells],0ull);
696 std::vector<char>compressed_bytes(n_compressed_bytes);
697
698 if (file.readArray("BLOCKVARIABLE", avgAttribs, scanBytesPerCell[localCellStartOffset], n_compressed_bytes, compressed_bytes.data()) == false) {
699 cerr << "ERROR, failed to read BLOCKVARIABLE in " << __FILE__ << ":" << __LINE__ << endl;
700 success = false;
701 }
702
703 if (sizeof (fileReal)!=4){
704 throw std::runtime_error("TODO: Not implemented yet!");
705 }
706
707 for(uint64_t i=0; i<localCells; i++) {
708 CellID cell = fileCells[localCellStartOffset + i]; //spatial cell id
709 if (mpiGrid[cell]->sysBoundaryFlag == sysboundarytype::DO_NOT_COMPUTE) {
710 continue;
711 }
712 std::size_t read_index = localScanBytesPerCell[i];
713 const std::size_t* n_ignored_blocks=reinterpret_cast<const std::size_t*>(compressed_bytes.data()+read_index);
714 read_index+=sizeof(std::size_t);
715 std::vector<vmesh::GlobalID> blocks_to_ignore(*n_ignored_blocks,vmesh::INVALID_GLOBALID);
716 std::memcpy(blocks_to_ignore.data() ,compressed_bytes.data()+read_index , blocks_to_ignore.size()*sizeof(vmesh::GlobalID) );
717 read_index+=blocks_to_ignore.size()*sizeof(vmesh::GlobalID);
718 const std::size_t* bbox_shape=reinterpret_cast<const std::size_t*>(compressed_bytes.data()+read_index);
719 read_index+=3*sizeof(std::size_t);
720 const Real* bbox_lims=reinterpret_cast<const Real*>(compressed_bytes.data()+read_index);
721 read_index+=6*sizeof(Real);
722
723
724 Real dv= (bbox_lims[3]-bbox_lims[0])/(Realf)bbox_shape[0];
725
726 const std::size_t inflated_size=bbox_shape[0]*bbox_shape[1]*bbox_shape[2];
727 ASTERIX::OrderedVDF vdf{.blocks_to_ignore=blocks_to_ignore,.sparse_vdf_bytes=0,
728 .vdf_vals=std::vector<Realf>(inflated_size,0),
729 .v_limits{bbox_lims[0],bbox_lims[1],bbox_lims[2],bbox_lims[3],bbox_lims[4],bbox_lims[5]},
730 .shape={bbox_shape[0],bbox_shape[1],bbox_shape[2]}};
731
732 uncompress_with_toctree_method( vdf.vdf_vals.data(),bbox_shape[0],bbox_shape[1],bbox_shape[2], (uint8_t*)&compressed_bytes[read_index],bytesPerCell[localCellStartOffset+i]-read_index);
733 SpatialCell* sc=mpiGrid[cell];
734 const Real sparse = getObjectWrapper().particleSpecies[popID].sparseMinValue;
735 for (std::size_t i=0;i<bbox_shape[0];++i){
736 for (std::size_t j=0;j<bbox_shape[1];++j){
737 for (std::size_t k=0;k<bbox_shape[2];++k){
738 const std::array<Real,3>coords={bbox_lims[0]+i*dv,bbox_lims[1]+j*dv,bbox_lims[2]+k*dv};
739 Realf& val=vdf.at(i,j,k);
740 const auto gid=sc->get_velocity_block(popID, &coords[0]);
741 const bool ignore_me=std::find(blocks_to_ignore.cbegin(),blocks_to_ignore.cend(),gid)!=blocks_to_ignore.cend();
742 if (val>=sparse && !ignore_me){
743 sc->add_velocity_block(gid,popID);
744 }
745 }
746 }
747 }
750 }
751 return success;
752}
753#endif //ASTERIX_OCTREE
754
755#ifdef ASTERIX_MLP
756template <typename fileReal>
757bool _readBlockDataCompressionMLP(vlsv::ParallelReader & file,
758 const std::string& spatMeshName,
759 const std::vector<uint64_t>& fileCells,
760 const uint64_t localCellStartOffset,
761 const uint64_t localCells,
762 const vmesh::LocalID* blocksPerCell,
763 const uint64_t localBlockStartOffset,
764 const uint64_t localBlocks,
765 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
766 std::function<vmesh::GlobalID(vmesh::GlobalID)> blockIDremapper,
767 const uint popID){
768
769 bool success=true;
770 const string popName = getObjectWrapper().particleSpecies[popID].name;
771 list<pair<string,string> > attribs;
772 attribs.push_back(make_pair("name",popName));
773
774 int nFileRanks;
775 if (!file.readParameter("numWritingRanks",nFileRanks)){
776 logFile <<"ERROR: Could not read numWritingRanks from restart file!";
777 return false;
778 }
779 std::vector<std::size_t> nbytes(nFileRanks);
780 if (!file.readArray("MLP_BYTES_PER_RANK",attribs,0,nFileRanks,reinterpret_cast<char*>((nbytes.data())))){
781 logFile<<"ERROR: Could not read mlp bytes per rank"<<endl<<write;
782 std::cerr<<"MLP BYTES PER RANK ARE INVALID"<<std::endl;
783 return false;
784 }
785 std::vector<std::size_t> nclusters(nFileRanks);
786 if (!file.readArray("MLP_CLUSTERS_PER_RANK",attribs,0,nFileRanks,reinterpret_cast<char*>((nclusters.data())))){
787 logFile<<"ERROR: Could not read mlp bytes per rank"<<endl<<write;
788 std::cerr<<"MLP CLUSTERS PER RANK ARE INVALID"<<std::endl;
789 return false;
790 }
791 const std::size_t nmlps = std::accumulate(nclusters.cbegin(),nclusters.cend(),0ull);
792
793 //Read in headers
794 std::vector<std::size_t> scanBytesPerCell(nFileRanks);
795 std::exclusive_scan(nbytes.cbegin(), nbytes.cend(),scanBytesPerCell.begin(),0ull);
796 std::vector<ASTERIX::PhaseSpaceUnion<Realf>::Header> mlp_headers(nmlps);
797 {
798 std::vector<std::size_t> nbytes_multi_mlp_case;
799 std::size_t cnt=0;
800 for (std::size_t i=0;i<(std::size_t)nFileRanks;++i){
801 std::size_t offset=0;
802 for (std::size_t cluster=0;cluster<nclusters[i];++cluster){
803 if (file.readArray("BLOCKVARIABLE", attribs, scanBytesPerCell[i]+offset, sizeof(ASTERIX::PhaseSpaceUnion<Realf>::Header),reinterpret_cast<char*>( &mlp_headers.at(cnt) ) ) == false) {
804 cerr << "ERROR, failed to read MLP BYTES in " << __FILE__ << ":" << __LINE__ << endl;
805 return false;
806 }
807 if(nmlps>(std::size_t)nFileRanks){
808 nbytes_multi_mlp_case.push_back(mlp_headers.at(cnt).total_size);
809 }
810 offset+=mlp_headers.at(cnt).total_size;
811 cnt++;
812 }
813 }
814 if (nmlps>(std::size_t)nFileRanks){
815 nbytes=nbytes_multi_mlp_case;
816 }
817 }
818
819 //We rebuild nbytes here if we have MLP_MULTI ie nmlps>nFileRanks
820 if (nmlps>(std::size_t)nFileRanks){
821 scanBytesPerCell.resize(nmlps);
822 std::exclusive_scan(nbytes.cbegin(), nbytes.cend(),scanBytesPerCell.begin(),0ull);
823 }
824
825 //Read in cids
826 std::vector<std::vector<CellID>> mlp_cids(nmlps);
827 {
828 std::size_t cnt=0;
829 for (std::size_t i=0;i<(std::size_t)nFileRanks;++i){
830 for (std::size_t cluster=0;cluster<nclusters[i];++cluster){
831 mlp_cids.at(cnt).resize(mlp_headers.at(cnt).cols);
832 if (file.readArray("BLOCKVARIABLE", attribs, scanBytesPerCell[cnt]+sizeof(ASTERIX::PhaseSpaceUnion<Realf>::Header),mlp_headers.at(cnt).cols*sizeof(CellID) ,reinterpret_cast<char*>( mlp_cids.at(cnt).data() ) ) == false) {
833 cerr << "ERROR, failed to read MLP BYTES in " << __FILE__ << ":" << __LINE__ << endl;
834 return false;
835 }
836 cnt++;
837 }
838 }
839 }
840
841 std::unordered_map<CellID ,std::size_t> cid2mlp_map;
842 std::unordered_set<std::size_t> mlp_lookup;
843
844 for (std::size_t i=0; i<localCells;++i){
845 CellID cid= fileCells[localCellStartOffset + i]; //spatial cell id
846 if (mpiGrid[cid]->sysBoundaryFlag == sysboundarytype::DO_NOT_COMPUTE) {
847 continue;
848 }
849
850 for (std::size_t j = 0; j < mlp_cids.size(); ++j) {
851 const auto& cand = mlp_cids.at(j);
852 if(std::find(cand.begin(),cand.end(),cid)!=cand.end()){
853 cid2mlp_map[cid]=j;
854 mlp_lookup.insert(j);
855 break;
856 }
857 }
858 }
859
860 //Move set to vector needed for later
861 std::vector<std::size_t >lookup;
862 lookup.reserve(mlp_lookup.size());
863 for (auto it = mlp_lookup.begin(); it != mlp_lookup.end(); ) {
864 lookup.push_back(std::move(mlp_lookup.extract(it++).value()));
865 }
866
867 std::size_t global_n_reads={0};
868 const std::size_t local_n_reads=lookup.size();
869
870 MPI_Allreduce(
871 &local_n_reads,
872 &global_n_reads,
873 1,
874 MPI_UNSIGNED_LONG_LONG,
875 MPI_MAX,
876 MPI_COMM_WORLD);
877 MPI_Barrier(MPI_COMM_WORLD);
878
879
880 const Real sparse = getObjectWrapper().particleSpecies[popID].sparseMinValue;
881
882 //Finally we know where to look at to reconstruct our local VDFs. Let's do it:
883 for (std::size_t i=0;i<global_n_reads;++i){
884 if (i<local_n_reads){
885 const auto id=lookup.at(i);
886
887 //Make room for this mlp state
888 std::vector<char> mlp_bytes( nbytes.at(id) );
889
890 //Read it in
891 if (file.readArray("BLOCKVARIABLE", attribs, scanBytesPerCell[id], nbytes[id], mlp_bytes.data()) == false) {
892 cerr << "ERROR, failed to read MLP BYTES in " << __FILE__ << ":" << __LINE__ << endl;
893 return false;
894 }
895
896 //Reconstruct this Union
897 ASTERIX::PhaseSpaceUnion<Realf> b(reinterpret_cast<unsigned char*>(mlp_bytes.data()));
898 ASTERIX::decompressPhaseSpace<Realf>(b);
899 b.unormalize_and_unscale(sparse);
900 b.sparsify(sparse);
901
902 //Keep only what you need
903 for (const auto& [cid,mlpid]:cid2mlp_map){
904 if (mlpid==id){
905 SpatialCell* sc = mpiGrid[cid];
907 continue;
908 }
909 const std::size_t column = std::find(b._cids.begin(), b._cids.end(), cid) - b._cids.begin();
910 for (std::size_t i=0; i< b._nrows;++i){
911 auto vbulk=b._vbulks[column];
912 auto coords = b._vcoords[i];
913 coords[0] += vbulk[0];
914 coords[1] += vbulk[1];
915 coords[2] += vbulk[2];
916 std::array<Real, 3> coords_updated = {static_cast<Real>(coords[0]), static_cast<Real>(coords[1]),
917 static_cast<Real>(coords[2])};
918 const auto gid = sc->get_velocity_block(popID, &coords_updated[0]);
919 const bool exists = b._map.find(gid)!=b._map.end();
920 if (gid != vmesh::INVALID_GLOBALID && exists && b._vspace[b.index_2d(i,column)]>=sparse){
921 sc->add_velocity_block(gid,popID);
922 }
923 }
924 ASTERIX::overwrite_cellids_vdf_single_cell<Realf>(b._cids, popID,sc,column,b._vcoords, b._vspace, b._map);
925 }
926 }
927 }else{
928 char* ptr=nullptr;
929 if (file.readArray("BLOCKVARIABLE", attribs, scanBytesPerCell[0], 0, ptr) == false) {
930 cerr << "ERROR, failed to read MLP BYTES in " << __FILE__ << ":" << __LINE__ << endl;
931 return false;
932 }
933 }
934 }
935 return success;
936}
937
938#endif // ASTERIX_MLP
939
953template <typename fileReal>
955 vlsv::ParallelReader & file,
956 const std::string& spatMeshName,
957 const std::vector<uint64_t>& fileCells,
958 const uint64_t localCellStartOffset,
959 const uint64_t localCells,
960 const vmesh::LocalID* blocksPerCell,
961 const std::vector<uint64_t>& blockSumOffsets,
962 const uint64_t localBlockStartOffset,
963 const uint64_t localBlocks,
964 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
965 std::function<vmesh::GlobalID(vmesh::GlobalID)> blockIDremapper,
966 const uint popID
967) {
968 bool success=true;
969 //Let's see if any compression was used in the restart file for the VDFs (ASTERIX)
971 if (!file.readParameter("COMPRESSION",cmp)){
972 logFile<<"(RESTART): Compression defaulted to NONE"<<endl<<write;
973 }
974
975 switch (static_cast<P::ASTERIX_COMPRESSION_METHODS>(cmp)){
977 success = _readBlockDataCompressionNone<fileReal>(file, spatMeshName, fileCells, localCellStartOffset,
978 localCells, blocksPerCell,blockSumOffsets, localBlockStartOffset,
979 localBlocks, mpiGrid, blockIDremapper, popID);
980 break;
981#ifdef ASTERIX_ZFP
983 success=_readBlockDataCompressionZFP<fileReal>(file,spatMeshName,fileCells,localCellStartOffset,localCells,blocksPerCell,localBlockStartOffset,localBlocks,mpiGrid,blockIDremapper,popID);
984 break;
985#endif
986#ifdef ASTERIX_MLP
988 success=_readBlockDataCompressionMLP<fileReal>(file,spatMeshName,fileCells,localCellStartOffset,localCells,blocksPerCell,localBlockStartOffset,localBlocks,mpiGrid,blockIDremapper,popID);
989 break;
991 success=_readBlockDataCompressionMLP<fileReal>(file,spatMeshName,fileCells,localCellStartOffset,localCells,blocksPerCell,localBlockStartOffset,localBlocks,mpiGrid,blockIDremapper,popID);
992 break;
993#endif
994#ifdef ASTERIX_OCTREE
996 success=_readBlockDataCompressionOCTREE<fileReal>(file,spatMeshName,fileCells,localCellStartOffset,localCells,blocksPerCell,localBlockStartOffset,localBlocks,mpiGrid,blockIDremapper,popID);
997 break;
998#endif
999 default:
1000 abort();
1001 }
1002
1003 return success;
1004}
1005
1015bool readBlockData(vlsv::ParallelReader& file, const string& meshName, const vector<CellID>& fileCells,
1016 const uint64_t localCellStartOffset, const uint64_t localCells,
1017 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
1018 bool success = true;
1019
1020 const uint64_t bytesReadStart = file.getBytesRead();
1021 int N_processes;
1022 MPI_Comm_size(MPI_COMM_WORLD, &N_processes);
1023
1024 uint64_t arraySize;
1025 uint64_t vectorSize;
1026 vlsv::datatype::type dataType;
1027 uint64_t byteSize;
1028 uint64_t* offsetArray = new uint64_t[N_processes];
1029
1030 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
1031 const string& popName = getObjectWrapper().particleSpecies[popID].name;
1032
1033 // Create a cellID remapping lambda that can renumber our velocity space, should its size have changed.
1034 // By default, this is a no-op that keeps the blockIDs untouched.
1035 std::function<vmesh::GlobalID(vmesh::GlobalID)> blockIDremapper = [](vmesh::GlobalID oldID) -> vmesh::GlobalID {
1036 return oldID;
1037 };
1038
1039 // Check that velocity space extents and DV matches the grids we have created
1040 list<pair<string, string>> attribs;
1041 attribs.push_back(make_pair("mesh", popName));
1042 std::array<unsigned int, 6> fileMeshBBox;
1043 unsigned int* bufferpointer = &fileMeshBBox[0];
1044 if (file.read("MESH_BBOX", attribs, 0, 6, bufferpointer, false) == false) {
1045 logFile << "(RESTART) ERROR: Failed to read MESH_BBOX at " << __FILE__ << ":" << __LINE__ << endl << write;
1046 success = false;
1047 }
1048
1049 const size_t meshID = getObjectWrapper().particleSpecies[popID].velocityMesh;
1050 const vmesh::MeshParameters& ourMeshParams = vmesh::getMeshWrapper()->velocityMeshes->at(meshID);
1051 if (fileMeshBBox[0] != ourMeshParams.gridLength[0] ||
1052 fileMeshBBox[1] != ourMeshParams.gridLength[1] ||
1053 fileMeshBBox[2] != ourMeshParams.gridLength[2]) {
1054
1055 logFile << "(RESTART) INFO: velocity mesh sizes don't match:" << endl
1056 << " restart file has " << fileMeshBBox[0] << " x " << fileMeshBBox[1] << " x " << fileMeshBBox[2] << "," << endl
1057 << " config specifies " << ourMeshParams.gridLength[0] << " x " << ourMeshParams.gridLength[1] << " x " << ourMeshParams.gridLength[2] << endl << write;
1058
1059 if (ourMeshParams.gridLength[0] < fileMeshBBox[0] ||
1060 ourMeshParams.gridLength[1] < fileMeshBBox[1] ||
1061 ourMeshParams.gridLength[2] < fileMeshBBox[2]) {
1062 logFile << "(RESTART) ERROR: trying to shrink velocity space." << endl << write;
1063 abort();
1064 }
1065
1066 // If we are mismatched, we have to iterate through the velocity coords to see if we have a
1067 // chance at renumbering.
1068 std::vector<Real> fileVelCoordsX(fileMeshBBox[0] * fileMeshBBox[3] + 1);
1069 std::vector<Real> fileVelCoordsY(fileMeshBBox[1] * fileMeshBBox[4] + 1);
1070 std::vector<Real> fileVelCoordsZ(fileMeshBBox[2] * fileMeshBBox[5] + 1);
1071
1072 Real* tempPointer = fileVelCoordsX.data();
1073 if (file.read("MESH_NODE_CRDS_X", attribs, 0, fileMeshBBox[0] * fileMeshBBox[3] + 1, tempPointer, false) == false) {
1074 logFile << "(RESTART) ERROR: Failed to read MESH_NODE_CRDS_X at " << __FILE__ << ":" << __LINE__ << endl << write;
1075 success = false;
1076 }
1077 tempPointer = fileVelCoordsY.data();
1078 if (file.read("MESH_NODE_CRDS_Y", attribs, 0, fileMeshBBox[1] * fileMeshBBox[4] + 1, tempPointer, false) == false) {
1079 logFile << "(RESTART) ERROR: Failed to read MESH_NODE_CRDS_Y at " << __FILE__ << ":" << __LINE__ << endl << write;
1080 success = false;
1081 }
1082 tempPointer = fileVelCoordsZ.data();
1083 if (file.read("MESH_NODE_CRDS_Z", attribs, 0, fileMeshBBox[2] * fileMeshBBox[5] + 1, tempPointer, false) == false) {
1084 logFile << "(RESTART) ERROR: Failed to read MESH_NODE_CRDS_Z at " << __FILE__ << ":" << __LINE__ << endl << write;
1085 success = false;
1086 }
1087
1088 const Real dVx = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).cellSize[0];
1089 for (const auto& c : fileVelCoordsX) {
1090 Real cellindex = (c - vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[0]) / dVx;
1091 if (fabs(nearbyint(cellindex) - cellindex) > 1. / 10000.) {
1092 logFile << "(RESTART) ERROR: Can't resize velocity space as cell coordinates don't match." << endl
1093 << " (X coordinate " << c << " = " << cellindex << " * " << dVx << " + "
1094 << vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[0] << endl
1095 << " coordinate = cellindex * dV + meshMinLimits)" << endl
1096 << write;
1097 abort();
1098 }
1099 }
1100
1101 const Real dVy = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).cellSize[1];
1102 for (const auto& c : fileVelCoordsY) {
1103 Real cellindex = (c - vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[1]) / dVy;
1104 if (fabs(nearbyint(cellindex) - cellindex) > 1. / 10000.) {
1105 logFile << "(RESTART) ERROR: Can't resize velocity space as cell coordinates don't match." << endl
1106 << " (Y coordinate " << c << " = " << cellindex << " * " << dVy << " + "
1107 << vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[1] << endl
1108 << " coordinate = cellindex * dV + meshMinLimits)" << endl
1109 << write;
1110 abort();
1111 }
1112 }
1113
1114 const Real dVz = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).cellSize[2];
1115 for (const auto& c : fileVelCoordsY) {
1116 Real cellindex = (c - vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[2]) / dVz;
1117 if (fabs(nearbyint(cellindex) - cellindex) > 1. / 10000.) {
1118 logFile << "(RESTART) ERROR: Can't resize velocity space as cell coordinates don't match." << endl
1119 << " (Z coordinate " << c << " = " << cellindex << " * " << dVz << " + "
1120 << vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[2] << endl
1121 << " coordinate = cellindex * dV + meshMinLimits)" << endl
1122 << write;
1123 abort();
1124 }
1125 }
1126
1127 // If we haven't aborted above, we can apparently renumber our
1128 // cellIDs. Build an approprita blockIDremapper lambda for this purpose.
1129 std::array<int, 3> velGridOffset;
1130 velGridOffset[0] = (fileVelCoordsX[0] - vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[0]) / dVx;
1131 velGridOffset[1] = (fileVelCoordsY[0] - vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[1]) / dVy;
1132 velGridOffset[2] = (fileVelCoordsZ[0] - vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[2]) / dVz;
1133
1134 if ((velGridOffset[0] % ourMeshParams.blockLength[0] != 0) ||
1135 (velGridOffset[1] % ourMeshParams.blockLength[1] != 0) ||
1136 (velGridOffset[2] % ourMeshParams.blockLength[2] != 0)) {
1137 logFile << "(RESTART) ERROR: resizing velocity space on restart must end up with the old velocity space" << endl
1138 << " at a block boundary of the new space!" << endl
1139 << " (It now starts at cell [" << velGridOffset[0] << ", " << velGridOffset[1] << "," << velGridOffset[2] << "])" << endl << write;
1140 abort();
1141 }
1142
1143 velGridOffset[0] /= ourMeshParams.blockLength[0];
1144 velGridOffset[1] /= ourMeshParams.blockLength[1];
1145 velGridOffset[2] /= ourMeshParams.blockLength[2];
1146
1147 blockIDremapper = [fileMeshBBox, velGridOffset, ourMeshParams](vmesh::GlobalID oldID) -> vmesh::GlobalID {
1148 unsigned int x, y, z;
1149 x = oldID % fileMeshBBox[0];
1150 y = (oldID / fileMeshBBox[0]) % fileMeshBBox[1];
1151 z = oldID / (fileMeshBBox[0] * fileMeshBBox[1]);
1152
1153 x += velGridOffset[0];
1154 y += velGridOffset[1];
1155 z += velGridOffset[2];
1156
1157 //logFile << " Remapping " << oldID << "(" << x << "," << y << "," << z << ") to " << x + y * ourMeshParams.gridLength[0] + z* ourMeshParams.gridLength[0] * ourMeshParams.gridLength[1] << endl << write;
1158 return x + y * ourMeshParams.gridLength[0] + z* ourMeshParams.gridLength[0] * ourMeshParams.gridLength[1];
1159 };
1160
1161 logFile << " => Resizing velocity space by renumbering GlobalIDs." << endl << endl << write;
1162 }
1163
1164 // In restart files each spatial cell has an entry in CELLSWITHBLOCKS.
1165 // Each process calculates how many velocity blocks it has for this species.
1166 attribs.clear();
1167 attribs.push_back(make_pair("mesh", meshName));
1168 attribs.push_back(make_pair("name", popName));
1169 vmesh::LocalID* blocksPerCell = NULL;
1170
1171 if (file.read("BLOCKSPERCELL", attribs, localCellStartOffset, localCells, blocksPerCell, true) == false) {
1172 logFile << "(RESTART) ERROR: Failed to read BLOCKSPERCELL at " << __FILE__ << ":" << __LINE__ << endl << write;
1173 success = false;
1174 }
1175
1176 // Count how many velocity blocks this process gets
1177 uint64_t blockSum = 0;
1178 std::vector<uint64_t> blockSumOffsets(localCells);
1179 for (uint64_t i = 0; i < localCells; ++i) {
1180 blockSumOffsets[i] = blockSum;
1181 blockSum += blocksPerCell[i];
1182 }
1183
1184 // Gather all block sums to master process who will them broadcast
1185 // the values to everyone
1186 MPI_Allgather(&blockSum, 1, MPI_Type<uint64_t>(), offsetArray, 1, MPI_Type<uint64_t>(), MPI_COMM_WORLD);
1187
1188 // Calculate the offset from which this process starts reading block data
1189 uint64_t myOffset = 0;
1190 for (int64_t i = 0; i < mpiGrid.get_rank(); ++i) {
1191 myOffset += offsetArray[i];
1192 }
1193
1194 if (!file.readParameter("VDF_BYTE_SIZE",byteSize)){
1195 logFile << "(RESTART): This must be a non Asterix Restart" << endl << write;
1196 if (file.getArrayInfo("BLOCKVARIABLE",attribs,arraySize,vectorSize,dataType,byteSize) == false) {
1197 logFile << "(RESTART) ERROR: Failed to read BLOCKVARIABLE INFO" << endl << write;
1198 return false;
1199 }
1200 }
1201
1202 switch (byteSize) {
1203 case sizeof(double):
1204 if (_readBlockData<double>(file, meshName, fileCells, localCellStartOffset, localCells, blocksPerCell,
1205 blockSumOffsets, myOffset, blockSum, mpiGrid, blockIDremapper, popID) == false)
1206 success = false;
1207 break;
1208
1209 case sizeof(float):
1210 if (_readBlockData<float>(file, meshName, fileCells, localCellStartOffset, localCells, blocksPerCell,
1211 blockSumOffsets, myOffset, blockSum, mpiGrid, blockIDremapper, popID) == false)
1212 success = false;
1213 break;
1214 }
1215 delete[] blocksPerCell;
1216 blocksPerCell = NULL;
1217 } // for-loop over particle species
1218
1219 delete[] offsetArray;
1220 offsetArray = NULL;
1221
1222 const uint64_t bytesReadEnd = file.getBytesRead() - bytesReadStart;
1223 logFile << "Velocity meshes and data read, approximate data rate is ";
1224 logFile << vlsv::printDataRate(bytesReadEnd, file.getReadTime()) << endl << write;
1225
1226 return success;
1227}
1228
1238template <typename fileReal>
1239static bool _readCellParamsVariable(vlsv::ParallelReader& file, const vector<uint64_t>& fileCells,
1240 const uint64_t localCellStartOffset, const uint64_t localCells,
1241 const string& variableName, const size_t cellParamsIndex,
1242 const size_t expectedVectorSize,
1243 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
1244 uint64_t arraySize;
1245 uint64_t vectorSize;
1246 vlsv::datatype::type dataType;
1247 uint64_t byteSize;
1248 list<pair<string, string>> attribs;
1249 fileReal* buffer;
1250 bool success = true;
1251
1252 attribs.push_back(make_pair("name", variableName));
1253 attribs.push_back(make_pair("mesh", "SpatialGrid"));
1254
1255 if (file.getArrayInfo("VARIABLE", attribs, arraySize, vectorSize, dataType, byteSize) == false) {
1256 logFile << "(RESTART) ERROR: Failed to read DCCRG ArrayInfo" << endl << write;
1257 return false;
1258 }
1259
1260 if (vectorSize != expectedVectorSize) {
1261 logFile << "(RESTART) vectorsize wrong " << endl << write;
1262 return false;
1263 }
1264
1265 buffer = ::new fileReal[vectorSize * localCells];
1266 if (file.readArray("VARIABLE", attribs, localCellStartOffset, localCells, (char*)buffer) == false) {
1267 logFile << "(RESTART) ERROR: Failed to read " << variableName << endl << write;
1268 return false;
1269 }
1270
1271 for (uint i = 0; i < localCells; i++) {
1272 uint cell = fileCells[localCellStartOffset + i];
1273 for (uint j = 0; j < vectorSize; j++) {
1274 mpiGrid[cell]->parameters[cellParamsIndex + j] = buffer[i * vectorSize + j];
1275 }
1276 }
1277
1278 delete[] buffer;
1279 return success;
1280}
1281
1291bool readCellParamsVariable(vlsv::ParallelReader& file, const vector<CellID>& fileCells,
1292 const uint64_t localCellStartOffset, const uint64_t localCells, const string& variableName,
1293 const size_t cellParamsIndex, const size_t expectedVectorSize,
1294 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
1295 uint64_t arraySize;
1296 uint64_t vectorSize;
1297 vlsv::datatype::type dataType;
1298 uint64_t byteSize;
1299 list<pair<string, string>> attribs;
1300
1301 attribs.push_back(make_pair("name", variableName));
1302 attribs.push_back(make_pair("mesh", "SpatialGrid"));
1303
1304 if (file.getArrayInfo("VARIABLE", attribs, arraySize, vectorSize, dataType, byteSize) == false) {
1305 logFile << "(RESTART) ERROR: Failed to read DCCRG ArrayInfo" << endl << write;
1306 return false;
1307 }
1308
1309 // Call _readCellParamsVariable
1310 if (dataType == vlsv::datatype::type::FLOAT) {
1311 switch (byteSize) {
1312 case sizeof(double):
1313 return _readCellParamsVariable<double>(file, fileCells, localCellStartOffset, localCells, variableName, cellParamsIndex, expectedVectorSize, mpiGrid);
1314 break;
1315 case sizeof(float):
1316 return _readCellParamsVariable<float>(file, fileCells, localCellStartOffset, localCells, variableName, cellParamsIndex, expectedVectorSize, mpiGrid);
1317 break;
1318 }
1319 } else if (dataType == vlsv::datatype::type::UINT) {
1320 switch (byteSize) {
1321 case sizeof(uint32_t):
1322 return _readCellParamsVariable<uint32_t>(file, fileCells, localCellStartOffset, localCells, variableName, cellParamsIndex, expectedVectorSize, mpiGrid);
1323 break;
1324 case sizeof(uint64_t):
1325 return _readCellParamsVariable<uint64_t>(file, fileCells, localCellStartOffset, localCells, variableName, cellParamsIndex, expectedVectorSize, mpiGrid);
1326 break;
1327 }
1328 } else if (dataType == vlsv::datatype::type::INT) {
1329 switch (byteSize) {
1330 case sizeof(int32_t):
1331 return _readCellParamsVariable<int32_t>(file, fileCells, localCellStartOffset, localCells, variableName, cellParamsIndex, expectedVectorSize, mpiGrid);
1332 break;
1333 case sizeof(int64_t):
1334 return _readCellParamsVariable<int64_t>(file, fileCells, localCellStartOffset, localCells, variableName, cellParamsIndex, expectedVectorSize, mpiGrid);
1335 break;
1336 }
1337 } else {
1338 logFile << "(RESTART) ERROR: Failed to read data type at readCellParamsVariable" << endl << write;
1339 return false;
1340 }
1341 // For compiler purposes
1342 return false;
1343}
1344
1351template <unsigned long int N>
1352bool readFsGridVariable(vlsv::ParallelReader& file, const string& variableName, int numWritingRanks,
1354 std::span<std::array<Real, N>> targetData) {
1355 phiprof::Timer preparations{"preparations"};
1356
1357 uint64_t arraySize;
1358 uint64_t vectorSize;
1359 vlsv::datatype::type dataType;
1360 uint64_t byteSize;
1361 list<pair<string, string>> attribs;
1362 bool convertFloatType = false;
1363
1364 attribs.push_back(make_pair("name", variableName));
1365 attribs.push_back(make_pair("mesh", "fsgrid"));
1366
1367 phiprof::Timer getArrayInfo{"getArrayInfo"};
1368 if (file.getArrayInfo("VARIABLE", attribs, arraySize, vectorSize, dataType, byteSize) == false) {
1369 logFile << "(RESTART) ERROR: Failed to read FsGrid ArrayInfo " << endl << write;
1370 return false;
1371 }
1372 if (!(dataType == vlsv::datatype::type::FLOAT && byteSize == sizeof(Real))) {
1373 logFile << "(RESTART) Converting floating point format of fsgrid variable " << variableName << " from "
1374 << byteSize * 8 << " bits to " << sizeof(Real) * 8 << " bits." << endl
1375 << write;
1376 convertFloatType = true;
1377 // Note: this implicitly assumes that Real is of type double, and we either read a double in directly, or read a
1378 // float and convert it to double.
1379 }
1380 getArrayInfo.stop();
1381
1382 // Are we restarting from the same number of tasks, or a different number?
1383 int size, myRank;
1384 MPI_Comm_size(MPI_COMM_WORLD, &size);
1385 MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
1386
1387 const auto* localSize = &fsgrid.getLocalSize()[0];
1388 const auto& localStart = fsgrid.getLocalStart();
1389 const auto& globalSize = fsgrid.getGlobalSize();
1390
1391 // Determine our tasks storage size
1392 size_t storageSize = localSize[0] * localSize[1] * localSize[2];
1393
1394 preparations.stop();
1395 std::array<fsgrid::Task_t, 3> fileDecomposition = {0, 0, 0};
1396 // No override given (zero array)
1397 if (P::overrideReadFsGridDecomposition == fileDecomposition) {
1398 // Try and read the decomposition from file
1399 if (readFsgridDecomposition(file, fileDecomposition) == false) {
1400 exitOnError(false, "(RESTART) Failed to read Fsgrid decomposition", MPI_COMM_WORLD);
1401 }
1402 } else {
1403 // Override
1404 logFile << "(RESTART) Using manual override for FsGrid MESH_DECOMPOSITION." << endl << write;
1405 fileDecomposition = P::overrideReadFsGridDecomposition;
1406 int fsgridInputRanks = 0;
1407 // Read numWritingRanks from file, that should exist and be sane
1408 if (readScalarParameter(file, "numWritingRanks", fsgridInputRanks, MASTER_RANK, MPI_COMM_WORLD) == false) {
1409 exitOnError(false, "(RESTART) FSGrid writing rank number not found in restart file", MPI_COMM_WORLD);
1410 }
1411 // Check that the override is sane wrt. numWritingRanks
1412 if (fileDecomposition[0] * fileDecomposition[1] * fileDecomposition[2] != fsgridInputRanks) {
1414 false,
1415 "(RESTART) Trying to use a manual FsGrid decomposition for a file with a differing number of input ranks.",
1416 MPI_COMM_WORLD);
1417 }
1418 }
1419
1420 const auto& decomposition = fsgrid.getDecomposition();
1421
1422 if (decomposition == fileDecomposition) {
1423 // Easy case: same decomposition => slurp it in.
1424 //
1425
1426 // Determine offset in file by summing up all the previous tasks' sizes.
1427 size_t localStartOffset = 0;
1428 for (fsgrid::Task_t task = 0; task < myRank; task++) {
1429 std::array<fsgrid::FsIndex_t, 3> thatTasksSize;
1430 thatTasksSize[0] = fsgrid::calcLocalSize(globalSize[0], decomposition[0], task / decomposition[2] / decomposition[1]);
1431 thatTasksSize[1] = fsgrid::calcLocalSize(globalSize[1], decomposition[1], (task / decomposition[2]) % decomposition[1]);
1432 thatTasksSize[2] = fsgrid::calcLocalSize(globalSize[2], decomposition[2], task % decomposition[2]);
1433 localStartOffset += thatTasksSize[0] * thatTasksSize[1] * thatTasksSize[2];
1434 }
1435
1436 // Read into buffer
1437 std::vector<Real> buffer(storageSize * N);
1438
1439 if (file.readArray("VARIABLE", attribs, localStartOffset, storageSize, buffer.data()) == false) {
1440 logFile << "(RESTART) ERROR: Failed to read fsgrid variable " << variableName << endl << write;
1441 return false;
1442 }
1443
1444 // Assign buffer into fsgrid
1445 // Should work in parallel too.
1446 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
1447 phiprof::initializeTimer("Map Refinement Level to FsGrid"), technical,
1448 [=](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
1449 cint index = N * (stencil.k * coordinates.localSize[1] * coordinates.localSize[0] + stencil.j * coordinates.localSize[0] + stencil.i);
1450 memcpy(targetData[stencil.ooo()].data(), &buffer[index], N * sizeof(Real));
1451 });
1452
1453 } else {
1454
1455 // More difficult case: different number of tasks.
1456 // In this case, our own fsgrid domain overlaps (potentially many) domains in the file.
1457 // We read the whole source rank into a temporary buffer, and transfer the overlapping
1458 // part.
1459 //
1460 // +------------+----------------+
1461 // | | |
1462 // | . . . . . . . . . . . . |
1463 // | .<----->|<----------->. |
1464 // | .<----->|<----------->. |
1465 // | .<----->|<----------->. |
1466 // +----+-------+-------------+--|
1467 // | .<----->|<----------->. |
1468 // | .<----->|<----------->. |
1469 // | .<----->|<----------->. |
1470 // | . . . . . . . . . . . . |
1471 // | | |
1472 // +------------+----------------+
1473
1474 // Iterate through tasks and find their overlap with our domain.
1475 size_t fileOffset = 0;
1476 for (int task = 0; task < numWritingRanks; task++) {
1477
1478 phiprof::Timer taskArithmetics1{"task overlap arithmetics 1"};
1479
1480 std::array<fsgrid::FsIndex_t, 3> thatTasksSize;
1481 std::array<fsgrid::FsIndex_t, 3> thatTasksStart;
1482 thatTasksSize[0] = fsgrid::calcLocalSize(globalSize[0], fileDecomposition[0], task / fileDecomposition[2] / fileDecomposition[1]);
1483 thatTasksSize[1] = fsgrid::calcLocalSize(globalSize[1], fileDecomposition[1], (task / fileDecomposition[2]) % fileDecomposition[1]);
1484 thatTasksSize[2] = fsgrid::calcLocalSize(globalSize[2], fileDecomposition[2], task % fileDecomposition[2]);
1485
1486 thatTasksStart[0] = fsgrid::calcLocalStart(globalSize[0], fileDecomposition[0], task / fileDecomposition[2] / fileDecomposition[1]);
1487 thatTasksStart[1] = fsgrid::calcLocalStart(globalSize[1], fileDecomposition[1], (task / fileDecomposition[2]) % fileDecomposition[1]);
1488 thatTasksStart[2] = fsgrid::calcLocalStart(globalSize[2], fileDecomposition[2], task % fileDecomposition[2]);
1489
1490 // Iterate through overlap area
1491 std::array<fsgrid::FsIndex_t, 3> overlapStart, overlapEnd, overlapSize;
1492 overlapStart[0] = max(localStart[0], thatTasksStart[0]);
1493 overlapStart[1] = max(localStart[1], thatTasksStart[1]);
1494 overlapStart[2] = max(localStart[2], thatTasksStart[2]);
1495
1496 overlapEnd[0] = min(localStart[0] + localSize[0], thatTasksStart[0] + thatTasksSize[0]);
1497 overlapEnd[1] = min(localStart[1] + localSize[1], thatTasksStart[1] + thatTasksSize[1]);
1498 overlapEnd[2] = min(localStart[2] + localSize[2], thatTasksStart[2] + thatTasksSize[2]);
1499
1500 overlapSize[0] = max(overlapEnd[0] - overlapStart[0], (fsgrid::FsIndex_t)0);
1501 overlapSize[1] = max(overlapEnd[1] - overlapStart[1], (fsgrid::FsIndex_t)0);
1502 overlapSize[2] = max(overlapEnd[2] - overlapStart[2], (fsgrid::FsIndex_t)0);
1503
1504 taskArithmetics1.stop();
1505
1506 // Read into buffer
1507 std::vector<Real> buffer(thatTasksSize[0] * thatTasksSize[1] * thatTasksSize[2] * N);
1508
1509 phiprof::Timer multiRead{"multiRead"};
1510 file.startMultiread("VARIABLE", attribs);
1511 // Read every source rank that we have an overlap with.
1512 if (overlapSize[0] * overlapSize[1] * overlapSize[2] > 0) {
1513
1514 if (!convertFloatType) {
1515 if (file.addMultireadUnit((char*)buffer.data(),
1516 thatTasksSize[0] * thatTasksSize[1] * thatTasksSize[2]) == false) {
1517 logFile << "(RESTART) ERROR: Failed to read fsgrid variable " << variableName << endl << write;
1518 return false;
1519 }
1520 file.endMultiread(fileOffset);
1521 } else {
1522 std::vector<float> readBuffer(thatTasksSize[0] * thatTasksSize[1] * thatTasksSize[2] * N);
1523 if (file.addMultireadUnit((char*)readBuffer.data(),
1524 thatTasksSize[0] * thatTasksSize[1] * thatTasksSize[2]) == false) {
1525 logFile << "(RESTART) ERROR: Failed to read fsgrid variable " << variableName << endl << write;
1526 return false;
1527 }
1528 file.endMultiread(fileOffset);
1529
1530 for (uint64_t i = 0; i < thatTasksSize[0] * thatTasksSize[1] * thatTasksSize[2] * N; i++) {
1531 buffer[i] = readBuffer[i];
1532 }
1533 }
1534
1535 // Copy continuous stripes in x direction.
1536 for (auto z = overlapStart[2]; z < overlapEnd[2]; z++) {
1537 for (auto y = overlapStart[1]; y < overlapEnd[1]; y++) {
1538 for (auto x = overlapStart[0]; x < overlapEnd[0]; x++) {
1539 const auto stencil = fsgrid.makeStencil(x, y, z);
1540 const fsgrid::FsIndex_t index = (z - thatTasksStart[2]) * thatTasksSize[0] * thatTasksSize[1] +
1541 (y - thatTasksStart[1]) * thatTasksSize[0] +
1542 (x - thatTasksStart[0]);
1543
1544 memcpy(targetData[stencil.indexFromOffset(-localStart[0], -localStart[1], -localStart[2])].data(),
1545 &buffer[index * N], N * sizeof(Real));
1546 }
1547 }
1548 }
1549 } else {
1550 // If we don't overlap, just perform a dummy read.
1551 file.endMultiread(fileOffset);
1552 }
1553 fileOffset += thatTasksSize[0] * thatTasksSize[1] * thatTasksSize[2];
1554 multiRead.stop();
1555 }
1556 }
1557 phiprof::Timer updateGhostsTimer{"updateGhostCells"};
1558 fsgrid.updateGhostCells(targetData);
1559 updateGhostsTimer.stop();
1560 return true;
1561}
1562
1570bool readIonosphereNodeVariable(vlsv::ParallelReader& file, const string& variableName, SBC::SphericalTriGrid& grid,
1572
1573 uint64_t arraySize;
1574 uint64_t vectorSize;
1575 vlsv::datatype::type dataType;
1576 uint64_t byteSize;
1577 list<pair<string, string>> attribs;
1578
1579 attribs.push_back(make_pair("name", variableName));
1580 attribs.push_back(make_pair("mesh", "ionosphere"));
1581
1582 // If we don't have an ionosphere (zero nodes), we simply skip trying to read any restart data for this.
1583 if (grid.nodes.size() == 0) {
1584 return true;
1585 }
1586
1587 if (file.getArrayInfo("VARIABLE", attribs, arraySize, vectorSize, dataType, byteSize) == false) {
1588 logFile << "(RESTART) ERROR: Failed to read array info for " << variableName << endl << write;
1589 return false;
1590 }
1591
1592 // Verify that this is a scalar variable
1593 if (vectorSize != 1) {
1594 logFile << "(RESTART) ERROR: Trying to read vector valued (" << vectorSize
1595 << " components) ionosphere parameter from restart file. Only scalars are supported." << endl
1596 << write;
1597 return false;
1598 }
1599
1600 // Verify that the size matches our constructed ionosphere object
1601 if (grid.nodes.size() != arraySize) {
1602 logFile << "(RESTART) ERROR: Ionosphere restart size mismatch: trying to read variable " << variableName
1603 << " with " << arraySize << " values into a ionosphere grid with " << grid.nodes.size() << " nodes!"
1604 << endl
1605 << write;
1606 return false;
1607 }
1608
1609 std::vector<Real> buffer(arraySize);
1610 if (file.readArray("VARIABLE", attribs, 0, arraySize, buffer.data()) == false) {
1611 logFile << "(RESTART) ERROR: Failed to read ionosphere variable " << variableName << endl << write;
1612 }
1613
1614 for (uint i = 0; i < grid.nodes.size(); i++) {
1615 grid.nodes[i].parameters[index] = buffer[i];
1616 }
1617
1618 return true;
1619}
1620
1628bool exec_readGrid(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
1629 fsgrids::perbspan perb,
1631 fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, const std::string& name) {
1632 vector<CellID> fileCells; /*< CellIds for all cells in file*/
1633 vector<size_t> nBlocks; /*< Number of blocks for all cells in file*/
1634 bool success = true;
1635 int myRank, processes;
1636
1637 // Note: Spatial grid name hard-coded here.
1638 // But so are the other mesh names below.
1639 const string meshName = "SpatialGrid";
1640
1641 // Attempt to open VLSV file for reading:
1642 MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
1643 MPI_Comm_size(MPI_COMM_WORLD, &processes);
1644
1645 phiprof::Timer readGridTimer{"readGrid"};
1646
1647 phiprof::Timer readScalarsTimer{"readScalars"};
1648
1649 vlsv::ParallelReader file;
1650
1651 MPI_Info MPIinfo;
1652 if (P::restartReadHints.size() == 0) {
1653 MPIinfo = MPI_INFO_NULL;
1654 } else {
1655 MPI_Info_create(&MPIinfo);
1656
1657 for (std::vector<std::pair<std::string, std::string>>::const_iterator it = P::restartReadHints.begin();
1658 it != P::restartReadHints.end(); it++) {
1659 MPI_Info_set(MPIinfo, it->first.c_str(), it->second.c_str());
1660 }
1661 }
1662
1663 if (file.open(name, MPI_COMM_WORLD, MASTER_RANK, MPIinfo) == false) {
1664 success = false;
1665 }
1666 exitOnError(success, "(RESTART) Could not open file", MPI_COMM_WORLD);
1667
1668 // Around May 2015 time was renamed from "t" to "time", we try to read both,
1669 // new way is read first
1670 if (readScalarParameter(file, "time", P::t, MASTER_RANK, MPI_COMM_WORLD) == false) {
1671 if (readScalarParameter(file, "t", P::t, MASTER_RANK, MPI_COMM_WORLD) == false) {
1672 success = false;
1673 }
1674 }
1675 P::t_min = P::t;
1676
1677 // Around May 2015 timestep was renamed from "tstep" to "timestep", we to read
1678 // both, new way is read first
1679 if (readScalarParameter(file, "timestep", P::tstep, MASTER_RANK, MPI_COMM_WORLD) == false) {
1680 if (readScalarParameter(file, "tstep", P::tstep, MASTER_RANK, MPI_COMM_WORLD) == false) {
1681 success = false;
1682 }
1683 }
1685
1686 if (readScalarParameter(file, "dt", P::dt, MASTER_RANK, MPI_COMM_WORLD) == false) {
1687 success = false;
1688 }
1689
1690 if (readScalarParameter(file, "fieldSolverSubcycles", P::fieldSolverSubcycles, MASTER_RANK, MPI_COMM_WORLD) ==
1691 false) {
1692 // Legacy restarts do not have this field, it "should" be safe for one or two steps...
1694 cout << " No P::fieldSolverSubcycles found in restart, setting 1." << endl;
1695 }
1696 MPI_Bcast(&(P::fieldSolverSubcycles), 1, MPI_Type<uint>(), MASTER_RANK, MPI_COMM_WORLD);
1697
1698 checkScalarParameter(file, "xmin", P::xmin, MASTER_RANK, MPI_COMM_WORLD);
1699 checkScalarParameter(file, "ymin", P::ymin, MASTER_RANK, MPI_COMM_WORLD);
1700 checkScalarParameter(file, "zmin", P::zmin, MASTER_RANK, MPI_COMM_WORLD);
1701 checkScalarParameter(file, "xmax", P::xmax, MASTER_RANK, MPI_COMM_WORLD);
1702 checkScalarParameter(file, "ymax", P::ymax, MASTER_RANK, MPI_COMM_WORLD);
1703 checkScalarParameter(file, "zmax", P::zmax, MASTER_RANK, MPI_COMM_WORLD);
1704 checkScalarParameter(file, "xcells_ini", P::xcells_ini, MASTER_RANK, MPI_COMM_WORLD);
1705 checkScalarParameter(file, "ycells_ini", P::ycells_ini, MASTER_RANK, MPI_COMM_WORLD);
1706 checkScalarParameter(file, "zcells_ini", P::zcells_ini, MASTER_RANK, MPI_COMM_WORLD);
1707
1708 readScalarsTimer.stop();
1709
1710 phiprof::Timer readLayoutimer{"readDatalayout"};
1711 if (success) {
1712 success = readCellIds(file, fileCells, MASTER_RANK, MPI_COMM_WORLD);
1713 }
1714
1715 // Check that the cellID lists are identical in file and grid
1716 if (myRank == 0) {
1717 vector<CellID> allGridCells = mpiGrid.get_all_cells();
1718 if (fileCells.size() != allGridCells.size()) {
1719 std::cout << "File has " << fileCells.size() << " cells, got " << allGridCells.size() << " cells!" << std::endl;
1720 success = false;
1721 }
1722 }
1723
1724 exitOnError(success, "(RESTART) Wrong number of cells in restart file", MPI_COMM_WORLD);
1725
1726 // Read the total number of velocity blocks in each spatial cell.
1727 // Note that this is a sum over all existing particle species.
1728 if (success == true) {
1729 success = readNBlocks(file, meshName, nBlocks, MASTER_RANK, MPI_COMM_WORLD);
1730 }
1731
1732 // make sure all cells are empty, we will anyway overwrite everything and
1733 // in that case moving cells is easier...
1734 {
1735 const vector<CellID>& gridCells = getLocalCells();
1736 for (size_t i = 0; i < gridCells.size(); i++) {
1737 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID)
1738 mpiGrid[gridCells[i]]->clear(popID);
1739 }
1740 }
1741
1742 uint64_t totalNumberOfBlocks = 0;
1743 unsigned int numberOfBlocksPerProcess;
1744 for (uint i = 0; i < nBlocks.size(); ++i) {
1745 totalNumberOfBlocks += nBlocks[i];
1746 }
1747 numberOfBlocksPerProcess = 1 + totalNumberOfBlocks / processes;
1748
1749 uint64_t localCellStartOffset = 0; // This is where local cells start in file-list after migration.
1750 uint64_t localCells = 0;
1751 uint64_t numberOfBlocksCount = 0;
1752
1753 // Pin local cells to remote processes, we try to balance number of blocks so that
1754 // each process has the same amount of blocks, more or less.
1755 for (size_t i = 0; i < fileCells.size(); ++i) {
1756 numberOfBlocksCount += nBlocks[i];
1757 int newCellProcess = numberOfBlocksCount / numberOfBlocksPerProcess;
1758 if (newCellProcess == myRank) {
1759 if (localCells == 0)
1760 localCellStartOffset = i; // here local cells start
1761 ++localCells;
1762 }
1763 if (mpiGrid.is_local(fileCells[i])) {
1764 mpiGrid.pin(fileCells[i], newCellProcess);
1765 }
1766 }
1767
1769
1770 // Do initial load balance based on pins. Need to transfer at least sysboundaryflags
1771 mpiGrid.balance_load(false);
1772
1773 // update list of local gridcells
1775
1776 // get new list of local gridcells
1777 const vector<CellID>& gridCells = getLocalCells();
1778
1779 // Unpin cells, otherwise we will never change this initial bad balance
1780 for (size_t i = 0; i < gridCells.size(); ++i) {
1781 mpiGrid.unpin(gridCells[i]);
1782 }
1783
1784 // Check for errors, has migration succeeded
1785 if (localCells != gridCells.size()) {
1786 success = false;
1787 }
1788
1789 if (success == true) {
1790 for (uint64_t i = localCellStartOffset; i < localCellStartOffset + localCells; ++i) {
1791 if (mpiGrid.is_local(fileCells[i]) == false) {
1792 success = false;
1793 }
1794 }
1795 }
1796
1797 exitOnError(success, "(RESTART) Cell migration failed", MPI_COMM_WORLD);
1798
1799 // Set cell coordinates based on cfg (mpigrid) information
1800 for (size_t i = 0; i < gridCells.size(); ++i) {
1801 array<double, 3> cell_min = mpiGrid.geometry.get_min(gridCells[i]);
1802 array<double, 3> cell_length = mpiGrid.geometry.get_length(gridCells[i]);
1803
1804 mpiGrid[gridCells[i]]->parameters[CellParams::XCRD] = cell_min[0];
1805 mpiGrid[gridCells[i]]->parameters[CellParams::YCRD] = cell_min[1];
1806 mpiGrid[gridCells[i]]->parameters[CellParams::ZCRD] = cell_min[2];
1807 mpiGrid[gridCells[i]]->parameters[CellParams::DX] = cell_length[0];
1808 mpiGrid[gridCells[i]]->parameters[CellParams::DY] = cell_length[1];
1809 mpiGrid[gridCells[i]]->parameters[CellParams::DZ] = cell_length[2];
1810 }
1811
1812 // Where local data start in the blocklists
1813 // uint64_t localBlocks=0;
1814 // for(uint64_t i=localCellStartOffset; i<localCellStartOffset+localCells; ++i) {
1815 // localBlocks += nBlocks[i];
1816 //}
1817 readLayoutimer.stop();
1818
1819 // todo, check file datatype, and do not just use double
1820 phiprof::Timer readParametersTimer{"readCellParameters"};
1821 if (success) {
1822 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "moments", CellParams::RHOM, 5, mpiGrid);
1823 }
1824 if (success) {
1825 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "moments_dt2", CellParams::RHOM_DT2, 5, mpiGrid);
1826 }
1827 if (success) {
1828 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "moments_r", CellParams::RHOM_R, 5, mpiGrid);
1829 }
1830 if (success) {
1831 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "moments_v", CellParams::RHOM_V, 5, mpiGrid);
1832 }
1833 if (success) {
1834 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "pressure", CellParams::P_11, 3, mpiGrid);
1835 }
1836 if (success) {
1837 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "pressure_dt2", CellParams::P_11_DT2, 3, mpiGrid);
1838 }
1839 if (success) {
1840 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "pressure_r", CellParams::P_11_R, 3, mpiGrid);
1841 }
1842 if (success) {
1843 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "pressure_v", CellParams::P_11_V, 3, mpiGrid);
1844 }
1845 if (success) {
1846 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "LB_weight", CellParams::LBWEIGHTCOUNTER, 1, mpiGrid);
1847 }
1848 if (success) {
1849 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "max_v_dt", CellParams::MAXVDT, 1, mpiGrid);
1850 }
1851 if (success) {
1852 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "max_r_dt", CellParams::MAXRDT, 1, mpiGrid);
1853 }
1854 if (success) {
1855 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "max_fields_dt", CellParams::MAXFDT, 1, mpiGrid);
1856 }
1857 if (success) {
1858 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "vg_drift", CellParams::BULKV_FORCING_X, 3, mpiGrid);
1859 }
1860 if (P::refineOnRestart) {
1861 // Refinement indices alpha_1 and alpha_2
1862 if (success) {
1863 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "vg_amr_alpha1", CellParams::AMR_ALPHA1, 1, mpiGrid);
1864 }
1865 if (success) {
1866 success = readCellParamsVariable(file, fileCells, localCellStartOffset, localCells, "vg_amr_alpha2", CellParams::AMR_ALPHA2, 1, mpiGrid);
1867 }
1868 }
1869
1870 // Backround B has to be set, there are also the derivatives that should be written/read if we wanted to only read in
1871 // background field
1872 readParametersTimer.stop();
1873
1874 phiprof::Timer readBlocksTimer{"readBlockData"};
1875 if (success == true) {
1876 success = readBlockData(file, meshName, fileCells, localCellStartOffset, localCells, mpiGrid);
1877 }
1878 readBlocksTimer.stop();
1879
1880 phiprof::Timer updateNeighborsTimer{"updateMpiGridNeighbors"};
1881 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::FULL);
1882 updateNeighborsTimer.stop();
1883
1884 phiprof::Timer readfsTimer{"readFsGrid"};
1885 // Read fsgrid data back in
1886 int fsgridInputRanks = 0;
1887 phiprof::Timer tReadScalarParameter{"readScalarParameter"};
1888 if (readScalarParameter(file, "numWritingRanks", fsgridInputRanks, MASTER_RANK, MPI_COMM_WORLD) == false) {
1889 exitOnError(false, "(RESTART) FSGrid writing rank number not found in restart file", MPI_COMM_WORLD);
1890 }
1891 tReadScalarParameter.stop();
1892
1893 if (success) {
1894 success = readFsGridVariable(file, "fg_PERB", fsgridInputRanks, technical, fsgrid, perb);
1895 }
1896 if (success) {
1897 success = readFsGridVariable(file, "fg_E", fsgridInputRanks, technical, fsgrid, e);
1898 }
1899 exitOnError(success, "(RESTART) Failure reading fsgrid restart variables", MPI_COMM_WORLD);
1900 readfsTimer.stop();
1901
1902 phiprof::Timer readIonosphereTimer{"readIonosphere"};
1903 bool ionosphereSuccess = true;
1905 // Reconstruct source term by multiplying the fac density with the element area
1906 for (uint i = 0; i < SBC::ionosphereGrid.nodes.size(); i++) {
1907 Real area = 0;
1908 for (uint e = 0; e < SBC::ionosphereGrid.nodes[i].numTouchingElements; e++) {
1909 area += SBC::ionosphereGrid.elementArea(SBC::ionosphereGrid.nodes[i].touchingElements[e]);
1910 }
1911 area /= 3.; // As every element has 3 corners, don't double-count areas
1912 SBC::ionosphereGrid.nodes[i].parameters[ionosphereParameters::SOURCE] *= area;
1913 }
1917 if (!ionosphereSuccess) {
1918 logFile << "(RESTART) Reading ionosphere variables failed. Continuing anyway. Variables will be zero, assuming "
1919 "this is an ionosphere cold start?"
1920 << std::endl;
1921 }
1922
1923 // Read additional variables that are not formally required for solving the
1924 // ionosphere, but help making the first output consistent if ionosphere
1925 // timestep is very large.
1926 // If these are missing from the restart file, we are fine continuing with
1927 // zeros.
1928 bool ionosphereOptionalSuccess = readIonosphereNodeVariable(file, "ig_sigmah", SBC::ionosphereGrid, ionosphereParameters::SIGMAH);
1929 ionosphereOptionalSuccess &= readIonosphereNodeVariable(file, "ig_sigmap", SBC::ionosphereGrid, ionosphereParameters::SIGMAP);
1930 ionosphereOptionalSuccess &= readIonosphereNodeVariable(file, "ig_sigmaparallel", SBC::ionosphereGrid, ionosphereParameters::SIGMAPARALLEL);
1931 ionosphereOptionalSuccess &= readIonosphereNodeVariable(file, "ig_precipitation", SBC::ionosphereGrid, ionosphereParameters::PRECIP);
1932 if (ionosphereSuccess && !ionosphereOptionalSuccess) {
1933 logFile << "(RESTART) Restart file contains no ionosphere conductivity data. Ionosphere will run fine, but first "
1934 "output bulk file might have bogus conductivities."
1935 << std::endl;
1936 }
1937 readIonosphereTimer.stop();
1938
1939 success = file.close();
1940
1941 exitOnError(success, "(RESTART) Other failure", MPI_COMM_WORLD);
1942 return success;
1943}
1944
1945// FIXME, readGrid has no support for checking or converting endianness
1951bool readGrid(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
1952 fsgrids::perbspan perb,
1954 fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, const std::string& name) {
1955 // Check the vlsv version from the file:
1956 return exec_readGrid(mpiGrid, perb, e, technical, fsgrid, name);
1957}
1958
1964bool readFileCells(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid, const std::string& name) {
1965 phiprof::Timer readCellIdsTimer{"Restart read File cellIDs"};
1966 vector<CellID> fileCells; /*< CellIds for all cells in file*/
1967 bool success = true;
1968 vlsv::ParallelReader file;
1969 MPI_Info mpiInfo = MPI_INFO_NULL;
1970
1971 // Not sure if this success business is useful at all...
1972 success = file.open(name, MPI_COMM_WORLD, MASTER_RANK, mpiInfo);
1973 exitOnError(success, "(READ_FILE_CELLS) Could not open file", MPI_COMM_WORLD);
1974
1975 readCellIds(file, fileCells, MASTER_RANK, MPI_COMM_WORLD);
1976 phiprof::Timer loadCellsTimer{"load CellIDs into grid"};
1977 success = mpiGrid.load_cells(fileCells);
1978 exitOnError(success, "(READ_FILE_CELLS) Failed to refine grid", MPI_COMM_WORLD);
1979 loadCellsTimer.stop();
1980
1981 success = file.close();
1982 exitOnError(success, "(READ_FILE_CELLS) Other error", MPI_COMM_WORLD);
1983 return success;
1984}
1985
1986bool readFsgridDecomposition(vlsv::ParallelReader& file, std::array<fsgrid::Task_t, 3>& decomposition) {
1987 list<pair<string, string>> attribs;
1988 int myRank;
1989 MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
1990
1991 phiprof::Timer readFsGridDecomposition{"readFsGridDecomposition"};
1992
1993 attribs.push_back(make_pair("mesh", "fsgrid"));
1994
1995 std::array<fsgrid::FsSize_t, 3> gridSize;
1996 fsgrid::FsSize_t* gridSizePtr = &gridSize[0];
1997 bool success = file.read("MESH_BBOX", attribs, 0, 3, gridSizePtr, false);
1998 if (success == false) {
1999 exitOnError(false, "(RESTART) FSGrid gridsize not found in file.", MPI_COMM_WORLD);
2000 return false;
2001 }
2002
2003 std::array<fsgrid::Task_t, 3> fsGridDecomposition = {0, 0, 0};
2004 fsgrid::Task_t* ptr = &fsGridDecomposition[0];
2005
2006 success = file.read("MESH_DECOMPOSITION", attribs, 0, 3, ptr, false);
2007 if (success == false) {
2008 if (myRank == MASTER_RANK) {
2009 std::cout << "Could not read MESH_DECOMPOSITION, attempting to calculate it from MESH." << endl;
2010 }
2011 int fsgridInputRanks = 0;
2012 if (file.readParameter("numWritingRanks", fsgridInputRanks) == false) {
2013 exitOnError(false, "(RESTART) FSGrid writing rank number not found in restart file.", MPI_COMM_WORLD);
2014 return false;
2015 }
2016
2017 int64_t* domainInfo = NULL;
2018 success = file.read("MESH_DOMAIN_SIZES", attribs, 0, fsgridInputRanks, domainInfo);
2019 if (success == false) {
2020 if (myRank == MASTER_RANK) {
2021 std::cerr << "Could not read MESH_DOMAIN_SIZES from file" << endl;
2022 }
2023 return false;
2024 }
2025 std::vector<uint64_t> mesh_domain_sizes;
2026 for (int i = 0; i < 2 * fsgridInputRanks; i += 2) {
2027 mesh_domain_sizes.push_back(domainInfo[i]);
2028 }
2029 list<pair<string, string>> mesh_attribs;
2030 mesh_attribs.push_back(make_pair("name", "fsgrid"));
2031 std::vector<fsgrid::FsSize_t> rank_first_ids(fsgridInputRanks);
2032 fsgrid::FsSize_t* ids_ptr = &rank_first_ids[0];
2033
2034 std::set<fsgrid::FsIndex_t> x_corners, y_corners, z_corners;
2035
2036 int64_t begin_rank = 0;
2037 for (auto rank_size : mesh_domain_sizes) {
2038 if (myRank == MASTER_RANK) {
2039 if (file.read("MESH", mesh_attribs, begin_rank, 1, ids_ptr, false) == false) {
2040 if (myRank == 0) {
2041 std::cerr << "Reading MESH failed.\n";
2042 }
2043 return false;
2044 }
2045 std::array<fsgrid::FsIndex_t, 3> inds = fsgrid::globalIDtoCellCoord(*ids_ptr, gridSize);
2046 x_corners.insert(inds[0]);
2047 y_corners.insert(inds[1]);
2048 z_corners.insert(inds[2]);
2049 ++ids_ptr;
2050 begin_rank += rank_size;
2051 } else {
2052 file.read("MESH", mesh_attribs, begin_rank, 0, ids_ptr, false);
2053 }
2054 }
2055
2056 decomposition[0] = x_corners.size();
2057 decomposition[1] = y_corners.size();
2058 decomposition[2] = z_corners.size();
2059 MPI_Bcast(&decomposition, 3, MPI_INT, MASTER_RANK, MPI_COMM_WORLD);
2060
2061 if (decomposition[0] * decomposition[1] * decomposition[2] == fsgridInputRanks) {
2062 if (myRank == MASTER_RANK) {
2063 std::cout << "Fsgrid decomposition computed from MESH to be " << decomposition[0] << " " << decomposition[1] << " " << decomposition[2] << endl;
2064 }
2065 return true;
2066 } else {
2067 if (myRank == MASTER_RANK) {
2068 std::cout << "Fsgrid decomposition computed from MESH to be " << decomposition[0] << " " << decomposition[1] << " " << decomposition[2] << ", which is not compatible with numWritingRanks (" << fsgridInputRanks << ")" << endl;
2069 }
2070 return false;
2071 }
2072
2073 } else {
2074 decomposition[0] = fsGridDecomposition[0];
2075 decomposition[1] = fsGridDecomposition[1];
2076 decomposition[2] = fsGridDecomposition[2];
2077 logFile << "(RESTART) Fsgrid decomposition read as " << decomposition[0] << " " << decomposition[1] << " " << decomposition[2] << "\n";
2078 return true;
2079 }
2080 return false;
2081}
Binary file
Definition Dispersion.m:11
for i
Definition Dispersion.m:24
set(gca, 'YDir', 'normal')
Constants c
Definition Dispersion.m:45
#define CHK_ERR(err)
#define gpuMallocHost
#define gpuFreeHost
void adjustSingleCellVelocityBlocks(const uint popID, bool doDeleteEmpty=false)
static void set_mpi_transfer_type(const uint64_t type, bool atSysBoundaries=false)
vmesh::GlobalID get_velocity_block(const uint popID, vmesh::GlobalID blockIndices[3]) const
bool add_velocity_block(const vmesh::GlobalID &block, const uint popID)
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
ionosphereParameters
Definition common.h:458
@ SOURCE
Definition common.h:459
@ SIGMAP
Definition common.h:464
@ SOLUTION
Definition common.h:472
@ SIGMAPARALLEL
Definition common.h:466
@ SIGMAH
Definition common.h:465
@ PRECIP
Definition common.h:467
@ TEMPERATURE
Definition common.h:469
@ RHON
Definition common.h:468
#define MASTER_RANK
Definition common.h:67
const int WID3
Definition common.h:517
Parameters P
const uint32_t cuint
Definition definitions.h:50
float Real
Definition definitions.h:41
const int cint
Definition definitions.h:45
uint64_t CellID
Definition definitions.h:54
float Realf
Definition definitions.h:33
fsgrid::FsGrid< FS_STENCIL_WIDTH > FieldSolverGrid
Definition definitions.h:78
__global__ void vmesh::VelocityMesh **__restrict__ ColumnOffsets split::SplitVector< vmesh::GlobalID > Hashinator::Hashmap< vmesh::GlobalID, vmesh::LocalID > const uint *__restrict__ const Realf const int const int const Realf const Realf dv
int myRank
Definition gpu_base.cpp:48
Logger logFile
Definition main.cpp:25
const int j
const int k
void recalculateLocalCellsCache(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:1486
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
bool readFsGridVariable(vlsv::ParallelReader &file, const string &variableName, int numWritingRanks, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, std::span< std::array< Real, N > > targetData)
Definition ioread.cpp:1352
bool exitOnError(bool success, const string &message, MPI_Comm comm)
Collective exit on error functions.
Definition ioread.cpp:152
bool readFsgridDecomposition(vlsv::ParallelReader &file, std::array< fsgrid::Task_t, 3 > &decomposition)
Definition ioread.cpp:1986
bool readCellIds(vlsv::ParallelReader &file, vector< CellID > &fileCells, const int masterRank, MPI_Comm comm)
Read cell ID's Read in cell ID's from file. Note: Uses the newer version of vlsv parallel reader.
Definition ioread.cpp:178
bool readBlockData(vlsv::ParallelReader &file, const string &meshName, const vector< CellID > &fileCells, const uint64_t localCellStartOffset, const uint64_t localCells, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition ioread.cpp:1015
bool _readBlockDataCompressionNone(vlsv::ParallelReader &file, const std::string &spatMeshName, const std::vector< uint64_t > &fileCells, const uint64_t localCellStartOffset, const uint64_t localCells, const vmesh::LocalID *blocksPerCell, const std::vector< uint64_t > &blockSumOffsets, const uint64_t localBlockStartOffset, const uint64_t localBlocks, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, std::function< vmesh::GlobalID(vmesh::GlobalID)> blockIDremapper, const uint popID)
Definition ioread.cpp:371
bool readIonosphereNodeVariable(vlsv::ParallelReader &file, const string &variableName, SBC::SphericalTriGrid &grid, ionosphereParameters index)
Definition ioread.cpp:1570
bool _readBlockData(vlsv::ParallelReader &file, const std::string &spatMeshName, const std::vector< uint64_t > &fileCells, const uint64_t localCellStartOffset, const uint64_t localCells, const vmesh::LocalID *blocksPerCell, const std::vector< uint64_t > &blockSumOffsets, const uint64_t localBlockStartOffset, const uint64_t localBlocks, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, std::function< vmesh::GlobalID(vmesh::GlobalID)> blockIDremapper, const uint popID)
Definition ioread.cpp:954
bool readCellParamsVariable(vlsv::ParallelReader &file, const vector< CellID > &fileCells, const uint64_t localCellStartOffset, const uint64_t localCells, const string &variableName, const size_t cellParamsIndex, const size_t expectedVectorSize, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition ioread.cpp:1291
bool exec_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:1628
void checkExternalCommands()
Checks for command files written to the local directory. If a file STOP was written and is readable,...
Definition ioread.cpp:72
bool checkScalarParameter(vlsv::ParallelReader &file, const string &name, T correctValue, int masterRank, MPI_Comm comm)
Definition ioread.cpp:350
Logger diagnostic
Definition ioread.cpp:59
bool readNBlocks(vlsv::ParallelReader &file, const std::string &meshName, std::vector< size_t > &nBlocks, int masterRank, MPI_Comm comm)
Definition ioread.cpp:252
static bool _readCellParamsVariable(vlsv::ParallelReader &file, const vector< uint64_t > &fileCells, const uint64_t localCellStartOffset, const uint64_t localCells, const string &variableName, const size_t cellParamsIndex, const size_t expectedVectorSize, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition ioread.cpp:1239
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 readScalarParameter(vlsv::ParallelReader &file, string name, T &value, int masterRank, MPI_Comm comm)
Definition ioread.cpp:331
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
Logger & write(Logger &logger)
Definition logger.cpp:193
#define index(i, j, k)
MPI_Datatype MPI_Type()
auto overwrite_pop_spatial_cell_vdf(spatial_cell::SpatialCell *sc, uint popID, const std::vector< Realf > &new_vspace) -> void
std::vector< double > decompressArrayDouble(char *compressedData, size_t compressedSize, size_t arraySize, double tol)
std::vector< float > decompressArrayFloat(char *compressedData, size_t compressedSize, size_t arraySize, float tol)
void overwrite_cellids_vdf_single_cell(const std::span< const CellID > cids, uint popID, spatial_cell::SpatialCell *sc, size_t cc, const std::vector< std::array< T, 3 > > &vcoords, const std::vector< T > &vspace_union, const std::unordered_map< vmesh::LocalID, std::size_t > &map_exists_id)
@ BULKV_FORCING_X
Definition common.h:225
@ AMR_ALPHA2
Definition common.h:221
@ AMR_ALPHA1
Definition common.h:220
@ LBWEIGHTCOUNTER
Definition common.h:198
SphericalTriGrid ionosphereGrid
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, fsgrids::efield::N_EFIELD > > efieldspan
Definition common.h:436
static const uint64_t ALL_SPATIAL_DATA
static const GlobalID INVALID_GLOBALID
Definition definitions.h:63
uint32_t LocalID
Definition definitions.h:60
uint32_t GlobalID
Definition definitions.h:59
ARCH_HOSTDEV MeshWrapper * getMeshWrapper()
std::vector< species::Species > particleSpecies
static Real ymax
Definition parameters.h:41
static std::vector< std::pair< std::string, std::string > > restartReadHints
Definition parameters.h:112
static Real t_min
Definition parameters.h:53
ASTERIX_COMPRESSION_METHODS
Definition parameters.h:249
static Real xmax
Definition parameters.h:39
static uint zcells_ini
Definition parameters.h:50
static Real zmax
Definition parameters.h:43
static bool refineOnRestart
Definition parameters.h:193
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 std::array< fsgrid::Task_t, 3 > overrideReadFsGridDecomposition
Definition parameters.h:246
static uint fieldSolverSubcycles
Definition parameters.h:69
static Real t
Definition parameters.h:52
static bool bailout_write_restart
Definition parameters.h:184
static uint tstep
Definition parameters.h:73
static Real zmin
Definition parameters.h:42
static Real dt
Definition parameters.h:55
static bool balanceLoad
Definition common.h:541
static bool doRefine
Definition common.h:542
static bool writeRecover
Definition common.h:540
static bool writeRestart
Definition common.h:539
std::array< vmesh::MeshParameters, MAX_VMESH_PARAMETERS_COUNT > * velocityMeshes
static ARCH_HOSTDEV VecSimple< T > min(VecSimple< T > const &l, VecSimple< T > const &r)
static ARCH_HOSTDEV VecSimple< T > max(VecSimple< T > const &l, VecSimple< T > const &r)