source: src/Fragmentation/Summation/SetValues/SamplingGrid.cpp@ 6a5eb2

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_StructOpt_integration_tests Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion GeometryObjects Gui_displays_atomic_force_velocity IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks RotateToPrincipalAxisSystem_UndoRedo StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps Ubuntu_1604_changes stable
Last change on this file since 6a5eb2 was 6a5eb2, checked in by Frederik Heber <heber@…>, 8 years ago

SamplingGrid::downsample() uses padWithZerosForEvenNumberedSamples().

  • in the end this requires copying the original grid as we might need to pad it with zeros but should not change the given one.
  • Added some debugging information to downsample().
  • Property mode set to 100644
File size: 34.8 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * SamplingGrid.cpp
26 *
27 * Created on: 25.07.2012
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36// include headers that implement a archive in simple text format
37// otherwise BOOST_CLASS_EXPORT_IMPLEMENT has no effect
38#include <boost/archive/text_oarchive.hpp>
39#include <boost/archive/text_iarchive.hpp>
40
41#include "CodePatterns/MemDebug.hpp"
42
43#include "Fragmentation/Summation/SetValues/SamplingGrid.hpp"
44
45#include <boost/assign.hpp>
46#include <boost/bind.hpp>
47#include <algorithm>
48#include <limits>
49
50#include "CodePatterns/Assert.hpp"
51#include "CodePatterns/Log.hpp"
52
53#include "LinearAlgebra/Vector.hpp"
54
55// static instances
56const double SamplingGrid::zeroOffset[NDIM] = { 0., 0., 0. };
57
58SamplingGrid::SamplingGrid() :
59 SamplingGridProperties()
60{
61 setWindowSize(zeroOffset, zeroOffset);
62 ASSERT( getWindowGridPoints() == (size_t)0,
63 "SamplingGrid::SamplingGrid() - incorrect number of samples given for the window.");
64}
65
66SamplingGrid::SamplingGrid(const double _begin[NDIM],
67 const double _end[NDIM],
68 const int _level) :
69 SamplingGridProperties(_begin, _end, _level)
70{
71 setWindowSize(zeroOffset, zeroOffset);
72 ASSERT( getWindowGridPoints() == (size_t)0,
73 "SamplingGrid::SamplingGrid() - incorrect number of samples given for the window.");
74}
75
76SamplingGrid::SamplingGrid(const double _begin[NDIM],
77 const double _end[NDIM],
78 const int _level,
79 const sampledvalues_t &_sampled_grid) :
80 SamplingGridProperties(_begin, _end, _level),
81 sampled_grid(_sampled_grid)
82{
83 setWindowSize(_begin, _end);
84 ASSERT( getWindowGridPoints() == (size_t)_sampled_grid.size(),
85 "SamplingGrid::SamplingGrid() - incorrect number of samples given for the window.");
86}
87
88SamplingGrid::SamplingGrid(const SamplingGrid &_grid) :
89 SamplingGridProperties(_grid),
90 sampled_grid(_grid.sampled_grid)
91{
92 setWindowSize(_grid.begin_window, _grid.end_window);
93 ASSERT( getWindowGridPoints() == _grid.getWindowGridPoints(),
94 "SamplingGrid::SamplingGrid() - incorrect number of samples given for the window.");
95}
96
97SamplingGrid::SamplingGrid(const SamplingGridProperties &_props) :
98 SamplingGridProperties(_props)
99{
100 setWindowSize(zeroOffset, zeroOffset);
101 ASSERT( getWindowGridPoints() == (size_t)0,
102 "SamplingGrid::SamplingGrid() - incorrect number of samples given for the window.");
103}
104
105SamplingGrid::SamplingGrid(
106 const SamplingGridProperties &_props,
107 const sampledvalues_t &_sampled_grid) :
108 SamplingGridProperties(_props),
109 sampled_grid(_sampled_grid)
110{
111 setWindowSize(_props.begin, _props.end);
112 ASSERT( getWindowGridPoints() == (size_t)_sampled_grid.size(),
113 "SamplingGrid::SamplingGrid() - incorrect number of samples given for the window.");
114}
115
116SamplingGrid::~SamplingGrid()
117{}
118
119bool SamplingGrid::isCongruent(const SamplingGrid &_props) const
120{
121 bool status = true;
122 status &= (static_cast<const SamplingGridProperties &>(*this) ==
123 static_cast<const SamplingGridProperties &>(_props));
124 for(size_t i = 0; i<NDIM; ++i) {
125 status &= begin_window[i] == _props.begin_window[i];
126 status &= end_window[i] == _props.end_window[i];
127 }
128 return status;
129}
130
131SamplingGrid& SamplingGrid::operator=(const SamplingGrid& other)
132{
133 // check for self-assignment
134 if (this != &other) {
135 static_cast<SamplingGridProperties &>(*this) = other;
136 setWindowSize(other.begin_window, other.end_window);
137 sampled_grid = other.sampled_grid;
138 }
139 return *this;
140}
141
142static void multiplyElements(
143 double &dest,
144 const double &source,
145 const double prefactor)
146{
147 dest *= prefactor*(source);
148}
149
150SamplingGrid& SamplingGrid::operator*=(const double _value)
151{
152 std::transform(
153 sampled_grid.begin(), sampled_grid.end(),
154 sampled_grid.begin(),
155 boost::bind(std::multiplies<double>(), _1, _value));
156
157 return *this;
158}
159
160SamplingGrid& SamplingGrid::operator*=(const SamplingGrid& other)
161{
162 // check that grids are compatible
163 if (isEquivalent(other)) {
164 /// get minimum of window
165 double min_begin_window[NDIM];
166 double min_end_window[NDIM];
167 bool doShrink = false;
168 for (size_t index=0; index<NDIM;++index) {
169 if (begin_window[index] <= other.begin_window[index]) {
170 min_begin_window[index] = other.begin_window[index];
171 doShrink = true;
172 } else {
173 min_begin_window[index] = begin_window[index];
174 }
175 if (end_window[index] <= other.end_window[index]) {
176 min_end_window[index] = end_window[index];
177 } else {
178 min_end_window[index] = other.end_window[index];
179 doShrink = true;
180 }
181 }
182 LOG(4, "DEBUG: min begin is " << min_begin_window[0] << "," << min_begin_window[1] << "," << min_begin_window[2] << ".");
183 LOG(4, "DEBUG: min end is " << min_end_window[0] << "," << min_end_window[1] << "," << min_end_window[2] << ".");
184 if (doShrink)
185 shrinkWindow(min_begin_window, min_end_window);
186 addWindowOntoWindow(
187 other.begin_window,
188 other.end_window,
189 begin_window,
190 end_window,
191 sampled_grid,
192 other.sampled_grid,
193 boost::bind(multiplyElements, _1, _2, 1.),
194 sourcewindow);
195 } else {
196 ASSERT(0, "SamplingGrid::operator*=() - multiplying incongruent grids is so far not in the cards.");
197 }
198 return *this;
199}
200
201void SamplingGrid::superposeOtherGrids(const SamplingGrid &other, const double prefactor)
202{
203 /// check that grids are compatible
204 if (isEquivalent(other)) {
205 /// get maximum of window
206 double max_begin_window[NDIM];
207 double max_end_window[NDIM];
208 bool doExtend = false;
209 for (size_t index=0; index<NDIM;++index) {
210 if (begin_window[index] >= other.begin_window[index]) {
211 max_begin_window[index] = other.begin_window[index];
212 doExtend = true;
213 } else {
214 max_begin_window[index] = begin_window[index];
215 }
216 if (end_window[index] >= other.end_window[index]) {
217 max_end_window[index] = end_window[index];
218 } else {
219 max_end_window[index] = other.end_window[index];
220 doExtend = true;
221 }
222 }
223 LOG(4, "DEBUG: max begin is " << max_begin_window[0] << "," << max_begin_window[1] << "," << max_begin_window[2] << ".");
224 LOG(4, "DEBUG: max end is " << max_end_window[0] << "," << max_end_window[1] << "," << max_end_window[2] << ".");
225 if (doExtend)
226 extendWindow(max_begin_window, max_end_window);
227 /// and copy other into larger window, too
228 addOntoWindow(other.begin_window, other.end_window, other.sampled_grid, prefactor);
229 } else {
230 ASSERT(0, "SamplingGrid::superposeOtherGrids() - superposing incompatible grids is so far not in the cards.");
231 }
232}
233
234const size_t SamplingGrid::getWindowGridPointsPerAxis(const size_t axis) const
235{
236 static const double round_offset(
237 (std::numeric_limits<size_t>::round_style == std::round_toward_zero) ?
238 0.5 : 0.); // need offset to get to round_toward_nearest behavior
239// const double total = getTotalLengthPerAxis(axis);
240 const double delta = getDeltaPerAxis(axis);
241 if (delta == 0)
242 return 0;
243 const double length = getWindowLengthPerAxis(axis);
244 if (length == 0)
245 return 0;
246 return (size_t)(length/delta+round_offset);
247}
248
249double SamplingGrid::integral() const
250{
251 const double volume_element = getVolume()/(double)getTotalGridPoints();
252 double int_value = 0.;
253 for (sampledvalues_t::const_iterator iter = sampled_grid.begin();
254 iter != sampled_grid.end();
255 ++iter)
256 int_value += *iter;
257 int_value *= volume_element;
258 LOG(2, "DEBUG: SamplingGrid::integral() is " << scientific << setprecision(13) << int_value << ".");
259 return int_value;
260}
261
262double SamplingGrid::integral(const SamplingGrid &weight) const
263{
264 if (isEquivalent(weight)) {
265 const double volume_element = getVolume()/(double)getTotalGridPoints();
266 double int_value = 0.;
267 sampledvalues_t::const_iterator iter = sampled_grid.begin();
268 sampledvalues_t::const_iterator weightiter = weight.sampled_grid.begin();
269 for (;iter != sampled_grid.end();++iter,++weightiter)
270 int_value += (*weightiter) * (*iter);
271 int_value *= volume_element;
272 //LOG(2, "DEBUG: SamplingGrid::integral() is " << scientific << setprecision(13) << int_value << ".");
273 return int_value;
274 } else
275 return 0.;
276}
277void SamplingGrid::setWindowSize(
278 const double _begin_window[NDIM],
279 const double _end_window[NDIM])
280{
281 for (size_t index=0;index<NDIM;++index) {
282 begin_window[index] = getNearestLowerGridPoint(_begin_window[index], index);
283 ASSERT( begin_window[index] >= begin[index],
284 "SamplingGrid::setWindowSize() - window starts earlier than domain on "
285 +toString(index)+"th component.");
286 end_window[index] = getNearestHigherGridPoint(_end_window[index], index);
287 ASSERT( end_window[index] <= end[index],
288 "SamplingGrid::setWindowSize() - window ends later than domain on "
289 +toString(index)+"th component.");
290 }
291}
292
293void SamplingGrid::setWindow(
294 const double _begin_window[NDIM],
295 const double _end_window[NDIM])
296{
297 setWindowSize(_begin_window, _end_window);
298 const size_t gridpoints_window = getWindowGridPoints();
299 sampled_grid.clear();
300 sampled_grid.resize(gridpoints_window, 0.);
301}
302
303void SamplingGrid::setDomain(
304 const double _begin[NDIM],
305 const double _end[NDIM])
306{
307 setDomainSize(_begin, _end);
308 setWindowSize(_begin, _end);
309 const size_t gridpoints = getTotalGridPoints();
310 sampled_grid.resize(gridpoints, 0.);
311}
312
313void SamplingGrid::extendWindow(
314 const double _begin_window[NDIM],
315 const double _end_window[NDIM])
316{
317#ifndef NDEBUG
318 for(size_t index=0;index < NDIM; ++index) {
319 // check that we truly have to extend the window
320 ASSERT ( begin_window[index] >= _begin_window[index],
321 "SamplingGrid::extendWindow() - component "+toString(index)+
322 " of window start is greater than old value.");
323 ASSERT ( end_window[index] <= _end_window[index],
324 "SamplingGrid::extendWindow() - component "+toString(index)+
325 " of window end is less than old value.");
326
327 // check that we are still less than domain
328 ASSERT ( _begin_window[index] >= begin[index],
329 "SamplingGrid::extendWindow() - component "+toString(index)+
330 " of window start is less than domain start.");
331 ASSERT ( _end_window[index] <= end[index],
332 "SamplingGrid::extendWindow() - component "+toString(index)+
333 " of window end is greater than domain end.");
334 }
335#endif
336 // copy old window size and values
337 double old_begin_window[NDIM];
338 double old_end_window[NDIM];
339 for(size_t index=0;index<NDIM;++index) {
340 old_begin_window[index] = begin_window[index];
341 old_end_window[index] = end_window[index];
342 }
343 sampledvalues_t old_values(sampled_grid);
344 // set new window
345 setWindow(_begin_window,_end_window);
346 // now extend it ...
347 addOntoWindow(old_begin_window, old_end_window, old_values, +1.);
348 LOG(6, "DEBUG: Grid after extension is " << sampled_grid << ".");
349}
350
351void SamplingGrid::shrinkWindow(
352 const double _begin_window[NDIM],
353 const double _end_window[NDIM])
354{
355#ifndef NDEBUG
356 for(size_t index=0;index < NDIM; ++index) {
357 // check that we truly have to shrink the window
358 ASSERT ( begin_window[index] <= _begin_window[index],
359 "SamplingGrid::shrinkWindow() - component "+toString(index)+
360 " of window start is less than old value.");
361 ASSERT ( end_window[index] >= _end_window[index],
362 "SamplingGrid::shrinkWindow() - component "+toString(index)+
363 " of window end is greater than old value.");
364
365 // check that we are still less than domain
366 ASSERT ( _begin_window[index] >= begin[index],
367 "SamplingGrid::shrinkWindow() - component "+toString(index)+
368 " of window start is less than domain start.");
369 ASSERT ( _end_window[index] <= end[index],
370 "SamplingGrid::shrinkWindow() - component "+toString(index)+
371 " of window end is greater than domain end.");
372 }
373#endif
374 // copy old window size and values
375 double old_begin_window[NDIM];
376 double old_end_window[NDIM];
377 for(size_t index=0;index<NDIM;++index) {
378 old_begin_window[index] = begin_window[index];
379 old_end_window[index] = end_window[index];
380 }
381 sampledvalues_t old_values(sampled_grid);
382 // set new window
383 setWindow(_begin_window,_end_window);
384 // now extend it ...
385 addIntoWindow(old_begin_window, old_end_window, old_values, +1.);
386 LOG(6, "DEBUG: Grid after extension is " << sampled_grid << ".");
387}
388
389static void addElements(
390 double &dest,
391 const double &source,
392 const double prefactor)
393{
394 dest += prefactor*(source);
395}
396
397void SamplingGrid::addOntoWindow(
398 const double _begin_window[NDIM],
399 const double _end_window[NDIM],
400 const sampledvalues_t &_sampled_grid,
401 const double prefactor)
402{
403 addWindowOntoWindow(
404 begin_window,
405 end_window,
406 _begin_window,
407 _end_window,
408 sampled_grid,
409 _sampled_grid,
410 boost::bind(addElements, _1, _2, boost::cref(prefactor)),
411 destwindow);
412}
413
414void SamplingGrid::addIntoWindow(
415 const double _begin_window[NDIM],
416 const double _end_window[NDIM],
417 const sampledvalues_t &_sampled_grid,
418 const double prefactor)
419{
420 addWindowOntoWindow(
421 _begin_window,
422 _end_window,
423 begin_window,
424 end_window,
425 sampled_grid,
426 _sampled_grid,
427 boost::bind(addElements, _1, _2, boost::cref(prefactor)),
428 sourcewindow);
429}
430
431void SamplingGrid::getDiscreteWindowIndices(
432 size_t _wbegin[NDIM],
433 size_t _wlength[NDIM],
434 size_t _wend[NDIM]) const
435{
436 const double round_offset =
437 (std::numeric_limits<size_t>::round_style == std::round_toward_zero) ?
438 0.5 : 0.; // need offset to get to round_toward_nearest behavior
439 for(size_t index=0;index<NDIM;++index) {
440 if (fabs(end[index] - begin[index]) > std::numeric_limits<double>::epsilon()*1e4) {
441 // we refrain from using floor/ceil as the window's starts and ends,
442 // the grids have to be compatible (equal level), should always be on
443 // discrete grid point locations.
444 const double delta = getDeltaPerAxis(index);
445 // delta is conversion factor from box length to discrete length, i.e. number of points
446 _wbegin[index] = (begin_window[index] - begin[index])/delta+round_offset;
447 _wlength[index] = (end_window[index] - begin_window[index])/delta+round_offset;
448 _wend[index] = (end_window[index] - begin[index])/delta+round_offset;
449 } else {
450 _wbegin[index] = 0;
451 _wlength[index] = 0;
452 _wend[index] = 0;
453 }
454 // total is used as safe-guard against loss due to discrete conversion
455 ASSERT( (_wend[index] - _wbegin[index]) == _wlength[index],
456 "SamplingGrid::getDiscreteWindowCopyIndices() - end - begin is not equal to length for "
457 +toString(index)+"th component.");
458 }
459}
460
461void SamplingGrid::getDiscreteWindowOffsets(
462 size_t _pre_offset[NDIM],
463 size_t _post_offset[NDIM],
464 size_t _length[NDIM],
465 size_t _total[NDIM]) const
466{
467 const double round_offset =
468 (std::numeric_limits<size_t>::round_style == std::round_toward_zero) ?
469 0.5 : 0.; // need offset to get to round_toward_nearest behavior
470 for(size_t index=0;index<NDIM;++index) {
471 if (fabs(end[index] - begin[index]) > std::numeric_limits<double>::epsilon()*1e4) {
472 // we refrain from using floor/ceil as the window's starts and ends,
473 // the grids have to be compatible (equal level), should always be on
474 // discrete grid point locations.
475 const double delta = getDeltaPerAxis(index);
476 // delta is conversion factor from box length to discrete length, i.e. number of points
477 _pre_offset[index] = (begin_window[index] - begin[index])/delta+round_offset;
478 _post_offset[index] = (end[index] - end_window[index])/delta+round_offset;
479 _length[index] = (end_window[index] - begin_window[index])/delta+round_offset;
480 _total[index] = (end[index] - begin[index])/delta+round_offset;
481 } else {
482 _pre_offset[index] = 0;
483 _post_offset[index] = 0;
484 _length[index] = 0;
485 _total[index] = 0;
486 }
487 // total is used as safe-guard against loss due to discrete conversion
488 ASSERT( (_pre_offset[index] + _post_offset[index]) + _length[index] == _total[index],
489 "SamplingGrid::getDiscreteWindowCopyIndices() - pre, length, post are not equal to total for "
490 +toString(index)+"th component.");
491 }
492}
493
494void SamplingGrid::getDiscreteWindowCopyIndices(
495 const double *larger_wbegin,
496 const double *larger_wend,
497 const double *smaller_wbegin,
498 const double *smaller_wend,
499 size_t *pre_offset,
500 size_t *post_offset,
501 size_t *length,
502 size_t *total) const
503{
504 const double round_offset =
505 (std::numeric_limits<size_t>::round_style == std::round_toward_zero) ?
506 0.5 : 0.; // need offset to get to round_toward_nearest behavior
507 for(size_t index=0;index<NDIM;++index) {
508 if (fabs(end[index] - begin[index]) > std::numeric_limits<double>::epsilon()*1e4) {
509 // we refrain from using floor/ceil as the window's starts and ends,
510 // the grids have to be compatible (equal level), should always be on
511 // discrete grid point locations.
512 const double delta = getDeltaPerAxis(index);
513 // delta is conversion factor from box length to discrete length, i.e. number of points
514 pre_offset[index] = (smaller_wbegin[index] - larger_wbegin[index])/delta+round_offset;
515 length[index] = (smaller_wend[index] - smaller_wbegin[index])/delta+round_offset;
516 post_offset[index] = (larger_wend[index] - smaller_wend[index])/delta+round_offset;
517 total[index] = (larger_wend[index] - larger_wbegin[index])/delta+round_offset;
518 } else {
519 pre_offset[index] = 0;
520 length[index] = 0;
521 post_offset[index] = 0;
522 total[index] = 0;
523 }
524 // total is used as safe-guard against loss due to discrete conversion
525 ASSERT( pre_offset[index]+post_offset[index]+length[index] == total[index],
526 "SamplingGrid::getDiscreteWindowCopyIndices() - pre, post, and length don't sum up to total for "
527 +toString(index)+"th component.");
528 }
529}
530
531void SamplingGrid::addWindowOntoWindow(
532 const double larger_wbegin[NDIM],
533 const double larger_wend[NDIM],
534 const double smaller_wbegin[NDIM],
535 const double smaller_wend[NDIM],
536 sampledvalues_t &dest_sampled_grid,
537 const sampledvalues_t &source_sampled_grid,
538 boost::function<void (double &, const double &)> op,
539 enum eLargerWindow larger_window)
540{
541#ifndef NDEBUG
542 for(size_t index=0;index<NDIM;++index) {
543 ASSERT( smaller_wbegin[index] >= larger_wbegin[index],
544 "SamplingGrid::addWindowOntoWindow() - given smaller window starts earlier than larger window in component "
545 +toString(index)+".");
546 ASSERT( smaller_wend[index] <= larger_wend[index],
547 "SamplingGrid::addWindowOntoWindow() - given smaller window ends later than larger window in component "
548 +toString(index)+".");
549 }
550#endif
551 // the only issue are indices
552 size_t pre_offset[NDIM];
553 size_t post_offset[NDIM];
554 size_t length[NDIM];
555 size_t total[NDIM];
556 getDiscreteWindowCopyIndices(
557 larger_wbegin, larger_wend,
558 smaller_wbegin, smaller_wend,
559 pre_offset,
560 post_offset,
561 length,
562 total
563 );
564 // assert that calculated lengths match with given vector sizes
565#ifndef NDEBUG
566 const size_t calculated_size = length[0]*length[1]*length[2];
567 if (larger_window == destwindow) {
568 ASSERT( calculated_size == source_sampled_grid.size(),
569 "SamplingGrid::addWindowOntoWindow() - not enough source sampled values given: "
570 +toString(calculated_size)+" != "+toString(source_sampled_grid.size())+".");
571 ASSERT( calculated_size <= dest_sampled_grid.size(),
572 "SamplingGrid::addWindowOntoWindow() - not enough sampled values available: "
573 +toString(calculated_size)+" <= "+toString(dest_sampled_grid.size())+".");
574 } else {
575 ASSERT( calculated_size == dest_sampled_grid.size(),
576 "SamplingGrid::addWindowOntoWindow() - not enough dest sampled values given: "
577 +toString(calculated_size)+" != "+toString(dest_sampled_grid.size())+".");
578 ASSERT( calculated_size <= source_sampled_grid.size(),
579 "SamplingGrid::addWindowOntoWindow() - not enough source sampled values available: "
580 +toString(calculated_size)+" <= "+toString(source_sampled_grid.size())+".");
581 }
582 const size_t total_size = total[0]*total[1]*total[2];
583 if (larger_window == destwindow) {
584 ASSERT( total_size == dest_sampled_grid.size(),
585 "SamplingGrid::addWindowOntoWindow() - total size is not equal to number of present dest points: "
586 +toString(total_size)+" != "+toString(dest_sampled_grid.size())+".");
587 } else {
588 ASSERT( total_size == source_sampled_grid.size(),
589 "SamplingGrid::addWindowOntoWindow() - total size is not equal to number of present source points: "
590 +toString(total_size)+" != "+toString(source_sampled_grid.size())+".");
591 }
592#endif
593 size_t N[NDIM];
594// size_t counter = 0;
595 sampledvalues_t::iterator destiter = dest_sampled_grid.begin();
596 sampledvalues_t::const_iterator sourceiter = source_sampled_grid.begin();
597 if (larger_window == destwindow)
598 std::advance(destiter, pre_offset[0]*total[1]*total[2]);
599 else
600 std::advance(sourceiter, pre_offset[0]*total[1]*total[2]);
601 for(N[0]=0; N[0] < length[0]; ++N[0]) {
602 if (larger_window == destwindow)
603 std::advance(destiter, pre_offset[1]*total[2]);
604 else
605 std::advance(sourceiter, pre_offset[1]*total[2]);
606 for(N[1]=0; N[1] < length[1]; ++N[1]) {
607 if (larger_window == destwindow)
608 std::advance(destiter, pre_offset[2]);
609 else
610 std::advance(sourceiter, pre_offset[2]);
611 for(N[2]=0; N[2] < length[2]; ++N[2]) {
612 ASSERT( destiter != dest_sampled_grid.end(),
613 "SamplingGrid::addWindowOntoWindow() - destiter is already at end of window.");
614 ASSERT( sourceiter != source_sampled_grid.end(),
615 "SamplingGrid::addWindowOntoWindow() - sourceiter is already at end of window.");
616 op(*destiter, *sourceiter);
617 ++destiter;
618 ++sourceiter;
619 }
620 if (larger_window == destwindow)
621 std::advance(destiter, post_offset[2]);
622 else
623 std::advance(sourceiter, post_offset[2]);
624 }
625 if (larger_window == destwindow)
626 std::advance(destiter, post_offset[1]*total[2]);
627 else
628 std::advance(sourceiter, post_offset[1]*total[2]);
629 }
630#ifndef NDEBUG
631 if (larger_window == destwindow)
632 std::advance(destiter, post_offset[0]*total[1]*total[2]);
633 else
634 std::advance(sourceiter, post_offset[0]*total[1]*total[2]);
635 ASSERT( destiter == dest_sampled_grid.end(),
636 "SamplingGrid::addWindowOntoWindow() - destiter is not at end of window.");
637 ASSERT( sourceiter == source_sampled_grid.end(),
638 "SamplingGrid::addWindowOntoWindow() - sourceiter is not at end of window.");
639#endif
640 LOG(8, "DEBUG: Grid after adding other is " << dest_sampled_grid << ".");
641}
642
643
644bool SamplingGrid::operator==(const SamplingGrid &other) const
645{
646 bool status =
647 static_cast<const SamplingGridProperties &>(*this)
648 == static_cast<const SamplingGridProperties &>(other);
649 // compare general properties
650 if (status) {
651 // compare windows
652 for (size_t i=0; i<NDIM; ++i) {
653 status &= begin_window[i] == other.begin_window[i];
654 status &= end_window[i] == other.end_window[i];
655 }
656 // compare grids
657 if (status)
658 status &= sampled_grid == other.sampled_grid;
659 }
660 return status;
661}
662
663/** Struct contains a single point with displacements from the
664 * central point and the weight in the restriction.
665 */
666struct PointWeight_t {
667 PointWeight_t(const int &d1, const int &d2, const int &d3, const double &_weight) :
668 displacement(NDIM),
669 weight(_weight)
670 {
671 displacement[0] = d1; displacement[1] = d2; displacement[2] = d3;
672 }
673 typedef std::vector<int> displacement_t;
674 displacement_t displacement;
675 double weight;
676};
677
678static void getLengthsOfWindow(
679 int _total[NDIM],
680 const SamplingGrid &_grid)
681{
682 const size_t gridpoints_axis = _grid.getGridPointsPerAxis();
683 static const double round_offset =
684 (std::numeric_limits<size_t>::round_style == std::round_toward_zero) ?
685 0.5 : 0.; // need offset to get to round_toward_nearest behavior
686 for (size_t index=0; index<NDIM; ++index) {
687 if (fabs(_grid.end[index] - _grid.begin[index]) > std::numeric_limits<double>::epsilon()*1e4) {
688 const double delta = (double)gridpoints_axis/(_grid.end[index] - _grid.begin[index]);
689 _total[index] = delta*(_grid.end_window[index] - _grid.begin_window[index])+round_offset;
690 } else
691 _total[index] = 0;
692 // we can only assert that its atmost the maximum number of grid points
693 ASSERT (_total[index] <= ::pow(2, _grid.level),
694 "SamplingGrid::downsample() - total "+toString(_total[index])
695 +" is not equal or less than 2^level: "+toString(_grid.level));
696 }
697}
698
699//!> stencil for full weight restriction, see vmg's stencils.hpp
700static const std::vector< PointWeight_t > FullWeightNearestNeighbor =
701 boost::assign::list_of
702 ( PointWeight_t( 0, 0, 0, 0.125) )
703 ( PointWeight_t( 1, 0, 0, 0.0625) )
704 ( PointWeight_t(-1, 0, 0, 0.0625) )
705 ( PointWeight_t( 0, 1, 0, 0.0625) )
706 ( PointWeight_t( 0, -1, 0, 0.0625) )
707 ( PointWeight_t( 0, 0, 1, 0.0625) )
708 ( PointWeight_t( 0, 0, -1, 0.0625) )
709 ( PointWeight_t( 1, 1, 0, 0.03125) )
710 ( PointWeight_t( 1, -1, 0, 0.03125) )
711 ( PointWeight_t(-1, 1, 0, 0.03125) )
712 ( PointWeight_t(-1, -1, 0, 0.03125) )
713 ( PointWeight_t( 0, 1, 1, 0.03125) )
714 ( PointWeight_t( 0, 1, -1, 0.03125) )
715 ( PointWeight_t( 0, -1, 1, 0.03125) )
716 ( PointWeight_t( 0, -1, -1, 0.03125) )
717 ( PointWeight_t( 1, 0, 1, 0.03125) )
718 ( PointWeight_t( 1, 0, -1, 0.03125) )
719 ( PointWeight_t(-1, 0, 1, 0.03125) )
720 ( PointWeight_t(-1, 0, -1, 0.03125) )
721 ( PointWeight_t( 1, 1, 1, 0.015625) )
722 ( PointWeight_t( 1, 1, -1, 0.015625) )
723 ( PointWeight_t( 1, -1, 1, 0.015625) )
724 ( PointWeight_t(-1, 1, 1, 0.015625) )
725 ( PointWeight_t( 1, -1, -1, 0.015625) )
726 ( PointWeight_t(-1, 1, -1, 0.015625) )
727 ( PointWeight_t(-1, -1, 1, 0.015625) )
728 ( PointWeight_t(-1, -1, -1, 0.015625) )
729;
730
731int getValidIndex(
732 const PointWeight_t::displacement_t &_disp,
733 const int N[NDIM],
734 const int length[NDIM])
735{
736 int index = 0;
737 // we simply truncate in case of out of bounds access
738 if ((N[2]+_disp[2] >= 0) && (N[2]+_disp[2] < length[2]))
739 index += _disp[2];
740 if ((N[1]+_disp[1] >= 0) && (N[1]+_disp[1] < length[1]))
741 index += _disp[1]*length[2];
742 if ((N[0]+_disp[0] >= 0) && (N[0]+_disp[0] < length[0]))
743 index += _disp[0]*length[1]*length[2];
744 return index;
745}
746
747void restrictFullWeight(
748 SamplingGrid::sampledvalues_t &_coarse_level,
749 const int length_c[NDIM],
750 const SamplingGrid::sampledvalues_t &_fine_level,
751 const int length_f[NDIM])
752{
753 int N_c[NDIM];
754 int N_f[NDIM];
755 SamplingGrid::sampledvalues_t::iterator coarseiter = _coarse_level.begin();
756 for(N_c[0]=0, N_f[0]=0; (N_c[0] < length_c[0]) && (N_f[0] < length_f[0]); ++N_c[0], N_f[0] +=2) {
757 for(N_c[1]=0, N_f[1]=0; (N_c[1] < length_c[1]) && (N_f[1] < length_f[1]); ++N_c[1], N_f[1] +=2) {
758 for(N_c[2]=0, N_f[2]=0; (N_c[2] < length_c[2]) && (N_f[2] < length_f[2]); ++N_c[2], N_f[2] +=2) {
759 const int index_base = N_f[2] + (N_f[1] + N_f[0]*length_f[1])*length_f[2];
760 // go through stencil and add each point relative to displacement with weight
761 for (std::vector< PointWeight_t >::const_iterator weightiter = FullWeightNearestNeighbor.begin();
762 weightiter != FullWeightNearestNeighbor.end(); ++weightiter) {
763 const PointWeight_t::displacement_t disp = weightiter->displacement;
764 const int index_disp = getValidIndex(disp, N_f, length_f);
765 *coarseiter += _fine_level[index_base+index_disp]*weightiter->weight;
766 }
767 ++coarseiter;
768 }
769 ASSERT ( (N_c[2] == length_c[2]) && (N_f[2] == length_f[2]),
770 "restrictFullWeight() - N_c "+toString(N_c[2])+" != length_c "+toString(length_c[2])
771 +" or N_f "+toString(N_f[2])+" != length_f "+toString(length_f[2]));
772 }
773 ASSERT ( (N_c[1] == length_c[1]) && (N_f[1] == length_f[1]),
774 "restrictFullWeight() - N_c "+toString(N_c[1])+" != length_c "+toString(length_c[1])
775 +" or N_f "+toString(N_f[1])+" != length_f "+toString(length_f[1]));
776 }
777 ASSERT ( (N_c[0] == length_c[0]) && (N_f[0] == length_f[0]),
778 "restrictFullWeight() - N_c "+toString(N_c[0])+" != length_c "+toString(length_c[0])
779 +" or N_f "+toString(N_f[0])+" != length_f "+toString(length_f[0]));
780 ASSERT( coarseiter == _coarse_level.end(),
781 "restrictFullWeight() - coarseiter is not at end of values.");
782}
783
784void SamplingGrid::padWithZerosForEvenNumberedSamples()
785{
786 size_t wbegin_index[NDIM];
787 size_t wend_index[NDIM];
788 size_t wlength_index[NDIM];
789 getDiscreteWindowIndices(wbegin_index, wlength_index, wend_index);
790
791 // calculate new window (always extend it such that both indices are even)
792 bool changed = false;
793 size_t wnewbegin_index[NDIM];
794 size_t wnewend_index[NDIM];
795 for(size_t i=0;i<NDIM;++i) {
796 LOG(2, "INFO: window[" << i << "] starts at " << wbegin_index[i] << " and ends at "
797 << wend_index[i] << " with length " << wlength_index[i]);
798 // We require begin and end of window on even indices (and inside grid).
799 wnewbegin_index[i] = wbegin_index[i];
800 if ((wnewbegin_index[i] % (size_t)2) != 0) {
801 if (wnewbegin_index[i] > 0)
802 --wnewbegin_index[i];
803 else
804 wnewbegin_index[i] = 0;
805 changed = true;
806 }
807 wnewend_index[i] = wend_index[i];
808 if ((wnewend_index[i] % (size_t)2) != 0) {
809 if (wnewend_index[i] < getGridPointsPerAxis())
810 ++wnewend_index[i];
811 else
812 wnewend_index[i] = getGridPointsPerAxis();
813 changed = true;
814 }
815 ASSERT( (wbegin_index[i] >= 0) && (wend_index[i] <= getGridPointsPerAxis()),
816 "SamplingGrid::padWithZerosForEvenNumberedSamples() - indices "
817 +toString(wbegin_index[i])+" and "+toString(wend_index[i])+" larger than grid "
818 +toString(getGridPointsPerAxis())+".");
819 }
820 if (changed) {
821 double begin_newwindow[NDIM];
822 double end_newwindow[NDIM];
823 for(size_t i=0;i<NDIM;++i) {
824 const double delta = getDeltaPerAxis(i);
825 begin_newwindow[i] = begin[i]+delta*wnewbegin_index[i];
826 end_newwindow[i] = begin[i]+delta*wnewend_index[i];
827 }
828 LOG(2, "INFO: Original window is " << Vector(begin_window) << " <-> " << Vector(end_window));
829 LOG(2, "INFO: Padded window is " << Vector(begin_newwindow) << " <-> " << Vector(end_newwindow));
830 // extend window
831 extendWindow(begin_newwindow, end_newwindow);
832 }
833 ASSERT( getWindowGridPoints() % (size_t)8 == 0,
834 "SamplingGrid::padWithZerosForEvenNumberedSamples() - new size "
835 +toString(getWindowGridPoints())+" is still not divisible by 8.");
836}
837
838void SamplingGrid::downsample(
839 SamplingGrid& instance,
840 const SamplingGrid& other,
841 const int _level)
842{
843 if (&instance != &other) {
844 LOG(2, "INFO: other's window is " << Vector(other.begin_window)
845 << " <-> " << Vector(other.end_window));
846 // take over properties
847 static_cast<SamplingGridProperties &>(instance) = other;
848 instance.setWindowSize(other.begin_window, other.end_window);
849 LOG(2, "INFO: Set instance's window to " << Vector(instance.begin_window)
850 << " <-> " << Vector(instance.end_window));
851 ASSERT( _level <= other.level,
852 "SamplingGrid::downsample() - desired level "+toString(_level)
853 +" larger than level "+toString(other.level)+" of the given values.");
854 if (_level == other.level) {
855 instance.sampled_grid = other.sampled_grid;
856 } else {
857 // if desired level is smaller we need to downsample
858 // we do this similarly to vmg::RestrictionFullWeight (i.e. a full nearest
859 // neighbor interpolation) and always one grid level at a time till we
860 // have reached the desired one
861
862 // we need to copy the other grid because we might need to pad it with zeros anyway
863 SamplingGrid FinerGrid(other);
864 int length_d[NDIM];
865 int length_s[NDIM];
866 for (instance.level = other.level-1; instance.level >= _level; --instance.level) {
867 // pad with zeros for even indices and get length of fine grid window
868 FinerGrid.padWithZerosForEvenNumberedSamples();
869 getLengthsOfWindow(length_s, FinerGrid);
870 ASSERT( FinerGrid.getWindowGridPoints() % 8 == 0,
871 "SamplingGrid::downsample() - at level "+toString( instance.level)
872 +" given grid points "+toString(FinerGrid.getWindowGridPoints())+" are not even numbered per axis anymore.");
873 // re-adjust the window (length), get the corresponding window length and downsample
874 instance.setWindow(FinerGrid.begin_window, FinerGrid.end_window);
875 getLengthsOfWindow(length_d, instance);
876 ASSERT( instance.sampled_grid.size() == FinerGrid.getWindowGridPoints()/(size_t)8,
877 "SamplingGrid::downsample() - at level "+toString( instance.level)
878 +" points on coarser grid "+toString(instance.sampled_grid.size())
879 +" and downsampled number on finer grid "
880 +toString(FinerGrid.getWindowGridPoints()/(size_t)8)+" do not match.");
881 restrictFullWeight(instance.sampled_grid, length_d, FinerGrid.sampled_grid, length_s);
882 // then use as new finer grid for next downsampling (if it's not the last level)
883 if (instance.level > _level)
884 FinerGrid = instance;
885 }
886 // loop stops at _level-1
887 instance.level = _level;
888
889 // and finally, renormalize downsampled grid to old value
890// instance *= other.integral()/instance.integral();
891 }
892 }
893}
894
895std::ostream & operator<<(std::ostream &ost, const SamplingGrid& other)
896{
897 ost << "SamplingGrid";
898 ost << " starting at " << other.begin[0] << "," << other.begin[1] << "," << other.begin[2];
899 ost << " ending at " << other.end[0] << "," << other.end[1] << "," << other.end[2];
900 ost << ", window starting at " << other.begin_window[0] << "," << other.begin_window[1] << "," << other.begin_window[2];
901 ost << ", window ending at " << other.end_window[0] << "," << other.end_window[1] << "," << other.end_window[2];
902 ost << ", level of " << other.level;
903 ost << " and integrated value of " << other.integral();
904 return ost;
905}
906
907template<> SamplingGrid ZeroInstance<SamplingGrid>()
908{
909 SamplingGrid returnvalue;
910 return returnvalue;
911}
912
913// we need to explicitly instantiate the serialization functions as
914// its is only serialized through its base class FragmentJob
915BOOST_CLASS_EXPORT_IMPLEMENT(SamplingGrid)
Note: See TracBrowser for help on using the repository browser.