|           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_VARIATIONAL_SMOOTHER_CONSTRAINT_H
      19             : #define LIBMESH_VARIATIONAL_SMOOTHER_CONSTRAINT_H
      20             : 
      21             : // Local Includes
      22             : #include "libmesh/system.h"
      23             : #include "libmesh/dof_map.h"
      24             : 
      25             : // C++ includes
      26             : #include <variant>
      27             : 
      28             : namespace libMesh
      29             : {
      30             : 
      31             : // Forward declarations
      32             : class PointConstraint;
      33             : class LineConstraint;
      34             : class PlaneConstraint;
      35             : class InvalidConstraint;
      36             : 
      37             : /**
      38             :  * Type used to store a constraint that may be a PlaneConstraint,
      39             :  * LineConstraint, or PointConstraint. std::variant is an alternative to using
      40             :  * the classic polymorphic approach where these constraints inherit from an
      41             :  * common base class.
      42             :  */
      43             : using ConstraintVariant = std::variant<PointConstraint, LineConstraint,
      44             :                                        PlaneConstraint, InvalidConstraint>;
      45             : 
      46             : /**
      47             :  * Represents a fixed point constraint.
      48             :  */
      49             : class PointConstraint
      50             : {
      51             : 
      52             : public:
      53         344 :   PointConstraint() = default;
      54             : 
      55             :   /**
      56             :    * Constructor
      57             :    * @param point The point defining the constraint.
      58             :    * @param tol The tolerance to use for numerical comparisons.
      59             :    */
      60     8880632 :   PointConstraint(const Point &point, const Real &tol = TOLERANCE * TOLERANCE);
      61             : 
      62             :   /**
      63             :    * Comparison operator for ordering PointConstraint objects.
      64             :    * A PointConstraint is considered less than another if its location
      65             :    * is lexicographically less than the other's location.
      66             :    * @param other The PointConstraint to compare with.
      67             :    * @param tol The tolerance to use for numerical comparisons.
      68             :    * @return True if this PointConstraint is less than the other.
      69             :    */
      70             :   bool operator<(const PointConstraint &other) const;
      71             : 
      72             :   /**
      73             :    * Equality operator.
      74             :    * @param other The PointConstraint to compare with.
      75             :    * @return True if both PointConstraints have the same location.
      76             :    */
      77             :   bool operator==(const PointConstraint &other) const;
      78             : 
      79             :   /**
      80             :    * Query whether a point lies on another point.
      81             :    * @param p The point in question
      82             :    * @return bool indicating whether p lies on this point.
      83             :    */
      84        1136 :   bool contains_point(const PointConstraint &p) const { return *this == p; }
      85             : 
      86             :   /**
      87             :    * Computes the intersection of this point with another constraint.
      88             :    * Handles intersection with PointConstraint, LineConstraint, or
      89             :    * PlaneConstraint.
      90             :    * @param other The constraint to intersect with.
      91             :    * @return The most specific ConstraintVariant that satisfies both
      92             :    * constraints. constraints. If no intersection exists, return an
      93             :    * InvalidConstraint.
      94             :    */
      95             :   ConstraintVariant intersect(const ConstraintVariant &other) const;
      96             : 
      97             :   /**
      98             :    * Const getter for the _point attribute
      99             :    */
     100      245480 :   const Point &point() const { return _point; }
     101             : 
     102             :   /**
     103             :    * Const getter for the _tol attribute
     104             :    */
     105             :   const Real &tol() const { return _tol; }
     106             : 
     107             : private:
     108             :   // Life is easier if we don't make this const
     109             :   /**
     110             :    * Location of constraint
     111             :    */
     112             :   Point _point;
     113             : 
     114             :   /**
     115             :    * Tolerance to use for numerical comparisons
     116             :    */
     117             :   Real _tol;
     118             : };
     119             : 
     120             : /**
     121             :  * Represents a line constraint defined by a base point and direction vector.
     122             :  */
     123             : class LineConstraint
     124             : {
     125             : public:
     126             :   LineConstraint() = default;
     127             : 
     128             :   /**
     129             :    * Constructor
     130             :    * @param point A point on the constraining line.
     131             :    * @param direction the direction of the constraining line.
     132             :    * @param tol The tolerance to use for numerical comparisons.
     133             :    */
     134             :   LineConstraint(const Point &point, const Point &direction,
     135       75482 :                  const Real &tol = TOLERANCE * TOLERANCE);
     136             : 
     137             :   /**
     138             :    * Comparison operator for ordering LineConstraint objects.
     139             :    * The comparison is primarily based on the direction vector. If the direction
     140             :    * vectors are equal (within tolerance), the tie is broken using the dot
     141             :    * product of the direction with the base point.
     142             :    * @param other The LineConstraint to compare with.
     143             :    * @return True if this LineConstraint is less than the other.
     144             :    */
     145             :   bool operator<(const LineConstraint &other) const;
     146             : 
     147             :   /**
     148             :    * Equality operator.
     149             :    * @param other The LineConstraint to compare with.
     150             :    * @return True if both LineConstraints represent the same line.
     151             :    */
     152             :   bool operator==(const LineConstraint &other) const;
     153             : 
     154             :   /**
     155             :    * Query whether a point lies on the line.
     156             :    * @param p The point in question
     157             :    * @return bool indicating whether p lies on the line.
     158             :    */
     159             :   bool contains_point(const PointConstraint &p) const;
     160             : 
     161             :   /**
     162             :    * Query whether a line is parallel to this line
     163             :    * @param l The line in question
     164             :    * @return bool indicating whether l is parallel to this line.
     165             :    */
     166             :   bool is_parallel(const LineConstraint &l) const;
     167             : 
     168             :   /**
     169             :    * Query whether a plane is parallel to this line
     170             :    * @param p The plane in question
     171             :    * @return bool indicating whether p is parallel to this line.
     172             :    */
     173             :   bool is_parallel(const PlaneConstraint &p) const;
     174             : 
     175             :   /**
     176             :    * Computes the intersection of this line with another constraint.
     177             :    * Handles intersection with LineConstraint, PlaneConstraint, or
     178             :    * PointConstraint.
     179             :    * @param other The constraint to intersect with.
     180             :    * @return The most specific ConstraintVariant that satisfies both
     181             :    * constraints. constraints. If no intersection exists, return an
     182             :    * InvalidConstraint.
     183             :    */
     184             :   ConstraintVariant intersect(const ConstraintVariant &other) const;
     185             : 
     186             :   /**
     187             :    * Const getter for the _point attribute
     188             :    */
     189       25725 :   const Point &point() const { return _point; }
     190             : 
     191             :   /**
     192             :    * Const getter for the _direction attribute
     193             :    */
     194       54346 :   const Point &direction() const { return _direction; }
     195             : 
     196             :   /**
     197             :    * Const getter for the _tol attribute
     198             :    */
     199             :   const Real &tol() const { return _tol; }
     200             : 
     201             : private:
     202             :   // Life is easier if we don't make these const
     203             :   /**
     204             :    * A point on the constraining line
     205             :    */
     206             :   Point _point;
     207             : 
     208             :   /**
     209             :    * Direction of the constraining line
     210             :    */
     211             :   Point _direction;
     212             : 
     213             :   /**
     214             :    * Tolerance to use for numerical comparisons
     215             :    */
     216             :   Real _tol;
     217             : };
     218             : 
     219             : /**
     220             :  * Represents a plane constraint defined by a point and normal vector.
     221             :  */
     222             : class PlaneConstraint
     223             : {
     224             : 
     225             : public:
     226             :   PlaneConstraint() = default;
     227             : 
     228             :   /**
     229             :    * Constructor
     230             :    * @param point A point on the constraining plane.
     231             :    * @param normal the direction normal to the constraining plane.
     232             :    * @param tol The tolerance to use for numerical comparisons.
     233             :    */
     234             :   PlaneConstraint(const Point &point, const Point &normal,
     235     4609107 :                   const Real &tol = TOLERANCE * TOLERANCE);
     236             : 
     237             :   /**
     238             :    * Comparison operator for ordering PlaneConstraint objects.
     239             :    * The comparison is primarily based on the normal vector. If the normal
     240             :    * vectors are equal (within tolerance), the tie is broken using the dot
     241             :    * product of the normal with the point on the plane.
     242             :    * @param other The PlaneConstraint to compare with.
     243             :    * @return True if this PlaneConstraint is less than the other.
     244             :    */
     245             :   bool operator<(const PlaneConstraint &other) const;
     246             : 
     247             :   /**
     248             :    * Equality operator.
     249             :    * @param other The PlaneConstraint to compare with.
     250             :    * @return True if both PlaneConstraints represent the same plane.
     251             :    */
     252             :   bool operator==(const PlaneConstraint &other) const;
     253             : 
     254             :   /**
     255             :    * Query whether a point lies on the plane.
     256             :    * @param p The point in question
     257             :    * @return bool indicating whether p lies on the plane.
     258             :    */
     259             :   bool contains_point(const PointConstraint &p) const;
     260             : 
     261             :   /**
     262             :    * Query whether a line lies on the plane.
     263             :    * @param l The line in question
     264             :    * @return bool indicating whether l lies on the plane.
     265             :    */
     266             :   bool contains_line(const LineConstraint &l) const;
     267             : 
     268             :   /**
     269             :    * Query whether a plane is parallel to this plane
     270             :    * @param p The plane in question
     271             :    * @return bool indicating whether p is parallel to this plane.
     272             :    */
     273             :   bool is_parallel(const PlaneConstraint &p) const;
     274             : 
     275             :   /**
     276             :    * Query whether a line is parallel to this plane
     277             :    * @param l The line in question
     278             :    * @return bool indicating whether l is parallel to this plane.
     279             :    */
     280             :   bool is_parallel(const LineConstraint &l) const;
     281             : 
     282             :   /**
     283             :    * Computes the intersection of this plane with another constraint.
     284             :    * Handles intersection with PlaneConstraint, LineConstraint, or
     285             :    * PointConstraint.
     286             :    * @param other The constraint to intersect with.
     287             :    * @return The most specific ConstraintVariant that satisfies both
     288             :    * constraints. constraints. If no intersection exists, return an
     289             :    * InvalidConstraint.
     290             :    */
     291             :   ConstraintVariant intersect(const ConstraintVariant &other) const;
     292             : 
     293             :   /**
     294             :    * Const getter for the _point attribute
     295             :    */
     296     8614058 :   const Point &point() const { return _point; }
     297             : 
     298             :   /**
     299             :    * Const getter for the _normal attribute
     300             :    */
     301      505145 :   const Point &normal() const { return _normal; }
     302             : 
     303             :   /**
     304             :    * Const getter for the _tol attribute
     305             :    */
     306             :   const Real &tol() const { return _tol; }
     307             : 
     308             : private:
     309             :   // Life is easier if we don't make these const
     310             :   /**
     311             :    * A point on the constraining plane
     312             :    */
     313             :   Point _point;
     314             : 
     315             :   /**
     316             :    * The direction normal to the constraining plane
     317             :    */
     318             :   Point _normal;
     319             : 
     320             :   /**
     321             :    * Tolerance to use for numerical comparisons
     322             :    */
     323             :   Real _tol;
     324             : };
     325             : 
     326             : /**
     327             :  * Represents an invalid constraint (i.e., when the two constraints don't
     328             :  * intersect)
     329             :  */
     330         536 : class InvalidConstraint
     331             : {
     332             : 
     333             : public:
     334           4 :   InvalidConstraint()
     335         142 :     : _err_msg("We should never get here! The InvalidConstraint object should be "
     336             :                "detected and replaced with a valid ConstraintVariant prior to calling "
     337           8 :                "any class methods.")
     338             :   {
     339           4 :   }
     340             : 
     341             :   /**
     342             :    * Dummy intersect method that should never be called.
     343             :    */
     344           0 :   ConstraintVariant intersect(const ConstraintVariant &) const {
     345           0 :     libmesh_assert_msg(false, _err_msg);
     346           0 :     return *this;
     347             :   }
     348             : 
     349             :   /**
     350             :    * Dummy contains_point method that should never be called.
     351             :    */
     352           0 :   bool contains_point(const PointConstraint &) const {
     353           0 :     libmesh_assert_msg(false, _err_msg);
     354           0 :     return false;
     355             :   }
     356             : 
     357             : private:
     358             :   std::string _err_msg;
     359             : };
     360             : 
     361             : /**
     362             :  * Dispatch intersection between two constraint variants.
     363             :  * Resolves to the appropriate method based on the type of the first operand.
     364             :  * @param a First constraint.
     365             :  * @param b Constraint to combine with a.
     366             :  * @return Combination (intersection) of constraint a and b.
     367             :  */
     368        4676 : inline ConstraintVariant intersect_constraints(const ConstraintVariant &a,
     369             :                                                const ConstraintVariant &b) {
     370             :   // std::visit applies the visitor v (a Callable that can be called with any
     371             :   // combination of types from Variants) to the active value inside a
     372             :   // std::Variant. This circumvents the issue that the literal ConstraintVariant
     373             :   // type does not have a method called 'intersect' (but the types defining
     374             :   // ConstraintVariant do)
     375             :   return std::visit(
     376      322542 :       [](const auto &lhs, const auto &rhs) -> ConstraintVariant {
     377      327214 :         return lhs.intersect(rhs);
     378             :       },
     379      165945 :       a, b);
     380             : }
     381             : 
     382             : /**
     383             :  * Constraint class for the VariationalMeshSmoother.
     384             :  *
     385             :  * Currently, all mesh boundary nodes are constrained to not move during
     386             :  * smoothing. If requested (preserve_subdomain_boundaries = true), nodes on
     387             :  * subdomain boundaries are also constrained to not move.
     388             :  */
     389         272 : class VariationalSmootherConstraint : public System::Constraint
     390             : {
     391             : private:
     392             : 
     393             :   /**
     394             :    * Verbosity setting.
     395             :    * The verbosity levels and the corresponding information output are as
     396             :    * follows:
     397             :    *
     398             :    *   verbosity = 0: No information.
     399             :    *
     400             :    *   20 < verbosity: Prints:
     401             :    *     - Constraint information on all boundary and subdomain nodes
     402             :    */
     403             :   const unsigned int _verbosity;
     404             : 
     405             :   System & _sys;
     406             : 
     407             :   /**
     408             :    * Whether nodes on subdomain boundaries are subject to change via smoothing
     409             :    */
     410             :   const bool _preserve_subdomain_boundaries;
     411             : 
     412             :   /**
     413             :    * Constrain (i.e., fix) a node to not move during mesh smoothing.
     414             :    * @param node Node to fix.
     415             :    */
     416             :   void fix_node(const Node & node);
     417             : 
     418             :   /**
     419             :    * Constrain a node to remain in the given plane during mesh smoothing.
     420             :    * @param node Node to constrain
     421             :    * @param ref_normal_vec Reference normal vector to the constraining plane.
     422             :    * This, along with the coordinates of node, are used to define the
     423             :    * constraining plane.
     424             :    */
     425             :   void constrain_node_to_plane(const Node & node, const Point & ref_normal_vec);
     426             : 
     427             :   /**
     428             :    * Constrain a node to remain on the given line during mesh smoothing.
     429             :    * @param node Node to constrain
     430             :    * @param line_vec vector parallel to the constraining line.
     431             :    * This, along with the coordinates of node, are used to define the
     432             :    * constraining line.
     433             :    */
     434             :   void constrain_node_to_line(const Node & node, const Point & line_vec);
     435             : 
     436             :   /**
     437             :    * Determines whether two neighboring nodes share a common boundary id.
     438             :    * @param boundary_node The first of the two prospective nodes.
     439             :    * @param neighbor_node The second of the two prospective nodes.
     440             :    * @param containing_elem The element containing node1 and node2.
     441             :    * @param boundary_info The mesh's BoundaryInfo.
     442             :    * @return nodes_share_bid Whether node1 and node2 share a common boundary id.
     443             :    */
     444             :   static bool nodes_share_boundary_id(
     445             :       const Node & boundary_node,
     446             :       const Node & neighbor_node,
     447             :       const Elem & containing_elem,
     448             :       const BoundaryInfo & boundary_info);
     449             : 
     450             :   /**
     451             :    * Get the relevant nodal neighbors for a subdomain constraint.
     452             :    * @param mesh The mesh being smoothed.
     453             :    * @param node The node (on the subdomain boundary) being constrained.
     454             :    * @param sub_id The subdomain id of the block on one side of the subdomain
     455             :    * boundary.
     456             :    * @param nodes_to_elem_map A mapping from node id to containing element ids.
     457             :    * @return A set of node pointer sets containing nodal neighbors to 'node' on
     458             :    * the sub_id1-sub_id2 boundary. The subsets are grouped by element faces
     459             :    * that form the subdomain boundary. Note that 'node' itself does not appear
     460             :    * in this set.
     461             :    */
     462             :   static std::set<std::set<const Node *>>
     463             :   get_neighbors_for_subdomain_constraint(
     464             :       const MeshBase &mesh, const Node &node, const subdomain_id_type sub_id,
     465             :       const std::unordered_map<dof_id_type, std::vector<const Elem *>>
     466             :           &nodes_to_elem_map);
     467             : 
     468             :   /**
     469             :    * Get the relevant nodal neighbors for an external boundary constraint.
     470             :    * @param mesh The mesh being smoothed.
     471             :    * @param node The node (on the external boundary) being constrained.
     472             :    * @param boundary_node_ids The set of mesh's external boundary node ids.
     473             :    * @param boundary_info The mesh's BoundaryInfo.
     474             :    * @param nodes_to_elem_map A mapping from node id to containing element ids.
     475             :    * @return A set of node pointer sets containing nodal neighbors to 'node' on
     476             :    * the external boundary. The subsets are grouped by element faces that form
     477             :    * the external boundary. Note that 'node' itself does not appear in this
     478             :    * set.
     479             :    */
     480             :   static std::set<std::set<const Node *>> get_neighbors_for_boundary_constraint(
     481             :       const MeshBase &mesh, const Node &node,
     482             :       const std::unordered_set<dof_id_type> &boundary_node_ids,
     483             :       const BoundaryInfo &boundary_info,
     484             :       const std::unordered_map<dof_id_type, std::vector<const Elem *>>
     485             :           &nodes_to_elem_map);
     486             : 
     487             :   /**
     488             :    * Determines the appropriate constraint (PointConstraint, LineConstraint, or
     489             :    * PlaneConstraint) for a node based on its neighbors.
     490             :    * @param node The node to constrain.
     491             :    * @param dim The mesh dimension.
     492             :    * @return The best-fit constraint for the given geometry.
     493             :    */
     494             :   static ConstraintVariant determine_constraint(
     495             :       const Node &node, const unsigned int dim,
     496             :       const std::set<std::set<const Node *>> &side_grouped_boundary_neighbors);
     497             : 
     498             :   /**
     499             :    * Applies a given constraint to a node (e.g., fixing it, restricting it to a
     500             :    * line or plane).
     501             :    * @param node The node to constrain.
     502             :    * @param constraint The geometric constraint variant to apply.
     503             :    * @throw libMesh::logicError If the constraint cannot be imposed.
     504             :    */
     505             :   void impose_constraint(const Node &node, const ConstraintVariant &constraint);
     506             : 
     507             : public:
     508             :   /**
     509             :    * Constructor
     510             :    * @param sys System to constrain.
     511             :    * @param preserve_subdomain_boundaries Whether to constrain nodes on
     512             :    * subdomain boundaries to not move.
     513             :    */
     514             :   VariationalSmootherConstraint(System & sys,
     515             :                                 const bool & preserve_subdomain_boundaries,
     516             :                                 const unsigned int verbosity);
     517             : 
     518             :   virtual ~VariationalSmootherConstraint() override;
     519             : 
     520             :   virtual void constrain() override;
     521             : };
     522             : 
     523             : 
     524             : } // namespace libMesh
     525             : 
     526             : #endif // LIBMESH_VARIATIONAL_SMOOTHER_CONSTRAINT_H
 |