PolyFEM
Loading...
Searching...
No Matches
APriori.cpp
Go to the documentation of this file.
1
2#include "APriori.hpp"
3
6
8
10{
11 using namespace mesh;
12 using namespace utils;
13
14 namespace
15 {
16 template <typename V1, typename V2>
17 double angle2(const V1 &v1, const V2 &v2)
18 {
19 assert(v1.size() == 2);
20 assert(v2.size() == 2);
21 return std::abs(atan2(v1(0) * v2(1) - v1(1) * v2(0), v1.dot(v2)));
22 }
23
24 template <typename V1, typename V2>
25 double angle3(const V1 &v1, const V2 &v2)
26 {
27 assert(v1.size() == 3);
28 assert(v2.size() == 3);
29 return std::abs(atan2(v1.cross(v2).norm(), v1.dot(v2)));
30 }
31
32 } // namespace
33
34 double get_opt_p(bool h1_formula, double B,
35 double h_ref, int p_ref, double rho_ref,
36 double h, double rho, int p_max)
37 {
38 const double sigma_ref = rho_ref / h_ref;
39 const double sigma = rho / h;
40
41 const double ptmp = h1_formula ? (std::log(B * std::pow(h_ref, p_ref + 1) * rho / (h * rho_ref)) / std::log(h)) : (std::log(B * std::pow(h_ref, p_ref + 1) * sigma * sigma / sigma_ref / sigma_ref) - std::log(h)) / std::log(h);
42 // (std::log(B*std::pow(h_ref, p_ref + 2)*rho*rho / (h * h *rho_ref*rho_ref))/std::log(h));
43
44 return std::min(std::max(p_ref, (int)std::round(ptmp)), p_max);
45 }
46
48 const Mesh2D &mesh2d,
49 const double B,
50 const bool h1_formula,
51 const int base_p,
52 const int discr_order_max,
53 io::OutStatsData &stats,
54 Eigen::VectorXi &disc_orders)
55 {
56 stats.max_angle = 0;
57 // static const int max_angles = 5;
58 // static const double angles[max_angles] = {0, 170./180.*M_PI, 179./180.*M_PI, 179.9/180.* M_PI, M_PI};
59
60 Eigen::MatrixXd p0, p1;
61 mesh2d.get_edges(p0, p1);
62 const auto tmp = p0 - p1;
63 const double h_ref = tmp.rowwise().norm().mean();
64
65 const double rho_ref = sqrt(3.0) / 6.0 * h_ref;
66 const int p_max = std::min(autogen::MAX_P_BASES, discr_order_max);
67
68 stats.sigma_avg = 0;
69 stats.sigma_max = 0;
70 stats.sigma_min = std::numeric_limits<double>::max();
71
72 for (int f = 0; f < mesh2d.n_faces(); ++f)
73 {
74 if (!mesh2d.is_simplex(f))
75 continue;
76
77 auto v0 = mesh2d.point(mesh2d.face_vertex(f, 0));
78 auto v1 = mesh2d.point(mesh2d.face_vertex(f, 1));
79 auto v2 = mesh2d.point(mesh2d.face_vertex(f, 2));
80
81 const RowVectorNd e0 = v1 - v0;
82 const RowVectorNd e1 = v2 - v1;
83 const RowVectorNd e2 = v0 - v2;
84
85 const double e0n = e0.norm();
86 const double e1n = e1.norm();
87 const double e2n = e2.norm();
88
89 const double alpha0 = angle2(e0, -e2);
90 const double alpha1 = angle2(e1, -e0);
91 const double alpha2 = angle2(e2, -e1);
92
93 const double P = e0n + e1n + e2n;
94 const double A = std::abs(e1(0) * e2(1) - e1(1) * e2(0)) / 2;
95 const double rho = 2 * A / P;
96 const double hp = std::max(e0n, std::max(e1n, e2n));
97 const double sigma = rho / hp;
98
99 stats.sigma_avg += sigma;
100 stats.sigma_max = std::max(stats.sigma_max, sigma);
101 stats.sigma_min = std::min(stats.sigma_min, sigma);
102
103 const int p = get_opt_p(h1_formula, B, h_ref, base_p, rho_ref, hp, rho, p_max);
104
105 if (p > disc_orders[f])
106 disc_orders[f] = p;
107 auto index = mesh2d.get_index_from_face(f);
108
109 for (int lv = 0; lv < 3; ++lv)
110 {
111 auto nav = mesh2d.switch_face(index);
112
113 if (nav.face >= 0)
114 {
115 if (p > disc_orders[nav.face])
116 disc_orders[nav.face] = p;
117 }
118
119 index = mesh2d.next_around_face(index);
120 }
121
122 stats.max_angle = std::max(stats.max_angle, alpha0);
123 stats.max_angle = std::max(stats.max_angle, alpha1);
124 stats.max_angle = std::max(stats.max_angle, alpha2);
125 }
126
127 stats.sigma_avg /= mesh2d.n_faces();
128 stats.max_angle = stats.max_angle / M_PI * 180.;
129 logger().info("using B={} with {} estimate max_angle {}", B, (h1_formula ? "H1" : "L2"), stats.max_angle);
130 logger().info("average sigma: {}", stats.sigma_avg);
131 logger().info("min sigma: {}", stats.sigma_min);
132 logger().info("max sigma: {}", stats.sigma_max);
133
134 logger().info("num_p1 {}", (disc_orders.array() == 1).count());
135 logger().info("num_p2 {}", (disc_orders.array() == 2).count());
136 logger().info("num_p3 {}", (disc_orders.array() == 3).count());
137 logger().info("num_p4 {}", (disc_orders.array() == 4).count());
138 logger().info("num_p5 {}", (disc_orders.array() == 5).count());
139 }
140
142 const Mesh3D &mesh3d,
143 const double B,
144 const bool h1_formula,
145 const int base_p,
146 const int discr_order_max,
147 io::OutStatsData &stats,
148 Eigen::VectorXi &disc_orders)
149 {
150 stats.max_angle = 0;
151
152 Eigen::MatrixXd p0, p1;
153 mesh3d.get_edges(p0, p1);
154 const auto tmp = p0 - p1;
155 const double h_ref = tmp.rowwise().norm().mean();
156 const double rho_ref = sqrt(6.) / 12. * h_ref;
157 const int p_max = std::min(autogen::MAX_P_BASES, discr_order_max);
158
159 stats.sigma_avg = 0;
160 stats.sigma_max = 0;
161 stats.sigma_min = std::numeric_limits<double>::max();
162
163 for (int c = 0; c < mesh3d.n_cells(); ++c)
164 {
165 if (!mesh3d.is_simplex(c))
166 continue;
167
168 const auto v0 = mesh3d.point(mesh3d.cell_vertex(c, 0));
169 const auto v1 = mesh3d.point(mesh3d.cell_vertex(c, 1));
170 const auto v2 = mesh3d.point(mesh3d.cell_vertex(c, 2));
171 const auto v3 = mesh3d.point(mesh3d.cell_vertex(c, 3));
172
173 Eigen::Matrix<double, 6, 3> e;
174 e.row(0) = v0 - v1;
175 e.row(1) = v1 - v2;
176 e.row(2) = v2 - v0;
177
178 e.row(3) = v0 - v3;
179 e.row(4) = v1 - v3;
180 e.row(5) = v2 - v3;
181
182 Eigen::Matrix<double, 6, 1> en = e.rowwise().norm();
183
184 Eigen::Matrix<double, 3 * 4, 1> alpha;
185 alpha(0) = angle3(e.row(0), -e.row(1));
186 alpha(1) = angle3(e.row(1), -e.row(2));
187 alpha(2) = angle3(e.row(2), -e.row(0));
188 alpha(3) = angle3(e.row(0), -e.row(4));
189 alpha(4) = angle3(e.row(4), e.row(3));
190 alpha(5) = angle3(-e.row(3), -e.row(0));
191 alpha(6) = angle3(-e.row(4), -e.row(1));
192 alpha(7) = angle3(e.row(1), -e.row(5));
193 alpha(8) = angle3(e.row(5), e.row(4));
194 alpha(9) = angle3(-e.row(2), -e.row(5));
195 alpha(10) = angle3(e.row(5), e.row(3));
196 alpha(11) = angle3(-e.row(3), e.row(2));
197
198 const double S = (e.row(0).cross(e.row(1)).norm() + e.row(0).cross(e.row(4)).norm() + e.row(4).cross(e.row(1)).norm() + e.row(2).cross(e.row(5)).norm()) / 2;
199 const double V = std::abs(e.row(3).dot(e.row(2).cross(-e.row(0)))) / 6;
200 const double rho = 3 * V / S;
201 const double hp = en.maxCoeff();
202
203 stats.sigma_avg += rho / hp;
204 stats.sigma_max = std::max(stats.sigma_max, rho / hp);
205 stats.sigma_min = std::min(stats.sigma_min, rho / hp);
206
207 const int p = get_opt_p(h1_formula, B, h_ref, base_p, rho_ref, hp, rho, p_max);
208
209 if (p > disc_orders[c])
210 disc_orders[c] = p;
211
212 for (int le = 0; le < 6; ++le)
213 {
214 const int e_id = mesh3d.cell_edge(c, le);
215 const auto cells = mesh3d.edge_neighs(e_id);
216
217 for (auto c_id : cells)
218 {
219 if (p > disc_orders[c_id])
220 disc_orders[c_id] = p;
221 }
222 }
223
224 stats.max_angle = std::max(stats.max_angle, alpha.maxCoeff());
225 }
226
227 stats.max_angle = stats.max_angle / M_PI * 180.;
228 stats.sigma_avg /= mesh3d.n_elements();
229
230 logger().info("using B={} with {} estimate max_angle {}", B, (h1_formula ? "H1" : "L2"), stats.max_angle);
231 logger().info("average sigma: {}", stats.sigma_avg);
232 logger().info("min sigma: {}", stats.sigma_min);
233 logger().info("max sigma: {}", stats.sigma_max);
234
235 logger().info("num_p1 {}", (disc_orders.array() == 1).count());
236 logger().info("num_p2 {}", (disc_orders.array() == 2).count());
237 logger().info("num_p3 {}", (disc_orders.array() == 3).count());
238 logger().info("num_p4 {}", (disc_orders.array() == 4).count());
239 logger().info("num_p5 {}", (disc_orders.array() == 5).count());
240 }
241
243 const mesh::Mesh &mesh,
244 const double B,
245 const bool h1_formula,
246 const int base_p,
247 const int discr_order_max,
248 io::OutStatsData &stats,
249 Eigen::VectorXi &disc_orders)
250 {
251 if (mesh.is_volume())
252 p_refine(static_cast<const Mesh3D &>(mesh), B, h1_formula, base_p, discr_order_max, stats, disc_orders);
253 else
254 p_refine(static_cast<const Mesh2D &>(mesh), B, h1_formula, base_p, discr_order_max, stats, disc_orders);
255 }
256} // namespace polyfem::refinement
int V
all stats from polyfem
Definition OutData.hpp:391
double max_angle
statiscs on angle, compute only when using p_ref (false by default)
Definition OutData.hpp:415
double sigma_max
statiscs on tri/tet quality, compute only when using p_ref (false by default)
Definition OutData.hpp:417
Navigation::Index next_around_face(Navigation::Index idx) const
Definition Mesh2D.hpp:61
void get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1) const override
Get all the edges.
Definition Mesh2D.cpp:21
virtual Navigation::Index get_index_from_face(int f, int lv=0) const =0
virtual Navigation::Index switch_face(Navigation::Index idx) const =0
virtual int cell_edge(const int c_id, const int le_id) const =0
virtual std::vector< uint32_t > edge_neighs(const int e_gid) const =0
void get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1) const override
Get all the edges.
Definition Mesh3D.cpp:33
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:39
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Definition Mesh.hpp:161
virtual RowVectorNd point(const int global_index) const =0
point coordinates
bool is_simplex(const int el_id) const
checks if element is simples compatible
Definition Mesh.cpp:422
virtual bool is_volume() const =0
checks if mesh is volume
virtual int n_cells() const =0
number of cells
virtual int n_faces() const =0
number of faces
virtual int cell_vertex(const int f_id, const int lv_id) const =0
id of the vertex of a cell
virtual int face_vertex(const int f_id, const int lv_id) const =0
id of the face vertex
static void p_refine(const mesh::Mesh &mesh, const double B, const bool h1_formula, const int base_p, const int discr_order_max, io::OutStatsData &stats, Eigen::VectorXi &disc_orders)
compute a priori prefinement
Definition APriori.cpp:242
double get_opt_p(bool h1_formula, double B, double h_ref, int p_ref, double rho_ref, double h, double rho, int p_max)
Definition APriori.cpp:34
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13