Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9709caf
Implicit coupling of active stress and struct
michelebucelli Sep 8, 2026
5d8615d
Aitken relaxation for active stress-struct implicit coupling
michelebucelli Sep 8, 2026
76a5e47
Implement global Aitken relaxation for active stress-struct coupling
michelebucelli Sep 8, 2026
018dd8f
Unified active stress between the different constitutive models
michelebucelli Sep 9, 2026
3ad2ec4
Add tangent of direct dependence of active tension on displacement
michelebucelli Sep 10, 2026
eb31d46
Rename 'implicit coupling' to 'implicit state coupling' in active stress
michelebucelli Sep 10, 2026
94108d1
WIP: code cleanup of implicit active tension evaluation
michelebucelli Sep 10, 2026
3c1dd6a
Further cleanup of implicit active tension coupling
michelebucelli Sep 10, 2026
a538f77
Fix typos in test_material_common.h
michelebucelli Sep 17, 2026
f31afbd
Update reference solutions of tests affected by changed active stress…
michelebucelli Sep 21, 2026
9a92447
Update reference solutions of tests affected by changed active stress…
michelebucelli Sep 21, 2026
2b367fb
Fix assertions checking fiber direction availability in compute_p2kcc
michelebucelli Sep 21, 2026
34f83f8
Cleanup cc_to_voigt_eigen
michelebucelli Sep 21, 2026
cd2777a
Cleanup tangent computation for active stress tensor
michelebucelli Sep 21, 2026
d14c509
Restore accidentally deleted todo comment
michelebucelli Sep 21, 2026
aacf029
Split time advancing of active stress to its own Integrator::time_adv…
michelebucelli Sep 21, 2026
1e2ea20
Nodal active tension only evaulated when writing output
michelebucelli Sep 22, 2026
40df8bc
Update slab_Regazzoni reference solution after changes in active tens…
michelebucelli Sep 22, 2026
1008fea
Merge branch 'main' into experiment/implicit-force-length-feedback-ne…
michelebucelli Sep 28, 2026
0dbb465
Remove unused argument Tfa from ArtificialNeuralNetMaterial::computeI…
michelebucelli Sep 28, 2026
bf75a63
Remove unused cemModelType class
michelebucelli Sep 28, 2026
bc79303
Integrator::update_active_stress only updates implicitly-coupled doma…
michelebucelli Sep 28, 2026
a921e78
Active stress unit test compares active tension derivative with finit…
michelebucelli Sep 28, 2026
f430b28
Merge branch 'main' into experiment/implicit-force-length-feedback-ne…
michelebucelli Oct 9, 2026
90ce27a
ActiveStress::Evaluator uses Eigen matrices and vectors, following st…
michelebucelli Oct 9, 2026
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
76 changes: 67 additions & 9 deletions Code/Source/solver/ActiveStress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,71 @@

#include "ActiveStress.h"

#include "mat_fun.h"

bool supports_active_stress(const consts::EquationType eq_type) {
return eq_type == consts::EquationType::phys_struct ||
eq_type == consts::EquationType::phys_ustruct ||
eq_type == consts::EquationType::phys_FSI;
}

void ActiveStress::Evaluator::update(const ActiveStress &active_stress,
const Vector<int> &nodes) {
active_stress_ = &active_stress;

const unsigned int n_states = active_stress.n_states;

state_.resize(n_states, nodes.size());

// Vector::resize reallocates even when the size is unchanged.
if (interpolated_state.size() != n_states)
interpolated_state.resize(n_states);

// Friend access to active_stress.states, so that gathering the state of an
// element does not need to go through an accessor.
for (int a = 0; a < nodes.size(); ++a)
for (unsigned int j = 0; j < n_states; ++j)
state_(j, a) = active_stress.states(j, nodes(a));
Comment thread
michelebucelli marked this conversation as resolved.
}

template <int nsd>
ActiveStress::ActiveTension ActiveStress::Evaluator::evaluate(
const Eigen::Ref<const Eigen::VectorXd> &N, const mat_fun::Matrix<nsd> &F,
const Eigen::Ref<const Eigen::Matrix<double, nsd, Eigen::Dynamic>> &fN)
const {
if (active_stress_ == nullptr)
return {};

// The fiber stretch is only computed for the models that use it. Besides
// saving the work, this keeps the other models usable on a mesh with no fiber
// directions, where fN is zero and the stretch would come out zero too.
double fiber_stretch = 1.0;

if (active_stress_->needs_fiber_stretch())
fiber_stretch = (F * fN.col(0)).norm();

// Interpolate the nodal state to the quadrature point.
Eigen::Map<Eigen::VectorXd>(interpolated_state.data(),
interpolated_state.size()) = state_ * N;

return active_stress_->compute_tension(interpolated_state, fiber_stretch);
}

template ActiveStress::ActiveTension ActiveStress::Evaluator::evaluate<2>(
const Eigen::Ref<const Eigen::VectorXd> &, const mat_fun::Matrix<2> &,
const Eigen::Ref<const Eigen::Matrix<double, 2, Eigen::Dynamic>> &) const;

template ActiveStress::ActiveTension ActiveStress::Evaluator::evaluate<3>(
const Eigen::Ref<const Eigen::VectorXd> &, const mat_fun::Matrix<3> &,
const Eigen::Ref<const Eigen::Matrix<double, 3, Eigen::Dynamic>> &) const;

void ActiveStress::read_parameters(const ActiveStressParameters &params) {
eta_f = params.get_eta_f();
eta_s = params.get_eta_s();
eta_n = params.get_eta_n();

implicit_state_coupling_ = params.get_implicit_state_coupling();

read_model_specific_parameters(
params.get_parameters(params.get_model_name()));
}
Expand All @@ -24,6 +78,8 @@ void ActiveStress::distribute_parameters(const CmMod &cm_mod,
cm.bcast(cm_mod, &eta_s);
cm.bcast(cm_mod, &eta_n);

cm.bcast(cm_mod, &implicit_state_coupling_);

distribute_model_specific_parameters(cm_mod, cm);
}

Expand All @@ -39,21 +95,23 @@ void ActiveStress::init(const unsigned int tnNo) {
states(j, i) = state_loc(j);
}

active_tension.resize(tnNo);
states_at_time_step_start.resize(n_states, tnNo);
states_at_time_step_start = states;
}

void ActiveStress::advance_time_step(const double t, const double dt,
const Vector<double> &calcium,
const Vector<double> &fiber_stretch,
const Vector<double> &fiber_stretch_rate) {
void ActiveStress::time_advance() { states_at_time_step_start = states; }

void ActiveStress::update(const double t, const double dt,
const Vector<double> &calcium,
const Vector<double> &fiber_stretch,
const Vector<double> &fiber_stretch_rate) {
time = t;

for (unsigned int i = 0; i < states.ncols(); ++i) {
Vector<double> state_loc = states.col(i);
// Advance the state from the beginning of the time step.
for (int i = 0; i < states.ncols(); ++i) {
Vector<double> state_loc = states_at_time_step_start.col(i);
advance_time_step_local(t, dt, calcium[i], fiber_stretch[i],
fiber_stretch_rate[i], state_loc);
states.set_col(i, state_loc);

active_tension[i] = compute_active_tension_local(state_loc, fiber_stretch[i]);
}
}
Loading
Loading