21 #ifndef __mast__libmesh_geometric_filter_h__ 22 #define __mast__libmesh_geometric_filter_h__ 34 #include "libmesh/system.h" 35 #include "libmesh/node.h" 36 #include "libmesh/elem.h" 37 #include "libmesh/mesh_base.h" 38 #include "libmesh/petsc_vector.h" 39 #ifdef LIBMESH_HAVE_NANOFLANN 40 #include "libmesh/nanoflann.hpp" 47 namespace libMeshWrapper {
69 #ifdef LIBMESH_HAVE_NANOFLANN 106 template <
typename Vec1Type,
110 (
const Vec1Type &input,
111 Vec2Type &output)
const {
115 "Method only for scalar runs");
117 input.size(),
_system.n_dofs(),
118 "Incompatible vector sizes");
120 output.size(),
_system.n_dofs(),
121 "Incompatible vector sizes");
126 first_local_dof =
_system.get_dof_map().first_dof(
_system.comm().rank()),
127 last_local_dof =
_system.get_dof_map().end_dof(
_system.comm().rank());
129 std::map<uint_t, std::vector<std::pair<uint_t, real_t>>>::const_iterator
133 for ( ; map_it != map_end; map_it++) {
136 if (map_it->first >= first_local_dof &&
137 map_it->first < last_local_dof) {
139 std::vector<std::pair<uint_t, real_t>>::const_iterator
140 vec_it = map_it->second.begin(),
141 vec_end = map_it->second.end();
143 for ( ; vec_it != vec_end; vec_it++) {
146 (output, map_it->first,
176 libMesh::NumericVector<real_t> &output)
const {
188 (
dynamic_cast<libMesh::PetscVector<real_t>&
>(input).vec(),
189 dynamic_cast<libMesh::PetscVector<real_t>&
>(output).vec());
197 template <
typename Vec1Type,
201 Vec2Type &output)
const {
205 "Method only for scalar runs");
207 input.size(),
_system.n_dofs(),
208 "Incompatible vector sizes");
210 output.size(),
_system.n_dofs(),
211 "Incompatible vector sizes");
215 const libMesh::DofMap
216 &dof_map =
_system.get_dof_map();
218 std::map<uint_t, std::vector<std::pair<uint_t, real_t>>>::const_iterator
222 for ( ; map_it != map_end; map_it++) {
226 if (dof_map.semilocal_index(map_it->first)) {
228 std::vector<std::pair<uint_t, real_t>>::const_iterator
229 vec_it = map_it->second.begin(),
230 vec_end = map_it->second.end();
232 for ( ; vec_it != vec_end; vec_it++) {
235 (output, map_it->first,
270 libMesh::NumericVector<real_t> &output)
const {
282 (
dynamic_cast<libMesh::PetscVector<real_t>&
>(input).vec(),
283 dynamic_cast<libMesh::PetscVector<real_t>&
>(output).vec());
291 #ifdef LIBMESH_HAVE_NANOFLANN 293 template <u
int_t Dim>
294 class NanoflannMeshAdaptor
298 const libMesh::MeshBase & _mesh;
303 NanoflannMeshAdaptor (
const libMesh::MeshBase &mesh,
304 const std::vector<const libMesh::Node*> &nodes) :
306 _n_local_nodes (nodes.size()),
307 _n_nodes (mesh.n_nodes()),
320 kdtree_get_point_count()
const {
return _n_local_nodes; }
327 kdtree_distance(
const coord_t * p1,
331 Assert2(size == Dim, size, Dim,
"Incompatible dimension");
335 libMesh::Point point1(p1[0],
336 size > 1 ? p1[1] : 0.,
337 size > 2 ? p1[2] : 0.);
340 const libMesh::Point & point2 = _mesh.point(idx_p2);
343 return (point1 - point2).norm_sq();
352 kdtree_get_pt(
const size_t idx,
int dim)
const 354 Assert2(dim < (
int) Dim, dim, (
int) Dim,
355 "Incompatible dimension");
356 Assert2(idx < _n_local_nodes, idx, _n_nodes,
357 "Invalid node index");
358 Assert1(dim < 3, dim,
"Invalid dimension");
360 return (*
_nodes[idx])(dim);
369 template <
class BBOX>
370 inline bool kdtree_get_bbox(BBOX & )
const {
return false; }
372 const std::vector<const libMesh::Node*> &
_nodes;
376 typedef nanoflann::L2_Simple_Adaptor<real_t, NanoflannMeshAdaptor<3> > adatper_t;
378 typedef nanoflann::KDTreeSingleIndexAdaptor<adatper_t, NanoflannMeshAdaptor<3>, 3> kd_tree_t;
383 local_mesh_index (-1),
391 std::vector<real_t> point;
395 inline void _init2() {
397 libMesh::MeshBase& mesh =
_system.get_mesh();
406 NanoflannMeshAdaptor<3> mesh_adaptor(mesh,
_nodes);
407 kd_tree_t kd_tree(3, mesh_adaptor, nanoflann::KDTreeSingleIndexAdaptorParams(10));
410 kd_tree.buildIndex();
418 rank_boxes[0] = kd_tree.root_bbox[0].low;
419 rank_boxes[1] = kd_tree.root_bbox[0].high;
421 rank_boxes[2] = kd_tree.root_bbox[1].low;
422 rank_boxes[3] = kd_tree.root_bbox[1].high;
424 rank_boxes[4] = kd_tree.root_bbox[2].low;
425 rank_boxes[5] = kd_tree.root_bbox[2].high;
429 mesh.comm().allgather(rank_boxes,
true);
431 Assert2(rank_boxes.size() == mesh.comm().size()*6,
432 rank_boxes.size(), mesh.comm().size()*6,
433 "Invalid vector dimension after allgather()");
441 std::set<uint_t> send_list;
443 const libMesh::DofMap
444 &dof_map =
_system.get_dof_map();
446 std::vector<PointData>
450 size = mesh.comm().size(),
451 rank = mesh.comm().rank(),
452 first_local_dof = dof_map.first_dof(rank),
453 last_local_dof = dof_map.end_dof(rank),
460 std::map<const libMesh::Node*, real_t>
463 std::vector<const libMesh::Node*>::const_iterator
467 std::vector<std::vector<const libMesh::Node*>>
468 remote_node_dependency(size);
470 for (; node_it != node_end; node_it++) {
472 const libMesh::Node* node = *node_it;
473 nd_radius =
_radius->el(node->dof_number(sys_num, 0, 0));
476 for (
uint_t i=0; i<size; i++) {
478 if (i == rank)
continue;
482 (*node)(0) >= rank_boxes[6*i+0]-nd_radius &&
483 (*node)(0) <= rank_boxes[6*i+1]+nd_radius &&
485 (*node)(1) >= rank_boxes[6*i+2]-nd_radius &&
486 (*node)(1) <= rank_boxes[6*i+3]+nd_radius &&
488 (*node)(2) >= rank_boxes[6*i+4]-nd_radius &&
489 (*node)(2) <= rank_boxes[6*i+5]+nd_radius) {
491 remote_node_dependency[i].push_back(node);
502 std::vector<std::vector<real_t>>
505 filter_data_node_loc_send(size),
506 filter_data_node_loc_recv(size);
508 std::vector<std::vector<uint_t>>
510 filter_data_n_indices_send(size),
511 filter_data_n_indices_recv(size),
514 filter_data_dof_index_send(size),
515 filter_data_dof_index_recv(size);
518 for (
uint_t i=0; i<size; i++) {
520 for (
uint_t j=0; j<size; j++) {
528 coords_send.resize(remote_node_dependency[j].size()*3, 0.);
529 radius_send.resize(remote_node_dependency[j].size(), 0.);
531 for (
uint_t k=0; k<remote_node_dependency[j].size(); k++) {
533 coords_send[k*3 + 0] = (*remote_node_dependency[j][k])(0);
534 coords_send[k*3 + 1] = (*remote_node_dependency[j][k])(1);
535 coords_send[k*3 + 2] = (*remote_node_dependency[j][k])(2);
537 _radius->el(remote_node_dependency[j][k]->dof_number
542 mesh.comm().send(j, coords_send);
543 mesh.comm().send(j, radius_send);
549 else if (j == rank) {
551 coords_recv[i].clear();
552 radius_recv[i].clear();
554 mesh.comm().receive(i, coords_recv[i]);
555 mesh.comm().receive(i, radius_recv[i]);
557 Assert1(coords_recv[i].size()%3 == 0,
558 coords_recv[i].size(),
559 "coordinates must be a multiple of 3");
566 for (
uint_t i=0; i<size; i++) {
569 if (i == rank)
continue;
574 n_nodes = coords_recv[i].size()/3;
577 filter_data_n_indices_send[i].reserve(coords_recv[i].size());
579 filter_data_dof_index_send[i].reserve(coords_recv[i].size()*27);
580 filter_data_node_loc_send[i].reserve (coords_recv[i].size()*27*3);
583 for (
uint_t j=0; j<n_nodes; j++) {
585 std::vector<std::pair<size_t, real_t>>
587 nanoflann::RadiusResultSet<real_t, size_t>
588 resultSet(radius_recv[i][j]*radius_recv[i][j], indices_dists);
590 kd_tree.findNeighbors(resultSet, &coords_recv[i][j*3], nanoflann::SearchParams());
593 filter_data_n_indices_send[i].push_back(indices_dists.size());
595 for (
unsigned r=0; r<indices_dists.size(); ++r) {
597 const libMesh::Node* nd =
_nodes[indices_dists[r].first];
600 filter_data_node_loc_send[i].push_back((*nd)(0));
601 filter_data_node_loc_send[i].push_back((*nd)(1));
602 filter_data_node_loc_send[i].push_back((*nd)(2));
604 filter_data_dof_index_send[i].push_back(nd->dof_number(
_system.number(), 0, 0));
612 for (
uint_t i=0; i<size; i++) {
614 for (
uint_t j=0; j<size; j++) {
621 mesh.comm().send(i, filter_data_n_indices_send[i]);
622 mesh.comm().send(i, filter_data_dof_index_send[i]);
623 mesh.comm().send(i, filter_data_node_loc_send[i]);
626 filter_data_n_indices_send[i].clear();
627 filter_data_dof_index_send[i].clear();
628 filter_data_node_loc_send[i].clear();
630 else if (i == rank) {
633 mesh.comm().receive(j, filter_data_n_indices_recv[j]);
634 mesh.comm().receive(j, filter_data_dof_index_recv[j]);
635 mesh.comm().receive(j, filter_data_node_loc_recv[j]);
647 for (; node_it != node_end; node_it++) {
649 const libMesh::Node* node = *node_it;
651 dof_1 = node->dof_number(
_system.number(), 0, 0);
652 nd_radius =
_radius->el(dof_1);
655 if (dof_map.semilocal_index(dof_1)) {
657 real_t query_pt[3] = {(*node)(0), (*node)(1), (*node)(2)};
659 std::vector<std::pair<size_t, real_t>>
661 indices_dists.push_back(std::pair<size_t, real_t>
663 nanoflann::RadiusResultSet<real_t, size_t>
664 resultSet(nd_radius*nd_radius, indices_dists);
666 kd_tree.findNeighbors(resultSet, query_pt, nanoflann::SearchParams());
670 for (
unsigned r=0; r<indices_dists.size(); ++r) {
672 d_12 = std::sqrt(indices_dists[r].second);
676 Assert2(d_12 <= nd_radius, d_12, nd_radius,
677 "Node distance must be <= search radius");
679 sum += nd_radius - d_12;
680 dof_2 =
_nodes[indices_dists[r].first]->dof_number(
_system.number(), 0, 0);
682 _filter_map[dof_1].push_back(std::pair<uint_t, real_t>
683 (dof_2, nd_radius - d_12));
686 if (dof_2 < first_local_dof ||
687 dof_2 >= last_local_dof)
688 send_list.insert(dof_2);
691 Assert1(sum > 0., sum,
"Weight must be > 0.");
694 node_sum[node] = sum;
705 for (
uint_t i=0; i<size; i++) {
710 for (
uint_t j=0; j<remote_node_dependency[i].size(); j++) {
713 node = remote_node_dependency[i][j];
715 dof_1 = node->dof_number(sys_num, 0, 0);
716 nd_radius =
_radius->el(dof_1);
720 n_remote_nodes = filter_data_n_indices_recv[i][j];
724 sum = node_sum[node];
727 for (
uint_t k=0; k<n_remote_nodes; k++) {
730 dof_2 = filter_data_dof_index_recv[i][idx];
734 sqrt(pow((*node)(0) - filter_data_node_loc_recv[i][idx*3+0], 2)+
735 pow((*node)(1) - filter_data_node_loc_recv[i][idx*3+1], 2)+
736 pow((*node)(2) - filter_data_node_loc_recv[i][idx*3+2], 2));
739 sum += nd_radius - d_12;
742 _filter_map[dof_1].push_back(std::pair<uint_t, real_t>
743 (dof_2, nd_radius - d_12));
746 send_list.insert(dof_2);
753 node_sum[node] = sum;
762 for (; node_it != node_end; node_it++) {
765 const libMesh::Node* node = *node_it;
768 dof_1 = node->dof_number(
_system.number(), 0, 0);
771 std::vector<std::pair<uint_t, real_t>>& vec =
_filter_map[dof_1];
775 sum = node_sum[node];
777 for (
uint_t i=0; i<vec.size(); i++) {
779 vec[i].second /= sum;
780 Assert1(vec[i].second <= 1., vec[i].second,
781 "Normalized weight must be <= 1.");
790 std::set<uint_t>::const_iterator
791 s_it = send_list.begin(),
792 s_end = send_list.end();
800 libMesh::MeshBase::const_element_iterator
801 e_it = mesh.local_elements_begin(),
802 e_end = mesh.local_elements_end();
804 for ( ; e_it != e_end; e_it++) {
805 const libMesh::Elem* e = *e_it;
822 libMesh::MeshBase& mesh =
_system.get_mesh();
825 Assert0(mesh.is_replicated() ||
827 "Function implemented only for replicated mesh or serial runs");
831 libMesh::MeshBase::const_node_iterator
832 node_it_1 = mesh.nodes_begin(),
833 node_it_2 = mesh.nodes_begin(),
834 node_end = mesh.nodes_end();
844 std::set<uint_t> send_list;
846 const libMesh::DofMap
847 &dof_map =
_system.get_dof_map();
850 first_local_dof =
_system.get_dof_map().first_dof(
_system.comm().rank()),
851 last_local_dof =
_system.get_dof_map().end_dof(
_system.comm().rank());
858 for ( ; node_it_1 != node_end; node_it_1++) {
860 dof_1 = (*node_it_1)->dof_number(sys_num, 0, 0);
861 nd_radius =
_radius->el(dof_1);
864 if (dof_map.semilocal_index(dof_1)) {
866 node_it_2 = mesh.nodes_begin();
869 for ( ; node_it_2 != node_end; node_it_2++) {
872 d = (**node_it_1) - (**node_it_2);
876 if (d_12 <= nd_radius) {
878 sum += nd_radius - d_12;
879 dof_2 = (*node_it_2)->dof_number(sys_num, 0, 0);
881 _filter_map[dof_1].push_back(std::pair<uint_t, real_t>(dof_2, nd_radius - d_12));
884 if (dof_2 < first_local_dof ||
885 dof_2 >= last_local_dof)
886 send_list.insert(dof_2);
890 Assert1(sum > 0., sum,
"Weight must be > 0.");
894 std::vector<std::pair<uint_t, real_t>>& vec =
_filter_map[dof_1];
895 for (
uint_t i=0; i<vec.size(); i++) {
897 vec[i].second /= sum;
898 Assert1(vec[i].second <= 1., vec[i].second,
899 "Normalized weight must be <= 1.");
909 std::set<uint_t>::const_iterator
910 s_it = send_list.begin(),
911 s_end = send_list.end();
919 libMesh::MeshBase::const_element_iterator
920 e_it = mesh.elements_begin(),
921 e_end = mesh.elements_end();
923 for ( ; e_it != e_end; e_it++) {
924 const libMesh::Elem* e = *e_it;
935 std::map<
uint_t, std::vector<std::pair<uint_t, real_t>>> &reverse_map) {
938 std::map<uint_t, std::vector<std::pair<uint_t, real_t>>>::const_iterator
939 it = forward_map.begin(),
940 end = forward_map.end();
942 for ( ; it!=end; it++) {
944 const std::vector<std::pair<uint_t, real_t>>
947 for (
uint_t i=0; i<vec.size(); i++)
948 reverse_map[vec[i].first].push_back(std::pair<uint_t, real_t>(it->first, vec[i].second));
957 std::unique_ptr<libMesh::NumericVector<real_t>>
958 n_elem_sum(
_system.solution->zero_clone().release());
962 libMesh::MeshBase::const_element_iterator
963 it =
_system.get_mesh().active_local_elements_begin(),
964 end =
_system.get_mesh().active_local_elements_end();
967 first_local_dof =
_system.get_dof_map().first_dof(
_system.comm().rank()),
968 last_local_dof =
_system.get_dof_map().end_dof(
_system.comm().rank()),
976 std::set<const libMesh::Node*>
982 for ( ; it!=end; it++) {
984 const libMesh::Elem *e = *it;
989 const libMesh::Node* nd = e->node_ptr(i);
990 dof_num = nd->dof_number(sys_num, 0, 0);
993 n_elem_sum->add(dof_num, 1.);
996 if (dof_num >= first_local_dof &&
997 dof_num < last_local_dof)
998 all_local_nodes.insert(nd);
1003 n_elem_sum->close();
1006 for (
uint_t i=first_local_dof; i<last_local_dof; i++) {
1012 std::set<const libMesh::Node*>::const_iterator
1013 n_it = all_local_nodes.begin(),
1014 n_end = all_local_nodes.end();
1016 for ( ; n_it != n_end; n_it++) {
1026 (
const std::map<
uint_t, std::vector<std::pair<uint_t, real_t>>>& filter_map) {
1030 n_local =
_system.get_dof_map().n_dofs_on_processor(
_system.processor_id()),
1031 first_local_dof =
_system.get_dof_map().first_dof(
_system.comm().rank()),
1032 last_local_dof =
_system.get_dof_map().end_dof(
_system.comm().rank());
1034 PetscErrorCode ierr;
1041 std::map<uint_t, std::vector<std::pair<uint_t, real_t>>>::const_iterator
1042 it = filter_map.begin(),
1043 end = filter_map.end();
1045 for ( ; it!=end; it++) {
1047 const std::vector<std::pair<uint_t, real_t>>
1050 for (
uint_t i=0; i<vec.size(); i++) {
1052 dof_id = vec[i].first;
1053 if (dof_id >= first_local_dof && dof_id < last_local_dof)
1054 n_nz[it->first - first_local_dof]++;
1056 n_oz[it->first - first_local_dof]++;
1062 CHKERRABORT(
_system.comm().get(), ierr);
1063 ierr = MatSetSizes(
_weight_matrix, n_local, n_local, n_vals, n_vals);
1064 CHKERRABORT(
_system.comm().get(), ierr);
1066 std::string nm =
_system.name() +
"_";
1068 CHKERRABORT(
_system.comm().get(), ierr);
1071 CHKERRABORT(
_system.comm().get(), ierr);
1075 (PetscInt*)&n_nz[0]);
1076 CHKERRABORT(
_system.comm().get(), ierr);
1079 (PetscInt*)&n_nz[0],
1081 (PetscInt*)&n_oz[0]);
1082 CHKERRABORT(
_system.comm().get(), ierr);
1084 MAT_NEW_NONZERO_ALLOCATION_ERR,
1086 CHKERRABORT(
_system.comm().get(), ierr);
1089 it = filter_map.begin();
1090 end = filter_map.end();
1092 for ( ; it!=end; it++) {
1094 const std::vector<std::pair<uint_t, real_t>>
1097 for (
uint_t i=0; i<vec.size(); i++) {
1107 CHKERRABORT(
_system.comm().get(), ierr);
1109 CHKERRABORT(
_system.comm().get(), ierr);
1121 std::unique_ptr<libMesh::NumericVector<real_t>>
_radius;
1174 #endif // __mast__libmesh_geometric_filter_h__ ScalarType get(const std::vector< ScalarType > &v, uint_t i)
void _init()
initializes the algebraic data structures
void compute_filtered_values(const Vec1Type &input, Vec2Type &output) const
std::vector< const libMesh::Node * > _nodes
Local nodes that belong to the first-order Lagrange basis on the elements.
real_t _fe_size
largest element size in the level set mesh
#define Assert1(cond, v1, msg)
void _init_reverse_map(const std::map< uint_t, std::vector< std::pair< uint_t, real_t >>> &forward_map, std::map< uint_t, std::vector< std::pair< uint_t, real_t >>> &reverse_map)
void _init_filter_radius()
std::unique_ptr< libMesh::NumericVector< real_t > > _radius
radius of the filter.
Creates a geometric filter for the location-based design variables, for example density and level-set...
void compute_reverse_filtered_values(libMesh::NumericVector< real_t > &input, libMesh::NumericVector< real_t > &output) const
libMesh::System & _system
system on which the level set discrete function is defined
MAST::Mesh::libMeshWrapper::GeometricFilterAugmentSendList * _augment_send_list
pointer to an object that appends the sendlist for dofmap to localize the dofs needed for local compu...
GeometricFilter(libMesh::System &sys, const real_t radius)
std::map< uint_t, std::vector< std::pair< uint_t, real_t > > > _filter_map
Algebraic relation between filtered level set values and the design variables .
void compute_filtered_values(Vec input, Vec output) const
void compute_reverse_filtered_values(const Vec1Type &input, Vec2Type &output) const
Applies the reverse map, which is used for sensitivity analysis by first computing the sensitivty wrt...
std::map< uint_t, uint_t > _node_id_to_vec_index
id of local nodes for use in kd-tree search
#define Assert0(cond, msg)
uint_t n_linear_basis_nodes_on_elem(const libMesh::Elem &e)
identifies number of ndoes on element
void add(std::vector< ScalarType > &v, uint_t i, ScalarType s)
virtual ~GeometricFilter()
#define Assert2(cond, v1, v2, msg)
void compute_reverse_filtered_values(Vec input, Vec output) const
Applies the reverse map, which is used for sensitivity analysis by first computing the sensitivty wrt...
Mat _weight_matrix
Sparse Matrix object that stores the filtering matrix.
void _init_filter_matrix(const std::map< uint_t, std::vector< std::pair< uint_t, real_t >>> &filter_map)
std::map< uint_t, std::vector< std::pair< uint_t, real_t > > > _reverse_map
this map stores the columns of the matrix, which is required for sensitivity analysis ...
std::vector< uint_t > _forward_send_list
vector of dof ids that the current processor depends on.
void compute_filtered_values(libMesh::NumericVector< real_t > &input, libMesh::NumericVector< real_t > &output) const