OPAL (Object Oriented Parallel Accelerator Library)  2024.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 
44 extern Inform* gmsg;
45 
46 namespace interpolation {
47 
49 
50 namespace {
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);
113  (posDim, polyPatchOrder_m-1, polyPatchOrder_m);
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)
202  if (smoothingPoints_m[i][j] == polyPatchOrder_m)
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();
303  getDerivPoints();
306  polyDim_m,
307  thisPoints_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 
347 std::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 }
PolynomialCoefficient represents a coefficient in a multi-dimensional polynomial. ...
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two distribute and or modify the software for each author s protection and we want to make certain that everyone understands that there is no warranty for this free software If the software is modified by someone else and passed we want its recipients to know that what they have is not the so that any problems introduced by others will not reflect on the original authors reputations any free program is threatened constantly by software patents We wish to avoid the danger that redistributors of a free program will individually obtain patent in effect making the program proprietary To prevent we have made it clear that any patent must be licensed for everyone s free use or not licensed at all The precise terms and conditions for distribution and modification follow GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR DISTRIBUTION AND MODIFICATION This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License The refers to any such program or and a work based on the Program means either the Program or any derivative work under copyright a work containing the Program or a portion of it
Definition: LICENSE:43
PolynomialCoefficient Coeff
static std::vector< std::vector< int > > getNearbyPointsSquares(int pointDim, int polyOrderLower, int polyOrderUpper)
std::vector< std::vector< double > > derivValues_m
virtual void getPosition(double *point) const
Definition: Mesh-inl.icc:80
std::vector< std::vector< double > > values_m
SolveFactory is a factory class for solving a set of linear equations to generate a polynomial based ...
Definition: SolveFactory.h:44
std::vector< std::vector< int > > derivIndices_m
std::vector< MVector< double > > derivPolyVec_m
Base class for meshing routines.
Definition: Mesh.h:49
virtual Mesh::Iterator begin() const =0
virtual Mesh * dual() const =0
clearpage the user may choose between constant or variable radius This model includes fringe fields begin
Definition: multipole_t.tex:6
const Mesh * getMesh() const
Definition: Mesh-inl.icc:70
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
std::vector< std::vector< int > > derivOrigins_m
std::vector< std::vector< double > > derivPoints_m
std::vector< std::vector< std::vector< int > > > edgePoints_m
std::vector< SquarePolynomialVector * > polynomials_m
Definition: Inform.h:42
std::vector< std::vector< double > > thisPoints_m
std::vector< double > outOfBoundsPosition(Mesh::Iterator outOfBoundsIt)
static std::vector< int > IndexByPower(int index, int nInputVariables)
void getDerivs(const Mesh::Iterator &it)
std::vector< int > getState() const
Definition: Mesh-inl.icc:58
PPSolveFactory(Mesh *points, std::vector< std::vector< double > > values, int polyPatchOrder, int smoothingOrder)
Patches together many SquarePolynomialVectors to make a multidimensional polynomial spline...
void getValues(Mesh::Iterator it)
virtual Mesh::Iterator end() const =0
static unsigned int NumberOfPolynomialCoefficients(int pointDimension, int order)
Tps< T > pow(const Tps< T > &x, int y)
Integer power.
Definition: TpsMath.h:76
virtual int getPositionDimension() const =0
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
Inform * gmsg
Definition: Main.cpp:70
std::vector< std::vector< int > > smoothingPoints_m
end
Definition: multipole_t.tex:9