OPAL (Object Oriented Parallel Accelerator Library) 2022.1
OPAL
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 <vector>
29#include <iostream>
30#include <string>
31#include <sstream>
32
33#include <gsl/gsl_sf_pow_int.h>
34#include <gsl/gsl_sf_gamma.h>
35
36#include "Utility/Inform.h" // ippl
37
39
43
44extern Inform* gmsg;
45
46namespace interpolation {
47
49
50namespace {
51 std::vector<double> getDeltaPos(Mesh* mesh) {
52 Mesh::Iterator it = mesh->begin();
53 std::vector<double> pos1 = it.getPosition();
54 for (size_t i = 0; i < it.getState().size(); ++i)
55 it[i]++;
56 std::vector<double> pos2 = it.getPosition();
57 for (size_t i = 0; i < pos2.size(); ++i)
58 pos2[i] -= pos1[i];
59 return pos2;
60 }
61}
62
64 std::vector<std::vector<double> > values,
65 int polyPatchOrder,
66 int smoothingOrder)
67 : polyPatchOrder_m(polyPatchOrder),
68 smoothingOrder_m(smoothingOrder),
69 polyDim_m(0),
70 polyMesh_m(),
71 points_m(points),
72 values_m(values),
73 polynomials_m(),
74 thisPoints_m(),
75 thisValues_m(),
76 derivPoints_m(),
77 derivValues_m(),
78 derivIndices_m(),
79 edgePoints_m(),
80 smoothingPoints_m() {
81 if (points == nullptr) {
83 "PPSolveFactory::Solve",
84 "nullptr Mesh input to Solve");
85 }
86 if (points->end().toInteger() != int(values.size())) {
87 std::stringstream ss;
88 ss << "Mismatch between Mesh and values in Solve. Mesh size was "
89 << points->end().toInteger() << " but field values size was "
90 << values.size();
92 "PPSolveFactory::Solve",
93 ss.str());
94 }
95 if (smoothingOrder < polyPatchOrder) {
97 "PPSolveFactory::Solve",
98 "Polynomial order must be <= smoothing order in Solve");
99 }
100 polyMesh_m = points->dual();
101 if (polyMesh_m == nullptr)
103 "PPSolveFactory::Solve",
104 "Dual of Mesh was nullptr");
105 polyDim_m = values[0].size();
106 int posDim = points->getPositionDimension();
107
108 edgePoints_m = std::vector< std::vector< std::vector<int> > >(posDim+1);
109 for (int i = 1; i <= posDim; ++i)
111 (i, 0, smoothingOrder-polyPatchOrder);
114}
115
117 Mesh::Iterator outOfBoundsIt) {
118 const Mesh* mesh = outOfBoundsIt.getMesh();
119 std::vector<int> state = outOfBoundsIt.getState();
120 std::vector<int> delta = std::vector<int>(state.size(), 2);
121 Mesh::Iterator end = mesh->end()-1;
122 std::vector<double> pos1 = mesh->begin().getPosition();
123 std::vector<double> pos2 = Mesh::Iterator(delta, mesh).getPosition();
124 for (size_t i = 0; i < state.size(); ++i)
125 if (state[i] < 1) {
126 state[i] = 1;
127 } else if (state[i] > end[i]) {
128 state[i] = end[i];
129 }
130 std::vector<double> position = Mesh::Iterator(state, mesh).getPosition();
131 state = outOfBoundsIt.getState();
132 for (size_t i = 0; i < state.size(); ++i)
133 if (state[i] < 1) {
134 position[i] = (pos2[i] - pos1[i])*(state[i]-1) + position[i];
135 } else if (state[i] > end[i]) {
136 position[i] = (pos2[i] - pos1[i])*(state[i]-end[i]) + position[i];
137 }
138 return position;
139}
140
142 int posDim = points_m->getPositionDimension();
143 std::vector< std::vector<int> > dataPoints =
145 thisPoints_m = std::vector< std::vector<double> >(dataPoints.size());
146 std::vector<double> deltaPos = getDeltaPos(points_m);
147 // now iterate over the index_by_power_list elements - offset; each of
148 // these makes a point in the polynomial fit
149 for (size_t i = 0; i < dataPoints.size(); ++i) {
150 thisPoints_m[i] = std::vector<double>(posDim);
151 for (int j = 0; j < posDim; ++j)
152 thisPoints_m[i][j] = (0.5-dataPoints[i][j])*deltaPos[j];
153 }
154}
155
157 thisValues_m = std::vector< std::vector<double> >();
158 int posDim = it.getState().size();
159 std::vector< std::vector<int> > dataPoints =
161 size_t dataPointsSize = dataPoints.size();
163 // now iterate over the indexByPowerList elements - offset; each of
164 // these makes a point in the polynomial fit
165 for (size_t i = 0; i < dataPointsSize; ++i) {
166 std::vector<int> itState = it.getState();
167 for (int j = 0; j < posDim; ++j)
168 itState[j]++;
169 Mesh::Iterator itCurrent = Mesh::Iterator(itState, points_m);
170 bool outOfBounds = false; // element is off the edge of the mesh
171 for (int j = 0; j < posDim; ++j) {
172 itCurrent[j] -= dataPoints[i][j];
173 outOfBounds = outOfBounds ||
174 itCurrent[j] < 1 ||
175 itCurrent[j] > end[j];
176 }
177 if (outOfBounds) { // if off the edge, then just constrain to zero
178 thisValues_m.push_back(values_m[it.toInteger()]);
179 } else { // else fit using values
180 thisValues_m.push_back(values_m[itCurrent.toInteger()]);
181 }
182 }
183}
184
186 derivPoints_m = std::vector< std::vector<double> >();
187 derivIndices_m = std::vector< std::vector<int> >();
188 derivOrigins_m = std::vector< std::vector<int> >();
189 derivPolyVec_m = std::vector<MVector<double> >();
190 int posDim = points_m->getPositionDimension();
191 // get the outer layer of points
192 int deltaOrder = smoothingOrder_m - polyPatchOrder_m;
193 if (deltaOrder <= 0)
194 return;
195 std::vector<double> deltaPos = getDeltaPos(points_m);
196 // smoothingPoints_m is the last layer of points used for polynomial fit
197 // walk around smoothingPoints_m finding the points used for smoothing
198 for (size_t i = 0; i < smoothingPoints_m.size(); ++i) {
199 // make a list of the axes that are on the edge of the space
200 std::vector<int> equalAxes;
201 for (size_t j = 0; j < smoothingPoints_m[i].size(); ++j)
203 equalAxes.push_back(j);
204 std::vector<std::vector<int> > edgePoints =
205 edgePoints_m[equalAxes.size()];
206 // note the first point, 0,0, is ignored
207 for (size_t j = 0; j < edgePoints.size(); ++j) {
208 derivIndices_m.push_back(std::vector<int>(posDim));
209 derivOrigins_m.push_back(smoothingPoints_m[i]);
210 derivPoints_m.push_back(std::vector<double>(posDim));
211
212 for (size_t k = 0; k < smoothingPoints_m[i].size(); ++k) {
213 derivPoints_m.back()[k] = (smoothingPoints_m[i][k]-0.5)*deltaPos[k];
214 }
215 for (size_t k = 0; k < edgePoints[j].size(); ++k) {
216 derivIndices_m.back()[equalAxes[k]] = edgePoints[j][k];
217 }
218 }
219 }
220
222 (posDim, smoothingOrder_m);
223 for (size_t i = 0; i < derivPoints_m.size(); ++i) {
224 derivPolyVec_m.push_back(MVector<double>(nPolyCoeffs, 1.));
225 // Product[x^{p_j-q_j}*p_j!/(p_j-q_j)!]
226 for (int j = 0; j < nPolyCoeffs; ++j) {
227 std::vector<int> pVec =
229 std::vector<int> qVec = derivIndices_m[i];
230 for (int l = 0; l < posDim; ++l) {
231 int pow = pVec[l]-qVec[l];
232 if (pow < 0) {
233 derivPolyVec_m.back()(j+1) = 0.;
234 break;
235 }
236 derivPolyVec_m.back()(j+1) *= gsl_sf_fact(pVec[l])/gsl_sf_fact(pow)*gsl_sf_pow_int(-deltaPos[l]/2., pow);
237 }
238 }
239 }
240}
241
243 // calculate the derivatives near to polynomial at position indexed by it
244 #ifdef DEBUG
245 bool verbose = false;
246 if (verbose) {
247 std::cerr << "PPSolveFactory::GetDerivs at position ";
248 for (auto p: it.getPosition()) {std::cerr << p << " ";}
249 std::cerr << std::endl;
250 }
251 #endif
252 // derivatives go in derivValues_m
253 derivValues_m = std::vector< std::vector<double> >(derivPoints_m.size());
254
255 std::vector<double> itPos = it.getPosition();
256 int posDim = it.getState().size();
257
258 // get the outer layer of points
259 Mesh::Iterator last = it.getMesh()->end()-1;
260 int deltaOrder = smoothingOrder_m - polyPatchOrder_m;
261 if (deltaOrder <= 0) { // no smoothing needed
262 return;
263 }
264 for (size_t i = 0; i < derivPoints_m.size(); ++i) {
265 Mesh::Iterator nearest = it;
266 bool inTheMesh = true;
267 for (int j = 0; j < posDim && inTheMesh; ++j) {
268 nearest[j] += derivOrigins_m[i][j];
269 inTheMesh = nearest[j] <= last[j];
270 }
271 if (!inTheMesh) {
272 derivValues_m[i] = std::vector<double>(polyDim_m, 0.);
273 } else {
274 MMatrix<double> coeffs =
275 polynomials_m[nearest.toInteger()]->GetCoefficientsAsMatrix();
276 MVector<double> values = coeffs*derivPolyVec_m[i];
277 derivValues_m[i] = std::vector<double>(polyDim_m);
278 for(int j = 0; j < posDim; ++j) {
279 derivValues_m[i][j] = values(j+1);
280 }
281 }
282 #ifdef DEBUG
283 if (verbose) {
284 std::cerr << "Point ";
285 for (auto p: derivPoints_m[i]) {std::cerr << p << " ";}
286 std::cerr << " values ";
287 for (auto v: derivValues_m[i]) {std::cerr << v << " ";}
288 std::cerr << " derivIndices ";
289 for (auto in: derivIndices_m[i]) {std::cerr << in << " ";}
290 std::cerr << std::endl;
291 }
292 #endif
293 }
294}
295
299 int meshSize = polyMesh_m->end().toInteger();
300 polynomials_m = std::vector<SquarePolynomialVector*>(meshSize, nullptr);
301 // get the list of points that are needed to make a given poly vector
302 getPoints();
306 polyDim_m,
310 int total = (polyMesh_m->end()-1).toInteger();
311 double oldPercentage = 0.;
312 for (Mesh::Iterator it = polyMesh_m->end()-1;
313 it >= polyMesh_m->begin();
314 --it) {
315 double newPercentage = (total-it.toInteger())/double(total)*100.;
316 if (newPercentage - oldPercentage > 10.) {
317 *gmsg << " Done " << newPercentage << " %" << endl;
318 oldPercentage = newPercentage;
319 }
320 // find the set of values and derivatives for this point in the mesh
321 getValues(it);
322 getDerivs(it);
323 // The polynomial is found using simultaneous equation solve
324 polynomials_m[it.toInteger()] = solver.PolynomialSolve
326 }
328}
329
331 std::vector<int> check,
332 size_t checkIndex,
333 size_t polyPower,
334 std::vector<std::vector<int> >& nearbyPoints) {
335 check[checkIndex] = polyPower;
336 nearbyPoints.push_back(check);
337 if (checkIndex+1 == check.size())
338 return;
339 for (int i = 1; i < int(polyPower); ++i)
340 nearbyPointsRecursive(check, checkIndex+1, i, nearbyPoints);
341 for (int i = 0; i <= int(polyPower); ++i) {
342 check[checkIndex] = i;
343 nearbyPointsRecursive(check, checkIndex+1, polyPower, nearbyPoints);
344 }
345}
346
347std::vector<std::vector<int> > PPSolveFactory::getNearbyPointsSquares(
348 int pointDim,
349 int polyOrderLower,
350 int polyOrderUpper) {
351 if (pointDim < 1)
352 throw(GeneralClassicException("PPSolveFactory::getNearbyPointsSquares",
353 "Point dimension must be > 0"));
354 if (polyOrderLower > polyOrderUpper)
355 throw(GeneralClassicException("PPSolveFactory::getNearbyPointsSquares",
356 "Polynomial lower bound must be <= polynomial upper bound"));
357 // polyOrder -1 (or less) means no terms
358 if (polyOrderUpper == polyOrderLower || polyOrderUpper < 0)
359 return std::vector<std::vector<int> >();
360 // polyOrder 0 means constant term
361 std::vector<std::vector<int> > nearbyPoints(1, std::vector<int>(pointDim, 0));
362 // polyOrder > 0 means corresponding poly terms (1 is linear, 2 is quadratic...)
363 for (size_t thisPolyOrder = 0;
364 thisPolyOrder < size_t(polyOrderUpper);
365 ++thisPolyOrder)
366 nearbyPointsRecursive(nearbyPoints[0], 0, thisPolyOrder+1, nearbyPoints);
367 if (polyOrderLower < 0)
368 return nearbyPoints; // no terms in lower bound
369 int nPointsLower = 1;
370 for (int dim = 0; dim < pointDim; ++dim)
371 nPointsLower *= polyOrderLower+1;
372 nearbyPoints.erase(nearbyPoints.begin(), nearbyPoints.begin()+nPointsLower);
373 return nearbyPoints;
374}
375}
PartBunchBase< T, Dim >::ConstIterator end(PartBunchBase< T, Dim > const &bunch)
PartBunchBase< T, Dim >::ConstIterator begin(PartBunchBase< T, Dim > const &bunch)
Inform * gmsg
Definition: Main.cpp:61
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
PolynomialCoefficient Coeff
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
virtual void getPosition(double *point) const
std::vector< int > getState() const
const Mesh * getMesh() const
PolynomialCoefficient represents a coefficient in a multi-dimensional polynomial.
Patches together many SquarePolynomialVectors to make a multidimensional polynomial spline.
std::vector< std::vector< int > > smoothingPoints_m
std::vector< std::vector< int > > derivIndices_m
std::vector< std::vector< double > > values_m
std::vector< std::vector< double > > derivValues_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 > > thisPoints_m
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< int > > derivOrigins_m
std::vector< double > outOfBoundsPosition(Mesh::Iterator outOfBoundsIt)
std::vector< MVector< double > > derivPolyVec_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 > > derivPoints_m
std::vector< std::vector< std::vector< int > > > edgePoints_m
SolveFactory is a factory class for solving a set of linear equations to generate a polynomial based ...
Definition: SolveFactory.h:44
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)
Definition: Inform.h:42