113 const int n_elements = int(bases.size());
114 term.setZero(n_verts * dim, 1);
121 for (
int e = start; e < end; ++e)
131 Eigen::MatrixXd p, grad_p;
134 Eigen::MatrixXd rhs_function;
137 for (
int q = 0; q <
vals.val.rows(); q++)
140 rhs_function.row(q) *= rho;
143 for (
int q = 0; q < local_storage.da.size(); ++q)
145 const double value = p.row(q).dot(rhs_function.row(q)) * local_storage.da(q);
146 for (
auto &v :
gvals.basis_values)
148 local_storage.vec.block(v.global[0].index * dim, 0, dim, 1) +=
value * v.grad_t_m.row(q).transpose();
156 Eigen::MatrixXd adjoint_zeroed = adjoint;
160 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
162 Eigen::MatrixXd uv, points, normals;
163 Eigen::VectorXd weights;
164 Eigen::VectorXi global_ids;
165 assembler::ElementAssemblyValues vals, gvals;
167 for (int lb_id = start; lb_id < end; ++lb_id)
169 const auto &lb = local_neumann_boundary_[lb_id];
170 const int e = lb.element_id();
172 for (int i = 0; i < lb.size(); i++)
174 const int global_primitive_id = lb.global_primitive_id(i);
176 utils::BoundarySampler::boundary_quadrature(lb, n_boundary_samples_, rhs_assembler_.mesh(), i, false, uv, points, normals, weights);
177 global_ids.setConstant(points.rows(), global_primitive_id);
179 Eigen::MatrixXd reference_normals = normals;
181 vals.compute(e, rhs_assembler_.mesh().is_volume(), points, bases[e], gbases[e]);
182 gvals.compute(e, rhs_assembler_.mesh().is_volume(), points, gbases[e], gbases[e]);
184 std::vector<std::vector<Eigen::MatrixXd>> grad_normal;
185 for (int n = 0; n < gvals.jac_it.size(); ++n)
187 Eigen::MatrixXd trafo = gvals.jac_it[n].inverse();
189 Eigen::MatrixXd deform_mat(dim, dim);
190 deform_mat.setZero();
191 Eigen::MatrixXd jac_mat(dim, gvals.basis_values.size());
193 for (const auto &b : gvals.basis_values)
195 jac_mat.col(b_idx++) = b.grad.row(n);
197 for (const auto &g : b.global)
198 for (int d = 0; d < dim; ++d)
199 deform_mat.row(d) += x(g.index * dim + d) * b.grad.row(n);
203 trafo = trafo.inverse();
205 Eigen::VectorXd displaced_normal = normals.row(n) * trafo;
206 normals.row(n) = displaced_normal / displaced_normal.norm();
208 std::vector<Eigen::MatrixXd> grad;
210 Eigen::MatrixXd vec = -(jac_mat.transpose() * trafo * reference_normals.row(n).transpose());
212 for (int k = 0; k < dim; ++k)
214 Eigen::MatrixXd grad_i(jac_mat.rows(), jac_mat.cols());
216 for (int m = 0; m < jac_mat.rows(); ++m)
217 for (int l = 0; l < jac_mat.cols(); ++l)
218 grad_i(m, l) = -(reference_normals.row(n) * trafo)(m) * (jac_mat.transpose() * trafo)(l, k);
219 grad.push_back(grad_i);
224 Eigen::MatrixXd normalization_chain_rule = (normals.row(n).transpose() * normals.row(n));
225 normalization_chain_rule = Eigen::MatrixXd::Identity(dim, dim) - normalization_chain_rule;
226 normalization_chain_rule /= displaced_normal.norm();
228 Eigen::VectorXd vec(dim);
230 for (const auto &b : gvals.basis_values)
232 for (int d = 0; d < dim; ++d)
234 for (int k = 0; k < dim; ++k)
235 vec(k) = grad[k](d, b_idx);
236 vec = normalization_chain_rule * vec;
237 for (int k = 0; k < dim; ++k)
238 grad[k](d, b_idx) = vec(k);
244 grad_normal.push_back(grad);
247 Eigen::MatrixXd neumann_val;
248 rhs_assembler_.problem().neumann_bc(rhs_assembler_.mesh(), global_ids, uv, vals.val, normals, t, neumann_val);
250 Eigen::MatrixXd p, grad_p;
251 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, adjoint_zeroed, p, grad_p);
253 const Eigen::VectorXi geom_nodes = gbases[e].local_nodes_for_primitive(global_primitive_id, rhs_assembler_.mesh());
255 if (geom_nodes.size() != dim)
256 log_and_throw_error(
"Only linear geometry is supported in shape derivative!");
258 Eigen::VectorXd value = (p.array() * neumann_val.array()).rowwise().sum() * weights.array();
260 Eigen::VectorXd pressure_bc;
261 pressure_bc = (neumann_val.array() * normals.array()).rowwise().sum();
263 for (long n = 0; n < geom_nodes.size(); ++n)
265 const assembler::AssemblyValues &v = gvals.basis_values[geom_nodes(n)];
267 Eigen::MatrixXd velocity_div_mat;
269 if (rhs_assembler_.mesh().is_volume())
271 Eigen::MatrixXd V(3, 3);
272 V.row(0) = gbases[e].bases[geom_nodes(0)].global()[0].node;
273 V.row(1) = gbases[e].bases[geom_nodes(1)].global()[0].node;
274 V.row(2) = gbases[e].bases[geom_nodes(2)].global()[0].node;
276 velocity_div_mat = AdjointTools::face_velocity_divergence(V);
280 Eigen::MatrixXd V(2, 2);
281 V.row(0) = gbases[e].bases[geom_nodes(0)].global()[0].node;
282 V.row(1) = gbases[e].bases[geom_nodes(1)].global()[0].node;
284 velocity_div_mat = AdjointTools::edge_velocity_divergence(V);
289 for (int d = 0; d < dim; d++)
291 assert(v.global.size() == 1);
292 const int g_index = v.global[0].index * dim + d;
294 Eigen::MatrixXd gvals(v.val.size(), dim);
296 gvals.col(d) = v.val;
298 local_storage.vec(g_index) += value.sum() * velocity_div_mat(n, d);
299 const bool is_pressure = rhs_assembler_.problem().is_boundary_pressure(rhs_assembler_.mesh().get_boundary_id(global_primitive_id));
317 for (
const LocalThreadVecStorage &local_storage : storage)
318 term += local_storage.
vec;
322 if (actual_dim == dim)
325 hessian_wrt_u_prev(
x, t, hess);
326 if (hess.cols() == term.size())
327 term += hess.transpose() * adjoint_zeroed;