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.
patchRecovery.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 
33 
34 using Eigen::VectorXd;
35 
36 //TODO: To define orthogonal polynomials over patches of a structured grid that has
37 // deformed from a rectilinear grid, a conformal mapping must be applied to transform
38 // the deformed mesh back to a rectilinear grid. Only then can we satisfy the
39 // requirements for a tensor-product construction of multivariate orthogonal polynomials.
40 
41 PatchRecovery::PatchRecovery(vtkDataSet *_dataSet, int _order,
42  const std::vector<int> &arrayIDs)
43  : order(_order)
44 {
45  cubature = GaussCubature::CreateUnique(_dataSet, arrayIDs);
46 }
47 
48 
50  std::vector<std::vector<double>> &coords,
51  std::vector<VectorXd> &data,
52  const std::vector<int> &numComponents,
53  int &pntNum) const
54 {
55  for (const auto &i : pntsAndData)
56  {
57  coords[pntNum] = i.first;
58  //nemAux::printVec(coords[pntNum]);
59  int currcomp = 0;
60  for (int numComponent : numComponents)
61  {
62  for (int k = 0; k < numComponent; ++k)
63  {
64  data[currcomp](pntNum) = i.second[currcomp];
65  ++currcomp;
66  }
67  }
68  pntNum += 1;
69  }
70 }
71 
72 
73 std::vector<double>
74 PatchRecovery::getMinMaxCoords(const std::vector<std::vector<double>> &coords) const
75 {
76  std::vector<double> minMaxXYZ(6);
77  for (int i = 0; i < 3; ++i)
78  {
79  minMaxXYZ[2 * i] = coords[0][i];
80  minMaxXYZ[2 * i + 1] = minMaxXYZ[2 * i];
81  }
82 
83  for (const auto &coord : coords)
84  {
85  for (int j = 0; j < 3; ++j)
86  {
87  // min
88  if (minMaxXYZ[2 * j] > coord[j])
89  {
90  minMaxXYZ[2 * j] = coord[j];
91  }
92  // max
93  else if (minMaxXYZ[2 * j + 1] < coord[j])
94  {
95  minMaxXYZ[2 * j + 1] = coord[j];
96  }
97  }
98  }
99  return minMaxXYZ;
100 }
101 
102 
103 void PatchRecovery::regularizeCoords(std::vector<std::vector<double>> &coords,
104  std::vector<double> &genNodeCoord) const
105 {
106  std::vector<double> minMaxXYZ = getMinMaxCoords(coords);
107  for (int j = 0; j < 3; ++j)
108  {
109  double coord_min = minMaxXYZ[2 * j];
110  double bound = minMaxXYZ[2 * j + 1] - coord_min;
111  for (auto &&coord : coords)
112  coord[j] = -1 + 2 * (coord[j] - coord_min) / bound;
113  genNodeCoord[j] = -1 + 2 * (genNodeCoord[j] - coord_min) / bound;
114  }
115 }
116 
117 
119 {
120  std::cout << "WARNING: mesh is assumed to be properly numbered" << std::endl;
121  // getting node mesh from cubature
122  vtkSmartPointer<vtkDataSet> dataSet = cubature->getDataSet();
123  int numPoints = dataSet->GetNumberOfPoints();
124  // initializing id list for patch cells
125  vtkSmartPointer<vtkIdList> patchCellIDs = vtkSmartPointer<vtkIdList>::New();
126  // getting cubature scheme dictionary for indexing
127  vtkQuadratureSchemeDefinition **dict = cubature->getDict();
128  std::vector<int> numComponents = cubature->getNumComponents();
129  // getting number of doubles representing all data at point
130  int totalComponents = cubature->getTotalComponents();
131  // storage for new point data
132  std::vector<vtkSmartPointer<vtkDoubleArray>> newPntData(numComponents.size());
133 
134  // initializing double arrays for new data
135  for (int i = 0; i < numComponents.size(); ++i)
136  {
137  std::string name = dataSet->GetPointData()
138  ->GetArrayName(cubature->getArrayIDs()[i]);
139  name += "New";
140  newPntData[i] = vtkSmartPointer<vtkDoubleArray>::New();
141  newPntData[i]->SetName(name.c_str());
142  newPntData[i]->SetNumberOfComponents(numComponents[i]);
143  newPntData[i]->SetNumberOfTuples(numPoints);
144  }
145 
146  // int totPatchPoints = 0;
147  // looping over all points, looping over patches per point
148  for (int i = 0; i < numPoints; ++i) //FIXME
149  {
150  // get ids of cells in patch of node
151  dataSet->GetPointCells(i, patchCellIDs);
152  // get total number of gauss points in patch
153  int numPatchPoints = 0;
154  for (int k = 0; k < patchCellIDs->GetNumberOfIds(); ++k)
155  {
156  int cellType = dataSet->GetCell(
157  patchCellIDs->GetId(k))->GetCellType();
158  numPatchPoints += dict[cellType]->GetNumberOfQuadraturePoints();
159  }
160 
161  if (patchCellIDs->GetNumberOfIds() < 2)
162  {
163  std::cerr << "Only " << patchCellIDs->GetNumberOfIds()
164  << " cell in patch of point " << i << std::endl;
165  }
166 
167  // coordinates of each gauss point in patch
168  std::vector<std::vector<double>> coords(numPatchPoints);
169  // vector of components of data at all gauss points in patch
170  std::vector<VectorXd> data(totalComponents);
171  for (int k = 0; k < totalComponents; ++k)
172  {
173  data[k].resize(numPatchPoints);
174  }
175 
176  int pntNum = 0;
177  for (int j = 0; j < patchCellIDs->GetNumberOfIds(); ++j)
178  {
179  pntDataPairVec pntsAndData = cubature->getGaussPointsAndDataAtCell(
180  patchCellIDs->GetId(j));
181  extractAxesAndData(pntsAndData, coords, data, numComponents, pntNum);
182  }
183 
184  // get coordinate of node that generates patch
185  std::vector<double> genNodeCoord(3);
186  dataSet->GetPoint(i, genNodeCoord.data());
187  // regularizing coordinates for preconditioning of basis matrix
188  regularizeCoords(coords, genNodeCoord);
189  if (!ortho)
190  {
191  // construct polyApprox from coords
192  std::unique_ptr<polyApprox> patchPolyApprox
193  = polyApprox::CreateUnique(order, coords);
194  // = new orthoPoly3D(order, coords);
195  int currComp = 0;
196  for (int k = 0; k < numComponents.size(); ++k)
197  {
198  auto *comps = new double[numComponents[k]];
199  for (int l = 0; l < numComponents[k]; ++l)
200  {
201  patchPolyApprox->computeCoeff(data[currComp]);
202  comps[l] = patchPolyApprox->eval(genNodeCoord);
203  patchPolyApprox->resetCoeff();
204  ++currComp;
205  }
206  newPntData[k]->InsertTuple(i, comps);
207  delete[] comps;
208  }
209  }
210  else
211  {
212  for (int k = 0; k < patchCellIDs->GetNumberOfIds(); ++k)
213  {
214  std::cout << "point " << i << " patch cell: " << patchCellIDs->GetId(k)
215  << std::endl;
216  }
217 
218  std::unique_ptr<orthoPoly3D> patchPolyApprox
219  = orthoPoly3D::CreateUnique(order, coords);
220  int currComp = 0;
221  for (int k = 0; k < numComponents.size(); ++k)
222  {
223  auto *comps = new double[numComponents[k]];
224  for (int l = 0; l < numComponents[k]; ++l)
225  {
226  std::cout << "computing coefficients of ortho polys" << std::endl;
227  patchPolyApprox->computeA(data[currComp]);
228  comps[l] = patchPolyApprox->eval(genNodeCoord);
229  patchPolyApprox->resetA();
230  ++currComp;
231  }
232  newPntData[k]->InsertTuple(i, comps);
233  delete[] comps;
234  }
235  }
236  }
237  for (int k = 0; k < numComponents.size(); ++k)
238  {
239  dataSet->GetPointData()->AddArray(newPntData[k]);
240  }
241 }
242 
243 
244 // TODO: check for whether recovered solution exists
245 std::vector<std::vector<double>> PatchRecovery::computeNodalError()
246 {
247  std::cout << "WARNING: mesh is assumed to be properly numbered" << std::endl;
248  // getting node mesh from cubature
249  vtkSmartPointer<vtkDataSet> dataSet = cubature->getDataSet();
250  std::vector<int> arrayIDs = cubature->getArrayIDs();
251  int numPoints = dataSet->GetNumberOfPoints();
252  // initializing id list for patch cells
253  vtkSmartPointer<vtkIdList> patchCellIDs = vtkSmartPointer<vtkIdList>::New();
254  // getting cubature scheme dictionary for indexing
255  vtkQuadratureSchemeDefinition **dict = cubature->getDict();
256  std::vector<int> numComponents = cubature->getNumComponents();
257  // getting number of doubles representing all data at a given point
258  int totalComponents = cubature->getTotalComponents();
259  // storage for new point data
260  std::vector<vtkSmartPointer<vtkDoubleArray>> newPntData(numComponents.size());
261  // storage for error data
262  std::vector<vtkSmartPointer<vtkDoubleArray>> errorPntData(
263  numComponents.size());
264  // reference point data
265  vtkSmartPointer<vtkPointData> pd = dataSet->GetPointData();
266 
267  std::vector<std::string> errorNames(numComponents.size());
268 
269  // initializing double arrays for new data
270  for (int i = 0; i < numComponents.size(); ++i)
271  {
272  std::string name = pd->GetArrayName(arrayIDs[i]);
273  std::string newName = name + "New";
274  newPntData[i] = vtkSmartPointer<vtkDoubleArray>::New();
275  newPntData[i]->SetName(newName.c_str());
276  newPntData[i]->SetNumberOfComponents(numComponents[i]);
277  newPntData[i]->SetNumberOfTuples(numPoints);
278 
279  std::string errName = name + "Error";
280  errorPntData[i] = vtkSmartPointer<vtkDoubleArray>::New();
281  errorPntData[i]->SetName(errName.c_str());
282  errorPntData[i]->SetNumberOfComponents(numComponents[i]);
283  errorPntData[i]->SetNumberOfTuples(numPoints);
284  errorNames[i] = errName;
285  }
286 
287  // storage for nodal average element sizes
288  vtkSmartPointer<vtkDoubleArray> nodeSizes = vtkSmartPointer<vtkDoubleArray>::New();
289  nodeSizes->SetName("nodeSizes");
290  nodeSizes->SetNumberOfComponents(1);
291  nodeSizes->SetNumberOfTuples(numPoints);
292 
293  // storage for generic cell if needed
294  vtkSmartPointer<vtkGenericCell> genCell = vtkSmartPointer<vtkGenericCell>::New();
295 
296  // looping over all points, looping over patches per point
297  for (int i = 0; i < numPoints; ++i)
298  {
299  // get ids of cells in patch of node
300  dataSet->GetPointCells(i, patchCellIDs);
301  // get total number of gauss points in patch and assign element size to
302  // patch generating node
303  int numPatchPoints = 0;
304  // also get average size of elements in patch
305  double nodeSize = 0;
306  for (int k = 0; k < patchCellIDs->GetNumberOfIds(); ++k)
307  {
308  // put current patch cell into genCell
309  dataSet->GetCell(patchCellIDs->GetId(k), genCell);
310  int cellType = dataSet->GetCell(
311  patchCellIDs->GetId(k))->GetCellType();
312  numPatchPoints += dict[cellType]->GetNumberOfQuadraturePoints();
313  //nodeSize += cbrt(
314  // 2.356194490192344 * cubature->computeCellVolume(genCell, cellType));
315  nodeSize += std::sqrt(genCell->GetLength2());
316  }
317  // patch-averaged node size
318  nodeSize /= patchCellIDs->GetNumberOfIds();
319  nodeSizes->InsertTuple(i, &nodeSize);
320  // coordinates of each gauss point in patch
321  std::vector<std::vector<double>> coords(numPatchPoints);
322  // vector of components of data at all gauss points in patch
323  std::vector<VectorXd> data(totalComponents);
324  for (int k = 0; k < totalComponents; ++k)
325  {
326  data[k].resize(numPatchPoints);
327  }
328 
329  int pntNum = 0;
330  for (int j = 0; j < patchCellIDs->GetNumberOfIds(); ++j)
331  {
332  pntDataPairVec pntsAndData = cubature->getGaussPointsAndDataAtCell(
333  patchCellIDs->GetId(j));
334  extractAxesAndData(pntsAndData, coords, data, numComponents, pntNum);
335  }
336 
337  // get coordinate of node that generates patch
338  std::vector<double> genNodeCoord(3);
339  dataSet->GetPoint(i, genNodeCoord.data());
340  // regularizing coordinates for preconditioning of basis matrix
341  regularizeCoords(coords, genNodeCoord);
342  // construct polyApprox from coords
343  std::unique_ptr<polyApprox> patchPolyApprox
344  = polyApprox::CreateUnique(order, coords);
345  // = new orthoPoly3D(order, coords);
346  int currComp = 0;
347  for (int k = 0; k < numComponents.size(); ++k)
348  {
349  auto *comps = new double[numComponents[k]];
350  auto *refComps = new double[numComponents[k]];
351  auto *errorComps = new double[numComponents[k]];
352  pd->GetArray(arrayIDs[k])->GetTuple(i, refComps);
353  for (int l = 0; l < numComponents[k]; ++l)
354  {
355  patchPolyApprox->computeCoeff(data[currComp]);
356  comps[l] = patchPolyApprox->eval(genNodeCoord);
357  errorComps[l] = std::pow(comps[l] - refComps[l], 2);
358  patchPolyApprox->resetCoeff();
359  ++currComp;
360  }
361  newPntData[k]->InsertTuple(i, comps);
362  errorPntData[k]->InsertTuple(i, errorComps);
363  delete[] comps;
364  delete[] refComps;
365  delete[] errorComps;
366  }
367  }
368  for (int k = 0; k < numComponents.size(); ++k)
369  {
370  //pd->AddArray(newPntData[k]);
371  pd->AddArray(errorPntData[k]);
372  }
373 
374  pd->AddArray(nodeSizes);
375  return cubature->integrateOverAllCells(errorNames, true);
376 }
static std::unique_ptr< polyApprox > CreateUnique(int order, const std::vector< std::vector< double >> &coords)
Definition: polyApprox.C:78
data_type data
Edge/face with sorted point ids (a, b, c, ...) is located at some index i in data[b], with data[b][i].first == [a, c] (for edges, third point id treated as -1).
std::vector< double > getMinMaxCoords(const std::vector< std::vector< double >> &coords) const
Definition: patchRecovery.C:74
std::vector< std::vector< double > > computeNodalError()
double eval(const std::vector< double > &coord) const
Definition: polyApprox.C:102
void computeCoeff(const Eigen::VectorXd &data)
Definition: polyApprox.C:85
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
std::vector< pntDataPair > pntDataPairVec
Definition: Cubature.H:55
void resetCoeff()
Definition: polyApprox.C:95
double eval(const std::vector< double > &coord)
Definition: orthoPoly3D.C:309
static std::unique_ptr< orthoPoly3D > CreateUnique(int _order, const std::vector< std::vector< double >> &coords)
Definition: orthoPoly3D.C:245
VTKCellType cellType
Definition: inpGeoMesh.C:129
void recoverNodalSolution(bool ortho)
PatchRecovery(vtkDataSet *_dataSet, int _order, const std::vector< int > &arrayIDs)
Definition: patchRecovery.C:41
void regularizeCoords(std::vector< std::vector< double >> &coords, std::vector< double > &genNodeCoord) const
void extractAxesAndData(const pntDataPairVec &pntsAndData, std::vector< std::vector< double >> &coords, std::vector< Eigen::VectorXd > &data, const std::vector< int > &numComponents, int &pntNum) const
Definition: patchRecovery.C:49
std::unique_ptr< GaussCubature > cubature
Definition: patchRecovery.H:67
void resetA()
Definition: orthoPoly3D.C:299
void computeA(const Eigen::VectorXd &sigma)
Definition: orthoPoly3D.C:254
static std::unique_ptr< GaussCubature > CreateUnique(vtkDataSet *_dataSet)
Definition: Cubature.C:135