PolyFEM
Loading...
Searching...
No Matches
PeriodicBoundary.cpp
Go to the documentation of this file.
6
7namespace
8{
9 Eigen::MatrixXd extract_vertices(const std::shared_ptr<polyfem::mesh::MeshNodes> &mesh_nodes)
10 {
11 Eigen::MatrixXd V;
12 V.setZero(mesh_nodes->n_nodes(), mesh_nodes->node_position(0).size());
13
14 for (int i = 0; i < V.rows(); i++)
15 V.row(i) = mesh_nodes->node_position(i);
16
17 return V;
18 }
19}
20
22{
24 const bool is_scalar,
25 const int n_bases,
26 const std::vector<basis::ElementBases> &bases,
27 const std::shared_ptr<mesh::MeshNodes> &mesh_nodes,
28 const Eigen::MatrixXd &affine_matrix,
29 const double tol): affine_matrix_(affine_matrix)
30 {
31 const int dim = affine_matrix.rows();
32 problem_dim_ = is_scalar ? 1 : dim;
33
34 Eigen::MatrixXd V = extract_vertices(mesh_nodes) * affine_matrix.inverse().transpose();
35 auto boundary_nodes = mesh_nodes->boundary_nodes();
36
37 RowVectorNd min = V.colwise().minCoeff();
38 RowVectorNd max = V.colwise().maxCoeff();
39 const double bbox_size = (max - min).maxCoeff();
40 for (int d = 0; d < dim; d++)
41 affine_matrix_.col(d) *= max(d) - min(d);
42 const double eps = tol * bbox_size;
43
44 Eigen::VectorXi index_map;
45 index_map.setConstant(n_bases, 1, -1);
46
47 Eigen::VectorXi dependent_map(n_bases);
48 dependent_map.setConstant(-1);
49
50 int n_pairs = 0;
51
52 // find corresponding periodic boundary nodes
53 for (int d = 0; d < dim; d++)
54 {
55 std::set<int> dependent_ids, target_ids;
56 for (int bid : boundary_nodes)
57 {
58 if (V(bid, d) > max(d) - eps)
59 target_ids.insert(bid);
60 else if (V(bid, d) < min(d) + eps)
61 dependent_ids.insert(bid);
62 }
63
64 for (int i : dependent_ids)
65 {
66 bool found_target = false;
67 for (int j : target_ids)
68 {
69 RowVectorNd projected_diff = V.row(j) - V.row(i);
70 projected_diff(d) = 0;
71 if (projected_diff.norm() < eps)
72 {
73 dependent_map(i) = j;
74 n_pairs++;
75 found_target = true;
76 break;
77 }
78 }
79 if (!found_target)
80 log_and_throw_error("Periodic boundary condition failed to find corresponding nodes!");
81 }
82 }
83
84 {
85 periodic_mask_.setZero(n_bases);
86 for (int i = 0; i < dependent_map.size(); i++)
87 {
88 if (dependent_map(i) >= 0)
89 {
90 periodic_mask_(dependent_map(i)) = 1;
91 periodic_mask_(i) = 1;
92 }
93 }
94 }
95
96 // break dependency chains into direct dependency
97 for (int d = 0; d < dim; d++)
98 for (int i = 0; i < dependent_map.size(); i++)
99 if (dependent_map(i) >= 0 && dependent_map(dependent_map(i)) >= 0)
100 dependent_map(i) = dependent_map(dependent_map(i));
101
102 // new indexing for independent dof
103 int independent_dof = 0;
104 for (int i = 0; i < dependent_map.size(); i++)
105 {
106 if (dependent_map(i) < 0)
107 index_map(i) = independent_dof++;
108 }
109
110 for (int i = 0; i < dependent_map.size(); i++)
111 if (dependent_map(i) >= 0)
112 index_map(i) = index_map(dependent_map(i));
113
114 const int old_size = index_map.size();
115 full_to_periodic_map_.setZero(old_size * problem_dim_);
116 for (int i = 0; i < old_size; i++)
117 for (int d = 0; d < problem_dim_; d++)
118 full_to_periodic_map_(i * problem_dim_ + d) = index_map(i) * problem_dim_ + d;
119 }
120
122 {
123 const int independent_dof = full_to_periodic_map_.maxCoeff() + 1;
124
125 // account for potential pressure block
126 auto index_map = [&](int id){
127 if (id < full_to_periodic_map_.size())
128 return full_to_periodic_map_(id);
129 else
130 return (int)(id + independent_dof - full_to_periodic_map_.size());
131 };
132
133 StiffnessMatrix A_periodic(index_map(A.rows()), index_map(A.cols()));
134 std::vector<Eigen::Triplet<double>> entries;
135 entries.reserve(A.nonZeros());
136 for (int k = 0; k < A.outerSize(); k++)
137 {
138 for (StiffnessMatrix::InnerIterator it(A,k); it; ++it)
139 {
140 entries.emplace_back(index_map(it.row()), index_map(it.col()), it.value());
141 }
142 }
143 A_periodic.setFromTriplets(entries.begin(),entries.end());
144
145 std::swap(A_periodic, A);
146
147 return independent_dof;
148 }
149 Eigen::MatrixXd PeriodicBoundary::full_to_periodic(const Eigen::MatrixXd &b, bool accumulate) const
150 {
151 const int independent_dof = full_to_periodic_map_.maxCoeff() + 1;
152
153 // account for potential pressure block
154 auto index_map = [&](int id){
155 if (id < full_to_periodic_map_.size())
156 return full_to_periodic_map_(id);
157 else
158 return (int)(id + independent_dof - full_to_periodic_map_.size());
159 };
160
161 // rhs under periodic basis
162 Eigen::MatrixXd b_periodic;
163 b_periodic.setZero(index_map(b.rows()), b.cols());
164 if (accumulate)
165 for (int k = 0; k < b.rows(); k++)
166 b_periodic.row(index_map(k)) += b.row(k);
167 else
168 for (int k = 0; k < b.rows(); k++)
169 b_periodic.row(index_map(k)) = b.row(k);
170
171 return b_periodic;
172 }
173 std::vector<int> PeriodicBoundary::full_to_periodic(const std::vector<int> &boundary_nodes) const
174 {
175 std::vector<int> boundary_nodes_reduced = boundary_nodes;
176 if (has_periodic_bc())
177 {
178 for (int i = 0; i < boundary_nodes_reduced.size(); i++)
179 boundary_nodes_reduced[i] = full_to_periodic_map_(boundary_nodes_reduced[i]);
180
181 std::sort(boundary_nodes_reduced.begin(), boundary_nodes_reduced.end());
182 auto it = std::unique(boundary_nodes_reduced.begin(), boundary_nodes_reduced.end());
183 boundary_nodes_reduced.resize(std::distance(boundary_nodes_reduced.begin(), it));
184 }
185 return boundary_nodes_reduced;
186 }
187
188 Eigen::MatrixXd PeriodicBoundary::periodic_to_full(const int ndofs, const Eigen::MatrixXd &x_periodic) const
189 {
190 const int independent_dof = full_to_periodic_map_.maxCoeff() + 1;
191
192 auto index_map = [&](int id){
193 if (id < full_to_periodic_map_.size())
194 return full_to_periodic_map_(id);
195 else
196 return (int)(id + independent_dof - full_to_periodic_map_.size());
197 };
198
199 Eigen::MatrixXd x_full;
200 x_full.resize(ndofs, x_periodic.cols());
201 for (int i = 0; i < x_full.rows(); i++)
202 x_full.row(i) = x_periodic.row(index_map(i));
203
204 return x_full;
205 }
206
208 {
209 return true;
210 }
212 {
213 return true;
214 }
215}
int V
std::vector< Eigen::Triplet< double > > entries
Eigen::MatrixXd periodic_to_full(const int ndofs, const Eigen::MatrixXd &x_periodic) const
PeriodicBoundary(const bool is_scalar, const int n_bases, const std::vector< basis::ElementBases > &bases, const std::shared_ptr< mesh::MeshNodes > &mesh_nodes, const Eigen::MatrixXd &affine_matrix, const double tol)
int full_to_periodic(StiffnessMatrix &A) const
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:22