122 const int n_elements = int(bases.size());
123 term.setZero(n_verts * dim, 1);
130 for (
int e = start; e < end; ++e)
140 Eigen::MatrixXd p, grad_p;
143 Eigen::MatrixXd rhs_function;
146 for (
int q = 0; q <
vals.val.rows(); q++)
149 rhs_function.row(q) *= rho;
152 for (
int q = 0; q < local_storage.da.size(); ++q)
154 const double value = p.row(q).dot(rhs_function.row(q)) * local_storage.da(q);
155 for (
auto &v :
gvals.basis_values)
157 local_storage.vec.block(v.global[0].index * dim, 0, dim, 1) +=
value * v.grad_t_m.row(q).transpose();
165 Eigen::MatrixXd adjoint_zeroed = adjoint;
169 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
171 Eigen::MatrixXd uv, points, normals;
172 Eigen::VectorXd weights;
173 Eigen::VectorXi global_ids;
174 assembler::ElementAssemblyValues vals, gvals;
176 for (int lb_id = start; lb_id < end; ++lb_id)
178 const auto &lb = local_neumann_boundary_[lb_id];
179 const int e = lb.element_id();
181 for (int i = 0; i < lb.size(); i++)
183 const int global_primitive_id = lb.global_primitive_id(i);
185 utils::BoundarySampler::boundary_quadrature(lb, n_boundary_samples_, rhs_assembler_.mesh(), i, false, uv, points, normals, weights);
186 global_ids.setConstant(points.rows(), global_primitive_id);
188 Eigen::MatrixXd reference_normals = normals;
190 vals.compute(e, rhs_assembler_.mesh().is_volume(), points, bases[e], gbases[e]);
191 gvals.compute(e, rhs_assembler_.mesh().is_volume(), points, gbases[e], gbases[e]);
193 std::vector<std::vector<Eigen::MatrixXd>> grad_normal;
194 for (int n = 0; n < gvals.jac_it.size(); ++n)
196 Eigen::MatrixXd trafo = gvals.jac_it[n].inverse();
198 Eigen::MatrixXd deform_mat(dim, dim);
199 deform_mat.setZero();
200 Eigen::MatrixXd jac_mat(dim, gvals.basis_values.size());
202 for (const auto &b : gvals.basis_values)
204 jac_mat.col(b_idx++) = b.grad.row(n);
206 for (const auto &g : b.global)
207 for (int d = 0; d < dim; ++d)
208 deform_mat.row(d) += x(g.index * dim + d) * b.grad.row(n);
212 trafo = trafo.inverse();
214 Eigen::VectorXd displaced_normal = normals.row(n) * trafo;
215 normals.row(n) = displaced_normal / displaced_normal.norm();
217 std::vector<Eigen::MatrixXd> grad;
219 Eigen::MatrixXd vec = -(jac_mat.transpose() * trafo * reference_normals.row(n).transpose());
221 for (int k = 0; k < dim; ++k)
223 Eigen::MatrixXd grad_i(jac_mat.rows(), jac_mat.cols());
225 for (int m = 0; m < jac_mat.rows(); ++m)
226 for (int l = 0; l < jac_mat.cols(); ++l)
227 grad_i(m, l) = -(reference_normals.row(n) * trafo)(m) * (jac_mat.transpose() * trafo)(l, k);
228 grad.push_back(grad_i);
233 Eigen::MatrixXd normalization_chain_rule = (normals.row(n).transpose() * normals.row(n));
234 normalization_chain_rule = Eigen::MatrixXd::Identity(dim, dim) - normalization_chain_rule;
235 normalization_chain_rule /= displaced_normal.norm();
237 Eigen::VectorXd vec(dim);
239 for (const auto &b : gvals.basis_values)
241 for (int d = 0; d < dim; ++d)
243 for (int k = 0; k < dim; ++k)
244 vec(k) = grad[k](d, b_idx);
245 vec = normalization_chain_rule * vec;
246 for (int k = 0; k < dim; ++k)
247 grad[k](d, b_idx) = vec(k);
253 grad_normal.push_back(grad);
256 Eigen::MatrixXd neumann_val;
257 rhs_assembler_.problem().neumann_bc(rhs_assembler_.mesh(), global_ids, uv, vals.val, normals, t, neumann_val);
259 Eigen::MatrixXd p, grad_p;
260 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, adjoint_zeroed, p, grad_p);
262 const Eigen::VectorXi geom_nodes = gbases[e].local_nodes_for_primitive(global_primitive_id, rhs_assembler_.mesh());
264 if (geom_nodes.size() != dim)
265 log_and_throw_error(
"Only linear geometry is supported in shape derivative!");
267 Eigen::VectorXd value = (p.array() * neumann_val.array()).rowwise().sum() * weights.array();
269 Eigen::VectorXd pressure_bc;
270 pressure_bc = (neumann_val.array() * normals.array()).rowwise().sum();
272 for (long n = 0; n < geom_nodes.size(); ++n)
274 const assembler::AssemblyValues &v = gvals.basis_values[geom_nodes(n)];
276 Eigen::MatrixXd velocity_div_mat;
278 if (rhs_assembler_.mesh().is_volume())
280 Eigen::MatrixXd V(3, 3);
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;
283 V.row(2) = gbases[e].bases[geom_nodes(2)].global()[0].node;
285 velocity_div_mat = AdjointTools::face_velocity_divergence(V);
289 Eigen::MatrixXd V(2, 2);
290 V.row(0) = gbases[e].bases[geom_nodes(0)].global()[0].node;
291 V.row(1) = gbases[e].bases[geom_nodes(1)].global()[0].node;
293 velocity_div_mat = AdjointTools::edge_velocity_divergence(V);
298 for (int d = 0; d < dim; d++)
300 assert(v.global.size() == 1);
301 const int g_index = v.global[0].index * dim + d;
303 Eigen::MatrixXd gvals(v.val.size(), dim);
305 gvals.col(d) = v.val;
307 local_storage.vec(g_index) += value.sum() * velocity_div_mat(n, d);
308 const bool is_pressure = rhs_assembler_.problem().is_boundary_pressure(rhs_assembler_.mesh().get_boundary_id(global_primitive_id));
326 for (
const LocalThreadVecStorage &local_storage : storage)
327 term += local_storage.
vec;
331 if (actual_dim == dim)
334 hessian_wrt_u_prev(
x, t, hess);
335 if (hess.cols() == term.size())
336 term += hess.transpose() * adjoint_zeroed;