2828
2929#include < limits>
3030
31+ #include " expression_parser/Parser.hpp"
32+
3133namespace wmtk ::components::image_simulation {
3234
3335
@@ -274,6 +276,50 @@ CellTag wmtk::components::image_simulation::ImageSimulationMesh::string_set_to_c
274276 return cell_tag;
275277}
276278
279+ void ImageSimulationMesh::set_length_regions (const nlohmann::json& length_region_json)
280+ {
281+ if (!length_region_json.is_array ()) {
282+ log_and_throw_error (
283+ " length_region should be an array of objects, each defining a region and its target "
284+ " length." );
285+ }
286+
287+ for (const auto & region_json : length_region_json) {
288+ if (!region_json.contains (" tags" )) {
289+ log_and_throw_error (" Each length_region entry must contain a 'tags' field." );
290+ }
291+ const std::string tags_str_set = region_json[" tags" ];
292+ auto & [expr, length] = m_length_regions.emplace_back ();
293+ expr = expression_parser::parse (tags_str_set, m_tag_name_to_id);
294+
295+ length = region_json[" length" ];
296+ double length_rel = region_json[" length_rel" ];
297+ if (length < 0 && length_rel < 0 ) {
298+ log_and_throw_error (
299+ " Each length_region entry must specify at least one of 'length' or 'length_rel'." );
300+ }
301+
302+ if (length_rel > 0 ) {
303+ length = length_rel * m_params.diag_l ;
304+ }
305+ }
306+
307+ // apply length regions to vertices
308+ for (const auto & [expr, length] : m_length_regions) {
309+ for (const Tuple& t : get_tets ()) {
310+ const auto tid = t.tid (*this );
311+ if (!expr->eval (m_tet_attribute[tid].tags )) {
312+ continue ;
313+ }
314+ const auto vs = oriented_tet_vids (tid);
315+ for (const size_t & vid : vs) {
316+ auto & s = m_vertex_attribute[vid].m_sizing_scalar ;
317+ s = std::min (s, length / m_params.l );
318+ }
319+ }
320+ }
321+ }
322+
277323bool ImageSimulationMesh::adjust_sizing_field_serial (double max_energy)
278324{
279325 logger ().info (" #vertices {}, #tets {}" , vert_capacity (), tet_capacity ());
@@ -282,114 +328,164 @@ bool ImageSimulationMesh::adjust_sizing_field_serial(double max_energy)
282328 double filter_energy = std::max (max_energy / 100 , stop_filter_energy);
283329 filter_energy = std::min (filter_energy, 100 .);
284330
285- const auto recover_scalar = 1.5 ;
286- const auto refine_scalar = 0.5 ;
287- const auto min_refine_scalar = m_params.l_min / m_params.l ;
331+ const double recover_scalar = 1.5 ;
332+ const double refine_scalar = 0.5 ;
333+ const double min_refine_scalar = m_params.l_min / m_params.l ;
288334
289- // outputs scale_multipliers
290- std::vector<double > scale_multipliers (vert_capacity (), recover_scalar);
335+ // // outputs scale_multipliers
336+ // std::vector<double> scale_multipliers(vert_capacity(), recover_scalar);
291337
292338 std::vector<Vector3d> pts;
339+ std::map<size_t , double > pts_scalars;
293340 std::queue<size_t > v_queue;
294341
295342 for (int i = 0 ; i < tet_capacity (); i++) {
296- auto t = tuple_from_tet (i);
297- if (!t.is_valid (*this )) continue ;
298- auto tid = t.tid (*this );
299- if (std::cbrt (m_tet_attribute[tid].m_quality ) < filter_energy) continue ;
300- auto vs = oriented_tet_vids (t);
343+ const Tuple t = tuple_from_tet (i);
344+ if (!t.is_valid (*this )) {
345+ continue ;
346+ }
347+ const size_t tid = t.tid (*this );
348+ if (std::cbrt (m_tet_attribute[tid].m_quality ) < filter_energy) {
349+ continue ;
350+ }
351+ const auto vs = oriented_tet_vids (t);
301352 Vector3d c (0 , 0 , 0 );
353+ double s = 0 ;
302354 for (int j = 0 ; j < 4 ; j++) {
303355 c += (m_vertex_attribute[vs[j]].m_posf );
304356 v_queue.emplace (vs[j]);
305- // std::cout << vs[j] << " " ;
357+ s = std::max (s, m_vertex_attribute[ vs[j]]. m_sizing_scalar ) ;
306358 }
359+ pts_scalars[pts.size ()] = s;
307360 pts.emplace_back (c / 4 );
308361 }
309362
310- // std::cout << std::endl;
311-
312-
313363 logger ().info (" filter energy {} Low Quality Tets {}" , filter_energy, pts.size ());
314364
315- // debug code
316- // std::queue<size_t> v_queue_serial;
317- // for (tbb::concurrent_queue<size_t>::const_iterator i(v_queue.unsafe_begin());
318- // i != v_queue.unsafe_end();
319- // ++i) {
320- // // std::cout << *i << " ";
321- // v_queue_serial.push(*i);
322- // }
323- // std::cout << std::endl;
324-
325365 const double R = m_params.l * 1.8 ;
326366
327367 int sum = 0 ;
328368 int adjcnt = 0 ;
329369
330- std::vector<bool > visited (vert_capacity (), false );
331-
332370 KNN knn (pts);
333371
334- std::vector<size_t > cache_one_ring;
335- // size_t vid;
336-
337- while (!v_queue.empty ()) {
338- // std::cout << vid << " ";
339- sum++;
340- size_t vid = v_queue.front ();
341- // std::cout << vid << " ";
342- v_queue.pop ();
343- if (visited[vid]) continue ;
344- visited[vid] = true ;
345- adjcnt++;
346-
347- auto & pos_v = m_vertex_attribute[vid].m_posf ;
348- double sq_dist = 0 .;
349- uint32_t idx;
350- knn.nearest_neighbor (pos_v, idx, sq_dist);
351- const double dist = std::sqrt (sq_dist);
352-
353- if (dist > R) { // outside R-ball, unmark.
372+ bool is_hit_min_edge_length = false ;
373+ /* *
374+ * Iterate through all vertices.
375+ * For each vertex, find all pts in the R-ball neighborhood.
376+ * Compute scalar based on the distance to the point.
377+ * Take smallest of all computed values.
378+ *
379+ * If no neighbor, multiply by recover_scalar.
380+ */
381+ for (int i = 0 ; i < vert_capacity (); i++) {
382+ const Tuple v = tuple_from_vertex (i);
383+ if (!v.is_valid (*this )) {
354384 continue ;
355385 }
386+ const size_t vid = v.vid (*this );
387+ const auto & pos_v = m_vertex_attribute[vid].m_posf ;
388+
389+ std::vector<nanoflann::ResultItem<uint32_t , double >> matches;
390+ knn.r_nearest_neighbors (pos_v, R * R, matches);
356391
357- scale_multipliers[vid] = std::min (
358- scale_multipliers[vid],
359- dist / R * (1 - refine_scalar) + refine_scalar); // linear interpolate
392+ auto & v_scalar = m_vertex_attribute[vid].m_sizing_scalar ;
360393
361- auto vids = get_one_ring_vids_for_vertex_adj (vid, cache_one_ring);
362- for (size_t n_vid : vids) {
363- if (visited[n_vid]) continue ;
364- v_queue.push (n_vid);
394+ if (matches.empty ()) {
395+ v_scalar = std::min (recover_scalar * v_scalar, 1 .);
396+ continue ;
365397 }
366- }
367398
368- // std::cout << std::endl;
399+ for (const auto & [index, sq_dist] : matches) {
400+ const auto & pt = pts[index];
401+ const double dist = std::sqrt (sq_dist);
402+ // linear interpolate between refine_scalar and 1 based on distance
403+ double u = dist / R * (1 - refine_scalar) + refine_scalar;
404+ double scalar = u * pts_scalars[index];
405+ v_scalar = std::min (v_scalar, scalar);
406+ }
369407
370- std::cout << sum << " " << adjcnt << std::endl;
408+ if (v_scalar < min_refine_scalar) {
409+ v_scalar = min_refine_scalar;
410+ is_hit_min_edge_length = true ;
411+ }
412+ }
371413
372- std::atomic_bool is_hit_min_edge_length = false ;
414+ // apply length regions to vertices
415+ for (const auto & [expr, length] : m_length_regions) {
416+ for (const Tuple& t : get_tets ()) {
417+ const auto tid = t.tid (*this );
418+ if (!expr->eval (m_tet_attribute[tid].tags )) {
419+ continue ;
420+ }
421+ const auto vs = oriented_tet_vids (tid);
422+ for (const size_t & vid : vs) {
423+ auto & s = m_vertex_attribute[vid].m_sizing_scalar ;
424+ s = std::min (s, length / m_params.l );
425+ }
426+ }
427+ }
373428
374- for (int i = 0 ; i < vert_capacity (); i++) {
375- auto v = tuple_from_vertex (i);
376- if (!v.is_valid (*this )) continue ;
377- auto vid = v.vid (*this );
378- // std::cout << vid << " ";
379- auto & v_attr = m_vertex_attribute[vid];
429+ // std::vector<bool> visited(vert_capacity(), false);
430+ // std::vector<size_t> cache_one_ring;
431+ // // size_t vid;
432+
433+ // while (!v_queue.empty()) {
434+ // sum++;
435+ // size_t vid = v_queue.front();
436+ // v_queue.pop();
437+ // if (visited[vid]) {
438+ // continue;
439+ // }
440+ // visited[vid] = true;
441+ // adjcnt++;
442+
443+ // const Vector3d& pos_v = m_vertex_attribute[vid].m_posf;
444+ // double sq_dist = 0.;
445+ // uint32_t idx;
446+ // knn.nearest_neighbor(pos_v, idx, sq_dist);
447+
448+ // const double dist = std::sqrt(sq_dist);
449+
450+ // if (dist > R) { // outside R-ball, unmark.
451+ // continue;
452+ // }
453+
454+ // scale_multipliers[vid] = std::min(
455+ // scale_multipliers[vid],
456+ // dist / R * (1 - refine_scalar) + refine_scalar); // linear interpolate
457+
458+ // const auto vids = get_one_ring_vids_for_vertex_adj(vid, cache_one_ring);
459+ // for (size_t n_vid : vids) {
460+ // if (visited[n_vid]) {
461+ // continue;
462+ // }
463+ // v_queue.push(n_vid);
464+ // }
465+ // }
380466
381- auto new_scale = v_attr.m_sizing_scalar * scale_multipliers[vid];
382- if (new_scale > 1 )
383- v_attr.m_sizing_scalar = 1 ;
384- else if (new_scale < min_refine_scalar) {
385- is_hit_min_edge_length = true ;
386- v_attr.m_sizing_scalar = min_refine_scalar;
387- } else
388- v_attr.m_sizing_scalar = new_scale;
389- }
390- // std::cout << std::endl;
467+ // std::cout << sum << " " << adjcnt << std::endl;
468+
469+ // bool is_hit_min_edge_length = false;
470+ // for (int i = 0; i < vert_capacity(); i++) {
471+ // const Tuple v = tuple_from_vertex(i);
472+ // if (!v.is_valid(*this)) {
473+ // continue;
474+ // }
475+ // const size_t vid = v.vid(*this);
476+ // auto& v_attr = m_vertex_attribute[vid];
477+
478+ // const double new_scale = v_attr.m_sizing_scalar * scale_multipliers[vid];
479+ // if (new_scale > 1)
480+ // v_attr.m_sizing_scalar = 1;
481+ // else if (new_scale < min_refine_scalar) {
482+ // is_hit_min_edge_length = true;
483+ // v_attr.m_sizing_scalar = min_refine_scalar;
484+ // } else
485+ // v_attr.m_sizing_scalar = new_scale;
486+ // }
391487
392- return is_hit_min_edge_length. load () ;
488+ return is_hit_min_edge_length;
393489}
394490
395491void bfs_orient (const Eigen::MatrixXi& F, Eigen::MatrixXi& FF , Eigen::VectorXi& C)
@@ -1100,7 +1196,11 @@ void ImageSimulationMesh::write_vtu(const std::string& path)
11001196 paraviewo::VTUWriter writer;
11011197
11021198 for (size_t j = 0 ; j < m_tags_count; ++j) {
1103- writer.add_cell_field (fmt::format (" tag_{}" , j), tags[j]);
1199+ if (m_tag_id_to_name.count (j)) {
1200+ writer.add_cell_field (m_tag_id_to_name[j], tags[j]);
1201+ } else {
1202+ writer.add_cell_field (fmt::format (" tag_{}" , j), tags[j]);
1203+ }
11041204 }
11051205 writer.add_cell_field (" quality" , amips);
11061206 writer.add_field (" sizing_field" , v_sizing_field);
0 commit comments