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.
ConservativeVolumeTransfer.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 #include "AuxiliaryFunctions.H"
32 #include "Mesh/vtkMesh.H"
33 
34 #include <libsupermesh-c.h>
35 
36 #include <vtkCell.h>
37 #include <vtkCellArray.h>
38 #include <vtkCellData.h>
39 #include <vtkCellType.h>
40 #include <vtkDataSetSurfaceFilter.h>
41 #include <vtkDoubleArray.h>
42 #include <vtkMergePoints.h>
43 #include <vtkMeshQuality.h>
44 #include <vtkPointData.h>
45 #include <vtkTetra.h>
46 
48  meshBase *_target) {
49  source = _source;
50  target = _target;
51 
52  // Set grids, allocate vectors/matrices, quadrature scheme and construct
53  // transfer objects
54  sourceGrid = vtkUnstructuredGrid::SafeDownCast(source->getDataSet());
55  targetGrid = vtkUnstructuredGrid::SafeDownCast(target->getDataSet());
56 
57  numSourceNodes = sourceGrid->GetNumberOfPoints();
58  numTargetNodes = targetGrid->GetNumberOfPoints();
59 
60  massMatrix = Eigen::SparseMatrix<double, Eigen::ColMajor, long>(
62  mixedMassMatrix = Eigen::SparseMatrix<double, Eigen::ColMajor, long>(
64 
65  // set quadrature scheme
67  quadrature->Initialize(VTK_TETRA, 4, 4, TET4, TET4W);
68  // quadrature->Initialize(VTK_TETRA, 4, 8, TET8, TET8W);
69 }
70 
71 int ConservativeVolumeTransfer::run(const std::vector<std::string> &newnames) {
75 
76  // transfer all point data
77  vtkSmartPointer<vtkPointData> sourcePointData = sourceGrid->GetPointData();
78  for (int arrayIdx = 0; arrayIdx < sourcePointData->GetNumberOfArrays();
79  ++arrayIdx) {
80  transfer(arrayIdx);
81  }
82 
83  /*
84  vtkSmartPointer<vtkCellData> sourceCellData = sourceGrid->GetCellData();
85  for(int arrayIdx = 0; arrayIdx < sourceCellData->GetNumberOfArrays();
86  ++arrayIdx)
87  {
88  // TODO implement transferCellData
89  }
90  */
91  return 0;
92 }
93 
98 }
99 
101  const std::vector<int> &arrayIDs,
102  const std::vector<std::string> &newnames) {
103  /*
104  if(surfaceTransferEnabled)
105  {
106  // extract source surface
107  vtkSmartPointer<vtkPolyData> sourceSurface = extractSurface(sourceGrid);
108  vtkSmartPointer<vtkPolyData> targetSurface = extractSurface(targetGrid);
109 
110  vtkMesh* sourceMesh = new vtkMesh(sourceSurface, "sourceSurface.vtp");
111  vtkMesh* targetMesh = new vtkMesh(targetSurface, "targetSurface.vtp");
112 
113  sourceMesh->write("source_surface_test.vtp");
114  targetMesh->write("target_surface_test.vtp");
115 
116  ConservativeSurfaceTransfer* surfaceTransfer = new
117  ConservativeSurfaceTransfer(sourceMesh, targetMesh);
118 
119  surfaceTransfer->transferPointData(arrayIDs);
120 
121  targetMesh->write("target_surface_test.vtp");
122  }
123  */
124 
125  for (const int &arrayId : arrayIDs) {
126  transfer(arrayId);
127  }
128  return 0;
129 }
130 
132  nemAux::Timer supermeshTimer;
133  std::cout << "Constructing supermesh..." << std::endl;
134  supermeshTimer.start();
135 
136  /*
137  * A - source
138  * B - target
139  */
140 
141  long nnodes_a;
142  int dim_a;
143  long nelements_a;
144  int loc_a;
145  double *positions_a;
146  long *enlist_a;
147 
148  nemAux::Timer sourceConversionTimer;
149  sourceConversionTimer.start();
150 
151  getLibSupermeshData(source->getDataSet(), nnodes_a, dim_a, nelements_a, loc_a,
152  positions_a, enlist_a, initSourceTetId);
153 
154  sourceConversionTimer.stop();
155  std::cout << "source converted to libsupermesh format in "
156  << sourceConversionTimer.elapsed() << " milliseconds." << std::endl;
157 
158  long nnodes_b;
159  int dim_b;
160  long nelements_b;
161  int loc_b;
162  double *positions_b;
163  long *enlist_b;
164 
165  nemAux::Timer targetConversionTimer;
166  targetConversionTimer.start();
167 
168  getLibSupermeshData(target->getDataSet(), nnodes_b, dim_b, nelements_b, loc_b,
169  positions_b, enlist_b, initTargetTetId);
170 
171  targetConversionTimer.stop();
172  std::cout << "target converted to libsupermesh format in "
173  << targetConversionTimer.elapsed() << " milliseconds." << std::endl;
174 
175  // volumeCheck();
176 
177  nemAux::Timer intersectionSearchTimer;
178  intersectionSearchTimer.start();
179 
180  libsupermesh_tree_intersection_finder_set_input(
181  &nnodes_a, &dim_a, &nelements_a, &loc_a, &nnodes_b, &dim_b, &nelements_b,
182  &loc_b, positions_a, enlist_a, positions_b, enlist_b);
183 
184  intersectionSearchTimer.stop();
185  std::cout << "intersection search completed in "
186  << intersectionSearchTimer.elapsed() << std::endl;
187 
188  nemAux::Timer intersectionCalcTimer;
189  intersectionCalcTimer.start();
190 
191  long nindices;
192  libsupermesh_tree_intersection_finder_query_output(&nindices);
193 
194  long nelements = nelements_a;
195  long *indices = new long[nindices];
196  long *ind_ptr = new long[nelements_a + 1];
197  libsupermesh_tree_intersection_finder_get_output(&nelements, &nindices,
198  indices, ind_ptr);
199 
200  auto getTet = [](long i, long *enlist, double *positions) -> double * {
201  double *tet = new double[3 * 4];
202  for (int j = 0; j < 4; ++j) {
203  // i*4 + j : index of node j in tet i
204  // multiply this by 3 to account for offset in positions array
205  long ptIndex = enlist[i * 4 + j] * 3;
206  double pt[3] = {positions[ptIndex], positions[ptIndex + 1],
207  positions[ptIndex + 2]};
208  int offset = j * 3;
209  tet[offset] = pt[0];
210  tet[offset + 1] = pt[1];
211  tet[offset + 2] = pt[2];
212  }
213  return tet;
214  };
215 
216  double *tets_c_buf = new double[1000];
217 
218  auto pushData = [this](std::vector<double> tet_c, long parent_a,
219  long parent_b) {
220  this->tets_c.push_back(tet_c);
221  this->parents_a.push_back(parent_a);
222  this->parents_b.push_back(parent_b);
223  };
224 
225  for (long ai = 0; ai < nelements_a; ++ai) // cells in A
226  {
227  double *tet_a = getTet(ai, enlist_a, positions_a);
228 
229  for (long bptr = ind_ptr[ai]; bptr < ind_ptr[ai + 1];
230  ++bptr) // indices of intersection candidates in B
231  {
232  long bj = indices[bptr]; // get index in b
233  double *tet_b = getTet(bj, enlist_b, positions_b);
234 
235  int n_tets_c;
236  // TODO if n_tets_c > buffer size -> reallocate
237  libsupermesh_intersect_tets_real(tet_a, tet_b, tets_c_buf, &n_tets_c);
238  if (!n_tets_c)
239  continue;
240 
241  for (int ck = 0; ck < n_tets_c; ++ck) {
242  int offs = ck * 12;
243 
244  std::vector<double> tet_c;
245  tet_c.insert(tet_c.end(), &tets_c_buf[offs], &tets_c_buf[offs + 12]);
246 
247  // push tet and its parent indices in A and B (source and target)
248  pushData(tet_c, ai, bj);
249  }
250  }
251  }
252 
253  intersectionCalcTimer.stop();
254  std::cout << "intersection calculation completed in "
255  << intersectionCalcTimer.elapsed() << " milliseconds." << std::endl;
256 
257  double totalVol = 0.;
258  for (auto tet : tets_c) {
259  double vol;
260  libsupermesh_tetrahedron_volume(&tet[0], &vol);
261  if (vol < 0)
262  std::cout << "NEGATIVE VOL" << std::endl;
263  totalVol += vol;
264  }
265  std::cout << std::setprecision(15) << "supermesh volume : " << totalVol
266  << std::endl;
267  std::cout << "number of elems : " << tets_c.size() << std::endl;
268 
269  // free
270  delete[] indices;
271  delete[] ind_ptr;
272  delete[] tets_c_buf;
273 
274  supermeshTimer.stop();
275  std::cout << "Supermesh constructed in " << supermeshTimer.elapsed()
276  << " milliseconds." << std::endl;
277  return 0;
278 }
279 
281  nemAux::Timer timer;
282  std::cout << "Constructing mass matrix..." << std::endl;
283  timer.start();
284 
285  const double *weights = quadrature->GetQuadratureWeights();
286 
287  using Tripletd = Eigen::Triplet<double>;
288  std::vector<Tripletd> tripletList;
289 
290  // TODO start from initTargetTetId
291  for (long cellId = initTargetTetId; cellId < targetGrid->GetNumberOfCells();
292  ++cellId) {
293  if (targetGrid->GetCellType(cellId) != VTK_TETRA)
294  continue;
295  vtkTetra *tet = vtkTetra::SafeDownCast(targetGrid->GetCell(cellId));
296 
297  double detJ = vtkMeshQuality::TetVolume(tet);
298 
299  for (int qi = 0; qi < quadrature->GetNumberOfQuadraturePoints(); ++qi) {
300  const double *psi = quadrature->GetShapeFunctionWeights(qi);
301  double wi = weights[qi];
302 
303  for (int r = 0; r < 4; ++r) {
304  for (int s = 0; s < 4; ++s) {
305  // TODO check that point ids are zero indexed
306  long rGlob = tet->GetPointId(r);
307  long sGlob = tet->GetPointId(s);
308  tripletList.push_back(
309  Tripletd(rGlob, sGlob, wi * psi[r] * psi[s] * detJ));
310  }
311  }
312  }
313  }
314 
315  massMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
316 
317  timer.stop();
318  std::cout << "Mass matrix constructed in " << timer.elapsed()
319  << " milliseconds." << std::endl;
320 
321  return 0;
322 }
323 
325  nemAux::Timer timer;
326  timer.start();
327  std::cout << "Constructing mixed mass matrix ..." << std::endl;
328 
329  const double *weights = quadrature->GetQuadratureWeights();
330 
331  using Tripletd = Eigen::Triplet<double>;
332  std::vector<Tripletd> tripletList(tets_c.size());
333 
334  for (long subCellIdx = 0; subCellIdx < tets_c.size(); ++subCellIdx) {
335  std::vector<double> childTet = tets_c[subCellIdx];
336 
337  long sourceCellId = parents_a[subCellIdx];
338  long targetCellId = parents_b[subCellIdx];
339 
340  // TODO check indexing for initSource/initTargetTetIds
341  vtkTetra *sourceParentTet = vtkTetra::SafeDownCast(
342  sourceGrid->GetCell(initSourceTetId + sourceCellId));
343  vtkTetra *targetParentTet = vtkTetra::SafeDownCast(
344  targetGrid->GetCell(initTargetTetId + targetCellId));
345 
346  double childVertices[4][3];
347  for (int i = 0; i < 4; ++i) {
348  int offs = i * 3;
349  childVertices[i][0] = childTet[offs];
350  childVertices[i][1] = childTet[offs + 1];
351  childVertices[i][2] = childTet[offs + 2];
352  }
353 
354  double sourceParentVertices[4][3];
355  double targetParentVertices[4][3];
356  for (int i = 0; i < 4; ++i) {
357  double x[3];
358 
359  sourceParentTet->GetPoints()->GetPoint(i, x);
360  for (int j = 0; j < 3; ++j)
361  sourceParentVertices[i][j] = x[j];
362 
363  targetParentTet->GetPoints()->GetPoint(i, x);
364  for (int j = 0; j < 3; ++j)
365  targetParentVertices[i][j] = x[j];
366  }
367 
368  // TODO check vol = detJ
369  double detJ;
370  libsupermesh_tetrahedron_volume(&childTet[0], &detJ);
371  // if(detJ < 1e-20) continue;
372 
373  for (int qi = 0; qi < quadrature->GetNumberOfQuadraturePoints(); ++qi) {
374  const double *psi = quadrature->GetShapeFunctionWeights(qi);
375  double wi = weights[qi];
376 
377  double x[3] = {0., 0., 0.};
378 
379  // get geometric coordinate
380  // TODO make sure x is contained in subtet
381  for (int i = 0; i < 4; ++i) {
382  for (int j = 0; j < 3; ++j)
383  x[j] += psi[i] * childVertices[i][j];
384  }
385 
386  // TODO check source/target psis are positive and sum to 1
387  // source shape function val
388  double srcPsi[4] = {};
389  vtkTetra::BarycentricCoords(
390  x, sourceParentVertices[0], sourceParentVertices[1],
391  sourceParentVertices[2], sourceParentVertices[3], srcPsi);
392 
393  // target shape function val
394  double tgtPsi[4] = {};
395  vtkTetra::BarycentricCoords(
396  x, targetParentVertices[0], targetParentVertices[1],
397  targetParentVertices[2], targetParentVertices[3], tgtPsi);
398 
399  for (int r = 0; r < 4; ++r) {
400  for (int s = 0; s < 4; ++s) {
401  // TODO check that point ids are zero indexed
402  long rGlobal = targetParentTet->GetPointId(r);
403  long sGlobal = sourceParentTet->GetPointId(s);
404  tripletList.push_back(
405  Tripletd(rGlobal, sGlobal, wi * tgtPsi[r] * srcPsi[s] * detJ));
406  }
407  }
408  }
409  }
410 
411  mixedMassMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
412 
413  timer.stop();
414 
415  std::cout << "Mixed mass matrix constructed in " << timer.elapsed()
416  << " milliseconds." << std::endl;
417 
418  return 0;
419 }
420 
422  int componentId) {
423  nemAux::Timer timer;
424 
425  std::cout << "Constructing load vector ..." << std::endl;
426  timer.start();
427 
428  vtkSmartPointer<vtkDoubleArray> sourceArray = vtkDoubleArray::SafeDownCast(
429  sourceGrid->GetPointData()->GetArray(arrayId));
430 
431  // allocate and populate source values vector
432  Eigen::VectorXd sourceValuesVector = Eigen::VectorXd(numSourceNodes);
433  auto sourcePointValues = vtkDoubleArray::SafeDownCast(
434  sourceGrid->GetPointData()->GetArray(arrayId));
435  for (int i = 0; i < numSourceNodes; ++i) {
436  sourceValuesVector(i) = sourcePointValues->GetComponent(i, componentId);
437  }
438 
439  loadVector = mixedMassMatrix * sourceValuesVector;
440  timer.stop();
441 
442  std::cout << "Load vector constructed in " << timer.elapsed()
443  << " milliseconds." << std::endl;
444 
445  return 0;
446 }
447 
449  nemAux::Timer timer;
450  timer.start();
451  std::cout << "Transferring ..." << std::endl;
452 
453  vtkSmartPointer<vtkDataArray> sourceArray =
454  sourceGrid->GetPointData()->GetArray(arrayId);
455 
456  auto targetPointValues = vtkSmartPointer<vtkDoubleArray>::New();
457  targetPointValues->SetName(sourceArray->GetName());
458  targetPointValues->SetNumberOfComponents(
459  sourceArray->GetNumberOfComponents());
460 
461  Eigen::SparseLU<Eigen::SparseMatrix<double, Eigen::ColMajor>,
462  Eigen::COLAMDOrdering<int>>
463  solver;
464  solver.analyzePattern(massMatrix);
465  solver.factorize(massMatrix);
466 
467  for (int componentId = 0; componentId < sourceArray->GetNumberOfComponents();
468  ++componentId) {
469  constructLoadVector(arrayId, componentId);
470 
471  Eigen::VectorXd targetValuesVector = solver.solve(loadVector);
472 
473  for (int targetNodeId = 0; targetNodeId < numTargetNodes; ++targetNodeId) {
474  targetPointValues->InsertComponent(targetNodeId, componentId,
475  targetValuesVector(targetNodeId));
476  }
477  }
478 
479  targetGrid->GetPointData()->AddArray(targetPointValues);
480 
481  timer.stop();
482  std::cout << "Transfer completed in " << timer.elapsed() << " milliseconds."
483  << std::endl;
484 
485  return 0;
486 }
487 
489  vtkSmartPointer<vtkDataArray> sourceCellValues =
490  sourceGrid->GetCellData()->GetArray(cellArrayId);
491 
492  auto sourcePointValues = vtkSmartPointer<vtkDoubleArray>::New();
493  sourcePointValues->SetName(sourceCellValues->GetName());
494  sourcePointValues->SetNumberOfComponents(
495  sourceCellValues->GetNumberOfComponents());
496 
497  for (int pointId = 0; pointId < sourceGrid->GetNumberOfPoints(); ++pointId) {
498  auto incidentCellIds = vtkSmartPointer<vtkIdList>::New();
499  sourceGrid->GetPointCells(pointId, incidentCellIds);
500 
501  double *tuple = new double[sourceCellValues->GetNumberOfComponents()]();
502 
503  double volSum = 0.;
504 
505  // get contribution from each incident cell
506  for (int i = 0; i < incidentCellIds->GetNumberOfIds(); ++i) {
507  int cellId = incidentCellIds->GetId(i);
508  vtkTetra *tet = vtkTetra::SafeDownCast(sourceGrid->GetCell(cellId));
509 
510  double vol = vtkMeshQuality::TetVolume(tet);
511  volSum += vol;
512  // ... at each component
513  for (int compIdx = 0; compIdx < sourceCellValues->GetNumberOfComponents();
514  ++compIdx) {
515  tuple[compIdx] += vol * sourceCellValues->GetComponent(cellId, compIdx);
516  }
517  }
518  double volAvg = volSum / incidentCellIds->GetNumberOfIds();
519 
520  // divide by volume average
521  for (int compIdx = 0; compIdx < sourceCellValues->GetNumberOfComponents();
522  ++compIdx) {
523  tuple[compIdx] = tuple[compIdx] / volAvg;
524  }
525  }
526 
527  return 0;
528 }
529 
531  vtkDataSet *data, long &nnodes, int &dim, long &nelements, int &loc,
532  double *&positions, long *&enlist, long &initTetId) {
533  initTetId = 0;
534  for (int cellId = 0; cellId < data->GetNumberOfCells(); ++cellId) {
535  if (data->GetCellType(cellId) == VTK_TETRA) {
536  initTetId = cellId;
537  break;
538  }
539  }
540 
541  long numNodes = data->GetNumberOfPoints();
542  // assume remaining cells are tets
543  long numTets = data->GetNumberOfCells() - initTetId;
544 
545  nnodes = numNodes;
546  dim = 3;
547  nelements = numTets;
548  loc = 4;
549 
550  // coordinates of nodes
551  positions = new double[dim * nnodes];
552  // element-node graph
553  enlist = new long[loc * nelements];
554 
555  // get coordinates
556  for (int ptIdx = 0; ptIdx < numNodes; ++ptIdx) {
557  double pt[3];
558  data->GetPoint(ptIdx, pt);
559 
560  int offset = ptIdx * 3;
561  positions[offset] = pt[0];
562  positions[offset + 1] = pt[1];
563  positions[offset + 2] = pt[2];
564  }
565 
566  // get element-node graph
567  for (int cellId = initTetId; cellId < data->GetNumberOfCells(); ++cellId) {
568  vtkCell *tet = data->GetCell(cellId);
569 
570  int offset = (cellId - initTetId) * 4;
571  enlist[offset] = tet->GetPointId(0);
572  enlist[offset + 1] = tet->GetPointId(1);
573  enlist[offset + 2] = tet->GetPointId(2);
574  enlist[offset + 3] = tet->GetPointId(3);
575  }
576 }
577 
580 
581  auto mergePoints = vtkSmartPointer<vtkMergePoints>::New();
582  auto supermeshGridPoints = vtkSmartPointer<vtkPoints>::New();
583  double bounds[6];
584  sourceGrid->GetBounds(bounds);
585 
586  mergePoints->InitPointInsertion(supermeshGridPoints, bounds, tets_c.size());
587 
588  // insert points
589  for (auto tet : tets_c) {
590  for (int ptIdx = 0; ptIdx < 4; ++ptIdx) {
591  int offs = ptIdx * 3;
592 
593  double x[3] = {tet[offs], tet[offs + 1], tet[offs + 2]};
594  vtkIdType ptId;
595  int inserted = mergePoints->InsertUniquePoint(x, ptId);
596  }
597  }
598 
599  supermeshGrid->SetPoints(supermeshGridPoints);
600 
601  auto tetArray = vtkSmartPointer<vtkCellArray>::New();
602  // add tets
603  for (auto tet : tets_c) {
604  auto tetra = vtkSmartPointer<vtkTetra>::New();
605 
606  Eigen::Vector3d faceVertices[3];
607  Eigen::Vector3d topVertex;
608 
609  vtkIdType ptIds[4];
610 
611  // get points of face and "top" vertex
612  for (int ptIdx = 0; ptIdx < 4; ++ptIdx) {
613  int offs = ptIdx * 3;
614 
615  double x[3] = {tet[offs], tet[offs + 1], tet[offs + 2]};
616 
617  if (ptIdx < 3)
618  faceVertices[ptIdx] = Eigen::Vector3d(x[0], x[1], x[2]);
619  else
620  topVertex = Eigen::Vector3d(x[0], x[1], x[2]);
621 
622  ptIds[ptIdx] = mergePoints->IsInsertedPoint(x);
623 
624  if (ptIds[ptIdx] < 0)
625  std::cout << "INVALID POINT" << std::endl;
626  }
627 
628  Eigen::Vector3d cross = (faceVertices[2] - faceVertices[0])
629  .cross(faceVertices[1] - faceVertices[0]);
630  cross = cross / cross.norm();
631 
632  Eigen::Vector3d topDirection = topVertex - faceVertices[0];
633  topDirection = topDirection / topDirection.norm();
634 
635  // if negative, reverse first 3 point ids
636  if (cross.dot(topDirection) > 0)
637  std::swap(ptIds[0], ptIds[2]);
638 
639  tetra->GetPointIds()->SetId(0, ptIds[0]);
640  tetra->GetPointIds()->SetId(1, ptIds[1]);
641  tetra->GetPointIds()->SetId(2, ptIds[2]);
642  tetra->GetPointIds()->SetId(3, ptIds[3]);
643 
644  // take first 3 - orient so that corresponding normal points to 4th
645  tetArray->InsertNextCell(tetra);
646  }
647 
648  supermeshGrid->SetCells(VTK_TETRA, tetArray);
649 
650  std::cout << "Converted grid has : " << supermeshGrid->GetNumberOfCells()
651  << " cells." << std::endl;
652 
653  if (supermeshGrid->GetNumberOfCells() != tets_c.size()) {
654  std::cout << "Reference grid has " << tets_c.size() << " cells."
655  << std::endl;
656  }
657 
658  return 0;
659 }
660 
662  for (int i = initSourceTetId; i < sourceGrid->GetNumberOfCells(); ++i) {
663  vtkTetra *tet = vtkTetra::SafeDownCast(sourceGrid->GetCell(i));
664  if (vtkMeshQuality::TetVolume(tet) < 0.) {
665  std::cout << "source cell " << i << " has negative volume" << std::endl;
666  }
667  }
668  for (int i = initTargetTetId; i < targetGrid->GetNumberOfCells(); ++i) {
669  vtkTetra *tet = vtkTetra::SafeDownCast(targetGrid->GetCell(i));
670  if (vtkMeshQuality::TetVolume(tet) < 0.) {
671  std::cout << "target cell " << i << " has negative volume" << std::endl;
672  }
673  }
674 }
675 
676 vtkSmartPointer<vtkPolyData>
677 ConservativeVolumeTransfer::extractSurface(vtkUnstructuredGrid *grid) {
678  // extract surface
679  auto surfaceFilter = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
680  surfaceFilter->SetPassThroughPointIds(true);
681  surfaceFilter->SetOriginalPointIdsName("original_point_ids");
682 
683  surfaceFilter->SetInputData(grid);
684  surfaceFilter->Update();
685 
686  vtkPolyData *surface = surfaceFilter->GetOutput();
687 
688  // polydata appears to be freed once dataset filter is freed, make deep copy
689  auto surfaceCopy = vtkSmartPointer<vtkPolyData>::New();
690  surfaceCopy->DeepCopy(surface);
691 
692  return surfaceCopy;
693 }
vtkSmartPointer< vtkPolyData > extractSurface(vtkUnstructuredGrid *grid)
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).
vtkSmartPointer< vtkUnstructuredGrid > targetGrid
int constructLoadVector(int arrayId, int componentId)
Construct load vector corresponding to a given array and component.
std::vector< std::vector< double > > tets_c
A brief description of meshBase.
Definition: meshBase.H:64
geoMeshBase * New(MeshType meshType)
Create a new mesh object.
void getLibSupermeshData(vtkDataSet *data, long &nnodes, int &dim, long &nelements, int &loc, double *&positions, long *&enlist, long &initTetId)
meshBase * target
Definition: TransferBase.H:106
int interpolateCellDataToPoints(int cellArrayId)
ConservativeVolumeTransfer(meshBase *_source, meshBase *_target)
Eigen::SparseMatrix< double, Eigen::ColMajor, long > massMatrix
int convertSupermeshToUnstructuredGrid()
Convertes supermesh to an unstructured grid.
vtkSmartPointer< vtkDataSet > getDataSet() const
get this meshes&#39; dataSet
Definition: meshBase.H:308
vtkSmartPointer< vtkUnstructuredGrid > supermeshGrid
int transferPointData(const std::vector< int > &arrayIDs, const std::vector< std::string > &newnames=std::vector< std::string >())
Transfer point data with given ids from source to target.
Eigen::SparseMatrix< double, Eigen::ColMajor, long > mixedMassMatrix
int constructMassMatrix()
Construct mass matrix corresponding to target.
vtkSmartPointer< vtkUnstructuredGrid > sourceGrid
int constructMixedMassMatrix()
Construct mixed mass matrix corresponding to the source and target.
vtkSmartPointer< vtkQuadratureSchemeDefinition > quadrature
int transfer(int arrayId)
Transfer array given its id.
int run(const std::vector< std::string > &newnames=std::vector< std::string >()) override
Transfer all fields.
int constructSupermesh()
Construct supermesh.
meshBase * source
Definition: TransferBase.H:105