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

Fix_ChargeSampling_PBC
Last change on this file since afc28a was afc28a, checked in by Frederik Heber <heber@…>, 8 years ago

SamplingGrid now also has flag to state boundary conditions.

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