source: src/Fragmentation/Summation/SetValues/SamplingGrid.cpp@ 1640be

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

tempcommit: Merge with ad6485c8

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