41 const Eigen::MatrixXd &
x,
42 const Eigen::MatrixXd &adjoint,
43 Eigen::VectorXd &term)
50 const int n_elements = int(bases.size());
51 term.setZero(n_verts * dim, 1);
58 for (
int e = start; e < end; ++e)
68 Eigen::MatrixXd p, grad_p;
71 Eigen::MatrixXd rhs_function;
74 for (
int q = 0; q <
vals.val.rows(); q++)
77 rhs_function.row(q) *= rho;
80 for (
int q = 0; q < local_storage.da.size(); ++q)
82 const double value = p.row(q).dot(rhs_function.row(q)) * local_storage.da(q);
83 for (
auto &v :
gvals.basis_values)
85 local_storage.vec.block(v.global[0].index * dim, 0, dim, 1) += value * v.grad_t_m.row(q).transpose();
93 Eigen::MatrixXd adjoint_zeroed = adjoint;
97 LocalThreadVecStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
99 Eigen::MatrixXd uv, points, normals;
100 Eigen::VectorXd weights;
101 Eigen::VectorXi global_ids;
102 assembler::ElementAssemblyValues vals, gvals;
104 for (int lb_id = start; lb_id < end; ++lb_id)
106 const auto &lb = form.local_neumann_boundary_[lb_id];
107 const int e = lb.element_id();
109 for (int i = 0; i < lb.size(); i++)
111 const int global_primitive_id = lb.global_primitive_id(i);
112 utils::BoundarySampler::boundary_quadrature(lb, form.n_boundary_samples_, form.rhs_assembler_.mesh(), i, false, uv, points, normals, weights);
113 global_ids.setConstant(points.rows(), global_primitive_id);
115 Eigen::MatrixXd reference_normals = normals;
117 vals.compute(e, form.rhs_assembler_.mesh().is_volume(), points, bases[e], gbases[e]);
118 gvals.compute(e, form.rhs_assembler_.mesh().is_volume(), points, gbases[e], gbases[e]);
120 std::vector<std::vector<Eigen::MatrixXd>> grad_normal;
121 for (int n = 0; n < gvals.jac_it.size(); ++n)
123 Eigen::MatrixXd trafo = gvals.jac_it[n].inverse();
125 Eigen::MatrixXd deform_mat(dim, dim);
126 deform_mat.setZero();
127 Eigen::MatrixXd jac_mat(dim, gvals.basis_values.size());
129 for (const auto &b : gvals.basis_values)
131 jac_mat.col(b_idx++) = b.grad.row(n);
133 for (const auto &g : b.global)
134 for (int d = 0; d < dim; ++d)
135 deform_mat.row(d) += x(g.index * dim + d) * b.grad.row(n);
139 trafo = trafo.inverse();
141 Eigen::VectorXd displaced_normal = normals.row(n) * trafo;
142 normals.row(n) = displaced_normal / displaced_normal.norm();
144 std::vector<Eigen::MatrixXd> grad;
146 Eigen::MatrixXd vec = -(jac_mat.transpose() * trafo * reference_normals.row(n).transpose());
148 for (int k = 0; k < dim; ++k)
150 Eigen::MatrixXd grad_i(jac_mat.rows(), jac_mat.cols());
152 for (int m = 0; m < jac_mat.rows(); ++m)
153 for (int l = 0; l < jac_mat.cols(); ++l)
154 grad_i(m, l) = -(reference_normals.row(n) * trafo)(m) * (jac_mat.transpose() * trafo)(l, k);
155 grad.push_back(grad_i);
160 Eigen::MatrixXd normalization_chain_rule = (normals.row(n).transpose() * normals.row(n));
161 normalization_chain_rule = Eigen::MatrixXd::Identity(dim, dim) - normalization_chain_rule;
162 normalization_chain_rule /= displaced_normal.norm();
164 Eigen::VectorXd vec(dim);
166 for (const auto &b : gvals.basis_values)
168 for (int d = 0; d < dim; ++d)
170 for (int k = 0; k < dim; ++k)
171 vec(k) = grad[k](d, b_idx);
172 vec = normalization_chain_rule * vec;
173 for (int k = 0; k < dim; ++k)
174 grad[k](d, b_idx) = vec(k);
180 grad_normal.push_back(grad);
183 Eigen::MatrixXd neumann_val;
184 form.rhs_assembler_.problem().neumann_bc(form.rhs_assembler_.mesh(), global_ids, uv, vals.val, normals, t, neumann_val);
186 Eigen::MatrixXd p, grad_p;
187 io::Evaluator::interpolate_at_local_vals(e, dim, actual_dim, vals, adjoint_zeroed, p, grad_p);
189 const Eigen::VectorXi geom_nodes = gbases[e].local_nodes_for_primitive(global_primitive_id, form.rhs_assembler_.mesh());
191 if (geom_nodes.size() != dim)
192 log_and_throw_error(
"Only linear geometry is supported in shape derivative!");
194 Eigen::VectorXd value = (p.array() * neumann_val.array()).rowwise().sum() * weights.array();
196 Eigen::VectorXd pressure_bc;
197 pressure_bc = (neumann_val.array() * normals.array()).rowwise().sum();
199 for (long n = 0; n < geom_nodes.size(); ++n)
201 const assembler::AssemblyValues &v = gvals.basis_values[geom_nodes(n)];
203 Eigen::MatrixXd velocity_div_mat;
205 if (form.rhs_assembler_.mesh().is_volume())
207 Eigen::MatrixXd V(3, 3);
208 V.row(0) = gbases[e].bases[geom_nodes(0)].global()[0].node;
209 V.row(1) = gbases[e].bases[geom_nodes(1)].global()[0].node;
210 V.row(2) = gbases[e].bases[geom_nodes(2)].global()[0].node;
212 velocity_div_mat = AdjointTools::face_velocity_divergence(V);
216 Eigen::MatrixXd V(2, 2);
217 V.row(0) = gbases[e].bases[geom_nodes(0)].global()[0].node;
218 V.row(1) = gbases[e].bases[geom_nodes(1)].global()[0].node;
220 velocity_div_mat = AdjointTools::edge_velocity_divergence(V);
225 for (int d = 0; d < dim; d++)
227 assert(v.global.size() == 1);
228 const int g_index = v.global[0].index * dim + d;
230 Eigen::MatrixXd gvals(v.val.size(), dim);
232 gvals.col(d) = v.val;
234 local_storage.vec(g_index) += value.sum() * velocity_div_mat(n, d);
235 const bool is_pressure = form.rhs_assembler_.problem().is_boundary_pressure(form.rhs_assembler_.mesh().get_boundary_id(global_primitive_id));
253 for (
const LocalThreadVecStorage &local_storage : storage)
254 term += local_storage.
vec;
258 if (actual_dim == dim)
261 form.hessian_wrt_u_prev(
x, t, hess);
262 if (hess.cols() == term.size())
263 term += hess.transpose() * adjoint_zeroed;
static void force_shape_derivative(BodyForm &form, const int n_verts, const double t, const Eigen::MatrixXd &x, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &term)