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.
OrderOfAccuracy.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 *******************************************************************************/
29 #include "AuxiliaryFunctions.H"
31 #include "Drivers/TransferDriver.H"
32 
33 #include <vtkDoubleArray.h>
34 #include <vtkPointData.h>
35 
37  std::vector<int> _arrayIDs,
38  std::string transferType, double targetGCI)
39  : f3(_f3),
40  f2(_f2),
41  f1(_f1),
42  arrayIDs(std::move(_arrayIDs)),
43  targetGCI(targetGCI) {
44  // set names for array from coarse mesh to be transferred to fine
45  int numArr = arrayIDs.size();
46 
47  f3ArrNames.resize(numArr);
48  f2ArrNames.resize(numArr);
49  diffIDs.resize(numArr);
50  relEIDs.resize(numArr);
51  realDiffIDs.resize(numArr);
52 
53  for (int i = 0; i < numArr; ++i) {
54  // get names from coarsest mesh
55  std::string name =
56  f3->getDataSet()->GetPointData()->GetArrayName(arrayIDs[i]);
57  std::string coarseName = name + "f3";
58  std::string fineName = name + "f2";
59  f3ArrNames[i] = coarseName;
60  f2ArrNames[i] = fineName;
61  }
62 
63  auto f3f2Transfer =
65  f3f2Transfer->transferPointData(arrayIDs, f3ArrNames);
66  auto f2f1Transfer =
68  f2f1Transfer->transferPointData(arrayIDs, f2ArrNames);
69 
72 
73  // TODO: Double-check the integer division below.
74  r21 = pow(f1->getNumberOfPoints() / f2->getNumberOfPoints(), 1. / 3.);
75  r32 = pow(f2->getNumberOfPoints() / f3->getNumberOfPoints(), 1. / 3.);
76  std::cout << "Refinement ratio from 2-to-1 is " << r21 << " "
77  << " and from 3-to-2 is " << r32 << std::endl;
78 }
79 
80 std::vector<std::vector<double>> OrderOfAccuracy::computeOrderOfAccuracy() {
81  orderOfAccuracy.resize(diffF3F2.size());
82  for (int i = 0; i < diffF3F2.size(); ++i) {
83  orderOfAccuracy[i].resize(diffF3F2[i].size());
84  for (int j = 0; j < diffF3F2[i].size(); ++j) {
85  // Picard-type iteration to solve transcendental equation for p
86  double q_p = 0;
87  double f32_f21 = diffF3F2[i][j] / diffF2F1[i][j];
88  int s = (f32_f21 > 0) - (f32_f21 < 0);
89  double p = -1;
90  double old_p = 1;
91  for (int k = 0; k < 1000; ++k) {
92  p = std::fabs(log(std::fabs(f32_f21)) + q_p) / log(r21);
93  q_p = log((pow(r21, p) - s) / (pow(r32, p) - s));
94  if (std::fabs(old_p - p) < 1e-16)
95  break;
96  else
97  old_p = p;
98  }
99  orderOfAccuracy[i][j] = p;
100  }
101  }
102  return orderOfAccuracy;
103 }
104 
105 std::vector<std::vector<double>> OrderOfAccuracy::computeGCI_21() {
106  if (GCI_21.empty()) {
107  if (orderOfAccuracy.empty()) {
109  }
110  std::vector<std::vector<double>> f1L2(f1->integrateOverMesh(relEIDs));
111  GCI_21.resize(orderOfAccuracy.size());
112  for (int i = 0; i < orderOfAccuracy.size(); ++i) {
113  GCI_21[i].resize(orderOfAccuracy[i].size());
114  for (int j = 0; j < orderOfAccuracy[i].size(); ++j) {
115  double relativeError = diffF2F1[i][j] / std::sqrt(f1L2[i][j]);
116  GCI_21[i][j] =
117  1.25 * relativeError / (pow(r21, orderOfAccuracy[i][j]) - 1);
118  }
119  }
120  }
121  return GCI_21;
122 }
123 
124 std::vector<std::vector<double>> OrderOfAccuracy::computeGCI_32() {
125  if (GCI_32.empty()) {
126  if (orderOfAccuracy.empty()) {
128  }
129  std::vector<std::vector<double>> f2L2(f2->integrateOverMesh(relEIDs));
130  GCI_32.resize(orderOfAccuracy.size());
131  for (int i = 0; i < orderOfAccuracy.size(); ++i) {
132  GCI_32[i].resize(orderOfAccuracy[i].size());
133  for (int j = 0; j < orderOfAccuracy[i].size(); ++j) {
134  double relativeError = diffF3F2[i][j] / std::sqrt(f2L2[i][j]);
135  GCI_32[i][j] =
136  1.25 * relativeError / (pow(r32, orderOfAccuracy[i][j]) - 1);
137  }
138  }
139  }
140  return GCI_32;
141 }
142 
143 std::vector<std::vector<double>> OrderOfAccuracy::computeResolution(
144  double gciStar) {
145  if (GCI_32.empty()) computeGCI_32();
146  std::vector<std::vector<double>> res(GCI_32.size());
147  for (int i = 0; i < GCI_32.size(); ++i) {
148  res[i].resize(GCI_32[i].size());
149  for (int j = 0; j < GCI_32[i].size(); ++j) {
150  res[i][j] = pow(gciStar / GCI_32[i][j], 1. / orderOfAccuracy[i][j]);
151  }
152  }
153  return res;
154 }
155 
157  const std::string &ofname) {
158  std::vector<std::vector<double>> ratios(checkAsymptoticRange());
159  for (const auto &ratio : ratios) {
160  for (double j : ratio) {
161  if (std::abs(j - 1) > 1) {
162  std::cerr
163  << "WARNING: Solutions are not in the asymptotic convergence range"
164  << std::endl;
165  }
166  }
167  }
168 
169  std::vector<double> resolution = nemAux::flatten(computeResolution(gciStar));
170  auto minmax = std::minmax_element(resolution.begin(), resolution.end());
171  double ave = (*minmax.first + *minmax.second) / 2;
172  f3->refineMesh("uniform", ave, ofname, false);
173  meshBase *refined = meshBase::Create(ofname);
174  // f3->unsetNewArrayNames();
175  // f3->transfer(refined, "Consistent Interpolation", arrayIDs);
176  auto f3refinedTransfer = NEM::DRV::TransferDriver::CreateTransferObject(
177  f3, refined, "Consistent Interpolation");
178  f3refinedTransfer->transferPointData(arrayIDs);
179  delete f3;
180  f3 = refined;
182  f3->write(ofname);
183 }
184 
185 std::vector<std::vector<double>> OrderOfAccuracy::checkAsymptoticRange() {
186  if (GCI_21.empty()) computeGCI_21();
187  if (GCI_32.empty()) computeGCI_32();
188  std::vector<std::vector<double>> ratios(GCI_21.size());
189  for (int i = 0; i < GCI_21.size(); ++i) {
190  ratios[i].resize(GCI_21[i].size());
191  for (int j = 0; j < GCI_21[i].size(); ++j) {
192  ratios[i][j] =
193  GCI_32[i][j] / (pow(r21, orderOfAccuracy[i][j]) * GCI_21[i][j]);
194  }
195  }
196  return ratios;
197 }
198 
201 
202  int numArr = arrayIDs.size();
203 
204  std::vector<vtkSmartPointer<vtkDoubleArray>> fineDatas(numArr);
205  std::vector<vtkSmartPointer<vtkDoubleArray>> diffDatas(numArr);
206  std::vector<vtkSmartPointer<vtkDoubleArray>> richardsonDatas(numArr);
207 
208  vtkSmartPointer<vtkPointData> finePD = f1->getDataSet()->GetPointData();
209 
210  std::vector<std::string> names(numArr);
211  for (int id = 0; id < numArr; ++id) {
212  diffDatas[id] =
213  vtkDoubleArray::SafeDownCast(finePD->GetArray(realDiffIDs[id]));
214  fineDatas[id] =
215  vtkDoubleArray::SafeDownCast(finePD->GetArray(arrayIDs[id]));
216 
217  auto richardsonData = vtkSmartPointer<vtkDoubleArray>::New();
218  richardsonData->SetNumberOfComponents(
219  diffDatas[id]->GetNumberOfComponents());
220  richardsonData->SetNumberOfTuples(f1->getNumberOfPoints());
221  std::string name(finePD->GetArrayName(arrayIDs[id]));
222  name += "_richExtrap";
223  names[id] = name;
224  richardsonData->SetName(&name[0u]);
225  richardsonDatas[id] = richardsonData;
226  }
227 
228  for (int i = 0; i < f1->getNumberOfPoints(); ++i) {
229  for (int id = 0; id < numArr; ++id) {
230  int numComponent = diffDatas[id]->GetNumberOfComponents();
231 
232  auto *fine_comps = new double[numComponent];
233  fineDatas[id]->GetTuple(i, fine_comps);
234 
235  auto *diff_comps = new double[numComponent];
236  diffDatas[id]->GetTuple(i, diff_comps);
237 
238  auto *val = new double[numComponent];
239  for (int j = 0; j < numComponent; ++j) {
240  double comp = fine_comps[j] +
241  diff_comps[j] / (pow(r21, orderOfAccuracy[id][j]) - 1);
242  val[j] = comp;
243  }
244  richardsonDatas[id]->SetTuple(i, val);
245 
246  delete[] fine_comps;
247  delete[] diff_comps;
248  delete[] val;
249  }
250  }
251 
252  std::vector<int> richExtrapIDs(numArr);
253  for (int id = 0; id < numArr; ++id) {
254  finePD->AddArray(richardsonDatas[id]);
255  finePD->GetArray(names[id].c_str(), richExtrapIDs[id]);
256  }
257  // f1->transfer(f3, "Consistent Interpolation", richExtrapIDs);
259  f1, f3, "Consistent Interpolation");
260  f1f3Transfer->transferPointData(arrayIDs, f1->getNewArrayNames());
261 }
262 
263 std::vector<std::vector<double>> OrderOfAccuracy::computeDiff(
264  meshBase *mesh, const std::vector<std::string> &newArrNames) {
265  // diff is computed across multiple data items, specified by arrayIDs
266  int numArr = arrayIDs.size();
267  std::vector<vtkSmartPointer<vtkDoubleArray>> fineDatas(numArr);
268  std::vector<vtkSmartPointer<vtkDoubleArray>> coarseDatas(numArr);
269  std::vector<vtkSmartPointer<vtkDoubleArray>> diffDatas(numArr);
270  std::vector<vtkSmartPointer<vtkDoubleArray>> fineDatasSqr(numArr);
271  std::vector<vtkSmartPointer<vtkDoubleArray>> realDiffDatas(numArr);
272 
273  vtkSmartPointer<vtkPointData> finePD = mesh->getDataSet()->GetPointData();
274 
275  std::vector<std::string> names(numArr);
276  std::vector<std::string> names2(numArr);
277  std::vector<std::string> names3(numArr);
278 
279  std::string diffSqrName, sqrName, diffName;
280  for (int id = 0; id < numArr; ++id) {
281  fineDatas[id] =
282  vtkDoubleArray::SafeDownCast(finePD->GetArray(arrayIDs[id]));
283  coarseDatas[id] =
284  vtkDoubleArray::SafeDownCast(finePD->GetArray(newArrNames[id].c_str()));
285 
286  // initialize
287  vtkSmartPointer<vtkDoubleArray> diffData =
289  vtkSmartPointer<vtkDoubleArray> fineDataSqr =
291  vtkSmartPointer<vtkDoubleArray> realDiffData =
293 
294  diffData->SetNumberOfComponents(fineDatas[id]->GetNumberOfComponents());
295  diffData->SetNumberOfTuples(mesh->getNumberOfPoints());
296  std::string name(finePD->GetArrayName(arrayIDs[id]));
297  name += "DiffSqr";
298  names[id] = name;
299  diffData->SetName(name.c_str());
300  diffDatas[id] = diffData;
301 
302  fineDataSqr->SetNumberOfComponents(fineDatas[id]->GetNumberOfComponents());
303  fineDataSqr->SetNumberOfTuples(mesh->getNumberOfPoints());
304  std::string name2(finePD->GetArrayName(arrayIDs[id]));
305  name2 += "Sqr";
306  names2[id] = name2;
307  fineDataSqr->SetName(name2.c_str());
308  fineDatasSqr[id] = fineDataSqr;
309 
310  realDiffData->SetNumberOfComponents(fineDatas[id]->GetNumberOfComponents());
311  realDiffData->SetNumberOfTuples(mesh->getNumberOfPoints());
312  std::string name3(finePD->GetArrayName(arrayIDs[id]));
313  name3 += "Diff";
314  names3[id] = name3;
315  realDiffData->SetName(name3.c_str());
316  realDiffDatas[id] = realDiffData;
317  }
318 
319  int numPts = mesh->getNumberOfPoints();
320  for (int id = 0; id < numArr; ++id) {
321  auto fineData = fineDatas[id];
322  auto coarseData = coarseDatas[id];
323  auto diffData = diffDatas[id];
324  auto fineDataSqr = fineDatasSqr[id];
325  auto realDiffData = realDiffDatas[id];
326 
327  int numComps = fineDatas[id]->GetNumberOfComponents();
328 
329  double *fine_comps = new double[numComps];
330  double *coarse_comps = new double[numComps];
331  double *diff = new double[numComps];
332  double *fsqr = new double[numComps];
333  double *realdiff = new double[numComps];
334 
335  for (int i = 0; i < numPts; ++i) {
336  fineData->GetTuple(i, fine_comps);
337  coarseData->GetTuple(i, coarse_comps);
338 
339  for (int j = 0; j < numComps; ++j) {
340  double error = coarse_comps[j] - fine_comps[j];
341  diff[j] = error * error;
342  fsqr[j] = fine_comps[j] * fine_comps[j];
343  realdiff[j] = fine_comps[j] - coarse_comps[j];
344  }
345 
346  diffData->SetTuple(i, diff);
347  fineDataSqr->SetTuple(i, fsqr);
348  realDiffData->SetTuple(i, realdiff);
349  }
350  delete[] fine_comps;
351  delete[] coarse_comps;
352  delete[] diff;
353  delete[] fsqr;
354  delete[] realdiff;
355  }
356 
357  for (int id = 0; id < numArr; ++id) {
358  finePD->AddArray(diffDatas[id]);
359  finePD->GetArray(names[id].c_str(), diffIDs[id]);
360  finePD->AddArray(fineDatasSqr[id]);
361  finePD->GetArray(names2[id].c_str(), relEIDs[id]);
362  finePD->AddArray(realDiffDatas[id]);
363  finePD->GetArray(names3[id].c_str(), realDiffIDs[id]);
364  }
365 
366  std::vector<std::vector<double>> diff_integral(
367  mesh->integrateOverMesh(diffIDs));
368  for (auto &&i : diff_integral) {
369  for (double &j : i) {
370  j = std::sqrt(j);
371  std::cout << j << " ";
372  }
373  std::cout << std::endl;
374  }
375  return diff_integral;
376 }
std::vector< int > diffIDs
array ids for differences^2 in solutions between meshes
void refineMesh(const std::string &method, int arrayID, double dev_mult, bool maxIsmin, double edge_scale, const std::string &ofname, bool transferData, double sizeFactor=1., bool constrainBoundary=false)
perform sizefield-based h-refinement.
Definition: meshBase.C:1565
A brief description of meshBase.
Definition: meshBase.H:64
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
std::vector< std::vector< double > > diffF2F1
L2 norm of the difference in solution between f2 and f1.
const std::vector< int > arrayIDs
array ids for arrays to be considered in analysis
std::vector< std::string > f3ArrNames
STL namespace.
std::vector< std::vector< double > > GCI_21
GCIs with respect to the finer mesh (f2)
std::vector< std::vector< double > > orderOfAccuracy
Order of accuracy (p) with respect to refinements f3-f2-f1.
static meshBase * Create(const std::string &fname)
Construct vtkMesh from filename.
Definition: meshBase.C:78
meshBase * f1
meshes from least to most refined (f3 - coarsest, f2 - finer, f1 - finest)
std::vector< std::vector< double > > checkAsymptoticRange()
Check if grids are in asymptotic range of convergence based on the computed GCIs (GCI_32 and GCI_21)...
std::vector< std::vector< double > > computeGCI_21()
Compute the GCI with respect to the finer and finest grids.
std::vector< std::vector< double > > computeOrderOfAccuracy()
Compute order of accuracy.
vtkSmartPointer< vtkDataSet > getDataSet() const
get this meshes&#39; dataSet
Definition: meshBase.H:308
OrderOfAccuracy(meshBase *_f3, meshBase *_f2, meshBase *_f1, std::vector< int > _arrayIDs, std::string transferType="Consistent Interpolation", double targetGCI=1.1)
nemId_t getNumberOfPoints() const
return the number of points
Definition: meshBase.H:545
vtkIdType id
id in .inp file
Definition: inpGeoMesh.C:128
void computeMeshWithResolution(double gciStar, const std::string &ofname)
Refine the coarsest mesh based on the target GCI, write to file with name ofname. ...
std::vector< std::vector< double > > computeDiff(meshBase *mesh, const std::vector< std::string > &newArrNames)
std::vector< std::string > f2ArrNames
names of data arrays transferred from f3 to f2 and from f2 to f1
virtual void write() const
write the mesh to file named after the private var &#39;filename&#39;.
Definition: meshBase.H:598
std::shared_ptr< meshBase > mesh
std::vector< int > relEIDs
array ids for integral of solutions on the most refined mesh, used in computing relative discretizati...
void computeRichardsonExtrapolation()
std::vector< std::vector< double > > diffF3F2
L2 norm of the difference in solution between f3 and f2.
std::vector< std::vector< double > > integrateOverMesh(const std::vector< int > &arrayIDs)
integrate arrays in arrayIDs over the mesh.
Definition: meshBase.C:387
std::vector< std::string > getNewArrayNames()
get new array names for use in transfer
Definition: meshBase.H:698
static std::shared_ptr< TransferBase > CreateTransferObject(meshBase *srcmsh, meshBase *trgmsh, const std::string &method)
std::vector< std::vector< double > > computeGCI_32()
Compute the GCI with respect to the coarsest and finer grids.
double r32
effective grid refinement ratios
std::vector< std::vector< double > > GCI_32
GCIs with respect to the coarse mesh (f3)
std::vector< std::vector< double > > computeResolution(double gciStar)
Compute the grid resolution required to obtain the desired gci/level of accuracy for each component a...
std::vector< T > flatten(const std::vector< std::vector< T >> &v)
std::vector< int > realDiffIDs
array ids for actual difference data