From 97ea44914f8a8ef303bc32c3df1ea174d5ab0262 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Wed, 20 Nov 2024 13:07:25 -0800 Subject: [PATCH 01/27] Resolving build conflicts. --- src/serac/physics/solid_mechanics.cpp | 6 +- src/serac/physics/solid_mechanics.hpp | 70 +++--- src/serac/physics/solid_mechanics_contact.hpp | 54 +++++ src/serac/physics/tests/CMakeLists.txt | 2 +- .../physics/tests/contact_solid_adjoint.cpp | 212 ++++++++++++++++++ tests | 2 +- 6 files changed, 315 insertions(+), 31 deletions(-) create mode 100644 src/serac/physics/tests/contact_solid_adjoint.cpp diff --git a/src/serac/physics/solid_mechanics.cpp b/src/serac/physics/solid_mechanics.cpp index ac1b34df79..9001d7b4ea 100644 --- a/src/serac/physics/solid_mechanics.cpp +++ b/src/serac/physics/solid_mechanics.cpp @@ -17,7 +17,7 @@ void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, mfem::HypreParVector& accel_adjoint_load_vector, mfem::HypreParVector& adjoint_displacement_, mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, - mfem::HypreParVector& adjoint_essential, BoundaryConditionManager& bcs_, + BoundaryConditionManager& bcs_, mfem::Solver& lin_solver) { // there are hard-coded here for now @@ -39,6 +39,10 @@ void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, // recall that temperature_adjoint_load_vector and d_temperature_dt_adjoint_load_vector were already multiplied by // -1 above + // By default, use a homogeneous essential boundary condition + mfem::HypreParVector adjoint_essential(adjoint_displacement_); + adjoint_essential = 0.0; + mfem::HypreParVector adjoint_rhs(accel_adjoint_load_vector); adjoint_rhs.Add(fac4 * dt_n, velo_adjoint_load_vector); adjoint_rhs.Add(fac3 * dt_n * dt_n, disp_adjoint_load_vector); diff --git a/src/serac/physics/solid_mechanics.hpp b/src/serac/physics/solid_mechanics.hpp index b6b9b7c7af..67499b33d9 100644 --- a/src/serac/physics/solid_mechanics.hpp +++ b/src/serac/physics/solid_mechanics.hpp @@ -38,7 +38,7 @@ void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, mfem::HypreParVector& accel_adjoint_load_vector, mfem::HypreParVector& adjoint_displacement_, mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, - mfem::HypreParVector& adjoint_essential, BoundaryConditionManager& bcs_, + BoundaryConditionManager& bcs_, mfem::Solver& lin_solver); } // namespace detail @@ -1191,6 +1191,9 @@ class SolidMechanics, std::integer_se // Build the dof array lookup tables displacement_.space().BuildDofToArrays(); + u_ = displacement_; + v_ = velocity_; + if (is_quasistatic_) { residual_with_bcs_ = buildQuasistaticOperator(); } else { @@ -1209,6 +1212,7 @@ class SolidMechanics, std::integer_se // tracking strategy // See https://github.com/mfem/mfem/issues/3531 r = res; + r.SetSubVector(bcs_.allEssentialTrueDofs(), 0.0); }, @@ -1216,7 +1220,7 @@ class SolidMechanics, std::integer_se add(1.0, u_, c0_, d2u_dt2, predicted_displacement_); // K := dR/du - auto K = serac::get((*residual_)(time_, shape_displacement_, + auto K = serac::get((*residual_)(time_, shape_displacement_, differentiate_wrt(predicted_displacement_), d2u_dt2, *parameters_[parameter_indices].state...)); std::unique_ptr k_mat(assemble(K)); @@ -1385,8 +1389,6 @@ class SolidMechanics, std::integer_se void reverseAdjointTimestep() override { SERAC_MARK_FUNCTION; - auto& lin_solver = nonlin_solver_->linearSolver(); - SLIC_ERROR_ROOT_IF(cycle_ <= min_cycle_, "Maximum number of adjoint timesteps exceeded! The number of adjoint timesteps must equal the " "number of forward timesteps"); @@ -1401,29 +1403,7 @@ class SolidMechanics, std::integer_se displacement_ = end_step_solution.at("displacement"); if (is_quasistatic_) { - auto [_, drdu] = (*residual_)(time_, shape_displacement_, differentiate_wrt(displacement_), acceleration_, - *parameters_[parameter_indices].state...); - J_.reset(); - J_ = assemble(drdu); - - auto J_T = std::unique_ptr(J_->Transpose()); - - J_e_.reset(); - J_e_ = bcs_.eliminateAllEssentialDofsFromMatrix(*J_T); - - auto& constrained_dofs = bcs_.allEssentialTrueDofs(); - - mfem::EliminateBC(*J_T, *J_e_, constrained_dofs, reactions_adjoint_bcs_, displacement_adjoint_load_); - for (int i = 0; i < constrained_dofs.Size(); i++) { - int j = constrained_dofs[i]; - displacement_adjoint_load_[j] = reactions_adjoint_bcs_[j]; - } - - lin_solver.SetOperator(*J_T); - lin_solver.Mult(displacement_adjoint_load_, adjoint_displacement_); - - // Reset the equation solver to use the full nonlinear residual operator. MRT, is this needed? - nonlin_solver_->setOperator(*residual_with_bcs_); + quasiStaticAdjointSolve(dt_n_to_np1); } else { SLIC_ERROR_ROOT_IF(ode2_.GetTimestepper() != TimestepMethod::Newmark, "Only Newmark implemented for transient adjoint solid mechanics."); @@ -1444,10 +1424,11 @@ class SolidMechanics, std::integer_se *parameters_[parameter_indices].state...)); std::unique_ptr m_mat(assemble(M)); + auto& lin_solver = nonlin_solver_->linearSolver(); solid_mechanics::detail::adjoint_integrate( dt_n_to_np1, dt_np1_to_np2, m_mat.get(), k_mat.get(), displacement_adjoint_load_, velocity_adjoint_load_, acceleration_adjoint_load_, adjoint_displacement_, implicit_sensitivity_displacement_start_of_step_, - implicit_sensitivity_velocity_start_of_step_, reactions_adjoint_bcs_, bcs_, lin_solver); + implicit_sensitivity_velocity_start_of_step_, bcs_, lin_solver); } time_end_step_ = time_; @@ -1558,15 +1539,20 @@ class SolidMechanics, std::integer_se /// sensitivity of qoi with respect to reaction forces FiniteElementState reactions_adjoint_bcs_; +public: + /// serac::Functional that is used to calculate the residual and its derivatives std::unique_ptr> residual_; + /// mfem::Operator that calculates the residual after applying essential boundary conditions std::unique_ptr residual_with_bcs_; /// the specific methods and tolerances specified to solve the nonlinear residual equations std::unique_ptr nonlin_solver_; +protected: + /** * @brief the ordinary differential equation that describes * how to solve for the second time derivative of displacement, given @@ -1636,6 +1622,34 @@ class SolidMechanics, std::integer_se nonlin_solver_->solve(displacement_); } + /// @brief Solve the Quasi-static adjoint linear + virtual void quasiStaticAdjointSolve(double /*dt*/) + { + // By default, use a homogeneous essential boundary condition + mfem::HypreParVector adjoint_essential(displacement_adjoint_load_); + adjoint_essential = 0.0; + + auto [_, drdu] = (*residual_)(time_, shape_displacement_, differentiate_wrt(displacement_), acceleration_, + *parameters_[parameter_indices].state...); + J_.reset(); + J_ = assemble(drdu); + auto J_T = std::unique_ptr(J_->Transpose()); + J_e_.reset(); + J_e_ = bcs_.eliminateAllEssentialDofsFromMatrix(*J_T); + + auto& constrained_dofs = bcs_.allEssentialTrueDofs(); + + mfem::EliminateBC(*J_T, *J_e_, constrained_dofs, reactions_adjoint_bcs_, displacement_adjoint_load_); + for (int i = 0; i < constrained_dofs.Size(); i++) { + int j = constrained_dofs[i]; + displacement_adjoint_load_[j] = reactions_adjoint_bcs_[j]; + } + + auto& lin_solver = nonlin_solver_->linearSolver(); + lin_solver.SetOperator(*J_T); + lin_solver.Mult(displacement_adjoint_load_, adjoint_displacement_); + } + /** * @brief Calculate a list of constrained dofs in the true displacement vector from a function that * returns true if a physical coordinate is in the constrained set diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index a855473894..89e62135eb 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -369,6 +369,55 @@ class SolidMechanicsContact, displacement_ += du_; } + + /// @brief Solve the Quasi-static Newton system + void quasiStaticAdjointSolve(double /*dt*/) override + { + SLIC_ERROR_ROOT_IF(contact_.haveLagrangeMultipliers(), "Lagrange multiplier contact does not currently support sensitivities/adjoints."); + + printf("in adjoint contact solve\n"); + + // By default, use a homogeneous essential boundary condition + mfem::HypreParVector adjoint_essential(displacement_adjoint_load_); + adjoint_essential = 0.0; + + auto [_, drdu] = (*residual_)(time_, shape_displacement_, differentiate_wrt(displacement_), acceleration_, + *parameters_[parameter_indices].state...); + auto jacobian = assemble(drdu); + + auto block_J = contact_.jacobianFunction(jacobian.release()); + block_J->owns_blocks = false; + jacobian = std::unique_ptr(static_cast(&block_J->GetBlock(0, 0))); + + auto J_T = std::unique_ptr(jacobian->Transpose()); + + for (const auto& bc : bcs_.essentials()) { + bc.apply(*J_T, displacement_adjoint_load_, adjoint_essential); + } + + auto& lin_solver = nonlin_solver_->linearSolver(); + lin_solver.SetOperator(*J_T); + lin_solver.Mult(displacement_adjoint_load_, adjoint_displacement_); + } + + /// @overload + FiniteElementDual& computeTimestepShapeSensitivity() override + { + printf("printing contact shape sensitivity\n"); + auto drdshape = + serac::get((*residual_)(time_end_step_, differentiate_wrt(shape_displacement_), displacement_, + acceleration_, *parameters_[parameter_indices].state...)); + + auto drdshape_mat = assemble(drdshape); + + auto block_J = contact_.jacobianFunction(drdshape_mat.release()); + block_J->owns_blocks = false; + drdshape_mat = std::unique_ptr(static_cast(&block_J->GetBlock(0, 0))); + + drdshape_mat->MultTranspose(adjoint_displacement_, *shape_displacement_sensitivity_); + + return *shape_displacement_sensitivity_; + } using BasePhysics::bcs_; using BasePhysics::cycle_; @@ -378,12 +427,15 @@ class SolidMechanicsContact, using BasePhysics::name_; using BasePhysics::parameters_; using BasePhysics::shape_displacement_; + using BasePhysics::shape_displacement_sensitivity_; using BasePhysics::states_; using BasePhysics::time_; using SolidMechanicsBase::acceleration_; using SolidMechanicsBase::d_residual_d_; using SolidMechanicsBase::DERIVATIVE; using SolidMechanicsBase::displacement_; + using SolidMechanicsBase::adjoint_displacement_; + using SolidMechanicsBase::displacement_adjoint_load_; using SolidMechanicsBase::du_; using SolidMechanicsBase::J_; using SolidMechanicsBase::J_e_; @@ -391,6 +443,8 @@ class SolidMechanicsContact, using SolidMechanicsBase::residual_; using SolidMechanicsBase::residual_with_bcs_; using SolidMechanicsBase::use_warm_start_; + using SolidMechanicsBase::warmStartDisplacement; + using SolidMechanicsBase::time_end_step_; /// Pointer to the Jacobian operator (J_ if no Lagrange multiplier contact, J_constraint_ otherwise) mfem::Operator* J_operator_; diff --git a/src/serac/physics/tests/CMakeLists.txt b/src/serac/physics/tests/CMakeLists.txt index f7505e4920..a1b24f86a6 100644 --- a/src/serac/physics/tests/CMakeLists.txt +++ b/src/serac/physics/tests/CMakeLists.txt @@ -44,8 +44,8 @@ set(physics_parallel_test_sources blt_list_append(TO physics_parallel_test_sources ELEMENTS contact_patch.cpp - contact_patch_tied.cpp contact_beam.cpp + contact_solid_adjoint.cpp IF TRIBOL_FOUND) serac_add_tests(SOURCES ${physics_parallel_test_sources} diff --git a/src/serac/physics/tests/contact_solid_adjoint.cpp b/src/serac/physics/tests/contact_solid_adjoint.cpp new file mode 100644 index 0000000000..5f9921b5e6 --- /dev/null +++ b/src/serac/physics/tests/contact_solid_adjoint.cpp @@ -0,0 +1,212 @@ +// Copyright (c) 2019-2024, Lawrence Livermore National Security, LLC and +// other Serac Project Developers. See the top-level LICENSE file for +// details. +// +// SPDX-License-Identifier: (BSD-3-Clause) +#include +#include +#include + +#include "serac/physics/solid_mechanics_contact.hpp" +#include "serac/physics/materials/solid_material.hpp" + +#include "axom/slic/core/SimpleLogger.hpp" +#include +#include "mfem.hpp" + +#include "serac/mesh/mesh_utils.hpp" +#include "serac/physics/state/state_manager.hpp" +#include "serac/serac_config.hpp" +#include "serac/infrastructure/terminator.hpp" + +namespace serac { + +constexpr int dim = 3; +constexpr int p = 1; + +const std::string mesh_tag = "mesh"; +const std::string physics_prefix = "solid"; + +using SolidMaterial = solid_mechanics::NeoHookean; + +struct TimeSteppingInfo { + TimeSteppingInfo() : dts({0.0, 0.2, 0.4, 0.24, 0.12, 0.0}) {} + + int numTimesteps() const { return dts.Size() - 2; } + + mfem::Vector dts; +}; + +constexpr double disp_target = -0.34; + +// MRT: add explicit velocity dependence +double computeStepQoi(const FiniteElementState& displacement) +{ + FiniteElementState displacement_error(displacement); + displacement_error = -disp_target; + displacement_error.Add(1.0, displacement); + return 0.5 * innerProduct(displacement_error, displacement_error); +} + +void computeStepAdjointLoad(const FiniteElementState& displacement, FiniteElementDual& d_qoi_d_displacement) +{ + d_qoi_d_displacement = -disp_target; + d_qoi_d_displacement.Add(1.0, displacement); +} + +using SolidMechT = serac::SolidMechanicsContact; + +std::unique_ptr createContactSolver( + const NonlinearSolverOptions& nonlinear_opts, const TimesteppingOptions& dyn_opts, const SolidMaterial& mat) +{ + static int iter = 0; + + auto solid = + std::make_unique(nonlinear_opts, solid_mechanics::direct_linear_options, dyn_opts, + physics_prefix + std::to_string(iter++), mesh_tag); + solid->setMaterial(mat); + + solid->setDisplacementBCs({2}, [](const mfem::Vector& /*X*/, double /*t*/, mfem::Vector& disp) { disp = 0.0; }); + solid->setDisplacementBCs({4}, [](const mfem::Vector& /*X*/, double /*t*/, mfem::Vector& disp) { disp = 0.0; disp[1] = -0.1; }); + + auto contact_type = serac::ContactEnforcement::Penalty; + double element_length = 1.0; + double penalty = 5 * mat.K / element_length; + + serac::ContactOptions contact_options{.method = serac::ContactMethod::SingleMortar, + .enforcement = contact_type, + .type = serac::ContactType::Frictionless, + .penalty = penalty}; + auto contact_interaction_id = 0; + solid->addContactInteraction(contact_interaction_id, {3}, {5}, contact_options); + + solid->completeSetup(); + + return solid; +} + +double computeSolidMechanicsQoi(BasePhysics& solid_solver, const TimeSteppingInfo& ts_info) +{ + auto dts = ts_info.dts; + solid_solver.resetStates(); + solid_solver.outputStateToDisk("paraview_contact"); + solid_solver.advanceTimestep(1.0); + solid_solver.outputStateToDisk("paraview_contact"); + return computeStepQoi(solid_solver.state("displacement")); +} + +auto computeContactQoiSensitivities( + BasePhysics& solid_solver, const TimeSteppingInfo& ts_info) +{ + EXPECT_EQ(0, solid_solver.cycle()); + + double qoi = computeSolidMechanicsQoi(solid_solver, ts_info); + + FiniteElementDual shape_sensitivity(solid_solver.shapeDisplacement().space(), "shape sensitivity"); + FiniteElementDual adjoint_load(solid_solver.state("displacement").space(), "adjoint_displacement_load"); + + auto previous_displacement = solid_solver.loadCheckpointedState("displacement", solid_solver.cycle()); + computeStepAdjointLoad(previous_displacement, adjoint_load); + EXPECT_EQ(1, solid_solver.cycle()); + solid_solver.setAdjointLoad({{"displacement", adjoint_load}}); + solid_solver.reverseAdjointTimestep(); + shape_sensitivity = solid_solver.computeTimestepShapeSensitivity(); + EXPECT_EQ(0, solid_solver.cycle()); + + return std::make_tuple(qoi, shape_sensitivity); +} + + +double computeSolidMechanicsQoiAdjustingShape(SolidMechanics& solid_solver, const TimeSteppingInfo& ts_info, + const FiniteElementState& shape_derivative_direction, double pertubation) +{ + FiniteElementState shape_disp(shape_derivative_direction.space(), "input_shape_displacement"); + + shape_disp.Add(pertubation, shape_derivative_direction); + solid_solver.setShapeDisplacement(shape_disp); + + return computeSolidMechanicsQoi(solid_solver, ts_info); +} + + +struct ContactSensitivityFixture : public ::testing::Test { + void SetUp() override + { + MPI_Barrier(MPI_COMM_WORLD); + StateManager::initialize(dataStore, "contact_solve"); + std::string filename = std::string(SERAC_REPO_DIR) + "/data/meshes/contact_two_blocks.g"; + mesh = &StateManager::setMesh(mesh::refineAndDistribute(buildMeshFromFile(filename), 0), mesh_tag); + + mat.density = 1.0; + mat.K = 1.0; + mat.G = 0.1; + } + + void fillDirection(FiniteElementState& direction) const + { + auto sz = direction.Size(); + for (int i = 0; i < sz; ++i) { + direction(i) = -1.2 + 2.02 * (double(i) / sz); + } + } + + axom::sidre::DataStore dataStore; + mfem::ParMesh* mesh; + + NonlinearSolverOptions nonlinear_opts{.relative_tol = 1.0e-10, .absolute_tol = 1.0e-12}; + + bool dispBc = true; + TimesteppingOptions dyn_opts{.timestepper = TimestepMethod::QuasiStatic}; + + SolidMaterial mat; + TimeSteppingInfo tsInfo; + + static constexpr double eps = 2e-7; +}; + + +TEST_F(ContactSensitivityFixture, WhenShapeSensitivitiesCalledTwice_GetSameObjectiveAndGradient) +{ + auto solid_solver = createContactSolver(nonlinear_opts, dyn_opts, mat); + auto [qoi1, shape_sensitivity1] = computeContactQoiSensitivities(*solid_solver, tsInfo); + + solid_solver->resetStates(); + FiniteElementState derivative_direction(shape_sensitivity1.space(), "derivative_direction"); + fillDirection(derivative_direction); + + auto [qoi2, shape_sensitivity2] = computeContactQoiSensitivities(*solid_solver, tsInfo); + + EXPECT_EQ(qoi1, qoi2); + + double directional_deriv1 = innerProduct(derivative_direction, shape_sensitivity1); + double directional_deriv2 = innerProduct(derivative_direction, shape_sensitivity2); + EXPECT_EQ(directional_deriv1, directional_deriv2); +} + + +TEST_F(ContactSensitivityFixture, QuasiStaticShapeSensitivities) +{ + auto solid_solver = createContactSolver(nonlinear_opts, dyn_opts, mat); + auto [qoi_base, shape_sensitivity] = computeContactQoiSensitivities(*solid_solver, tsInfo); + + solid_solver->resetStates(); + FiniteElementState derivative_direction(shape_sensitivity.space(), "derivative_direction"); + fillDirection(derivative_direction); + + double qoi_plus = computeSolidMechanicsQoiAdjustingShape(*solid_solver, tsInfo, derivative_direction, eps); + + double directional_deriv = innerProduct(derivative_direction, shape_sensitivity); + EXPECT_NEAR(directional_deriv, (qoi_plus - qoi_base) / eps, 0.0001); //eps); +} + +} // namespace serac + +int main(int argc, char* argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + serac::initialize(argc, argv); + int result = RUN_ALL_TESTS(); + serac::exitGracefully(result); + + return result; +} diff --git a/tests b/tests index 57f8983b97..662c093ddd 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit 57f8983b977f70445342a211c3ee5538bb81dc4f +Subproject commit 662c093dddcff184983547ea0212adce3632a751 From c63bf3a0337ec8480091391c9d7f1d66e895528a Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Tue, 10 Sep 2024 16:18:47 -0700 Subject: [PATCH 02/27] Add mesh, cleanup a bit. --- data/meshes/contact_two_blocks.g | Bin 0 -> 12288 bytes src/serac/physics/solid_mechanics.hpp | 6 +----- 2 files changed, 1 insertion(+), 5 deletions(-) create mode 100644 data/meshes/contact_two_blocks.g diff --git a/data/meshes/contact_two_blocks.g b/data/meshes/contact_two_blocks.g new file mode 100644 index 0000000000000000000000000000000000000000..1355b6306c0987333d5db33f55408c6add740f8a GIT binary patch literal 12288 zcmeI2yLVK_9miKZwL%!jJOaUqSAY!yp%;RH;u!HX;0M?a1Wd7Bq?OpiYImc(3XhY* zMamQ@QsfWFImUnkNtMo&DN;~UCSA&uIj;Qu%*=1OJ33cO4(Eh|ox}J3?#%Bwzj^GP z5hqTbUXk;qPh_jmTP@d$wbFb!m+OI(Pb%}}Vlyc>sQI$Cwm4s$smxPbDdefw>NDl0 z=U)}+rL9~oBeYZK^Y!Aj>J2A^-}SULD>JfRPJ-@gwZ9f*D>cN&ocwk@H_$FW#YTBS zwjHB)iTt>er#+H)4BGpj`E6okLU8fT%odxjC6{{=$)TKYlkOD^}ikdE)5>g{s0csZy0t5R{HJnh;TuvN45#RaI)$5=L#g-UJC@dxzm7uE{v zN{veK*X4y~rCx(c-g}Pa?)*!1ZASan*=oI%$Xc;cuhf#_&HBQO#_x{iit~qm@|&Nn zR5hlak>bJMIA6L|nP(g|$BGJYF1fDemVQC+{W5-NLXnq}MWzLPL6@>RsU%e#sxXJ9 zrWdbOl074HBXeV8BgtZ;d}DlMx?W34(@8P8S=S7zPv2+`&kar%Mvsi>-}vbG#AIP? zd~#x9a%>bk>x6>P=jQs&>-FFOpXOJuxitd)Q*nCv^0j9{su5Z8Xoa|geEu%)l5Z^3 z8_YSAWjuIa<=33+)5^0a)#CeY`j1r4H=9fR5t9}CZSs};-$Z*QpZ14rCx52@56P~X zu4{yEIg7-|TDKxwE1vpF{-2^=_O@$TMz){0yzHG$vKxLc335him) z?{`NStQjlJyC=R`gI>{!IZHom373{z6-uxpK%U*J6vG7ZR><_${dlE~~-NzcVSUSlvo^7$9po0B3 z+?#)}mcI0_`<{wgEc{v_yV3L9GZo9wWwlr=on#sNwpjd6p|ig!Wj__m&@Hw1`QJ$G zWlbl=!rLrt5q{`e{DXD!TmL%rUs2zO`BFpg^ntjo@cuhr+5a2Sem5uiu;?g1+>1Ql zOT~71+Ym4-`#n`&a=GC@=z)I&aoT%K;bDjPRzD6|$)ewWch8kT?*{rOYmfD;J<$6Z z{0D*mAcOx^%n$WPCLiketZp>4f1RP<@@M)-eg7T=`gNf9qjuvz4DI(aD+^;pgR>-c*R^MXAjPqu=^*UNSEt{x?DHVbmVan{Oh1 zYaRxDn=hH;9?b`nH~Mhu1?PpuXEelR>ne^nuG>1W_^od9_Fkv>%&*bl|8AhMzqoFB zFuzte+R^`#_;}1b{>1%_`1g$;^55Ej zL;X>pf3fk(qGs3Zg?en??6vl5vzMXY+6O}%t@upOXyn)CL+s!5m-Hw0AN>8*>}T*> z{fPW8Sr1YCExpM8lKw{g*8Dbm#q4 z{S`d!n7Nll1|Ijk+{N;@N_gD0a;J$5U%u#Z=gGY!cWmf!@5reN9(vsSAp;LR?f{X2 zhi&cyk%5QptpYOGL~on$BLSP}@ps8L1$gNFSU?6IdYk}}frst41Z3c0yC5LL9~aX3 z7*KtOuv6f)80Q1t+rm2nGI2iO?H2Y3$i(@;CVGRyULnp0JoNSn$i(@8hwUK&nK&QV zL~p+^EX4VMhu(;QOq>sR*d7&-iSse0Hm>Lo2opk_4|oTKLjp2!KH&XSI4mF&=L4JQ z9T6slI3MuP`I*5a$CPdPfCh;(Wlv_LP9kG2ysyLO3a$ z5>5;63ugp)XN7YDGVneSJ`|8ahxU(zj|FsSKQCMm;Gz48fDAlzKNXOP{e7mkUkDe4 zOG4}q-Y^Jt&X7A{K^b6`0Y>smLsz)y7N{UQpw7LSm|#dzP~sZ@vW8qu3`+9MV9?;yE5m?4iUZ+ z?K`q9pD#O4iYxxEZCh6_JH8VakDuiLl3B(M4Udfuk7n|7&;BcEhD`eZmu85x?Mdmg zMtZHJ_bSdb+);3DNw2N+9+q_;vGK6^Qjm=S!R8U;WBcRFj)n6VvF#VE|8ML4h(ONn4-1Ulh(PX{ zZ|s++h0g@e$L|ZAjV}sUg|os(!UchI`lrGr;iPayI3=7HIHw;InC6_HPY8D2zpVG; H!nyAOTY7uL literal 0 HcmV?d00001 diff --git a/src/serac/physics/solid_mechanics.hpp b/src/serac/physics/solid_mechanics.hpp index 67499b33d9..fb614c252d 100644 --- a/src/serac/physics/solid_mechanics.hpp +++ b/src/serac/physics/solid_mechanics.hpp @@ -1539,8 +1539,6 @@ class SolidMechanics, std::integer_se /// sensitivity of qoi with respect to reaction forces FiniteElementState reactions_adjoint_bcs_; -public: - /// serac::Functional that is used to calculate the residual and its derivatives std::unique_ptr> residual_; @@ -1551,8 +1549,6 @@ class SolidMechanics, std::integer_se /// the specific methods and tolerances specified to solve the nonlinear residual equations std::unique_ptr nonlin_solver_; -protected: - /** * @brief the ordinary differential equation that describes * how to solve for the second time derivative of displacement, given @@ -1628,7 +1624,7 @@ class SolidMechanics, std::integer_se // By default, use a homogeneous essential boundary condition mfem::HypreParVector adjoint_essential(displacement_adjoint_load_); adjoint_essential = 0.0; - + auto [_, drdu] = (*residual_)(time_, shape_displacement_, differentiate_wrt(displacement_), acceleration_, *parameters_[parameter_indices].state...); J_.reset(); From e5eb7dd278295e5b9d4680ea46c7b65a1687625e Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Tue, 10 Sep 2024 16:23:06 -0700 Subject: [PATCH 03/27] Adjust test. --- src/serac/physics/tests/contact_solid_adjoint.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/serac/physics/tests/contact_solid_adjoint.cpp b/src/serac/physics/tests/contact_solid_adjoint.cpp index 5f9921b5e6..a851ee95af 100644 --- a/src/serac/physics/tests/contact_solid_adjoint.cpp +++ b/src/serac/physics/tests/contact_solid_adjoint.cpp @@ -71,7 +71,7 @@ std::unique_ptr createContactSolver( auto contact_type = serac::ContactEnforcement::Penalty; double element_length = 1.0; - double penalty = 5 * mat.K / element_length; + double penalty = 2.0 * mat.K / element_length; serac::ContactOptions contact_options{.method = serac::ContactMethod::SingleMortar, .enforcement = contact_type, @@ -196,7 +196,7 @@ TEST_F(ContactSensitivityFixture, QuasiStaticShapeSensitivities) double qoi_plus = computeSolidMechanicsQoiAdjustingShape(*solid_solver, tsInfo, derivative_direction, eps); double directional_deriv = innerProduct(derivative_direction, shape_sensitivity); - EXPECT_NEAR(directional_deriv, (qoi_plus - qoi_base) / eps, 0.0001); //eps); + EXPECT_NEAR(directional_deriv, (qoi_plus - qoi_base) / eps, 0.005); } } // namespace serac From 17981a1ff8dea593b64c1b8acb3927ef5f4fbc01 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Tue, 10 Sep 2024 20:40:21 -0700 Subject: [PATCH 04/27] Get test to a closer state, only off by 20%. --- src/serac/physics/solid_mechanics_contact.hpp | 20 +++++++++++-------- .../physics/tests/contact_solid_adjoint.cpp | 8 +++++--- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 89e62135eb..6129ce3ac9 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -123,7 +123,9 @@ class SolidMechanicsContact, // See https://github.com/mfem/mfem/issues/3531 mfem::Vector r_blk(r, 0, displacement_.Size()); r_blk = res; - contact_.residualFunction(u, r); + mfem::Vector uPlusShapeDisp = u; + uPlusShapeDisp += shape_displacement_; + contact_.residualFunction(uPlusShapeDisp, r); r_blk.SetSubVector(bcs_.allEssentialTrueDofs(), 0.0); }; // This if-block below breaks up building the Jacobian operator depending if there is Lagrange multiplier @@ -141,6 +143,9 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); + mfem::Vector uPlusShapeDisp = u; + uPlusShapeDisp += shape_displacement_; + // create block operator holding jacobian contributions J_constraint_ = contact_.jacobianFunction(J_.release()); @@ -177,6 +182,9 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); + mfem::Vector uPlusShapeDisp = u; + uPlusShapeDisp += shape_displacement_; + // get 11-block holding jacobian contributions auto block_J = contact_.jacobianFunction(J_.release()); block_J->owns_blocks = false; @@ -375,8 +383,6 @@ class SolidMechanicsContact, { SLIC_ERROR_ROOT_IF(contact_.haveLagrangeMultipliers(), "Lagrange multiplier contact does not currently support sensitivities/adjoints."); - printf("in adjoint contact solve\n"); - // By default, use a homogeneous essential boundary condition mfem::HypreParVector adjoint_essential(displacement_adjoint_load_); adjoint_essential = 0.0; @@ -388,8 +394,7 @@ class SolidMechanicsContact, auto block_J = contact_.jacobianFunction(jacobian.release()); block_J->owns_blocks = false; jacobian = std::unique_ptr(static_cast(&block_J->GetBlock(0, 0))); - - auto J_T = std::unique_ptr(jacobian->Transpose()); + auto J_T = std::unique_ptr(jacobian->Transpose()); for (const auto& bc : bcs_.essentials()) { bc.apply(*J_T, displacement_adjoint_load_, adjoint_essential); @@ -400,10 +405,9 @@ class SolidMechanicsContact, lin_solver.Mult(displacement_adjoint_load_, adjoint_displacement_); } - /// @overload + /// @overload FiniteElementDual& computeTimestepShapeSensitivity() override { - printf("printing contact shape sensitivity\n"); auto drdshape = serac::get((*residual_)(time_end_step_, differentiate_wrt(shape_displacement_), displacement_, acceleration_, *parameters_[parameter_indices].state...)); @@ -413,7 +417,7 @@ class SolidMechanicsContact, auto block_J = contact_.jacobianFunction(drdshape_mat.release()); block_J->owns_blocks = false; drdshape_mat = std::unique_ptr(static_cast(&block_J->GetBlock(0, 0))); - + drdshape_mat->MultTranspose(adjoint_displacement_, *shape_displacement_sensitivity_); return *shape_displacement_sensitivity_; diff --git a/src/serac/physics/tests/contact_solid_adjoint.cpp b/src/serac/physics/tests/contact_solid_adjoint.cpp index a851ee95af..91be05cde7 100644 --- a/src/serac/physics/tests/contact_solid_adjoint.cpp +++ b/src/serac/physics/tests/contact_solid_adjoint.cpp @@ -71,7 +71,7 @@ std::unique_ptr createContactSolver( auto contact_type = serac::ContactEnforcement::Penalty; double element_length = 1.0; - double penalty = 2.0 * mat.K / element_length; + double penalty = 105.1 * mat.K / element_length; serac::ContactOptions contact_options{.method = serac::ContactMethod::SingleMortar, .enforcement = contact_type, @@ -186,7 +186,7 @@ TEST_F(ContactSensitivityFixture, WhenShapeSensitivitiesCalledTwice_GetSameObjec TEST_F(ContactSensitivityFixture, QuasiStaticShapeSensitivities) { - auto solid_solver = createContactSolver(nonlinear_opts, dyn_opts, mat); + auto solid_solver = createContactSolver(nonlinear_opts, dyn_opts, mat); auto [qoi_base, shape_sensitivity] = computeContactQoiSensitivities(*solid_solver, tsInfo); solid_solver->resetStates(); @@ -196,7 +196,9 @@ TEST_F(ContactSensitivityFixture, QuasiStaticShapeSensitivities) double qoi_plus = computeSolidMechanicsQoiAdjustingShape(*solid_solver, tsInfo, derivative_direction, eps); double directional_deriv = innerProduct(derivative_direction, shape_sensitivity); - EXPECT_NEAR(directional_deriv, (qoi_plus - qoi_base) / eps, 0.005); + double directional_deriv_fd = (qoi_plus - qoi_base) / eps; + // std::cout << "qoi, derivs = " << qoi_base << " " << directional_deriv << " " << directional_deriv_fd << std::endl; + EXPECT_NEAR(directional_deriv, directional_deriv_fd, 0.2); // These are very large tolerances } } // namespace serac From 80dccdadb7c06b8d284fe30a6b901bd99aa6e841 Mon Sep 17 00:00:00 2001 From: Agent Style Date: Tue, 10 Sep 2024 20:44:16 -0700 Subject: [PATCH 05/27] Apply style updates --- src/serac/physics/solid_mechanics.cpp | 7 ++-- src/serac/physics/solid_mechanics.hpp | 10 +++--- src/serac/physics/solid_mechanics_contact.hpp | 13 +++---- .../physics/tests/contact_solid_adjoint.cpp | 34 +++++++++---------- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/serac/physics/solid_mechanics.cpp b/src/serac/physics/solid_mechanics.cpp index 9001d7b4ea..4d49ec49b5 100644 --- a/src/serac/physics/solid_mechanics.cpp +++ b/src/serac/physics/solid_mechanics.cpp @@ -15,10 +15,9 @@ namespace detail { void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, mfem::HypreParMatrix* k_mat, mfem::HypreParVector& disp_adjoint_load_vector, mfem::HypreParVector& velo_adjoint_load_vector, mfem::HypreParVector& accel_adjoint_load_vector, mfem::HypreParVector& adjoint_displacement_, - mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, - mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, - BoundaryConditionManager& bcs_, - mfem::Solver& lin_solver) + mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, + mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, + BoundaryConditionManager& bcs_, mfem::Solver& lin_solver) { // there are hard-coded here for now static constexpr double beta = 0.25; diff --git a/src/serac/physics/solid_mechanics.hpp b/src/serac/physics/solid_mechanics.hpp index fb614c252d..abc4c9d25d 100644 --- a/src/serac/physics/solid_mechanics.hpp +++ b/src/serac/physics/solid_mechanics.hpp @@ -36,10 +36,9 @@ namespace detail { void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, mfem::HypreParMatrix* k_mat, mfem::HypreParVector& disp_adjoint_load_vector, mfem::HypreParVector& velo_adjoint_load_vector, mfem::HypreParVector& accel_adjoint_load_vector, mfem::HypreParVector& adjoint_displacement_, - mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, - mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, - BoundaryConditionManager& bcs_, - mfem::Solver& lin_solver); + mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, + mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, + BoundaryConditionManager& bcs_, mfem::Solver& lin_solver); } // namespace detail /** @@ -1220,7 +1219,7 @@ class SolidMechanics, std::integer_se add(1.0, u_, c0_, d2u_dt2, predicted_displacement_); // K := dR/du - auto K = serac::get((*residual_)(time_, shape_displacement_, + auto K = serac::get((*residual_)(time_, shape_displacement_, differentiate_wrt(predicted_displacement_), d2u_dt2, *parameters_[parameter_indices].state...)); std::unique_ptr k_mat(assemble(K)); @@ -1542,7 +1541,6 @@ class SolidMechanics, std::integer_se /// serac::Functional that is used to calculate the residual and its derivatives std::unique_ptr> residual_; - /// mfem::Operator that calculates the residual after applying essential boundary conditions std::unique_ptr residual_with_bcs_; diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 6129ce3ac9..7eb5958014 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -122,7 +122,7 @@ class SolidMechanicsContact, // tracking strategy // See https://github.com/mfem/mfem/issues/3531 mfem::Vector r_blk(r, 0, displacement_.Size()); - r_blk = res; + r_blk = res; mfem::Vector uPlusShapeDisp = u; uPlusShapeDisp += shape_displacement_; contact_.residualFunction(uPlusShapeDisp, r); @@ -381,14 +381,15 @@ class SolidMechanicsContact, /// @brief Solve the Quasi-static Newton system void quasiStaticAdjointSolve(double /*dt*/) override { - SLIC_ERROR_ROOT_IF(contact_.haveLagrangeMultipliers(), "Lagrange multiplier contact does not currently support sensitivities/adjoints."); + SLIC_ERROR_ROOT_IF(contact_.haveLagrangeMultipliers(), + "Lagrange multiplier contact does not currently support sensitivities/adjoints."); // By default, use a homogeneous essential boundary condition mfem::HypreParVector adjoint_essential(displacement_adjoint_load_); adjoint_essential = 0.0; - + auto [_, drdu] = (*residual_)(time_, shape_displacement_, differentiate_wrt(displacement_), acceleration_, - *parameters_[parameter_indices].state...); + *parameters_[parameter_indices].state...); auto jacobian = assemble(drdu); auto block_J = contact_.jacobianFunction(jacobian.release()); @@ -417,7 +418,7 @@ class SolidMechanicsContact, auto block_J = contact_.jacobianFunction(drdshape_mat.release()); block_J->owns_blocks = false; drdshape_mat = std::unique_ptr(static_cast(&block_J->GetBlock(0, 0))); - + drdshape_mat->MultTranspose(adjoint_displacement_, *shape_displacement_sensitivity_); return *shape_displacement_sensitivity_; @@ -435,10 +436,10 @@ class SolidMechanicsContact, using BasePhysics::states_; using BasePhysics::time_; using SolidMechanicsBase::acceleration_; + using SolidMechanicsBase::adjoint_displacement_; using SolidMechanicsBase::d_residual_d_; using SolidMechanicsBase::DERIVATIVE; using SolidMechanicsBase::displacement_; - using SolidMechanicsBase::adjoint_displacement_; using SolidMechanicsBase::displacement_adjoint_load_; using SolidMechanicsBase::du_; using SolidMechanicsBase::J_; diff --git a/src/serac/physics/tests/contact_solid_adjoint.cpp b/src/serac/physics/tests/contact_solid_adjoint.cpp index 91be05cde7..513fbcbf6a 100644 --- a/src/serac/physics/tests/contact_solid_adjoint.cpp +++ b/src/serac/physics/tests/contact_solid_adjoint.cpp @@ -56,8 +56,8 @@ void computeStepAdjointLoad(const FiniteElementState& displacement, FiniteElemen using SolidMechT = serac::SolidMechanicsContact; -std::unique_ptr createContactSolver( - const NonlinearSolverOptions& nonlinear_opts, const TimesteppingOptions& dyn_opts, const SolidMaterial& mat) +std::unique_ptr createContactSolver(const NonlinearSolverOptions& nonlinear_opts, + const TimesteppingOptions& dyn_opts, const SolidMaterial& mat) { static int iter = 0; @@ -67,17 +67,20 @@ std::unique_ptr createContactSolver( solid->setMaterial(mat); solid->setDisplacementBCs({2}, [](const mfem::Vector& /*X*/, double /*t*/, mfem::Vector& disp) { disp = 0.0; }); - solid->setDisplacementBCs({4}, [](const mfem::Vector& /*X*/, double /*t*/, mfem::Vector& disp) { disp = 0.0; disp[1] = -0.1; }); + solid->setDisplacementBCs({4}, [](const mfem::Vector& /*X*/, double /*t*/, mfem::Vector& disp) { + disp = 0.0; + disp[1] = -0.1; + }); - auto contact_type = serac::ContactEnforcement::Penalty; + auto contact_type = serac::ContactEnforcement::Penalty; double element_length = 1.0; - double penalty = 105.1 * mat.K / element_length; + double penalty = 105.1 * mat.K / element_length; serac::ContactOptions contact_options{.method = serac::ContactMethod::SingleMortar, .enforcement = contact_type, .type = serac::ContactType::Frictionless, .penalty = penalty}; - auto contact_interaction_id = 0; + auto contact_interaction_id = 0; solid->addContactInteraction(contact_interaction_id, {3}, {5}, contact_options); solid->completeSetup(); @@ -95,8 +98,7 @@ double computeSolidMechanicsQoi(BasePhysics& solid_solver, const TimeSteppingInf return computeStepQoi(solid_solver.state("displacement")); } -auto computeContactQoiSensitivities( - BasePhysics& solid_solver, const TimeSteppingInfo& ts_info) +auto computeContactQoiSensitivities(BasePhysics& solid_solver, const TimeSteppingInfo& ts_info) { EXPECT_EQ(0, solid_solver.cycle()); @@ -116,7 +118,6 @@ auto computeContactQoiSensitivities( return std::make_tuple(qoi, shape_sensitivity); } - double computeSolidMechanicsQoiAdjustingShape(SolidMechanics& solid_solver, const TimeSteppingInfo& ts_info, const FiniteElementState& shape_derivative_direction, double pertubation) { @@ -128,7 +129,6 @@ double computeSolidMechanicsQoiAdjustingShape(SolidMechanics& solid_solv return computeSolidMechanicsQoi(solid_solver, ts_info); } - struct ContactSensitivityFixture : public ::testing::Test { void SetUp() override { @@ -137,9 +137,9 @@ struct ContactSensitivityFixture : public ::testing::Test { std::string filename = std::string(SERAC_REPO_DIR) + "/data/meshes/contact_two_blocks.g"; mesh = &StateManager::setMesh(mesh::refineAndDistribute(buildMeshFromFile(filename), 0), mesh_tag); - mat.density = 1.0; - mat.K = 1.0; - mat.G = 0.1; + mat.density = 1.0; + mat.K = 1.0; + mat.G = 0.1; } void fillDirection(FiniteElementState& direction) const @@ -156,7 +156,7 @@ struct ContactSensitivityFixture : public ::testing::Test { NonlinearSolverOptions nonlinear_opts{.relative_tol = 1.0e-10, .absolute_tol = 1.0e-12}; bool dispBc = true; - TimesteppingOptions dyn_opts{.timestepper = TimestepMethod::QuasiStatic}; + TimesteppingOptions dyn_opts{.timestepper = TimestepMethod::QuasiStatic}; SolidMaterial mat; TimeSteppingInfo tsInfo; @@ -164,7 +164,6 @@ struct ContactSensitivityFixture : public ::testing::Test { static constexpr double eps = 2e-7; }; - TEST_F(ContactSensitivityFixture, WhenShapeSensitivitiesCalledTwice_GetSameObjectiveAndGradient) { auto solid_solver = createContactSolver(nonlinear_opts, dyn_opts, mat); @@ -183,7 +182,6 @@ TEST_F(ContactSensitivityFixture, WhenShapeSensitivitiesCalledTwice_GetSameObjec EXPECT_EQ(directional_deriv1, directional_deriv2); } - TEST_F(ContactSensitivityFixture, QuasiStaticShapeSensitivities) { auto solid_solver = createContactSolver(nonlinear_opts, dyn_opts, mat); @@ -195,10 +193,10 @@ TEST_F(ContactSensitivityFixture, QuasiStaticShapeSensitivities) double qoi_plus = computeSolidMechanicsQoiAdjustingShape(*solid_solver, tsInfo, derivative_direction, eps); - double directional_deriv = innerProduct(derivative_direction, shape_sensitivity); + double directional_deriv = innerProduct(derivative_direction, shape_sensitivity); double directional_deriv_fd = (qoi_plus - qoi_base) / eps; // std::cout << "qoi, derivs = " << qoi_base << " " << directional_deriv << " " << directional_deriv_fd << std::endl; - EXPECT_NEAR(directional_deriv, directional_deriv_fd, 0.2); // These are very large tolerances + EXPECT_NEAR(directional_deriv, directional_deriv_fd, 0.2); // These are very large tolerances } } // namespace serac From 957a194b9017f89702d517924588cbd9bdf58538 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Wed, 11 Sep 2024 12:51:02 -0700 Subject: [PATCH 06/27] Trying to fix a potential memory issue. --- src/serac/physics/solid_mechanics_contact.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 7eb5958014..52731762ea 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -123,8 +123,10 @@ class SolidMechanicsContact, // See https://github.com/mfem/mfem/issues/3531 mfem::Vector r_blk(r, 0, displacement_.Size()); r_blk = res; - mfem::Vector uPlusShapeDisp = u; + mfem::Vector uPlusShapeDisp(u.Size()); + uPlusShapeDisp = u; uPlusShapeDisp += shape_displacement_; + contact_.residualFunction(uPlusShapeDisp, r); r_blk.SetSubVector(bcs_.allEssentialTrueDofs(), 0.0); }; @@ -143,7 +145,8 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); - mfem::Vector uPlusShapeDisp = u; + mfem::Vector uPlusShapeDisp(u.Size()); + uPlusShapeDisp = u; uPlusShapeDisp += shape_displacement_; // create block operator holding jacobian contributions @@ -182,7 +185,8 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); - mfem::Vector uPlusShapeDisp = u; + mfem::Vector uPlusShapeDisp(u.Size()); + uPlusShapeDisp = u; uPlusShapeDisp += shape_displacement_; // get 11-block holding jacobian contributions From aa3248c38338defc83bd3b8c1fd26534220d5480 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Wed, 11 Sep 2024 12:59:56 -0700 Subject: [PATCH 07/27] style. --- src/serac/physics/solid_mechanics_contact.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 52731762ea..4de4e5c913 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -122,7 +122,7 @@ class SolidMechanicsContact, // tracking strategy // See https://github.com/mfem/mfem/issues/3531 mfem::Vector r_blk(r, 0, displacement_.Size()); - r_blk = res; + r_blk = res; mfem::Vector uPlusShapeDisp(u.Size()); uPlusShapeDisp = u; uPlusShapeDisp += shape_displacement_; From 9cd9e4dfb8c57a5ec352fbc96279eb37795161e6 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Wed, 11 Sep 2024 14:33:11 -0700 Subject: [PATCH 08/27] try to fix memory issue. --- src/serac/physics/solid_mechanics_contact.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 4de4e5c913..346c30b422 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -125,7 +125,7 @@ class SolidMechanicsContact, r_blk = res; mfem::Vector uPlusShapeDisp(u.Size()); uPlusShapeDisp = u; - uPlusShapeDisp += shape_displacement_; + uPlusShapeDisp.Add(1.0, shape_displacement_); contact_.residualFunction(uPlusShapeDisp, r); r_blk.SetSubVector(bcs_.allEssentialTrueDofs(), 0.0); @@ -147,7 +147,7 @@ class SolidMechanicsContact, mfem::Vector uPlusShapeDisp(u.Size()); uPlusShapeDisp = u; - uPlusShapeDisp += shape_displacement_; + uPlusShapeDisp.Add(1.0, shape_displacement_); // create block operator holding jacobian contributions J_constraint_ = contact_.jacobianFunction(J_.release()); @@ -187,7 +187,7 @@ class SolidMechanicsContact, mfem::Vector uPlusShapeDisp(u.Size()); uPlusShapeDisp = u; - uPlusShapeDisp += shape_displacement_; + uPlusShapeDisp.Add(1.0, shape_displacement_); // get 11-block holding jacobian contributions auto block_J = contact_.jacobianFunction(J_.release()); From 94eafbfe8571e8882eed5b5737f4ccd3f6dc8d2b Mon Sep 17 00:00:00 2001 From: Michael Tupek <135926736+tupek2@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:18:32 -0700 Subject: [PATCH 09/27] Update solid_mechanics.hpp Delete copy --- src/serac/physics/solid_mechanics.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/serac/physics/solid_mechanics.hpp b/src/serac/physics/solid_mechanics.hpp index abc4c9d25d..277bae4139 100644 --- a/src/serac/physics/solid_mechanics.hpp +++ b/src/serac/physics/solid_mechanics.hpp @@ -1190,9 +1190,6 @@ class SolidMechanics, std::integer_se // Build the dof array lookup tables displacement_.space().BuildDofToArrays(); - u_ = displacement_; - v_ = velocity_; - if (is_quasistatic_) { residual_with_bcs_ = buildQuasistaticOperator(); } else { From 0efe1757379d1122a9d10be221cb0ccbc40105eb Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Fri, 27 Sep 2024 11:03:39 -0700 Subject: [PATCH 10/27] Fix contact patch unit test failure. Needed to use serac finite element states instead of generic mfem vectors. --- src/serac/physics/solid_mechanics_contact.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 346c30b422..946fd52ab6 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -123,7 +123,7 @@ class SolidMechanicsContact, // See https://github.com/mfem/mfem/issues/3531 mfem::Vector r_blk(r, 0, displacement_.Size()); r_blk = res; - mfem::Vector uPlusShapeDisp(u.Size()); + serac::FiniteElementState uPlusShapeDisp(shape_displacement_.space(), "u_plus_shape_disp"); uPlusShapeDisp = u; uPlusShapeDisp.Add(1.0, shape_displacement_); @@ -145,7 +145,7 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); - mfem::Vector uPlusShapeDisp(u.Size()); + serac::FiniteElementState uPlusShapeDisp(shape_displacement_.space(), "u_plus_shape_disp"); uPlusShapeDisp = u; uPlusShapeDisp.Add(1.0, shape_displacement_); @@ -185,7 +185,7 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); - mfem::Vector uPlusShapeDisp(u.Size()); + serac::FiniteElementState uPlusShapeDisp(shape_displacement_.space(), "u_plus_shape_disp"); uPlusShapeDisp = u; uPlusShapeDisp.Add(1.0, shape_displacement_); From 4ca8daa8e9a9776699058008a7e61a0a203a4e01 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Fri, 27 Sep 2024 15:37:41 -0700 Subject: [PATCH 11/27] Fix up contact adjoint by modifying interface a bit to take shape displacements. --- src/serac/physics/contact/contact_data.cpp | 10 +++++++--- src/serac/physics/contact/contact_data.hpp | 4 ++-- src/serac/physics/solid_mechanics_contact.hpp | 15 ++------------- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/serac/physics/contact/contact_data.cpp b/src/serac/physics/contact/contact_data.cpp index c7f595bd0d..6d103b92df 100644 --- a/src/serac/physics/contact/contact_data.cpp +++ b/src/serac/physics/contact/contact_data.cpp @@ -226,7 +226,7 @@ std::unique_ptr ContactData::mergedJacobian() const return block_J; } -void ContactData::residualFunction(const mfem::Vector& u, mfem::Vector& r) +void ContactData::residualFunction(const mfem::Vector& u_shape, const mfem::Vector& u, mfem::Vector& r) { const int disp_size = reference_nodes_->ParFESpace()->GetTrueVSize(); @@ -239,7 +239,7 @@ void ContactData::residualFunction(const mfem::Vector& u, mfem::Vector& r) mfem::Vector r_blk(r, 0, disp_size); mfem::Vector g_blk(r, disp_size, numPressureDofs()); - setDisplacements(u_blk); + setDisplacements(u_shape, u_blk); // we need to call update first to update gaps update(cycle_, time_, dt_); // with updated gaps, we can update pressure for contact interactions with penalty enforcement @@ -289,10 +289,14 @@ void ContactData::setPressures(const mfem::Vector& merged_pressures) const } } -void ContactData::setDisplacements(const mfem::Vector& u) +void ContactData::setDisplacements(const mfem::Vector& shape_u, const mfem::Vector& u) { + mfem::ParGridFunction prolonged_shape_disp{current_coords_}; reference_nodes_->ParFESpace()->GetProlongationMatrix()->Mult(u, current_coords_); + reference_nodes_->ParFESpace()->GetProlongationMatrix()->Mult(shape_u, prolonged_shape_disp); + current_coords_ += *reference_nodes_; + current_coords_ += prolonged_shape_disp; } void ContactData::updateDofOffsets() const diff --git a/src/serac/physics/contact/contact_data.hpp b/src/serac/physics/contact/contact_data.hpp index 5f9a837149..b37d10d13a 100644 --- a/src/serac/physics/contact/contact_data.hpp +++ b/src/serac/physics/contact/contact_data.hpp @@ -133,7 +133,7 @@ class ContactData { * * @note This method calls update() to compute residual and Jacobian contributions based on the current configuration */ - void residualFunction(const mfem::Vector& u, mfem::Vector& r); + void residualFunction(const mfem::Vector& u_shape, const mfem::Vector& u, mfem::Vector& r); /** * @brief Computes the Jacobian including contact terms, given the non-contact Jacobian terms @@ -163,7 +163,7 @@ class ContactData { * * @param u Current displacement dof values */ - void setDisplacements(const mfem::Vector& u); + void setDisplacements(const mfem::Vector& u_shape, const mfem::Vector& u); /** * @brief Have there been contact interactions added? diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 946fd52ab6..3a5de20dd2 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -123,11 +123,8 @@ class SolidMechanicsContact, // See https://github.com/mfem/mfem/issues/3531 mfem::Vector r_blk(r, 0, displacement_.Size()); r_blk = res; - serac::FiniteElementState uPlusShapeDisp(shape_displacement_.space(), "u_plus_shape_disp"); - uPlusShapeDisp = u; - uPlusShapeDisp.Add(1.0, shape_displacement_); - contact_.residualFunction(uPlusShapeDisp, r); + contact_.residualFunction(shape_displacement_, u, r); r_blk.SetSubVector(bcs_.allEssentialTrueDofs(), 0.0); }; // This if-block below breaks up building the Jacobian operator depending if there is Lagrange multiplier @@ -145,10 +142,6 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); - serac::FiniteElementState uPlusShapeDisp(shape_displacement_.space(), "u_plus_shape_disp"); - uPlusShapeDisp = u; - uPlusShapeDisp.Add(1.0, shape_displacement_); - // create block operator holding jacobian contributions J_constraint_ = contact_.jacobianFunction(J_.release()); @@ -185,10 +178,6 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); - serac::FiniteElementState uPlusShapeDisp(shape_displacement_.space(), "u_plus_shape_disp"); - uPlusShapeDisp = u; - uPlusShapeDisp.Add(1.0, shape_displacement_); - // get 11-block holding jacobian contributions auto block_J = contact_.jacobianFunction(J_.release()); block_J->owns_blocks = false; @@ -396,7 +385,7 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); auto jacobian = assemble(drdu); - auto block_J = contact_.jacobianFunction(jacobian.release()); + auto block_J = contact_.jacobianFunction(jacobian.release()); block_J->owns_blocks = false; jacobian = std::unique_ptr(static_cast(&block_J->GetBlock(0, 0))); auto J_T = std::unique_ptr(jacobian->Transpose()); From 30883ee987dc0be787cdb90cc5db2195dfc93d05 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Fri, 27 Sep 2024 15:43:56 -0700 Subject: [PATCH 12/27] Do not change submodule yet. --- tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests b/tests index 662c093ddd..24a744dc3a 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit 662c093dddcff184983547ea0212adce3632a751 +Subproject commit 24a744dc3aa747acf343c388a2a29df7f8e74fcf From 8a68ea011af7f2de401ccb1929948b32b9ecae17 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Fri, 27 Sep 2024 15:50:18 -0700 Subject: [PATCH 13/27] Fix test pointer. --- tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests b/tests index 24a744dc3a..3915833d01 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit 24a744dc3aa747acf343c388a2a29df7f8e74fcf +Subproject commit 3915833d01199339995da39bd0238599e926022b From 07e2dbf129f1874e16e99e487cd24d3c852ee6ee Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Fri, 27 Sep 2024 15:52:52 -0700 Subject: [PATCH 14/27] Tests. --- tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests b/tests index 3915833d01..ba34e958ec 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit 3915833d01199339995da39bd0238599e926022b +Subproject commit ba34e958ec41f4a8d5d7197056cdb4acb38dd734 From 2c135806b2bdb3f3114e4c06d51ec20b4d407a1c Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Mon, 30 Sep 2024 09:18:18 -0700 Subject: [PATCH 15/27] Fix docs. --- src/serac/physics/contact/contact_data.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/serac/physics/contact/contact_data.hpp b/src/serac/physics/contact/contact_data.hpp index b37d10d13a..45f069c416 100644 --- a/src/serac/physics/contact/contact_data.hpp +++ b/src/serac/physics/contact/contact_data.hpp @@ -125,6 +125,7 @@ class ContactData { /** * @brief Computes the residual including contact terms * + * @param [in] u_shape Shape displacement vector (size of [displacement] block) * @param [in] u Solution vector ([displacement; pressure] block vector) * @param [in,out] r Residual vector ([force; gap] block vector); takes in initialized residual force vector and adds * contact contributions @@ -161,6 +162,7 @@ class ContactData { /** * @brief Update the current coordinates based on the new displacement field * + * @param u_shape Shape displacement vector * @param u Current displacement dof values */ void setDisplacements(const mfem::Vector& u_shape, const mfem::Vector& u); From 8bebe7347817f06fa876590d6a97ca59ad1d1604 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Tue, 1 Oct 2024 07:45:10 -0700 Subject: [PATCH 16/27] Use new tests submodule. --- tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests b/tests index ba34e958ec..662c093ddd 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit ba34e958ec41f4a8d5d7197056cdb4acb38dd734 +Subproject commit 662c093dddcff184983547ea0212adce3632a751 From 5761382f35feae776c678dbc81e45186b0e8c149 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Wed, 2 Oct 2024 13:37:18 -0700 Subject: [PATCH 17/27] Fix no tribol build. --- src/serac/physics/contact/contact_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serac/physics/contact/contact_data.cpp b/src/serac/physics/contact/contact_data.cpp index 6d103b92df..71f4efe1d3 100644 --- a/src/serac/physics/contact/contact_data.cpp +++ b/src/serac/physics/contact/contact_data.cpp @@ -394,7 +394,7 @@ std::unique_ptr ContactData::jacobianFunction(mfem::HyprePa void ContactData::setPressures([[maybe_unused]] const mfem::Vector& true_pressures) const {} -void ContactData::setDisplacements([[maybe_unused]] const mfem::Vector& true_displacement) {} +void ContactData::setDisplacements([[maybe_unused]] const mfem::Vector& u_shape, [[maybe_unused]] const mfem::Vector& true_displacement) {} #endif From 3af8c9f18207c663d340e4ba3a3fe07aadb42795 Mon Sep 17 00:00:00 2001 From: Agent Style Date: Thu, 3 Oct 2024 08:04:14 -0700 Subject: [PATCH 18/27] Apply style updates --- src/serac/physics/contact/contact_data.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/serac/physics/contact/contact_data.cpp b/src/serac/physics/contact/contact_data.cpp index 71f4efe1d3..7d8bbb035c 100644 --- a/src/serac/physics/contact/contact_data.cpp +++ b/src/serac/physics/contact/contact_data.cpp @@ -394,7 +394,10 @@ std::unique_ptr ContactData::jacobianFunction(mfem::HyprePa void ContactData::setPressures([[maybe_unused]] const mfem::Vector& true_pressures) const {} -void ContactData::setDisplacements([[maybe_unused]] const mfem::Vector& u_shape, [[maybe_unused]] const mfem::Vector& true_displacement) {} +void ContactData::setDisplacements([[maybe_unused]] const mfem::Vector& u_shape, + [[maybe_unused]] const mfem::Vector& true_displacement) +{ +} #endif From 68ed0374c1aeaf4cce14028300f2d0bfc841161b Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Thu, 3 Oct 2024 12:37:04 -0700 Subject: [PATCH 19/27] Try again to fix no tribol build. --- src/serac/physics/contact/contact_data.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serac/physics/contact/contact_data.cpp b/src/serac/physics/contact/contact_data.cpp index 7d8bbb035c..63a419483a 100644 --- a/src/serac/physics/contact/contact_data.cpp +++ b/src/serac/physics/contact/contact_data.cpp @@ -377,7 +377,7 @@ std::unique_ptr ContactData::mergedJacobian() const return std::make_unique(jacobian_offsets_); } -void ContactData::residualFunction([[maybe_unused]] const mfem::Vector& u, [[maybe_unused]] mfem::Vector& r) {} +void ContactData::residualFunction([[maybe_unused]] const mfem::Vector& u_shape, [[maybe_unused]] const mfem::Vector& u, [[maybe_unused]] mfem::Vector& r) {} std::unique_ptr ContactData::jacobianFunction(mfem::HypreParMatrix* orig_J) const { From 9113de27fbb4a772062eb22d12e1e93ab2b888fb Mon Sep 17 00:00:00 2001 From: Agent Style Date: Thu, 3 Oct 2024 12:38:21 -0700 Subject: [PATCH 20/27] Apply style updates --- src/serac/physics/contact/contact_data.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/serac/physics/contact/contact_data.cpp b/src/serac/physics/contact/contact_data.cpp index 63a419483a..b3b909bbf6 100644 --- a/src/serac/physics/contact/contact_data.cpp +++ b/src/serac/physics/contact/contact_data.cpp @@ -377,7 +377,10 @@ std::unique_ptr ContactData::mergedJacobian() const return std::make_unique(jacobian_offsets_); } -void ContactData::residualFunction([[maybe_unused]] const mfem::Vector& u_shape, [[maybe_unused]] const mfem::Vector& u, [[maybe_unused]] mfem::Vector& r) {} +void ContactData::residualFunction([[maybe_unused]] const mfem::Vector& u_shape, [[maybe_unused]] const mfem::Vector& u, + [[maybe_unused]] mfem::Vector& r) +{ +} std::unique_ptr ContactData::jacobianFunction(mfem::HypreParMatrix* orig_J) const { From 294653757bb631bfe865f5a5197547356a853c7b Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Thu, 21 Nov 2024 12:00:16 -0800 Subject: [PATCH 21/27] Get nonlinear adjoint tests passing again. --- src/serac/physics/solid_mechanics.cpp | 11 ++++------- src/serac/physics/solid_mechanics.hpp | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/serac/physics/solid_mechanics.cpp b/src/serac/physics/solid_mechanics.cpp index 4d49ec49b5..1a26c46479 100644 --- a/src/serac/physics/solid_mechanics.cpp +++ b/src/serac/physics/solid_mechanics.cpp @@ -15,8 +15,9 @@ namespace detail { void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, mfem::HypreParMatrix* k_mat, mfem::HypreParVector& disp_adjoint_load_vector, mfem::HypreParVector& velo_adjoint_load_vector, mfem::HypreParVector& accel_adjoint_load_vector, mfem::HypreParVector& adjoint_displacement_, - mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, - mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, + mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, + mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, + mfem::HypreParVector& adjoint_essential_, BoundaryConditionManager& bcs_, mfem::Solver& lin_solver) { // there are hard-coded here for now @@ -38,10 +39,6 @@ void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, // recall that temperature_adjoint_load_vector and d_temperature_dt_adjoint_load_vector were already multiplied by // -1 above - // By default, use a homogeneous essential boundary condition - mfem::HypreParVector adjoint_essential(adjoint_displacement_); - adjoint_essential = 0.0; - mfem::HypreParVector adjoint_rhs(accel_adjoint_load_vector); adjoint_rhs.Add(fac4 * dt_n, velo_adjoint_load_vector); adjoint_rhs.Add(fac3 * dt_n * dt_n, disp_adjoint_load_vector); @@ -51,7 +48,7 @@ void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, implicit_sensitivity_displacement_start_of_step_); for (const auto& bc : bcs_.essentials()) { - bc.apply(*J_T, adjoint_rhs, adjoint_essential); + bc.apply(*J_T, adjoint_rhs, adjoint_essential_); } lin_solver.SetOperator(*J_T); diff --git a/src/serac/physics/solid_mechanics.hpp b/src/serac/physics/solid_mechanics.hpp index 277bae4139..1154dd7bfb 100644 --- a/src/serac/physics/solid_mechanics.hpp +++ b/src/serac/physics/solid_mechanics.hpp @@ -36,8 +36,9 @@ namespace detail { void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, mfem::HypreParMatrix* k_mat, mfem::HypreParVector& disp_adjoint_load_vector, mfem::HypreParVector& velo_adjoint_load_vector, mfem::HypreParVector& accel_adjoint_load_vector, mfem::HypreParVector& adjoint_displacement_, - mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, - mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, + mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, + mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, + mfem::HypreParVector& adjoint_essential_, BoundaryConditionManager& bcs_, mfem::Solver& lin_solver); } // namespace detail @@ -1424,7 +1425,7 @@ class SolidMechanics, std::integer_se solid_mechanics::detail::adjoint_integrate( dt_n_to_np1, dt_np1_to_np2, m_mat.get(), k_mat.get(), displacement_adjoint_load_, velocity_adjoint_load_, acceleration_adjoint_load_, adjoint_displacement_, implicit_sensitivity_displacement_start_of_step_, - implicit_sensitivity_velocity_start_of_step_, bcs_, lin_solver); + implicit_sensitivity_velocity_start_of_step_, reactions_adjoint_bcs_, bcs_, lin_solver); } time_end_step_ = time_; @@ -1616,15 +1617,13 @@ class SolidMechanics, std::integer_se /// @brief Solve the Quasi-static adjoint linear virtual void quasiStaticAdjointSolve(double /*dt*/) { - // By default, use a homogeneous essential boundary condition - mfem::HypreParVector adjoint_essential(displacement_adjoint_load_); - adjoint_essential = 0.0; - auto [_, drdu] = (*residual_)(time_, shape_displacement_, differentiate_wrt(displacement_), acceleration_, *parameters_[parameter_indices].state...); J_.reset(); J_ = assemble(drdu); - auto J_T = std::unique_ptr(J_->Transpose()); + + auto J_T = std::unique_ptr(J_->Transpose()); + J_e_.reset(); J_e_ = bcs_.eliminateAllEssentialDofsFromMatrix(*J_T); @@ -1639,6 +1638,9 @@ class SolidMechanics, std::integer_se auto& lin_solver = nonlin_solver_->linearSolver(); lin_solver.SetOperator(*J_T); lin_solver.Mult(displacement_adjoint_load_, adjoint_displacement_); + + // Reset the equation solver to use the full nonlinear residual operator. MRT, is this needed? + nonlin_solver_->setOperator(*residual_with_bcs_); } /** From c910872069530151b6b919ae91a03ef3fc6d7877 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Fri, 22 Nov 2024 10:40:31 -0800 Subject: [PATCH 22/27] Refactors so that we can call contact with resets in between and get the same answer. --- src/serac/physics/contact/contact_data.cpp | 10 ++++ src/serac/physics/contact/contact_data.hpp | 6 +++ src/serac/physics/solid_mechanics_contact.hpp | 50 ++++++++++++------- .../physics/tests/contact_solid_adjoint.cpp | 9 ++-- 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/serac/physics/contact/contact_data.cpp b/src/serac/physics/contact/contact_data.cpp index b3b909bbf6..4e35a4bcff 100644 --- a/src/serac/physics/contact/contact_data.cpp +++ b/src/serac/physics/contact/contact_data.cpp @@ -41,6 +41,15 @@ void ContactData::addContactInteraction(int interaction_id, const std::set& } } +void ContactData::reset() +{ + for (auto& interaction : interactions_) { + FiniteElementState zero = interaction.pressure(); + zero = 0.0; + interaction.setPressure(zero); + } +} + void ContactData::update(int cycle, double time, double& dt) { cycle_ = cycle; @@ -240,6 +249,7 @@ void ContactData::residualFunction(const mfem::Vector& u_shape, const mfem::Vect mfem::Vector g_blk(r, disp_size, numPressureDofs()); setDisplacements(u_shape, u_blk); + // we need to call update first to update gaps update(cycle_, time_, dt_); // with updated gaps, we can update pressure for contact interactions with penalty enforcement diff --git a/src/serac/physics/contact/contact_data.hpp b/src/serac/physics/contact/contact_data.hpp index 45f069c416..e2ad3dcb8e 100644 --- a/src/serac/physics/contact/contact_data.hpp +++ b/src/serac/physics/contact/contact_data.hpp @@ -74,6 +74,12 @@ class ContactData { */ void update(int cycle, double time, double& dt); + /** + * @brief Updates the positions, forces, and Jacobian contributions associated with contact + * + */ + void reset(); + /** * @brief Get the contact constraint residual (i.e. nodal forces) from all contact interactions * diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 3a5de20dd2..4afe837a2a 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -110,6 +110,17 @@ class SolidMechanicsContact, duals_.push_back(&forces_); } + /// @overload + void resetStates(int cycle = 0, double time = 0.0) override + { + SolidMechanicsBase::resetStates(cycle, time); + forces_ = 0.0; + contact_.setDisplacements(shape_displacement_, displacement_); + contact_.reset(); + double dt = 0.0; + contact_.update(cycle, time, dt); + } + /// @brief Build the quasi-static operator corresponding to the total Lagrangian formulation std::unique_ptr buildQuasistaticOperator() override { @@ -121,7 +132,7 @@ class SolidMechanicsContact, // NOTE this copy is required as the sundials solvers do not allow move assignments because of their memory // tracking strategy // See https://github.com/mfem/mfem/issues/3531 - mfem::Vector r_blk(r, 0, displacement_.Size()); + mfem::Vector r_blk(r, 0, displacement_.space().TrueVSize()); r_blk = res; contact_.residualFunction(shape_displacement_, u, r); @@ -178,6 +189,7 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); + //contact_.setDisplacements(u_shape, u_blk); // get 11-block holding jacobian contributions auto block_J = contact_.jacobianFunction(J_.release()); block_J->owns_blocks = false; @@ -296,13 +308,30 @@ class SolidMechanicsContact, } if (use_warm_start_) { + + // Update the system residual + mfem::Vector augmented_residual(displacement_.space().TrueVSize() + contact_.numPressureDofs()); + augmented_residual = 0.0; + const mfem::Vector res = (*residual_)(time_ + dt, shape_displacement_, displacement_, acceleration_, + *parameters_[parameter_indices].state...); + + contact_.setPressures(mfem::Vector(augmented_residual, displacement_.Size(), contact_.numPressureDofs())); + contact_.update(cycle_, time_, dt); + // TODO this copy is required as the sundials solvers do not allow move assignments because of their memory + // tracking strategy + // See https://github.com/mfem/mfem/issues/3531 + mfem::Vector r_blk(augmented_residual, 0, displacement_.space().TrueVSize()); + r_blk = res; + + contact_.residualFunction(shape_displacement_, displacement_, augmented_residual); + r_blk.SetSubVector(bcs_.allEssentialTrueDofs(), 0.0); + // use the most recently evaluated Jacobian auto [_, drdu] = (*residual_)(time_, shape_displacement_, differentiate_wrt(displacement_), acceleration_, *parameters_[parameter_indices].previous_state...); J_.reset(); J_ = assemble(drdu); - contact_.update(cycle_, time_, dt); if (contact_.haveLagrangeMultipliers()) { J_offsets_ = mfem::Array({0, displacement_.Size(), displacement_.Size() + contact_.numPressureDofs()}); J_constraint_ = contact_.jacobianFunction(J_.release()); @@ -334,29 +363,16 @@ class SolidMechanicsContact, J_operator_ = J_.get(); } - // Update the linearized Jacobian matrix - mfem::Vector augmented_residual(displacement_.space().TrueVSize() + contact_.numPressureDofs()); - augmented_residual = 0.0; - const mfem::Vector res = (*residual_)(time_ + dt, shape_displacement_, displacement_, acceleration_, - *parameters_[parameter_indices].state...); - - // TODO this copy is required as the sundials solvers do not allow move assignments because of their memory - // tracking strategy - // See https://github.com/mfem/mfem/issues/3531 - mfem::Vector r(augmented_residual, 0, displacement_.space().TrueVSize()); - r = res; - r += contact_.forces(); - augmented_residual *= -1.0; mfem::Vector augmented_solution(displacement_.space().TrueVSize() + contact_.numPressureDofs()); augmented_solution = 0.0; mfem::Vector du(augmented_solution, 0, displacement_.space().TrueVSize()); du = du_; - mfem::EliminateBC(*J_, *J_e_, constrained_dofs, du, r); + mfem::EliminateBC(*J_, *J_e_, constrained_dofs, du, r_blk); for (int i = 0; i < constrained_dofs.Size(); i++) { int j = constrained_dofs[i]; - r[j] = du[j]; + r_blk[j] = du[j]; } auto& lin_solver = nonlin_solver_->linearSolver(); diff --git a/src/serac/physics/tests/contact_solid_adjoint.cpp b/src/serac/physics/tests/contact_solid_adjoint.cpp index 513fbcbf6a..1dc3d9babe 100644 --- a/src/serac/physics/tests/contact_solid_adjoint.cpp +++ b/src/serac/physics/tests/contact_solid_adjoint.cpp @@ -63,7 +63,7 @@ std::unique_ptr createContactSolver(const NonlinearSolverOptions& no auto solid = std::make_unique(nonlinear_opts, solid_mechanics::direct_linear_options, dyn_opts, - physics_prefix + std::to_string(iter++), mesh_tag); + physics_prefix + std::to_string(iter++), mesh_tag, std::vector{}, 0, 0.0, false, true); solid->setMaterial(mat); solid->setDisplacementBCs({2}, [](const mfem::Vector& /*X*/, double /*t*/, mfem::Vector& disp) { disp = 0.0; }); @@ -168,15 +168,14 @@ TEST_F(ContactSensitivityFixture, WhenShapeSensitivitiesCalledTwice_GetSameObjec { auto solid_solver = createContactSolver(nonlinear_opts, dyn_opts, mat); auto [qoi1, shape_sensitivity1] = computeContactQoiSensitivities(*solid_solver, tsInfo); + auto [qoi2, shape_sensitivity2] = computeContactQoiSensitivities(*solid_solver, tsInfo); + EXPECT_EQ(qoi1, qoi2); + solid_solver->resetStates(); FiniteElementState derivative_direction(shape_sensitivity1.space(), "derivative_direction"); fillDirection(derivative_direction); - auto [qoi2, shape_sensitivity2] = computeContactQoiSensitivities(*solid_solver, tsInfo); - - EXPECT_EQ(qoi1, qoi2); - double directional_deriv1 = innerProduct(derivative_direction, shape_sensitivity1); double directional_deriv2 = innerProduct(derivative_direction, shape_sensitivity2); EXPECT_EQ(directional_deriv1, directional_deriv2); From 6edbdc77d97a6c5fc80c09b2ccc2c092a4c2da2c Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Thu, 12 Dec 2024 11:18:52 -0800 Subject: [PATCH 23/27] Update contact adjoint after interface changes. --- src/serac/physics/tests/CMakeLists.txt | 1 + src/serac/physics/tests/contact_patch_tied.cpp | 6 +++--- src/serac/physics/tests/contact_solid_adjoint.cpp | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/serac/physics/tests/CMakeLists.txt b/src/serac/physics/tests/CMakeLists.txt index a1b24f86a6..580ae53d63 100644 --- a/src/serac/physics/tests/CMakeLists.txt +++ b/src/serac/physics/tests/CMakeLists.txt @@ -44,6 +44,7 @@ set(physics_parallel_test_sources blt_list_append(TO physics_parallel_test_sources ELEMENTS contact_patch.cpp + contact_patch_tied.cpp contact_beam.cpp contact_solid_adjoint.cpp IF TRIBOL_FOUND) diff --git a/src/serac/physics/tests/contact_patch_tied.cpp b/src/serac/physics/tests/contact_patch_tied.cpp index 0eb767cf89..fbee17b8d2 100644 --- a/src/serac/physics/tests/contact_patch_tied.cpp +++ b/src/serac/physics/tests/contact_patch_tied.cpp @@ -55,7 +55,7 @@ TEST_P(ContactPatchTied, patch) // }; // #elif defined(MFEM_USE_STRUMPACK) #ifdef MFEM_USE_STRUMPACK - LinearSolverOptions linear_options{.linear_solver = LinearSolver::Strumpack, .print_level = 1}; + LinearSolverOptions linear_options{.linear_solver = LinearSolver::Strumpack, .print_level = 0}; #else LinearSolverOptions linear_options{}; SLIC_INFO_ROOT("Contact requires MFEM built with strumpack."); @@ -64,8 +64,8 @@ TEST_P(ContactPatchTied, patch) NonlinearSolverOptions nonlinear_options{.nonlin_solver = NonlinearSolver::Newton, .relative_tol = 1.0e-10, - .absolute_tol = 1.0e-10, - .max_iterations = 20, + .absolute_tol = 5.0e-10, + .max_iterations = 25, .print_level = 1}; ContactOptions contact_options{.method = ContactMethod::SingleMortar, diff --git a/src/serac/physics/tests/contact_solid_adjoint.cpp b/src/serac/physics/tests/contact_solid_adjoint.cpp index 1dc3d9babe..61d6b1bbc4 100644 --- a/src/serac/physics/tests/contact_solid_adjoint.cpp +++ b/src/serac/physics/tests/contact_solid_adjoint.cpp @@ -64,7 +64,10 @@ std::unique_ptr createContactSolver(const NonlinearSolverOptions& no auto solid = std::make_unique(nonlinear_opts, solid_mechanics::direct_linear_options, dyn_opts, physics_prefix + std::to_string(iter++), mesh_tag, std::vector{}, 0, 0.0, false, true); - solid->setMaterial(mat); + + + Domain whole_mesh = EntireDomain(StateManager::mesh(mesh_tag)); + solid->setMaterial(mat, whole_mesh); solid->setDisplacementBCs({2}, [](const mfem::Vector& /*X*/, double /*t*/, mfem::Vector& disp) { disp = 0.0; }); solid->setDisplacementBCs({4}, [](const mfem::Vector& /*X*/, double /*t*/, mfem::Vector& disp) { From 9c4df5c7f895a6f6587b698188c7920900ed1daa Mon Sep 17 00:00:00 2001 From: Agent Style Date: Thu, 12 Dec 2024 11:20:27 -0800 Subject: [PATCH 24/27] Apply style updates --- src/serac/physics/contact/contact_data.cpp | 2 +- src/serac/physics/solid_mechanics.cpp | 4 ++-- src/serac/physics/solid_mechanics.hpp | 6 +++--- src/serac/physics/solid_mechanics_contact.hpp | 15 +++++++-------- src/serac/physics/tests/contact_solid_adjoint.cpp | 9 ++++----- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/serac/physics/contact/contact_data.cpp b/src/serac/physics/contact/contact_data.cpp index 4e35a4bcff..05fc38d9f5 100644 --- a/src/serac/physics/contact/contact_data.cpp +++ b/src/serac/physics/contact/contact_data.cpp @@ -45,7 +45,7 @@ void ContactData::reset() { for (auto& interaction : interactions_) { FiniteElementState zero = interaction.pressure(); - zero = 0.0; + zero = 0.0; interaction.setPressure(zero); } } diff --git a/src/serac/physics/solid_mechanics.cpp b/src/serac/physics/solid_mechanics.cpp index 1a26c46479..23038d99d4 100644 --- a/src/serac/physics/solid_mechanics.cpp +++ b/src/serac/physics/solid_mechanics.cpp @@ -17,8 +17,8 @@ void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, mfem::HypreParVector& accel_adjoint_load_vector, mfem::HypreParVector& adjoint_displacement_, mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, - mfem::HypreParVector& adjoint_essential_, - BoundaryConditionManager& bcs_, mfem::Solver& lin_solver) + mfem::HypreParVector& adjoint_essential_, BoundaryConditionManager& bcs_, + mfem::Solver& lin_solver) { // there are hard-coded here for now static constexpr double beta = 0.25; diff --git a/src/serac/physics/solid_mechanics.hpp b/src/serac/physics/solid_mechanics.hpp index 1154dd7bfb..f4a4f36e14 100644 --- a/src/serac/physics/solid_mechanics.hpp +++ b/src/serac/physics/solid_mechanics.hpp @@ -38,8 +38,8 @@ void adjoint_integrate(double dt_n, double dt_np1, mfem::HypreParMatrix* m_mat, mfem::HypreParVector& accel_adjoint_load_vector, mfem::HypreParVector& adjoint_displacement_, mfem::HypreParVector& implicit_sensitivity_displacement_start_of_step_, mfem::HypreParVector& implicit_sensitivity_velocity_start_of_step_, - mfem::HypreParVector& adjoint_essential_, - BoundaryConditionManager& bcs_, mfem::Solver& lin_solver); + mfem::HypreParVector& adjoint_essential_, BoundaryConditionManager& bcs_, + mfem::Solver& lin_solver); } // namespace detail /** @@ -1618,7 +1618,7 @@ class SolidMechanics, std::integer_se virtual void quasiStaticAdjointSolve(double /*dt*/) { auto [_, drdu] = (*residual_)(time_, shape_displacement_, differentiate_wrt(displacement_), acceleration_, - *parameters_[parameter_indices].state...); + *parameters_[parameter_indices].state...); J_.reset(); J_ = assemble(drdu); diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 4afe837a2a..6acfbe64e5 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -189,8 +189,8 @@ class SolidMechanicsContact, *parameters_[parameter_indices].state...); J_ = assemble(drdu); - //contact_.setDisplacements(u_shape, u_blk); - // get 11-block holding jacobian contributions + // contact_.setDisplacements(u_shape, u_blk); + // get 11-block holding jacobian contributions auto block_J = contact_.jacobianFunction(J_.release()); block_J->owns_blocks = false; J_ = std::unique_ptr(static_cast(&block_J->GetBlock(0, 0))); @@ -308,7 +308,6 @@ class SolidMechanicsContact, } if (use_warm_start_) { - // Update the system residual mfem::Vector augmented_residual(displacement_.space().TrueVSize() + contact_.numPressureDofs()); augmented_residual = 0.0; @@ -371,8 +370,8 @@ class SolidMechanicsContact, du = du_; mfem::EliminateBC(*J_, *J_e_, constrained_dofs, du, r_blk); for (int i = 0; i < constrained_dofs.Size(); i++) { - int j = constrained_dofs[i]; - r_blk[j] = du[j]; + int j = constrained_dofs[i]; + r_blk[j] = du[j]; } auto& lin_solver = nonlin_solver_->linearSolver(); @@ -386,7 +385,7 @@ class SolidMechanicsContact, displacement_ += du_; } - + /// @brief Solve the Quasi-static Newton system void quasiStaticAdjointSolve(double /*dt*/) override { @@ -424,7 +423,7 @@ class SolidMechanicsContact, auto drdshape_mat = assemble(drdshape); - auto block_J = contact_.jacobianFunction(drdshape_mat.release()); + auto block_J = contact_.jacobianFunction(drdshape_mat.release()); block_J->owns_blocks = false; drdshape_mat = std::unique_ptr(static_cast(&block_J->GetBlock(0, 0))); @@ -456,9 +455,9 @@ class SolidMechanicsContact, using SolidMechanicsBase::nonlin_solver_; using SolidMechanicsBase::residual_; using SolidMechanicsBase::residual_with_bcs_; + using SolidMechanicsBase::time_end_step_; using SolidMechanicsBase::use_warm_start_; using SolidMechanicsBase::warmStartDisplacement; - using SolidMechanicsBase::time_end_step_; /// Pointer to the Jacobian operator (J_ if no Lagrange multiplier contact, J_constraint_ otherwise) mfem::Operator* J_operator_; diff --git a/src/serac/physics/tests/contact_solid_adjoint.cpp b/src/serac/physics/tests/contact_solid_adjoint.cpp index 61d6b1bbc4..6f9559abf9 100644 --- a/src/serac/physics/tests/contact_solid_adjoint.cpp +++ b/src/serac/physics/tests/contact_solid_adjoint.cpp @@ -61,10 +61,9 @@ std::unique_ptr createContactSolver(const NonlinearSolverOptions& no { static int iter = 0; - auto solid = - std::make_unique(nonlinear_opts, solid_mechanics::direct_linear_options, dyn_opts, - physics_prefix + std::to_string(iter++), mesh_tag, std::vector{}, 0, 0.0, false, true); - + auto solid = std::make_unique(nonlinear_opts, solid_mechanics::direct_linear_options, dyn_opts, + physics_prefix + std::to_string(iter++), mesh_tag, + std::vector{}, 0, 0.0, false, true); Domain whole_mesh = EntireDomain(StateManager::mesh(mesh_tag)); solid->setMaterial(mat, whole_mesh); @@ -174,7 +173,7 @@ TEST_F(ContactSensitivityFixture, WhenShapeSensitivitiesCalledTwice_GetSameObjec auto [qoi2, shape_sensitivity2] = computeContactQoiSensitivities(*solid_solver, tsInfo); EXPECT_EQ(qoi1, qoi2); - + solid_solver->resetStates(); FiniteElementState derivative_direction(shape_sensitivity1.space(), "derivative_direction"); fillDirection(derivative_direction); From ba216738fe6706567ac25143aaa43a2841638c96 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Thu, 12 Dec 2024 11:26:05 -0800 Subject: [PATCH 25/27] Put tests back. --- tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests b/tests index 662c093ddd..57f8983b97 160000 --- a/tests +++ b/tests @@ -1 +1 @@ -Subproject commit 662c093dddcff184983547ea0212adce3632a751 +Subproject commit 57f8983b977f70445342a211c3ee5538bb81dc4f From ef1f00a79e8b66cad5c926b6b55d8bb1d04e17c4 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Thu, 12 Dec 2024 16:25:38 -0800 Subject: [PATCH 26/27] Make contact adjoint test serial for now. Maybe there is a parallel issue to address once we are further along. --- src/serac/physics/tests/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/serac/physics/tests/CMakeLists.txt b/src/serac/physics/tests/CMakeLists.txt index 580ae53d63..01b6f04371 100644 --- a/src/serac/physics/tests/CMakeLists.txt +++ b/src/serac/physics/tests/CMakeLists.txt @@ -21,6 +21,11 @@ set(physics_serial_test_sources solid_multi_material.cpp ) +blt_list_append(TO physics_serial_test_sources + ELEMENTS + contact_solid_adjoint.cpp + IF TRIBOL_FOUND) + serac_add_tests(SOURCES ${physics_serial_test_sources} DEPENDS_ON ${physics_test_depends} NUM_MPI_TASKS 1) @@ -46,7 +51,6 @@ blt_list_append(TO physics_parallel_test_sources contact_patch.cpp contact_patch_tied.cpp contact_beam.cpp - contact_solid_adjoint.cpp IF TRIBOL_FOUND) serac_add_tests(SOURCES ${physics_parallel_test_sources} From 48f8cd045e1dd6312865dd939072ddd163b682a9 Mon Sep 17 00:00:00 2001 From: Michael Tupek Date: Fri, 13 Dec 2024 12:06:36 -0800 Subject: [PATCH 27/27] Small to change to potentially fix a sporadic failure in contact beam test with multipliers. --- src/serac/physics/solid_mechanics_contact.hpp | 4 ++-- src/serac/physics/tests/contact_beam.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serac/physics/solid_mechanics_contact.hpp b/src/serac/physics/solid_mechanics_contact.hpp index 6acfbe64e5..7b47aeeb78 100644 --- a/src/serac/physics/solid_mechanics_contact.hpp +++ b/src/serac/physics/solid_mechanics_contact.hpp @@ -132,7 +132,7 @@ class SolidMechanicsContact, // NOTE this copy is required as the sundials solvers do not allow move assignments because of their memory // tracking strategy // See https://github.com/mfem/mfem/issues/3531 - mfem::Vector r_blk(r, 0, displacement_.space().TrueVSize()); + mfem::Vector r_blk(r, 0, displacement_.Size()); r_blk = res; contact_.residualFunction(shape_displacement_, u, r); @@ -309,7 +309,7 @@ class SolidMechanicsContact, if (use_warm_start_) { // Update the system residual - mfem::Vector augmented_residual(displacement_.space().TrueVSize() + contact_.numPressureDofs()); + mfem::Vector augmented_residual(displacement_.Size() + contact_.numPressureDofs()); augmented_residual = 0.0; const mfem::Vector res = (*residual_)(time_ + dt, shape_displacement_, displacement_, acceleration_, *parameters_[parameter_indices].state...); diff --git a/src/serac/physics/tests/contact_beam.cpp b/src/serac/physics/tests/contact_beam.cpp index daf0718840..3ccc18cf5b 100644 --- a/src/serac/physics/tests/contact_beam.cpp +++ b/src/serac/physics/tests/contact_beam.cpp @@ -42,7 +42,7 @@ TEST_P(ContactTest, beam) auto mesh = mesh::refineAndDistribute(buildMeshFromFile(filename), 1, 0); auto& pmesh = serac::StateManager::setMesh(std::move(mesh), "beam_mesh"); - LinearSolverOptions linear_options{.linear_solver = LinearSolver::Strumpack, .print_level = 1}; + LinearSolverOptions linear_options{.linear_solver = LinearSolver::Strumpack, .print_level = 0}; #ifndef MFEM_USE_STRUMPACK SLIC_INFO_ROOT("Contact requires MFEM built with strumpack."); return;