OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
PPSolveFactory.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2015, Chris Rogers
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * 1. Redistributions of source code must retain the above copyright notice,
7 * this list of conditions and the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright notice,
9 * this list of conditions and the following disclaimer in the documentation
10 * and/or other materials provided with the distribution.
11 * 3. Neither the name of STFC nor the names of its contributors may be used to
12 * endorse or promote products derived from this software without specific
13 * prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <iostream>
29#include <sstream>
30#include <string>
31#include <vector>
32
33#include "Utilities/GSLCompat.h"
34
35#include "Utility/Inform.h" // ippl
36
38
42
43extern Inform* gmsg;
44
45namespace interpolation {
46
48
49 namespace {
50 std::vector<double> getDeltaPos(Mesh* mesh) {
51 Mesh::Iterator it = mesh->begin();
52 std::vector<double> pos1 = it.getPosition();
53 for (size_t i = 0; i < it.getState().size(); ++i)
54 it[i]++;
55 std::vector<double> pos2 = it.getPosition();
56 for (size_t i = 0; i < pos2.size(); ++i)
57 pos2[i] -= pos1[i];
58 return pos2;
59 }
60 } // namespace
61
63 Mesh* points, std::vector<std::vector<double> > values, int polyPatchOrder,
64 int smoothingOrder)
65 : polyPatchOrder_m(polyPatchOrder),
66 smoothingOrder_m(smoothingOrder),
67 polyDim_m(0),
68 polyMesh_m(),
69 points_m(points),
70 values_m(values),
71 polynomials_m(),
72 thisPoints_m(),
73 thisValues_m(),
74 derivPoints_m(),
75 derivValues_m(),
76 derivIndices_m(),
77 edgePoints_m(),
78 smoothingPoints_m() {
79 if (points == nullptr) {
80 throw GeneralOpalException("PPSolveFactory::Solve", "nullptr Mesh input to Solve");
81 }
82 if (points->end().toInteger() != int(values.size())) {
83 std::stringstream ss;
84 ss << "Mismatch between Mesh and values in Solve. Mesh size was "
85 << points->end().toInteger() << " but field values size was " << values.size();
86 throw GeneralOpalException("PPSolveFactory::Solve", ss.str());
87 }
88 if (smoothingOrder < polyPatchOrder) {
90 "PPSolveFactory::Solve",
91 "Polynomial order must be <= smoothing order in Solve");
92 }
93 polyMesh_m = points->dual();
94 if (polyMesh_m == nullptr)
95 throw GeneralOpalException("PPSolveFactory::Solve", "Dual of Mesh was nullptr");
96 polyDim_m = values[0].size();
97 int posDim = points->getPositionDimension();
98
99 edgePoints_m = std::vector<std::vector<std::vector<int> > >(posDim + 1);
100 for (int i = 1; i <= posDim; ++i)
101 edgePoints_m[i] = getNearbyPointsSquares(i, 0, smoothingOrder - polyPatchOrder);
103 }
104
105 std::vector<double> PPSolveFactory::outOfBoundsPosition(Mesh::Iterator outOfBoundsIt) {
106 const Mesh* mesh = outOfBoundsIt.getMesh();
107 std::vector<int> state = outOfBoundsIt.getState();
108 std::vector<int> delta = std::vector<int>(state.size(), 2);
109 Mesh::Iterator end = mesh->end() - 1;
110 std::vector<double> pos1 = mesh->begin().getPosition();
111 std::vector<double> pos2 = Mesh::Iterator(delta, mesh).getPosition();
112 for (size_t i = 0; i < state.size(); ++i)
113 if (state[i] < 1) {
114 state[i] = 1;
115 } else if (state[i] > end[i]) {
116 state[i] = end[i];
117 }
118 std::vector<double> position = Mesh::Iterator(state, mesh).getPosition();
119 state = outOfBoundsIt.getState();
120 for (size_t i = 0; i < state.size(); ++i)
121 if (state[i] < 1) {
122 position[i] = (pos2[i] - pos1[i]) * (state[i] - 1) + position[i];
123 } else if (state[i] > end[i]) {
124 position[i] = (pos2[i] - pos1[i]) * (state[i] - end[i]) + position[i];
125 }
126 return position;
127 }
128
130 int posDim = points_m->getPositionDimension();
131 std::vector<std::vector<int> > dataPoints =
133 thisPoints_m = std::vector<std::vector<double> >(dataPoints.size());
134 std::vector<double> deltaPos = getDeltaPos(points_m);
135 // now iterate over the index_by_power_list elements - offset; each of
136 // these makes a point in the polynomial fit
137 for (size_t i = 0; i < dataPoints.size(); ++i) {
138 thisPoints_m[i] = std::vector<double>(posDim);
139 for (int j = 0; j < posDim; ++j)
140 thisPoints_m[i][j] = (0.5 - dataPoints[i][j]) * deltaPos[j];
141 }
142 }
143
145 thisValues_m = std::vector<std::vector<double> >();
146 int posDim = it.getState().size();
147 std::vector<std::vector<int> > dataPoints =
149 size_t dataPointsSize = dataPoints.size();
150 Mesh::Iterator end = points_m->end() - 1;
151 // now iterate over the indexByPowerList elements - offset; each of
152 // these makes a point in the polynomial fit
153 for (size_t i = 0; i < dataPointsSize; ++i) {
154 std::vector<int> itState = it.getState();
155 for (int j = 0; j < posDim; ++j)
156 itState[j]++;
157 Mesh::Iterator itCurrent = Mesh::Iterator(itState, points_m);
158 bool outOfBounds = false; // element is off the edge of the mesh
159 for (int j = 0; j < posDim; ++j) {
160 itCurrent[j] -= dataPoints[i][j];
161 outOfBounds = outOfBounds || itCurrent[j] < 1 || itCurrent[j] > end[j];
162 }
163 if (outOfBounds) { // if off the edge, then just constrain to zero
164 thisValues_m.push_back(values_m[it.toInteger()]);
165 } else { // else fit using values
166 thisValues_m.push_back(values_m[itCurrent.toInteger()]);
167 }
168 }
169 }
170
172 derivPoints_m = std::vector<std::vector<double> >();
173 derivIndices_m = std::vector<std::vector<int> >();
174 derivOrigins_m = std::vector<std::vector<int> >();
175 derivPolyVec_m = std::vector<MVector<double> >();
176 int posDim = points_m->getPositionDimension();
177 // get the outer layer of points
178 int deltaOrder = smoothingOrder_m - polyPatchOrder_m;
179 if (deltaOrder <= 0) return;
180 std::vector<double> deltaPos = getDeltaPos(points_m);
181 // smoothingPoints_m is the last layer of points used for polynomial fit
182 // walk around smoothingPoints_m finding the points used for smoothing
183 for (size_t i = 0; i < smoothingPoints_m.size(); ++i) {
184 // make a list of the axes that are on the edge of the space
185 std::vector<int> equalAxes;
186 for (size_t j = 0; j < smoothingPoints_m[i].size(); ++j)
187 if (smoothingPoints_m[i][j] == polyPatchOrder_m) equalAxes.push_back(j);
188 std::vector<std::vector<int> > edgePoints = edgePoints_m[equalAxes.size()];
189 // note the first point, 0,0, is ignored
190 for (size_t j = 0; j < edgePoints.size(); ++j) {
191 derivIndices_m.push_back(std::vector<int>(posDim));
192 derivOrigins_m.push_back(smoothingPoints_m[i]);
193 derivPoints_m.push_back(std::vector<double>(posDim));
194
195 for (size_t k = 0; k < smoothingPoints_m[i].size(); ++k) {
196 derivPoints_m.back()[k] = (smoothingPoints_m[i][k] - 0.5) * deltaPos[k];
197 }
198 for (size_t k = 0; k < edgePoints[j].size(); ++k) {
199 derivIndices_m.back()[equalAxes[k]] = edgePoints[j][k];
200 }
201 }
202 }
203
204 int nPolyCoeffs =
206 for (size_t i = 0; i < derivPoints_m.size(); ++i) {
207 derivPolyVec_m.push_back(MVector<double>(nPolyCoeffs, 1.));
208 // Product[x^{p_j-q_j}*p_j!/(p_j-q_j)!]
209 for (int j = 0; j < nPolyCoeffs; ++j) {
210 std::vector<int> pVec = SquarePolynomialVector::IndexByPower(j, posDim);
211 std::vector<int> qVec = derivIndices_m[i];
212 for (int l = 0; l < posDim; ++l) {
213 int pow = pVec[l] - qVec[l];
214 if (pow < 0) {
215 derivPolyVec_m.back()(j + 1) = 0.;
216 break;
217 }
218 derivPolyVec_m.back()(j + 1) *= gsl_sf_fact(pVec[l]) / gsl_sf_fact(pow)
219 * gsl_sf_pow_int(-deltaPos[l] / 2., pow);
220 }
221 }
222 }
223 }
224
226// calculate the derivatives near to polynomial at position indexed by it
227#ifdef DEBUG
228 bool verbose = false;
229 if (verbose) {
230 std::cerr << "PPSolveFactory::GetDerivs at position ";
231 for (auto p : it.getPosition()) {
232 std::cerr << p << " ";
233 }
234 std::cerr << std::endl;
235 }
236#endif
237 // derivatives go in derivValues_m
238 derivValues_m = std::vector<std::vector<double> >(derivPoints_m.size());
239
240 std::vector<double> itPos = it.getPosition();
241 int posDim = it.getState().size();
242
243 // get the outer layer of points
244 Mesh::Iterator last = it.getMesh()->end() - 1;
245 int deltaOrder = smoothingOrder_m - polyPatchOrder_m;
246 if (deltaOrder <= 0) { // no smoothing needed
247 return;
248 }
249 for (size_t i = 0; i < derivPoints_m.size(); ++i) {
250 Mesh::Iterator nearest = it;
251 bool inTheMesh = true;
252 for (int j = 0; j < posDim && inTheMesh; ++j) {
253 nearest[j] += derivOrigins_m[i][j];
254 inTheMesh = nearest[j] <= last[j];
255 }
256 if (!inTheMesh) {
257 derivValues_m[i] = std::vector<double>(polyDim_m, 0.);
258 } else {
259 MMatrix<double> coeffs =
260 polynomials_m[nearest.toInteger()]->GetCoefficientsAsMatrix();
261 MVector<double> values = coeffs * derivPolyVec_m[i];
262 derivValues_m[i] = std::vector<double>(polyDim_m);
263 for (int j = 0; j < posDim; ++j) {
264 derivValues_m[i][j] = values(j + 1);
265 }
266 }
267#ifdef DEBUG
268 if (verbose) {
269 std::cerr << "Point ";
270 for (auto p : derivPoints_m[i]) {
271 std::cerr << p << " ";
272 }
273 std::cerr << " values ";
274 for (auto v : derivValues_m[i]) {
275 std::cerr << v << " ";
276 }
277 std::cerr << " derivIndices ";
278 for (auto in : derivIndices_m[i]) {
279 std::cerr << in << " ";
280 }
281 std::cerr << std::endl;
282 }
283#endif
284 }
285 }
286
288 Mesh::Iterator begin = points_m->begin();
289 Mesh::Iterator end = points_m->end() - 1;
290 int meshSize = polyMesh_m->end().toInteger();
291 polynomials_m = std::vector<SquarePolynomialVector*>(meshSize, nullptr);
292 // get the list of points that are needed to make a given poly vector
293 getPoints();
295 SolveFactory solver(
298 int total = (polyMesh_m->end() - 1).toInteger();
299 double oldPercentage = 0.;
300 for (Mesh::Iterator it = polyMesh_m->end() - 1; it >= polyMesh_m->begin(); --it) {
301 double newPercentage = (total - it.toInteger()) / double(total) * 100.;
302 if (newPercentage - oldPercentage > 10.) {
303 *gmsg << " Done " << newPercentage << " %" << endl;
304 oldPercentage = newPercentage;
305 }
306 // find the set of values and derivatives for this point in the mesh
307 getValues(it);
308 getDerivs(it);
309 // The polynomial is found using simultaneous equation solve
310 polynomials_m[it.toInteger()] = solver.PolynomialSolve(thisValues_m, derivValues_m);
311 }
313 }
314
316 std::vector<int> check, size_t checkIndex, size_t polyPower,
317 std::vector<std::vector<int> >& nearbyPoints) {
318 check[checkIndex] = polyPower;
319 nearbyPoints.push_back(check);
320 if (checkIndex + 1 == check.size()) return;
321 for (int i = 1; i < int(polyPower); ++i)
322 nearbyPointsRecursive(check, checkIndex + 1, i, nearbyPoints);
323 for (int i = 0; i <= int(polyPower); ++i) {
324 check[checkIndex] = i;
325 nearbyPointsRecursive(check, checkIndex + 1, polyPower, nearbyPoints);
326 }
327 }
328
329 std::vector<std::vector<int> > PPSolveFactory::getNearbyPointsSquares(
330 int pointDim, int polyOrderLower, int polyOrderUpper) {
331 if (pointDim < 1)
333 "PPSolveFactory::getNearbyPointsSquares", "Point dimension must be > 0"));
334 if (polyOrderLower > polyOrderUpper)
336 "PPSolveFactory::getNearbyPointsSquares",
337 "Polynomial lower bound must be <= polynomial upper bound"));
338 // polyOrder -1 (or less) means no terms
339 if (polyOrderUpper == polyOrderLower || polyOrderUpper < 0)
340 return std::vector<std::vector<int> >();
341 // polyOrder 0 means constant term
342 std::vector<std::vector<int> > nearbyPoints(1, std::vector<int>(pointDim, 0));
343 // polyOrder > 0 means corresponding poly terms (1 is linear, 2 is quadratic...)
344 for (size_t thisPolyOrder = 0; thisPolyOrder < size_t(polyOrderUpper); ++thisPolyOrder)
345 nearbyPointsRecursive(nearbyPoints[0], 0, thisPolyOrder + 1, nearbyPoints);
346 if (polyOrderLower < 0) return nearbyPoints; // no terms in lower bound
347 int nPointsLower = 1;
348 for (int dim = 0; dim < pointDim; ++dim)
349 nPointsLower *= polyOrderLower + 1;
350 nearbyPoints.erase(nearbyPoints.begin(), nearbyPoints.begin() + nPointsLower);
351 return nearbyPoints;
352 }
353} // namespace interpolation
Inform * gmsg
Definition changes.cpp:7
double gsl_sf_fact(unsigned int n)
Factorial (computed via for large ).
Definition GSLCompat.h:69
double gsl_sf_pow_int(double x, int n)
Integer power .
Definition GSLCompat.h:57
Inform * gmsg
Definition changes.cpp:7
virtual void getPosition(double *point) const
std::vector< int > getState() const
const Mesh * getMesh() const
Base class for meshing routines.
Definition Mesh.h:49
virtual int getPositionDimension() const =0
virtual Mesh * dual() const =0
virtual Mesh::Iterator end() const =0
virtual Mesh::Iterator begin() const =0
std::vector< std::vector< int > > derivOrigins_m
std::vector< std::vector< double > > values_m
std::vector< std::vector< double > > derivPoints_m
static void nearbyPointsRecursive(std::vector< int > check, size_t checkIndex, size_t polyPower, std::vector< std::vector< int > > &nearbyPoints)
std::vector< std::vector< double > > thisValues_m
PPSolveFactory(Mesh *points, std::vector< std::vector< double > > values, int polyPatchOrder, int smoothingOrder)
void getValues(Mesh::Iterator it)
std::vector< SquarePolynomialVector * > polynomials_m
std::vector< std::vector< double > > thisPoints_m
std::vector< double > outOfBoundsPosition(Mesh::Iterator outOfBoundsIt)
std::vector< std::vector< int > > derivIndices_m
static std::vector< std::vector< int > > getNearbyPointsSquares(int pointDim, int polyOrderLower, int polyOrderUpper)
void getDerivs(const Mesh::Iterator &it)
std::vector< std::vector< double > > derivValues_m
std::vector< std::vector< int > > smoothingPoints_m
std::vector< MVector< double > > derivPolyVec_m
std::vector< std::vector< std::vector< int > > > edgePoints_m
PolynomialCoefficient represents a coefficient in a multi-dimensional polynomial.
Patches together many SquarePolynomialVectors to make a multidimensional polynomial spline.
SolveFactory is a factory class for solving a set of linear equations to generate a polynomial based ...
SquarePolynomialVector * PolynomialSolve(const std::vector< std::vector< double > > &values, const std::vector< std::vector< double > > &deriv_values)
static unsigned int NumberOfPolynomialCoefficients(int pointDimension, int order)
static std::vector< int > IndexByPower(int index, int nInputVariables)
PolynomialCoefficient Coeff