Line data Source code
1 : // The libMesh Finite Element Library. 2 : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 3 : 4 : // This library is free software; you can redistribute it and/or 5 : // modify it under the terms of the GNU Lesser General Public 6 : // License as published by the Free Software Foundation; either 7 : // version 2.1 of the License, or (at your option) any later version. 8 : 9 : // This library is distributed in the hope that it will be useful, 10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 : // Lesser General Public License for more details. 13 : 14 : // You should have received a copy of the GNU Lesser General Public 15 : // License along with this library; if not, write to the Free Software 16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 : 18 : #include "libmesh/boundary_volume_solution_transfer.h" 19 : #include "libmesh/elem.h" 20 : #include "libmesh/numeric_vector.h" 21 : #include "libmesh/dof_map.h" 22 : 23 : namespace libMesh { 24 : 25 0 : void BoundaryVolumeSolutionTransfer::transfer(const Variable & from_var, 26 : const Variable & to_var) 27 : { 28 : // Determine which direction the transfer is in 29 0 : System * from_sys = from_var.system(); 30 0 : System * to_sys = to_var.system(); 31 : 32 : unsigned int 33 0 : from_dimension = from_sys->get_mesh().mesh_dimension(), 34 0 : to_dimension = to_sys->get_mesh().mesh_dimension(); 35 : 36 : // Sanity check 37 0 : libmesh_error_msg_if(from_dimension == to_dimension, 38 : "Error: Transfer must be from volume mesh to its boundary or vice-versa!"); 39 : 40 0 : if (from_dimension > to_dimension) 41 0 : this->transfer_volume_boundary(from_var, to_var); 42 : else 43 0 : this->transfer_boundary_volume(from_var, to_var); 44 0 : } 45 : 46 : 47 : 48 0 : void BoundaryVolumeSolutionTransfer:: 49 : transfer_volume_boundary(const Variable & from_var, const Variable & to_var) 50 : { 51 : // Get references to the Systems from the Variables 52 0 : System * from_sys = from_var.system(); // volume system 53 0 : System * to_sys = to_var.system(); // boundary system 54 : 55 : // Get reference to the BoundaryMesh. Note: we always loop over the 56 : // BoundaryMesh since, by definition, it has fewer dofs than the 57 : // volume mesh. 58 0 : const MeshBase & to_mesh = to_sys->get_mesh(); 59 : 60 : // Get system number and variable numbers 61 0 : const unsigned int from_sys_number = from_sys->number(); 62 0 : const unsigned int from_var_number = from_var.number(); 63 : 64 0 : const unsigned int to_sys_number = to_sys->number(); 65 0 : const unsigned int to_var_number = to_var.number(); 66 : 67 : // Get a constant reference to variables, get their number of components 68 0 : const unsigned int from_n_comp = from_var.n_components(from_sys->get_mesh()); 69 0 : const unsigned int to_n_comp = to_var.n_components(to_mesh); 70 : 71 : // Sanity check that the variables have the same number of components 72 0 : libmesh_assert_equal_to(from_n_comp, to_n_comp); 73 : 74 : // Construct map from "from" dofs to "to" dofs. 75 : typedef std::map<numeric_index_type, numeric_index_type> DofMapping; 76 0 : DofMapping dof_mapping; 77 : 78 : // Loop through all boundary elements. 79 0 : for (const auto & to_elem : to_mesh.active_local_element_ptr_range()) 80 : { 81 0 : const Elem * from_elem = to_elem->interior_parent(); 82 : 83 0 : libmesh_error_msg_if(!from_elem, "Error, transfer must be between a Mesh and its associated BoundaryMesh."); 84 : 85 : // loop through all nodes in each boundary element. 86 0 : for (const Node & to_node : to_elem->node_ref_range()) 87 : { 88 : // Nodes in interior_parent element. 89 0 : for (const Node & from_node : from_elem->node_ref_range()) 90 : { 91 0 : const dof_id_type from_dof = from_node.dof_number(from_sys_number, 92 : from_var_number, 93 0 : from_n_comp - 1); 94 : 95 : // If we've already mapped this dof, we don't need to map 96 : // it again or do floating point comparisons. 97 0 : if (!dof_mapping.count(from_dof) && 98 0 : from_node.absolute_fuzzy_equals(to_node, TOLERANCE)) 99 : { 100 : // Global dof_index for node in BoundaryMesh. 101 0 : const dof_id_type to_dof = to_node.dof_number(to_sys_number, 102 : to_var_number, 103 : to_n_comp - 1); 104 : 105 : // Keep track of the volume system dof index which is needed. 106 0 : dof_mapping[from_dof] = to_dof; 107 : } 108 : } 109 : } 110 0 : } 111 : 112 : // Construct a vector of the indices needed from the Volume system's 113 : // global solution vector on this processor. 114 0 : std::vector<numeric_index_type> needed_indices; 115 0 : needed_indices.reserve(dof_mapping.size()); 116 : { 117 : DofMapping::iterator 118 0 : it = dof_mapping.begin(), 119 0 : end = dof_mapping.end(); 120 : 121 0 : for (; it!=end; ++it) 122 0 : needed_indices.push_back(it->first); 123 : } 124 : 125 : // Communicate just the required values without making a copy of the 126 : // global solution vector. 127 0 : std::vector<Number> needed_values; 128 0 : from_sys->solution->localize(needed_values, needed_indices); 129 : 130 : // Loop over DofMapping again, assigning values in the 131 : // Boundary System solution vector. 132 : { 133 : DofMapping::iterator 134 0 : it = dof_mapping.begin(), 135 0 : end = dof_mapping.end(); 136 : 137 0 : for (unsigned idx=0; it!=end; ++it, ++idx) 138 0 : to_sys->solution->set(it->second, needed_values[idx]); 139 : } 140 0 : } 141 : 142 : 143 0 : void BoundaryVolumeSolutionTransfer:: 144 : transfer_boundary_volume(const Variable & from_var, const Variable & to_var) 145 : { 146 : // Get references to the Systems from the Variables 147 0 : System * from_sys = from_var.system(); // boundary system 148 0 : System * to_sys = to_var.system(); // volume system 149 : 150 : // Get reference to BoundaryMesh. 151 0 : const MeshBase & from_mesh = from_sys->get_mesh(); 152 : 153 : // DofMap for BoundaryMesh 154 0 : const DofMap & dof_map = from_sys->get_dof_map(); 155 : 156 : // Get system number and variable numbers 157 0 : const unsigned int to_sys_number = to_sys->number(); 158 0 : const unsigned int to_var_number = to_var.number(); 159 0 : const unsigned int from_var_number = from_var.number(); 160 0 : const unsigned int to_n_comp = to_var.n_components(to_sys->get_mesh()); 161 : 162 : // In order to get solution vectors from BoundaryMesh 163 0 : std::vector<dof_id_type> from_dof_indices; 164 0 : std::vector<Number> value; 165 : 166 : // Loop through all boundary elements. 167 0 : for (const auto & from_elem : from_mesh.active_local_element_ptr_range()) 168 : { 169 0 : const Elem * to_elem = from_elem->interior_parent(); 170 : 171 0 : libmesh_error_msg_if(!to_elem, "Error, transfer must be between a Mesh and its associated BoundaryMesh."); 172 : 173 : // Get dof indices for phi2 for all nodes on this boundary element 174 0 : dof_map.dof_indices(from_elem, from_dof_indices, from_var_number); 175 : 176 : // Get values from BoundaryMesh for this element 177 0 : from_sys->current_local_solution->get(from_dof_indices, value); 178 : 179 : // loop through all nodes in each boundary element. 180 0 : for (auto node : from_elem->node_index_range()) 181 : { 182 : // Node in boundary element. 183 0 : const Node * from_node = from_elem->node_ptr(node); 184 : 185 : // Nodes in interior_parent element. 186 0 : for (const Node & to_node : to_elem->node_ref_range()) 187 : { 188 : // Match BoundaryNode & VolumeNode. 189 0 : if (to_node.absolute_fuzzy_equals(*from_node, TOLERANCE)) 190 : { 191 : // Global dof_index for node in VolumeMesh. 192 0 : const dof_id_type to_dof = to_node.dof_number(to_sys_number, 193 : to_var_number, 194 : to_n_comp - 1); 195 : 196 : // Assign values to boundary in VolumeMesh. 197 0 : to_sys->solution->set(to_dof, value[node]); 198 : } 199 : } 200 : } 201 0 : } 202 0 : } 203 : 204 : } // namespace libMesh