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 : #ifndef LIBMESH_STATIC_CONDENSATION_DOF_MAP_H 19 : #define LIBMESH_STATIC_CONDENSATION_DOF_MAP_H 20 : 21 : #include "libmesh/libmesh_config.h" 22 : 23 : #include "libmesh/id_types.h" 24 : #include "libmesh/libmesh_common.h" 25 : #include "libmesh/dof_map_base.h" 26 : #include "libmesh/variable.h" 27 : #include "libmesh/sparsity_pattern.h" 28 : #include "libmesh/utility.h" 29 : 30 : #include <unordered_map> 31 : #include <memory> 32 : #include <vector> 33 : 34 : namespace libMesh 35 : { 36 : class MeshBase; 37 : class System; 38 : class DofMap; 39 : class Elem; 40 : 41 : /** 42 : * A class holding degree of freedom information pertinent to static condensation. 43 : * Static condensation is a process for reducing the number of unknowns in a 44 : * linear(ized) system. It is often used in conjunction with a hybridized discontinuous Galerkin 45 : * (HDG) method to reduce the number of unknowns in the linear system to something more on the order 46 : * of a continuous Galerkin (CG) method as opposed to a discontinuous Galerkin method. In the HDG 47 : * example, degrees of freedom on the element interiors are condensed out and only the degrees of 48 : * freedom on element faces are retained in the condensed system. Static condensation is not only 49 : * applicable to HDG methods, however. One could also use static condensation with a high order CG 50 : * method, again removing internal degrees of freedom and leaving those on element boundaries. 51 : * 52 : * Users may query this class for condensed space degree of freedom information associated with 53 : * elements. Queries with nodes are not supported. This class also holds information for mapping 54 : * degree of freedom indices in the global, uncondensed space to local element degree of freedom 55 : * numbers. This information is essential in order to build the element Schur complement matrices 56 : * that are used to map global system vector and matrix data to the condensed system vector and 57 : * matrix data 58 : */ 59 60 : class StaticCondensationDofMap : public DofMapBase 60 : { 61 : public: 62 : StaticCondensationDofMap(MeshBase & mesh, System & system, const DofMap & dof_map); 63 : virtual ~StaticCondensationDofMap(); 64 : 65 : // 66 : // Unique methods 67 : // 68 : 69 : /** 70 : * Build the element global to local index maps 71 : */ 72 : void reinit(); 73 : 74 : /** 75 : * Add \p vars to the list of variables not to condense. This can be useful when some variable's 76 : * equation is discretized with a DG method or if including the variable in the condensed block 77 : * diagonal would result in it being singular 78 : */ 79 : void dont_condense_vars(const std::unordered_set<unsigned int> & vars); 80 : 81 : /** 82 : * @returns our list of variables for whom we do not condense out any dofs 83 : */ 84 3786 : const std::unordered_set<unsigned int> & uncondensed_vars() const { return _uncondensed_vars; } 85 : 86 : virtual unsigned int n_variables() const override; 87 : 88 : virtual const Variable & variable(const unsigned int c) const override; 89 : 90 : virtual void dof_indices(const Elem * const elem, 91 : std::vector<dof_id_type> & di, 92 : const unsigned int vn, 93 : int p_level = -12345) const override; 94 : 95 : virtual void dof_indices(const Node * const node, 96 : std::vector<dof_id_type> & di, 97 : const unsigned int vn) const override; 98 : 99 : /* 100 : * @returns The dummyish reduced system 101 : */ 102 : const System & reduced_system() const; 103 : 104 : /** 105 : * Whether we are initialized 106 : */ 107 490 : bool initialized() const { return _sc_is_initialized; } 108 : 109 : virtual void clear() override; 110 : 111 : /** 112 : * Retrieve the dof index in the reduced system corresponding to the provided dof index in the 113 : * full system. This dof index should be a dof index involved in constraints 114 : */ 115 : dof_id_type get_reduced_from_global_constraint_dof(dof_id_type full_dof) const; 116 : 117 : private: 118 : /** 119 : * Add an uncondensed dof potentially along with constraining dofs which themselves must/will also 120 : * be uncondensed 121 : * @param full_dof_number The dof id in the full (uncondensed + condensed) system 122 : * @param involved_in_constraints Whether the \p full_dof_number is involved in constraints 123 : * @param uncondensed_local_to_global_map A map from uncondensed full dof numbering to local 124 : * (element) numbering for a given element 125 : * @param local_uncondensed_dofs_set Set of local uncondensed degrees of freedom (numbered in the 126 : * full system) 127 : * @param nonlocal_uncondensed_dofs Map from processor IDs to sets of nonlocal uncondensed degrees 128 : * of freedom (numbered in the full system) 129 : * @param elem_uncondensed_dofs Used for temporary storage of uncondensed degrees of freedom 130 : * active on an element 131 : * @param uncondensed_local_dof_number Counter for number of uncondensed dofs on an element 132 : * @param constraint_dofs Set of degrees of freedom numbered in the full system involved in 133 : * constraints 134 : */ 135 : void add_uncondensed_dof_plus_constraint_dofs( 136 : dof_id_type full_dof_number, 137 : bool involved_in_constraints, 138 : std::unordered_map<dof_id_type, dof_id_type> & uncondensed_global_to_local_map, 139 : std::unordered_set<dof_id_type> & local_uncondensed_dofs_set, 140 : std::unordered_map<processor_id_type, std::unordered_set<dof_id_type>> & 141 : nonlocal_uncondensed_dofs, 142 : std::vector<dof_id_type> & elem_uncondensed_dofs, 143 : dof_id_type & uncondensed_local_dof_number, 144 : std::unordered_set<dof_id_type> & constraint_dofs); 145 : 146 : /** 147 : * Add an uncondensed dof 148 : * @param full_dof_number The dof id in the full (uncondensed + condensed) system 149 : * @param involved_in_constraints Whether the \p full_dof_number is involved in constraints 150 : * @param uncondensed_local_to_global_map A map from uncondensed full dof numbering to local 151 : * (element) numbering for a given element 152 : * @param local_uncondensed_dofs_set Set of local uncondensed degrees of freedom (numbered in the 153 : * full system) 154 : * @param nonlocal_uncondensed_dofs Map from processor IDs to sets of nonlocal uncondensed degrees 155 : * of freedom (numbered in the full system) 156 : * @param elem_uncondensed_dofs Used for temporary storage of uncondensed degrees of freedom 157 : * active on an element 158 : * @param uncondensed_local_dof_number Counter for number of uncondensed dofs on an element 159 : * @param constraint_dofs Set of degrees of freedom numbered in the full system involved in 160 : * constraints 161 : */ 162 : void add_uncondensed_dof( 163 : dof_id_type full_dof_number, 164 : bool involved_in_constraints, 165 : std::unordered_map<dof_id_type, dof_id_type> & uncondensed_global_to_local_map, 166 : std::unordered_set<dof_id_type> & local_uncondensed_dofs_set, 167 : std::unordered_map<processor_id_type, std::unordered_set<dof_id_type>> & 168 : nonlocal_uncondensed_dofs, 169 : std::vector<dof_id_type> & elem_uncondensed_dofs, 170 : dof_id_type & uncondensed_local_dof_number, 171 : std::unordered_set<dof_id_type> & constraint_dofs); 172 : 173 : /** 174 : * Data stored on a per-element basis used to compute element Schur complements and their 175 : * applications to vectors 176 : */ 177 : struct DofData 178 : { 179 : /// The uncondensed degrees of freedom with global numbering corresponding to the the \emph reduced 180 : /// system. Note that initially this will actually hold the indices corresponding to the fully 181 : /// sized problem, but we will swap it out by the time we are done initializing 182 : std::vector<std::vector<dof_id_type>> reduced_space_indices; 183 : 184 : /// A map from the global degree of freedom number for the full system (condensed + uncondensed) 185 : /// to an element local number. If this map is queried with a condensed dof, nothing will be 186 : /// found. The size of this container will be the number of uncondensed degrees of freedom whose 187 : /// basis functions are nonzero on the element 188 : std::unordered_map<dof_id_type, dof_id_type> uncondensed_global_to_local_map; 189 : /// A map from the global degree of freedom number for the full system (condensed + uncondensed) 190 : /// to an element local number. If this map is queried with an uncondensed dof, nothing will be 191 : /// found. The size of this container will be the number of condensed degrees of freedom whose 192 : /// basis functions are nonzero on the element 193 : std::unordered_map<dof_id_type, dof_id_type> condensed_global_to_local_map; 194 : }; 195 : 196 : /// Friend the static condensation matrix class so they can inspect our degree of freedom data 197 : friend class StaticCondensation; 198 : 199 : /// A map from element ID to Schur complement data 200 : std::unordered_map<dof_id_type, DofData> _elem_to_dof_data; 201 : 202 : /// All the uncondensed degrees of freedom (numbered in the "full" uncondensed + condensed 203 : /// space). This data member is used for creating subvectors corresponding to only uncondensed 204 : /// dofs 205 : std::vector<dof_id_type> _local_uncondensed_dofs; 206 : 207 : MeshBase & _mesh; 208 : System & _system; 209 : const DofMap & _dof_map; 210 : 211 : /// Variables for which we will keep all dofs 212 : std::unordered_set<unsigned int> _uncondensed_vars; 213 : 214 : /// Whether our object has been initialized 215 : bool _sc_is_initialized; 216 : 217 : /// The variables in the reduced system 218 : std::vector<Variable> _reduced_vars; 219 : 220 : /// A dummyish system to help with DofObjects 221 : System * _reduced_system; 222 : 223 : /// Owned storage of the reduced system sparsity pattern 224 : std::unique_ptr<SparsityPattern::Build> _reduced_sp; 225 : 226 : /// Number of on-diagonal nonzeros per row in the reduced system 227 : std::vector<dof_id_type> _reduced_nnz; 228 : 229 : /// Number of off-diagonal nonzeros per row in the reduced system 230 : std::vector<dof_id_type> _reduced_noz; 231 : 232 : /// A small map from full system degrees of freedom to reduced/condensed system degrees of freedom 233 : /// involved in constraints. This may be leveraged by \p StaticCondensation::set during \p 234 : /// DofMap::enforce_constraints_on_jacobian at the very end of Jacobian evaluation 235 : std::unordered_map<dof_id_type, dof_id_type> _full_to_reduced_constraint_dofs; 236 : }; 237 : 238 : inline void 239 272 : StaticCondensationDofMap::dont_condense_vars(const std::unordered_set<unsigned int> & vars) 240 : { 241 272 : _uncondensed_vars.insert(vars.begin(), vars.end()); 242 272 : } 243 : 244 : inline const System & StaticCondensationDofMap::reduced_system() const 245 : { 246 : libmesh_assert(_reduced_system); 247 : return *_reduced_system; 248 : } 249 : 250 : inline dof_id_type 251 0 : StaticCondensationDofMap::get_reduced_from_global_constraint_dof(const dof_id_type full_dof) const 252 : { 253 0 : return libmesh_map_find(_full_to_reduced_constraint_dofs, full_dof); 254 : } 255 : 256 : } 257 : 258 : #endif // LIBMESH_STATIC_CONDENSATION_DOF_MAP_H