PolyFEM
Loading...
Searching...
No Matches
BCPenaltyForm.cpp
Go to the documentation of this file.
1#include "BCPenaltyForm.hpp"
2
4
5namespace polyfem::solver
6{
8 const std::vector<int> &boundary_nodes,
9 const std::vector<mesh::LocalBoundary> &local_boundary,
10 const std::vector<mesh::LocalBoundary> &local_neumann_boundary,
11 const int n_boundary_samples,
12 const StiffnessMatrix &mass,
13 const assembler::RhsAssembler &rhs_assembler,
14 const size_t obstacle_ndof,
15 const bool is_time_dependent,
16 const double t)
17 : boundary_nodes_(boundary_nodes),
18 local_boundary_(&local_boundary),
19 local_neumann_boundary_(&local_neumann_boundary),
20 n_boundary_samples_(n_boundary_samples),
21 rhs_assembler_(&rhs_assembler),
22 is_time_dependent_(is_time_dependent)
23 {
24 init_masked_lumped_mass(ndof, mass, obstacle_ndof);
25 update_target(t); // initialize target_x_
26 }
27
29 const std::vector<int> &boundary_nodes,
30 const StiffnessMatrix &mass,
31 const size_t obstacle_ndof,
32 const Eigen::MatrixXd &target_x)
33 : boundary_nodes_(boundary_nodes),
34 local_boundary_(nullptr),
35 local_neumann_boundary_(nullptr),
36 n_boundary_samples_(0),
37 rhs_assembler_(nullptr),
38 is_time_dependent_(false),
39 target_x_(target_x)
40 {
41 init_masked_lumped_mass(ndof, mass, obstacle_ndof);
42 }
43
45 const int ndof,
46 const StiffnessMatrix &mass,
47 const size_t obstacle_ndof)
48 {
49 std::vector<bool> is_boundary_dof(ndof, true);
50 for (const auto bn : boundary_nodes_)
51 is_boundary_dof[bn] = false;
52
54 assert(ndof == masked_lumped_mass_.rows() && ndof == masked_lumped_mass_.cols());
55
56 // Give the collision obstacles a entry in the lumped mass matrix
57 if (obstacle_ndof > 0)
58 {
59 const int n_fe_dof = ndof - obstacle_ndof;
60 const double avg_mass = masked_lumped_mass_.diagonal().head(n_fe_dof).mean();
61 for (int i = n_fe_dof; i < ndof; ++i)
62 {
63 masked_lumped_mass_.coeffRef(i, i) = avg_mass;
64 }
65 }
66
67 // Remove non-boundary ndof from mass matrix
68 masked_lumped_mass_.prune([&](const int &row, const int &col, const double &value) -> bool {
69 assert(row == col); // matrix should be diagonal
70 return !is_boundary_dof[row];
71 });
72
73 mask_.resize(masked_lumped_mass_.rows(), masked_lumped_mass_.cols());
74 mask_.setIdentity();
75 mask_.prune([&](const int &row, const int &col, const double &value) -> bool {
76 assert(row == col); // matrix should be diagonal
77 return !is_boundary_dof[row];
78 });
79 }
80
81 double BCPenaltyForm::value_unweighted(const Eigen::VectorXd &x) const
82 {
83 const Eigen::VectorXd dist = x - target_x_;
84 const double AL_penalty = 0.5 * dist.transpose() * masked_lumped_mass_ * dist;
85 return AL_penalty;
86 }
87
88 void BCPenaltyForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
89 {
90 gradv = masked_lumped_mass_ * (x - target_x_);
91 }
92
93 void BCPenaltyForm::second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const
94 {
95 hessian = masked_lumped_mass_;
96 }
97
98 void BCPenaltyForm::update_quantities(const double t, const Eigen::VectorXd &)
99 {
101 update_target(t);
102 }
103
104 double BCPenaltyForm::compute_error(const Eigen::VectorXd &x) const
105 {
106 return (this->target() - x).transpose() * this->mask() * (this->target() - x);
107 }
108
109 void BCPenaltyForm::update_target(const double t)
110 {
111 assert(rhs_assembler_ != nullptr);
112 assert(local_boundary_ != nullptr);
113 assert(local_neumann_boundary_ != nullptr);
114 target_x_.setZero(masked_lumped_mass_.rows(), 1);
117 *local_neumann_boundary_, target_x_, Eigen::MatrixXd(), t);
118 }
119} // namespace polyfem::solver
int x
void set_bc(const std::vector< mesh::LocalBoundary > &local_boundary, const std::vector< int > &bounday_nodes, const int resolution, const std::vector< mesh::LocalBoundary > &local_neumann_boundary, Eigen::MatrixXd &rhs, const Eigen::MatrixXd &displacement=Eigen::MatrixXd(), const double t=1) const
StiffnessMatrix masked_lumped_mass_
mass matrix masked by the AL dofs
const std::vector< int > & boundary_nodes_
const std::vector< mesh::LocalBoundary > * local_neumann_boundary_
void update_target(const double t)
Update target x to the Dirichlet boundary values at time t.
BCPenaltyForm(const int ndof, const std::vector< int > &boundary_nodes, const std::vector< mesh::LocalBoundary > &local_boundary, const std::vector< mesh::LocalBoundary > &local_neumann_boundary, const int n_boundary_samples, const StiffnessMatrix &mass, const assembler::RhsAssembler &rhs_assembler, const size_t obstacle_ndof, const bool is_time_dependent, const double t)
Construct a new BCPenaltyForm object with a time dependent Dirichlet boundary.
void update_quantities(const double t, const Eigen::VectorXd &x) override
Update time dependent quantities.
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
void first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Compute the first derivative of the value wrt x.
void init_masked_lumped_mass(const int ndof, const StiffnessMatrix &mass, const size_t obstacle_ndof)
Initialize the masked lumped mass matrix.
void second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const override
Compute the second derivative of the value wrt x.
Eigen::MatrixXd target_x_
actually a vector with the same size as x with target nodal positions
StiffnessMatrix mask_
identity matrix masked by the AL dofs
Eigen::VectorXd target() const
const assembler::RhsAssembler * rhs_assembler_
Reference to the RHS assembler.
const std::vector< mesh::LocalBoundary > * local_boundary_
double compute_error(const Eigen::VectorXd &x) const
virtual double value(const Eigen::VectorXd &x) const
Compute the value of the form multiplied with the weigth.
Definition Form.hpp:24
Eigen::SparseMatrix< double > lump_matrix(const Eigen::SparseMatrix< double > &M)
Lump each row of a matrix into the diagonal.
Eigen::SparseMatrix< double > sparse_identity(int rows, int cols)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:22