NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
plotasset.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2021 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19#include "plotasset.hpp"
20
21mglData duplicatePoints(const mglData& _mData);
22
23
36void PlotAsset::create(PlotType _t, size_t nDim, size_t nAxes, const std::vector<size_t>& samples, size_t nLayers)
37{
38 if (_t == PT_NONE || !nDim || samples.size() < nDim || samples.size() < nAxes || !nLayers)
39 {
40 type = PT_NONE;
41 return;
42 }
43
44 for (size_t s = 0; s < samples.size(); s++)
45 {
46 if (!samples[s])
47 {
48 type = PT_NONE;
49 return;
50 }
51 }
52
53 type = _t;
54 data.resize(nLayers);
55
56 for (size_t l = 0; l < nLayers; l++)
57 {
58 data[l].first.Create(samples[XCOORD],
59 nDim >= 2 ? samples[YCOORD] : 1,
60 nDim == 3 ? samples[ZCOORD] : 1);
61 data[l].second.Create(samples[XCOORD],
62 nDim >= 2 ? samples[YCOORD] : 1,
63 nDim == 3 ? samples[ZCOORD] : 1);
64 data[l].first.Put(NAN);
65 data[l].second.Put(NAN);
66 }
67
68 if (nAxes)
69 {
70 axes.resize(nAxes);
71
72 for (size_t a = 0; a < nAxes; a++)
73 {
74 axes[a].Create(samples[a]);
75 }
76 }
77}
78
79
92void PlotAsset::writeData(const mu::value_type& val, size_t layer, size_t x, size_t y, size_t z)
93{
94 if (layer >= data.size()
95 || x >= (size_t)data[layer].first.nx
96 || y >= (size_t)data[layer].first.ny
97 || z >= (size_t)data[layer].first.nz)
99
100 data[layer].first.a[x + data[layer].first.nx*y + data[layer].first.nx*data[layer].first.ny*z] = mu::isinf(val) ? NAN : val.real();
101 data[layer].second.a[x + data[layer].second.nx*y + data[layer].second.nx*data[layer].second.ny*z] = mu::isinf(val) ? NAN : val.imag();
102}
103
104
115void PlotAsset::writeAxis(double val, size_t pos, PlotCoords c)
116{
117 if (c >= axes.size())
118 return;
119
120 if (pos >= (size_t)axes[c].nx)
122
123 axes[c].a[pos] = isinf(val) ? NAN : val;
124}
125
126
136{
137 for (size_t l = 0; l < data.size(); l++)
138 {
139 data[l].first = ::duplicatePoints(data[l].first);
140 data[l].second = ::duplicatePoints(data[l].second);
141 }
142
143 for (size_t n = 0; n < axes.size(); n++)
144 {
145 axes[n] = ::duplicatePoints(axes[n]);
146 }
147}
148
149
162{
163 if (c < axes.size())
164 {
165 for (int n = 0; n < axes[c].GetNN(); n++)
166 {
167 axes[c].a[n] = axes[c].a[n] >= 0.0 ? axes[c].a[n] : NAN;
168 }
169 }
170 else if (c - axes.size() < data.size())
171 {
172 for (int i = 0; i < data[c-axes.size()].first.GetNN(); i++)
173 {
174 data[c-axes.size()].first.a[i] = data[c-axes.size()].first.a[i] >= 0.0
175 ? data[c-axes.size()].first.a[i] : NAN;
176 data[c-axes.size()].second.a[i] = data[c-axes.size()].second.a[i] >= 0.0
177 ? data[c-axes.size()].second.a[i] : NAN;
178 }
179 }
180}
181
182
192{
193 if (c >= axes.size())
194 return Interval();
195
196 return Interval(axes[c].Minimal(), axes[c].Maximal());
197}
198
199
209{
210 IntervalSet ivl;
211
212 if (layer >= data.size())
213 {
214 // Always return an "valid" intervalset
215 ivl.intervals.resize(4);
216 return ivl;
217 }
218
219 ivl.intervals.push_back(Interval(data[layer].first.Minimal(), data[layer].first.Maximal()));
220 ivl.intervals.push_back(Interval(data[layer].second.Minimal(), data[layer].second.Maximal()));
221 ivl.intervals.push_back(ivl[0].combine(ivl[1]));
222 mglData normData = norm(layer);
223 ivl.intervals.push_back(Interval(normData.Minimal(), normData.Maximal()));
224 ivl.setNames({"Re", "Im", "ReIm", "AbsReIm"});
225
226 return ivl;
227}
228
229
238mglData PlotAsset::norm(size_t layer) const
239{
240 if (layer >= data.size())
241 return mglData();
242
243 mglData absData = data[layer].first * data[layer].first + data[layer].second*data[layer].second;
244
245 for (int i = 0; i < absData.GetNN(); i++)
246 absData.a[i] = sqrt(absData.a[i]);
247
248 return absData;
249}
250
251
260mglData PlotAsset::arg(size_t layer) const
261{
262 if (layer >= data.size())
263 return mglData();
264
265 mglData phaseData(data[layer].first.nx, data[layer].first.ny, data[layer].first.nz);
266
267 for (int i = 0; i < phaseData.GetNN(); i++)
268 phaseData.a[i] = atan2(data[layer].second.a[i], data[layer].first.a[i]);
269
270 return phaseData;
271}
272
273
282bool PlotAsset::isComplex(size_t layer) const
283{
284 if (layer >= data.size())
285 return false;
286
287 return data[layer].second.Minimal() != 0.0 || data[layer].second.Maximal() != 0.0;
288}
289
290
301{
302 if (c < axes.size())
303 {
304 for (int n = 0; n < axes[c].nx; n++)
305 {
306 axes[c].a[n] = ::fmod(axes[c].a[n], mod);
307
308 if (axes[c].a[n] < 0)
309 axes[c].a[n] += mod;
310 }
311 }
312 else if (c - axes.size() < data.size())
313 {
314 for (int n = 0; n < data[c-axes.size()].first.GetNN(); n++)
315 {
316 data[c-axes.size()].first.a[n] = ::fmod(data[c-axes.size()].first.a[n], mod);
317 data[c-axes.size()].second.a[n] = ::fmod(data[c-axes.size()].second.a[n], mod);
318
319 if (data[c-axes.size()].first.a[n] < 0)
320 data[c-axes.size()].first.a[n] += mod;
321
322 if (data[c-axes.size()].second.a[n] < 0)
323 data[c-axes.size()].second.a[n] += mod;
324 }
325 }
326}
327
328
337{
338 int maxdim = data[0].first.nx;
339
340 // Find the largest vector
341 for (size_t val = 1; val < data.size(); val++)
342 {
343 if (maxdim < data[val].first.nx)
344 maxdim = data[val].first.nx;
345 }
346
347 // Create the target array and copy the data
348 mglData _mData(maxdim, data.size());
349
350 for (size_t val = 0; val < data.size(); val++)
351 {
352 for (int col = 0; col < data[val].first.nx; col++)
353 {
354 _mData.a[col + val * maxdim] = data[val].first.a[col];
355 }
356 }
357
358 return _mData;
359}
360
361
371IntervalSet PlotAsset::getWeightedRanges(size_t layer, double dLowerPercentage, double dUpperPercentage) const
372{
373 IntervalSet ivl;
374 ivl.intervals.resize(2);
375
376 if (layer >= data.size())
377 return ivl;
378
379 mglData cp(data[layer].first);
380 size_t nLength = qSortDouble(cp.a, cp.GetNN());
381 size_t lowerpos = rint(fabs(1.0-dLowerPercentage)/2.0*(nLength));
382 size_t upperpos = rint((dUpperPercentage/2.0+0.5)*(nLength));
383
384 ivl[0].reset(cp.a[lowerpos], cp.a[upperpos]);
385
386 cp = data[layer].second;
387 nLength = qSortDouble(cp.a, cp.GetNN());
388 lowerpos = rint(fabs(1.0-dLowerPercentage)/2.0*(nLength));
389 upperpos = rint((dUpperPercentage/2.0+0.5)*(nLength));
390
391 ivl[1].reset(cp.a[lowerpos], cp.a[upperpos]);
392
393 return ivl;
394}
395
396
397
399// PLOTASSETMANAGER
401
402
403
414{
415 IntervalSet ivl;
416 ivl.intervals.resize(DATIVLCOUNT);
417
418 for (size_t i = 0; i < assets.size(); i++)
419 {
420 if (assets[i].type != t)
421 continue;
422
423 if (coord == ALLRANGES
424 || (coord == ONLYLEFT && assets[i].boundAxes.find('l') != std::string::npos)
425 || (coord == ONLYRIGHT && assets[i].boundAxes.find('r') != std::string::npos))
426 {
427 IntervalSet dataIntervals;
428
429 for (size_t l = 0; l < assets[i].getLayers(); l++)
430 {
431 dataIntervals = assets[i].getDataIntervals(l);
432
433 for (int n = 0; n < DATIVLCOUNT; n++)
434 ivl[n] = ivl[n].combine(dataIntervals[n]);
435 }
436 }
437 else
438 {
439 if ((int)assets[i].getLayers() <= coord)
440 continue;
441
442 IntervalSet dataIntervals = assets[i].getDataIntervals(coord);
443
444 for (int n = 0; n < DATIVLCOUNT; n++)
445 ivl[n] = ivl[n].combine(dataIntervals[n]);
446 }
447 }
448
449 return ivl;
450}
451
452
462{
463 IntervalSet ivl;
464 ivl.intervals.resize(3);
465
466 for (size_t i = 0; i < assets.size(); i++)
467 {
468 if (assets[i].type != t)
469 continue;
470
471 for (size_t c = 0; c < std::min(3u, assets[i].getDim()); c++)
472 {
473 ivl[c] = ivl[c].combine(assets[i].getAxisInterval((PlotCoords)c));
474 }
475 }
476
477 return ivl;
478}
479
480
490{
491 std::pair<double, double> maxnorm(0, 0);
492
493 for (const PlotAsset& ass : assets)
494 {
495 for (size_t layer = 0; layer < ass.getLayers(); layer++)
496 {
497 IntervalSet ivl = ass.getDataIntervals(layer);
498
499 if (maxnorm.first < std::max(fabs(ivl[REAL].min()), fabs(ivl[REAL].max())))
500 maxnorm.first = std::max(fabs(ivl[REAL].min()), fabs(ivl[REAL].max()));
501
502 if (maxnorm.second < std::max(fabs(ivl[IMAG].min()), fabs(ivl[IMAG].max())))
503 maxnorm.second = std::max(fabs(ivl[IMAG].min()), fabs(ivl[IMAG].max()));
504 }
505 }
506
507 if (!t_animate)
508 m_maxnorm = maxnorm;
509
510 for (PlotAsset& ass : assets)
511 {
512 for (size_t layer = 0; layer < ass.getLayers(); layer++)
513 {
514 if (maxnorm.first)
515 ass.data[layer].first /= maxnorm.first * maxnorm.first / m_maxnorm.first;
516
517 if (maxnorm.second)
518 ass.data[layer].second /= maxnorm.second * maxnorm.second / m_maxnorm.second;
519 }
520 }
521}
522
523
533{
534 return getIntervalsOfType(PT_DATA, coord);
535}
536
537
547{
548 return getIntervalsOfType(PT_FUNCTION, coord);
549}
550
551
561IntervalSet PlotAssetManager::getWeightedFunctionIntervals(int coord, double dLowerPercentage, double dUpperPercentage) const
562{
563 IntervalSet ivl;
564 ivl.intervals.resize(2);
565
566 for (size_t i = 0; i < assets.size(); i++)
567 {
568 if (assets[i].type != PT_FUNCTION)
569 continue;
570
571 if (coord == ALLRANGES
572 || (coord == ONLYLEFT && assets[i].boundAxes.find('l') != std::string::npos)
573 || (coord == ONLYRIGHT && assets[i].boundAxes.find('r') != std::string::npos))
574 {
575 IntervalSet dataIntervals;
576
577 for (size_t l = 0; l < assets[i].getLayers(); l++)
578 {
579 dataIntervals = assets[i].getWeightedRanges(l, dLowerPercentage, dUpperPercentage);
580 ivl[REAL] = ivl[REAL].combine(dataIntervals[REAL]);
581 ivl[IMAG] = ivl[IMAG].combine(dataIntervals[IMAG]);
582 }
583 }
584 else
585 {
586 if ((int)assets[i].getLayers() <= coord)
587 continue;
588
589 IntervalSet dataIntervals = assets[i].getWeightedRanges(coord, dLowerPercentage, dUpperPercentage);
590 ivl[REAL] = ivl[REAL].combine(dataIntervals[REAL]);
591 ivl[IMAG] = ivl[IMAG].combine(dataIntervals[IMAG]);
592 }
593 }
594
595 return ivl;
596}
597
598
607{
609}
610
611
620{
622}
623
624
636void PlotAssetManager::weightedRange(int coord, Interval& ivl) const
637{
638 if (log(ivl.range()) > 5)
639 {
640 const double dPercentage = 0.975;
641 const double dSinglePercentageValue = 0.99;
642 double dSinglePercentageUse;
643
644 if (coord == ALLRANGES)
645 dSinglePercentageUse = dSinglePercentageValue;
646 else
647 dSinglePercentageUse = dPercentage;
648
649 if (log(fabs(ivl.min())) <= 1)
650 ivl = getWeightedFunctionIntervals(coord, 1.0, dSinglePercentageUse)[0];
651 else if (log(fabs(ivl.max())) <= 1)
652 ivl = getWeightedFunctionIntervals(coord, dSinglePercentageUse, 1.0)[0];
653 else
654 ivl = getWeightedFunctionIntervals(coord, dPercentage, dPercentage)[0];
655 }
656}
657
658
667{
668 for (const PlotAsset& ass : assets)
669 {
670 if (ass.type == PT_DATA)
671 return true;
672 }
673
674 return false;
675}
676
677
689{
690 // Do not apply cartesian coordinates
691 if (coords == CARTESIAN)
692 return;
693
694 for (size_t i = 0; i < assets.size(); i += every)
695 {
696 // Special case for 1D plots, as there are only two
697 // possible valid combinations
698 if (assets[i].getDim() == 1)
699 {
700 switch (coords)
701 {
702 case POLAR_PZ:
703 case SPHERICAL_PT:
704 assets[i].applyModulus(XCOORD, 2.0*M_PI);
705 assets[i].removeNegativeValues(YCOORD);
706 break;
707 case POLAR_RP:
708 case POLAR_RZ:
709 case SPHERICAL_RP:
710 case SPHERICAL_RT:
711 assets[i].applyModulus(YCOORD, 2.0*M_PI);
712 assets[i].removeNegativeValues(XCOORD);
713 break;
714 case CARTESIAN: break;
715 }
716 }
717 else
718 {
719 switch (coords)
720 {
721 case POLAR_PZ:
722 assets[i].applyModulus(XCOORD, 2.0*M_PI);
723 assets[i].removeNegativeValues(ZCOORD);
724 break;
725 case POLAR_RP:
726 assets[i].applyModulus(YCOORD, 2.0*M_PI);
727 assets[i].removeNegativeValues(XCOORD);
728 break;
729 case POLAR_RZ:
730 assets[i].applyModulus(ZCOORD, 2.0*M_PI);
731 assets[i].removeNegativeValues(XCOORD);
732 break;
733 case SPHERICAL_PT:
734 assets[i].applyModulus(XCOORD, 2.0*M_PI);
735 assets[i].applyModulus(YCOORD, 1.00001*M_PI);
736 assets[i].removeNegativeValues(ZCOORD);
737 break;
738 case SPHERICAL_RP:
739 assets[i].applyModulus(YCOORD, 2.0*M_PI);
740 assets[i].applyModulus(ZCOORD, 1.00001*M_PI);
741 assets[i].removeNegativeValues(XCOORD);
742 break;
743 case SPHERICAL_RT:
744 assets[i].applyModulus(ZCOORD, 2.0*M_PI);
745 assets[i].applyModulus(YCOORD, 1.00001*M_PI);
746 assets[i].removeNegativeValues(XCOORD);
747 break;
748 case CARTESIAN: break;
749 }
750 }
751 }
752}
753
754
This class represents a single interval in code providing reading access functionality.
Definition: interval.hpp:34
double range() const
Return the real inteval range of this interval.
Definition: interval.cpp:265
double max() const
Return the maximal element in the interval.
Definition: interval.cpp:252
double min() const
Return the minimal element in the interval.
Definition: interval.cpp:239
void weightedRange(int coord, Interval &ivl) const
This member function does the "undefined data point" magic, where the range of the plot is chosen so ...
Definition: plotasset.cpp:636
IntervalSet getIntervalsOfType(PlotType t, int coord) const
Returns the intervals fitting to all selected data and type.
Definition: plotasset.cpp:413
IntervalSet getFunctionAxes() const
Returns the axis intervals of function plots.
Definition: plotasset.cpp:619
IntervalSet getDataIntervals(int coord=ALLRANGES) const
Returns the intervals fitting to all selected data.
Definition: plotasset.cpp:532
IntervalSet getFunctionIntervals(int coord=ALLRANGES) const
Returns the intervals fitting to all selected data.
Definition: plotasset.cpp:546
IntervalSet getDataAxes() const
Returns the axis intervals of data plots.
Definition: plotasset.cpp:606
bool hasDataPlots() const
Returns true, if the manager contains some data plots.
Definition: plotasset.cpp:666
void applyCoordSys(CoordinateSystem coords, size_t every=1)
Apply the necessary transformation for the selected coordinate system to the managed assets.
Definition: plotasset.cpp:688
IntervalSet getWeightedFunctionIntervals(int coord=ALLRANGES, double dLowerPercentage=1.0, double dUpperPercentage=1.0) const
Returns the central function quantiles.
Definition: plotasset.cpp:561
std::pair< double, double > m_maxnorm
Definition: plotasset.hpp:205
void normalize(int t_animate)
Normalize the managed data to be below 1 (or the starting amplitude in an animation).
Definition: plotasset.cpp:489
std::vector< PlotAsset > assets
Definition: plotasset.hpp:193
IntervalSet getAxisIntervalsOfType(PlotType t) const
Returns the axis intervals of the selected type.
Definition: plotasset.cpp:461
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ PLOT_ERROR
Definition: error.hpp:189
MUP_BASETYPE value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:251
bool isinf(const value_type &v)
Definition: muParserDef.h:374
value_type rint(value_type v)
mglData duplicatePoints(const mglData &_mData)
This static function is a fix for the MathGL bug, which connects points outside of the data range.
Definition: plotting.cpp:157
@ ALLRANGES
Definition: plotasset.hpp:180
@ ONLYLEFT
Definition: plotasset.hpp:181
@ ONLYRIGHT
Definition: plotasset.hpp:182
PlotType
Definition: plotdef.hpp:24
@ PT_NONE
Definition: plotdef.hpp:25
@ PT_FUNCTION
Definition: plotdef.hpp:26
@ PT_DATA
Definition: plotdef.hpp:27
CoordinateSystem
Definition: plotdef.hpp:59
@ POLAR_RP
Definition: plotdef.hpp:62
@ POLAR_RZ
Definition: plotdef.hpp:63
@ SPHERICAL_RP
Definition: plotdef.hpp:65
@ POLAR_PZ
Definition: plotdef.hpp:61
@ SPHERICAL_RT
Definition: plotdef.hpp:66
@ SPHERICAL_PT
Definition: plotdef.hpp:64
@ CARTESIAN
Definition: plotdef.hpp:60
PlotCoords
Definition: plotdef.hpp:40
@ ZCOORD
Definition: plotdef.hpp:43
@ XCOORD
Definition: plotdef.hpp:41
@ YCOORD
Definition: plotdef.hpp:42
#define min(a, b)
Definition: resampler.cpp:34
#define M_PI
Definition: resampler.cpp:47
#define max(a, b)
Definition: resampler.cpp:30
This class represents a set of intervals used together for calculations and simulations.
Definition: interval.hpp:84
void setNames(const std::vector< std::string > &vNames)
Set the interval names.
Definition: interval.cpp:677
std::vector< Interval > intervals
Definition: interval.hpp:85
A single plot data asset to be plotted. Contains the data, its axes and its type.
Definition: plotasset.hpp:37
std::vector< mglData > axes
Definition: plotasset.hpp:39
mglData norm(size_t layer) const
Get the absolute value of the complex value contained within this asset.
Definition: plotasset.cpp:238
IntervalSet getWeightedRanges(size_t layer=0, double dLowerPercentage=1.0, double dUpperPercentage=1.0) const
Get the centralized data quantiles.
Definition: plotasset.cpp:371
mglData arg(size_t layer) const
Get the phase angle of the complex value contained within this asset.
Definition: plotasset.cpp:260
void duplicatePoints()
This function is a fix for the MathGL bug, which connects points outside of the data range.
Definition: plotasset.cpp:135
void applyModulus(PlotCoords c, double mod)
Apply a modulus to a selected axis (e.g. for curvilinear coordinates).
Definition: plotasset.cpp:300
std::vector< std::pair< mglData, mglData > > data
Definition: plotasset.hpp:38
IntervalSet getDataIntervals(size_t layer=0) const
Return the internal data arrays for real and imaginary values.
Definition: plotasset.cpp:208
void writeData(const mu::value_type &val, size_t layer, size_t x, size_t y=0, size_t z=0)
Convenience function to write multi- dimensional data to the internal data object.
Definition: plotasset.cpp:92
bool isComplex(size_t layer=0) const
Return true, if the internal data is complex valued.
Definition: plotasset.cpp:282
void removeNegativeValues(PlotCoords c)
This function is a fix for the MathGL bug to connect points, which are out of data range....
Definition: plotasset.cpp:161
PlotType type
Definition: plotasset.hpp:40
mglData vectorsToMatrix() const
Converts the vectors in multiple layers into a single matrix.
Definition: plotasset.cpp:336
void writeAxis(double val, size_t pos, PlotCoords c=XCOORD)
Convenience function to write the axis values.
Definition: plotasset.cpp:115
void create(PlotType _t, size_t nDim, size_t nAxes, const std::vector< size_t > &samples, size_t nLayers=1)
Prepares the internal memory to fit the desired elements.
Definition: plotasset.cpp:36
Interval getAxisInterval(PlotCoords c=XCOORD) const
Return the interval, which is governed by the corresponding axis.
Definition: plotasset.cpp:191
size_t qSortDouble(double *dArray, size_t nlength)
This is a wrapper for the standard qsort algorithm. It returns the number of valid elements and sorts...
Definition: tools.cpp:3762