Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
fluxfunction.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#include <mpi.h>
23#include <iostream>
24#include <string>
25#include <unistd.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <fcntl.h>
29#include <errno.h>
30#include <string.h>
31#include "common.h"
32#include "particles/field.h"
34
35using namespace std;
36
37static bool isInside(Field& B, double R, int x, int y, int z) {
38 double R2 = 0;
39 std::array<int, 3> xyz{x, y, z};
40 for (int i = 0; i < 3; ++i) {
41 R2 += pow(B.dimension[i]->min + xyz[i] * B.dx[i], 2);
42 }
43 return R2 < pow(R, 2);
44}
45
46// Calculate fluxfunction by integrating along -y/z boundary first,
47// and then going along y/z-direction.
48std::vector<double> computeFluxUp(Field& B, int outerBoundary, double innerBoundary) {
49 // Create fluxfunction-field to be the same shape as B
50 std::vector<double> flux(B.dimension[0]->cells * B.dimension[1]->cells * B.dimension[2]->cells);
51 for (unsigned int i = 0; i < flux.size(); ++i) {
52 flux[i] = NAN;
53 }
54
55 bool eqPlane = B.dimension[1]->cells > 1;
56 int yCoord = eqPlane ? 1 : 2;
57
58 long double tmp_flux=0.;
59 long double bottom_flux=0.;
60
61 // First, fill the y/z=3 cells
62 // Then integrate in y/z direction
63 for (int x = B.dimension[0]->cells - (outerBoundary+1); x >= outerBoundary; x--) {
64 int i = outerBoundary;
65 int y = eqPlane ? i : 0;
66 int z = eqPlane ? 0 : i;
67 if (isInside(B, innerBoundary, x, y, z)) {
68 break;
69 }
70
71 Vec3d bval = B.getCell(x,y,z);
72
73 bottom_flux -= bval[yCoord] * B.dx[0];
74 flux[B.dimension[0]->cells * i + x] = bottom_flux;
75
76 tmp_flux = bottom_flux;
77 for(i++; i < B.dimension[yCoord]->cells - outerBoundary; i++) {
78 y = eqPlane ? i : 0;
79 z = eqPlane ? 0 : i;
80 if (isInside(B, innerBoundary, x, y, z)) {
81 break;
82 }
83
84 bval = B.getCell(x,y,z);
85
86 tmp_flux -= bval[0] * B.dx[yCoord];
87 flux[B.dimension[0]->cells * i + x] = tmp_flux;
88 }
89 }
90
91 return flux;
92}
93
94// Calculate fluxfunction by integrating along +y/z boundary first,
95// and then going along negative y/z-direction.
96std::vector<double> computeFluxDown(Field& B, int outerBoundary, double innerBoundary) {
97 // Create fluxfunction-field to be the same shape as B
98 std::vector<double> flux(B.dimension[0]->cells * B.dimension[1]->cells * B.dimension[2]->cells);
99 for (unsigned int i = 0; i < flux.size(); ++i) {
100 flux[i] = NAN;
101 }
102
103 bool eqPlane = B.dimension[1]->cells > 1;
104 int yCoord = eqPlane ? 1 : 2;
105
106 long double tmp_flux=0.;
107 long double top_flux=0.;
108
109 // Calculate flux-difference between bottom and top edge
110 // of +x boundary (so that values are consistent with computeFluxUp)
111 for(int i = outerBoundary; i < B.dimension[yCoord]->cells - outerBoundary; i++) {
112 int x = B.dimension[0]->cells - (outerBoundary + 1);
113 int y = eqPlane ? i : 0;
114 int z = eqPlane ? 0 : i;
115 if (isInside(B, innerBoundary, x, y, z)) {
116 break;
117 }
118
119 Vec3d bval = B.getCell(x, y, z);
120
121 top_flux -= bval[0]*B.dx[yCoord];
122 flux[B.dimension[0]->cells * i + x] = top_flux;
123 }
124
125 // First, fill the y/z = max - 4 cells
126 // Then integrate in -y/z direction
127 for(int x = B.dimension[0]->cells - (outerBoundary + 2); x >= outerBoundary; x--) {
128 int i = B.dimension[yCoord]->cells - (outerBoundary + 1);
129 int y = eqPlane ? i : 0;
130 int z = eqPlane ? 0 : i;
131 if (isInside(B, innerBoundary, x, y, z)) {
132 break;
133 }
134
135 Vec3d bval = B.getCell(x, y, z);
136
137 top_flux -= bval[yCoord] * B.dx[0];
138 flux[B.dimension[0]->cells * i + x] = top_flux;
139
140 tmp_flux = top_flux;
141 for (i--; i >= outerBoundary; i--) {
142 y = eqPlane ? i : 0;
143 z = eqPlane ? 0 : i;
144 if (isInside(B, innerBoundary, x, y, z)) {
145 break;
146 }
147
148 bval = B.getCell(x, y, z);
149
150 tmp_flux += bval[0] * B.dx[yCoord];
151 flux[B.dimension[0]->cells * i + x] = tmp_flux;
152 }
153 }
154
155 return flux;
156}
157
158// Calculate fluxfunction by integrating along -x from the right boundary
159std::vector<double> computeFluxLeft(Field& B, int outerBoundary, double innerBoundary) {
160 // Create fluxfunction-field to be the same shape as B
161 std::vector<double> flux(B.dimension[0]->cells * B.dimension[1]->cells * B.dimension[2]->cells);
162 for (unsigned int i = 0; i < flux.size(); ++i) {
163 flux[i] = NAN;
164 }
165
166 bool eqPlane = B.dimension[1]->cells > 1;
167 int yCoord = eqPlane ? 1 : 2;
168
169 long double tmp_flux=0.;
170 long double right_flux=0.;
171
172 // First calculate flux difference to bottom right corner
173 // Now, for each row, integrate in -z-direction.
174 for(int i = outerBoundary; i < B.dimension[yCoord]->cells - outerBoundary; i++) {
175 int x = B.dimension[0]->cells - (outerBoundary + 1);
176 int y = eqPlane ? i : 0;
177 int z = eqPlane ? 0 : i;
178 if (isInside(B, innerBoundary, x, y, z)) {
179 break;
180 }
181
182 Vec3d bval = B.getCell(x, y, z);
183
184 right_flux -= bval[0] * B.dx[yCoord];
185 flux[B.dimension[0]->cells * i + x] = right_flux;
186
187 tmp_flux = right_flux;
188 for(x--; x >= outerBoundary; x--) {
189 if (isInside(B, innerBoundary, x, y, z)) {
190 break;
191 }
192
193 bval = B.getCell(x,y,z);
194
195 tmp_flux -= bval[yCoord] * B.dx[0];
196 flux[B.dimension[0]->cells * i + x] = tmp_flux;
197 }
198 }
199
200 return flux;
201}
202
203// Calculate fluxfunction by integrating along -y/z boundary
204// Then along the -x boundary
205// And finally right in the +x direction
206std::vector<double> computeFluxUpRight(Field& B, int outerBoundary, double innerBoundary) {
207 // Create fluxfunction-field to be the same shape as B
208 std::vector<double> flux(B.dimension[0]->cells * B.dimension[1]->cells * B.dimension[2]->cells);
209 for (unsigned int i = 0; i < flux.size(); ++i) {
210 flux[i] = NAN;
211 }
212
213 bool eqPlane = B.dimension[1]->cells > 1;
214 int yCoord = eqPlane ? 1 : 2;
215
216 long double tmp_flux=0.;
217 long double left_flux=0.;
218
219 // First calculate flux difference from the right edge
220 for (int x = B.dimension[0]->cells - (outerBoundary + 1); x >= outerBoundary; x--) {
221 int i = outerBoundary;
222 int y = eqPlane ? i : 0;
223 int z = eqPlane ? 0 : i;
224 if (isInside(B, innerBoundary, x, y, z)) {
225 break;
226 }
227
228 Vec3d bval = B.getCell(x,y,z);
229
230 left_flux -= bval[yCoord] * B.dx[0];
231 flux[B.dimension[0]->cells * i + x] = left_flux;
232 }
233
234 // Now, for each row, integrate in y/z-direction,
235 // Then integrate in +x direction
236 for (int i = outerBoundary; i < B.dimension[yCoord]->cells - outerBoundary; i++) {
237 int x = outerBoundary;
238 int y = eqPlane ? i : 0;
239 int z = eqPlane ? 0 : i;
240 if (isInside(B, innerBoundary, x, y, z)) {
241 break;
242 }
243
244 Vec3d bval = B.getCell(x, y, z);
245
246 left_flux -= bval[0] * B.dx[yCoord];
247 flux[B.dimension[0]->cells * i + x] = left_flux;
248
249 tmp_flux = left_flux;
250 for(x++; x < B.dimension[0]->cells - outerBoundary; x++) {
251 if (isInside(B, innerBoundary, x, y, z)) {
252 break;
253 }
254
255 bval = B.getCell(x,y,z);
256
257 tmp_flux += bval[yCoord] * B.dx[0];
258 flux[B.dimension[0]->cells * i + x] = tmp_flux;
259 }
260 }
261
262 return flux;
263}
264
265// Calculate fluxfunction by integrating along +y/z boundary
266// Then along the -x boundary
267// And finally right in the +x direction
268std::vector<double> computeFluxDownRight(Field& B, int outerBoundary, double innerBoundary) {
269 // Create fluxfunction-field to be the same shape as B
270 std::vector<double> flux(B.dimension[0]->cells * B.dimension[1]->cells * B.dimension[2]->cells);
271 for (unsigned int i = 0; i < flux.size(); ++i) {
272 flux[i] = NAN;
273 }
274
275 bool eqPlane = B.dimension[1]->cells > 1;
276 int yCoord = eqPlane ? 1 : 2;
277
278 long double tmp_flux=0.;
279 long double left_flux=0.;
280
281 // Calculate flux-difference between bottom and top edge
282 // of +x boundary (so that values are consistent with computeFluxUp)
283 for(int i = outerBoundary; i < B.dimension[yCoord]->cells - outerBoundary; i++) {
284 int x = B.dimension[0]->cells - (outerBoundary + 1);
285 int y = eqPlane ? i : 0;
286 int z = eqPlane ? 0 : i;
287 if (isInside(B, innerBoundary, x, y, z)) {
288 break;
289 }
290
291 Vec3d bval = B.getCell(x, y, z);
292
293 left_flux -= bval[0]*B.dx[yCoord];
294 flux[B.dimension[0]->cells * i + x] = left_flux;
295 }
296
297 // Then to left edge
298 for(int x = B.dimension[0]->cells - (outerBoundary + 2); x >= outerBoundary; x--) {
299 int i = B.dimension[yCoord]->cells - (outerBoundary + 1);
300 int y = eqPlane ? i : 0;
301 int z = eqPlane ? 0 : i;
302 if (isInside(B, innerBoundary, x, y, z)) {
303 break;
304 }
305
306 Vec3d bval = B.getCell(x, y, z);
307
308 left_flux -= bval[yCoord]*B.dx[0];
309 flux[B.dimension[0]->cells * i + x] = left_flux;
310 }
311
312 // Now, for each row, integrate in y/z-direction,
313 // Then integrate in +x direction
314 for (int i = B.dimension[yCoord]->cells - (outerBoundary + 2); i >= outerBoundary; i--) {
315 int x = outerBoundary;
316 int y = eqPlane ? i : 0;
317 int z = eqPlane ? 0 : i;
318 if (isInside(B, innerBoundary, x, y, z)) {
319 break;
320 }
321
322 Vec3d bval = B.getCell(x, y, z);
323
324 left_flux += bval[0] * B.dx[yCoord];
325 flux[B.dimension[0]->cells * i + x] = left_flux;
326
327 tmp_flux = left_flux;
328 for(x++; x < B.dimension[0]->cells - outerBoundary; x++) {
329 if (isInside(B, innerBoundary, x, y, z)) {
330 break;
331 }
332
333 bval = B.getCell(x,y,z);
334
335 tmp_flux += bval[yCoord] * B.dx[0];
336 flux[B.dimension[0]->cells * i + x] = tmp_flux;
337 }
338 }
339
340 return flux;
341}
342
343// Get median of vector
344double nanMedian(std::vector<double> &v) {
345 v.erase(std::remove_if(v.begin(), v.end(), [](const double& value) {return !isfinite(value);}), v.end());
346 int n = v.size();
347 if (!n) {
348 return NAN;
349 } else if (n % 2) {
350 std::nth_element(v.begin(), v.begin() + n/2, v.end());
351 return v[n/2];
352 } else {
353 std::nth_element(v.begin(), v.begin() + n/2 - 1, v.end()); // Left median
354 std::nth_element(v.begin(), v.begin() + n/2, v.end()); // Right median
355 return (v[n/2 - 1] + v[n/2])/2;
356 }
357}
358
359// Get mean of vector
360double nanMean(std::vector<double> &v) {
361 v.erase(std::remove_if(v.begin(), v.end(), [](const double& value) {return !isfinite(value);}), v.end());
362 int n = v.size();
363 return n ? std::accumulate(v.begin(), v.end(), 0.0) / n : NAN;
364}
365
366int main(int argc, char** argv) {
367
368 // MPI::Init(argc, argv);
369
370 if(argc < 3) {
371 cerr << "Syntax: fluxfunction input.vlsv output.bin" << endl;
372 cerr << "Output will be two files: output.bin and output.bin.bov." << endl;
373 cerr << "Point visit to the BOV file." << endl;
374 return 1;
375 }
376 string inFile(argv[1]);
377 string outFile(argv[2]);
378
379 // TODO: Don't uselessly read E, we really only care about B.
380 Field E,B,V;
381 readfields(inFile.c_str(),E,B,V,false);
382
383 // Make sure we are working with a 2D simulation here.
384 if(B.dimension[0]->cells > 1 && B.dimension[1]->cells > 1 && B.dimension[2]->cells > 1) {
385 cerr << "This is a 3D simulation output. Flux function calculation only makes sense for 2D data."
386 << endl;
387 exit(1);
388 }
389
390 cerr << "File read, calculating flux function..." << endl;
391
392 double dOuter = 2;
393 double rInner = 5*physicalconstants::R_E; // Default for now
394 std::vector<double> fluxUp, fluxDown, fluxLeft, fluxUR, fluxDR;
395 fluxUp = computeFluxUp(B, dOuter, rInner);
396 fluxDown = computeFluxDown(B, dOuter, rInner);
397 fluxLeft = computeFluxLeft(B, dOuter, rInner);
398 fluxUR = computeFluxUpRight(B, dOuter, rInner);
399 fluxDR = computeFluxDownRight(B, dOuter, rInner);
400
401 for(unsigned int i=0; i<fluxUp.size(); i++) {
402 std::vector<double> v {fluxUp[i], fluxDown[i], fluxLeft[i], fluxUR[i], fluxDR[i]};
403 fluxUp[i] = nanMedian(v);
404 //fluxDown[i] = nanMedian(v);
405 //fluxLeft[i] = nanMean(v);
406 //fluxUR[i] = abs((fluxDown[i] - fluxLeft[i])/fluxDown[i]);
407 //fluxDR[i] = abs((fluxDown[i] - fluxLeft[i])/fluxLeft[i]);
408 }
409
410 cerr << "Done. Writing output..." << endl;
411 // std::cout << "Mean of medians " << nanMean(fluxDown) << std::endl;
412 // std::cout << "Mean of means " << nanMean(fluxLeft) << std::endl;
413 // std::cout << "Mean relative difference " << nanMean(fluxUR) << std::endl;
414 // std::cout << "Mean relative difference " << nanMean(fluxDR) << std::endl;
415 // std::cout << "Maximum difference " << *max_element(fluxUR.begin(), fluxUR.end()) << std::endl;
416 // std::cout << "Maximum difference " << *max_element(fluxDR.begin(), fluxDR.end()) << std::endl;
417
418 // Write output as a visit-compatible BOV file
419 int fd = open(outFile.c_str(), O_CREAT|O_TRUNC|O_WRONLY, 0644);
420 if(!fd || fd == -1) {
421 cerr << "Error: cannot open output file " << outFile << ": " << strerror(errno) << endl;
422 return 1;
423 }
424 size_t size=B.dimension[0]->cells*B.dimension[1]->cells*B.dimension[2]->cells*sizeof(double);
425
426 // Write binary blob
427 for(ssize_t remain=size; remain > 0; ) {
428 remain -= write(fd, ((char*) &(fluxUp[0]))+remain-size, remain);
429 }
430 close(fd);
431
432 // Write BOV header
433 string outBov = outFile + ".bov";
434 FILE* f=fopen(outBov.c_str(), "w");
435 if(!f) {
436 cerr<< "Error: unable to write BOV ascii file " << outBov << ":" << strerror(errno) << endl;
437 return 1;
438 }
439 fprintf(f, "TIME: %lf\n", B.time);
440 fprintf(f, "DATA_FILE: %s\n", outFile.c_str());
441 fprintf(f, "DATA_SIZE: %i %i %i\n", B.dimension[0]->cells, B.dimension[1]->cells, B.dimension[2]->cells);
442 fprintf(f, "DATA_FORMAT: DOUBLE\nVARIABLE: fluxfunction\nDATA_ENDIAN: LITTLE\nCENTERING: zonal\n");
443 fprintf(f, "BRICK_ORIGIN: %lf %lf %lf\n", B.dimension[0]->min, B.dimension[1]->min, B.dimension[2]->min);
444 fprintf(f, "BRICK_SIZE: %lf %lf %lf\n", B.dimension[0]->max - B.dimension[0]->min, B.dimension[1]->max - B.dimension[1]->min, B.dimension[2]->max - B.dimension[2]->min);
445 fprintf(f, "DATA_COMPONENTS: 1\n");
446
447 fclose(f);
448
449 return 0;
450}
fclose(file)
for i
Definition Dispersion.m:24
Numerical propagation V
Definition Dispersion.m:98
#define Vec3d
std::vector< double > computeFluxUpRight(Field &B, int outerBoundary, double innerBoundary)
std::vector< double > computeFluxLeft(Field &B, int outerBoundary, double innerBoundary)
std::vector< double > computeFluxDownRight(Field &B, int outerBoundary, double innerBoundary)
double nanMedian(std::vector< double > &v)
static bool isInside(Field &B, double R, int x, int y, int z)
double nanMean(std::vector< double > &v)
std::vector< double > computeFluxDown(Field &B, int outerBoundary, double innerBoundary)
std::vector< double > computeFluxUp(Field &B, int outerBoundary, double innerBoundary)
Logger & write(Logger &logger)
Definition logger.cpp:193
const Real R_E
Definition common.h:575
#define NAN
void readfields(const char *filename, Field &E, Field &B, Field &V, bool doV=true)
Definition readfields.h:396
Definition field.h:34
int main()