34 #include <libsupermesh-c.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> 60 massMatrix = Eigen::SparseMatrix<double, Eigen::ColMajor, long>(
67 quadrature->Initialize(VTK_TETRA, 4, 4,
TET4,
TET4W);
77 vtkSmartPointer<vtkPointData> sourcePointData =
sourceGrid->GetPointData();
78 for (
int arrayIdx = 0; arrayIdx < sourcePointData->GetNumberOfArrays();
101 const std::vector<int> &arrayIDs,
102 const std::vector<std::string> &newnames) {
125 for (
const int &arrayId : arrayIDs) {
133 std::cout <<
"Constructing supermesh..." << std::endl;
134 supermeshTimer.
start();
149 sourceConversionTimer.
start();
154 sourceConversionTimer.
stop();
155 std::cout <<
"source converted to libsupermesh format in " 156 << sourceConversionTimer.
elapsed() <<
" milliseconds." << std::endl;
166 targetConversionTimer.
start();
171 targetConversionTimer.
stop();
172 std::cout <<
"target converted to libsupermesh format in " 173 << targetConversionTimer.
elapsed() <<
" milliseconds." << std::endl;
178 intersectionSearchTimer.
start();
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);
184 intersectionSearchTimer.
stop();
185 std::cout <<
"intersection search completed in " 186 << intersectionSearchTimer.
elapsed() << std::endl;
189 intersectionCalcTimer.
start();
192 libsupermesh_tree_intersection_finder_query_output(&nindices);
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,
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) {
205 long ptIndex = enlist[i * 4 + j] * 3;
206 double pt[3] = {positions[ptIndex], positions[ptIndex + 1],
207 positions[ptIndex + 2]};
210 tet[offset + 1] = pt[1];
211 tet[offset + 2] = pt[2];
216 double *tets_c_buf =
new double[1000];
218 auto pushData = [
this](std::vector<double> tet_c,
long parent_a,
220 this->
tets_c.push_back(tet_c);
225 for (
long ai = 0; ai < nelements_a; ++ai)
227 double *tet_a = getTet(ai, enlist_a, positions_a);
229 for (
long bptr = ind_ptr[ai]; bptr < ind_ptr[ai + 1];
232 long bj = indices[bptr];
233 double *tet_b = getTet(bj, enlist_b, positions_b);
237 libsupermesh_intersect_tets_real(tet_a, tet_b, tets_c_buf, &n_tets_c);
241 for (
int ck = 0; ck < n_tets_c; ++ck) {
244 std::vector<double> tet_c;
245 tet_c.insert(tet_c.end(), &tets_c_buf[offs], &tets_c_buf[offs + 12]);
248 pushData(tet_c, ai, bj);
253 intersectionCalcTimer.
stop();
254 std::cout <<
"intersection calculation completed in " 255 << intersectionCalcTimer.
elapsed() <<
" milliseconds." << std::endl;
257 double totalVol = 0.;
260 libsupermesh_tetrahedron_volume(&tet[0], &vol);
262 std::cout <<
"NEGATIVE VOL" << std::endl;
265 std::cout << std::setprecision(15) <<
"supermesh volume : " << totalVol
267 std::cout <<
"number of elems : " << tets_c.size() << std::endl;
274 supermeshTimer.
stop();
275 std::cout <<
"Supermesh constructed in " << supermeshTimer.
elapsed()
276 <<
" milliseconds." << std::endl;
282 std::cout <<
"Constructing mass matrix..." << std::endl;
285 const double *weights =
quadrature->GetQuadratureWeights();
287 using Tripletd = Eigen::Triplet<double>;
288 std::vector<Tripletd> tripletList;
293 if (
targetGrid->GetCellType(cellId) != VTK_TETRA)
295 vtkTetra *tet = vtkTetra::SafeDownCast(
targetGrid->GetCell(cellId));
297 double detJ = vtkMeshQuality::TetVolume(tet);
299 for (
int qi = 0; qi <
quadrature->GetNumberOfQuadraturePoints(); ++qi) {
300 const double *psi =
quadrature->GetShapeFunctionWeights(qi);
301 double wi = weights[qi];
303 for (
int r = 0; r < 4; ++r) {
304 for (
int s = 0; s < 4; ++s) {
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));
315 massMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
318 std::cout <<
"Mass matrix constructed in " << timer.
elapsed()
319 <<
" milliseconds." << std::endl;
327 std::cout <<
"Constructing mixed mass matrix ..." << std::endl;
329 const double *weights =
quadrature->GetQuadratureWeights();
331 using Tripletd = Eigen::Triplet<double>;
332 std::vector<Tripletd> tripletList(
tets_c.size());
334 for (
long subCellIdx = 0; subCellIdx <
tets_c.size(); ++subCellIdx) {
335 std::vector<double> childTet =
tets_c[subCellIdx];
337 long sourceCellId =
parents_a[subCellIdx];
338 long targetCellId =
parents_b[subCellIdx];
341 vtkTetra *sourceParentTet = vtkTetra::SafeDownCast(
343 vtkTetra *targetParentTet = vtkTetra::SafeDownCast(
346 double childVertices[4][3];
347 for (
int i = 0; i < 4; ++i) {
349 childVertices[i][0] = childTet[offs];
350 childVertices[i][1] = childTet[offs + 1];
351 childVertices[i][2] = childTet[offs + 2];
354 double sourceParentVertices[4][3];
355 double targetParentVertices[4][3];
356 for (
int i = 0; i < 4; ++i) {
359 sourceParentTet->GetPoints()->GetPoint(i, x);
360 for (
int j = 0; j < 3; ++j)
361 sourceParentVertices[i][j] = x[j];
363 targetParentTet->GetPoints()->GetPoint(i, x);
364 for (
int j = 0; j < 3; ++j)
365 targetParentVertices[i][j] = x[j];
370 libsupermesh_tetrahedron_volume(&childTet[0], &detJ);
373 for (
int qi = 0; qi <
quadrature->GetNumberOfQuadraturePoints(); ++qi) {
374 const double *psi =
quadrature->GetShapeFunctionWeights(qi);
375 double wi = weights[qi];
377 double x[3] = {0., 0., 0.};
381 for (
int i = 0; i < 4; ++i) {
382 for (
int j = 0; j < 3; ++j)
383 x[j] += psi[i] * childVertices[i][j];
388 double srcPsi[4] = {};
389 vtkTetra::BarycentricCoords(
390 x, sourceParentVertices[0], sourceParentVertices[1],
391 sourceParentVertices[2], sourceParentVertices[3], srcPsi);
394 double tgtPsi[4] = {};
395 vtkTetra::BarycentricCoords(
396 x, targetParentVertices[0], targetParentVertices[1],
397 targetParentVertices[2], targetParentVertices[3], tgtPsi);
399 for (
int r = 0; r < 4; ++r) {
400 for (
int s = 0; s < 4; ++s) {
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));
411 mixedMassMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
415 std::cout <<
"Mixed mass matrix constructed in " << timer.
elapsed()
416 <<
" milliseconds." << std::endl;
425 std::cout <<
"Constructing load vector ..." << std::endl;
428 vtkSmartPointer<vtkDoubleArray> sourceArray = vtkDoubleArray::SafeDownCast(
429 sourceGrid->GetPointData()->GetArray(arrayId));
432 Eigen::VectorXd sourceValuesVector = Eigen::VectorXd(
numSourceNodes);
433 auto sourcePointValues = vtkDoubleArray::SafeDownCast(
434 sourceGrid->GetPointData()->GetArray(arrayId));
436 sourceValuesVector(i) = sourcePointValues->GetComponent(i, componentId);
442 std::cout <<
"Load vector constructed in " << timer.
elapsed()
443 <<
" milliseconds." << std::endl;
451 std::cout <<
"Transferring ..." << std::endl;
453 vtkSmartPointer<vtkDataArray> sourceArray =
454 sourceGrid->GetPointData()->GetArray(arrayId);
457 targetPointValues->SetName(sourceArray->GetName());
458 targetPointValues->SetNumberOfComponents(
459 sourceArray->GetNumberOfComponents());
461 Eigen::SparseLU<Eigen::SparseMatrix<double, Eigen::ColMajor>,
462 Eigen::COLAMDOrdering<int>>
467 for (
int componentId = 0; componentId < sourceArray->GetNumberOfComponents();
471 Eigen::VectorXd targetValuesVector = solver.solve(
loadVector);
473 for (
int targetNodeId = 0; targetNodeId <
numTargetNodes; ++targetNodeId) {
474 targetPointValues->InsertComponent(targetNodeId, componentId,
475 targetValuesVector(targetNodeId));
479 targetGrid->GetPointData()->AddArray(targetPointValues);
482 std::cout <<
"Transfer completed in " << timer.
elapsed() <<
" milliseconds." 489 vtkSmartPointer<vtkDataArray> sourceCellValues =
490 sourceGrid->GetCellData()->GetArray(cellArrayId);
493 sourcePointValues->SetName(sourceCellValues->GetName());
494 sourcePointValues->SetNumberOfComponents(
495 sourceCellValues->GetNumberOfComponents());
497 for (
int pointId = 0; pointId <
sourceGrid->GetNumberOfPoints(); ++pointId) {
499 sourceGrid->GetPointCells(pointId, incidentCellIds);
501 double *tuple =
new double[sourceCellValues->GetNumberOfComponents()]();
506 for (
int i = 0; i < incidentCellIds->GetNumberOfIds(); ++i) {
507 int cellId = incidentCellIds->GetId(i);
508 vtkTetra *tet = vtkTetra::SafeDownCast(
sourceGrid->GetCell(cellId));
510 double vol = vtkMeshQuality::TetVolume(tet);
513 for (
int compIdx = 0; compIdx < sourceCellValues->GetNumberOfComponents();
515 tuple[compIdx] += vol * sourceCellValues->GetComponent(cellId, compIdx);
518 double volAvg = volSum / incidentCellIds->GetNumberOfIds();
521 for (
int compIdx = 0; compIdx < sourceCellValues->GetNumberOfComponents();
523 tuple[compIdx] = tuple[compIdx] / volAvg;
531 vtkDataSet *
data,
long &nnodes,
int &dim,
long &nelements,
int &loc,
532 double *&positions,
long *&enlist,
long &initTetId) {
534 for (
int cellId = 0; cellId < data->GetNumberOfCells(); ++cellId) {
535 if (data->GetCellType(cellId) == VTK_TETRA) {
541 long numNodes = data->GetNumberOfPoints();
543 long numTets = data->GetNumberOfCells() - initTetId;
551 positions =
new double[dim * nnodes];
553 enlist =
new long[loc * nelements];
556 for (
int ptIdx = 0; ptIdx < numNodes; ++ptIdx) {
558 data->GetPoint(ptIdx, pt);
560 int offset = ptIdx * 3;
561 positions[offset] = pt[0];
562 positions[offset + 1] = pt[1];
563 positions[offset + 2] = pt[2];
567 for (
int cellId = initTetId; cellId < data->GetNumberOfCells(); ++cellId) {
568 vtkCell *tet = data->GetCell(cellId);
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);
586 mergePoints->InitPointInsertion(supermeshGridPoints, bounds,
tets_c.size());
590 for (
int ptIdx = 0; ptIdx < 4; ++ptIdx) {
591 int offs = ptIdx * 3;
593 double x[3] = {tet[offs], tet[offs + 1], tet[offs + 2]};
595 int inserted = mergePoints->InsertUniquePoint(x, ptId);
603 for (
auto tet : tets_c) {
606 Eigen::Vector3d faceVertices[3];
607 Eigen::Vector3d topVertex;
612 for (
int ptIdx = 0; ptIdx < 4; ++ptIdx) {
613 int offs = ptIdx * 3;
615 double x[3] = {tet[offs], tet[offs + 1], tet[offs + 2]};
618 faceVertices[ptIdx] = Eigen::Vector3d(x[0], x[1], x[2]);
620 topVertex = Eigen::Vector3d(x[0], x[1], x[2]);
622 ptIds[ptIdx] = mergePoints->IsInsertedPoint(x);
624 if (ptIds[ptIdx] < 0)
625 std::cout <<
"INVALID POINT" << std::endl;
628 Eigen::Vector3d cross = (faceVertices[2] - faceVertices[0])
629 .cross(faceVertices[1] - faceVertices[0]);
630 cross = cross / cross.norm();
632 Eigen::Vector3d topDirection = topVertex - faceVertices[0];
633 topDirection = topDirection / topDirection.norm();
636 if (cross.dot(topDirection) > 0)
637 std::swap(ptIds[0], ptIds[2]);
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]);
645 tetArray->InsertNextCell(tetra);
650 std::cout <<
"Converted grid has : " <<
supermeshGrid->GetNumberOfCells()
651 <<
" cells." << std::endl;
654 std::cout <<
"Reference grid has " << tets_c.size() <<
" cells." 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;
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;
676 vtkSmartPointer<vtkPolyData>
680 surfaceFilter->SetPassThroughPointIds(
true);
681 surfaceFilter->SetOriginalPointIdsName(
"original_point_ids");
683 surfaceFilter->SetInputData(grid);
684 surfaceFilter->Update();
686 vtkPolyData *surface = surfaceFilter->GetOutput();
690 surfaceCopy->DeepCopy(surface);
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.
Eigen::VectorXd loadVector
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)
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' dataSet
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.
std::vector< long > parents_b
Eigen::SparseMatrix< double, Eigen::ColMajor, long > mixedMassMatrix
std::vector< long > parents_a
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.