Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
iowrite.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2016 Finnish Meteorological Institute
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
26
27#include <cstddef>
28#include <cstdlib>
29#include <iostream>
30#include <iomanip> // for setprecision()
31#include <cmath>
32#include <sstream>
33#include <ctime>
34#include <cstring>
35#include <array>
36#include <algorithm>
37#include <limits>
38#include <initializer_list>
39#include "object_wrapper.h"
40
41
43#include "iowrite.h"
45#include "math.h"
46#include "grid.h"
47#include "phiprof.hpp"
48#include "parameters.h"
49#include "logger.h"
51#include "object_wrapper.h"
55
56using namespace std;
57using namespace vlsv;
58
60
61char* IObuffer = 0; // For GPU VDF output
62typedef Parameters P;
63
64bool writeVelocityDistributionData(const uint popID, Writer& vlsvWriter,
65 const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
66 const std::vector<CellID>& cells, MPI_Comm comm);
67
68bool writeVelocityDistributionDataAsterix(const uint popID,Writer& vlsvWriter,
69 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
70 const std::vector<CellID>& cells,std::vector<std::vector<char>>&mpl_bytes,MPI_Comm comm);
71
72
79bool updateLocalIds(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
80 const std::vector<CellID>& local_cells,
81 MPI_Comm comm) {
82 int myRank;
83 MPI_Comm_rank(comm, &myRank);
84
85 // Declare an iterator for iterating though the cell ids
86 vector<CellID>::const_iterator it;
87 // Local ids for the process start from 0 (this is used in the iteration)
88 CellID thisProcessLocalId = 0;
89 // Iterate through local cells
90 for (it = local_cells.begin(); it != local_cells.end(); ++it) {
91 // NOTE: (*it) = cellId
92 // Set the local id
93 mpiGrid[(*it)]->ioLocalCellId = thisProcessLocalId;
94 // Increment the local id
95 thisProcessLocalId++;
96 }
97 // Update the local ids (let the other processes know they've been updated)
99 mpiGrid.update_copies_of_remote_neighbors(Neighborhoods::FULL);
100
101 return true;
102}
103
110bool globalSuccess(bool success, const string& errorMessage, MPI_Comm comm) {
111 int successInt;
112 int globalSuccessInt;
113 if (success) {
114 successInt = 1;
115 } else {
116 successInt = 0;
117 }
118
119 MPI_Allreduce(&successInt, &globalSuccessInt, 1, MPI_INT, MPI_MIN, comm);
120
121 if (globalSuccessInt == 1) {
122 return true;
123 } else {
124 logFile << errorMessage << endl << write;
125 return false;
126 }
127}
128
135bool writeVelocityDistributionData(Writer& vlsvWriter,
136 const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
137 const vector<CellID>& cells, MPI_Comm comm) {
138 bool success = true;
139 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID) {
140 if (writeVelocityDistributionData(popID, vlsvWriter, mpiGrid, cells, comm) == false) success = false;
141 }
142 return success;
143}
144
146 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
147 const vector<CellID>& cells,std::vector<std::vector<char>>&mlp_bytes,MPI_Comm comm) {
148 bool success = true;
149 for (size_t p=0; p<getObjectWrapper().particleSpecies.size(); ++p) {
150 if (writeVelocityDistributionDataAsterix(p,vlsvWriter,mpiGrid,cells,mlp_bytes,comm) == false) success = false;
151 }
152 return success;
153}
154
161bool writeVelocityDistributionData(const uint popID, Writer& vlsvWriter,
162 const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
163 const std::vector<CellID>& cells, MPI_Comm comm) {
164 // Write velocity blocks and related data.
165 // In restart we just write velocity grids for all cells.
166 // First write global Ids of those cells which write velocity blocks (here: all cells):
167 map<string, string> attribs;
168 const string popName = getObjectWrapper().particleSpecies[popID].name;
169 const string spatMeshName = "SpatialGrid";
170 attribs["name"] = popName;
171 bool success = true;
172
173 // Compute totalBlocks
174 uint64_t totalBlocks = 0;
175 vector<vmesh::LocalID> blocksPerCell;
176 for (size_t i = 0; i < cells.size(); ++i) {
177 totalBlocks += mpiGrid[cells[i]]->get_number_of_velocity_blocks(popID);
178 blocksPerCell.push_back(mpiGrid[cells[i]]->get_number_of_velocity_blocks(popID));
179 }
180
181 // The name of the mesh is "SpatialGrid"
182 attribs["mesh"] = spatMeshName;
183
184 const unsigned int vectorSize = 1;
185 // Write the array:
186 if (vlsvWriter.writeArray("CELLSWITHBLOCKS", attribs, cells.size(), vectorSize, cells.data()) == false) success = false;
187 if (success == false) logFile << "(MAIN) writeGrid: ERROR failed to write CELLSWITHBLOCKS to file!" << endl << writeVerbose;
188 // Write blocks per cell, this has to be in the same order as cellswitblocks so that extracting works
189 if (vlsvWriter.writeArray("BLOCKSPERCELL", attribs, blocksPerCell.size(), vectorSize, blocksPerCell.data()) == false) success = false;
190 if (success == false) logFile << "(MAIN) writeGrid: ERROR failed to write CELLSWITHBLOCKS to file!" << endl << writeVerbose;
191
192 // Write (partial) velocity mesh data
193 // The mesh bounding box gives the outer extent of the available velocity space
194 // in blocks and cells. Note that this is not the physical extent of that
195 // space, but a purely numerical bounding box.
196 uint64_t bbox[6];
197 const size_t meshID = getObjectWrapper().particleSpecies[popID].velocityMesh;
198 bbox[0] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).gridLength[0];
199 bbox[1] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).gridLength[1];
200 bbox[2] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).gridLength[2];
201 bbox[3] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).blockLength[0];
202 bbox[4] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).blockLength[1];
203 bbox[5] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).blockLength[2];
204
205 attribs.clear();
206 attribs["mesh"] = getObjectWrapper().particleSpecies[popID].name;
207 attribs["type"] = vlsv::mesh::STRING_UCD_AMR;
208
209 // stringstream is necessary here to correctly convert refLevelMaxAllowed (hardcoded to zero now) into a string
210 stringstream ss;
211 // ss << static_cast<unsigned int>(vmesh::getMeshWrapper()->velocityMeshes->at(meshID).refLevelMaxAllowed);
212 ss << static_cast<unsigned int>(0);
213 attribs["max_velocity_ref_level"] = ss.str();
214
215 if (mpiGrid.get_rank() == MASTER_RANK) {
216 if (vlsvWriter.writeArray("MESH_BBOX", attribs, 6, 1, bbox) == false) success = false;
217
218 for (int crd = 0; crd < 3; ++crd) {
219 const size_t N_nodes = bbox[crd] * bbox[crd + 3] + 1;
220 Real* crds = new Real[N_nodes];
221 const Real dV = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).cellSize[crd];
222
223 for (size_t i = 0; i < N_nodes; ++i) {
224 crds[i] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[crd] + i * dV;
225 }
226
227 if (crd == 0) {
228 if (vlsvWriter.writeArray("MESH_NODE_CRDS_X", attribs, N_nodes, 1, crds) == false) success = false;
229 }
230 if (crd == 1) {
231 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Y", attribs, N_nodes, 1, crds) == false) success = false;
232 }
233 if (crd == 2) {
234 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Z", attribs, N_nodes, 1, crds) == false) success = false;
235 }
236 delete[] crds;
237 crds = NULL;
238 }
239 } else {
240 if (vlsvWriter.writeArray("MESH_BBOX", attribs, 0, 1, bbox) == false) success = false;
241 Real* crds = NULL;
242 if (vlsvWriter.writeArray("MESH_NODE_CRDS_X", attribs, 0, 1, crds) == false) success = false;
243 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Y", attribs, 0, 1, crds) == false) success = false;
244 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Z", attribs, 0, 1, crds) == false) success = false;
245 }
246
247 // Write velocity block IDs
248 vector<vmesh::GlobalID> velocityBlockIds(totalBlocks);
249 uint blockIndex = 0;
250 try {
251 // gather data for writing
252 for (size_t i = 0; i < cells.size(); ++i) {
253 SpatialCell* SC = mpiGrid[cells[i]];
254 const vmesh::LocalID nBlocks = SC->get_number_of_velocity_blocks(popID);
255#ifdef USE_GPU
256 const vmesh::GlobalID* GIDlist = SC->get_velocity_grid(popID);
257 CHK_ERR(gpuMemcpy(&velocityBlockIds[blockIndex], GIDlist, nBlocks * sizeof(vmesh::GlobalID), gpuMemcpyDeviceToHost));
258#else
259 for (vmesh::LocalID block_i = 0; block_i < nBlocks; ++block_i) {
260 const vmesh::GlobalID block = SC->get_velocity_block_global_id(block_i, popID);
261 velocityBlockIds[blockIndex + block_i] = block;
262 }
263#endif
264 blockIndex += nBlocks;
265 }
266 } catch (...) {
267 cerr << "FAILED TO WRITE VELOCITY BLOCK IDS AT: " << __FILE__ << " " << __LINE__ << endl;
268 success = false;
269 }
270
271 if (globalSuccess(success, "(MAIN) writeGrid: ERROR: Failed to fill temporary array velocityBlockIds", MPI_COMM_WORLD) == false) {
272 vlsvWriter.close();
273 return false;
274 }
275
276 attribs.clear();
277 attribs["mesh"] = spatMeshName;
278 attribs["name"] = popName;
279 if (vlsvWriter.writeArray("BLOCKIDS", attribs, totalBlocks, vectorSize, velocityBlockIds.data()) == false) success = false;
280 if (success == false) logFile << "(MAIN) writeGrid: ERROR failed to write BLOCKIDS to file!" << endl << writeVerbose;
281
282 vector<vmesh::GlobalID>().swap(velocityBlockIds);
283
284 // Write the velocity space data
285 // set everything that is needed for writing in data such as the array name, size, datatype, etc..
286 attribs.clear();
287 attribs["mesh"] = spatMeshName; // Name of the spatial mesh
288 attribs["name"] = popName; // Name of the velocity space distribution is written avgs
289 const string datatype_avgs = "float";
290 const uint64_t arraySize_avgs = totalBlocks;
291 const uint64_t vectorSize_avgs = WID3; // There are 64 (WID=4) or 512 (WID=8) elements in every velocity block
292
293 // Get the data size needed for writing in data
294 uint64_t dataSize_avgs = sizeof(Realf);
295
296 // Start multi write
297 vlsvWriter.startMultiwrite(datatype_avgs, arraySize_avgs, vectorSize_avgs, dataSize_avgs);
298
299#ifdef USE_GPU
300 // single pinned host buffer for facilitating IO from GPU memory
301 uint64_t bufferOffset = 0;
302 CHK_ERR(gpuMallocHost((void**)&IObuffer, totalBlocks * WID3 * sizeof(Realf)));
303#endif
304 // Loop over cells
305 for (size_t i = 0; i < cells.size(); ++i) {
306 // Get the spatial cell
307 SpatialCell* SC = mpiGrid[cells[i]];
308
309 // Get the number of blocks in this cell
310 const uint64_t arrayElements = SC->get_number_of_velocity_blocks(popID);
311 // Add a subarray to write. Note: We told beforehands that the vectorsize = WID3
312#ifdef USE_GPU
313 char* arrayToWrite = IObuffer + bufferOffset;
314 if (arrayElements > 0) {
315 CHK_ERR(gpuMemcpy(arrayToWrite, SC->get_data(popID), arrayElements * WID3 * sizeof(Realf), gpuMemcpyDeviceToHost));
316 bufferOffset += arrayElements * WID3 * sizeof(Realf);
317 }
318#else
319 char* arrayToWrite = reinterpret_cast<char*>(SC->get_data(popID));
320#endif
321 vlsvWriter.addMultiwriteUnit(arrayToWrite, arrayElements);
322 }
323 if (cells.size() == 0) {
324 vlsvWriter.addMultiwriteUnit(NULL, 0); // Dummy write to avoid hang in end multiwrite
325 }
326
327 // Write the subarrays
328 vlsvWriter.endMultiwrite("BLOCKVARIABLE", attribs);
329
330 if (globalSuccess(success, "(MAIN) writeGrid: ERROR: Failed to fill temporary velocityBlockData array", MPI_COMM_WORLD) == false) {
331 vlsvWriter.close();
332 return false;
333 }
334
335 if (success == false) {
336 logFile << "(MAIN) writeGrid: ERROR occurred when writing BLOCKVARIABLE f" << endl << writeVerbose;
337 }
338
339 return success;
340}
341
342bool writeVspaceDataCompressionNone(const uint popID,Writer& vlsvWriter,
343 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
344 const std::vector<CellID>& cells,std::size_t totalBlocks, MPI_Comm comm){
345
346 const int cmp=P::vdf_compression_method;
347 vlsvWriter.writeParameter("COMPRESSION",&cmp);
348 bool success=true;
349 const string popName = getObjectWrapper().particleSpecies[popID].name;
350 const string spatMeshName = "SpatialGrid";
351 map<string,string> attribs;
352 vector<vmesh::GlobalID> velocityBlockIds;
353 try {
354 velocityBlockIds.reserve( totalBlocks );
355 // gather data for writing
356 for (size_t cell=0; cell<cells.size(); ++cell) {
357 SpatialCell* SC = mpiGrid[cells[cell]];
358 for (vmesh::LocalID block_i=0; block_i<SC->get_number_of_velocity_blocks(popID); ++block_i) {
359 vmesh::GlobalID block = SC->get_velocity_block_global_id(block_i,popID);
360 velocityBlockIds.push_back( block );
361 }
362 }
363 } catch (...) {
364 cerr << "FAILED TO WRITE VELOCITY BLOCK IDS AT: " << __FILE__ << " " << __LINE__ << endl;
365 success=false;
366 }
367
368 if (globalSuccess(success,"(MAIN) writeGrid: ERROR: Failed to fill temporary array velocityBlockIds",MPI_COMM_WORLD) == false) {
369 vlsvWriter.close();
370 return false;
371 }
372
373 attribs.clear();
374 attribs["mesh"] = spatMeshName;
375 attribs["name"] = popName;
376 if (vlsvWriter.writeArray("BLOCKIDS", attribs, totalBlocks, 1, velocityBlockIds.data()) == false) success = false;
377 if (success == false) logFile << "(MAIN) writeGrid: ERROR failed to write BLOCKIDS to file!" << endl << writeVerbose;
378 {
379 vector<vmesh::GlobalID>().swap(velocityBlockIds);
380 }
381
382 attribs.clear();
383 attribs["mesh"] = spatMeshName;
384 attribs["name"] = popName;
385 attribs["compression"] = "None";
386 const string datatype_avgs = "float";
387 const uint64_t arraySize_avgs = totalBlocks;
388 const uint64_t vectorSize_avgs = WID3; // There are 64 elements in every velocity block
389
390 // Get the data size needed for writing in data
391 uint64_t dataSize_avgs = sizeof(Realf);
392
393 // Start multi write
394 vlsvWriter.startMultiwrite(datatype_avgs,arraySize_avgs,vectorSize_avgs,dataSize_avgs);
395
396 // Loop over cells
397 for (size_t cell = 0; cell<cells.size(); ++cell) {
398 // Get the spatial cell
399 SpatialCell* SC = mpiGrid[cells[cell]];
400
401 // Get the number of blocks in this cell
402 const uint64_t arrayElements = SC->get_number_of_velocity_blocks(popID);
403 char* arrayToWrite = reinterpret_cast<char*>(SC->get_data(popID));
404
405 // Add a subarray to write
406 vlsvWriter.addMultiwriteUnit(arrayToWrite, arrayElements); // Note: We told beforehands that the vectorsize = WID3 = 64
407 }
408 if (cells.size() == 0) {
409 vlsvWriter.addMultiwriteUnit(NULL, 0); //Dummy write to avoid hang in end multiwrite
410 }
411 // Write the subarrays
412 vlsvWriter.endMultiwrite("BLOCKVARIABLE", attribs);
413
414 if (globalSuccess(success,"(MAIN) writeGrid: ERROR: Failed to fill temporary velocityBlockData array",MPI_COMM_WORLD) == false) {
415 vlsvWriter.close();
416 return false;
417 }
418
419 return success;
420}
421
422#ifdef ASTERIX_ZFP
423bool writeVspaceDataCompressionZFP(const uint popID,Writer& vlsvWriter,
424 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
425 const std::vector<CellID>& cells,std::size_t totalBlocks, MPI_Comm comm){
426
427 bool success=true;
428
429 //Write the compression method used in this file
430 const int cmp=P::vdf_compression_method;
431 if(!vlsvWriter.writeParameter("COMPRESSION",&cmp)){
432 logFile<<"ERROR: Failed to write COMPRESSION parameter in vlsv file"<<std::endl<<write;
433 return false;
434 }
435
436 const string popName = getObjectWrapper().particleSpecies[popID].name;
437 const string spatMeshName = "SpatialGrid";
438 map<string,string> attribs;
439 vector<vmesh::GlobalID> velocityBlockIds;
440 try {
441 velocityBlockIds.reserve( totalBlocks );
442 // gather data for writing
443 for (size_t cell=0; cell<cells.size(); ++cell) {
444 SpatialCell* SC = mpiGrid[cells[cell]];
445 for (vmesh::LocalID block_i=0; block_i<SC->get_number_of_velocity_blocks(popID); ++block_i) {
447 velocityBlockIds.push_back( block );
448 }
449 }
450 } catch (...) {
451 cerr << "FAILED TO WRITE VELOCITY BLOCK IDS AT: " << __FILE__ << " " << __LINE__ << endl;
452 success=false;
453 }
454
455 if (globalSuccess(success,"(MAIN) writeGrid: ERROR: Failed to fill temporary array velocityBlockIds",MPI_COMM_WORLD) == false) {
456 vlsvWriter.close();
457 return false;
458 }
459
460 attribs.clear();
461 attribs["mesh"] = spatMeshName;
462 attribs["name"] = popName;
463 if (vlsvWriter.writeArray("BLOCKIDS", attribs, totalBlocks, 1, velocityBlockIds.data()) == false) success = false;
464 if (success == false) logFile << "(MAIN) writeGrid: ERROR failed to write BLOCKIDS to file!" << endl << writeVerbose;
465 {
466 vector<vmesh::GlobalID>().swap(velocityBlockIds);
467 }
468
469 std::size_t totalElements=0;
470 for (const auto& cid:cells){
471 totalElements+=mpiGrid[cid]->get_population(popID).compressed_state_buffer.size();
472 }
473
474 attribs.clear();
475 attribs["mesh"] = spatMeshName;
476 attribs["name"] = popName;
477 attribs["compression"] = "ZFP";
478 const string datatype_avgs = "uint"; //TODO why dont we have pure bytes in vlsv??
479 const uint64_t arraySize_avgs = totalElements;
480 const uint64_t vectorSize_avgs = 1; // There are 64 elements in every velocity block
481
482 // Get the data size needed for writing in data
483 uint64_t dataSize_avgs = 1;
484
485 // Start multi write
486 vlsvWriter.startMultiwrite(datatype_avgs,arraySize_avgs,vectorSize_avgs,dataSize_avgs);
487
488 // Loop over cells
489 for (size_t cell = 0; cell<cells.size(); ++cell) {
490 // Get the spatial cell
491 SpatialCell* SC = mpiGrid[cells[cell]];
492
493 // Get the number of blocks in this cell
494 const uint64_t arrayElements = SC->get_population(popID).compressed_state_buffer.size();
495 char* arrayToWrite = reinterpret_cast<char*>(SC->get_population(popID).compressed_state_buffer.data());
496
497 // Add a subarray to write
498 vlsvWriter.addMultiwriteUnit(arrayToWrite, arrayElements); // Note: We told beforehands that the vectorsize = WID3 = 64
499 }
500 if (cells.size() == 0) {
501 vlsvWriter.addMultiwriteUnit(NULL, 0); //Dummy write to avoid hang in end multiwrite
502 }
503 // Write the subarrays
504 vlsvWriter.endMultiwrite("BLOCKVARIABLE", attribs);
505
506 if (globalSuccess(success,"(MAIN) writeGrid: ERROR: Failed to fill temporary velocityBlockData array",MPI_COMM_WORLD) == false) {
507 vlsvWriter.close();
508 return false;
509 }
510
511 return success;
512}
513#endif //ASTERIX_ZFP
514
515
516#ifdef ASTERIX_OCTREE
517bool writeVspaceDataCompressionOCTREE(const uint popID,Writer& vlsvWriter,
518 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
519 const std::vector<CellID>& cells,std::size_t totalBlocks, MPI_Comm comm){
520
521 //Write the compression method used in this file
522 const int cmp=P::vdf_compression_method;
523 if (!vlsvWriter.writeParameter("COMPRESSION",&cmp)){
524 logFile<<"ERROR: Failed to write COMPRESSION parameter in vlsv file"<<std::endl<<write;
525 return false;
526 }
527 std::size_t totalElements=0;
528 for (const auto& cid:cells){
529 totalElements+=mpiGrid[cid]->get_population(popID).compressed_state_buffer.size();
530 }
531 bool success=true;
532 map<string,string> attribs;
533 const string popName = getObjectWrapper().particleSpecies[popID].name;
534 const string spatMeshName = "SpatialGrid";
535 attribs["mesh"] = spatMeshName;
536 attribs["name"] = popName;
537 attribs["compression"] = "OCTREE";
538 const string datatype_avgs = "uint"; //TODO why dont we have pure bytes in vlsv??
539 const uint64_t arraySize_avgs = totalElements;
540 const uint64_t vectorSize_avgs = 1; // There are 64 elements in every velocity block
541
542 // Get the data size needed for writing in data
543 uint64_t dataSize_avgs =1;
544
545 // Start multi write
546 vlsvWriter.startMultiwrite<char>(arraySize_avgs,vectorSize_avgs);
547
548 // Loop over cells
549 for (size_t cell = 0; cell<cells.size(); ++cell) {
550 // Get the spatial cell
551 SpatialCell* SC = mpiGrid[cells[cell]];
552
553 // Get the number of blocks in this cell
554 const uint64_t arrayElements = SC->get_population(popID).compressed_state_buffer.size();
555 char* arrayToWrite = reinterpret_cast<char*>(SC->get_population(popID).compressed_state_buffer.data());
556
557 // Add a subarray to write
558 vlsvWriter.addMultiwriteUnit<char>(arrayToWrite, arrayElements); // Note: We told beforehands that the vectorsize = WID3 = 64
559 }
560 if (cells.size() == 0) {
561 vlsvWriter.addMultiwriteUnit(NULL, 0); //Dummy write to avoid hang in end multiwrite
562 }
563 // Write the subarrays
564 vlsvWriter.endMultiwrite("BLOCKVARIABLE", attribs);
565
566 if (globalSuccess(success,"(MAIN) writeGrid: ERROR: Failed to fill temporary velocityBlockData array",MPI_COMM_WORLD) == false) {
567 vlsvWriter.close();
568 return false;
569 }
570
571 return success;
572}
573#endif //ASTERIX_OCTREE
574
575#ifdef ASTERIX_MLP
576bool writeVspaceDataCompressionMLP(const uint popID,Writer& vlsvWriter,
577 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
578 const std::vector<CellID>& cells,std::vector<std::vector<char>>&mlp_bytes,std::size_t totalBlocks, MPI_Comm comm){
579
580 //Write the compression method used in this file
581 const string popName = getObjectWrapper().particleSpecies[popID].name;
582 const string spatMeshName = "SpatialGrid";
583 const int cmp=P::vdf_compression_method;
584 if (!vlsvWriter.writeParameter("COMPRESSION",&cmp)){
585 logFile<<"ERROR: Failed to write COMPRESSION parameter in vlsv file"<<std::endl<<write;
586 return false;
587 }
588 const int fourier_order=P::mlp_fourier_order;
589 if (!vlsvWriter.writeParameter("FOURIER_ORDER",&fourier_order)){
590 logFile<<"ERROR: Failed to write FOURIER_ORDER parameter in vlsv file"<<std::endl<<write;
591 return false;
592 }
593 map<string,string> attribs;
594 attribs.clear();
595 attribs["mesh"] = spatMeshName;
596 attribs["name"] = popName;
597 auto array_size= P::mlp_arch.size();
598 if (!vlsvWriter.writeArrayMaster("MLP_ARCH",attribs,"int",array_size,1,sizeof(size_t),(const char*)P::mlp_arch.data())){
599 logFile<<"ERROR: Failed to write MLP_ARCH in vlsv file"<<std::endl<<write;
600 return false;
601 }
602
603
604 std::size_t totalElements=0;
605 for (const auto& b: mlp_bytes){
606 totalElements+=b.size();
607 }
608 bool success=true;
609 attribs.clear();
610 attribs["mesh"] = spatMeshName;
611 attribs["name"] = popName;
612 attribs["compression"] = "MLP";
613 const string datatype_avgs = "uint"; //TODO why dont we have pure bytes in vlsv??
614 const uint64_t arraySize_avgs = totalElements;
615 const uint64_t vectorSize_avgs = 1; // There are 64 elements in every velocity block
616 vlsvWriter.startMultiwrite(datatype_avgs,arraySize_avgs,vectorSize_avgs,1);
617 for (const auto& b: mlp_bytes){
618 const auto arrayElements = b.size();
619 if (arrayElements>0){
620 vlsvWriter.addMultiwriteUnit(b.data(), arrayElements);
621 }else{
622 vlsvWriter.addMultiwriteUnit(nullptr, 0);
623 }
624 }
625 vlsvWriter.endMultiwrite("BLOCKVARIABLE", attribs);
626 if (globalSuccess(success,"(MAIN) writeGrid: ERROR: Failed to fill temporary velocityBlockData array",MPI_COMM_WORLD) == false) {
627 vlsvWriter.close();
628 return false;
629 }
630 return success;
631}
632#endif //ASTERIX_MLP
633
634bool writeVelocityDistributionDataAsterix(const uint popID,Writer& vlsvWriter,
635 dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid,
636 const std::vector<CellID>& cells,std::vector<std::vector<char>>&bytes,MPI_Comm comm) {
637 // Write velocity blocks and related data.
638 // In restart we just write velocity grids for all cells.
639 // First write global Ids of those cells which write velocity blocks (here: all cells):
640 map<string,string> attribs;
641 const string popName = getObjectWrapper().particleSpecies[popID].name;
642 const string spatMeshName = "SpatialGrid";
643 attribs["name"] = popName;
644 bool success=true;
645
646 // Compute totalBlocks
647 uint64_t totalBlocks = 0;
648 vector<vmesh::LocalID> blocksPerCell;
649 vector<std::size_t> bytesPerCell;
650 vector<std::size_t> mlpBytesPerRank;
651 for (size_t cell=0; cell<cells.size(); ++cell){
652 totalBlocks+=mpiGrid[cells[cell]]->get_number_of_velocity_blocks(popID);
653 blocksPerCell.push_back(mpiGrid[cells[cell]]->get_number_of_velocity_blocks(popID));
654 bytesPerCell.push_back(mpiGrid[cells[cell]]->get_population(popID).compressed_state_buffer.size());
655 }
656
657 if (bytes.size()>0){
658 // const std::size_t bpr = std::accumulate(bytes.begin(), bytes.end(), 0, [](std::size_t bpr, const std::vector<char>& vec) {
659 // return bpr + vec.size();
660 // });
661 std::size_t bpr=0;
662 for (const auto& b:bytes){
663 bpr+=b.size();
664 }
665 if (!vlsvWriter.writeArray<std::size_t>("MLP_BYTES_PER_RANK",attribs,1,1,&bpr)){
666 logFile<<"ERROR: Failed to write mlp bytes per rank to restart file"<<endl<<write;
667 return false;
668 }
669
670 const std::size_t mlp_clusters_per_rank=bytes.size();
671 if (!vlsvWriter.writeArray<std::size_t>("MLP_CLUSTERS_PER_RANK",attribs,1,1,&mlp_clusters_per_rank)){
672 logFile<<"ERROR: Failed to write mlp cluster per rank to restart file"<<endl<<write;
673 return false;
674 }
675 }
676
677 // The name of the mesh is "SpatialGrid"
678 attribs["mesh"] = spatMeshName;
679
680 const unsigned int vectorSize = 1;
681 // Write the array:
682 if (vlsvWriter.writeArray("CELLSWITHBLOCKS",attribs,cells.size(),vectorSize,cells.data()) == false) success = false;
683 if (success == false) logFile << "(MAIN) writeGrid: ERROR failed to write CELLSWITHBLOCKS to file!" << endl << writeVerbose;
684 // Write blocks per cell, this has to be in the same order as cellswitblocks so that extracting works
685 if(vlsvWriter.writeArray("BLOCKSPERCELL",attribs,blocksPerCell.size(),vectorSize,blocksPerCell.data()) == false) success = false;
686 if(vlsvWriter.writeArray("BYTESPERCELL",attribs,bytesPerCell.size(),1,bytesPerCell.data()) == false) success = false;
687 if (success == false) logFile << "(MAIN) writeGrid: ERROR failed to write CELLSWITHBLOCKS to file!" << endl << writeVerbose;
688
689 // Write (partial) velocity mesh data
690 // The mesh bounding box gives the outer extent of the available velocity space
691 // in blocks and cells. Note that this is not the physical extent of that
692 // space, but a purely numerical bounding box.
693 uint64_t bbox[6];
694 const size_t meshID = getObjectWrapper().particleSpecies[popID].velocityMesh;
695 bbox[0] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).gridLength[0];
696 bbox[1] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).gridLength[1];
697 bbox[2] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).gridLength[2];
698 bbox[3] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).blockLength[0];
699 bbox[4] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).blockLength[1];
700 bbox[5] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).blockLength[2];
701
702 attribs.clear();
703 attribs["mesh"] = getObjectWrapper().particleSpecies[popID].name;
704 attribs["type"] = vlsv::mesh::STRING_UCD_AMR;
705
706 // stringstream is necessary here to correctly convert refLevelMaxAllowed (hardcoded to zero now) into a string
707 stringstream ss;
708 //ss << static_cast<unsigned int>(vmesh::getMeshWrapper()->velocityMeshes->at(meshID).refLevelMaxAllowed);
709 ss << static_cast<unsigned int>(0);
710 attribs["max_velocity_ref_level"] = ss.str();
711 if (mpiGrid.get_rank() == MASTER_RANK) {
712 if (vlsvWriter.writeArray("MESH_BBOX",attribs,6,1,bbox) == false) success = false;
713
714 for (int crd=0; crd<3; ++crd) {
715 const size_t N_nodes = bbox[crd]*bbox[crd+3]+1;
716 Real* crds = new Real[N_nodes];
717 const Real dV = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).cellSize[crd];
718
719 for (size_t i=0; i<N_nodes; ++i) {
720 crds[i] = vmesh::getMeshWrapper()->velocityMeshes->at(meshID).meshMinLimits[crd] + i*dV;
721 }
722
723 if (crd == 0) {
724 if (vlsvWriter.writeArray("MESH_NODE_CRDS_X",attribs,N_nodes,1,crds) == false) success = false;
725 }
726 if (crd == 1) {
727 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Y",attribs,N_nodes,1,crds) == false) success = false;
728 }
729 if (crd == 2) {
730 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Z",attribs,N_nodes,1,crds) == false) success = false;
731 }
732 delete [] crds; crds = NULL;
733 }
734 } else {
735 if (vlsvWriter.writeArray("MESH_BBOX",attribs,0,1,bbox) == false) success = false;
736 Real* crds = NULL;
737 if (vlsvWriter.writeArray("MESH_NODE_CRDS_X",attribs,0,1,crds) == false) success = false;
738 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Y",attribs,0,1,crds) == false) success = false;
739 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Z",attribs,0,1,crds) == false) success = false;
740 }
741
742 const std::size_t vdf_byte_size=sizeof(Realf);
743 if (!vlsvWriter.writeParameter<size_t>("VDF_BYTE_SIZE",&vdf_byte_size)){
744 logFile<<"ERROR: Failed to write compression type parameter in vlsv!"<<endl<<write;
745 return false;
746 }
747
750 success=writeVspaceDataCompressionNone(popID,vlsvWriter,mpiGrid,cells,totalBlocks,comm);
751 break;
752#ifdef ASTERIX_MLP
754 success=writeVspaceDataCompressionMLP(popID,vlsvWriter,mpiGrid,cells,bytes,totalBlocks,comm);
755 break;
757 success=writeVspaceDataCompressionMLP(popID,vlsvWriter,mpiGrid,cells,bytes,totalBlocks,comm);
758 break;
759#endif
760#ifdef ASTERIX_ZFP
762 success=writeVspaceDataCompressionZFP(popID,vlsvWriter,mpiGrid,cells,totalBlocks,comm);
763 break;
764#endif
765#ifdef ASTERIX_OCTREE
767 success=writeVspaceDataCompressionOCTREE(popID,vlsvWriter,mpiGrid,cells,totalBlocks,comm);
768 break;
769#endif
770 default:
771 std::cout<<"ABORT DEFAULT"<<std::endl;
772 break;
773 }
774
775 if (success ==false) {
776 logFile << "(MAIN) writeGrid: ERROR occurred when writing BLOCKVARIABLE f" << endl << writeVerbose;
777 }
778 return success;
779}
780
790bool writeDataReducer(const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
791 const std::vector<CellID>& cells, const FieldSolverData& fieldSolverData, const bool writeAsFloat,
792 const bool writeFsGrid, DataReducer& dataReducer, cint dataReducerIndex, Writer& vlsvWriter) {
793 map<string, string> attribs;
794 string variableName, dataType, unitString, unitStringLaTeX, variableStringLaTeX, unitConversionFactor;
795 bool success = true;
796
797 if (!writeFsGrid) { // if we shouldn't write fsgrid DROs
798 variableName = dataReducer.getName(dataReducerIndex);
799 if (variableName.find("fg_", 0) == 0) { // and if the DRO's name includes the string "fg_"
800 return success; // we're good to go
801 }
802 }
803
804 const string meshName = "SpatialGrid";
805 variableName = dataReducer.getName(dataReducerIndex);
806 phiprof::Timer droTimer{"DRO_" + variableName};
807
808 // Get basic data on a variable:
809 uint dataSize, vectorSize;
810 attribs["mesh"] = meshName;
811 attribs["name"] = variableName;
812 if (dataReducer.getDataVectorInfo(dataReducerIndex, dataType, dataSize, vectorSize) == false) {
813 cerr << "ERROR when requesting info from DRO " << dataReducerIndex << endl;
814 return false;
815 }
816
817 // Request variable unit metadata: unit, latex-formatted unit, and conversion factor to SI
818 if (dataReducer.getMetadata(dataReducerIndex, unitString, unitStringLaTeX, variableStringLaTeX, unitConversionFactor) == false) {
819 cerr << "ERROR when requesting unit metadata from DRO " << dataReducerIndex << endl;
820 return false;
821 }
822 attribs["unit"] = unitString;
823 attribs["unitLaTeX"] = unitStringLaTeX;
824 attribs["unitConversion"] = unitConversionFactor;
825 attribs["variableLaTeX"] = variableStringLaTeX;
826
827 // If DRO has a vector size of 0 it means this DRO should not write out anything. This is used e.g. for DROs we want only for certain populations.
828 if (vectorSize == 0) {
829 return true;
830 }
831
832 const uint64_t varBufferArraySize = cells.size() * vectorSize * dataSize;
833
834 // Request DataReductionOperator to calculate the reduced data for all local cells:
835 char* varBuffer = NULL;
836 try {
837 varBuffer = new char[varBufferArraySize];
838 } catch (bad_alloc&) {
839 cerr << "ERROR, FAILED TO ALLOCATE MEMORY AT: " << __FILE__ << " " << __LINE__ << endl;
840 logFile << "(MAIN) writeGrid: ERROR FAILED TO ALLOCATE MEMORY AT: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
841 return false;
842 }
843
844 for (size_t cell = 0; cell < cells.size(); ++cell) {
845 // Reduce data ( return false if the operation fails )
846 if (dataReducer.reduceData(mpiGrid[cells[cell]], dataReducerIndex, varBuffer + cell * vectorSize * dataSize) == false) {
847 success = false;
848 // Note that this is not an error (anymore), since fsgrid reducers will return false here.
849 }
850 }
851
852 if (dataReducer.getName(dataReducerIndex).find("fg_", 0) == 0) {
853 // Write fsgrid data
854 phiprof::Timer writeFsTimer{"writeFsGrid"};
855 success = dataReducer.writeFsGridData(fieldSolverData, "fsgrid", dataReducerIndex, vlsvWriter, writeAsFloat);
856 writeFsTimer.stop();
857
858 } else if (dataReducer.getName(dataReducerIndex).find("ig_", 0) == 0) {
859 // Or maybe it will be writing ionosphere data?
860 phiprof::Timer writeIonosphereTimer{"writeIonosphere"};
861 success |= dataReducer.writeIonosphereGridData(SBC::ionosphereGrid, "ionosphere", dataReducerIndex, vlsvWriter);
862 writeIonosphereTimer.stop();
863 } else {
864 // If the data reducer didn't want to write fg or ig data, maybe it will be happy writing dccrg data
865 if ((writeAsFloat == true && dataType.compare("float") == 0) && dataSize == sizeof(double)) {
866 double* varBuffer_double = reinterpret_cast<double*>(varBuffer);
867 // Declare smaller varbuffer:
868 const uint64_t arraySize_smaller = cells.size();
869 const uint32_t vectorSize_smaller = vectorSize;
870 const uint32_t dataSize_smaller = sizeof(float);
871 const string dataType_smaller = dataType;
872 float* varBuffer_smaller = NULL;
873 try {
874 varBuffer_smaller = new float[arraySize_smaller * vectorSize_smaller];
875 } catch (bad_alloc&) {
876 cerr << "ERROR, FAILED TO ALLOCATE MEMORY AT: " << __FILE__ << " " << __LINE__ << endl;
877 logFile << "(MAIN) writeGrid: ERROR FAILED TO ALLOCATE MEMORY AT: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
878 delete[] varBuffer;
879 varBuffer = NULL;
880 return false;
881 }
882 // Input varBuffer_double into varBuffer_smaller:
883 for (uint64_t i = 0; i < arraySize_smaller * vectorSize_smaller; ++i) {
884 const double value = varBuffer_double[i];
885 varBuffer_smaller[i] = (float)(value);
886 }
887 // Cast the varBuffer to char:
888 char* varBuffer_smaller_char = reinterpret_cast<char*>(varBuffer_smaller);
889 // Write the array:
890 phiprof::Timer writeArrayTimer{"writeArray"};
891 if (vlsvWriter.writeArray("VARIABLE", attribs, dataType_smaller, arraySize_smaller, vectorSize_smaller, dataSize_smaller, varBuffer_smaller_char) == false) {
892 success = false;
893 logFile << "(MAIN) writeGrid: ERROR failed to write datareductionoperator data to file!" << endl << writeVerbose;
894 }
895 writeArrayTimer.stop();
896 delete[] varBuffer_smaller;
897 varBuffer_smaller = NULL;
898 } else {
899 // Write reduced data to file if DROP was successful:
900 phiprof::Timer writeArrayTimer{"writeArray"};
901 if (vlsvWriter.writeArray("VARIABLE", attribs, dataType, cells.size(), vectorSize, dataSize, varBuffer) == false) {
902 success = false;
903 logFile << "(MAIN) writeGrid: ERROR failed to write datareductionoperator data to file!" << endl << writeVerbose;
904 }
905 }
906 }
907
908 // Check if the DataReducer wants to write paramters to the output file
909 if (dataReducer.hasParameters(dataReducerIndex) == true) {
910 success = dataReducer.writeParameters(dataReducerIndex, vlsvWriter);
911 }
912
913 delete[] varBuffer;
914 varBuffer = NULL;
915 return success;
916}
917
927 Writer& vlsvWriter,
928 const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
929 const vector<uint64_t>& local_cells,
930 const uint& fileIndex,
931 MPI_Comm comm
932) {
933 // Writes parameters and cell ids into the VLSV file
934 int myRank;
935 MPI_Comm_rank(comm, &myRank);
936 // Write local cells into array as a variable:
937 // Note: This needs to be done separately from the array MESH
938 const short unsigned int vectorSize = 1;
939 const uint32_t arraySize = local_cells.size();
940 map<string, string> xmlAttributes;
941 xmlAttributes["name"] = "CellID";
942 xmlAttributes["mesh"] = "SpatialGrid";
943 if (vlsvWriter.writeArray("VARIABLE", xmlAttributes, arraySize, vectorSize, local_cells.data()) == false) {
944 return false;
945 }
946
947 // Write parameters:
948 if (vlsvWriter.writeParameter("time", &P::t) == false) { return false; }
949 if (vlsvWriter.writeParameter("dt", &P::dt) == false) { return false; }
950 if (vlsvWriter.writeParameter("timestep", &P::tstep) == false) { return false; }
951 if (vlsvWriter.writeParameter("fieldSolverSubcycles", &P::fieldSolverSubcycles) == false) { return false; }
952 if (vlsvWriter.writeParameter("fileIndex", &fileIndex) == false) { return false; }
953 if (vlsvWriter.writeParameter("xmin", &P::xmin) == false) { return false; }
954 if (vlsvWriter.writeParameter("xmax", &P::xmax) == false) { return false; }
955 if (vlsvWriter.writeParameter("ymin", &P::ymin) == false) { return false; }
956 if (vlsvWriter.writeParameter("ymax", &P::ymax) == false) { return false; }
957 if (vlsvWriter.writeParameter("zmin", &P::zmin) == false) { return false; }
958 if (vlsvWriter.writeParameter("zmax", &P::zmax) == false) { return false; }
959 if (vlsvWriter.writeParameter("xcells_ini", &P::xcells_ini) == false) { return false; }
960 if (vlsvWriter.writeParameter("ycells_ini", &P::ycells_ini) == false) { return false; }
961 if (vlsvWriter.writeParameter("zcells_ini", &P::zcells_ini) == false) { return false; }
962 // Although the stored velocity meshes already include block size information, the parameter WID
963 // is also stored for ease of reading in post-processing.
964 const int writewid = WID;
965 if (vlsvWriter.writeParameter("velocity_block_width", &writewid) == false) { return false; }
966 if (FieldTracing::fieldTracingParameters.doTraceFullBox) {
967 if (vlsvWriter.writeParameter("fieldTracingFluxRopeMaxDistance", &FieldTracing::fieldTracingParameters.fluxrope_max_curvature_radii_to_trace) == false) {
968 return false;
969 }
970 }
971
972 // Mark the new version:
973 float version = 3.00;
974 if (vlsvWriter.writeParameter("version", &version) == false) { return false; }
975 return true;
976}
977
986bool writeGhostZoneDomainAndLocalIdNumbers(const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
987 Writer& vlsvWriter,
988 const string& meshName,
989 const vector<uint64_t>& ghost_cells) {
990 // Declare vectors for storing data
991 vector<uint64_t> ghostDomainIds;
992 ghostDomainIds.reserve(ghost_cells.size());
993 vector<uint64_t> ghostLocalIds;
994 ghostLocalIds.reserve(ghost_cells.size());
995
996 // Iterate through all ghost zones:
997 vector<uint64_t>::const_iterator it;
998 for (it = ghost_cells.begin(); it != ghost_cells.end(); ++it) {
999 // Domain id is the MPI process rank owning the ghost zone
1000
1001 // get the local id of the zone in the process where THIS ghost zone is a local zone:
1002 // In order to do this we need MPI (Done in createZone)
1003 // Example:
1004 // Marking zones with a letter A, B, C, D etc and local ids are numbers above the zones
1005 // local id: 0 1 2 3 4 5
1006 // Process 1. has: local zones ( A, B, C ), ghost zones ( D E F )
1007
1008 // local id: 0 1 2
1009 // Process 2. has: local zones ( D, G ), ghost zones ( H )
1010 // Now if we're in process 1. and our ghost zone is D, its domainId would be 2. because process 2. has D as local zone
1011 // In process 2, the local id of D is 0, so that's the local id we want now
1012 // The local id is being saved in createZone function
1013
1014 // Append to the vectors Note: Check updateLocalIds function
1015 ghostDomainIds.push_back(mpiGrid.get_process(*it));
1016 ghostLocalIds.push_back(mpiGrid[(*it)]->ioLocalCellId);
1017 }
1018
1019 // We need the number of ghost zones for vlsvWriter:
1020 uint64_t numberOfGhosts = ghost_cells.size();
1021
1022 // Write:
1023 map<string, string> xmlAttributes; // Used for writing in info
1024 // Note: should be "SpatialGrid"
1025 xmlAttributes["mesh"] = meshName;
1026 const unsigned int vectorSize = 1;
1027 // Write the in the number of ghost domains: (Returns false if writing fails)
1028 if (vlsvWriter.writeArray("MESH_GHOST_DOMAINS", xmlAttributes, numberOfGhosts, vectorSize, ghostDomainIds.data()) == false) {
1029 cerr << "Error, failed to write MEST_GHOST_DOMAINS at: " << __FILE__ << " " << __LINE__ << endl;
1030 logFile << "(MAIN) writeGrid: ERROR failed to write MEST_GHOST_DOMAINS at: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
1031 return false;
1032 }
1033 // Write the in the number of ghost local ids: (Returns false if writing fails)
1034 if (vlsvWriter.writeArray("MESH_GHOST_LOCALIDS", xmlAttributes, numberOfGhosts, vectorSize, ghostLocalIds.data()) == false) {
1035 cerr << "Error, failed to write MEST_GHOST_LOCALIDS at: " << __FILE__ << " " << __LINE__ << endl;
1036 logFile << "(MAIN) writeGrid: ERROR failed to write MEST_GHOST_LOCALIDS at: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
1037 return false;
1038 }
1039 // Everything good
1040 return true;
1041}
1042
1050bool writeDomainSizes(Writer& vlsvWriter, const string& meshName, const unsigned int& numberOfLocalZones, const unsigned int& numberOfGhostZones) {
1051 // Declare domainSize. There are two types of domain sizes -- ghost and local
1052 const unsigned int numberOfDomainTypes = 2;
1053 uint32_t domainSize[numberOfDomainTypes];
1054 domainSize[0] = numberOfLocalZones + numberOfGhostZones;
1055 domainSize[1] = numberOfGhostZones;
1056
1057 // Write the array:
1058 map<string, string> xmlAttributes;
1059 // Put the meshName
1060 xmlAttributes["mesh"] = meshName;
1061 const unsigned int arraySize = 1;
1062 const unsigned int vectorSize = 2;
1063 // Write (writeArray does the writing) Note: Here the important part is "MESH_DOMAIN_SIZES" -- visit plugin needs this
1064 if (vlsvWriter.writeArray("MESH_DOMAIN_SIZES", xmlAttributes, arraySize, vectorSize, domainSize) == false) {
1065 cerr << "Error at: " << __FILE__ << " " << __LINE__ << ", FAILED TO WRITE MESH_DOMAIN_SIZES" << endl;
1066 logFile << "(MAIN) writeGrid: ERROR FAILED TO WRITE MESH_DOMAIN_SIZES AT: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
1067 return false;
1068 }
1069 return true;
1070}
1071
1079
1080bool writeDomainExtents(Writer& vlsvWriter, const string& meshName, const std::vector<CellID>& local_cells,
1081 const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid) {
1082 vector<CellID>::const_iterator it;
1083
1084 // Write the array:
1085 map<string, string> xmlAttributes;
1086 // Put the meshName
1087 xmlAttributes["mesh"] = meshName;
1088 Real ret[6] = {0., 0., 0., 0., 0., 0.};
1089
1090 // Loop through the domain cells and find a box that bounds all the cells
1091 for (it = local_cells.begin(); it != local_cells.end(); it++) {
1092 CellID cellId = *it;
1093
1094 const SpatialCell& cell = *mpiGrid[cellId];
1095 Real lowcorner[6] = {
1099 };
1100 if (it == local_cells.begin()) {
1101 for (uint8_t i = 0; i != 6; i++) {
1102 ret[i] = lowcorner[i];
1103 }
1104 continue;
1105 }
1106 for (uint8_t i = 0; i != 6; i++) {
1107 // min
1108 if ((lowcorner[i] < ret[i]) && (i % 2 == 0)) {
1109 ret[i] = lowcorner[i];
1110 // max
1111 } else if ((lowcorner[i] > ret[i]) && (i % 2 != 0)) {
1112 ret[i] = lowcorner[i];
1113 }
1114 }
1115 }
1116 const unsigned int arraySize = 1;
1117 const unsigned int vectorSize = 6;
1118
1119 // Write the mesh extents, ret corresponds to [xmin,xmax,ymin,ymax,zmin,zmax]
1120 if (vlsvWriter.writeArray("MESH_DOMAIN_EXTENTS", xmlAttributes, arraySize, vectorSize, ret) == false) {
1121 cerr << "Error at: " << __FILE__ << " " << __LINE__ << ", FAILED TO WRITE MESH_DOMAIN_EXTENTS" << endl;
1122 logFile << "(MAIN) writeGrid: ERROR FAILED TO WRITE MESH_DOMAIN_EXTENTS AT: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
1123 return false;
1124 }
1125
1126 return true;
1127}
1128
1141bool writeZoneGlobalIdNumbers(const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
1142 Writer& vlsvWriter,
1143 const string& meshName,
1144 const vector<uint64_t>& local_cells,
1145 const vector<uint64_t>& ghost_cells) {
1146 if (local_cells.empty()) {
1147 if (!ghost_cells.empty()) {
1148 // Something very wrong -- local zones should always have members when ghost zones has members
1149 cerr << "ERROR, LOCAL ZONES EMPTY BUT GHOST ZONES NOT AT " << __FILE__ << __LINE__ << endl;
1150 return false;
1151 }
1152 }
1153
1154 vector<uint64_t> globalIds;
1155 globalIds.reserve(local_cells.size() + ghost_cells.size());
1156
1157 // Iterate through local_cells and store the values into globalIDs
1158 // Note: globalID is defined as follows: global ID = z*yCells*xCells + y*xCells + x
1159 vector<uint64_t>::const_iterator it;
1160 for (it = local_cells.begin(); it != local_cells.end(); ++it) {
1161 if ((*it) == 0) {
1162 cerr << "ERROR, Invalid cell id at " << __FILE__ << " " << __LINE__ << endl;
1163 return false;
1164 }
1165 // Add the global id:
1166 // Note: Unlike cell ids, global ids start from 0
1167 globalIds.push_back((*it) - 1);
1168 }
1169 // Do the same for ghost zones: (Append to the end of the list of global ids)
1170 for (it = ghost_cells.begin(); it != ghost_cells.end(); ++it) {
1171 if ((*it) == 0) {
1172 cerr << "ERROR, Invalid cell id at " << __FILE__ << " " << __LINE__ << endl;
1173 return false;
1174 }
1175 // Add the global id:
1176 globalIds.push_back((*it) - 1);
1177 }
1178
1179 // Get the total number of zones:
1180 const uint64_t numberOfZones = globalIds.size();
1181
1182 // Write the array:
1183 map<string, string> xmlAttributes;
1184 // The name of the mesh (user input -- should be "SpatialGrid")
1185 xmlAttributes["name"] = meshName;
1186 // A mandatory 'type' -- just something visit hopefully understands, because I dont (some of us do!) :)
1187 xmlAttributes["type"] = vlsv::mesh::STRING_UCD_AMR;
1188 char refLevelString[] = "0";
1189 // Ultra-dirty number-to-string
1190 refLevelString[0] += P::amrMaxSpatialRefLevel;
1191 xmlAttributes["max_refinement_level"] = refLevelString;
1192
1193 // Set periodicity:
1194 if (mpiGrid.topology.is_periodic(0)) { xmlAttributes["xperiodic"] = "yes"; } else { xmlAttributes["xperiodic"] = "no"; }
1195 if (mpiGrid.topology.is_periodic(1)) { xmlAttributes["yperiodic"] = "yes"; } else { xmlAttributes["yperiodic"] = "no"; }
1196 if (mpiGrid.topology.is_periodic(2)) { xmlAttributes["zperiodic"] = "yes"; } else { xmlAttributes["zperiodic"] = "no"; }
1197 // Write:
1198 if (numberOfZones == 0) {
1199 const uint64_t dummy_data = 0;
1200 const unsigned int dummy_array = 0;
1201 if (vlsvWriter.writeArray("MESH", xmlAttributes, dummy_array, 1, &dummy_data) == false) {
1202 cerr << "Unsuccessful writing of MESH at: " << __FILE__ << " " << __LINE__ << endl;
1203 return false;
1204 }
1205 } else {
1206 if (vlsvWriter.writeArray("MESH", xmlAttributes, numberOfZones, 1, globalIds.data()) == false) {
1207 cerr << "Unsuccessful writing of MESH at: " << __FILE__ << " " << __LINE__ << endl;
1208 return false;
1209 }
1210 }
1211 // Successfully wrote the array
1212 return true;
1213}
1214
1225bool writeBoundingBoxNodeCoordinates(Writer& vlsvWriter,
1226 const string& meshName,
1227 const int masterRank,
1228 MPI_Comm comm) {
1229
1230 // Create variables xCells, yCells, zCells which tell the number of zones in the given direction
1231 // Note: This is for the sake of clarity.
1232 const uint64_t& xCells = P::xcells_ini;
1233 const uint64_t& yCells = P::ycells_ini;
1234 const uint64_t& zCells = P::zcells_ini;
1235
1236 // Create variables xmin, ymin, zmin for calculations
1237 const Real& xmin = (Real)P::xmin;
1238 const Real& ymin = (Real)P::ymin;
1239 const Real& zmin = (Real)P::zmin;
1240
1241 // Create variables for cell lengths in x, y, z directions for calculations
1242 const Real& xCellLength = (Real)P::dx_ini;
1243 const Real& yCellLength = (Real)P::dy_ini;
1244 const Real& zCellLength = (Real)P::dz_ini;
1245
1246 // Create node coordinates:
1247 // These are the coordinates for any given node in x y or z direction
1248 // Note: Nodes are basically the box coordinates
1249 vector<Real> xNodeCoordinates;
1250 xNodeCoordinates.reserve(xCells + 1);
1251 vector<Real> yNodeCoordinates;
1252 yNodeCoordinates.reserve(yCells + 1);
1253 vector<Real> zNodeCoordinates;
1254 zNodeCoordinates.reserve(zCells + 1);
1255
1256 // Input the coordinates for the nodes:
1257 for (unsigned int i = 0; i < xCells + 1; ++i) {
1258 // The x coordinate of the first node should be xmin, the second xmin + xCellLength and so on
1259 xNodeCoordinates.push_back(xmin + xCellLength * i);
1260 }
1261 for (unsigned int i = 0; i < yCells + 1; ++i) {
1262 yNodeCoordinates.push_back(ymin + yCellLength * i);
1263 }
1264 for (unsigned int i = 0; i < zCells + 1; ++i) {
1265 zNodeCoordinates.push_back(zmin + zCellLength * i);
1266 }
1267
1268 // Write the arrays:
1269 map<string, string> xmlAttributes;
1270 // Note: meshName should be "SpatialGrid", probably
1271 xmlAttributes["mesh"] = meshName;
1272 //"success"'s value will be returned. By default it's true but if some of the vlsvWriter operations fail it will be false:
1273 bool success = true;
1274 // Depending on whether our rank is master rank or not the operation is slightly different, so let's get out rank from the MPI_Comm comm:
1275 int myRank;
1276 // Input myRank:
1277 MPI_Comm_rank(comm, &myRank);
1278 // Check the rank and write the arrays:
1279 const unsigned int vectorSize = 1;
1280 uint64_t arraySize;
1281 if (myRank == masterRank) {
1282 // Save with the correct name "MESH_NODE_CRDS_X" -- writeArray returns false if something goes wrong
1283 arraySize = xCells + 1;
1284 if (vlsvWriter.writeArray("MESH_NODE_CRDS_X", xmlAttributes, arraySize, vectorSize, xNodeCoordinates.data()) == false) success = false;
1285 arraySize = yCells + 1;
1286 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Y", xmlAttributes, arraySize, vectorSize, yNodeCoordinates.data()) == false) success = false;
1287 arraySize = zCells + 1;
1288 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Z", xmlAttributes, arraySize, vectorSize, zNodeCoordinates.data()) == false) success = false;
1289 } else {
1290 // Not a master process, so write empty:
1291 arraySize = 0;
1292 if (vlsvWriter.writeArray("MESH_NODE_CRDS_X", xmlAttributes, arraySize, vectorSize, xNodeCoordinates.data()) == false) success = false;
1293 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Y", xmlAttributes, arraySize, vectorSize, yNodeCoordinates.data()) == false) success = false;
1294 if (vlsvWriter.writeArray("MESH_NODE_CRDS_Z", xmlAttributes, arraySize, vectorSize, zNodeCoordinates.data()) == false) success = false;
1295 }
1296 // Free the memory
1297 xNodeCoordinates.clear();
1298 yNodeCoordinates.clear();
1299 zNodeCoordinates.clear();
1300 return success;
1301}
1302
1311bool writeMeshBoundingBox(Writer& vlsvWriter, const string& meshName, const int masterRank, MPI_Comm comm) {
1312 // Get my rank from the MPI_Comm
1313 int myRank;
1314 MPI_Comm_rank(comm, &myRank);
1315
1316 // Declare boundaryBox (writeArray expects it to tell the size of
1317 const unsigned int box_size = 6;
1318 const unsigned int notBlockBasedMesh = 1; // 1 because we are not interested in block based mesh
1319 // Note: If we were, the 3 last values in boundaryBox(below) would tell the
1320 // number of cells in blocks in x, y, z direction
1321 // Set the boundary box
1322 const uint64_t& numberOfXCells = P::xcells_ini;
1323 const uint64_t& numberOfYCells = P::ycells_ini;
1324 const uint64_t& numberOfZCells = P::zcells_ini;
1325 uint64_t boundaryBox[box_size] = {numberOfXCells, numberOfYCells, numberOfZCells,
1326 notBlockBasedMesh, notBlockBasedMesh, notBlockBasedMesh};
1327
1328 // Write:
1329 // Declare attributes
1330 map<string, string> xmlAttributes;
1331 // We received mesh name as a parameter: MOST LIKELY THIS IS SpatialGrid!
1332 xmlAttributes["mesh"] = meshName;
1333
1334 // Write an array (NOTE: success will be returned and writeArray will return true or false depending on whether or not the write is successful)
1335 bool success;
1336 if (myRank == masterRank) {
1337 // The visit plugin expects MESH_BBOX as a keyword
1338 // NOTE: writeArray writes boundaryBox
1339 const unsigned int arraySize = 6;
1340 const unsigned int vectorSize = 1;
1341 success = vlsvWriter.writeArray("MESH_BBOX", xmlAttributes, arraySize, vectorSize, boundaryBox);
1342 } else {
1343 const unsigned int arraySize = 0;
1344 const unsigned int vectorSize = 1;
1345 success = vlsvWriter.writeArray("MESH_BBOX", xmlAttributes, arraySize, vectorSize, boundaryBox);
1346 }
1347 return success;
1348}
1349
1350/*Function to append version information to current output file
1351 \param vlsvWriter Some vlsv writer with a file open
1352 \param comm MPI comm
1353 \return Returns true if operation was successful
1354 */
1355bool writeVersionInfo(const std::string& version, vlsv::Writer& vlsvWriter, MPI_Comm comm) {
1356
1357 int myRank;
1358 MPI_Comm_rank(comm, &myRank);
1359
1360 std::map<std::string, std::string> xmlAttributes;
1361 xmlAttributes["name"] = "version_information";
1362
1363 bool retval;
1364 if (myRank == 0) {
1365 retval = vlsvWriter.writeArray("VERSION", xmlAttributes, version.size(), 1, &version[0]);
1366 } else {
1367 retval = vlsvWriter.writeArray("VERSION", xmlAttributes, 0, 1, &version[0]);
1368 }
1369
1370 return retval;
1371}
1372
1373/*Function to append config information to current output file
1374 \param vlsvWriter Some vlsv writer with a file open
1375 \param comm MPI comm
1376 \return Returns true if operation was successful
1377 */
1378bool writeConfigInfo(const std::string& config, vlsv::Writer& vlsvWriter, MPI_Comm comm) {
1379
1380 int myRank;
1381 MPI_Comm_rank(comm, &myRank);
1382
1383 std::map<std::string, std::string> xmlAttributes;
1384 xmlAttributes["name"] = "config_file";
1385
1386 bool retval;
1387 if (myRank == 0) {
1388 retval = vlsvWriter.writeArray("CONFIG", xmlAttributes, config.size(), 1, &config[0]);
1389 } else {
1390 retval = vlsvWriter.writeArray("CONFIG", xmlAttributes, 0, 1, &config[0]);
1391 }
1392
1393 return retval;
1394}
1395
1400bool writeFsGridMetadata(FieldSolverGrid& fsgrid, fsgrids::consttechnicalspan technical, vlsv::Writer& vlsvWriter, bool writeIDs = false) {
1401
1402 std::map<std::string, std::string> xmlAttributes;
1403 const std::string meshName = "fsgrid";
1404 xmlAttributes["mesh"] = meshName;
1405
1406 // The visit plugin expects MESH_BBOX as a keyword. We only write one
1407 // from the first rank.
1408 const std::array<fsgrid::FsSize_t, 3>& globalSize = fsgrid.getGlobalSize();
1409 std::array<fsgrid::FsSize_t, 6> boundaryBox({globalSize[0], globalSize[1], globalSize[2], 1, 1, 1});
1410
1411 if (fsgrid.getRank() == 0) {
1412 const unsigned int arraySize = 6;
1413 const unsigned int vectorSize = 1;
1414 vlsvWriter.writeArray("MESH_BBOX", xmlAttributes, arraySize, vectorSize, &boundaryBox[0]);
1415 } else {
1416 const unsigned int arraySize = 0;
1417 const unsigned int vectorSize = 1;
1418 vlsvWriter.writeArray("MESH_BBOX", xmlAttributes, arraySize, vectorSize, &boundaryBox);
1419 }
1420
1421 // Write three 1-dimensional arrays of node coordinates (x,y,z) for
1422 // visit to create a cartesian grid out of.
1423 std::vector<double> xNodeCoordinates(globalSize[0] + 1);
1424 for (int64_t i = 0; i < globalSize[0] + 1; i++) {
1425 xNodeCoordinates[i] = fsgrid.getPhysicalCoords(i, 0, 0)[0];
1426 }
1427 std::vector<double> yNodeCoordinates(globalSize[1] + 1);
1428 for (int64_t i = 0; i < globalSize[1] + 1; i++) {
1429 yNodeCoordinates[i] = fsgrid.getPhysicalCoords(0, i, 0)[1];
1430 }
1431 std::vector<double> zNodeCoordinates(globalSize[2] + 1);
1432 for (int64_t i = 0; i < globalSize[2] + 1; i++) {
1433 zNodeCoordinates[i] = fsgrid.getPhysicalCoords(0, 0, i)[2];
1434 }
1435 if (fsgrid.getRank() == 0) {
1436 // Write this data only on rank 0
1437 vlsvWriter.writeArray("MESH_NODE_CRDS_X", xmlAttributes, globalSize[0] + 1, 1, xNodeCoordinates.data());
1438 vlsvWriter.writeArray("MESH_NODE_CRDS_Y", xmlAttributes, globalSize[1] + 1, 1, yNodeCoordinates.data());
1439 vlsvWriter.writeArray("MESH_NODE_CRDS_Z", xmlAttributes, globalSize[2] + 1, 1, zNodeCoordinates.data());
1440
1441 } else {
1442
1443 // The others just write an empty dummy
1444 vlsvWriter.writeArray("MESH_NODE_CRDS_X", xmlAttributes, 0, 1, xNodeCoordinates.data());
1445 vlsvWriter.writeArray("MESH_NODE_CRDS_Y", xmlAttributes, 0, 1, yNodeCoordinates.data());
1446 vlsvWriter.writeArray("MESH_NODE_CRDS_Z", xmlAttributes, 0, 1, zNodeCoordinates.data());
1447 }
1448
1449 // Dummy ghost info
1450 int dummyghost = 0;
1451 vlsvWriter.writeArray("MESH_GHOST_DOMAINS", xmlAttributes, 0, 1, &dummyghost);
1452 vlsvWriter.writeArray("MESH_GHOST_LOCALIDS", xmlAttributes, 0, 1, &dummyghost);
1453
1454 // writeDomainSizes
1455 const std::array<fsgrid::FsIndex_t, 3>& localSize = fsgrid.getLocalSize();
1456 std::array<uint64_t, 2> meshDomainSize({(uint64_t)localSize[0] * (uint64_t)localSize[1] * (uint64_t)localSize[2], 0});
1457 vlsvWriter.writeArray("MESH_DOMAIN_SIZES", xmlAttributes, 1, 2, &meshDomainSize[0]);
1458
1459 // how many MPI ranks we wrote from
1460 int size = fsgrid.getNumFsRanks();
1461 vlsvWriter.writeParameter("numWritingRanks", &size);
1462
1463 // Save the FSgrid decomposition
1464 std::array<fsgrid::Task_t, 3> decom = fsgrid.getDecomposition();
1465 if (fsgrid.getRank() == 0) {
1466 vlsvWriter.writeArray("MESH_DECOMPOSITION", xmlAttributes, 3u, 1u, &decom[0]);
1467 } else {
1468 vlsvWriter.writeArray("MESH_DECOMPOSITION", xmlAttributes, 0u, 3u, &decom[0]);
1469 }
1470
1471 // Finally, write mesh object itself.
1472 xmlAttributes.clear();
1473 xmlAttributes["name"] = meshName;
1474 xmlAttributes["type"] = vlsv::mesh::STRING_UCD_MULTI;
1475 xmlAttributes["xperiodic"] = fsgrid.getPeriodic()[0] ? "yes" : "no";
1476 xmlAttributes["yperiodic"] = fsgrid.getPeriodic()[1] ? "yes" : "no";
1477 xmlAttributes["zperiodic"] = fsgrid.getPeriodic()[2] ? "yes" : "no";
1478
1479 if (writeIDs) {
1480 // Write cell "globalID" numbers, which are just the global array indices.
1481 std::vector<fsgrid::FsSize_t> globalIds(static_cast<fsgrid::FsSize_t>(localSize[0] * localSize[1] * localSize[2]));
1482 // Should work in parallel too
1483 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; }, phiprof::initializeTimer("Map Refinement Level to FsGrid"), technical,
1484 [=, &globalIds](const fsgrid::Coordinates& coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
1485 cint index = stencil.k * coordinates.localSize[1] * coordinates.localSize[0] + stencil.j * coordinates.localSize[0] + stencil.i;
1486 const std::array<fsgrid::FsSize_t, 3> globalIndex = coordinates.localToGlobal(stencil.i, stencil.j, stencil.k);
1487 globalIds[index] = globalIndex[2] * globalSize[0] * globalSize[1] + globalIndex[1] * globalSize[0] + globalIndex[0];
1488 });
1489 vlsvWriter.writeArray("MESH", xmlAttributes, globalIds.size(), 1, globalIds.data());
1490 }
1491 return true;
1492}
1493
1496bool writeIonosphereGridMetadata(vlsv::Writer& vlsvWriter) {
1497
1498 // Don't even bother writing an ionosphere mesh, if the ionosphere datastructure has 0 mesh nodes
1499 if (SBC::ionosphereGrid.nodes.size() == 0) {
1500 return true;
1501 }
1502
1503 std::map<std::string, std::string> xmlAttributes;
1504 const std::string meshName = "ionosphere";
1505 xmlAttributes["mesh"] = meshName;
1506 int rank;
1507 if (SBC::ionosphereGrid.isCouplingInwards || SBC::ionosphereGrid.isCouplingOutwards) {
1508 MPI_Comm_rank(SBC::ionosphereGrid.communicator, &rank);
1509 } else {
1510 rank = -1;
1511 }
1512
1513 // the MESH_BBOX for unstructured meshes needs to be present, but isn't really being used.
1514 std::array<int64_t, 6> boundaryBox({1, 1, 1, 1, 1, 1});
1515
1516 if (rank == 0) {
1517 const unsigned int arraySize = 6;
1518 const unsigned int vectorSize = 1;
1519 vlsvWriter.writeArray("MESH_BBOX", xmlAttributes, arraySize, vectorSize, &boundaryBox[0]);
1520 } else {
1521 const unsigned int arraySize = 0;
1522 const unsigned int vectorSize = 1;
1523 vlsvWriter.writeArray("MESH_BBOX", xmlAttributes, arraySize, vectorSize, &boundaryBox[0]);
1524 }
1525
1526 // write DomainSizes
1527 std::array<uint64_t, 4> meshDomainSize({SBC::ionosphereGrid.elements.size(), 0, SBC::ionosphereGrid.nodes.size(), 0});
1528 if (rank == 0) {
1529 vlsvWriter.writeArray("MESH_DOMAIN_SIZES", xmlAttributes, 1, 4, &meshDomainSize[0]);
1530 } else {
1531 vlsvWriter.writeArray("MESH_DOMAIN_SIZES", xmlAttributes, 0, 4, &meshDomainSize[0]);
1532 }
1533
1534 // write Offset arrays (no offset here, since we're writing only from a single task)
1535 std::array<uint64_t, 2> meshOffsets({SBC::ionosphereGrid.elements.size() * 5, SBC::ionosphereGrid.nodes.size()});
1536 if (rank == 0) {
1537 vlsvWriter.writeArray("MESH_OFFSETS", xmlAttributes, 1, 2, &meshOffsets[0]);
1538 } else {
1539 vlsvWriter.writeArray("MESH_OFFSETS", xmlAttributes, 0, 2, &meshOffsets[0]);
1540 }
1541
1542 // Write node coordinates
1543 std::vector<double> nodeCoordinates(3 * SBC::ionosphereGrid.nodes.size());
1544 for (uint64_t i = 0; i < SBC::ionosphereGrid.nodes.size(); i++) {
1545 nodeCoordinates[3 * i] = SBC::ionosphereGrid.nodes[i].x[0];
1546 nodeCoordinates[3 * i + 1] = SBC::ionosphereGrid.nodes[i].x[1];
1547 nodeCoordinates[3 * i + 2] = SBC::ionosphereGrid.nodes[i].x[2];
1548 }
1549 if (rank == 0) {
1550 // Write this data only on rank 0
1551 vlsvWriter.writeArray("MESH_NODE_CRDS", xmlAttributes, SBC::ionosphereGrid.nodes.size(), 3, nodeCoordinates.data());
1552 } else {
1553 // The others just write an empty dummy
1554 vlsvWriter.writeArray("MESH_NODE_CRDS", xmlAttributes, 0, 3, nodeCoordinates.data());
1555 }
1556
1557 // Write cell connectivity information - which elements touch which nodes.
1558 // struct VlsvMeshData __attribute__((packed)) {
1559 // uint32_t cell_type = vlsv::celltype::TRIANGLE; // This cell is a triangle
1560 // uint32_t num_nodes = 3; // It has three corners.
1561 // std::array<uint32_t, 3> nodes; // The corner data
1562 //};
1563 std::vector<uint32_t> ionosphereGridElementsAndCorners;
1564 for (uint i = 0; i < SBC::ionosphereGrid.elements.size(); i++) {
1565 ionosphereGridElementsAndCorners.push_back(vlsv::celltype::TRIANGLE);
1566 ionosphereGridElementsAndCorners.push_back(3);
1567 ionosphereGridElementsAndCorners.push_back(SBC::ionosphereGrid.elements[i].corners[0]);
1568 ionosphereGridElementsAndCorners.push_back(SBC::ionosphereGrid.elements[i].corners[1]);
1569 ionosphereGridElementsAndCorners.push_back(SBC::ionosphereGrid.elements[i].corners[2]);
1570 }
1571
1572 // Finally, write mesh object itself.
1573 xmlAttributes.clear();
1574 xmlAttributes["name"] = meshName;
1575 xmlAttributes["type"] = vlsv::mesh::STRING_UCD_GENERIC_MULTI;
1576 xmlAttributes["domains"] = "1";
1577 xmlAttributes["cells"] = std::to_string(SBC::ionosphereGrid.elements.size());
1578 xmlAttributes["nodes"] = std::to_string(SBC::ionosphereGrid.nodes.size());
1579
1580 if (rank == 0) {
1581 // Write this data only on rank 0
1582 vlsvWriter.writeArray("MESH", xmlAttributes, ionosphereGridElementsAndCorners.size(), 1, ionosphereGridElementsAndCorners.data());
1583 } else {
1584 vlsvWriter.writeArray("MESH", xmlAttributes, 0, 1, ionosphereGridElementsAndCorners.data());
1585 }
1586
1587 // Write different parameters of the class Ionosphere into the VLSV file
1588 if (vlsvWriter.writeParameter("ionosphere_radius", &SBC::Ionosphere::innerRadius) == false) { return false; }
1589 if (vlsvWriter.writeParameter("ionosphere_downmapping_radius", &SBC::Ionosphere::downmapRadius) == false) { return false; }
1590 if (vlsvWriter.writeParameter("ionosphere_time_smoothing_constant", &SBC::Ionosphere::couplingTimescale) == false) { return false; }
1591 if (vlsvWriter.writeParameter("ionosphere_time_interval", &SBC::Ionosphere::couplingInterval) == false) { return false; }
1592
1593 return true;
1594}
1595
1603bool writeVelocitySpace(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
1604 Writer& vlsvWriter, int index, const vector<uint64_t>& cells) {
1605 // Compute which cells will write out their velocity space
1606 vector<uint64_t> velSpaceCells;
1607 int lineX, lineY, lineZ;
1608 Real shellRadiusSquare;
1609 Real cellX, cellY, cellZ, DX, DY, DZ;
1610 Real dx_rm, dx_rp, dy_rm, dy_rp, dz_rm, dz_rp;
1611 Real rsquare_minus, rsquare_plus;
1612 bool withinshell, stridecheck;
1613 // #warning TODO: thread evaluation of cells due to trigonometrics in shells?
1614 for (uint i = 0; i < cells.size(); i++) {
1615 mpiGrid[cells[i]]->parameters[CellParams::ISCELLSAVINGF] = 0.0;
1616 // CellID stride selection
1618 velSpaceCells.push_back(cells[i]);
1619 mpiGrid[cells[i]]->parameters[CellParams::ISCELLSAVINGF] = 1.0;
1620 continue; // Avoid double entries in case the cell also matches following conditions.
1621 }
1622 // Cell lines selection
1623 // Determine cellID's 3D indices
1624
1625 // Loop over AMR levels
1626 uint startindex = 1;
1627 uint endindex = 1;
1628 for (int AMR = 0; AMR <= P::amrMaxSpatialRefLevel; AMR++) {
1629 int AMRm = 1u << AMR;
1630 uint cellsthislevel = (AMRm * P::xcells_ini) * (AMRm * P::ycells_ini) * (AMRm * P::zcells_ini);
1631 startindex = endindex;
1632 endindex = endindex + cellsthislevel;
1633
1634 // If cell belongs to this AMR level, find indices
1635 if ((cells[i] >= startindex) && (cells[i] < endindex)) {
1636 lineX = (cells[i] - startindex) % (AMRm * P::xcells_ini);
1637 lineY = ((cells[i] - startindex) / (AMRm * P::xcells_ini)) % (AMRm * P::ycells_ini);
1638 lineZ = ((cells[i] - startindex) / ((AMRm * P::xcells_ini) * (AMRm * P::ycells_ini))) % (AMRm * P::zcells_ini);
1639 // Check that indices are in correct intersection at least in one plane
1644 &&
1649 &&
1654 ) {
1655 velSpaceCells.push_back(cells[i]);
1656 mpiGrid[cells[i]]->parameters[CellParams::ISCELLSAVINGF] = 1.0;
1657 break; // Avoid double entries in case the cell also matches following conditions.
1658 }
1659 }
1660 }
1661 // Avoid double entries in case the cell also matches following conditions.
1662 if (mpiGrid[cells[i]]->parameters[CellParams::ISCELLSAVINGF] > 0) continue;
1663
1664 // Loop over spherical shells at defined distances
1665 for (uint ishell = 0; ishell < P::systemWriteDistributionWriteShellRadius.size(); ishell++) {
1667 cellX = mpiGrid[cells[i]]->parameters[CellParams::XCRD];
1668 cellY = mpiGrid[cells[i]]->parameters[CellParams::YCRD];
1669 cellZ = mpiGrid[cells[i]]->parameters[CellParams::ZCRD];
1670 DX = mpiGrid[cells[i]]->parameters[CellParams::DX];
1671 DY = mpiGrid[cells[i]]->parameters[CellParams::DY];
1672 DZ = mpiGrid[cells[i]]->parameters[CellParams::DZ];
1673
1674 dx_rm = cellX < 0 ? DX : 0;
1675 dx_rp = cellX < 0 ? 0 : DX;
1676 dy_rm = cellY < 0 ? DY : 0;
1677 dy_rp = cellY < 0 ? 0 : DY;
1678 dz_rm = cellZ < 0 ? DZ : 0;
1679 dz_rp = cellZ < 0 ? 0 : DZ;
1680 rsquare_minus = (cellX + dx_rm) * (cellX + dx_rm) + (cellY + dy_rm) * (cellY + dy_rm) + (cellZ + dz_rm) * (cellZ + dz_rm);
1681 rsquare_plus = (cellX + dx_rp) * (cellX + dx_rp) + (cellY + dy_rp) * (cellY + dy_rp) + (cellZ + dz_rp) * (cellZ + dz_rp);
1682 // Sometimes two face-neighboring cells can both intersect the sphere. In these cases, if the
1683 // stride applied in that region is in a different direction than the neighborhood, both cells will be saved.
1684 withinshell = (rsquare_minus <= shellRadiusSquare && rsquare_plus > shellRadiusSquare && P::systemWriteDistributionWriteShellStride[ishell] > 0);
1685 if (withinshell) {
1686 // sort centerpoints
1687 std::array<Real, 3> s = {abs(cellX + 0.5 * DX), abs(cellY + 0.5 * DY), abs(cellZ + 0.5 * DZ)};
1688 std::sort(s.begin(), s.end());
1690 int shellS = P::systemWriteDistributionWriteShellStride[ishell];
1691 // After this, assumes DX==DY==DZ
1692 // Dominant direction (+-x,+-y,+-z) is used for concentric rings
1693 Real D = s[2];
1694 // Tangential direction
1695 Real T;
1696 // Clock angle distance for stride steps
1697 Real clock;
1698 if ((P::xcells_ini == 1) || (P::ycells_ini == 1) || (P::zcells_ini == 1)) {
1699 // 1D or 2D simulation
1700 T = s[1];
1701 s[0] = 0;
1702 clock = 0;
1703 } else { // 3D simulation
1704 T = sqrt(s[0] * s[0] + s[1] * s[1]);
1705 clock = T * atan(s[0] / s[1]);
1706 }
1707 // Distance along great circle away from dominant coordinate
1708 Real dist = shellR * atan(T / D);
1709 // Now find the closest point(s) which fulfills the stride requirement
1710 Real dist2 = DX * shellS * round(dist / DX / shellS);
1711 Real clock2 = DX * shellS * round(clock / DX / shellS);
1712
1713 // Find Cartesian coordinates of this stridepoint
1714 Real D2 = shellR * cos(dist2 / shellR);
1715 Real T2 = shellR * sin(dist2 / shellR);
1716
1717 stridecheck = false;
1718 // Now check if the stridepoint is exactly in this cell
1719 if ((P::xcells_ini == 1) || (P::ycells_ini == 1) || (P::zcells_ini == 1)) {
1720 // 1D or 2D
1721 if ((D2 >= D - 0.5 * DX) && (D2 < D + 0.5 * DX) && (T2 >= T - 0.5 * DX) && (T2 < T + 0.5 * DX))
1722 stridecheck = true;
1723 // Special case for corners:
1724 if ((abs(D - T) < 0.5 * DX) && (dist2 > dist))
1725 stridecheck = true;
1726
1727 // Only save 1 cell touching axes
1728 if ((P::ycells_ini == 1) && (((cellX > -1.1 * DX) && (cellX < 0)) || ((cellZ > -1.1 * DZ) && (cellZ < 0))))
1729 stridecheck = false;
1730 if ((P::zcells_ini == 1) && (((cellX > -1.1 * DX) && (cellX < 0)) || ((cellY > -1.1 * DY) && (cellY < 0))))
1731 stridecheck = false;
1732
1733 } else {
1734 // 3D simulation, account for clock angle
1735 Real T2A = T2 * cos(clock2 / T2);
1736 Real T2B = T2 * sin(clock2 / T2);
1737 // Rings at given stride from dominant direction
1738 bool ring = (D2 >= D - 0.5 * DX) && (D2 < D + 0.5 * DX) && (T2 >= T - 0.5 * DX) && (T2 < T + 0.5 * DX);
1739 // Special case for 45 degree ring:
1740 ring = ring || ((abs(D - T) < 0.5 * DX) && (dist2 > dist));
1741 // Clock angle
1742 bool clockcheck = (T2A >= s[1] - 0.5 * DX) && (T2A < s[1] + 0.5 * DX) && (T2B >= s[0] - 0.5 * DX) && (T2B < s[0] + 0.5 * DX);
1743 // Special case for 45 degree clock angle
1744 clockcheck = clockcheck || ((abs(s[1] - s[0]) < 0.5 * DX) && (clock2 > clock));
1745 if (ring && clockcheck)
1746 stridecheck = true;
1747
1748 // Ensure cells touching Cartesian axes are included
1749 if ((s[1] < DX) && (s[0] < DX) && (D2 >= D - 0.5 * DX) && (D2 < D + 0.5 * DX))
1750 stridecheck = true;
1751
1752 // Special corner-corner-case
1753 if ((abs(s[2] - s[1]) < DX) && (abs(s[1] - s[0]) < DX) && (abs(s[2] - s[0]) < DX))
1754 stridecheck = true;
1755
1756 // Only save 1 cell touching axes (assumes origin is at corner intersection of 8 cells)
1757 if (((cellX > -1.1 * DX) && (cellX < 0)) || ((cellY > -1.1 * DY) && (cellY < 0)) || ((cellZ > -1.1 * DZ) && (cellZ < 0)))
1758 stridecheck = false;
1759 }
1760
1761 if (stridecheck) {
1762 velSpaceCells.push_back(cells[i]);
1763 mpiGrid[cells[i]]->parameters[CellParams::ISCELLSAVINGF] = 1.0;
1764 break; // Avoid double entries in case the cell also matches following conditions.
1765 }
1766 }
1767 }
1768 }
1769
1770 uint64_t numVelSpaceCells;
1771 uint64_t localNumVelSpaceCells;
1772 localNumVelSpaceCells = velSpaceCells.size();
1773 MPI_Allreduce(&localNumVelSpaceCells, &numVelSpaceCells, 1, MPI_UINT64_T, MPI_SUM, MPI_COMM_WORLD);
1774 bool ok = false;
1775 // Compress
1777 std::vector<std::vector<char>> mlp_clustered_bytes;
1778 phiprof::Timer compression_interface{"asterix-compression"};
1779 const auto& local_cells_to_compress = getLocalCells();
1780 ASTERIX::compress_vdfs(mpiGrid, velSpaceCells, P::vdf_compression_method, false, mlp_clustered_bytes, 1);
1781 compression_interface.stop();
1782 ok =
1783 writeVelocityDistributionDataAsterix(vlsvWriter, mpiGrid, velSpaceCells, mlp_clustered_bytes, MPI_COMM_WORLD);
1784 } else {
1785 // write out velocity space data NOTE: There is mpi communication in writeVelocityDistributionData
1786 ok = writeVelocityDistributionData(vlsvWriter, mpiGrid, velSpaceCells, MPI_COMM_WORLD);
1787 }
1788 if (!ok) {
1789 cerr << "ERROR, FAILED TO WRITE VELOCITY DISTRIBUTION DATA AT " << __FILE__ << " " << __LINE__ << endl;
1790 logFile << "(MAIN) writeGrid: ERROR FAILED TO WRITE VELOCITY DISTRIBUTION DATA AT: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
1791 return false;
1792 }
1793 return true;
1794}
1795
1800bool checkForSameMembers(const vector<uint64_t>& local_cells, const vector<uint64_t>& ghost_cells) {
1801 // NOTE: VECTORS MUST BE SORTED
1802 // Make sure ghost cells and local cells don't have same members in them:
1803 vector<uint64_t>::const_iterator i = local_cells.begin();
1804 vector<uint64_t>::const_iterator j = ghost_cells.begin();
1805 while (i != local_cells.end() && j != ghost_cells.end()) {
1806 if ((*i) < (*j)) {
1807 ++i;
1808 } else if ((*i) > (*j)) {
1809 ++j;
1810 } else {
1811 // Has a same member
1812 cerr << "ERROR SAME CELL ID " << *i << " -" << endl;
1813 logFile << "(MAIN) writeGrid: ERROR SAME CELL ID AT: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
1814 return true;
1815 }
1816 }
1817 return false;
1818}
1819
1830 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
1831 const FieldSolverData& fieldSolverData,
1833 const std::string& versionInfo,
1834 const std::string& configInfo,
1835 DataReducer* dataReducer,
1836 const uint& outputFileTypeIndex,
1837 const int& stripe,
1838 const bool writeGhosts,
1839 bool compress_vdfs
1840) {
1841 bool success = true;
1842 int myRank;
1843 phiprof::Timer barrierWritegridTimer{"Barrier-entering-writegrid", {"MPI", "Barrier"}};
1844 MPI_Barrier(MPI_COMM_WORLD);
1845 barrierWritegridTimer.stop();
1846
1847 MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
1848 phiprof::Timer writeReducedTimer{"writeGrid-reduced"};
1849 // Create a name for the output file and open it with VLSVWriter:
1850 stringstream fname;
1851 fname << P::systemWritePath.at(outputFileTypeIndex) << P::systemWriteName.at(outputFileTypeIndex);
1852 if (compress_vdfs) {
1853 fname << "_compressed";
1854 }
1855 fname<<".";
1856 fname.width(7);
1857 fname.fill('0');
1858 fname << P::systemWrites.at(outputFileTypeIndex) << ".vlsv";
1859
1860 // Open the file with vlsvWriter:
1861 Writer vlsvWriter;
1862 const int masterProcessId = 0;
1863
1864 MPI_Info MPIinfo;
1865 if (P::systemWriteHints.size() == 0) {
1866 MPIinfo = MPI_INFO_NULL;
1867 } else {
1868 MPI_Info_create(&MPIinfo);
1869
1870 for (std::vector<std::pair<std::string, std::string>>::const_iterator it = P::systemWriteHints.begin();
1871 it != P::systemWriteHints.end();
1872 it++)
1873 {
1874 MPI_Info_set(MPIinfo, it->first.c_str(), it->second.c_str());
1875 }
1876 }
1877 if (stripe < -1) {
1878 cerr << "Error: trying to set an invalid lustre stripe count in bulk IO. Ignoring value." << endl;
1879 } else {
1880 if (MPIinfo == MPI_INFO_NULL) {
1881 MPI_Info_create(&MPIinfo);
1882 }
1883 char stripeChar[6];
1884 sprintf(stripeChar, "%d", stripe);
1885 /* no. of I/O devices to be used for file striping */
1886 char factor[] = "striping_factor";
1887 MPI_Info_set(MPIinfo, factor, stripeChar);
1888 }
1889
1890 phiprof::Timer openTimer{"open"};
1891 vlsvWriter.open(fname.str(), MPI_COMM_WORLD, masterProcessId, MPIinfo);
1892 openTimer.stop();
1893
1894 if (MPIinfo != MPI_INFO_NULL) {
1895 MPI_Info_free(&MPIinfo);
1896 }
1897
1898 vlsvWriter.setBuffer(P::vlsvBufferSize);
1899
1900 phiprof::Timer metadataTimer{"metadataIO"};
1901
1902 // Get all local cell Ids
1903 const vector<CellID>& local_cells = getLocalCells();
1904
1905 // Declare ghost cells:
1906 vector<CellID> ghost_cells;
1907 if (writeGhosts) {
1908 // Writing ghost cells:
1909 // Get all ghost cell Ids (NOTE: this works slightly differently depending on whether the grid is periodic or not)
1910 ghost_cells = mpiGrid.get_remote_cells_on_process_boundary(Neighborhoods::NEAREST);
1911 }
1912
1913 // Make sure the local cells and ghost cells are fetched properly
1914 if (local_cells.empty()) {
1915 if (!ghost_cells.empty()) {
1916 // Local cells empty but ghost cells not empty -- something very wrong
1917 cerr << "ERROR! LOCAL CELLS EMPTY BUT GHOST CELLS NOT AT: " << __FILE__ << " " << __LINE__ << endl;
1918 }
1919 }
1920
1921 // The mesh name is "SpatialGrid" (This is used for writing in data)
1922 const string meshName = "SpatialGrid";
1923
1924 // Write mesh boundaries: NOTE: master process only
1925 // Visit plugin needs to know the boundaries of the mesh so the number of cells in x, y, z direction
1926 if (writeMeshBoundingBox(vlsvWriter, meshName, masterProcessId, MPI_COMM_WORLD) == false) {
1927 return false;
1928 }
1929
1930 // Write the node coordinates: NOTE: master process only
1931 if (writeBoundingBoxNodeCoordinates(vlsvWriter, meshName, masterProcessId, MPI_COMM_WORLD) == false) {
1932 return false;
1933 }
1934
1935 // Write basic grid variables: NOTE: master process only
1936 if (writeCommonGridData(vlsvWriter, mpiGrid, local_cells, P::systemWrites[outputFileTypeIndex], MPI_COMM_WORLD) == false) {
1937 return false;
1938 }
1939
1940 // Write zone global id numbers:
1941 if (writeZoneGlobalIdNumbers(mpiGrid, vlsvWriter, meshName, local_cells, ghost_cells) == false) {
1942 return false;
1943 }
1944 // Write domain sizes:
1945 if (writeDomainSizes(vlsvWriter, meshName, local_cells.size(), ghost_cells.size()) == false) {
1946 return false;
1947 }
1948 // Write domain extents
1949 if (writeDomainExtents(vlsvWriter, meshName, local_cells, mpiGrid) == false) {
1950 return false;
1951 }
1952 // Update local ids for cells:
1953 if (updateLocalIds(mpiGrid, local_cells, MPI_COMM_WORLD) == false) {
1954 return false;
1955 }
1956
1957 // Write ghost zone domain and local id numbers ( VisIt plugin needs this for MPI )
1958 if (writeGhostZoneDomainAndLocalIdNumbers(mpiGrid, vlsvWriter, meshName, ghost_cells) == false) {
1959 return false;
1960 }
1961
1962 // Write FSGrid metadata
1963 if (writeFsGridMetadata(fieldSolverData.fsgrid, technical, vlsvWriter, P::systemWriteFsGrid.at(outputFileTypeIndex)) == false) {
1964 return false;
1965 }
1966
1967 // Write Ionosphere Grid
1968 if (writeIonosphereGridMetadata(vlsvWriter) == false) {
1969 return false;
1970 }
1971
1972 // Write Version Info
1973 if (writeVersionInfo(versionInfo, vlsvWriter, MPI_COMM_WORLD) == false) {
1974 return false;
1975 }
1976
1977 // Write Config Info
1978 if (writeConfigInfo(configInfo, vlsvWriter, MPI_COMM_WORLD) == false) {
1979 return false;
1980 }
1981
1982 metadataTimer.stop();
1983 // Write Velocity Space contents i.e. VDFs
1984 phiprof::Timer vspaceTimer{"velocityspaceIO"};
1985 if (writeVelocitySpace(mpiGrid, vlsvWriter, outputFileTypeIndex, local_cells) == false) {
1986 return false;
1987 }
1988 vspaceTimer.stop();
1989
1990 phiprof::Timer reducedTimer{"reduceddataIO"};
1991 // Write necessary variables:
1992 // Determines whether we write in floats or doubles
1993 phiprof::Timer writeDataTimer{"writeDataReducer"};
1994 if (dataReducer != NULL)
1995 for (uint i = 0; i < dataReducer->size(); ++i) {
1996 if (writeDataReducer(mpiGrid, local_cells, fieldSolverData, (P::writeAsFloat == 1), P::systemWriteFsGrid.at(outputFileTypeIndex), *dataReducer, i, vlsvWriter) == false) {
1997 return false;
1998 }
1999 }
2000 writeDataTimer.stop();
2001
2002 phiprof::Timer barrierTimer{"Barrier", {"MPI", "Barrier"}};
2003 MPI_Barrier(MPI_COMM_WORLD);
2004 barrierTimer.stop();
2005
2006 const uint64_t bytesWritten = vlsvWriter.getBytesWritten();
2007 const double writeTime = vlsvWriter.getWriteTime();
2008 logFile << "(writeGrid) Wrote ";
2009
2010 if (bytesWritten > 1.0e9) logFile << bytesWritten / 1.0e9 << " GB in ";
2011 else if (bytesWritten > 1e6) logFile << bytesWritten / 1.0e6 << " MB in ";
2012 else if (bytesWritten > 1e3) logFile << bytesWritten / 1.0e3 << " kB in ";
2013 else logFile << bytesWritten << " B in ";
2014
2015 logFile << writeTime << " seconds, approximate data rate is ";
2016
2017 if (bytesWritten / writeTime > 1e9) logFile << bytesWritten / writeTime / 1e9 << " GB/s";
2018 else if (bytesWritten / writeTime > 1e6) logFile << bytesWritten / writeTime / 1e6 << " MB/s";
2019 else if (bytesWritten / writeTime > 1e3) logFile << bytesWritten / writeTime / 1e3 << " kB/s";
2020 else logFile << bytesWritten / writeTime << " B/s";
2021 logFile << endl;
2022
2023 reducedTimer.stop();
2024
2025 phiprof::Timer closeTimer{"close"};
2026 vlsvWriter.close();
2027 closeTimer.stop();
2028 writeReducedTimer.stop(bytesWritten * 1e-9, "GB");
2029
2030#ifdef USE_GPU
2031 if (IObuffer) {
2033 IObuffer = 0;
2034 }
2035#endif
2036 return success;
2037}
2038
2049 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
2050 const FieldSolverData& fieldSolverData,
2052 const std::string& versionInfo,
2053 const std::string& configInfo,
2054 DataReducer& dataReducer,
2055 const string& name,
2056 const uint& fileIndex,
2057 const bool dateInFileName,
2058 const int& stripe,
2059 bool compress_vdfs)
2060{
2061 // Writes a restart
2062 bool success = true;
2063 int myRank;
2064
2065 MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
2066 phiprof::Timer barrierEnteringTimer{"BarrierEnteringWriteRestart", {"MPI", "Barrier"}};
2067 MPI_Barrier(MPI_COMM_WORLD);
2068 barrierEnteringTimer.stop();
2069
2070 phiprof::Timer writeTimer{"writeRestart"};
2071 phiprof::Timer deallocateTimer{"DeallocateRemoteBlocks"};
2072 // deallocate blocks in remote cells to decrease memory load
2074 deallocateTimer.stop();
2075
2076 // Get the current time.
2077 // Avoid different times on different processes!
2078 char currentDate[80];
2079 if (dateInFileName) {
2080 if (myRank == MASTER_RANK) {
2081 const time_t rawTime = time(NULL);
2082 const struct tm* timeInfo = localtime(&rawTime);
2083 strftime(currentDate, 80, ".%F_%H-%M-%S", timeInfo); // note the dot prefixed
2084 }
2085 MPI_Bcast(&currentDate, 80, MPI_CHAR, MASTER_RANK, MPI_COMM_WORLD);
2086 } else {
2087 currentDate[0] = '\0';
2088 }
2089
2090 // Create a name for the output file and open it with VLSVWriter:
2091 stringstream fname;
2092 if (dateInFileName) {
2093 fname << P::restartWritePath;
2094 } else {
2095 fname << P::recoverWritePath;
2096 }
2097 fname << "/" << name << ".";
2098 if (dateInFileName) {
2099 fname.width(7);
2100 fname.fill('0');
2101 }
2102 fname << fileIndex << currentDate << ".vlsv";
2103
2104 phiprof::Timer openTimer{"open"};
2105 // Open the file with vlsvWriter:
2106 Writer vlsvWriter;
2107 const int masterProcessId = 0;
2108 MPI_Info MPIinfo;
2109 if (P::restartWriteHints.size() == 0) {
2110 MPIinfo = MPI_INFO_NULL;
2111 } else {
2112 MPI_Info_create(&MPIinfo);
2113
2114 for (std::vector<std::pair<std::string, std::string>>::const_iterator it = P::restartWriteHints.begin();
2115 it != P::restartWriteHints.end();
2116 it++)
2117 {
2118 MPI_Info_set(MPIinfo, it->first.c_str(), it->second.c_str());
2119 }
2120 }
2121 if (stripe < -1) {
2122 cerr << "Error: trying to set an invalid lustre stripe count in restart IO. Ignoring value." << endl;
2123 } else {
2124 if (MPIinfo == MPI_INFO_NULL) {
2125 MPI_Info_create(&MPIinfo);
2126 }
2127 char stripeChar[6];
2128 sprintf(stripeChar, "%d", stripe);
2129 /* no. of I/O devices to be used for file striping */
2130 char factor[] = "striping_factor";
2131 MPI_Info_set(MPIinfo, factor, stripeChar);
2132 }
2133
2134 if (vlsvWriter.open(fname.str(), MPI_COMM_WORLD, masterProcessId, MPIinfo) == false) return false;
2135
2136 if (MPIinfo != MPI_INFO_NULL) {
2137 MPI_Info_free(&MPIinfo);
2138 }
2139
2140 openTimer.stop();
2141
2142 vlsvWriter.setBuffer(P::vlsvBufferSize);
2143
2144 phiprof::Timer metadataTimer{"metadataIO"};
2145
2146 // Get all local cell Ids
2147 vector<CellID> local_cells = getLocalCells();
2148 // no order assumed so let's order cells here
2149 std::sort(local_cells.begin(), local_cells.end());
2150
2151 // Note: No need to write ghost zones for write restart
2152 const vector<CellID> ghost_cells;
2153
2154 // The mesh name is "SpatialGrid"
2155 const string meshName = "SpatialGrid";
2156
2157 // Write mesh boundaries: NOTE: master process only
2158 // Visit plugin needs to know the boundaries of the mesh so the number of cells in x, y, z direction
2159 if (writeMeshBoundingBox(vlsvWriter, meshName, masterProcessId, MPI_COMM_WORLD) == false) {
2160 return false;
2161 }
2162 // Write the node coordinates: NOTE: master process only
2163 if (writeBoundingBoxNodeCoordinates(vlsvWriter, meshName, masterProcessId, MPI_COMM_WORLD) == false) {
2164 return false;
2165 }
2166 // Write basic grid parameters: NOTE: master process only ( I think )
2167 if (writeCommonGridData(vlsvWriter, mpiGrid, local_cells, fileIndex, MPI_COMM_WORLD) == false) {
2168 return false;
2169 }
2170 // Write zone global id numbers:
2171 if (writeZoneGlobalIdNumbers(mpiGrid, vlsvWriter, meshName, local_cells, ghost_cells) == false) {
2172 return false;
2173 }
2174 // Write domain sizes:
2175 if (writeDomainSizes(vlsvWriter, meshName, local_cells.size(), ghost_cells.size()) == false) {
2176 return false;
2177 }
2178 // Write domain extents
2179 if (writeDomainExtents(vlsvWriter, meshName, local_cells, mpiGrid) == false) {
2180 return false;
2181 }
2182 // Write FSGrid metadata
2183 if (writeFsGridMetadata(fieldSolverData.fsgrid, technical, vlsvWriter, true) == false) {
2184 return false;
2185 }
2186 // Write Version Info
2187 if (writeVersionInfo(versionInfo, vlsvWriter, MPI_COMM_WORLD) == false) {
2188 return false;
2189 }
2190 // Write Config Info
2191 if (writeConfigInfo(configInfo, vlsvWriter, MPI_COMM_WORLD) == false) {
2192 return false;
2193 }
2194 // Write Ionosphere Grid
2195 if (writeIonosphereGridMetadata(vlsvWriter) == false) {
2196 return false;
2197 }
2198
2199 // write the velocity distribution data -- note: it's expecting a vector of pointers:
2200 // Note: restart should always write double values to ensure the accuracy of the restart runs.
2201 // In case of distribution data it is not as important as they are mainly used for visualization purpose
2202 bool ok = false;
2203 if (compress_vdfs) {
2204 std::vector<std::vector<char>> mlp_clustered_bytes;
2205 phiprof::Timer compression_interface{"asterix-compression"};
2206 const auto& local_cells_to_compress = getLocalCells();
2207 ASTERIX::compress_vdfs(mpiGrid, local_cells, P::vdf_compression_method, false, mlp_clustered_bytes, 1);
2208 compression_interface.stop();
2209 phiprof::Timer vspaceTimer{"velocityspaceIO"};
2210 ok = writeVelocityDistributionDataAsterix(vlsvWriter, mpiGrid, local_cells, mlp_clustered_bytes, MPI_COMM_WORLD);
2211 vspaceTimer.stop();
2212 } else {
2213 phiprof::Timer vspaceTimer{"velocityspaceIO"};
2214 ok = writeVelocityDistributionData(vlsvWriter, mpiGrid, local_cells, MPI_COMM_WORLD);
2215 vspaceTimer.stop();
2216 }
2217 if (!ok) {
2218 cerr << "ERROR, FAILED TO WRITE VELOCITY DISTRIBUTION DATA AT " << __FILE__ << " " << __LINE__ << endl;
2219 logFile << "(MAIN) writeGrid: ERROR FAILED TO WRITE VELOCITY DISTRIBUTION DATA AT: " << __FILE__ << " " << __LINE__ << endl << writeVerbose;
2220 return false;
2221 }
2222
2223 metadataTimer.stop();
2224 phiprof::Timer reducedTimer{"reduceddataIO"};
2225 // write out DROs we need for restarts
2226 DataReducer restartReducer;
2227 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("moments", CellParams::RHOM, 5));
2228 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("moments_dt2", CellParams::RHOM_DT2, 5));
2229 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("moments_r", CellParams::RHOM_R, 5));
2230 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("moments_v", CellParams::RHOM_V, 5));
2231 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("pressure", CellParams::P_11, 3));
2232 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("pressure_dt2", CellParams::P_11_DT2, 3));
2233 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("pressure_r", CellParams::P_11_R, 3));
2234 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("pressure_v", CellParams::P_11_V, 3));
2236 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("max_v_dt", CellParams::MAXVDT, 1));
2237 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("max_r_dt", CellParams::MAXRDT, 1));
2238 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("max_fields_dt", CellParams::MAXFDT, 1));
2240 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("vg_amr_alpha1", CellParams::AMR_ALPHA1, 1));
2241 restartReducer.addOperator(new DRO::DataReductionOperatorCellParams("vg_amr_alpha2", CellParams::AMR_ALPHA2, 1));
2242 restartReducer.addOperator(new DRO::VariableBVol);
2243 restartReducer.addMetadata(restartReducer.size() - 1, "T", "$\\mathrm{T}$", "$B_\\mathrm{vol,vg}$", "1.0");
2244 restartReducer.addOperator(new DRO::MPIrank);
2245 restartReducer.addOperator(new DRO::BoundaryType);
2246 restartReducer.addOperator(new DRO::BoundaryLayer);
2247 //TODO enable multi pop MLP
2248 restartReducer.addOperator(new DRO::MLPepochs(0));
2249 restartReducer.addOperator(new DRO::MLPerror(0));
2250
2251 // Fsgrid Reducers
2252 restartReducer.addOperator(new DRO::DataReductionOperatorFsGrid("fg_E", [](const FieldSolverData& fieldSolverData) -> std::vector<Real> {
2253 const auto* localSize = &fieldSolverData.fsgrid.getLocalSize()[0];
2254 std::vector<Real> retval(localSize[0] * localSize[1] * localSize[2] * 3);
2255
2256 fieldSolverData.fsgrid.serial_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; }, phiprof::initializeTimer("DRO_fg_E"), fieldSolverData.technical,
2257 [=, &retval](const fsgrid::Coordinates coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
2258 const auto lid = stencil.ooo();
2259 const auto ri = localSize[1] * localSize[0] * stencil.k + localSize[0] * stencil.j + stencil.i;
2260 retval[3 * ri] = fieldSolverData.E[lid][fsgrids::EX];
2261 retval[3 * ri + 1] = fieldSolverData.E[lid][fsgrids::EY];
2262 retval[3 * ri + 2] = fieldSolverData.E[lid][fsgrids::EZ];
2263 });
2264 return retval;
2265 }));
2266
2267 restartReducer.addOperator(new DRO::DataReductionOperatorFsGrid("fg_PERB", [](const FieldSolverData& fieldSolverData) -> std::vector<Real> {
2268 const auto* localSize = &fieldSolverData.fsgrid.getLocalSize()[0];
2269 std::vector<Real> retval(localSize[0] * localSize[1] * localSize[2] * 3);
2270
2271 fieldSolverData.fsgrid.serial_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; }, phiprof::initializeTimer("DRO_fg_PERB"), fieldSolverData.technical,
2272 [=, &retval](const fsgrid::Coordinates coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
2273 const auto lid = stencil.ooo();
2274 const auto ri = localSize[1] * localSize[0] * stencil.k + localSize[0] * stencil.j + stencil.i;
2275 retval[3 * ri] = fieldSolverData.perB[lid][fsgrids::PERBX];
2276 retval[3 * ri + 1] = fieldSolverData.perB[lid][fsgrids::PERBY];
2277 retval[3 * ri + 2] = fieldSolverData.perB[lid][fsgrids::PERBZ];
2278 });
2279 return retval;
2280 }));
2281
2282 // Add ionosphere restart variables
2283 // (To reconstruct state, we need the time-smoothed downmapped quantities: FACs, rhon and pressure.
2284 // Also, to be immediately consistent after restart, write the potential)
2285 if (SBC::ionosphereGrid.nodes.size() > 0) {
2286 restartReducer.addOperator(new DRO::DataReductionOperatorIonosphereNode("ig_fac", [](SBC::SphericalTriGrid& grid) -> std::vector<Real> {
2287 std::vector<Real> retval(grid.nodes.size());
2288
2289 for (uint i = 0; i < grid.nodes.size(); i++) {
2290 Real area = 0;
2291 for (uint e = 0; e < grid.nodes[i].numTouchingElements; e++) {
2292 area += grid.elementArea(grid.nodes[i].touchingElements[e]);
2293 }
2294 area /= 3.; // As every element has 3 corners, don't double-count areas
2295 retval[i] = grid.nodes[i].parameters[ionosphereParameters::SOURCE] / area;
2296 }
2297
2298 return retval;
2299 }));
2300 restartReducer.addOperator(new DRO::DataReductionOperatorIonosphereNode("ig_rhon", [](SBC::SphericalTriGrid& grid) -> std::vector<Real> {
2301 std::vector<Real> retval(grid.nodes.size());
2302
2303 for (uint i = 0; i < grid.nodes.size(); i++) {
2304 retval[i] = grid.nodes[i].parameters[ionosphereParameters::RHON];
2305 }
2306
2307 return retval;
2308 }));
2309 restartReducer.addOperator(new DRO::DataReductionOperatorIonosphereNode("ig_electrontemp", [](SBC::SphericalTriGrid& grid) -> std::vector<Real> {
2310 std::vector<Real> retval(grid.nodes.size());
2311
2312 for (uint i = 0; i < grid.nodes.size(); i++) {
2313 retval[i] = grid.nodes[i].parameters[ionosphereParameters::TEMPERATURE];
2314 }
2315
2316 return retval;
2317 }));
2318 restartReducer.addOperator(new DRO::DataReductionOperatorIonosphereNode("ig_potential", [](SBC::SphericalTriGrid& grid) -> std::vector<Real> {
2319 std::vector<Real> retval(grid.nodes.size());
2320
2321 for (uint i = 0; i < grid.nodes.size(); i++) {
2322 retval[i] = grid.nodes[i].parameters[ionosphereParameters::SOLUTION];
2323 }
2324
2325 return retval;
2326 }));
2327
2328 // These following ones aren't really necessary to restart the ionosphere
2329 // correctly, but we'll write them anyway as to not have dropouts in
2330 // rendered animations:
2331 restartReducer.addOperator(new DRO::DataReductionOperatorIonosphereNode("ig_sigmap", [](SBC::SphericalTriGrid& grid) -> std::vector<Real> {
2332 std::vector<Real> retval(grid.nodes.size());
2333
2334 for (uint i = 0; i < grid.nodes.size(); i++) {
2335 retval[i] = grid.nodes[i].parameters[ionosphereParameters::SIGMAP];
2336 }
2337
2338 return retval;
2339 }));
2340 restartReducer.addOperator(new DRO::DataReductionOperatorIonosphereNode("ig_sigmah", [](SBC::SphericalTriGrid& grid) -> std::vector<Real> {
2341 std::vector<Real> retval(grid.nodes.size());
2342
2343 for (uint i = 0; i < grid.nodes.size(); i++) {
2344 retval[i] = grid.nodes[i].parameters[ionosphereParameters::SIGMAH];
2345 }
2346
2347 return retval;
2348 }));
2349 restartReducer.addOperator(new DRO::DataReductionOperatorIonosphereNode("ig_sigmaparallel", [](SBC::SphericalTriGrid& grid) -> std::vector<Real> {
2350 std::vector<Real> retval(grid.nodes.size());
2351
2352 for (uint i = 0; i < grid.nodes.size(); i++) {
2353 retval[i] = grid.nodes[i].parameters[ionosphereParameters::SIGMAPARALLEL];
2354 }
2355
2356 return retval;
2357 }));
2358 restartReducer.addOperator(new DRO::DataReductionOperatorIonosphereNode("ig_precipitation", [](SBC::SphericalTriGrid& grid) -> std::vector<Real> {
2359 std::vector<Real> retval(grid.nodes.size());
2360
2361 for (uint i = 0; i < grid.nodes.size(); i++) {
2362 retval[i] = grid.nodes[i].parameters[ionosphereParameters::PRECIP];
2363 }
2364
2365 return retval;
2366 }));
2367 }
2368
2369 // Write necessary variables:
2370 const bool writeAsFloat = P::writeRestartAsFloat;
2371 for (uint i = 0; i < restartReducer.size(); ++i) {
2372 writeDataReducer(mpiGrid, local_cells, fieldSolverData, writeAsFloat, true, restartReducer, i, vlsvWriter);
2373 }
2374 reducedTimer.stop();
2375
2376 phiprof::Timer closeTimer{"close"};
2377 vlsvWriter.close();
2378 closeTimer.stop();
2379
2380#ifdef USE_GPU
2381 if (IObuffer) {
2383 IObuffer = 0;
2384 }
2385#endif
2386
2387 phiprof::Timer updateRemoteTimer{"updateRemoteBlocks"};
2388 // Updated newly adjusted velocity block lists on remote cells, and
2389 // prepare to receive block data
2390 for (uint popID = 0; popID < getObjectWrapper().particleSpecies.size(); ++popID)
2391 updateRemoteVelocityBlockLists(mpiGrid, popID);
2392 updateRemoteTimer.stop();
2393
2394 const uint64_t bytesWritten = vlsvWriter.getBytesWritten();
2395 const double writeTime = vlsvWriter.getWriteTime();
2396 logFile << "(writeGrid) Wrote ";
2397
2398 if (bytesWritten > 1.0e9) logFile << bytesWritten / 1.0e9 << " GB in ";
2399 else if (bytesWritten > 1e6) logFile << bytesWritten / 1.0e6 << " MB in ";
2400 else if (bytesWritten > 1e3) logFile << bytesWritten / 1.0e3 << " kB in ";
2401 else logFile << bytesWritten << " B in ";
2402
2403 logFile << writeTime << " seconds, approximate data rate is ";
2404
2405 if (bytesWritten / writeTime > 1e9) logFile << bytesWritten / writeTime / 1e9 << " GB/s";
2406 else if (bytesWritten / writeTime > 1e6) logFile << bytesWritten / writeTime / 1e6 << " MB/s";
2407 else if (bytesWritten / writeTime > 1e3) logFile << bytesWritten / writeTime / 1e3 << " kB/s";
2408 else logFile << bytesWritten / writeTime << " B/s";
2409 logFile << endl;
2410
2411 writeTimer.stop(bytesWritten * 1e-9, "GB");
2412 return success;
2413}
2414
2422bool writeDiagnostic(const dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid, DataReducer& dataReducer) {
2423 int myRank;
2424 MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
2425
2426 string dataType;
2427 uint dataSize, vectorSize;
2428 const vector<CellID>& cells = getLocalCells();
2429 cuint nCells = cells.size();
2430 cuint nOps = dataReducer.size();
2431
2432 // Exit if the user does not want any diagnostics output
2433 if (nOps == 0) return true;
2434
2435 vector<Real> localMin(nOps), localMax(nOps), localSum(nOps+1), localAvg(nOps),
2436 globalMin(nOps), globalMax(nOps), globalSum(nOps+1), globalAvg(nOps);
2437 localSum[0] = 1.0 * nCells;
2438 Real buffer;
2439 bool success = true;
2440 static bool printDiagnosticHeader = true;
2441
2442 if (printDiagnosticHeader == true && myRank == MASTER_RANK) {
2443 if (P::isRestart) {
2444 diagnostic << "# ==== Restart from file " << P::restartFileName << " ====" << endl;
2445 }
2446 diagnostic << "# Column 1 Step" << endl;
2447 diagnostic << "# Column 2 Simulation time" << endl;
2448 diagnostic << "# Column 3 Time step dt" << endl;
2449 for (uint i = 0; i < nOps; ++i) {
2450 diagnostic << "# Columns " << 4 + i * 4 << " to " << 7 + i * 4 << ": " << dataReducer.getName(i) << " min max sum average" << endl;
2451 }
2452 printDiagnosticHeader = false;
2453 }
2454
2455 for (uint i = 0; i < nOps; ++i) {
2456
2457 if (dataReducer.getDataVectorInfo(i, dataType, dataSize, vectorSize) == false) {
2458 cerr << "ERROR when requesting info from diagnostic DRO " << dataReducer.getName(i) << endl;
2459 }
2460 localMin[i] = std::numeric_limits<Real>::max();
2461 localMax[i] = std::numeric_limits<Real>::min();
2462 localSum[i + 1] = 0.0;
2463 buffer = 0.0;
2464
2465 // Request DataReductionOperator to calculate the reduced data for all local cells:
2466 for (uint64_t cell = 0; cell < nCells; ++cell) {
2467 success = true;
2468 if (dataReducer.reduceDiagnostic(mpiGrid[cells[cell]], i, &buffer) == false) success = false;
2469 localMin[i] = min(buffer, localMin[i]);
2470 localMax[i] = max(buffer, localMax[i]);
2471 localSum[i + 1] += buffer;
2472 }
2473 localAvg[i] = localSum[i + 1];
2474
2475 if (success == false) {
2476 logFile << "(MAIN) writeDiagnostic: ERROR datareductionoperator '" << dataReducer.getName(i) << "' returned false!" << endl << writeVerbose;
2477 }
2478 }
2479
2480 MPI_Reduce(&localMin[0], &globalMin[0], nOps, MPI_Type<Real>(), MPI_MIN, 0, MPI_COMM_WORLD);
2481 MPI_Reduce(&localMax[0], &globalMax[0], nOps, MPI_Type<Real>(), MPI_MAX, 0, MPI_COMM_WORLD);
2482 MPI_Reduce(&localSum[0], &globalSum[0], nOps + 1, MPI_Type<Real>(), MPI_SUM, 0, MPI_COMM_WORLD);
2483
2484 diagnostic << setprecision(12);
2485 diagnostic << Parameters::tstep << "\t";
2486 diagnostic << Parameters::t << "\t";
2487 diagnostic << Parameters::dt << "\t";
2488
2489 for (uint i = 0; i < nOps; ++i) {
2490 if (globalSum[0] != 0.0) {
2491 globalAvg[i] = globalSum[i + 1] / globalSum[0];
2492 } else {
2493 globalAvg[i] = globalSum[i + 1];
2494 }
2495 if (myRank == MASTER_RANK) {
2496 diagnostic << globalMin[i] << "\t" << globalMax[i] << "\t" << globalSum[i + 1] << "\t" << globalAvg[i] << "\t";
2497 }
2498 }
2499 if (myRank == MASTER_RANK) diagnostic << endl << write;
2500 return true;
2501}
for i
Definition Dispersion.m:24
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
#define CHK_ERR(err)
#define gpuMemcpy
#define gpuMemcpyDeviceToHost
#define gpuMallocHost
#define gpuFreeHost
bool reduceDiagnostic(const SpatialCell *cell, const unsigned int &operatorID, Real *result)
bool getMetadata(const unsigned int &operatorID, std::string &unit, std::string &unitLaTeX, std::string &variableLaTeX, std::string &unitConversion) const
unsigned int size() const
bool writeFsGridData(const FieldSolverData &fieldSolverData, const std::string &meshName, const unsigned int operatorID, vlsv::Writer &vlsvWriter, const bool writeAsFloat=false)
bool addOperator(DRO::DataReductionOperator *op)
bool hasParameters(const unsigned int &operatorID) const
bool addMetadata(const unsigned int operatorID, std::string unit, std::string unitLaTeX, std::string variableLaTeX, std::string unitConversion)
bool writeParameters(const unsigned int &operatorID, vlsv::Writer &vlsvWriter)
std::string getName(const unsigned int &operatorID) const
bool reduceData(const SpatialCell *cell, const unsigned int &operatorID, char *buffer)
bool writeIonosphereGridData(SBC::SphericalTriGrid &grid, const std::string &meshName, const unsigned int operatorID, vlsv::Writer &vlsvWriter)
bool getDataVectorInfo(const unsigned int &operatorID, std::string &dataType, unsigned int &dataSize, unsigned int &vectorSize) const
static Real innerRadius
Definition ionosphere.h:622
static Real downmapRadius
Definition ionosphere.h:638
static Real couplingInterval
Definition ionosphere.h:648
static Real couplingTimescale
Definition ionosphere.h:647
const vmesh::GlobalID * get_velocity_grid(const uint popID)
vmesh::LocalID get_number_of_velocity_blocks(const uint popID) const
vmesh::GlobalID get_velocity_block_global_id(const vmesh::LocalID &blockLID, const uint popID) const
static void set_mpi_transfer_type(const uint64_t type, bool atSysBoundaries=false)
Realf * get_data(const uint popID)
Population & get_population(const uint popID)
std::array< Real, CellParams::N_SPATIAL_CELL_PARAMS > parameters
const std::vector< CellID > & getLocalCells()
Definition main.cpp:39
@ 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 WID
Definition common.h:514
#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
int myRank
Definition gpu_base.cpp:48
Logger logFile
Definition main.cpp:25
const int j
void deallocateRemoteCellBlocks(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition grid.cpp:902
void updateRemoteVelocityBlockLists(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const uint popID, const uint neighborhood)
Definition grid.cpp:919
ObjectWrapper & getObjectWrapper()
Definition main.cpp:33
Logger diagnostic
Definition ioread.cpp:59
bool checkForSameMembers(const vector< uint64_t > &local_cells, const vector< uint64_t > &ghost_cells)
Definition iowrite.cpp:1800
bool updateLocalIds(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &local_cells, MPI_Comm comm)
Definition iowrite.cpp:79
bool writeVspaceDataCompressionNone(const uint popID, Writer &vlsvWriter, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, std::size_t totalBlocks, MPI_Comm comm)
Definition iowrite.cpp:342
bool writeVersionInfo(const std::string &version, vlsv::Writer &vlsvWriter, MPI_Comm comm)
Definition iowrite.cpp:1355
char * IObuffer
Definition iowrite.cpp:61
bool writeGrid(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const FieldSolverData &fieldSolverData, fsgrids::consttechnicalspan technical, const std::string &versionInfo, const std::string &configInfo, DataReducer *dataReducer, const uint &outputFileTypeIndex, const int &stripe, const bool writeGhosts, bool compress_vdfs)
Write out system into a vlsv file.
Definition iowrite.cpp:1829
bool writeZoneGlobalIdNumbers(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, Writer &vlsvWriter, const string &meshName, const vector< uint64_t > &local_cells, const vector< uint64_t > &ghost_cells)
Definition iowrite.cpp:1141
bool writeDomainSizes(Writer &vlsvWriter, const string &meshName, const unsigned int &numberOfLocalZones, const unsigned int &numberOfGhostZones)
Definition iowrite.cpp:1050
bool writeVelocityDistributionDataAsterix(const uint popID, Writer &vlsvWriter, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, std::vector< std::vector< char > > &mpl_bytes, MPI_Comm comm)
Definition iowrite.cpp:634
bool writeRestart(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const FieldSolverData &fieldSolverData, fsgrids::consttechnicalspan technical, const std::string &versionInfo, const std::string &configInfo, DataReducer &dataReducer, const string &name, const uint &fileIndex, const bool dateInFileName, const int &stripe, bool compress_vdfs)
Write out a restart of the simulation into a vlsv file. All block data in remote cells will be reset.
Definition iowrite.cpp:2048
bool writeDataReducer(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, const FieldSolverData &fieldSolverData, const bool writeAsFloat, const bool writeFsGrid, DataReducer &dataReducer, cint dataReducerIndex, Writer &vlsvWriter)
Definition iowrite.cpp:790
bool writeDiagnostic(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, DataReducer &dataReducer)
Write out simulation diagnostics into diagnostic.txt.
Definition iowrite.cpp:2422
bool writeIonosphereGridMetadata(vlsv::Writer &vlsvWriter)
Definition iowrite.cpp:1496
bool writeConfigInfo(const std::string &config, vlsv::Writer &vlsvWriter, MPI_Comm comm)
Definition iowrite.cpp:1378
bool globalSuccess(bool success, const string &errorMessage, MPI_Comm comm)
Definition iowrite.cpp:110
bool writeMeshBoundingBox(Writer &vlsvWriter, const string &meshName, const int masterRank, MPI_Comm comm)
Definition iowrite.cpp:1311
bool writeBoundingBoxNodeCoordinates(Writer &vlsvWriter, const string &meshName, const int masterRank, MPI_Comm comm)
Definition iowrite.cpp:1225
bool writeCommonGridData(Writer &vlsvWriter, const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const vector< uint64_t > &local_cells, const uint &fileIndex, MPI_Comm comm)
Definition iowrite.cpp:926
bool writeGhostZoneDomainAndLocalIdNumbers(const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, Writer &vlsvWriter, const string &meshName, const vector< uint64_t > &ghost_cells)
Definition iowrite.cpp:986
bool writeFsGridMetadata(FieldSolverGrid &fsgrid, fsgrids::consttechnicalspan technical, vlsv::Writer &vlsvWriter, bool writeIDs=false)
Definition iowrite.cpp:1400
bool writeDomainExtents(Writer &vlsvWriter, const string &meshName, const std::vector< CellID > &local_cells, const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
Definition iowrite.cpp:1080
bool writeVelocityDistributionData(const uint popID, Writer &vlsvWriter, const dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &cells, MPI_Comm comm)
Definition iowrite.cpp:161
bool writeVelocitySpace(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, Writer &vlsvWriter, int index, const vector< uint64_t > &cells)
Definition iowrite.cpp:1603
Logger & writeVerbose(Logger &logger)
Definition logger.cpp:177
Logger & write(Logger &logger)
Definition logger.cpp:193
#define index(i, j, k)
MPI_Datatype MPI_Type()
void compress_vdfs(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const std::vector< CellID > &local_cells, P::ASTERIX_COMPRESSION_METHODS method, bool update_weights, std::vector< std::vector< char > > &mpl_bytes, uint32_t downsampling_factor=1)
@ BULKV_FORCING_X
Definition common.h:225
@ AMR_ALPHA2
Definition common.h:221
@ ISCELLSAVINGF
Definition common.h:199
@ AMR_ALPHA1
Definition common.h:220
@ LBWEIGHTCOUNTER
Definition common.h:198
FieldTracingParameters fieldTracingParameters
SphericalTriGrid ionosphereGrid
std::span< const technical > consttechnicalspan
Definition common.h:453
@ PERBY
Definition common.h:276
@ PERBZ
Definition common.h:277
@ PERBX
Definition common.h:275
static const uint64_t CELL_IOLOCALCELLID
uint32_t LocalID
Definition definitions.h:60
uint32_t GlobalID
Definition definitions.h:59
ARCH_HOSTDEV MeshWrapper * getMeshWrapper()
fsgrids::consttechnicalspan technical
Definition grid.h:52
fsgrids::constefieldspan E
Definition grid.h:40
FieldSolverGrid & fsgrid
Definition grid.h:36
fsgrids::constperbspan perB
Definition grid.h:38
std::vector< species::Species > particleSpecies
static Real ymax
Definition parameters.h:41
static Real dz_ini
Definition parameters.h:46
static Real dx_ini
Definition parameters.h:44
static std::vector< int > systemWriteDistributionWriteZlineStride
Definition parameters.h:97
static Real xmax
Definition parameters.h:39
static int writeRestartAsFloat
Definition parameters.h:179
static uint zcells_ini
Definition parameters.h:50
static Real zmax
Definition parameters.h:43
static std::string restartWritePath
Definition parameters.h:126
static int amrMaxSpatialRefLevel
Definition parameters.h:190
static std::vector< int > systemWriteDistributionWriteShellStride
Definition parameters.h:103
static std::vector< bool > systemWriteFsGrid
Definition parameters.h:105
static std::vector< int > systemWriteDistributionWriteYlineStride
Definition parameters.h:94
static std::vector< int > systemWrites
Definition parameters.h:108
static Real ymin
Definition parameters.h:40
static std::vector< Real > systemWriteDistributionWriteShellRadius
Definition parameters.h:100
static std::vector< std::size_t > mlp_arch
Definition parameters.h:257
static std::vector< std::string > systemWritePath
Definition parameters.h:83
static std::vector< std::pair< std::string, std::string > > restartWriteHints
Definition parameters.h:114
static std::vector< int > systemWriteDistributionWriteXlineStride
Definition parameters.h:91
static std::string recoverWritePath
Definition parameters.h:128
static uint ycells_ini
Definition parameters.h:49
static uint xcells_ini
Definition parameters.h:48
static int writeAsFloat
Definition parameters.h:177
static Real xmin
Definition parameters.h:38
static uint64_t vlsvBufferSize
Definition parameters.h:123
static std::string restartFileName
Definition parameters.h:175
static uint fieldSolverSubcycles
Definition parameters.h:69
static ASTERIX_COMPRESSION_METHODS vdf_compression_method
Definition parameters.h:266
static Real t
Definition parameters.h:52
static uint tstep
Definition parameters.h:73
static bool isRestart
Definition parameters.h:176
static std::vector< std::pair< std::string, std::string > > systemWriteHints
Definition parameters.h:110
static Real zmin
Definition parameters.h:42
static Real dy_ini
Definition parameters.h:45
static std::vector< int > systemWriteDistributionWriteStride
Definition parameters.h:86
static std::size_t mlp_fourier_order
Definition parameters.h:258
static bool systemWriteDistributionCompressed
Definition parameters.h:87
static std::vector< std::string > systemWriteName
Definition parameters.h:82
static Real dt
Definition parameters.h:55
std::vector< char > compressed_state_buffer
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)
static ARCH_HOSTDEV VecSimple< T > abs(const VecSimple< T > &l)