Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
vlsvdiff.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
39
40#include <algorithm>
41#include <cmath>
42#include <cstdlib>
43#include <cstring>
44#include <dirent.h>
45#include <exception>
46#include <iomanip>
47#include <iostream>
48#include <limits> // YK
49#include <list>
50#include <set>
51#include <sstream>
52#include <stdint.h>
53#include <string>
54#include <typeinfo>
55
56#include "../definitions.h"
57#include "vlsvreaderinterface.h"
58#include <vlsv_reader.h>
59#include <vlsv_writer.h>
60
61// #include "../ioread.h" //getFsGridDomainDecomposition
62#include <fsgrid.hpp> // computeDomainDecomposition
63
64using namespace std;
65using namespace vlsv;
66
67// Command line option,value pairs are parsed and stored to map attributes.
68// The key is the option name, and the value is the value. For example,
69// "vlsvdiff --meshname=plaa" would cause 'attributes["meshname"]' to be
70// equal to 'plaa'.
71static map<string, string> attributes;
72
73// Global enum and variable
74static int gridName;
80
81static uint64_t convUInt(const char* ptr, const vlsv::datatype::type& dataType, const uint64_t& dataSize) {
82 if (dataType != vlsv::datatype::type::UINT) {
83 cerr << "Erroneous datatype given to convUInt" << endl;
84 exit(1);
85 }
86
87 switch (dataSize) {
88 case 1:
89 return *reinterpret_cast<const unsigned char*>(ptr);
90 break;
91 case 2:
92 return *reinterpret_cast<const unsigned short int*>(ptr);
93 break;
94 case 4:
95 return *reinterpret_cast<const unsigned int*>(ptr);
96 break;
97 case 8:
98 return *reinterpret_cast<const unsigned long int*>(ptr);
99 break;
100 }
101 return 0;
102}
103
111bool copyArray(vlsv::Reader& input, vlsv::Writer& output, const std::string& tagName,
112 const list<pair<string, string>>& inputAttribs, bool optional = false) {
113 bool success = true;
114
115 // Read input array attributes
116 map<string, string> outputAttribs;
117 if (input.getArrayAttributes(tagName, inputAttribs, outputAttribs) == false) {
118
119 if (!optional) {
120 cerr << "ERROR: Failed to read array '" << tagName << "' attributes in " << __FILE__ << ":" << __LINE__ << endl;
121 cerr << "Input attributes are:" << endl;
122 for (list<pair<string, string>>::const_iterator it = inputAttribs.begin(); it != inputAttribs.end(); ++it) {
123 cerr << "\t '" << it->first << "' = '" << it->second << "'" << endl;
124 }
125 return false;
126 } else {
127 // This was an optional parameter, so whatever.
128 return true;
129 }
130 }
131
132 // Figure out arraysize, vectorsize, datasize, and datatype of the copied array
133 map<string, string>::const_iterator it;
134 map<string, string>::iterator it2;
135 it = outputAttribs.find("arraysize");
136 if (it == outputAttribs.end()) return false;
137 uint64_t arraysize = atol(it->second.c_str());
138 it = outputAttribs.find("vectorsize");
139 if (it == outputAttribs.end()) return false;
140 const uint64_t vectorsize = atol(it->second.c_str());
141 it = outputAttribs.find("datasize");
142 if (it == outputAttribs.end()) return false;
143 const uint64_t datasize = atol(it->second.c_str());
144 it = outputAttribs.find("datatype");
145 if (it == outputAttribs.end()) return false;
146 const string datatype = it->second;
147
148 const size_t bytes = arraysize * vectorsize * datasize;
149
150 // Read values from input file
151 char* ptr = new char[bytes];
152 if (input.readArray(tagName, inputAttribs, 0, arraysize, ptr) == false) {
153 cerr << "ERROR: Failed to clone array '" << tagName << "' in " << __FILE__ << ":" << __LINE__ << endl;
154 delete[] ptr;
155 return false;
156 }
157
158 // Write array to output file
159 if (output.writeArray(tagName, outputAttribs, datatype, arraysize, vectorsize, datasize, ptr) == false) {
160 cerr << "ERROR: Failed to write array '" << tagName << "' in " << __FILE__ << ":" << __LINE__ << endl;
161 success = false;
162 }
163
164 delete[] ptr;
165 ptr = NULL;
166 return success;
167}
168
169/* Small function that overrides how fsgrid diff files are written*/
170bool HandleFsGrid(const string& inputFileName, vlsv::Writer& output, std::map<uint, Real> orderedData) {
171
172 // Open input file
173 vlsv::Reader input;
174 if (input.open(inputFileName) == false) {
175 cerr << "ERROR failed to open input file '" << inputFileName << "' in " << __FILE__ << ":" << __LINE__ << endl;
176 return false;
177 }
178
179 // Read Mesh Attributes
180 std::string tagName = "MESH";
181 list<pair<string, string>> inputAttribs;
182 inputAttribs.push_back(make_pair("name", "fsgrid"));
183 map<string, string> outputAttribs;
184
185 if (input.getArrayAttributes(tagName, inputAttribs, outputAttribs) == false) {
186 cerr << "ERROR: Failed to read array '" << tagName << "' attributes in " << __FILE__ << ":" << __LINE__ << endl;
187 cerr << "Input attributes are:" << endl;
188 for (list<pair<string, string>>::const_iterator it = inputAttribs.begin(); it != inputAttribs.end(); ++it) {
189 cerr << "\t '" << it->first << "' = '" << it->second << "'" << endl;
190 }
191 return false;
192 }
193
194 // Collect needed attributes to a map named patch
195 map<string, string>::const_iterator it;
196 it = outputAttribs.find("arraysize");
197 if (it == outputAttribs.end()) return false;
198 uint64_t arraysize = atol(it->second.c_str());
199 it = outputAttribs.find("vectorsize");
200 if (it == outputAttribs.end()) return false;
201 const uint64_t vectorsize = atol(it->second.c_str());
202 it = outputAttribs.find("datasize");
203 if (it == outputAttribs.end()) return false;
204 const uint64_t datasize = atol(it->second.c_str());
205 it = outputAttribs.find("datatype");
206 if (it == outputAttribs.end()) return false;
207 const string datatype = it->second;
208 it = outputAttribs.find("xperiodic");
209 if (it == outputAttribs.end()) return false;
210 const string xperiodic = it->second;
211 it = outputAttribs.find("yperiodic");
212 if (it == outputAttribs.end()) return false;
213 const string yperiodic = it->second;
214 it = outputAttribs.find("zperiodic");
215 if (it == outputAttribs.end())
216 return false;
217 const string zperiodic = it->second;
218 it = outputAttribs.find("type");
219 if (it == outputAttribs.end())
220 return false;
221 const string type = it->second;
222
223 map<string, string> patch;
224 patch["arraysize"] = std::to_string(arraysize);
225 patch["datasize"] = std::to_string(datasize);
226 patch["datatype"] = datatype;
227 patch["name"] = "fsgrid";
228 patch["type"] = type;
229 patch["vectorsize"] = std::to_string(vectorsize);
230 patch["xperiodic"] = xperiodic;
231 patch["yperiodic"] = yperiodic;
232 patch["zperiodic"] = zperiodic;
233
234 // Get the global IDs in a vector
235 std::vector<uint64_t> globalIds;
236 for (const auto iter : orderedData) {
237 globalIds.push_back(iter.first);
238 }
239
240 // Write to file
241 output.writeArray("MESH", patch, arraysize, 1, &globalIds[0]);
242
243 std::array<int, 1> numWritingRanks = {1};
244 output.writeParameter("numWritingRanks", &numWritingRanks[0]);
245
246 // Save the FSgrid decomposition
247 std::map<std::string, std::string> xmlAttributes;
248 const std::string meshName = "fsgrid";
249 xmlAttributes["mesh"] = meshName;
250 std::array<fsgrid::Task_t, 3> decom = {1, 1, 1};
251 output.writeArray("MESH_DECOMPOSITION", outputAttribs, 3u, 1u, &decom[0]);
252
253 // Now for MESH_DOMAIN_SIZES
254 inputAttribs.clear();
255 inputAttribs.push_back(make_pair("mesh", "fsgrid"));
256 tagName = "MESH_DOMAIN_SIZES";
257
258 if (input.getArrayAttributes(tagName, inputAttribs, outputAttribs) == false) {
259 cerr << "ERROR: Failed to read array '" << tagName << "' attributes in " << __FILE__ << ":" << __LINE__ << endl;
260 cerr << "Input attributes are:" << endl;
261 for (list<pair<string, string>>::const_iterator it = inputAttribs.begin(); it != inputAttribs.end(); ++it) {
262 cerr << "\t '" << it->first << "' = '" << it->second << "'" << endl;
263 }
264 return false;
265 }
266
267 // Read some attributes we need and parse to our map
268 it = outputAttribs.find("datasize");
269 if (it == outputAttribs.end()) return false;
270 const uint64_t datasize2 = atol(it->second.c_str());
271 it = outputAttribs.find("datatype");
272 if (it == outputAttribs.end()) return false;
273 const string datatype2 = it->second;
274 it = outputAttribs.find("vectorsize");
275 if (it == outputAttribs.end()) return false;
276 const uint64_t vectorsize2 = atol(it->second.c_str());
277
278 patch.clear();
279 patch["arraysize"] = "1";
280 patch["datasize"] = to_string(datasize2);
281 patch["datatype"] = datatype2;
282 patch["mesh"] = "fsgrid";
283 patch["vectorsize"] = to_string(vectorsize2);
284
285 // Override MESH_DOMAIN_SIZES
286 std::array<uint64_t, 2> meshDomainSize({globalIds.size(), 0});
287 output.writeArray("MESH_DOMAIN_SIZES", patch, 1, vectorsize2, &meshDomainSize[0]);
288
289 // Close the file
290 input.close();
291
292 return true;
293}
294
295bool getFsgridDecomposition(vlsvinterface::Reader& file, std::array<int, 3>& decomposition) {
296 uint64_t arraySize;
297 uint64_t vectorSize;
298 vlsv::datatype::type dataType;
299 uint64_t byteSize;
300
301 list<pair<string, string>> attribs;
302 attribs.push_back(make_pair("mesh", "fsgrid"));
303
304 std::array<fsgrid::Task_t, 3> fsGridDecomposition = {0, 0, 0};
305 int* ptr = &fsGridDecomposition[0];
306
307 // Check if array exists:
308 bool success = file.getArrayInfo("MESH_DECOMPOSITION", attribs, arraySize, vectorSize, dataType, byteSize);
309 if (success == false) {
310 // std::cout << "Could not read MESH_DECOMPOSITION" << endl;
311 // std::cerr << "ptr " << fsGridDecomposition[0] <<" "<< fsGridDecomposition[1] << " " <<
312 // fsGridDecomposition[2]<<"\n"; std::cerr << "No decomposition found in restart file. Computing fsgrid
313 // decomposition for ioread, check results!" <<std::endl;
314
315 int fsgridInputRanks = 0;
316 if (file.readParameter("numWritingRanks", fsgridInputRanks) == false) {
317 std::cerr << "FSGrid writing rank number not found in restart file" << endl;
318 exit(1);
319 }
320 std::array<fsgrid::FsSize_t, 3> gridSize;
321 fsgrid::FsSize_t* gridSizePtr = &gridSize[0];
322 success = file.read("MESH_BBOX", attribs, 0, 3, gridSizePtr, false);
323 if (success == false) {
324 std::cerr << "Could not read MESH_BBOX from file" << endl;
325 exit(1);
326 }
327 int64_t* domainInfo = NULL;
328 success = file.read("MESH_DOMAIN_SIZES", attribs, 0, fsgridInputRanks, domainInfo);
329 if (success == false) {
330 std::cerr << "Could not read MESH_DOMAIN_SIZES from file" << endl;
331 exit(1);
332 }
333 std::vector<uint64_t> mesh_domain_sizes;
334 for (int i = 0; i < 2 * fsgridInputRanks; i += 2) {
335 mesh_domain_sizes.push_back(domainInfo[i]);
336 }
337 list<pair<string, string>> mesh_attribs;
338 mesh_attribs.push_back(make_pair("name", "fsgrid"));
339 std::vector<fsgrid::FsSize_t> rank_first_ids(fsgridInputRanks);
340 fsgrid::FsSize_t* ids_ptr = &rank_first_ids[0];
341
342 std::set<fsgrid::FsIndex_t> x_corners, y_corners, z_corners;
343
344 int64_t begin_rank = 0;
345 int i = 0;
346 for (auto rank_size : mesh_domain_sizes) {
347 if (file.read("MESH", mesh_attribs, begin_rank, 1, ids_ptr, false) == false) {
348 std::cerr << "Reading MESH failed.\n";
349 exit(1);
350 }
351 std::array<fsgrid::FsIndex_t, 3> inds = fsgrid::globalIDtoCellCoord(*ids_ptr, gridSize);
352 x_corners.insert(inds[0]);
353 y_corners.insert(inds[1]);
354 z_corners.insert(inds[2]);
355 ++ids_ptr;
356 begin_rank += rank_size;
357 }
358
359 decomposition[0] = x_corners.size();
360 decomposition[1] = y_corners.size();
361 decomposition[2] = z_corners.size();
362 std::cout << "Fsgrid decomposition computed from MESH to be " << decomposition[0] << " " << decomposition[1] << " " << decomposition[2] << endl;
363
364 return true;
365 } else {
366 // data exists, now read it
367 success = file.read("MESH_DECOMPOSITION", attribs, 0, 3, ptr, false);
368 decomposition[0] = fsGridDecomposition[0];
369 decomposition[1] = fsGridDecomposition[1];
370 decomposition[2] = fsGridDecomposition[2];
371 std::cout << "Fsgrid decomposition read as " << decomposition[0] << " " << decomposition[1] << " " << decomposition[2] << endl;
372 return true;
373 }
374
375 return false;
376}
377
383bool cloneMesh(const string& inputFileName, vlsv::Writer& output, const string& meshName,
384 std::map<uint, Real> orderedData) {
385 bool success = true;
386
387 vlsv::Reader input;
388 if (input.open(inputFileName) == false) {
389 cerr << "ERROR failed to open input file '" << inputFileName << "' in " << __FILE__ << ":" << __LINE__ << endl;
390 return false;
391 }
392
393 list<pair<string, string>> inputAttribs;
394 inputAttribs.push_back(make_pair("name", meshName));
395 inputAttribs.clear();
396 inputAttribs.push_back(make_pair("mesh", meshName));
397 if (copyArray(input, output, "MESH_BBOX", inputAttribs) == false) success = false;
398
399 // Mesh have either individual coordinate arrays (for cartesian geometries)...
400 if (copyArray(input, output, "MESH_NODE_CRDS_X", inputAttribs, meshName == "ionosphere") == false) success = false;
401 if (copyArray(input, output, "MESH_NODE_CRDS_Y", inputAttribs, meshName == "ionosphere") == false) success = false;
402 if (copyArray(input, output, "MESH_NODE_CRDS_Z", inputAttribs, meshName == "ionosphere") == false) success = false;
403
404 // Or they have per-node coordinate arrays (for unstructured meshes)
405 if (copyArray(input, output, "MESH_NODE_CRDS", inputAttribs, meshName != "ionosphere") == false) success = false;
406 if (copyArray(input, output, "MESH_OFFSETS", inputAttribs, meshName != "ionosphere") == false) success = false;
407
408 if (copyArray(input, output, "MESH_GHOST_LOCALIDS", inputAttribs, meshName == "ionosphere") == false) success = false;
409 if (copyArray(input, output, "MESH_GHOST_DOMAINS", inputAttribs, meshName == "ionosphere") == false) success = false;
410
411 // Only do this if we diff SpatialGrid data
413 if (copyArray(input, output, "MESH_DOMAIN_SIZES", inputAttribs) == false) success = false;
414
415 inputAttribs.clear();
416 inputAttribs.push_back(make_pair("name", meshName));
417 if (copyArray(input, output, "MESH", inputAttribs) == false) success = false;
418 } else {
419 HandleFsGrid(inputFileName, output, orderedData);
420 }
421
422 input.close();
423 return success;
424}
425
433bool convertMesh(vlsvinterface::Reader& vlsvReader, const string& meshName, const char* varToExtract,
434 const uint compToExtract, map<uint, Real>* orderedData, unordered_map<size_t, size_t>& cellOrder,
435 const bool& storeCellOrder) {
436
437 // Check for null pointer:
438 if (!varToExtract || !orderedData) {
439 cerr << "ERROR, PASSED A NULL POINTER AT " << __FILE__ << " " << __LINE__ << endl;
440 return false;
441 }
442 bool meshSuccess = true;
443 bool variableSuccess = true;
444
445 datatype::type meshDataType;
446 datatype::type variableDataType;
447 uint64_t meshArraySize, meshVectorSize, meshDataSize;
448 uint64_t variableArraySize, variableVectorSize, variableDataSize;
449
450 list<pair<string, string>> variableAttributes;
451 const string _varToExtract(varToExtract);
452 variableAttributes.push_back(make_pair("mesh", meshName));
453 variableAttributes.push_back(make_pair("name", _varToExtract));
454 // Read in array size, vector size, data type and data size of the array "VARIABLE" in the vlsv file (Needed in
455 // reading the array)
456 if (vlsvReader.getArrayInfo("VARIABLE", variableAttributes, variableArraySize, variableVectorSize, variableDataType,
457 variableDataSize) == false) {
458 cerr << "ERROR, failed to get array info for '" << _varToExtract << "' on mesh '" << meshName << "' at " << __FILE__ << " " << __LINE__ << endl;
459 return false;
460 }
461
462 switch (gridName) {
464 std::vector<char> variableBuffer(variableVectorSize * variableDataSize);
465 float* variablePtrFloat = reinterpret_cast<float*>(variableBuffer.data());
466 double* variablePtrDouble = reinterpret_cast<double*>(variableBuffer.data());
467 uint* variablePtrUint = reinterpret_cast<uint*>(variableBuffer.data());
468 int* variablePtrInt = reinterpret_cast<int*>(variableBuffer.data());
469
470 // Read the mesh array one node (of a spatial cell) at a time
471 // and create a map which contains each cell's CellID and variable to be extracted
472 // Get local cell ids:
473 vector<uint64_t> local_cells;
474 if (vlsvReader.getCellIds(local_cells, meshName) == false) {
475 cerr << "Failed to read cell ids at " << __FILE__ << " " << __LINE__ << endl;
476 return false;
477 }
478
479 // Check for correct output:
480 if (local_cells.size() != variableArraySize) {
481 cerr << "ERROR array size mismatch: " << local_cells.size() << " " << variableArraySize << endl;
482 }
483 if (compToExtract + 1 > variableVectorSize) {
484 cerr << "ERROR invalid component, this variable has size " << variableVectorSize << endl;
485 abort();
486 }
487
488 if (storeCellOrder == true) {
489 cellOrder.clear();
490 }
491
492 orderedData->clear();
493
494 for (uint64_t i = 0; i < local_cells.size(); ++i) {
495 const short int amountToReadIn = 1;
496 const uint64_t& startingReadIndex = i;
497 if (vlsvReader.readArray("VARIABLE", variableAttributes, startingReadIndex, amountToReadIn,
498 variableBuffer.data()) == false) {
499 cerr << "ERROR, failed to read variable '" << _varToExtract << "' at " << __FILE__ << " " << __LINE__ << endl;
500 variableSuccess = false;
501 break;
502 }
503 // Get the CellID
504 uint64_t& CellID = local_cells[i];
505
506 // Get the variable value
507 Real extract = NAN;
508
509 switch (variableDataType) {
510 case datatype::type::FLOAT:
511 if (variableDataSize == sizeof(float)) extract = (Real)(variablePtrFloat[compToExtract]);
512 if (variableDataSize == sizeof(double)) extract = (Real)(variablePtrDouble[compToExtract]);
513 break;
514 case datatype::type::UINT:
515 extract = (Real)(variablePtrUint[compToExtract]);
516 break;
517 case datatype::type::INT:
518 extract = (Real)(variablePtrInt[compToExtract]);
519 break;
520 case datatype::type::UNKNOWN:
521 cerr << "ERROR, BAD DATATYPE AT " << __FILE__ << " " << __LINE__ << endl;
522 break;
523 }
524 // Put those into the map
525 orderedData->insert(pair<uint64_t, Real>(CellID, extract));
526 if (storeCellOrder == true) {
527 cellOrder[CellID] = i;
528 }
529 }
530 } break;
531
532 case GridType::FSGRID:
533
534 {
535 // Get Spatial Grid's max refinement Level
536 int maxRefLevel = 0;
537 list<pair<string, string>> meshAttributesIn;
538 meshAttributesIn.push_back(make_pair("name", "SpatialGrid"));
539 map<string, string> meshAttributesOut;
540 if (vlsvReader.getArrayAttributes("MESH", meshAttributesIn, meshAttributesOut) == false) {
541 cerr << "ERROR, failed to get array info for '" << _varToExtract << "' at " << __FILE__ << " " << __LINE__ << endl;
542 return false;
543 }
544
545 std::map<string, string>::iterator attributesOutIt;
546 attributesOutIt = meshAttributesOut.find("max_refinement_level");
547 if (attributesOutIt != meshAttributesOut.end()) {
548 maxRefLevel = stoi(attributesOutIt->second);
549 }
550 int numtasks;
551 int xcells, ycells, zcells;
552 vlsvReader.readParameter("numWritingRanks", numtasks);
553 vlsvReader.readParameter("xcells_ini", xcells);
554 vlsvReader.readParameter("ycells_ini", ycells);
555 vlsvReader.readParameter("zcells_ini", zcells);
556 xcells *= pow(2, maxRefLevel);
557 ycells *= pow(2, maxRefLevel);
558 zcells *= pow(2, maxRefLevel);
559 std::array<int, 3> GlobalBox = {xcells, ycells, zcells};
560 std::array<int, 3> thisDomainDecomp;
561
562 // Compute Domain Decomposition Scheme for this vlsv file
563 // fsgrid::computeDomainDecomposition(GlobalBox,numtasks,thisDomainDecomp);
564 getFsgridDecomposition(vlsvReader, thisDomainDecomp);
565
566 std::array<int32_t, 3> taskSize, taskStart;
567 std::array<int32_t, 3> taskEnd;
568 int readOffset = 0;
569 int index, my_x, my_y, my_z;
570 orderedData->clear();
571
572 for (int task = 0; task < numtasks; task++) {
573
574 my_x = task / thisDomainDecomp[2] / thisDomainDecomp[1];
575 my_y = (task / thisDomainDecomp[2]) % thisDomainDecomp[1];
576 my_z = task % thisDomainDecomp[2];
577
578 taskStart[0] = fsgrid::calcLocalStart(GlobalBox[0], thisDomainDecomp[0], my_x);
579 taskStart[1] = fsgrid::calcLocalStart(GlobalBox[1], thisDomainDecomp[1], my_y);
580 taskStart[2] = fsgrid::calcLocalStart(GlobalBox[2], thisDomainDecomp[2], my_z);
581
582 taskSize[0] = fsgrid::calcLocalSize(GlobalBox[0], thisDomainDecomp[0], my_x);
583 taskSize[1] = fsgrid::calcLocalSize(GlobalBox[1], thisDomainDecomp[1], my_y);
584 taskSize[2] = fsgrid::calcLocalSize(GlobalBox[2], thisDomainDecomp[2], my_z);
585
586 taskEnd[0] = taskStart[0] + taskSize[0];
587 taskEnd[1] = taskStart[1] + taskSize[1];
588 taskEnd[2] = taskStart[2] + taskSize[2];
589
590 int64_t readSize = taskSize[0] * taskSize[1] * taskSize[2];
591 // Allocate vector for reading
592 std::vector<Real> buffer(readSize * variableVectorSize);
593
594 if (variableDataSize == sizeof(Real)) {
595 if (vlsvReader.readArray("VARIABLE", variableAttributes, readOffset, readSize, (char*)buffer.data()) ==
596 false) {
597 cerr << "ERROR, failed to read variable '" << _varToExtract << "' at " << __FILE__ << " " << __LINE__ << endl;
598 variableSuccess = false;
599 break;
600 }
601 } else {
602 std::vector<float> tmpbuffer(readSize * variableVectorSize);
603 if (vlsvReader.readArray("VARIABLE", variableAttributes, readOffset, readSize, (char*)tmpbuffer.data()) ==
604 false) {
605 cerr << "ERROR, failed to read variable '" << _varToExtract << "' at " << __FILE__ << " " << __LINE__ << endl;
606 variableSuccess = false;
607 break;
608 }
609 for (unsigned int i = 0; i < readSize * variableVectorSize; i++) {
610 buffer[i] = tmpbuffer[i];
611 }
612 }
613
614 uint64_t globalindex, counter = 0;
615 ;
616 for (int z = taskStart[2]; z < taskEnd[2]; z++) {
617 for (int y = taskStart[1]; y < taskEnd[1]; y++) {
618 for (int x = taskStart[0]; x < taskEnd[0]; x++) {
619 globalindex = x + y * xcells + z * xcells * ycells;
620 Real data;
621 switch (variableDataType) {
622 case datatype::type::FLOAT:
623 if (variableDataSize == sizeof(float))
624 memcpy(&data, &buffer[counter + compToExtract], sizeof(float));
625 if (variableDataSize == sizeof(double))
626 memcpy(&data, &buffer[counter + compToExtract], sizeof(double));
627 break;
628 case datatype::type::UINT:
629 memcpy(&data, &buffer[counter + compToExtract], sizeof(uint));
630 break;
631 case datatype::type::INT:
632 memcpy(&data, &buffer[counter + compToExtract], sizeof(int));
633 break;
634 case datatype::type::UNKNOWN:
635 cerr << "ERROR, BAD DATATYPE AT " << __FILE__ << " " << __LINE__ << endl;
636 break;
637 }
638 // Add to map
639 orderedData->insert(pair<uint64_t, Real>(globalindex, data));
640 counter += variableVectorSize;
641 }
642 }
643 }
644 readOffset += readSize;
645 }
646 } break;
647
649
650 if (compToExtract >= variableVectorSize) {
651 cerr << "ERROR invalid component, this variable has size " << variableVectorSize << endl;
652 abort();
653 }
654 orderedData->clear();
655
656 switch (variableDataType) {
657 case datatype::type::FLOAT: {
658 if (variableDataSize == sizeof(double)) {
659 std::vector<double> buffer(variableVectorSize * variableArraySize);
660 // The mesh is simply one big blob that can be read in one go.
661 if (vlsvReader.readArray("VARIABLE", variableAttributes, 0, variableArraySize, (char*)buffer.data()) ==
662 false) {
663 cerr << "ERROR, failed to read variable '" << _varToExtract << "' at " << __FILE__ << " " << __LINE__ << endl;
664 variableSuccess = false;
665 break;
666 }
667
668 for (unsigned int i = 0; i < variableArraySize; i++) {
669 orderedData->insert(pair<uint64_t, Real>(i, buffer[i * variableVectorSize + compToExtract]));
670 }
671 } else if (variableDataSize == sizeof(float)) {
672 std::vector<double> buffer(variableVectorSize * variableArraySize);
673 // The mesh is simply one big blob that can be read in one go.
674 if (vlsvReader.readArray("VARIABLE", variableAttributes, 0, variableArraySize, (char*)buffer.data()) ==
675 false) {
676 cerr << "ERROR, failed to read variable '" << _varToExtract << "' at " << __FILE__ << " " << __LINE__ << endl;
677 variableSuccess = false;
678 break;
679 }
680
681 for (unsigned int i = 0; i < variableArraySize; i++) {
682 orderedData->insert(pair<uint64_t, Real>(i, buffer[i * variableVectorSize + compToExtract]));
683 }
684 }
685 } break;
686 default:
687 cerr << "Error: No support for ionosphere parameters that are not float-valued implemented, at " << __FILE__ << " " << __LINE__ << endl;
688 break;
689 }
690
691 break;
692 default:
693 cerr << "meshName not recognized\t" << __FILE__ << " " << __LINE__ << endl;
694 abort();
695 }
696
697 if (meshSuccess == false) {
698 cerr << "ERROR reading array MESH" << endl;
699 }
700 if (variableSuccess == false) {
701 cerr << "ERROR reading array VARIABLE " << varToExtract << endl;
702 }
703 return meshSuccess && variableSuccess;
704}
705
713template <class T>
714bool convertSILO(const string fileName, const char* varToExtract, const uint compToExtract,
715 map<uint, Real>* orderedData, unordered_map<size_t, size_t>& cellOrder, Real& time,
716 const bool& storeCellOrder = false) {
717 bool success = true;
718
719 // Open VLSV file for reading:
720 T vlsvReader;
721
722 if (vlsvReader.open(fileName) == false) {
723 cerr << "Failed to open '" << fileName << "'" << endl;
724 cerr << "VLSV error " << vlsvReader.getErrorString() << endl;
725 return false;
726 }
727
728 // Get the names of all meshes in vlsv file
729 list<string> meshNames;
730 if (vlsvReader.getMeshNames(meshNames) == false) {
731 cerr << "Failed to read mesh names" << endl;
732 exit(1);
733 }
734
735 // Clear old data
736 orderedData->clear();
737
738 for (list<string>::const_iterator it = meshNames.begin(); it != meshNames.end(); ++it) {
739 if (*it != attributes["--meshname"]) continue;
740
741 if (convertMesh(vlsvReader, *it, varToExtract, compToExtract, orderedData, cellOrder, storeCellOrder) == false) {
742 return false;
743 }
744 }
745
746 vlsvReader.readParameter("time", time);
747
748 vlsvReader.close();
749 return success;
750}
751
757bool shiftAverage(const map<uint, Real>* const orderedData1, const map<uint, Real>* const orderedData2,
758 map<uint, Real>* shiftedData2) {
759 map<uint, Real>::const_iterator it1, it2;
760 Real avg1 = 0.0;
761 Real avg2 = 0.0;
762
763 for (it1 = orderedData1->begin(), it2 = orderedData2->begin();
764 it1 != orderedData1->end(), it2 != orderedData2->end(); it1++, it2++) {
765 avg1 += orderedData1->at(it1->first);
766 avg2 += orderedData2->at(it2->first);
767 }
768 avg1 /= orderedData1->size();
769 avg2 /= orderedData1->size();
770
771 for (it2 = orderedData2->begin(); it2 != orderedData2->end(); it2++) {
772 shiftedData2->insert(pair<uint, Real>(it2->first, it2->second - avg2 + avg1));
773 }
774
775 return 0;
776}
777
810bool pDistance(const map<uint, Real>& orderedData1, const map<uint, Real>& orderedData2, creal p, Real* absolute,
811 Real* relative, const bool doShiftAverage, const unordered_map<size_t, size_t>& cellOrder,
812 vlsv::Writer& outputFile, const std::string& meshName, const std::string& varName) {
813 map<uint, Real> shiftedData2;
814 map<uint, Real>* data2 = const_cast<map<uint, Real>*>(&orderedData2);
815
816 if (doShiftAverage == true) {
817 shiftAverage(&orderedData1, &orderedData2, &shiftedData2);
818 data2 = &shiftedData2;
819 }
820
821 // Reset old values
822 *absolute = 0.0;
823 *relative = 0.0;
824
825 vector<Real> array(orderedData1.size());
826 for (size_t i = 0; i < array.size(); ++i)
827 array[i] = -1.0;
828
829 Real length = 0.0;
830 if (p == 0) {
831 for (map<uint, Real>::const_iterator it1 = orderedData1.begin(); it1 != orderedData1.end(); ++it1) {
832 map<uint, Real>::const_iterator it2 = data2->find(it1->first);
833 Real value = 0.0;
834 if (it2 != data2->end()) {
835 value = abs(it1->second - it2->second);
836 *absolute = max(*absolute, value);
837 length = max(length, abs(it1->second));
838 }
840 array[cellOrder.at(it1->first)] = value;
842 array.at(it1->first) = value;
843 }
844 }
845 } else if (p == 1) {
846 for (map<uint, Real>::const_iterator it1 = orderedData1.begin(); it1 != orderedData1.end(); ++it1) {
847 map<uint, Real>::const_iterator it2 = data2->find(it1->first);
848 Real value = 0.0;
849 if (it2 != data2->end()) {
850 value = abs(it1->second - it2->second);
851 *absolute += value;
852 length += abs(it1->second);
853 }
855 array[cellOrder.at(it1->first)] = value;
857 array[it1->first] = value;
858 }
859 }
860 } else {
861 for (map<uint, Real>::const_iterator it1 = orderedData1.begin(); it1 != orderedData1.end(); ++it1) {
862 map<uint, Real>::const_iterator it2 = data2->find(it1->first);
863 Real value = 0.0;
864 if (it2 != data2->end()) {
865 value = pow(abs(it1->second - it2->second), p);
866 *absolute += value;
867 length += pow(abs(it1->second), p);
868 }
870 array[cellOrder.at(it1->first)] = pow(value, 1.0 / p);
872 array[it1->first] = pow(value, 1.0 / p);
873 }
874 }
875 *absolute = pow(*absolute, 1.0 / p);
876 length = pow(length, 1.0 / p);
877 }
878
879 if (length != 0.0)
880 *relative = *absolute / length;
881 else {
882 cout << "WARNING (pDistance) : length of reference is 0.0, cannot divide to give relative distance." << endl;
883 *relative = -1;
884 }
885
886 // Write out the difference (if requested):
887 if (attributes.find("--diff") != attributes.end()) {
888 map<string, string> attributes;
889 attributes["mesh"] = meshName;
890 attributes["name"] = varName;
891 if (meshName == "ionosphere") {
892 attributes["centering"] = "node";
893 }
894
895 if (outputFile.writeArray("VARIABLE", attributes, array.size(), 1, &(array[0])) == false) {
896 cerr << "ERROR failed to write variable '" << varName << "' to output file in " << __FILE__ << ":" << __LINE__ << endl;
897 return 1;
898 }
899 }
900
901 return 0;
902}
903
913bool outputDistance(const Real p, const Real* absolute, const Real* relative, const bool shiftedAverage,
914 const bool verboseOutput, const bool lastCall) {
915 if (verboseOutput == true) {
916 if (shiftedAverage == false) {
917 cout << "The absolute " << p << "-distance between both datasets is " << setprecision(3) << *absolute << endl;
918 cout << "The relative " << p << "-distance between both datasets is " << setprecision(3) << *relative << endl;
919 } else {
920 cout << "The average-shifted absolute " << p << "-distance between both datasets is " << setprecision(3) << *absolute << endl;
921 cout << "The average-shifted relative " << p << "-distance between both datasets is " << setprecision(3) << *relative << endl;
922 }
923 } else {
924 static vector<Real> fileOutputData;
925 static uint fileNumber = 0;
926
927 if (lastCall == true) {
928 vector<Real>::const_iterator it;
929 for (it = fileOutputData.begin(); it != fileOutputData.end(); it++) {
930 cout << setprecision(3) << *it << "\t";
931 }
932 fileOutputData.clear();
933 return 0;
934 }
935
936 fileOutputData.push_back(*absolute);
937 fileOutputData.push_back(*relative);
938 }
939 return 0;
940}
941
947bool outputDt(const Real dt, const bool verboseOutput, const bool lastCall) {
948 if (verboseOutput == true) {
949 cout << "The delta t between both datasets is " << dt << endl;
950 } else {
951 static vector<Real> fileOutputData;
952 static uint fileNumber = 0;
953
954 if (lastCall == true) {
955 vector<Real>::const_iterator it;
956 for (auto f : fileOutputData) {
957 cout << f << "\t";
958 }
959 fileOutputData.clear();
960 return 0;
961 }
962
963 fileOutputData.push_back(dt);
964 }
965 return 0;
966}
967
975bool singleStatistics(map<uint, Real>* orderedData, Real* size, Real* mini, Real* maxi, Real* avg, Real* stdev) {
976 /*
977 * Returns basic statistics on the map passed to it.
978 */
979 map<uint, Real>::const_iterator it;
980
981 *size = orderedData->size();
982 *mini = numeric_limits<Real>::max();
983 *maxi = numeric_limits<Real>::min();
984 *avg = 0.0;
985 *stdev = 0.0;
986
987 for (it = orderedData->begin(); it != orderedData->end(); it++) {
988 *mini = min(*mini, orderedData->at(it->first));
989 *maxi = max(*maxi, orderedData->at(it->first));
990 *avg += orderedData->at(it->first);
991 }
992 *avg /= *size;
993 for (it = orderedData->begin(); it != orderedData->end(); it++) {
994 *stdev += pow(orderedData->at(it->first) - *avg, 2.0);
995 }
996 *stdev = sqrt(*stdev);
997 *stdev /= (*size - 1);
998 return 0;
999}
1000
1011bool outputStats(const Real* size, const Real* mini, const Real* maxi, const Real* avg, const Real* stdev,
1012 const bool verboseOutput, const bool lastCall) {
1013 if (verboseOutput == true) {
1014 cout << "Statistics on file: size " << *size << " min = " << *mini << " max = " << *maxi << " average = " << *avg
1015 << " standard deviation " << *stdev << endl;
1016 } else {
1017 static uint fileNumber = 0;
1018 static vector<Real> pairStats;
1019
1020 if (lastCall == true) {
1021 vector<Real>::const_iterator it;
1022 for (it = pairStats.begin(); it != pairStats.end(); it++) {
1023 cout << *it << "\t";
1024 }
1025 pairStats.clear();
1026 return 0;
1027 }
1028
1029 if (fileNumber % 2 == 0) {
1030 pairStats.push_back(fileNumber / 2 + 1);
1031 }
1032 pairStats.push_back(*size);
1033 pairStats.push_back(*mini);
1034 pairStats.push_back(*maxi);
1035 pairStats.push_back(*avg);
1036 pairStats.push_back(*stdev);
1037 fileNumber++;
1038 }
1039 return 0;
1040}
1041
1046 static bool header = true;
1047 if (header == true) {
1048 // Key to contents
1049 cout << "#1 File number in folder\n"
1050 << "#2 File 1 size\n"
1051 << "#3 File 1 min\n"
1052 << "#4 File 1 max\n"
1053 << "#5 File 1 average\n"
1054 << "#6 File 1 standard deviation\n"
1055 << "#7 File 2 size\n"
1056 << "#8 File 2 min\n"
1057 << "#9 File 2 max\n"
1058 << "#10 File 2 average\n"
1059 << "#11 File 2 standard deviation\n"
1060 << "#12 absolute infinity-distance\n"
1061 << "#13 relative infinity-distance\n"
1062 << "#14 absolute average-shifted infinity-distance\n"
1063 << "#15 relative average-shifted infinity-distance\n"
1064 << "#16 absolute 1-distance\n"
1065 << "#17 relative 1-distance\n"
1066 << "#18 absolute average-shifted 1-distance\n"
1067 << "#19 relative average-shifted 1-distance\n"
1068 << "#20 absolute 2-distance\n"
1069 << "#21 relative 2-distance\n"
1070 << "#22 absolute average-shifted 2-distance\n"
1071 << "#23 relative average-shifted 2-distance\n"
1072 << endl;
1073 header = false;
1074 }
1075
1076 // Data
1077 // last argument (lastCall) is true to get the output of the whole stored dataset
1078 outputStats(NULL, NULL, NULL, NULL, NULL, false, true);
1079 outputDistance(0, NULL, NULL, false, false, true);
1080 outputDt(0, false, true);
1081
1082 return 0;
1083}
1084
1086 const unordered_map<uint64_t, pair<uint64_t, uint32_t>>& cellsWithBlocksLocations,
1087 const uint64_t& cellId, vector<uint32_t>& blockIds) {
1088 // Read the block ids:
1089 // Check if the cell id can be found:
1090 unordered_map<uint64_t, pair<uint64_t, uint32_t>>::const_iterator it = cellsWithBlocksLocations.find(cellId);
1091 if (it == cellsWithBlocksLocations.end()) {
1092 cerr << "COULDNT FIND CELL ID " << cellId << " AT " << __FILE__ << " " << __LINE__ << endl;
1093 return false;
1094 }
1095 // Get offset and number of blocks:
1096 pair<uint64_t, uint32_t> offsetAndBlocks = it->second;
1097 const uint64_t blockOffset = get<0>(offsetAndBlocks);
1098 const uint32_t N_blocks = get<1>(offsetAndBlocks);
1099
1100 // Get some required info from VLSV file:
1101 list<pair<string, string>> attribs;
1102 attribs.push_back(make_pair("mesh", attributes["--meshname"]));
1103
1104 // READ BLOCK IDS:
1105 uint64_t blockIds_arraySize, blockIds_vectorSize, blockIds_dataSize;
1106 vlsv::datatype::type blockIds_dataType;
1107 // Input blockIds_arraySize, blockIds_vectorSize, blockIds_dataSize blockIds_dataType: (Returns false if fails)
1108 if (vlsvReader.getArrayInfo("BLOCKIDS", attribs, blockIds_arraySize, blockIds_vectorSize, blockIds_dataType,
1109 blockIds_dataSize) == false) {
1110 cerr << "ERROR, COULD NOT FIND BLOCKIDS AT " << __FILE__ << " " << __LINE__ << endl;
1111 return false;
1112 }
1113 // Make sure blockid's datatype is correct:
1114 if (blockIds_dataType != vlsv::datatype::type::UINT) {
1115 cerr << "ERROR, bad datatype at " << __FILE__ << " " << __LINE__ << endl;
1116 return false;
1117 }
1118 // Create buffer for reading in data: (Note: arraySize, vectorSize, etc were fetched from getArrayInfo)
1119 char* blockIds_buffer = new char[N_blocks * blockIds_vectorSize * blockIds_dataSize];
1120 // Read the data into the buffer:
1121 if (vlsvReader.readArray("BLOCKIDS", attribs, blockOffset, N_blocks, blockIds_buffer) == false) {
1122 cerr << "ERROR, FAILED TO READ BLOCKIDS AT " << __FILE__ << " " << __LINE__ << endl;
1123 delete[] blockIds_buffer;
1124 return false;
1125 }
1126 // Input the block ids:
1127 blockIds.reserve(N_blocks);
1128 for (uint64_t i = 0; i < N_blocks; ++i) {
1129 const uint64_t blockId = convUInt(blockIds_buffer + i * blockIds_dataSize, blockIds_dataType, blockIds_dataSize);
1130 blockIds.push_back((uint32_t)(blockId));
1131 }
1132 delete[] blockIds_buffer;
1133 return true;
1134}
1135
1136uint32_t getBlockId(const double vx, const double vy, const double vz, const double dvx, const double dvy,
1137 const double dvz, const double vx_min, const double vy_min, const double vz_min,
1138 const double vx_length, const double vy_length, const double vz_length) {
1139
1140 const array<unsigned int, 3> indices{{(unsigned int)floor((vx - vx_min) / (double)(dvx * 4)),
1141 (unsigned int)floor((vy - vy_min) / (double)(dvy * 4)),
1142 (unsigned int)floor((vz - vz_min) / (double)(dvz * 4))}};
1143 const uint32_t blockId = indices[0] + indices[1] * vx_length + indices[2] * vx_length * vy_length;
1144
1145 return blockId;
1146}
1147
1148// Reads avgs values of some given cell id
1149// Input:
1150// [0] vlsvReader -- Some vlsv reader with a file open
1151// [1] cellId -- The spatial cell's ID
1152// Output:
1153// [2] avgs -- Saves the output into an unordered map with block id as the key and an array of avgs as the value
1154// [3] vectorSize -- cells per block
1155// return false or true depending on whether the operation was successful
1156template <class T>
1157bool readAvgs( T & vlsvReader,
1158 string name,
1159 const unordered_map<uint64_t, pair<uint64_t, uint32_t>> & cellsWithBlocksLocations,
1160 const uint64_t & cellId,
1161 unordered_map<uint32_t, vector<double> > & avgs,
1162 uint64_t& vectorSize
1163) {
1164 // Get the block ids:
1165 vector<uint32_t> blockIds;
1166 if (getBlockIds(vlsvReader, cellsWithBlocksLocations, cellId, blockIds) == false) {
1167 return false;
1168 }
1169 // Read avgs:
1170 list<pair<string, string>> attribs;
1171 attribs.push_back(make_pair("name", name));
1172 attribs.push_back(make_pair("mesh", attributes["--meshname"]));
1173
1174 datatype::type dataType;
1175 uint64_t arraySize, dataSize;
1176 if (vlsvReader.getArrayInfo("BLOCKVARIABLE", attribs, arraySize, vectorSize, dataType, dataSize) == false) {
1177 // no
1178 // cerr << "ERROR READING BLOCKVARIABLE AT " << __FILE__ << " " << __LINE__ << endl;
1179 return false;
1180 }
1181
1182 // Make a routine error checks:
1183 unordered_map<uint64_t, pair<uint64_t, uint32_t>>::const_iterator it = cellsWithBlocksLocations.find( cellId );
1184 if( it == cellsWithBlocksLocations.end() ) {
1185 cerr << "COULDNT FIND CELL ID " << cellId << " AT " << __FILE__ << " " << __LINE__ << endl;
1186 return false;
1187 }
1188 // Get offset and number of blocks:
1189 pair<uint64_t, uint32_t> offsetAndBlocks = it->second;
1190 const uint64_t blockOffset = get<0>(offsetAndBlocks);
1191 const uint32_t N_blocks = get<1>(offsetAndBlocks);
1192
1193 if (N_blocks != blockIds.size()) {
1194 cerr << "ERROR, BAD AVGS ARRAY SIZE AT " << __FILE__ << " " << __LINE__ << endl;
1195 cerr << "AVGS SIZE: " << N_blocks << endl;
1196 cerr << "BLOCKIDS SIZE: " << blockIds.size() << endl;
1197 return false;
1198 }
1199
1200 char* buffer = new char[N_blocks * vectorSize * dataSize];
1201 if (vlsvReader.readArray("BLOCKVARIABLE", attribs, blockOffset, N_blocks, buffer) == false) {
1202 cerr << "ERROR could not read block variable at " << __FILE__ << " " << __LINE__ << endl;
1203 delete[] buffer;
1204 return false;
1205 }
1206 // Input avgs values:
1207 vector<double> avgs_temp (vectorSize);
1208 if( dataSize == 4 ) {
1209 float * buffer_float = reinterpret_cast<float*>( buffer );
1210 for( uint b = 0; b < blockIds.size(); ++b ) {
1211 const uint32_t & blockId = blockIds[b];
1212 for( uint i = 0; i < vectorSize; ++i ) {
1213 avgs_temp[i] = buffer_float[vectorSize * b + i];
1214 }
1215 avgs[blockId] = avgs_temp;
1216 }
1217 } else if (dataSize == 8) {
1218 double* buffer_double = reinterpret_cast<double*>(buffer);
1219 for (uint b = 0; b < blockIds.size(); ++b) {
1220 const uint32_t& blockId = blockIds[b];
1221 for (uint i = 0; i < vectorSize; ++i) {
1222 avgs_temp[i] = buffer_double[vectorSize * b + i];
1223 }
1224 avgs[blockId] = avgs_temp;
1225 }
1226 } else {
1227 cerr << "ERROR, BAD AVGS DATASIZE AT " << __FILE__ << " " << __LINE__ << endl;
1228 delete[] buffer;
1229 return false;
1230 }
1231 delete[] buffer;
1232 return true;
1233}
1234
1235template <class T>
1237 unordered_map<uint64_t, pair<uint64_t, uint32_t>>& cellsWithBlocksLocations) {
1238 if (cellsWithBlocksLocations.empty() == false) {
1239 cellsWithBlocksLocations.clear();
1240 }
1241 const string meshName = attributes["--meshname"];
1242 vlsv::datatype::type cwb_dataType;
1243 uint64_t cwb_arraySize, cwb_vectorSize, cwb_dataSize;
1244 list<pair<string, string>> attribs;
1245
1246 // Get the mesh name for reading in data from the correct place
1247 attribs.push_back(make_pair("mesh", meshName));
1248
1249 // Get array info
1250 if (vlsvReader.getArrayInfo("CELLSWITHBLOCKS", attribs, cwb_arraySize, cwb_vectorSize, cwb_dataType, cwb_dataSize) == false) {
1251 cerr << "ERROR, COULD NOT FIND ARRAY CELLSWITHBLOCKS AT " << __FILE__ << " " << __LINE__ << endl;
1252 return false;
1253 }
1254
1255 // Make sure the data format is correct:
1256 if (cwb_vectorSize != 1) {
1257 cerr << "ERROR, BAD VECTORSIZE AT " << __FILE__ << " " << __LINE__ << endl;
1258 return false;
1259 }
1260 if (cwb_dataType != vlsv::datatype::type::UINT) {
1261 cerr << "ERROR, BAD DATATYPE AT " << __FILE__ << " " << __LINE__ << endl;
1262 return false;
1263 }
1264 if (cwb_dataSize != sizeof(uint64_t)) {
1265 cerr << "ERROR, BAD DATASIZE AT " << __FILE__ << " " << __LINE__ << endl;
1266 return false;
1267 }
1268
1269 // Create buffer and read data:
1270 const uint64_t cwb_amountToReadIn = cwb_arraySize * cwb_vectorSize * cwb_dataSize;
1271 const uint16_t cwb_startingPoint = 0;
1272 char* cwb_buffer = new char[cwb_amountToReadIn];
1273 if (vlsvReader.readArray("CELLSWITHBLOCKS", attribs, cwb_startingPoint, cwb_arraySize, cwb_buffer) == false) {
1274 cerr << "Failed to read block metadata for mesh '" << meshName << "'" << endl;
1275 delete[] cwb_buffer;
1276 return false;
1277 }
1278
1279 vlsv::datatype::type nb_dataType;
1280 uint64_t nb_arraySize, nb_vectorSize, nb_dataSize;
1281
1282 // Get the mesh name for reading in data from the correct place
1283 // Read array info -- stores output in nb_arraySize, nb_vectorSize, nb_dataType, nb_dataSize
1284 if (vlsvReader.getArrayInfo("BLOCKSPERCELL", attribs, nb_arraySize, nb_vectorSize, nb_dataType, nb_dataSize) == false) {
1285 cerr << "ERROR, COULD NOT FIND ARRAY BLOCKSPERCELL AT " << __FILE__ << " " << __LINE__ << endl;
1286 return false;
1287 }
1288
1289 // Create buffers for number of blocks (nb) and read data:
1290 const short int startingPoint = 0; // Read the array from 0 (the beginning)
1291 char* nb_buffer = new char[nb_arraySize * nb_vectorSize * nb_dataSize];
1292 if (vlsvReader.readArray("BLOCKSPERCELL", attribs, startingPoint, nb_arraySize, nb_buffer) == false) {
1293 cerr << "Failed to read number of blocks for mesh '" << meshName << "'" << endl;
1294 delete[] nb_buffer;
1295 delete[] cwb_buffer;
1296 return false;
1297 }
1298
1299 // Input cellswithblock locations:
1300 uint64_t blockOffset = 0;
1301 uint64_t N_blocks;
1302 for (uint64_t cell = 0; cell < cwb_arraySize; ++cell) {
1303 const uint64_t readCellID = convUInt(cwb_buffer + cell * cwb_dataSize, cwb_dataType, cwb_dataSize);
1304 N_blocks = convUInt(nb_buffer + cell * nb_dataSize, nb_dataType, nb_dataSize);
1305 const pair<uint64_t, uint32_t> input = make_pair(blockOffset, N_blocks);
1306 // Insert the location and number of blocks into the map
1307 cellsWithBlocksLocations.insert(make_pair(readCellID, input));
1308 blockOffset += N_blocks;
1309 }
1310
1311 delete[] cwb_buffer;
1312 delete[] nb_buffer;
1313 return true;
1314}
1315
1316template <class T, class U>
1317bool compareAvgs(const string fileName1, const string fileName2, const bool verboseOutput, vector<uint64_t>& cellIds1,
1318 vector<uint64_t>& cellIds2) {
1319 if (cellIds1.empty() == true || cellIds2.empty() == true) {
1320 cerr << "ERROR, CELL IDS EMPTY IN COMPARE AVGS" << endl;
1321 return false;
1322 }
1323 // Declare map for locating velocity spaces within cell ids
1324 // Note: Key = cell id, value->first = blockOffset, value->second = numberOfBlocksToRead
1325 unordered_map<uint64_t, pair<uint64_t, uint32_t>> cellsWithBlocksLocations1;
1326 unordered_map<uint64_t, pair<uint64_t, uint32_t>> cellsWithBlocksLocations2;
1327 // Open the files for reading:
1328 T vlsvReader1;
1329 if (vlsvReader1.open(fileName1) == false) {
1330 cerr << "Error opening file name " << fileName1 << " at " << __FILE__ << " " << __LINE__ << endl;
1331 return false;
1332 }
1333
1334 U vlsvReader2;
1335 if (vlsvReader2.open(fileName2) == false) {
1336 cerr << "Error opening file name " << fileName2 << " at " << __FILE__ << " " << __LINE__ << endl;
1337 return false;
1338 }
1339
1340 if (getCellsWithBlocksLocations(vlsvReader1, cellsWithBlocksLocations1) == false) {
1341 cerr << "ERROR AT " << __FILE__ << " " << __LINE__ << endl;
1342 return false;
1343 }
1344
1345 if (getCellsWithBlocksLocations(vlsvReader2, cellsWithBlocksLocations2) == false) {
1346 cerr << "ERROR AT " << __FILE__ << " " << __LINE__ << endl;
1347 return false;
1348 }
1349 // Consistency check:
1350 if (cellsWithBlocksLocations2.size() != cellsWithBlocksLocations1.size()) {
1351 cerr << "BAD CELLS WITH BLOCKS SIZE AT " << __FILE__ << " " << __LINE__ << endl;
1352 return false;
1353 }
1354
1355 // Create a few variables for the cell id loop:
1356 vector<double> avgsDiffs;
1357 double totalAbsAvgs = 0;
1358 double totalAbsDiff = 0;
1359 double totalAbsLog10Diff = 0;
1360 double threshold = 1e-16;
1361 uint64_t numOfRelevantCells = 0;
1362 uint64_t numOfIdenticalBlocks = 0;
1363 uint64_t numOfNonIdenticalBlocks = 0;
1364 if (cellIds1[0] == 0 || cellIds2[0] == 0) {
1365 // User input 0 as the cell id -- compare all cell ids
1366 cellIds1.clear();
1367 cellIds2.clear();
1368 for (unordered_map<uint64_t, pair<uint64_t, uint32_t>>::const_iterator it = cellsWithBlocksLocations1.begin();
1369 it != cellsWithBlocksLocations1.end(); ++it) {
1370 cellIds1.push_back(it->first);
1371 cellIds2.push_back(it->first);
1372 }
1373 }
1374
1375 if (cellIds1.size() != cellIds2.size()) {
1376 cerr << "ERROR, BAD CELL ID SIZES AT " << __FILE__ << " " << __LINE__ << endl;
1377 return false;
1378 }
1379 // Go through cell ids:
1380 for (uint cellIndex = 0; cellIndex < cellIds2.size(); cellIndex++) {
1381 const uint64_t& cellId1 = cellIds1[cellIndex];
1382 const uint64_t& cellId2 = cellIds2[cellIndex];
1383 // Get the avgs in a hash map (The velocity block id is the key and avgs is the value):
1384 uint64_t vectorSize1 = 0, vectorSize2;
1385 unordered_map<uint32_t, vector<double> > avgs1;
1386 unordered_map<uint32_t, vector<double> > avgs2;
1387 // Store the avgs in avgs1 and 2:
1388 if( readAvgs( vlsvReader1, "proton", cellsWithBlocksLocations1, cellId1, avgs1, vectorSize1 ) == false ) {
1389 if( readAvgs( vlsvReader1, "avgs", cellsWithBlocksLocations1, cellId1, avgs1, vectorSize1 ) == false ) {
1390 cerr << "ERROR, FAILED TO READ AVGS AT " << __FILE__ << " " << __LINE__ << endl;
1391 return false;
1392 }
1393 }
1394
1395 if( readAvgs( vlsvReader2, "proton", cellsWithBlocksLocations2, cellId2, avgs2, vectorSize2 ) == false ) {
1396 if( readAvgs( vlsvReader2, "avgs", cellsWithBlocksLocations2, cellId2, avgs2, vectorSize2 ) == false ) {
1397 cerr << "ERROR, FAILED TO READ AVGS AT " << __FILE__ << " " << __LINE__ << endl;
1398 return false;
1399 }
1400 }
1401
1402 if (vectorSize1 != vectorSize2) {
1403 cerr << "ERROR, VECTORSIZES DON'T MATCH " << vectorSize1 << " VS " << vectorSize2 << " AT " << __FILE__ << " " << __LINE__ << endl;
1404 return false;
1405 }
1406 const uint64_t velocityCellsPerBlock = vectorSize1;
1407
1408 //Compare the avgs values:
1409 // First make a check on how many of the block ids are identical:
1410 const size_t sizeOfAvgs1 = avgs1.size();
1411 const size_t sizeOfAvgs2 = avgs2.size();
1412 // Vector of block ids that are the same
1413 vector<uint32_t> blockIds1;
1414 vector<uint32_t> blockIds2;
1415 blockIds1.reserve(sizeOfAvgs1);
1416 blockIds2.reserve(sizeOfAvgs2);
1417 // Input block ids:
1418 for( unordered_map<uint32_t, vector<double> >::const_iterator it = avgs1.begin(); it != avgs1.end(); ++it ) {
1419 blockIds1.push_back(it->first);
1420 }
1421 for( unordered_map<uint32_t, vector<double> >::const_iterator it = avgs2.begin(); it != avgs2.end(); ++it ) {
1422 blockIds2.push_back(it->first);
1423 }
1424 // Compare block ids:
1425 // Sort
1426 sort(blockIds1.begin(), blockIds1.end());
1427 sort(blockIds2.begin(), blockIds2.end());
1428 // Create iterators
1429 vector<uint32_t>::const_iterator it1 = blockIds1.begin();
1430 vector<uint32_t>::const_iterator it2 = blockIds2.begin();
1431 // Separate block ids into two categories -- the ones that blockids1 and blockids2 share and ones that only one of
1432 // them shares
1433 vector<uint32_t> identicalBlockIds;
1434 vector<uint32_t> nonIdenticalBlockIds;
1435
1436 while (true) {
1437 if (it1 == blockIds1.end() || it2 == blockIds2.end()) {
1438 // Reach end of block ids
1439 break;
1440 }
1441 if (*it1 == *it2) {
1442 // Identical block id
1443 identicalBlockIds.push_back(*it1);
1444 it1++;
1445 it2++;
1446 } else if (*it1 < *it2) {
1447 // Non identical block id
1448 // The block ids are sorted so to get identical block ids one must increment the lower value
1449 nonIdenticalBlockIds.push_back(*it1);
1450 it1++;
1451 } else if (*it2 < *it1) {
1452 // Non identical block id
1453 // The block ids are sorted so to get identical block ids one must increment the lower value
1454 nonIdenticalBlockIds.push_back(*it2);
1455 it2++;
1456 }
1457 }
1458 // Get the rest of the non identical block ids (If there are any)
1459 // Note: This is only needed if for example it1 hit the end of the iteration and it2 still isn't at the end
1460 for (; it1 != blockIds1.end(); ++it1) {
1461 nonIdenticalBlockIds.push_back(*it1);
1462 }
1463 for (; it2 != blockIds2.end(); ++it2) {
1464 nonIdenticalBlockIds.push_back(*it2);
1465 }
1466 // Compare block ids:
1467 const uint64_t totalNumberOfBlocks = identicalBlockIds.size() + nonIdenticalBlockIds.size();
1468 const double percentageOfIdenticalBlocks = (double)(totalNumberOfBlocks) / (double)(identicalBlockIds.size());
1469 // Compare the avgs values of the identical blocks:
1470 avgsDiffs.reserve(avgsDiffs.size() + identicalBlockIds.size() * velocityCellsPerBlock);
1471 for (vector<uint32_t>::const_iterator it = identicalBlockIds.begin(); it != identicalBlockIds.end(); ++it) {
1472 // Get the block id
1473 const uint32_t blockId = *it;
1474 // Get avgs values:
1475 const vector<double> & avgsValues1 = avgs1.at(blockId);
1476 const vector<double> & avgsValues2 = avgs2.at(blockId);
1477 // Get the diff:
1478 for (uint i = 0; i < velocityCellsPerBlock; ++i) {
1479 double val1 = avgsValues1[i] > threshold ? avgsValues1[i] : threshold;
1480 double val2 = avgsValues2[i] > threshold ? avgsValues2[i] : threshold;
1481 if (avgsValues1[i] > threshold || avgsValues2[i] > threshold)
1482 numOfRelevantCells++;
1483
1484 avgsDiffs.push_back(abs(val1 - val2));
1485 totalAbsAvgs += (abs(val1) + abs(val2));
1486 totalAbsDiff += abs(val1 - val2);
1487 totalAbsLog10Diff += abs(log10(val1) - log10(val2));
1488 }
1489 }
1490 // Compare the avgs values of nonidentical blocks:
1491 vector<double> zeroAvgs(velocityCellsPerBlock, 0);
1492 for( vector<uint32_t>::const_iterator it = nonIdenticalBlockIds.begin(); it != nonIdenticalBlockIds.end(); ++it ) {
1493 // Get the block id
1494 const uint32_t blockId = *it;
1495 // Get avgs values:
1496
1497 const vector<double>* avgsValues1;
1498 const vector<double>* avgsValues2;
1499
1500 unordered_map<uint32_t, vector<double> >::const_iterator it2 = avgs1.find( blockId );
1501 if( it2 == avgs1.end() ) {
1502 avgsValues1 = &zeroAvgs;
1503 } else {
1504 avgsValues1 = &(it2->second);
1505 }
1506
1507 it2 = avgs2.find(blockId);
1508 if (it2 == avgs2.end()) {
1509 avgsValues2 = &zeroAvgs;
1510 } else {
1511 avgsValues2 = &(it2->second);
1512 }
1513 // Get the diff:
1514 for (uint i = 0; i < velocityCellsPerBlock; ++i) {
1515 double val1 = avgsValues1->operator[](i) > threshold ? avgsValues1->operator[](i) : threshold;
1516 double val2 = avgsValues2->operator[](i) > threshold ? avgsValues2->operator[](i) : threshold;
1517 if (avgsValues1->operator[](i) > threshold || avgsValues2->operator[](i) > threshold)
1518 numOfRelevantCells++;
1519
1520 avgsDiffs.push_back(abs(val1 - val2));
1521 totalAbsAvgs += (abs(val1) + abs(val2));
1522 totalAbsDiff += abs(val1 - val2);
1523 totalAbsLog10Diff += abs(log10(val1) - log10(val2));
1524 }
1525 }
1526 numOfIdenticalBlocks += identicalBlockIds.size();
1527 numOfNonIdenticalBlocks += nonIdenticalBlockIds.size();
1528 }
1529 // Get the max and min diff, and the sum of the diff
1530 double maxDiff = 0;
1531 double minDiff = numeric_limits<Real>::max();
1532 double sumDiff = 0;
1533 for (vector<double>::const_iterator it = avgsDiffs.begin(); it != avgsDiffs.end(); ++it) {
1534 sumDiff += *it;
1535 if (maxDiff < *it) {
1536 maxDiff = *it;
1537 }
1538 if (minDiff > *it) {
1539 minDiff = *it;
1540 }
1541 }
1542
1543 Real time1{0.0};
1544 Real time2{0.0};
1545 vlsvReader1.readParameter("time", time1);
1546 vlsvReader2.readParameter("time", time2);
1547
1548 const double relativeSumDiff = sumDiff / totalAbsAvgs;
1549 cout << "File names: " << fileName1 << " & " << fileName2 << endl
1550 << setprecision(3) << "NonIdenticalBlocks: " << numOfNonIdenticalBlocks << endl
1551 << "IdenticalBlocks: " << numOfIdenticalBlocks << endl
1552 << "Absolute_Error: " << totalAbsDiff << endl
1553 << "Mean-Absolute-Error: " << totalAbsDiff / numOfRelevantCells << endl
1554 << "Max-Absolute-Error: " << maxDiff << endl
1555 << "Absolute-log-Error: " << totalAbsLog10Diff << endl
1556 << "Mean-Absolute-log-Error: " << totalAbsLog10Diff / numOfRelevantCells << endl
1557 << "Delta-t: " << time2 - time1 << endl;
1558
1559 return true;
1560}
1561
1570bool process2Files(const string fileName1, const string fileName2, const char* varToExtract, const uint compToExtract,
1571 const bool verboseOutput, const uint compToExtract2 = 0) {
1572 map<uint, Real> orderedData1;
1573 map<uint, Real> orderedData2;
1574 Real absolute, relative, mini, maxi, size, avg, stdev;
1575
1576 // If the user wants to check avgs, call the avgs check function and return it. Otherwise move on to compare
1577 // variables:
1578 if (strcmp(varToExtract, "proton") == 0 && attributes.find("--no-distrib") == attributes.end()) {
1579 vector<uint64_t> cellIds1;
1580 vector<uint64_t> cellIds2;
1581 cellIds1.reserve(1);
1582 cellIds2.reserve(1);
1583 cellIds1.push_back(compToExtract);
1584 cellIds2.push_back(compToExtract2);
1585 // Compare files:
1586 if (compareAvgs<vlsvinterface::Reader, vlsvinterface::Reader>(fileName1, fileName2, verboseOutput, cellIds1, cellIds2) == false) {
1587 return false;
1588 }
1589 } else {
1590 unordered_map<size_t, size_t> cellOrder;
1591
1592 bool success = true;
1593 Real time1{0.0};
1594 success = convertSILO<vlsvinterface::Reader>(fileName1, varToExtract, compToExtract, &orderedData1, cellOrder, time1, true);
1595
1596 if (success == false) {
1597 cerr << "ERROR Data import error with " << fileName1 << endl;
1598 return 1;
1599 }
1600
1601 Real time2{0.0};
1602 success = convertSILO<vlsvinterface::Reader>(fileName2, varToExtract, compToExtract, &orderedData2, cellOrder, time2, false);
1603
1604 if (success == false) {
1605 cerr << "ERROR Data import error with " << fileName2 << endl;
1606 return 1;
1607 }
1608
1609 // Basic consistency check
1610 if (orderedData1.size() != orderedData2.size()) {
1611 cerr << "ERROR Datasets have different size." << endl;
1612 return 1;
1613 }
1614
1615 // Open VLSV file where the diffence in the chosen variable is written
1616 const string prefix = fileName1.substr(0, fileName1.find_last_of('.'));
1617 const string suffix = fileName1.substr(fileName1.find_last_of('.'), fileName1.size());
1618 string outputFileName = prefix + ".diff." + varToExtract + suffix;
1619 const string varName = varToExtract;
1620 vlsv::Writer outputFile;
1621 if (attributes.find("--diff") != attributes.end()) {
1622 if (outputFileName[0] == '.' && outputFileName[1] == '/') {
1623 outputFileName = outputFileName.substr(2, string::npos);
1624 }
1625
1626 for (size_t s = 0; s < outputFileName.size(); ++s)
1627 if (outputFileName[s] == '/')
1628 outputFileName[s] = '_';
1629
1630 if (outputFile.open(outputFileName, MPI_COMM_SELF, 0) == false) {
1631 cerr << "ERROR failed to open output file '" << outputFileName << "' in " << __FILE__ << ":" << __LINE__ << endl;
1632 return false;
1633 }
1634
1635 map<string, string>::const_iterator it = attributes.find("--meshname");
1636 if (cloneMesh(fileName1, outputFile, it->second, orderedData1) == false) {
1637 std::cerr << "Failed" << std::endl;
1638 return false;
1639 }
1640 }
1641
1642 singleStatistics(&orderedData1, &size, &mini, &maxi, &avg, &stdev); // CONTINUE
1643 // Clone mesh from input file to diff file
1644 outputStats(&size, &mini, &maxi, &avg, &stdev, verboseOutput, false);
1645
1646 singleStatistics(&orderedData2, &size, &mini, &maxi, &avg, &stdev);
1647 outputStats(&size, &mini, &maxi, &avg, &stdev, verboseOutput, false);
1648
1649 pDistance(orderedData1, orderedData2, 0, &absolute, &relative, false, cellOrder, outputFile, attributes["--meshname"], "d0_" + varName);
1650 outputDistance(0, &absolute, &relative, false, verboseOutput, false);
1651 pDistance(orderedData1, orderedData2, 0, &absolute, &relative, true, cellOrder, outputFile, attributes["--meshname"], "d0_sft_" + varName);
1652 outputDistance(0, &absolute, &relative, true, verboseOutput, false);
1653
1654 pDistance(orderedData1, orderedData2, 1, &absolute, &relative, false, cellOrder, outputFile, attributes["--meshname"], "d1_" + varName);
1655 outputDistance(1, &absolute, &relative, false, verboseOutput, false);
1656 pDistance(orderedData1, orderedData2, 1, &absolute, &relative, true, cellOrder, outputFile, attributes["--meshname"], "d1_sft_" + varName);
1657 outputDistance(1, &absolute, &relative, true, verboseOutput, false);
1658
1659 pDistance(orderedData1, orderedData2, 2, &absolute, &relative, false, cellOrder, outputFile, attributes["--meshname"], "d2_" + varName);
1660 outputDistance(2, &absolute, &relative, false, verboseOutput, false);
1661 pDistance(orderedData1, orderedData2, 2, &absolute, &relative, true, cellOrder, outputFile, attributes["--meshname"], "d2_sft_" + varName);
1662 outputDistance(2, &absolute, &relative, true, verboseOutput, false);
1663
1664 outputDt(time2 - time1, verboseOutput, false);
1665
1666 outputFile.close();
1667 }
1668
1669 if (verboseOutput == false) {
1671 cout << endl;
1672 }
1673
1674 return 0;
1675}
1676
1681bool processDirectory(DIR* dir, set<string>* fileList) {
1682 int filesFound = 0, entryCounter = 0;
1683
1684 const string mask = attributes["--filemask"];
1685 const string suffix = ".vlsv";
1686
1687 struct dirent* entry = readdir(dir);
1688 while (entry != NULL) {
1689 const string entryName = entry->d_name;
1690 if (entryName.find(mask) == string::npos || entryName.find(suffix) == string::npos) {
1691 entry = readdir(dir);
1692 continue;
1693 }
1694 fileList->insert(entryName);
1695 filesFound++;
1696 entry = readdir(dir);
1697 }
1698 if (filesFound == 0)
1699 cout << "INFO no matches found" << endl;
1700
1701 return 0;
1702}
1703
1704void printHelp(const map<string, string>& defAttribs, const map<string, string>& descriptions) {
1705 cout << endl;
1706 cout << "VLSVDIFF command line attributes are given as option=value pairs, value can be empty." << endl;
1707 cout << "If the default value is 'unset', then giving the option in the command line turns it on." << endl;
1708 cout << "For example, \"vlsvdiff --help\" displays this message and the option '--help' does not have a value."
1709 << endl
1710 << endl;
1711
1712 cout << "Known attributes and default values are:" << endl;
1713 for (map<string, string>::const_iterator it = defAttribs.begin(); it != defAttribs.end(); ++it) {
1714 cout << endl;
1715 const size_t optionWidth = 30;
1716 const size_t descrMaxWidth = 120;
1717
1718 // Print the option,value pair so that the field width is always 30 characters
1719 string option = it->first;
1720 if (it->second.size() > 0)
1721 option = option + "=" + it->second;
1722 else
1723 option = option + " (unset)";
1724
1725 if (option.size() < optionWidth) {
1726 size_t padding = optionWidth - option.size();
1727 for (size_t i = 0; i < padding; ++i)
1728 option = option + ' ';
1729 }
1730 cout << option;
1731
1732 // Print the description, possibly on multiple lines.
1733 map<string, string>::const_iterator descr = descriptions.find(it->first);
1734 if (descr == descriptions.end()) {
1735 cout << "(no description given)" << endl;
1736 continue;
1737 }
1738
1739 // If the description fits in the first line, print it and continue
1740 if (descr->second.size() <= descrMaxWidth - optionWidth) {
1741 cout << descr->second << endl;
1742 continue;
1743 }
1744
1745 // Print the description on multiple lines. First parse the description
1746 // string and store each word to a vector.
1747 vector<string> text;
1748 size_t i = 0;
1749 while (i < descr->second.size()) {
1750 size_t i_space = descr->second.find_first_of(' ', i);
1751 if (i_space == string::npos)
1752 i_space = descr->second.size();
1753 text.push_back(descr->second.substr(i, i_space - i));
1754 i = i_space + 1;
1755 }
1756
1757 // Write out the words in vector 'text' so that the length of any line
1758 // does not exceed descrMaxWidth characters.
1759 i = optionWidth;
1760 for (size_t s = 0; s < text.size(); ++s) {
1761 if (i + text[s].size() <= descrMaxWidth) {
1762 cout << text[s] << ' ';
1763 i += text[s].size() + 1;
1764 } else {
1765 cout << endl;
1766 for (unsigned int j = 0; j < optionWidth; ++j)
1767 cout << ' ';
1768 i = optionWidth;
1769
1770 cout << text[s] << ' ';
1771 i += text[s].size() + 1;
1772 }
1773 }
1774 cout << endl;
1775 }
1776 cout << endl;
1777}
1778
1783int main(int argn, char* args[]) {
1784 MPI_Init(&argn, &args);
1785
1786 // Create default attributes
1787 map<string, string> defAttribs;
1788 map<string, string> descriptions;
1789 defAttribs.insert(make_pair("--meshname", "SpatialGrid"));
1790 defAttribs.insert(make_pair("--filemask", "bulk"));
1791 defAttribs.insert(make_pair("--help", ""));
1792 defAttribs.insert(make_pair("--no-distrib", ""));
1793 defAttribs.insert(make_pair("--diff", ""));
1794
1795 descriptions["--meshname"] = "Name of the spatial mesh that is used in diff.";
1796 descriptions["--filemask"] = "File mask used in directory comparison mode. For example, if you want to compare "
1797 "files starting with 'fullf', set '--filemask=fullf'.";
1798 descriptions["--help"] = "Print this help message.";
1799 descriptions["--diff"] = "If set, difference file(s) are written.";
1800 descriptions["--no-distrib"] =
1801 "If set, velocity block data are not compared even if the given variable corresponds to velocity block data.";
1802
1803 // Create default attributes
1804 for (map<string, string>::const_iterator it = defAttribs.begin(); it != defAttribs.end(); ++it) {
1805 if (it->second.size() == 0) continue;
1806 attributes.insert(make_pair(it->first, it->second));
1807 }
1808
1809 vector<string> argsVector;
1810
1811 // Parse attributes,value pairs from command line
1812 int i = 0;
1813 while (i < argn) {
1814 if (args[i][1] == '\0') {
1815 argsVector.push_back(args[i]);
1816 ++i;
1817 continue;
1818 }
1819 if (args[i][0] == '-' && args[i][1] == '-') {
1820 string s = args[i];
1821 if (argn > i) {
1822 if (s.find("=") == string::npos) {
1823 attributes.insert(make_pair(string(args[i]), ""));
1824 } else {
1825 size_t pos = s.find("=");
1826 string arg = s.substr(0, s.find('='));
1827 string val = s.substr(s.find('=') + 1, string::npos);
1828 attributes[arg] = val;
1829 }
1830 ++i;
1831 continue;
1832 } else {
1833 if (s.find("=") == string::npos) {
1834 attributes.insert(make_pair(string(args[i]), ""));
1835 } else {
1836 size_t pos = s.find("=");
1837 string arg = s.substr(0, s.find('='));
1838 string val = s.substr(s.find('=') + 1, string::npos);
1839 attributes[arg] = val;
1840 }
1841 ++i;
1842 break;
1843 }
1844 } else {
1845 argsVector.push_back(args[i]);
1846 }
1847 ++i;
1848 }
1849
1850 if (attributes.find("--help") != attributes.end()) {
1851 printHelp(defAttribs, descriptions);
1852 return 0;
1853 }
1854
1855 if (argsVector.size() < 5) {
1856 cout << endl;
1857 cout << "USAGE 1: ./vlsvdiff <file1> <file2> <Variable> <component>" << endl;
1858 cout << "Gives single-file statistics and distances between the two files given, for the variable and component given" << endl;
1859 cout << "USAGE 2: ./vlsvdiff <folder1> <folder2> <Variable> <component>" << endl;
1860 cout << "Gives single-file statistics and distances between pairs of files grid*.vlsv taken in alphanumeric "
1861 "order in the two folders given, for the variable and component given" << endl;
1862 cout << "USAGE 3: ./vlsvdiff <file1> <folder2> <Variable> <component>" << endl;
1863 cout << " ./vlsvdiff <folder1> <file2> <Variable> <component>" << endl;
1864 cout << "Gives single-file statistics and distances between a file, and files grid*.vlsv taken in alphanumeric "
1865 "order in the given folder, for the variable and component given" << endl;
1866 cout << endl;
1867 cout << "Type ./vlsvdiff --help for more info" << endl;
1868 cout << endl;
1869 return 1;
1870 }
1871
1872 // 1st arg is file1 name
1873 const string fileName1 = argsVector[1];
1874 // 2nd arg is file2 name
1875 const string fileName2 = argsVector[2];
1876 // 3rd arg is variable name
1877 const char* varToExtract = argsVector[3].c_str();
1878
1879 // 4th arg is its component, 0 for scalars, 2 for z component etc
1880 uint compToExtract = atoi(argsVector[4].c_str());
1881 // 5h arg if there is one:
1882 uint compToExtract2;
1883 if (argsVector.size() > 5) {
1884 compToExtract2 = atoi(argsVector[5].c_str());
1885 } else {
1886 compToExtract2 = compToExtract;
1887 }
1888
1889 // Figure out Meshname
1890 if (attributes["--meshname"] == "SpatialGrid") {
1892 } else if (attributes["--meshname"] == "fsgrid") {
1894 } else if (attributes["--meshname"] == "ionosphere") {
1896 } else {
1897 std::cout << attributes["--meshname"] << std::endl;
1898 std::cerr << "Wrong grid type" << std::endl;
1899 abort();
1900 }
1901
1902 DIR* dir1 = opendir(fileName1.c_str());
1903 DIR* dir2 = opendir(fileName2.c_str());
1904
1905 if (dir1 == nullptr && dir2 == nullptr) {
1906 cout << "INFO Reading in two files." << endl;
1907
1908 // Process two files with verbose output (last argument true)
1909 process2Files(fileName1, fileName2, varToExtract, compToExtract, true, compToExtract2);
1910 } else if (dir1 == nullptr || dir2 == nullptr) {
1911 // Mixed file and directory
1912 cout << "#INFO Reading in one file and one directory." << endl;
1913 set<string> fileList;
1914
1915 if (dir1 == nullptr) {
1916 // file in 1, directory in 2
1917 processDirectory(dir2, &fileList);
1918 for (auto f : fileList) {
1919 // Process two files with non-verbose output (last argument false), give full path to the file processor
1920 process2Files(fileName1, fileName2 + "/" + f, varToExtract, compToExtract, false, compToExtract2);
1921 }
1922 closedir(dir2);
1923 }
1924
1925 if (dir2 == nullptr) {
1926 // directory in 1, file in 2
1927 processDirectory(dir1, &fileList);
1928 for (auto f : fileList) {
1929 // Process two files with non-verbose output (last argument false), give full path to the file processor
1930 process2Files(fileName1 + "/" + f, fileName2, varToExtract, compToExtract, false, compToExtract2);
1931 }
1932 closedir(dir1);
1933 }
1934 } else if (dir1 && dir2) {
1935 // Process two folders, files of the same rank compared, first folder is reference in relative distances
1936 cout << "#INFO Reading in two directories." << endl;
1937 set<string> fileList1, fileList2;
1938
1939 // Produce a sorted file list
1940 processDirectory(dir1, &fileList1);
1941 processDirectory(dir2, &fileList2);
1942
1943 // Basic consistency check
1944 if (fileList1.size() != fileList2.size()) {
1945 cerr << "ERROR Folders have different number of files." << endl;
1946 return 1;
1947 }
1948
1949 // TODO zip these once we're using C++23
1950 for (auto it1 = fileList1.begin(), it2 = fileList2.begin(); it1 != fileList2.end(), it2 != fileList2.end(); it1++, it2++) {
1951 // Process two files with non-verbose output (last argument false), give full path to the file processor
1952 process2Files(fileName1 + "/" + *it1, fileName2 + "/" + *it2, varToExtract, compToExtract, false, compToExtract2);
1953 }
1954
1955 closedir(dir1);
1956 closedir(dir2);
1957 }
1958
1959 MPI_Finalize();
1960 return 0;
1961}
Binary file
Definition Dispersion.m:11
for i
Definition Dispersion.m:24
dt
Definition Dispersion.m:39
hold on text('Interpreter', 'tex')
set(gca, 'YDir', 'normal')
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
Parameters length
Definition Dispersion.m:36
bool getCellIds(std::vector< uint64_t > &cellIds, const std::string &meshName="SpatialGrid")
float Real
Definition definitions.h:41
uint64_t CellID
Definition definitions.h:54
const float creal
Definition definitions.h:42
const int j
__global__ void const Realf const uint *__restrict__ const uint *__restrict__ const vmesh::GlobalID *__restrict__ const uint const uint const uint const Realf threshold
const Realf dvz
const Realf vz_min
#define index(i, j, k)
#define NAN
int main()
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)
static ARCH_HOSTDEV VecSimple< T > floor(VecSimple< T > const &a)
bool printNonVerboseData()
bool convertSILO(const string fileName, const char *varToExtract, const uint compToExtract, map< uint, Real > *orderedData, unordered_map< size_t, size_t > &cellOrder, Real &time, const bool &storeCellOrder=false)
Definition vlsvdiff.cpp:714
bool process2Files(const string fileName1, const string fileName2, const char *varToExtract, const uint compToExtract, const bool verboseOutput, const uint compToExtract2=0)
GridType
Definition vlsvdiff.cpp:75
@ FSGRID
Definition vlsvdiff.cpp:77
@ IONOSPHERE
Definition vlsvdiff.cpp:78
@ SPATIALGRID
Definition vlsvdiff.cpp:76
static map< string, string > attributes
Definition vlsvdiff.cpp:71
bool readAvgs(T &vlsvReader, string name, const unordered_map< uint64_t, pair< uint64_t, uint32_t > > &cellsWithBlocksLocations, const uint64_t &cellId, unordered_map< uint32_t, vector< double > > &avgs, uint64_t &vectorSize)
bool singleStatistics(map< uint, Real > *orderedData, Real *size, Real *mini, Real *maxi, Real *avg, Real *stdev)
Definition vlsvdiff.cpp:975
uint32_t getBlockId(const double vx, const double vy, const double vz, const double dvx, const double dvy, const double dvz, const double vx_min, const double vy_min, const double vz_min, const double vx_length, const double vy_length, const double vz_length)
bool copyArray(vlsv::Reader &input, vlsv::Writer &output, const std::string &tagName, const list< pair< string, string > > &inputAttribs, bool optional=false)
Definition vlsvdiff.cpp:111
bool pDistance(const map< uint, Real > &orderedData1, const map< uint, Real > &orderedData2, creal p, Real *absolute, Real *relative, const bool doShiftAverage, const unordered_map< size_t, size_t > &cellOrder, vlsv::Writer &outputFile, const std::string &meshName, const std::string &varName)
Definition vlsvdiff.cpp:810
bool outputStats(const Real *size, const Real *mini, const Real *maxi, const Real *avg, const Real *stdev, const bool verboseOutput, const bool lastCall)
bool shiftAverage(const map< uint, Real > *const orderedData1, const map< uint, Real > *const orderedData2, map< uint, Real > *shiftedData2)
Definition vlsvdiff.cpp:757
bool compareAvgs(const string fileName1, const string fileName2, const bool verboseOutput, vector< uint64_t > &cellIds1, vector< uint64_t > &cellIds2)
void printHelp(const map< string, string > &defAttribs, const map< string, string > &descriptions)
static uint64_t convUInt(const char *ptr, const vlsv::datatype::type &dataType, const uint64_t &dataSize)
Definition vlsvdiff.cpp:81
bool HandleFsGrid(const string &inputFileName, vlsv::Writer &output, std::map< uint, Real > orderedData)
Definition vlsvdiff.cpp:170
bool processDirectory(DIR *dir, set< string > *fileList)
bool getFsgridDecomposition(vlsvinterface::Reader &file, std::array< int, 3 > &decomposition)
Definition vlsvdiff.cpp:295
bool getBlockIds(vlsvinterface::Reader &vlsvReader, const unordered_map< uint64_t, pair< uint64_t, uint32_t > > &cellsWithBlocksLocations, const uint64_t &cellId, vector< uint32_t > &blockIds)
bool getCellsWithBlocksLocations(T &vlsvReader, unordered_map< uint64_t, pair< uint64_t, uint32_t > > &cellsWithBlocksLocations)
bool outputDistance(const Real p, const Real *absolute, const Real *relative, const bool shiftedAverage, const bool verboseOutput, const bool lastCall)
Definition vlsvdiff.cpp:913
bool cloneMesh(const string &inputFileName, vlsv::Writer &output, const string &meshName, std::map< uint, Real > orderedData)
Definition vlsvdiff.cpp:383
static int gridName
Definition vlsvdiff.cpp:74
bool convertMesh(vlsvinterface::Reader &vlsvReader, const string &meshName, const char *varToExtract, const uint compToExtract, map< uint, Real > *orderedData, unordered_map< size_t, size_t > &cellOrder, const bool &storeCellOrder)
Definition vlsvdiff.cpp:433
bool outputDt(const Real dt, const bool verboseOutput, const bool lastCall)
Definition vlsvdiff.cpp:947