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
RevLine 
[28c025]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. All rights reserved.
[5aaa43]5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
[28c025]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
[fbf143]43#include "Fragmentation/Summation/SetValues/SamplingGrid.hpp"
[28c025]44
[06653a]45#include <boost/assign.hpp>
[fb3485]46#include <boost/bind.hpp>
[8eafd6]47#include <algorithm>
[98f8fe]48#include <limits>
49
[c889b7]50#include "CodePatterns/Assert.hpp"
[cb3363]51#include "CodePatterns/Log.hpp"
[28c025]52
[1a00bb]53// static instances
[5b1e5e]54const double SamplingGrid::zeroOffset[NDIM] = { 0., 0., 0. };
[1a00bb]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
[5b1e5e]64SamplingGrid::SamplingGrid(const double _begin[NDIM],
65 const double _end[NDIM],
[c6355f]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
[5b1e5e]74SamplingGrid::SamplingGrid(const double _begin[NDIM],
75 const double _end[NDIM],
[28c025]76 const int _level,
[c889b7]77 const sampledvalues_t &_sampled_grid) :
[3d9a8d]78 SamplingGridProperties(_begin, _end, _level),
[28c025]79 sampled_grid(_sampled_grid)
[1a00bb]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}
[28c025]85
86SamplingGrid::SamplingGrid(const SamplingGrid &_grid) :
87 SamplingGridProperties(_grid),
88 sampled_grid(_grid.sampled_grid)
[1a00bb]89{
[c6355f]90 setWindowSize(_grid.begin_window, _grid.end_window);
91 ASSERT( getWindowGridPoints() == _grid.getWindowGridPoints(),
92 "SamplingGrid::SamplingGrid() - incorrect number of samples given for the window.");
[1a00bb]93}
[28c025]94
95SamplingGrid::SamplingGrid(const SamplingGridProperties &_props) :
96 SamplingGridProperties(_props)
[1a00bb]97{
[c6355f]98 setWindowSize(zeroOffset, zeroOffset);
99 ASSERT( getWindowGridPoints() == (size_t)0,
100 "SamplingGrid::SamplingGrid() - incorrect number of samples given for the window.");
[1a00bb]101}
[28c025]102
[c889b7]103SamplingGrid::SamplingGrid(
104 const SamplingGridProperties &_props,
105 const sampledvalues_t &_sampled_grid) :
106 SamplingGridProperties(_props),
107 sampled_grid(_sampled_grid)
[1a00bb]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}
[c889b7]113
[28c025]114SamplingGrid::~SamplingGrid()
115{}
116
[c0e8fb]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));
[5b1e5e]122 for(size_t i = 0; i<NDIM; ++i) {
[c0e8fb]123 status &= begin_window[i] == _props.begin_window[i];
124 status &= end_window[i] == _props.end_window[i];
125 }
126 return status;
127}
128
[c889b7]129SamplingGrid& SamplingGrid::operator=(const SamplingGrid& other)
130{
131 // check for self-assignment
132 if (this != &other) {
133 static_cast<SamplingGridProperties &>(*this) = other;
[e2404f]134 setWindowSize(other.begin_window, other.end_window);
[c889b7]135 sampled_grid = other.sampled_grid;
136 }
137 return *this;
138}
139
[313f83]140static void multiplyElements(
141 double &dest,
142 const double &source,
143 const double prefactor)
144{
145 dest *= prefactor*(source);
146}
147
[8eafd6]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}
[313f83]157
[a1fcc6]158SamplingGrid& SamplingGrid::operator*=(const SamplingGrid& other)
159{
160 // check that grids are compatible
[cb30d9]161 if (isEquivalent(other)) {
[313f83]162 /// get minimum of window
[5b1e5e]163 double min_begin_window[NDIM];
164 double min_end_window[NDIM];
[313f83]165 bool doShrink = false;
[5b1e5e]166 for (size_t index=0; index<NDIM;++index) {
[313f83]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 }
[10f0cb]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] << ".");
[313f83]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);
[a1fcc6]193 } else {
[c0e8fb]194 ASSERT(0, "SamplingGrid::operator*=() - multiplying incongruent grids is so far not in the cards.");
[a1fcc6]195 }
196 return *this;
197}
198
[c889b7]199void SamplingGrid::superposeOtherGrids(const SamplingGrid &other, const double prefactor)
200{
[1a00bb]201 /// check that grids are compatible
[cb30d9]202 if (isEquivalent(other)) {
[1a00bb]203 /// get maximum of window
[5b1e5e]204 double max_begin_window[NDIM];
205 double max_end_window[NDIM];
[1a00bb]206 bool doExtend = false;
[5b1e5e]207 for (size_t index=0; index<NDIM;++index) {
[1a00bb]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 }
[10f0cb]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] << ".");
[1a00bb]223 if (doExtend)
224 extendWindow(max_begin_window, max_end_window);
225 /// and copy other into larger window, too
[de6dfb]226 addOntoWindow(other.begin_window, other.end_window, other.sampled_grid, prefactor);
[c889b7]227 } else {
228 ASSERT(0, "SamplingGrid::superposeOtherGrids() - superposing incompatible grids is so far not in the cards.");
229 }
230}
231
[620517]232const size_t SamplingGrid::getWindowGridPointsPerAxis(const size_t axis) const
[3d9a8d]233{
[620517]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)
[1a00bb]243 return 0;
[620517]244 return (size_t)(length/delta+round_offset);
[1a00bb]245}
246
[cb3363]247double SamplingGrid::integral() const
248{
[98f8fe]249 const double volume_element = getVolume()/(double)getTotalGridPoints();
[cb3363]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
[e72c61]260double SamplingGrid::integral(const SamplingGrid &weight) const
261{
[cb30d9]262 if (isEquivalent(weight)) {
[98f8fe]263 const double volume_element = getVolume()/(double)getTotalGridPoints();
[e72c61]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}
[1a00bb]275void SamplingGrid::setWindowSize(
[5b1e5e]276 const double _begin_window[NDIM],
277 const double _end_window[NDIM])
[1a00bb]278{
[5b1e5e]279 for (size_t index=0;index<NDIM;++index) {
[64bafe0]280 begin_window[index] = getNearestLowerGridPoint(_begin_window[index], index);
281 ASSERT( begin_window[index] >= begin[index],
[e2404f]282 "SamplingGrid::setWindowSize() - window starts earlier than domain on "
283 +toString(index)+"th component.");
[64bafe0]284 end_window[index] = getNearestHigherGridPoint(_end_window[index], index);
285 ASSERT( end_window[index] <= end[index],
[e2404f]286 "SamplingGrid::setWindowSize() - window ends later than domain on "
287 +toString(index)+"th component.");
[1a00bb]288 }
289}
290
291void SamplingGrid::setWindow(
[5b1e5e]292 const double _begin_window[NDIM],
293 const double _end_window[NDIM])
[1a00bb]294{
295 setWindowSize(_begin_window, _end_window);
296 const size_t gridpoints_window = getWindowGridPoints();
[c6355f]297 sampled_grid.clear();
[1a00bb]298 sampled_grid.resize(gridpoints_window, 0.);
299}
300
[e2404f]301void SamplingGrid::setDomain(
[5b1e5e]302 const double _begin[NDIM],
303 const double _end[NDIM])
[e2404f]304{
305 setDomainSize(_begin, _end);
306 setWindowSize(_begin, _end);
307 const size_t gridpoints = getTotalGridPoints();
308 sampled_grid.resize(gridpoints, 0.);
309}
310
[1a00bb]311void SamplingGrid::extendWindow(
[5b1e5e]312 const double _begin_window[NDIM],
313 const double _end_window[NDIM])
[1a00bb]314{
315#ifndef NDEBUG
[5b1e5e]316 for(size_t index=0;index < NDIM; ++index) {
[c6355f]317 // check that we truly have to extend the window
[1a00bb]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.");
[c6355f]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.");
[1a00bb]332 }
333#endif
334 // copy old window size and values
[5b1e5e]335 double old_begin_window[NDIM];
336 double old_end_window[NDIM];
337 for(size_t index=0;index<NDIM;++index) {
[1a00bb]338 old_begin_window[index] = begin_window[index];
339 old_end_window[index] = end_window[index];
340 }
341 sampledvalues_t old_values(sampled_grid);
[de6dfb]342 // set new window
343 setWindow(_begin_window,_end_window);
[1a00bb]344 // now extend it ...
[de6dfb]345 addOntoWindow(old_begin_window, old_end_window, old_values, +1.);
[10f0cb]346 LOG(6, "DEBUG: Grid after extension is " << sampled_grid << ".");
[1a00bb]347}
348
[313f83]349void SamplingGrid::shrinkWindow(
[5b1e5e]350 const double _begin_window[NDIM],
351 const double _end_window[NDIM])
[313f83]352{
353#ifndef NDEBUG
[5b1e5e]354 for(size_t index=0;index < NDIM; ++index) {
[313f83]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
[5b1e5e]373 double old_begin_window[NDIM];
374 double old_end_window[NDIM];
375 for(size_t index=0;index<NDIM;++index) {
[313f83]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.);
[10f0cb]384 LOG(6, "DEBUG: Grid after extension is " << sampled_grid << ".");
[313f83]385}
386
[fb3485]387static void addElements(
388 double &dest,
389 const double &source,
390 const double prefactor)
391{
392 dest += prefactor*(source);
393}
394
[1a00bb]395void SamplingGrid::addOntoWindow(
[5b1e5e]396 const double _begin_window[NDIM],
397 const double _end_window[NDIM],
[de6dfb]398 const sampledvalues_t &_sampled_grid,
399 const double prefactor)
[fb3485]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)),
[313f83]409 destwindow);
410}
411
412void SamplingGrid::addIntoWindow(
[5b1e5e]413 const double _begin_window[NDIM],
414 const double _end_window[NDIM],
[313f83]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);
[fb3485]427}
428
[c1948c]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
[336da8]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
[e51f2c]492void SamplingGrid::getDiscreteWindowCopyIndices(
[3f64ee]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
[5b1e5e]505 for(size_t index=0;index<NDIM;++index) {
[3f64ee]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.
[978234]510 const double delta = getDeltaPerAxis(index);
[3f64ee]511 // delta is conversion factor from box length to discrete length, i.e. number of points
[978234]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;
[3f64ee]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],
[e51f2c]524 "SamplingGrid::getDiscreteWindowCopyIndices() - pre, post, and length don't sum up to total for "
[3f64ee]525 +toString(index)+"th component.");
526 }
527}
528
[fb3485]529void SamplingGrid::addWindowOntoWindow(
[5b1e5e]530 const double larger_wbegin[NDIM],
531 const double larger_wend[NDIM],
532 const double smaller_wbegin[NDIM],
533 const double smaller_wend[NDIM],
[313f83]534 sampledvalues_t &dest_sampled_grid,
535 const sampledvalues_t &source_sampled_grid,
[fb3485]536 boost::function<void (double &, const double &)> op,
[313f83]537 enum eLargerWindow larger_window)
[1a00bb]538{
539#ifndef NDEBUG
[5b1e5e]540 for(size_t index=0;index<NDIM;++index) {
[313f83]541 ASSERT( smaller_wbegin[index] >= larger_wbegin[index],
[fb3485]542 "SamplingGrid::addWindowOntoWindow() - given smaller window starts earlier than larger window in component "
[1a00bb]543 +toString(index)+".");
[313f83]544 ASSERT( smaller_wend[index] <= larger_wend[index],
[fb3485]545 "SamplingGrid::addWindowOntoWindow() - given smaller window ends later than larger window in component "
[1a00bb]546 +toString(index)+".");
547 }
548#endif
549 // the only issue are indices
[5b1e5e]550 size_t pre_offset[NDIM];
551 size_t post_offset[NDIM];
552 size_t length[NDIM];
553 size_t total[NDIM];
[e51f2c]554 getDiscreteWindowCopyIndices(
[3f64ee]555 larger_wbegin, larger_wend,
556 smaller_wbegin, smaller_wend,
557 pre_offset,
558 post_offset,
559 length,
560 total
561 );
[64bafe0]562 // assert that calculated lengths match with given vector sizes
[c6355f]563#ifndef NDEBUG
564 const size_t calculated_size = length[0]*length[1]*length[2];
[313f83]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 }
[c6355f]580 const size_t total_size = total[0]*total[1]*total[2];
[313f83]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 }
[c6355f]590#endif
[5b1e5e]591 size_t N[NDIM];
[64bafe0]592// size_t counter = 0;
[313f83]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]);
[fb3485]597 else
[313f83]598 std::advance(sourceiter, pre_offset[0]*total[1]*total[2]);
[de6dfb]599 for(N[0]=0; N[0] < length[0]; ++N[0]) {
[313f83]600 if (larger_window == destwindow)
601 std::advance(destiter, pre_offset[1]*total[2]);
[fb3485]602 else
[313f83]603 std::advance(sourceiter, pre_offset[1]*total[2]);
[de6dfb]604 for(N[1]=0; N[1] < length[1]; ++N[1]) {
[313f83]605 if (larger_window == destwindow)
606 std::advance(destiter, pre_offset[2]);
[fb3485]607 else
[313f83]608 std::advance(sourceiter, pre_offset[2]);
[de6dfb]609 for(N[2]=0; N[2] < length[2]; ++N[2]) {
[313f83]610 ASSERT( destiter != dest_sampled_grid.end(),
611 "SamplingGrid::addWindowOntoWindow() - destiter is already at end of window.");
612 ASSERT( sourceiter != source_sampled_grid.end(),
[06653a]613 "SamplingGrid::addWindowOntoWindow() - sourceiter is already at end of window.");
[313f83]614 op(*destiter, *sourceiter);
615 ++destiter;
616 ++sourceiter;
[1a00bb]617 }
[313f83]618 if (larger_window == destwindow)
619 std::advance(destiter, post_offset[2]);
[fb3485]620 else
[313f83]621 std::advance(sourceiter, post_offset[2]);
[1a00bb]622 }
[313f83]623 if (larger_window == destwindow)
624 std::advance(destiter, post_offset[1]*total[2]);
[fb3485]625 else
[313f83]626 std::advance(sourceiter, post_offset[1]*total[2]);
[1a00bb]627 }
[c6355f]628#ifndef NDEBUG
[313f83]629 if (larger_window == destwindow)
630 std::advance(destiter, post_offset[0]*total[1]*total[2]);
[fb3485]631 else
[313f83]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.");
[c6355f]637#endif
[10f0cb]638 LOG(8, "DEBUG: Grid after adding other is " << dest_sampled_grid << ".");
[1a00bb]639}
640
[955051]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
[5b1e5e]650 for (size_t i=0; i<NDIM; ++i) {
[955051]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
[06653a]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
[91e7658]676static void getLengthsOfWindow(
[06653a]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;
[91e7658]690 // we can only assert that its atmost the maximum number of grid points
691 ASSERT (_total[index] <= ::pow(2, _grid.level),
[06653a]692 "SamplingGrid::downsample() - total "+toString(_total[index])
[91e7658]693 +" is not equal or less than 2^level: "+toString(_grid.level));
[06653a]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
[d56e21]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
[06653a]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);
[91e7658]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) {
[06653a]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];
[91e7658]857 getLengthsOfWindow(length_s, other);
[06653a]858 for (instance.level = other.level-1; instance.level >= _level; --instance.level) {
[91e7658]859 getLengthsOfWindow(length_d, instance);
[06653a]860 // we always have an eighth of the number of sample points as we stop
[91e7658]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.");
[06653a]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
[c889b7]882std::ostream & operator<<(std::ostream &ost, const SamplingGrid& other)
883{
[1a00bb]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];
[80959a1]889 ost << ", level of " << other.level;
890 ost << " and integrated value of " << other.integral();
[c889b7]891 return ost;
892}
893
[beb16e]894template<> SamplingGrid ZeroInstance<SamplingGrid>()
895{
896 SamplingGrid returnvalue;
897 return returnvalue;
898}
899
[28c025]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.