19 bool delta(
int i,
int j)
21 return (i == j) ? true :
false;
24 double dot(
const Eigen::MatrixXd &A,
const Eigen::MatrixXd &B) {
return (A.array() * B.array()).sum(); }
26 class LocalThreadScalarStorage
33 LocalThreadScalarStorage()
39 class LocalThreadVecStorage
46 LocalThreadVecStorage(
const int size)
85 return Eigen::VectorXd::Zero(state.
ndof());
101 j.
set_j([formulation,
this](
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &grad_u,
const Eigen::VectorXd &lambda,
const Eigen::VectorXd &mu,
const Eigen::MatrixXd &reference_normals,
const assembler::ElementAssemblyValues &
vals,
const IntegrableFunctional::ParameterType ¶ms, Eigen::MatrixXd &
val) {
102 val.setZero(grad_u.rows(), 1);
103 const int dim = u.cols();
104 Eigen::MatrixXd grad_u_q;
105 for (
int q = 0; q < grad_u.rows(); q++)
108 if (formulation ==
"LinearElasticity")
110 grad_u_q = (grad_u_q + grad_u_q.transpose()).eval() / 2.;
111 val(q) = mu(q) * (grad_u_q.transpose() * grad_u_q).trace() + lambda(q) / 2. * grad_u_q.trace() * grad_u_q.trace();
113 else if (formulation ==
"NeoHookean")
115 Eigen::MatrixXd def_grad = grad_u_q + Eigen::MatrixXd::Identity(dim, dim);
116 double log_det_j = log(def_grad.determinant());
117 val(q) = mu(q) / 2 * ((def_grad.transpose() * def_grad).trace() - dim - 2 * log_det_j) + lambda(q) / 2 * log_det_j * log_det_j;
124 j.
set_dj_dgradu([formulation,
this](
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &grad_u,
const Eigen::VectorXd &lambda,
const Eigen::VectorXd &mu,
const Eigen::MatrixXd &reference_normals,
const assembler::ElementAssemblyValues &
vals,
const IntegrableFunctional::ParameterType ¶ms, Eigen::MatrixXd &
val) {
125 val.setZero(grad_u.rows(), grad_u.cols());
126 Eigen::MatrixXd grad_u_q, def_grad, FmT, stress;
127 for (
int q = 0; q < grad_u.rows(); q++)
130 if (formulation ==
"LinearElasticity")
132 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
134 else if (formulation ==
"NeoHookean")
136 def_grad = Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols()) + grad_u_q;
137 FmT = def_grad.inverse().transpose();
138 stress = mu(q) * (def_grad - FmT) + lambda(q) * std::log(def_grad.determinant()) * FmT;
154 return Eigen::VectorXd::Zero(0).eval();
165 j.
set_j([formulation, power, &state = std::as_const(
state_)](
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &grad_u,
const Eigen::VectorXd &lambda,
const Eigen::VectorXd &mu,
const Eigen::MatrixXd &reference_normals,
const assembler::ElementAssemblyValues &
vals,
const IntegrableFunctional::ParameterType ¶ms, Eigen::MatrixXd &
val) {
166 val.setZero(grad_u.rows(), 1);
167 const double dt = state.problem->is_time_dependent() ? state.args[
"time"][
"dt"].get<
double>() : 0;
169 Eigen::MatrixXd grad_u_q, stress, grad_unused;
170 for (
int q = 0; q < grad_u.rows(); q++)
172 if (formulation ==
"Laplacian")
173 stress = grad_u.row(q);
177 state.assembler->compute_stress_grad_multiply_mat(
OptAssemblerData(params.
t, dt, params.
elem, local_pts.row(q), pts.row(q), grad_u_q), Eigen::MatrixXd::Zero(grad_u_q.rows(), grad_u_q.cols()), stress, grad_unused);
179 val(q) = pow(stress.squaredNorm(), power / 2.);
183 j.
set_dj_dgradu([formulation, power, &state = std::as_const(
state_)](
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &grad_u,
const Eigen::VectorXd &lambda,
const Eigen::VectorXd &mu,
const Eigen::MatrixXd &reference_normals,
const assembler::ElementAssemblyValues &
vals,
const IntegrableFunctional::ParameterType ¶ms, Eigen::MatrixXd &
val) {
184 val.setZero(grad_u.rows(), grad_u.cols());
185 const double dt = state.problem->is_time_dependent() ? state.args[
"time"][
"dt"].get<
double>() : 0;
186 const int dim = state.mesh->dimension();
188 if (formulation ==
"Laplacian")
190 for (
int q = 0; q < grad_u.rows(); q++)
192 const double coef = power * pow(grad_u.row(q).squaredNorm(), power / 2. - 1.);
193 val.row(q) = coef * grad_u.row(q);
198 Eigen::MatrixXd grad_u_q, stress, stress_dstress;
199 for (
int q = 0; q < grad_u.rows(); q++)
202 state.assembler->compute_stress_grad_multiply_stress(
OptAssemblerData(params.
t, dt, params.
elem, local_pts.row(q), pts.row(q), grad_u_q), stress, stress_dstress);
204 const double coef = power * pow(stress.squaredNorm(), power / 2. - 1.);
218 return Eigen::VectorXd::Zero(0).eval();
230 val.setZero(grad_u.rows(), 1);
232 Eigen::MatrixXd grad_u_q, stress;
233 for (
int q = 0; q < grad_u.rows(); q++)
236 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
237 val(q) = (stress.array() * grad_u_q.array()).sum();
242 val.setZero(grad_u.rows(), grad_u.cols());
243 const int dim = u.cols();
245 Eigen::MatrixXd grad_u_q, stress;
246 for (
int q = 0; q < grad_u.rows(); q++)
249 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
260 const double t =
state_.
problem->is_time_dependent() ? dt * time_step +
state_.
args[
"time"][
"t0"].get<
double>() : 0;
265 Eigen::VectorXd term = Eigen::VectorXd::Zero(bases.size() * 2);
268 for (
int e = 0; e < bases.size(); e++)
276 Eigen::MatrixXd u, grad_u;
279 Eigen::MatrixXd grad_u_q;
288 Eigen::MatrixXd f_prime_dmu, f_prime_dlambda;
291 term(e + bases.size()) += dot(f_prime_dmu, grad_u_q) *
da(q);
292 term(e) += dot(f_prime_dlambda, grad_u_q) *
da(q);
302 const int dim =
dim_;
305 val = u.col(dim) + pts.col(dim);
309 val.setZero(u.rows(), u.cols());
310 val.col(dim).setOnes();
314 val.setZero(pts.rows(), pts.cols());
315 val.col(dim).setOnes();
324 const int dim = this->
dim_;
326 j.
set_j([dim, &state = std::as_const(this->
state_)](
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &grad_u,
const Eigen::VectorXd &lambda,
const Eigen::VectorXd &mu,
const Eigen::MatrixXd &reference_normals,
const assembler::ElementAssemblyValues &
vals,
const IntegrableFunctional::ParameterType ¶ms, Eigen::MatrixXd &
val) {
327 Eigen::MatrixXd acc, grad_acc;
333 j.
set_dj_du([dim,
this](
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &grad_u,
const Eigen::VectorXd &lambda,
const Eigen::VectorXd &mu,
const Eigen::MatrixXd &reference_normals,
const assembler::ElementAssemblyValues &
vals,
const IntegrableFunctional::ParameterType ¶ms, Eigen::MatrixXd &
val) {
334 val.setZero(u.rows(), u.cols());
346 Eigen::MatrixXd v, grad_v;
349 val.setZero(u.rows(), 1);
350 for (
int q = 0; q < v.rows(); q++)
353 val(q) = 0.5 * rho * v.row(q).squaredNorm();
358 val.setZero(u.rows(), u.cols());
371 return Eigen::VectorXd::Zero(0).eval();
382 j.
set_j([formulation, dimensions,
this](
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &grad_u,
const Eigen::VectorXd &lambda,
const Eigen::VectorXd &mu,
const Eigen::MatrixXd &reference_normals,
const assembler::ElementAssemblyValues &
vals,
const IntegrableFunctional::ParameterType ¶ms, Eigen::MatrixXd &
val) {
383 val.setZero(grad_u.rows(), 1);
385 Eigen::MatrixXd grad_u_q, stress;
386 for (
int q = 0; q < grad_u.rows(); q++)
389 if (formulation ==
"LinearElasticity")
391 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
393 else if (formulation ==
"NeoHookean")
395 Eigen::MatrixXd def_grad = Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols()) + grad_u_q;
396 Eigen::MatrixXd FmT = def_grad.inverse().transpose();
397 stress = mu(q) * (def_grad - FmT) + lambda(q) * std::log(def_grad.determinant()) * FmT;
401 val(q) = stress(dimensions[0], dimensions[1]);
405 j.
set_dj_dgradu([formulation, dimensions,
this](
const Eigen::MatrixXd &local_pts,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &u,
const Eigen::MatrixXd &grad_u,
const Eigen::VectorXd &lambda,
const Eigen::VectorXd &mu,
const Eigen::MatrixXd &reference_normals,
const assembler::ElementAssemblyValues &
vals,
const IntegrableFunctional::ParameterType ¶ms, Eigen::MatrixXd &
val) {
406 val.setZero(grad_u.rows(), grad_u.cols());
409 Eigen::MatrixXd grad_u_q, stiffness, stress;
410 for (
int q = 0; q < grad_u.rows(); q++)
412 stiffness.setZero(1, dim * dim * dim * dim);
415 if (formulation ==
"LinearElasticity")
417 stress = mu(q) * (grad_u_q + grad_u_q.transpose()) + lambda(q) * grad_u_q.trace() * Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols());
418 for (
int i = 0, idx = 0; i < dim; i++)
419 for (
int j = 0; j < dim; j++)
420 for (
int k = 0; k < dim; k++)
421 for (
int l = 0; l < dim; l++)
423 stiffness(idx++) = mu(q) * delta(i, k) * delta(j, l) + mu(q) * delta(i, l) * delta(j, k) + lambda(q) * delta(i, j) * delta(k, l);
426 else if (formulation ==
"NeoHookean")
428 Eigen::MatrixXd def_grad = Eigen::MatrixXd::Identity(grad_u_q.rows(), grad_u_q.cols()) + grad_u_q;
429 Eigen::MatrixXd FmT = def_grad.inverse().transpose();
430 stress = mu(q) * (def_grad - FmT) + lambda(q) * std::log(def_grad.determinant()) * FmT;
432 double J = def_grad.determinant();
433 double tmp1 = mu(q) - lambda(q) * std::log(J);
434 for (
int i = 0, idx = 0; i < dim; i++)
435 for (
int j = 0; j < dim; j++)
436 for (
int k = 0; k < dim; k++)
437 for (
int l = 0; l < dim; l++)
439 stiffness(idx++) = mu(q) * delta(i, k) * delta(j, l) + tmp1 * FmT(i, l) * FmT(k, j);
441 stiffness += lambda(q) *
utils::flatten(FmT_vec * FmT_vec.transpose()).transpose();
446 val.row(q) = stiffness.block(0, (dimensions[0] * dim + dimensions[1]) * dim * dim, 1, dim * dim);
458 val.setOnes(grad_u.rows(), 1);
ElementAssemblyValues vals
void set_dj_du(const functionalType &dj_du)
void set_dj_dgradu(const functionalType &dj_dgradu)
void set_j(const functionalType &j)
void set_dj_dx(const functionalType &dj_dx)
main class that contains the polyfem solver and all its state
std::string formulation() const
return the formulation (checks if the problem is scalar or not and deals with multiphysics)
assembler::AssemblyValsCache ass_vals_cache
used to store assembly values for small problems
const std::vector< basis::ElementBases > & geom_bases() const
Get a constant reference to the geometry mapping bases.
std::shared_ptr< assembler::Assembler > assembler
assemblers
std::shared_ptr< assembler::Mass > mass_matrix_assembler
std::vector< int > primitive_to_node() const
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
json args
main input arguments containing all defaults
solver::DiffCache diff_cached
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
solver::SolveData solve_data
timedependent stuff cached
void compute(const int el_index, const bool is_volume, const basis::ElementBases &basis, const basis::ElementBases &gbasis, ElementAssemblyValues &vals) const
retrieves cached basis evaluation and geometric for the given element if it doesn't exist,...
stores per element basis values at given quadrature points and geometric mapping
quadrature::Quadrature quadrature
static void interpolate_at_local_vals(const mesh::Mesh &mesh, const bool is_problem_scalar, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const int el_index, const Eigen::MatrixXd &local_pts, const Eigen::MatrixXd &fun, Eigen::MatrixXd &result, Eigen::MatrixXd &result_grad)
interpolate solution and gradient at element (calls interpolate_at_local_vals with sol)
Eigen::MatrixXd disp_grad(int step=0) const
Eigen::VectorXd v(int step) const
Eigen::VectorXd u(int step) const
TVector reduced_to_full_shape_derivative(const Eigen::MatrixXd &disp_grad, const TVector &adjoint_full) const
std::shared_ptr< solver::NLProblem > nl_problem
virtual Eigen::VectorXd apply_parametrization_jacobian(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, const std::function< Eigen::VectorXd()> &grad) const
Maps the partial gradient wrt.
void vector2matrix(const Eigen::VectorXd &vec, Eigen::MatrixXd &mat)
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, MAX_QUAD_POINTS, 1 > QuadratureVector
void log_and_throw_adjoint_error(const std::string &msg)
Parameters for the functional evaluation.