OGS
ComputeNaturalCoordsAlgorithm.h
Go to the documentation of this file.
1
10#pragma once
11
12#include <vtkCell.h>
13#include <vtkLine.h>
14#include <vtkPointData.h>
15
16#include <algorithm>
17
19#include "FindCellsForPoints.h"
23
25{
27{
28 Eigen::MatrixXd natural_coords;
29 Eigen::MatrixXd real_coords;
30 Eigen::VectorX<vtkIdType> bulk_element_ids;
31 Eigen::VectorX<vtkIdType> point_cloud_node_ids;
32 bool success;
33};
34
36{
37public:
38 void append(Eigen::Vector3d const& natural_coords,
39 Eigen::Vector3d const& real_coords,
40 vtkIdType bulk_element_id,
41 vtkIdType point_cloud_node_id)
42 {
43 natural_coordss.push_back(natural_coords);
44 real_coordss.push_back(real_coords);
45 bulk_element_ids.push_back(bulk_element_id);
46 point_cloud_node_ids.push_back(point_cloud_node_id);
47 }
48
49 void fail() { success = false; }
50
52 {
53 auto bei = Eigen::Map<Eigen::VectorX<vtkIdType>>(
54 bulk_element_ids.data(), bulk_element_ids.size());
55 auto pcni = Eigen::Map<Eigen::VectorX<vtkIdType>>(
57 return {conv(natural_coordss), conv(real_coordss), bei, pcni, success};
58 }
59
60private:
61 static Eigen::MatrixXd conv(std::vector<Eigen::Vector3d> const& in)
62 {
63 Eigen::MatrixXd out(in.size(), 3);
64 for (std::size_t i = 0; i < in.size(); ++i)
65 {
66 out.row(i).noalias() = in[i].transpose();
67 }
68 return out;
69 }
70
71 std::vector<Eigen::Vector3d> natural_coordss;
72 std::vector<Eigen::Vector3d> real_coordss;
73 std::vector<vtkIdType> bulk_element_ids;
74 std::vector<vtkIdType> point_cloud_node_ids;
75 bool success = true;
76};
77
79 vtkUnstructuredGrid* const bulk_mesh, Eigen::MatrixXd const& real_coords,
80 double const tolerance, int const max_iter)
81{
82 // Check inputs ------------------------------------------------------------
83
84 if (real_coords.cols() != 3)
85 {
86 OGS_FATAL("Wrong number of input coordinates");
87 }
88
89 // General definitions -----------------------------------------------------
90 using SolverRegistry =
93
94 double const real_coords_tolerance = tolerance;
95
96 // Initialization ----------------------------------------------------------
97 FindCellsForPoints findCellsForPoints;
98 findCellsForPoints.initialize(bulk_mesh);
99
101
102 // Do computation for each point ------------------------------------------
103 for (Eigen::Index rc_idx = 0; rc_idx < real_coords.rows(); ++rc_idx)
104 {
105 Eigen::RowVector3d const real_coords_single_point =
106 real_coords.row(rc_idx);
107
108 // Find cells for point
109 auto const filtered_bulk_mesh =
110 findCellsForPoints.find(real_coords_single_point, tolerance);
111
112 // Check multiplicity
113 int const actual_multiplicity = filtered_bulk_mesh->GetNumberOfCells();
114 if (actual_multiplicity == 0)
115 {
116 OGS_FATAL(
117 "Did not find any cell for the point {} (coordinates: {})",
118 rc_idx, real_coords_single_point);
119 }
120 assert(actual_multiplicity > 0);
121 if (actual_multiplicity != 1)
122 {
123 INFO(
124 "Found more then one cell (namely {}) for point #{} "
125 "(coordinates: {})",
126 actual_multiplicity, rc_idx, real_coords_single_point);
127 }
128
129 // Convert to OGS
130 std::unique_ptr<MeshLib::Mesh> ogs_mesh(
132 filtered_bulk_mesh, "filtered_bulk_mesh"));
133
134 auto const* bulk_element_ids = MeshLib::bulkElementIDs(*ogs_mesh);
135
136 auto const& elements = ogs_mesh->getElements();
137
138 // Compute natural coordinates
139 // Found a solution, no need to test other elements ignoring
140 // multiplicity.
141 constexpr std::size_t elt_idx = 0;
142 auto const& element = *elements[elt_idx];
143 auto const bulk_element_id = bulk_element_ids->getComponent(elt_idx, 0);
144
145 auto const& solver = SolverRegistry::getFor(element);
146 auto const opt_natural_coords = solver.solve(
147 element, real_coords_single_point, max_iter, real_coords_tolerance);
148
149 result.append(opt_natural_coords, real_coords_single_point,
150 bulk_element_id, rc_idx);
151 }
152
153 return result.finished();
154}
155
156template <typename T>
157void addPointData(vtkUnstructuredGrid* grid, std::string const& name,
158 Eigen::MatrixX<T> const& data)
159{
160 INFO("converting {}", name);
161 vtkNew<vtkAOSDataArrayTemplate<T>> array;
162 array->SetName(name.c_str());
163 array->SetNumberOfComponents(data.cols());
164 array->SetNumberOfTuples(grid->GetNumberOfPoints());
165
166 if (grid->GetNumberOfPoints() != data.rows())
167 {
168 OGS_FATAL(
169 "Got {} rows in the table but expected {} rows, same as number of "
170 "points in the grid.",
171 data.rows(), grid->GetNumberOfPoints());
172 }
173 for (Eigen::Index i = 0; i < data.rows(); ++i)
174 {
175 // copy to contiguous storage
176 Eigen::RowVectorX<T> const row = data.row(i);
177
178 array->SetTypedTuple(i, row.data());
179 DBUG("> {}", row);
180 }
181
182 grid->GetPointData()->AddArray(array);
183}
184
191vtkSmartPointer<vtkUnstructuredGrid> toVTKGrid(
192 ComputeNaturalCoordsResult const& result)
193{
194 INFO("converting points");
195 auto const n_pts = result.natural_coords.rows();
196 if (n_pts == 0)
197 {
198 OGS_FATAL(
199 "No point was found in the mesh. Please check whether all anchors "
200 "are within the model region.");
201 }
202 else if (n_pts == 1)
203 {
204 OGS_FATAL(
205 "Only one point was found in the mesh. Please check whether all "
206 "anchors are within the model region.");
207 }
208 else if (n_pts % 2 != 0)
209 {
210 // number should be even if multiplicity is ignored
211 OGS_FATAL(
212 "Number of points is not even. Anchors are believed to consist of "
213 "a start and an end point.");
214 }
215
216 vtkNew<vtkUnstructuredGrid> grid;
217
218 // Points ------------------------------------------------------------------
219 vtkNew<vtkPoints> points;
220 points->SetNumberOfPoints(n_pts);
221
222 auto const& css = result.real_coords;
223 for (Eigen::Index i = 0; i < css.rows(); ++i)
224 {
225 points->SetPoint(i, css(i, 0), css(i, 1), css(i, 2));
226
227 if ((i % 2) == 1)
228 {
229 vtkNew<vtkLine> line;
230 line->GetPointIds()->SetId(0, i - 1);
231 line->GetPointIds()->SetId(1, i);
232 grid->InsertNextCell(line->GetCellType(), line->GetPointIds());
233 }
234 }
235
236 grid->SetPoints(points);
237
238 // Point data --------------------------------------------------------------
239 addPointData<double>(grid, "natural_coordinates", result.natural_coords);
240 addPointData<std::size_t>(grid, "bulk_element_ids",
241 result.bulk_element_ids.cast<std::size_t>());
242 addPointData<std::size_t>(grid, "point_cloud_node_ids",
243 result.point_cloud_node_ids.cast<std::size_t>());
244
245 return grid;
246}
247} // namespace ApplicationUtils
#define OGS_FATAL(...)
Definition Error.h:26
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:30
Definition of the VtkMeshConverter class.
static Eigen::MatrixXd conv(std::vector< Eigen::Vector3d > const &in)
void append(Eigen::Vector3d const &natural_coords, Eigen::Vector3d const &real_coords, vtkIdType bulk_element_id, vtkIdType point_cloud_node_id)
vtkSmartPointer< vtkUnstructuredGrid > find(Eigen::Vector3d const &coords, double const tolerance)
void initialize(vtkUnstructuredGrid *const bulk_mesh)
static MeshLib::Mesh * convertUnstructuredGrid(vtkUnstructuredGrid *grid, bool const compute_element_neighbors=false, std::string const &mesh_name="vtkUnstructuredGrid")
Converts a vtkUnstructuredGrid object to a Mesh.
ComputeNaturalCoordsResult computeNaturalCoords(vtkUnstructuredGrid *const bulk_mesh, Eigen::MatrixXd const &real_coords, double const tolerance, int const max_iter)
void addPointData(vtkUnstructuredGrid *grid, std::string const &name, Eigen::MatrixX< T > const &data)
vtkSmartPointer< vtkUnstructuredGrid > toVTKGrid(ComputeNaturalCoordsResult const &result)
PropertyVector< std::size_t > const * bulkElementIDs(Mesh const &mesh)
Definition Mesh.cpp:300