NEMoSys  0.63.0
A modular, extensible resource with robust automated mesh generation, mesh quality analysis, adaptive mesh refinement, and data transfer between arbitrary meshes.
orthoPoly3D.C
Go to the documentation of this file.
1 /*******************************************************************************
2 * Promesh *
3 * Copyright (C) 2022, IllinoisRocstar LLC. All rights reserved. *
4 * *
5 * Promesh is the property of IllinoisRocstar LLC. *
6 * *
7 * IllinoisRocstar LLC *
8 * Champaign, IL *
9 * www.illinoisrocstar.com *
10 * promesh@illinoisrocstar.com *
11 *******************************************************************************/
12 /*******************************************************************************
13 * This file is part of Promesh *
14 * *
15 * This version of Promesh is free software: you can redistribute it and/or *
16 * modify it under the terms of the GNU Lesser General Public License as *
17 * published by the Free Software Foundation, either version 3 of the License, *
18 * or (at your option) any later version. *
19 * *
20 * Promesh is distributed in the hope that it will be useful, but WITHOUT ANY *
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more *
23 * details. *
24 * *
25 * You should have received a copy of the GNU Lesser General Public License *
26 * along with this program. If not, see <https://www.gnu.org/licenses/>. *
27 * *
28 *******************************************************************************/
30 
31 #ifdef NEMOSYS_DEBUG
32  #include "AuxiliaryFunctions.H"
33 #endif
34 
35 #include <unsupported/Eigen/KroneckerProduct>
36 
37 using Eigen::KroneckerProduct;
38 using Eigen::MatrixXd;
39 using Eigen::VectorXd;
40 
41 // remove given column from matrix in place (VERY SLOW)
42 void removeColumn(MatrixXd &matrix, unsigned int colToRemove)
43 {
44  unsigned int numRows = matrix.rows();
45  unsigned int numCols = matrix.cols() - 1;
46 
47  if (colToRemove < numCols)
48  matrix.block(0, colToRemove, numRows, numCols - colToRemove) =
49  matrix.rightCols(numCols - colToRemove);
50 
51  matrix.conservativeResize(numRows, numCols);
52 }
53 
54 
55 // remove column from matrix, out of place
56 // is efficient given referenced matrices are stored as column-major
57 void removeColumn(const MatrixXd &matrix,
58  MatrixXd &matrix_red,
59  const std::vector<unsigned int> &toRemove)
60 {
61  int m = 0;
62  for (int i = 0; i < matrix.cols(); ++i)
63  {
64  bool remove = false;
65  for (unsigned int k : toRemove)
66  {
67  if (i == k)
68  {
69  remove = true;
70  break;
71  }
72  }
73  if (!remove)
74  {
75  matrix_red.col(m) = matrix.col(i);
76  m += 1;
77  }
78  }
79 }
80 
81 
82 // exclude columns from a matrix and construct the transpose
83 // of such an exclusion. This method is fast given the immutable
84 // matrix is stored as column-major and the mutable one is row-major
85 void removeRowT(const MatrixXd &matrix,
86  MatrixXdRM &matrix_red,
87  const std::vector<unsigned int> &toRemove)
88 {
89  int m = 0;
90  for (int i = 0; i < matrix.cols(); ++i)
91  {
92  bool remove = false;
93  for (unsigned int k : toRemove)
94  {
95  if (i == k)
96  {
97  remove = true;
98  break;
99  }
100  }
101  if (!remove)
102  {
103  matrix_red.row(m) = matrix.col(i);
104  m += 1;
105  }
106  }
107 }
108 
109 // default ctor
111  opy(new orthoPoly1D()),
112  opz(new orthoPoly1D()),
113  finished(false)
114 {
115  a.resize(0);
116 }
117 
119 {
120  if (order == 1)
121  toRemove = {3, 5, 6, 7};
122  else if (order == 2)
123  toRemove = {5, 7, 8, 11, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25,
124  26};
125  else if (order == 3)
126  toRemove = {7, 10, 11, 13, 14, 15, 19, 22, 23, 25, 26,
127  27, 28, 29, 30, 31, 34, 35, 37, 38, 39, 40,
128  41, 42, 43, 44, 45, 46, 47, 49, 50, 51, 52,
129  53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
130  else
131  {
132  std::cerr << "Polynomial order greater than 3 is not supported"
133  << std::endl;
134  exit(1);
135  }
136 }
137 
138 // complete ctor
139 orthoPoly3D::orthoPoly3D(int _order, const VectorXd &sigma,
140  const std::vector<double> &x,
141  const std::vector<double> &y,
142  const std::vector<double> &z)
143  : order(_order), finished(false)
144 {
145  initCheck();
146 
147  opx = std::unique_ptr<orthoPoly1D>(new orthoPoly1D(order, x));
148  opy = std::unique_ptr<orthoPoly1D>(new orthoPoly1D(order, y));
149  opz = std::unique_ptr<orthoPoly1D>(new orthoPoly1D(order, z));
150  computeA(sigma);
151 }
152 
154  const std::vector<std::vector<double>> &coords)
155  : order(_order), finished(false)
156 {
157  //int root(round(cbrt(coords.size())));
158  //if (coords.size() != root * root * root &&
159  // coords.size() != (root + 1) * (root + 1) * (root + 1))
160  //{
161  // std::cerr << "coords are definitely not in a cartesian product set"
162  // << std::endl;
163  // exit(1);
164  //}
165 
166  initCheck();
167 
168  std::vector<double> x(coords.size());
169  std::vector<double> y(coords.size());
170  std::vector<double> z(coords.size());
171 
172  for (int i = 0; i < coords.size(); ++i)
173  {
174  x[i] = coords[i][0];
175  y[i] = coords[i][1];
176  z[i] = coords[i][2];
177  }
178  std::cout << "non-unique coords" << std::endl;
179 #ifdef NEMOSYS_DEBUG
180  nemAux::printVec(x); //nemAux::printVec(y); nemAux::printVec(z);
181 #endif
182  //std::vector<double> x_unique;
183  //for (int i = 0; i < x.size(); ++i)
184  //{
185  // x_unique.push_back(x[i]);
186  // for (int j = i + 1; j < x.size(); ++j)
187  // {
188  // if (x_unique[i] != x[j])
189  // }
190  //}
191 
192  //std::sort(x.begin(), x.end());
193  //x.erase(std::unique(x.begin(), x.end(), Pred), x.end());
194  //std::cout << "unique coords" << std::endl;
195  //nemAux::printVec(x); //nemAux::printVec(y); nemAux::printVec(z);
196 
197  opx = std::unique_ptr<orthoPoly1D>(new orthoPoly1D(order, x));
198  opy = std::unique_ptr<orthoPoly1D>(new orthoPoly1D(order, y));
199  opz = std::unique_ptr<orthoPoly1D>(new orthoPoly1D(order, z));
200 }
201 
202 // move ctor
204  : order(op.order),
205  opx(std::move(op.opx)),
206  opy(std::move(op.opy)),
207  opz(std::move(op.opz)),
208  a(op.a),
209  toRemove(op.toRemove),
210  finished(op.finished)
211 {
212  op.Reset();
213 }
214 
215 
216 // move assignment
218 {
219  // check against self assignment
220  if (this != &op)
221  {
222  // release held resources
223  this->Reset();
224  // move resources from op to this (i.e. pilfer)
225  opx = std::move(op.opx);
226  opy = std::move(op.opy);
227  opz = std::move(op.opz);
228  a = op.a;
229  toRemove = op.toRemove;
230  finished = op.finished;
231  order = op.order;
232  // set op to default state
233  op.Reset();
234  }
235  return *this;
236 }
237 
238 orthoPoly3D *
239 orthoPoly3D::Create(int _order, const std::vector<std::vector<double>> &coords)
240 {
241  return new orthoPoly3D(_order, coords);
242 }
243 
244 std::unique_ptr<orthoPoly3D>
246  const std::vector<std::vector<double>> &coords)
247 {
248  return std::unique_ptr<orthoPoly3D>(
249  orthoPoly3D::Create(_order, coords));
250 }
251 
252 
253 // compute coefficients for polynomial expansion of sampled function
254 void orthoPoly3D::computeA(const VectorXd &sigma)
255 {
256  if (!finished)
257  {
258 #ifdef NEMOSYS_DEBUG
259  nemAux::Timer T;
260 #endif
261 
262  MatrixXd tmp1 = opx->phi * opx->phiTphiInv;
263  MatrixXd tmp2 = opy->phi * opy->phiTphiInv;
264  MatrixXd tmp3 = opz->phi * opz->phiTphiInv;
265 #ifdef NEMOSYS_DEBUG
266  nemAux::Timer T1;
267  T1.start();
268 #endif
269  MatrixXd kronProd_full = kroneckerProduct(tmp1, tmp2);
270  kronProd_full = kroneckerProduct(kronProd_full, tmp3).eval();
271 #ifdef NEMOSYS_DEBUG
272  T1.stop();
273  std::cout << "Time for building kronprod in constructor: " << T1.elapsed()
274  << "\n";
275  std::cout << "kronProd_full: " << kronProd_full.rows() << " "
276  << kronProd_full.cols() << "\n";
277  std::cout << "Removing rows: ";
279 #endif
280  MatrixXdRM kronProd_red(kronProd_full.cols() - toRemove.size(),
281  kronProd_full.rows());
282 #ifdef NEMOSYS_DEBUG
283  T.start();
284 #endif
285  removeRowT(kronProd_full, kronProd_red, toRemove);
286  std::cout << "kronProd_red: " << kronProd_red.rows() << " "
287  << kronProd_red.cols() << "\n";
288  std::cout << "sigma size: " << sigma.size() << "\n";
289  a = kronProd_red * sigma;
290 #ifdef NEMOSYS_DEBUG
291  T.stop();
292  std::cout << "Time: " << T.elapsed() << std::endl;
293  std::cout << "shape of a: " << a.rows() << " " << a.cols() << std::endl;
294 #endif
295  finished = true;
296  }
297 }
298 
300 {
301  if (finished)
302  {
303  a.resize(0);
304  finished = false;
305  }
306 }
307 
308 
309 double orthoPoly3D::eval(const std::vector<double> &coord)
310 {
311  if (!finished)
312  {
313  std::cerr << "Coefficients to basis have not been generated" << std::endl;
314  exit(1);
315  }
316 
317  MatrixXd phix(1, order + 1);
318  MatrixXd phiy(1, order + 1);
319  MatrixXd phiz(1, order + 1);
320  for (int i = 0; i < order + 1; ++i)
321  {
322  phix(0, i) = opx->EvaluateOrthogonal(i, coord[0]);
323  phiy(0, i) = opy->EvaluateOrthogonal(i, coord[1]);
324  phiz(0, i) = opz->EvaluateOrthogonal(i, coord[2]);
325  }
326 
327  MatrixXd Phi = kroneckerProduct(phix, phiy);
328  Phi = kroneckerProduct(Phi, phiz).eval();
329 #ifdef NEMOSYS_DEBUG
330  std::cout << Phi.rows() << " " << Phi.cols() << std::endl;
331 #endif
332  MatrixXd Phi_red(Phi.rows(), Phi.cols() - toRemove.size());
333  removeColumn(Phi, Phi_red, toRemove);
334 
335 #ifdef NEMOSYS_DEBUG
336  std::cout << Phi_red.rows() << " " << Phi_red.cols() << std::endl;
337  std::cout << a.rows() << " " << a.cols() << std::endl;
338 #endif
339 
340  return (Phi_red * a)(0, 0);
341 }
342 
343 // evaluate the fitting polynomial at coord
344 double orthoPoly3D::operator()(const std::vector<double> &coord)
345 {
346  return eval(coord);
347 }
348 
349 #ifdef NEMOSYS_DEBUG
350 // compute multivariate polynomial approximation of prescribed order to sigma
351 void orthoPoly3D::run1(const VectorXd &sigma)
352 {
353  MatrixXd NewPhi;
354  NewPhi = kroneckerProduct(opx->phi, opy->phi);
355  NewPhi = kroneckerProduct(NewPhi, opz->phi).eval();
356 
357  nemAux::Timer T;
358  std::cout << "Removing stuff" << std::endl;
359  T.start();
360 
361  MatrixXd NewPhi_red(NewPhi.rows(), NewPhi.cols() - toRemove.size());
362 
363  removeColumn(NewPhi, NewPhi_red, toRemove);
364 
365  T.stop();
366  std::cout << "Time spent removing: " << T.elapsed() << std::endl;
367 
368  VectorXd sigma_approx = NewPhi_red * a;
369 
370  VectorXd error = (sigma_approx - sigma).cwiseAbs();
371  std::cout << "max error " << error.maxCoeff() << std::endl;
372  std::cout << "min error " << error.minCoeff() << std::endl;
373 }
374 #endif
375 
377 {
378  if (opx) opx.reset();
379  if (opy) opy.reset();
380  if (opz) opz.reset();
381  a.resize(0);
382  finished = false;
383  toRemove.resize(0);
384 }
Eigen::VectorXd a
Definition: orthoPoly3D.H:146
std::unique_ptr< orthoPoly1D > opy
Definition: orthoPoly3D.H:142
double operator()(const std::vector< double > &coord)
Definition: orthoPoly3D.C:344
STL namespace.
std::unique_ptr< orthoPoly1D > opx
Definition: orthoPoly3D.H:140
double eval(const std::vector< double > &coord)
Definition: orthoPoly3D.C:309
void initCheck()
Definition: orthoPoly3D.C:118
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > MatrixXdRM
Definition: orthoPoly3D.H:61
void Reset()
Definition: orthoPoly3D.C:376
static std::unique_ptr< orthoPoly3D > CreateUnique(int _order, const std::vector< std::vector< double >> &coords)
Definition: orthoPoly3D.C:245
void removeRowT(const MatrixXd &matrix, MatrixXdRM &matrix_red, const std::vector< unsigned int > &toRemove)
Definition: orthoPoly3D.C:85
std::vector< unsigned int > toRemove
Definition: orthoPoly3D.H:148
void printVec(const std::vector< T > &v)
orthoPoly3D & operator=(orthoPoly3D &&op)
Definition: orthoPoly3D.C:217
static orthoPoly3D * Create(int _order, const std::vector< std::vector< double >> &coords)
Definition: orthoPoly3D.C:239
void resetA()
Definition: orthoPoly3D.C:299
void removeColumn(MatrixXd &matrix, unsigned int colToRemove)
Definition: orthoPoly3D.C:42
void computeA(const Eigen::VectorXd &sigma)
Definition: orthoPoly3D.C:254
std::unique_ptr< orthoPoly1D > opz
Definition: orthoPoly3D.H:144