source: src/Fragmentation/Summation/SetValues/SamplingGrid.cpp@ d56e21

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 d56e21 was d56e21, checked in by Frederik Heber <heber@…>, 8 years ago

Added padWithZerosForEvenNumberedSamples(), required by downsample().

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