Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 33 additions & 20 deletions examples/contact/homotopy/two_blocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ class TiedContactProblem : public EqualityConstrainedHomotopyProblem {
std::shared_ptr<smith::ContactConstraint> constraints, mfem::Array<int> fixed_tdof_list,
mfem::Array<int> disp_tdof_list, mfem::Vector uDC);
mfem::Vector residual(const mfem::Vector& u, bool fresh_evaluation) const;
mfem::HypreParMatrix* residualJacobian(const mfem::Vector& u, bool fresh_evaluation);
mfem::HypreParMatrix* residualJacobian(const mfem::Vector& u, bool fresh_evaluation, bool fresh_derivative);
mfem::Vector constraint(const mfem::Vector& u, bool fresh_evaluation) const;
mfem::HypreParMatrix* constraintJacobian(const mfem::Vector& u, bool fresh_evaluation);
mfem::Vector constraintJacobianTvp(const mfem::Vector& u, const mfem::Vector& l, bool fresh_evaluation) const;
mfem::HypreParMatrix* constraintJacobian(const mfem::Vector& u, bool fresh_evaluation, bool fresh_derivative);
mfem::Vector constraintJacobianTvp(const mfem::Vector& u, const mfem::Vector& l, bool fresh_evaluation,
bool fresh_derivative) const;
void fullDisplacement(const mfem::Vector& x, mfem::Vector& u);
virtual ~TiedContactProblem();
};
Expand Down Expand Up @@ -290,7 +291,8 @@ int main(int argc, char* argv[])
SLIC_WARNING_ROOT_IF(!converged, "Homotopy solver did not converge");

// visualize
auto writer = createParaviewOutput(mesh->mfemParMesh(), smith::getConstFieldPointers(states), "contact");
auto writer =
createParaviewOutput(mesh->mfemParMesh(), smith::getConstFieldPointers(states), "two_block_tiedcontact_plot");
if (visualize) {
mfem::Vector u(states[FIELD::DISP].space().GetTrueVSize());
u = problem.GetDisplacement(X0);
Expand Down Expand Up @@ -349,25 +351,31 @@ TiedContactProblem<SolidWeakFormType>::TiedContactProblem(std::vector<smith::Fin
template <typename SolidWeakFormType>
mfem::Vector TiedContactProblem<SolidWeakFormType>::residual(const mfem::Vector& u, bool /*fresh_evaluation*/) const
{
// TODO: cache this evaluation
residual_states_[FIELD::DISP]->Set(1.0, u);
auto res = weak_form_->residual(time_info_, shape_disp_.get(), smith::getConstFieldPointers(residual_states_));
return res;
};

template <typename SolidWeakFormType>
mfem::HypreParMatrix* TiedContactProblem<SolidWeakFormType>::residualJacobian(const mfem::Vector& u,
bool /*fresh_evaluation*/)
bool fresh_evaluation,
bool fresh_derivative)
{
residual_states_[FIELD::DISP]->Set(1.0, u);
drdu_ = weak_form_->jacobian(time_info_, shape_disp_.get(), smith::getConstFieldPointers(residual_states_),
jacobian_weights_);
if (fresh_evaluation || fresh_derivative) {
residual_states_[FIELD::DISP]->Set(1.0, u);
drdu_ = weak_form_->jacobian(time_info_, shape_disp_.get(), smith::getConstFieldPointers(residual_states_),
jacobian_weights_);
} else {
SLIC_ERROR_ROOT_IF(!drdu_, "must call evaluation method prior to using cached data");
}
return drdu_.get();
}

template <typename SolidWeakFormType>
mfem::Vector TiedContactProblem<SolidWeakFormType>::constraint(const mfem::Vector& u, bool /*fresh_evaluation*/) const
mfem::Vector TiedContactProblem<SolidWeakFormType>::constraint(const mfem::Vector& u, bool fresh_evaluation) const
{
bool fresh_evaluation = true;
// No caching necessary as that is already done in ContactConstraint::evaluate
contact_states_[smith::ContactFields::DISP]->Set(1.0, u);
auto gap = constraints_->evaluate(time_info_.time(), time_info_.dt(), smith::getConstFieldPointers(contact_states_),
fresh_evaluation);
Expand All @@ -376,24 +384,29 @@ mfem::Vector TiedContactProblem<SolidWeakFormType>::constraint(const mfem::Vecto

template <typename SolidWeakFormType>
mfem::HypreParMatrix* TiedContactProblem<SolidWeakFormType>::constraintJacobian(const mfem::Vector& u,
bool /*fresh_evaluation*/)
bool fresh_evaluation,
bool fresh_derivative)
{
bool fresh_evaluation = true;
contact_states_[smith::ContactFields::DISP]->Set(1.0, u);
dcdu_ = constraints_->jacobian(time_info_.time(), time_info_.dt(), smith::getConstFieldPointers(contact_states_),
smith::ContactFields::DISP, fresh_evaluation);
if (fresh_evaluation || fresh_derivative) {
contact_states_[smith::ContactFields::DISP]->Set(1.0, u);
dcdu_ = constraints_->jacobian(time_info_.time(), time_info_.dt(), smith::getConstFieldPointers(contact_states_),
smith::ContactFields::DISP, fresh_evaluation, fresh_derivative);
} else {
SLIC_ERROR_ROOT_IF(!dcdu_, "must call evaluation method prior to using cached data");
}
return dcdu_.get();
}

template <typename SolidWeakFormType>
mfem::Vector TiedContactProblem<SolidWeakFormType>::constraintJacobianTvp(const mfem::Vector& u, const mfem::Vector& l,
bool /*fresh_evaluation*/) const
bool fresh_evaluation,
bool fresh_derivative) const
{
bool fresh_evaluation = true;
// internal caching done in ContactConstraint::residual_contribution
contact_states_[smith::ContactFields::DISP]->Set(1.0, u);
auto res_contribution = constraints_->residual_contribution(time_info_.time(), time_info_.dt(),
smith::getConstFieldPointers(contact_states_), l,
smith::ContactFields::DISP, fresh_evaluation);
auto res_contribution = constraints_->residual_contribution(
time_info_.time(), time_info_.dt(), smith::getConstFieldPointers(contact_states_), l, smith::ContactFields::DISP,
fresh_evaluation, fresh_derivative);
return res_contribution;
}

Expand Down
25 changes: 14 additions & 11 deletions examples/inertia_relief/inertia_relief_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,11 @@ class InertialReliefProblem : public EqualityConstrainedHomotopyProblem {
std::shared_ptr<smith::Mesh> mesh, std::shared_ptr<SolidWeakFormT> weak_form,
std::vector<std::shared_ptr<smith::ScalarObjective>> constraints);
mfem::Vector residual(const mfem::Vector& u, bool fresh_evaluation) const;
mfem::Vector constraintJacobianTvp(const mfem::Vector& u, const mfem::Vector& l, bool fresh_evaluation) const;
mfem::Vector constraintJacobianTvp(const mfem::Vector& u, const mfem::Vector& l, bool fresh_evaluation,
bool fresh_derivative) const;
mfem::Vector constraint(const mfem::Vector& u, bool fresh_evaluation) const;
mfem::HypreParMatrix* constraintJacobian(const mfem::Vector& u, bool fresh_evaluation);
mfem::HypreParMatrix* residualJacobian(const mfem::Vector& u, bool fresh_evaluation);
mfem::HypreParMatrix* constraintJacobian(const mfem::Vector& u, bool fresh_evaluation, bool fresh_derivative);
mfem::HypreParMatrix* residualJacobian(const mfem::Vector& u, bool fresh_evaluation, bool fresh_derivative);
virtual ~InertialReliefProblem();
};

Expand Down Expand Up @@ -362,9 +363,9 @@ mfem::Vector InertialReliefProblem::residual(const mfem::Vector& u, bool fresh_e

// constraint Jacobian transpose vector product
mfem::Vector InertialReliefProblem::constraintJacobianTvp(const mfem::Vector& u, const mfem::Vector& l,
bool fresh_evaluation) const
bool fresh_evaluation, bool fresh_derivative) const
{
if (fresh_evaluation) {
if (fresh_evaluation || fresh_derivative) {
int dim_constraints = GetMultiplierDim();
int dim_displacement = GetDisplacementDim();
obj_states_[FIELD::DISP]->Set(1.0, u);
Expand All @@ -389,9 +390,10 @@ mfem::Vector InertialReliefProblem::constraintJacobianTvp(const mfem::Vector& u,
}

// Jacobian of the residual
mfem::HypreParMatrix* InertialReliefProblem::residualJacobian(const mfem::Vector& u, bool fresh_evaluation)
mfem::HypreParMatrix* InertialReliefProblem::residualJacobian(const mfem::Vector& u, bool fresh_evaluation,
bool fresh_derivative)
{
if (fresh_evaluation) {
if (fresh_evaluation || fresh_derivative) {
obj_states_[FIELD::DISP]->Set(1.0, u);
drdu_.reset();
drdu_ = weak_form_->jacobian(time_info_, shape_disp_.get(), getConstFieldPointers(all_states_), jacobian_weights_);
Expand Down Expand Up @@ -425,11 +427,12 @@ mfem::Vector InertialReliefProblem::constraint(const mfem::Vector& u, bool fresh
}

// Jacobian of the constraint
mfem::HypreParMatrix* InertialReliefProblem::constraintJacobian(const mfem::Vector& u, bool fresh_evaluation)
mfem::HypreParMatrix* InertialReliefProblem::constraintJacobian(const mfem::Vector& u, bool fresh_evaluation,
bool fresh_derivative)
{
int dim_constraints = GetMultiplierDim();
int glbdim_displacement = GetGlobalDisplacementDim();
if (fresh_evaluation) {
if (fresh_evaluation || fresh_derivative) {
int dim_constraints = GetMultiplierDim();
int glbdim_displacement = GetGlobalDisplacementDim();
obj_states_[FIELD::DISP]->Set(1.0, u);
// dense rows
int nentries = glbdim_displacement;
Expand Down
24 changes: 18 additions & 6 deletions src/smith/physics/constraint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,14 @@ class Constraint {
* @param fields vector of smith::FiniteElementState*
* @param direction index for which field to take the gradient with respect to
* @param fresh_evaluation boolean indicating if we re-evaluate or use previously cached evaluation
* @param fresh_derivative boolean indicating with fresh_evaluation if we re-evaluate or use previously cached
* evaluation
* @return std::unique_ptr<mfem::HypreParMatrix>
*/
virtual std::unique_ptr<mfem::HypreParMatrix> jacobian(double time, double dt,
const std::vector<ConstFieldPtr>& fields, int direction,
bool fresh_evaluation = true) const = 0;
bool fresh_evaluation = true,
bool fresh_derivative = true) const = 0;

/** @brief Virtual interface for computing constraint Jacobian_tilde from a vector of smith::FiniteElementState*
* Jacobian_tilde is an optional approximation of the true Jacobian
Expand All @@ -68,13 +71,16 @@ class Constraint {
* @param fields vector of smith::FiniteElementState*
* @param direction index for which field to take the gradient with respect to
* @param fresh_evaluation boolean indicating if we re-evaluate or use previously cached evaluation
* @param fresh_derivative boolean indicating with fresh_evaluation if we re-evaluate or use previously cached
* evaluation
* @return std::unique_ptr<mfem::HypreParMatrix>
*/
virtual std::unique_ptr<mfem::HypreParMatrix> jacobian_tilde(double time, double dt,
const std::vector<ConstFieldPtr>& fields, int direction,
bool fresh_evaluation = true) const
bool fresh_evaluation = true,
bool fresh_derivative = true) const
{
return jacobian(time, dt, fields, direction, fresh_evaluation);
return jacobian(time, dt, fields, direction, fresh_evaluation, fresh_derivative);
};

/** @brief Virtual interface for computing residual contribution Jacobian_tilde^(Transpose) * (Lagrange multiplier)
Expand All @@ -86,13 +92,16 @@ class Constraint {
* @param multipliers mfem::Vector of Lagrange multipliers
* @param direction index for which field to take the gradient with respect to
* @param fresh_evaluation boolean indicating if we re-evaluate or use previously cached evaluation
* @param fresh_derivative boolean indicating with fresh_evaluation if we re-evaluate or use previously cached
* evaluation
* @return std::Vector
*/
virtual mfem::Vector residual_contribution(double time, double dt, const std::vector<ConstFieldPtr>& fields,
const mfem::Vector& multipliers, int direction,
bool fresh_evaluation = true) const
bool fresh_evaluation = true, bool fresh_derivative = true) const
{
std::unique_ptr<mfem::HypreParMatrix> jac = jacobian_tilde(time, dt, fields, direction, fresh_evaluation);
std::unique_ptr<mfem::HypreParMatrix> jac =
jacobian_tilde(time, dt, fields, direction, fresh_evaluation, fresh_derivative);
mfem::Vector y(jac->Width());
y = 0.0;
SLIC_ERROR_ROOT_IF(jac->Height() != multipliers.Size(), "Incompatible matrix and vector sizes.");
Expand All @@ -109,12 +118,15 @@ class Constraint {
* @param multipliers mfem::Vector of Lagrange multipliers
* @param direction index for which field to take the gradient with respect to
* @param fresh_evaluation boolean indicating if we re-evaluate or use previously cached evaluation
* @param fresh_derivative boolean indicating with fresh_evaluation if we re-evaluate or use previously cached
* evaluation
* @return std::unique_ptr<mfem::HypreParMatrix>
*/
virtual std::unique_ptr<mfem::HypreParMatrix> residual_contribution_jacobian(
[[maybe_unused]] double time, [[maybe_unused]] double dt,
[[maybe_unused]] const std::vector<ConstFieldPtr>& fields, [[maybe_unused]] const mfem::Vector& multipliers,
[[maybe_unused]] int direction, [[maybe_unused]] bool fresh_evaluation = true) const
[[maybe_unused]] int direction, [[maybe_unused]] bool fresh_evaluation = true,
[[maybe_unused]] bool fresh_derivative = true) const
{
SLIC_ERROR_ROOT(axom::fmt::format("Base class must override residual_contribution_jacobian before usage"));
std::unique_ptr<mfem::HypreParMatrix> res_contr_jacobian = nullptr;
Expand Down
Loading