275 * <a name=
"Linear_active_muscle_model.cc-Includefiles"></a>
276 * <h3>Include files</h3>
282 * #include <deal.II/base/quadrature_lib.h>
283 * #include <deal.II/base/function.h>
284 * #include <deal.II/base/logstream.h>
285 * #include <deal.II/base/parameter_handler.h>
286 * #include <deal.II/lac/affine_constraints.h>
287 * #include <deal.II/lac/vector.h>
288 * #include <deal.II/lac/full_matrix.h>
289 * #include <deal.II/lac/sparse_matrix.h>
290 * #include <deal.II/lac/solver_cg.h>
291 * #include <deal.II/lac/precondition.h>
292 * #include <deal.II/grid/grid_out.h>
293 * #include <deal.II/grid/manifold_lib.h>
294 * #include <deal.II/grid/tria.h>
295 * #include <deal.II/grid/grid_generator.h>
296 * #include <deal.II/grid/grid_refinement.h>
297 * #include <deal.II/grid/grid_tools.h>
298 * #include <deal.II/grid/tria_accessor.h>
299 * #include <deal.II/grid/tria_iterator.h>
300 * #include <deal.II/dofs/dof_handler.h>
301 * #include <deal.II/dofs/dof_accessor.h>
302 * #include <deal.II/dofs/dof_tools.h>
303 * #include <deal.II/fe/fe_values.h>
304 * #include <deal.II/fe/fe_system.h>
305 * #include <deal.II/fe/fe_q.h>
306 * #include <deal.II/numerics/vector_tools.h>
307 * #include <deal.II/numerics/matrix_tools.h>
308 * #include <deal.II/numerics/data_out.h>
309 * #include <deal.II/numerics/error_estimator.h>
310 * #include <deal.II/physics/transformations.h>
313 * #include <iostream>
323 * <a name=
"Linear_active_muscle_model.cc-Runtimeparameters"></a>
324 * <h3>Run-time parameters</h3>
328 * There are several parameters that can be
set in the code so we
set up a
332 *
namespace Parameters
337 * <a name=
"Linear_active_muscle_model.cc-FiniteElementsystem"></a>
338 * <h4>Finite Element system</h4>
342 * Here we specify the polynomial order used to
approximate the solution.
343 * The quadrature order should be adjusted accordingly.
348 *
unsigned int poly_degree;
349 *
unsigned int quad_order;
360 * prm.enter_subsection(
"Finite element system");
362 * prm.declare_entry(
"Polynomial degree",
"1",
364 *
"Displacement system polynomial order");
366 * prm.declare_entry(
"Quadrature order",
"2",
368 *
"Gauss quadrature order");
370 * prm.leave_subsection();
375 * prm.enter_subsection(
"Finite element system");
377 * poly_degree = prm.get_integer(
"Polynomial degree");
378 * quad_order = prm.get_integer(
"Quadrature order");
380 * prm.leave_subsection();
386 * <a name=
"Linear_active_muscle_model.cc-Problem"></a>
391 * Choose which problem is going to be solved
396 * std::string problem;
407 * prm.enter_subsection(
"Problem");
409 * prm.declare_entry(
"Problem",
"IsotonicContraction",
411 *
"The problem that is to be solved");
413 * prm.leave_subsection();
418 * prm.enter_subsection(
"Problem");
420 * problem = prm.get(
"Problem");
422 * prm.leave_subsection();
428 * <a name=
"Linear_active_muscle_model.cc-IsotonicContractionGeometry"></a>
429 * <h4>IsotonicContractionGeometry</h4>
433 * Make adjustments to the geometry and discretisation of the
434 * isotonic contraction model from Martins2006.
440 *
struct IsotonicContraction
442 *
const double half_length_x = 10
e-3/2.0;
443 *
const double half_length_y = 10
e-3/2.0;
444 *
const double half_length_z = 1
e-3/2.0;
469 * <a name=
"Linear_active_muscle_model.cc-BicepsBrachiiGeometry"></a>
470 * <h4>BicepsBrachiiGeometry</h4>
474 * Make adjustments to the geometry and discretisation of the
481 *
struct BicepsBrachii
483 *
double axial_length;
484 *
double radius_insertion_origin;
485 *
double radius_midpoint;
487 *
unsigned int elements_along_axis;
488 *
unsigned int n_refinements_radial;
489 *
bool include_gravity;
490 *
double axial_force;
505 * prm.enter_subsection(
"Biceps Brachii geometry");
507 * prm.declare_entry(
"Axial length",
"250",
509 *
"Axial length of the muscle");
511 * prm.declare_entry(
"Radius insertion and origin",
"5",
513 *
"Insertion and origin radius");
515 * prm.declare_entry(
"Radius midpoint",
"7.5",
517 *
"Radius at the midpoint of the muscle");
519 * prm.declare_entry(
"Grid scale",
"1e-3",
521 *
"Global grid scaling factor");
523 * prm.declare_entry(
"Elements along axis",
"32",
525 *
"Number of elements along the muscle axis");
527 * prm.declare_entry(
"Radial refinements",
"4",
529 *
"Control the discretisation in the radial direction");
531 * prm.declare_entry(
"Gravity",
"false",
533 *
"Include the effects of gravity (in the y-direction; "
534 *
" perpendicular to the muscle axis)");
536 * prm.declare_entry(
"Axial force",
"1",
538 *
"Applied distributed axial force (in Newtons)");
540 * prm.leave_subsection();
545 * prm.enter_subsection(
"Biceps Brachii geometry");
547 * axial_length = prm.get_double(
"Axial length");
548 * radius_insertion_origin = prm.get_double(
"Radius insertion and origin");
549 * radius_midpoint = prm.get_double(
"Radius midpoint");
550 *
scale = prm.get_double(
"Grid scale");
551 * elements_along_axis = prm.get_integer(
"Elements along axis");
552 * n_refinements_radial = prm.get_integer(
"Radial refinements");
553 * include_gravity = prm.get_bool(
"Gravity");
554 * axial_force = prm.get_double(
"Axial force");
556 * prm.leave_subsection();
558 *
AssertThrow(radius_midpoint >= radius_insertion_origin,
559 * ExcMessage(
"Unrealistic geometry"));
565 * <a name=
"Linear_active_muscle_model.cc-Neurologicalsignal"></a>
566 * <h4>Neurological signal</h4>
572 *
struct NeurologicalSignal
574 *
double neural_signal_start_time;
575 *
double neural_signal_end_time;
586 * prm.enter_subsection(
"Neurological signal");
588 * prm.declare_entry(
"Start time",
"1.0",
590 *
"Time at which to start muscle activation");
592 * prm.declare_entry(
"End time",
"2.0",
594 *
"Time at which to remove muscle activation signal");
596 * prm.leave_subsection();
601 * prm.enter_subsection(
"Neurological signal");
603 * neural_signal_start_time = prm.get_double(
"Start time");
604 * neural_signal_end_time = prm.get_double(
"End time");
606 * prm.leave_subsection();
608 *
Assert(neural_signal_start_time < neural_signal_end_time,
609 * ExcMessage(
"Invalid neural signal times."));
615 * <a name=
"Linear_active_muscle_model.cc-Time"></a>
620 * Set the timestep size @f$ \varDelta t @f$ and the simulation
end-time.
627 *
double end_ramp_time;
638 * prm.enter_subsection(
"Time");
640 * prm.declare_entry(
"End time",
"3",
644 * prm.declare_entry(
"End ramp time",
"1",
646 *
"Force ramp end time");
648 * prm.declare_entry(
"Time step size",
"0.1",
652 * prm.leave_subsection();
657 * prm.enter_subsection(
"Time");
659 * end_time = prm.get_double(
"End time");
660 * end_ramp_time = prm.get_double(
"End ramp time");
661 * delta_t = prm.get_double(
"Time step size");
663 * prm.leave_subsection();
669 * <a name=
"Linear_active_muscle_model.cc-Allparameters"></a>
670 * <h4>All parameters</h4>
674 * Finally we consolidate all of the above structures into a single container
675 * that holds all of our
run-time selections.
678 *
struct AllParameters :
public FESystem,
680 *
public IsotonicContraction,
681 *
public BicepsBrachii,
682 *
public NeurologicalSignal,
685 * AllParameters(
const std::string &input_file);
694 * AllParameters::AllParameters(
const std::string &input_file)
697 * declare_parameters(prm);
698 * prm.parse_input(input_file);
699 * parse_parameters(prm);
704 * FESystem::declare_parameters(prm);
705 * Problem::declare_parameters(prm);
706 * IsotonicContraction::declare_parameters(prm);
707 * BicepsBrachii::declare_parameters(prm);
708 * NeurologicalSignal::declare_parameters(prm);
709 * Time::declare_parameters(prm);
714 * FESystem::parse_parameters(prm);
715 * Problem::parse_parameters(prm);
716 * IsotonicContraction::parse_parameters(prm);
717 * BicepsBrachii::parse_parameters(prm);
718 * NeurologicalSignal::parse_parameters(prm);
719 * Time::parse_parameters(prm);
723 * Override time setting
for test defined
727 *
if (problem ==
"IsotonicContraction")
730 * end_ramp_time = 1.0;
733 * neural_signal_start_time = 1.0;
734 * neural_signal_end_time = 2.0;
742 * <a name=
"Linear_active_muscle_model.cc-Bodyforcevalues"></a>
743 * <h3>Body force values</h3>
750 *
class BodyForce :
public Function<dim>
753 * BodyForce (
const double rho,
755 *
virtual ~BodyForce () {}
770 * BodyForce<dim>::BodyForce (
const double rho,
778 *
Assert(M.norm() == 1.0, ExcMessage(
"Direction vector is not a unit vector"));
784 *
void BodyForce<dim>::vector_value (
const Point<dim> &,
787 *
Assert (values.size() == dim,
788 * ExcDimensionMismatch (values.size(), dim));
789 *
Assert (dim >= 2, ExcNotImplemented());
790 *
for (
unsigned int d=0;
d<dim; ++
d)
792 * values(d) = rho*g*M[
d];
798 *
void BodyForce<dim>::vector_value_list (
const std::vector<
Point<dim> > &points,
801 *
Assert (value_list.size() == points.size(),
802 * ExcDimensionMismatch (value_list.size(), points.size()));
804 *
const unsigned int n_points = points.size();
806 *
for (
unsigned int p=0; p<n_points; ++p)
807 * BodyForce<dim>::vector_value (points[p],
812 *
class Traction :
public Function<dim>
815 * Traction (
const double force,
816 *
const double area);
817 *
virtual ~Traction () {}
830 * Traction<dim>::Traction (
const double force,
840 *
void Traction<dim>::vector_value (
const Point<dim> &,
843 *
Assert (values.size() == dim,
844 * ExcDimensionMismatch (values.size(), dim));
845 *
Assert (dim == 3, ExcNotImplemented());
849 * Assume uniform distributed load
859 *
void Traction<dim>::vector_value_list (
const std::vector<
Point<dim> > &points,
862 *
Assert (value_list.size() == points.size(),
863 * ExcDimensionMismatch (value_list.size(), points.size()));
865 *
const unsigned int n_points = points.size();
867 *
for (
unsigned int p=0; p<n_points; ++p)
868 * Traction<dim>::vector_value (points[p],
875 * <a name=
"Linear_active_muscle_model.cc-Utilityfunctions"></a>
886 *
Assert (grad.size() == dim, ExcInternalError());
889 *
for (
unsigned int i=0; i<dim; ++i)
890 *
for (
unsigned int j=0; j<dim; ++j)
891 * F[i][j] += grad[i][j];
899 *
Assert (grad.size() == dim, ExcInternalError());
902 *
for (
unsigned int i=0; i<dim; ++i)
903 * strain[i][i] = grad[i][i];
905 *
for (
unsigned int i=0; i<dim; ++i)
906 *
for (
unsigned int j=i+1; j<dim; ++j)
907 * strain[i][j] = (grad[i][j] + grad[j][i]) / 2;
914 * <a name=
"Linear_active_muscle_model.cc-Propertiesformusclematrix"></a>
915 * <h3>Properties
for muscle
matrix</h3>
921 *
struct MuscleMatrix
923 *
static const double E;
924 *
static const double nu;
926 *
static const double mu;
927 *
static const double lambda;
930 *
const double MuscleMatrix::E = 26e3;
931 *
const double MuscleMatrix::nu = 0.45;
932 *
const double MuscleMatrix::mu = MuscleMatrix::E/(2.0*(1.0 + MuscleMatrix::nu));
933 *
const double MuscleMatrix::lambda = 2.0*MuscleMatrix::mu *MuscleMatrix::nu/(1.0 - 2.0*MuscleMatrix::nu);
938 * <a name=
"Linear_active_muscle_model.cc-Localdataformusclefibres"></a>
939 * <h3>Local data
for muscle fibres</h3>
945 * #define convert_gf_to_N 1.0/101.97
946 * #define convert_gf_per_cm2_to_N_per_m2 convert_gf_to_N*1e2*1e2
947 * #define T0 6280.0*convert_gf_per_cm2_to_N_per_m2
951 * A
struct that governs the functioning of a single muscle fibre
962 * epsilon_c_t1 (0.0),
963 * epsilon_c_dot (0.0)
974 * epsilon_c_t1 (0.0),
975 * epsilon_c_dot (0.0)
978 * ExcMessage(
"Fibre direction is not a unit vector"));
981 *
void update_alpha (
const double u,
991 *
double get_m_p ()
const;
992 *
double get_m_s ()
const;
993 *
double get_beta (
const double dt)
const;
994 *
double get_gamma (
const double dt)
const;
1001 *
const double &get_alpha() const
1005 *
const double &get_epsilon_f() const
1009 *
const double &get_epsilon_c() const
1013 *
const double &get_epsilon_c_dot() const
1015 *
return epsilon_c_dot;
1026 *
double epsilon_c_t1;
1027 *
double epsilon_c_dot;
1029 *
double get_f_c_L ()
const;
1030 *
double get_m_c_V ()
const;
1031 *
double get_c_c_V ()
const;
1034 *
template <
int dim>
1035 *
void MuscleFibre<dim>::update_alpha (
const double u,
1038 *
static const double tau_r = 0.15;
1039 *
static const double tau_f = 0.15;
1040 *
static const double alpha_min = 0;
1043 * alpha = (alpha_t1*tau_r*tau_f + dt*tau_f) / (tau_r*tau_f + dt*tau_f);
1045 * alpha = (alpha_t1*tau_r*tau_f + dt*alpha_min*tau_r) / (tau_r*tau_f + dt*tau_r);
1048 *
const double b = 1.0/tau_r - 1.0/tau_f;
1049 *
const double c = 1.0/tau_f;
1050 *
const double d = alpha_min/tau_f;
1051 *
const double f1 = 1.0/tau_r - alpha_min/tau_f;
1052 *
const double p =
b*u + c;
1053 *
const double q = f1*u +
d;
1055 * alpha = (q*dt + alpha_t1)/(1.0 + p*dt);
1060 *
template <
int dim>
1061 *
double MuscleFibre<dim>::get_m_p () const
1063 *
static const double A = 8.568e-4*convert_gf_per_cm2_to_N_per_m2;
1064 *
static const double a = 12.43;
1065 *
if (epsilon_f >= 0.0)
1069 * 100 times more compliant than Martins2006
1072 *
static const double m_p = 2.0*A*a/1e2;
1079 *
template <
int dim>
1080 *
double MuscleFibre<dim>::get_m_s (
void)
const
1082 *
const double epsilon_s = epsilon_f - epsilon_c;
1083 *
if (epsilon_s >= -1e-6)
1089 *
template <
int dim>
1090 *
double MuscleFibre<dim>::get_f_c_L (
void)
const
1092 *
if (epsilon_c <= 0.5 && epsilon_c >= -0.5)
1098 *
template <
int dim>
1099 *
double MuscleFibre<dim>::get_m_c_V (
void)
const
1101 *
if (epsilon_c_dot < -5.0)
1103 *
else if (epsilon_c_dot <= 3.0)
1109 *
template <
int dim>
1110 *
double MuscleFibre<dim>::get_c_c_V (
void)
const
1112 *
if (epsilon_c_dot < -5.0)
1114 *
else if (epsilon_c_dot <= 3.0)
1120 *
template <
int dim>
1121 *
double MuscleFibre<dim>::get_beta(
const double dt)
const
1123 *
return get_f_c_L()*get_m_c_V()*alpha/dt + get_m_s();
1126 *
template <
int dim>
1127 *
double MuscleFibre<dim>::get_gamma(
const double dt)
const
1129 *
return get_f_c_L()*alpha*(get_m_c_V()*epsilon_c_t1/dt - get_c_c_V());
1132 *
template <
int dim>
1138 * Values from previous state
1139 * These were the values that were used in the assembly,
1140 * so we must use them in the update step to be consistent.
1141 * Need to compute these before we overwrite epsilon_c_t1
1144 *
const double m_s = get_m_s();
1145 *
const double beta = get_beta(dt);
1146 *
const double gamma = get_gamma(dt);
1150 * Update current state
1154 * epsilon_f = M*
static_cast< Tensor<2,dim> >(strain_tensor)*M;
1155 * epsilon_c_t1 = epsilon_c;
1156 * epsilon_c = (m_s*epsilon_f +
gamma)/beta;
1157 * epsilon_c_dot = (epsilon_c - epsilon_c_t1)/dt;
1164 * <a name=
"Linear_active_muscle_model.cc-ThecodeLinearMuscleModelProblemcodeclasstemplate"></a>
1165 * <h3>The <code>LinearMuscleModelProblem</code>
class template</h3>
1171 *
template <
int dim>
1172 *
class LinearMuscleModelProblem
1175 * LinearMuscleModelProblem (
const std::string &input_file);
1176 * ~LinearMuscleModelProblem ();
1180 *
void make_grid ();
1181 *
void setup_muscle_fibres ();
1182 *
double get_neural_signal (
const double time);
1183 *
void update_fibre_activation (
const double time);
1184 *
void update_fibre_state ();
1185 *
void setup_system ();
1186 *
void assemble_system (
const double time);
1187 *
void apply_boundary_conditions ();
1189 *
void output_results (
const unsigned int timestep,
1190 *
const double time)
const;
1192 * Parameters::AllParameters parameters;
1214 *
const double t_end;
1216 *
const double t_ramp_end;
1223 *
const BodyForce<dim> body_force;
1224 *
const Traction<dim> traction;
1231 * std::vector< std::vector<MuscleFibre<dim> > > fibre_data;
1239 *
const unsigned int q_point_cell)
const;
1241 *
const unsigned int q_point_cell)
const;
1247 * <a name=
"Linear_active_muscle_model.cc-LinearMuscleModelProblemLinearMuscleModelProblem"></a>
1248 * <h4>LinearMuscleModelProblem::LinearMuscleModelProblem</h4>
1254 *
template <
int dim>
1255 * LinearMuscleModelProblem<dim>::LinearMuscleModelProblem (
const std::string &input_file)
1257 * parameters(input_file),
1259 * fe (
FE_Q<dim>(parameters.poly_degree), dim),
1260 * qf_cell (parameters.quad_order),
1261 * qf_face (parameters.quad_order),
1262 * t_end (parameters.end_time),
1263 * dt (parameters.delta_t),
1264 * t_ramp_end(parameters.end_ramp_time),
1265 * body_force ((parameters.problem ==
"BicepsBrachii" &¶meters.include_gravity ==
true) ?
1267 * BodyForce<dim>(0.0,
Tensor<1,dim>({0,0,1})) ),
1268 * traction (parameters.problem ==
"BicepsBrachii" ?
1269 * Traction<dim>(parameters.axial_force,
1270 * M_PI*
std::pow(parameters.radius_insertion_origin *parameters.scale,2.0) ) :
1271 * Traction<dim>(4.9*convert_gf_to_N,
1272 * (2.0*parameters.half_length_y)*(2.0*parameters.half_length_z)) )
1274 *
Assert(dim==3, ExcNotImplemented());
1281 * <a name=
"Linear_active_muscle_model.cc-LinearMuscleModelProblemLinearMuscleModelProblem"></a>
1282 * <h4>LinearMuscleModelProblem::~LinearMuscleModelProblem</h4>
1288 *
template <
int dim>
1289 * LinearMuscleModelProblem<dim>::~LinearMuscleModelProblem ()
1291 * dof_handler.clear ();
1298 * <a name=
"Linear_active_muscle_model.cc-LinearMuscleModelProblemmake_grid"></a>
1299 * <h4>LinearMuscleModelProblem::make_grid</h4>
1306 *
struct BicepsGeometry
1308 * BicepsGeometry(
const double axial_length,
1309 *
const double radius_ins_orig,
1310 *
const double radius_mid)
1312 * ax_lgth (axial_length),
1313 * r_ins_orig (radius_ins_orig),
1314 * r_mid (radius_mid)
1319 * The radial profile of the muscle
1320 * This provides the
new coordinates
for points @p pt
1321 * on a
cylinder of radius r_ins_orig and length
1322 * ax_lgth to be moved to in order to create the
1323 * physiologically representative geometry of
1329 *
Assert(pt_0[0] > -1e-6,
1330 * ExcMessage(
"All points must have x-coordinate > 0"));
1332 *
const double r_scale = get_radial_scaling_factor(pt_0[0]);
1333 *
return pt_0 +
Point<dim>(0.0, r_scale*pt_0[1], r_scale*pt_0[2]);
1338 *
return profile(pt);
1343 * Provides the muscle direction at the
point @p pt
1344 * in the real geometry (one that has undergone the
1345 * transformation given by the profile() function)
1346 * and subsequent grid rescaling.
1347 * The directions are given by the
gradient of the
1348 * transformation function (i.e. the fibres are
1349 * orientated by the curvature of the muscle).
1354 * to the original
point on the completely unscaled
1355 * cylindrical grid. We then evaluate the transformation
1356 * at two points (axially displaced) very close to the
1357 *
point of interest. The normalised vector joining the
1358 * transformed counterparts of the perturbed points is
1359 * the
gradient of the transformation function and,
1360 * thus, defines the fibre direction.
1364 *
const double &grid_scale)
const
1366 *
const Point<dim> pt = (1.0/grid_scale)*pt_scaled;
1369 *
static const double eps = 1
e-6;
1372 *
const Point<dim> pt_eps_p = profile(pt_0_eps_p);
1373 *
const Point<dim> pt_eps_m = profile(pt_0_eps_m);
1375 *
static const double tol = 1
e-9;
1377 *
Assert(profile(pt_0).distance(pt) < tol, ExcInternalError());
1378 *
Assert(inv_profile(pt_eps_p).distance(pt_0_eps_p) < tol, ExcInternalError());
1379 *
Assert(inv_profile(pt_eps_m).distance(pt_0_eps_m) < tol, ExcInternalError());
1382 * dir /= dir.
norm();
1387 *
const double ax_lgth;
1388 *
const double r_ins_orig;
1389 *
const double r_mid;
1391 *
double get_radial_scaling_factor (
const double &x)
const
1395 * Expect all grid points with X>=0, but we provide a
1396 * tolerant location
for points
"on" the Cartesian plane X=0
1399 *
const double lgth_frac =
std::max(x/ax_lgth,0.0);
1400 *
const double amplitude = 0.25*(r_mid - r_ins_orig);
1401 *
const double phase_shift = M_PI;
1402 *
const double y_shift = 1.0;
1403 *
const double wave_func = y_shift +
std::cos(phase_shift + 2.0*M_PI*lgth_frac);
1404 *
Assert(wave_func >= 0.0, ExcInternalError());
1405 *
return std::sqrt(amplitude*wave_func);
1411 * ExcMessage(
"All points must have x-coordinate > 0"));
1413 *
const double r_scale = get_radial_scaling_factor(pt[0]);
1414 *
const double trans_inv_scale = 1.0/(1.0+r_scale);
1415 *
return Point<dim>(pt[0], trans_inv_scale*pt[1], trans_inv_scale*pt[2]);
1419 *
template <
int dim>
1420 *
void LinearMuscleModelProblem<dim>::make_grid ()
1422 *
Assert (dim == 3, ExcNotImplemented());
1424 *
if (parameters.problem ==
"IsotonicContraction")
1426 *
const Point<dim> p1(-parameters.half_length_x,
1427 * -parameters.half_length_y,
1428 * -parameters.half_length_z);
1429 *
const Point<dim> p2( parameters.half_length_x,
1430 * parameters.half_length_y,
1431 * parameters.half_length_z);
1437 *
for (; cell != endc; ++cell)
1439 *
for (
unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
1441 *
if (cell->face(face)->at_boundary() ==
true)
1443 *
if (cell->face(face)->center()[0] == -parameters.half_length_x)
1444 * cell->face(face)->set_boundary_id(parameters.bid_CC_dirichlet_symm_X);
1445 *
else if (cell->face(face)->center()[0] == parameters.half_length_x)
1446 * cell->face(face)->set_boundary_id(parameters.bid_CC_neumann);
1447 *
else if (
std::abs(cell->face(face)->center()[2]) == parameters.half_length_z)
1448 * cell->face(face)->set_boundary_id(parameters.bid_CC_dirichlet_symm_Z);
1455 *
else if (parameters.problem ==
"BicepsBrachii")
1461 * parameters.radius_insertion_origin);
1463 * cell = tria_cap.begin_active();
1464 * cell != tria_cap.end(); ++cell)
1466 *
for (
unsigned int face = 0; face < GeometryInfo<2>::faces_per_cell; ++face)
1468 *
if (cell->face(face)->at_boundary() ==
true)
1469 * cell->face(face)->set_all_manifold_ids(0);
1472 * tria_cap.set_manifold (0, manifold_cap);
1473 * tria_cap.refine_global(parameters.n_refinements_radial);
1479 * parameters.elements_along_axis,
1480 * parameters.axial_length,
1494 * Rotate grid so that the length is axially
1495 * coincident and aligned with the X-axis
1502 * Deform the grid into something that vaguely
1503 * resemble
's a Biceps Brachii
1506 * GridTools::transform (BicepsGeometry<dim>(parameters.axial_length,
1507 * parameters.radius_insertion_origin,
1508 * parameters.radius_midpoint), triangulation);
1515 * typename Triangulation<dim>::active_cell_iterator cell =
1516 * triangulation.begin_active(), endc = triangulation.end();
1517 * for (; cell != endc; ++cell)
1519 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
1521 * if (cell->face(face)->at_boundary() == true)
1523 * static const double tol =1e-6;
1524 * if (std::abs(cell->face(face)->center()[0]) < tol) // -X oriented face
1525 * cell->face(face)->set_boundary_id(parameters.bid_BB_dirichlet_X); // Dirichlet
1526 * else if (std::abs(cell->face(face)->center()[0] - parameters.axial_length) < tol) // +X oriented face
1527 * cell->face(face)->set_boundary_id(parameters.bid_BB_neumann); // Neumann
1534 * Finally resize the grid
1537 * GridTools::scale (parameters.scale, triangulation);
1540 * AssertThrow(false, ExcNotImplemented());
1546 * <a name="Linear_active_muscle_model.cc-LinearMuscleModelProblemsetup_muscle_fibres"></a>
1547 * <h4>LinearMuscleModelProblem::setup_muscle_fibres</h4>
1553 * template <int dim>
1554 * void LinearMuscleModelProblem<dim>::setup_muscle_fibres ()
1556 * fibre_data.clear();
1557 * const unsigned int n_cells = triangulation.n_active_cells();
1558 * fibre_data.resize(n_cells);
1559 * const unsigned int n_q_points_cell = qf_cell.size();
1561 * if (parameters.problem == "IsotonicContraction")
1563 * MuscleFibre<dim> fibre_template (Tensor<1,dim>({1,0,0}));
1565 * for (unsigned int cell_no=0; cell_no<triangulation.n_active_cells(); ++cell_no)
1567 * fibre_data[cell_no].resize(n_q_points_cell);
1568 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1570 * fibre_data[cell_no][q_point_cell] = fibre_template;
1574 * else if (parameters.problem == "BicepsBrachii")
1576 * FEValues<dim> fe_values (fe, qf_cell, update_quadrature_points);
1577 * BicepsGeometry<dim> bicep_geom (parameters.axial_length,
1578 * parameters.radius_insertion_origin,
1579 * parameters.radius_midpoint);
1581 * unsigned int cell_no = 0;
1582 * for (typename Triangulation<dim>::active_cell_iterator
1583 * cell = triangulation.begin_active();
1584 * cell != triangulation.end();
1585 * ++cell, ++cell_no)
1587 * Assert(cell_no<fibre_data.size(), ExcMessage("Trying to access fibre data not stored for this cell index"));
1588 * fe_values.reinit(cell);
1590 * fibre_data[cell_no].resize(n_q_points_cell);
1591 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1593 * const Point<dim> pt = fe_values.get_quadrature_points()[q_point_cell];
1594 * fibre_data[cell_no][q_point_cell] = MuscleFibre<dim>(bicep_geom.direction(pt,parameters.scale));
1599 * AssertThrow(false, ExcNotImplemented());
1605 * <a name="Linear_active_muscle_model.cc-LinearMuscleModelProblemupdate_fibre_state"></a>
1606 * <h4>LinearMuscleModelProblem::update_fibre_state</h4>
1612 * template <int dim>
1613 * double LinearMuscleModelProblem<dim>::get_neural_signal (const double time)
1617 * Note: 40 times less force generated than Martins2006
1618 * This is necessary due to the (compliant) linear tissue model
1621 * return (time > parameters.neural_signal_start_time && time < parameters.neural_signal_end_time ?
1626 * template <int dim>
1627 * void LinearMuscleModelProblem<dim>::update_fibre_activation (const double time)
1629 * const double u = get_neural_signal(time);
1631 * const unsigned int n_q_points_cell = qf_cell.size();
1632 * for (unsigned int cell=0; cell<triangulation.n_active_cells(); ++cell)
1634 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1636 * MuscleFibre<dim> &fibre = fibre_data[cell][q_point_cell];
1637 * fibre.update_alpha(u,dt);
1642 * template <int dim>
1643 * void LinearMuscleModelProblem<dim>::update_fibre_state ()
1645 * const unsigned int n_q_points_cell = qf_cell.size();
1647 * FEValues<dim> fe_values (fe, qf_cell, update_gradients);
1651 * Displacement gradient
1654 * std::vector< std::vector< Tensor<1,dim> > > u_grads (n_q_points_cell,
1655 * std::vector<Tensor<1,dim> >(dim));
1657 * unsigned int cell_no = 0;
1658 * for (typename DoFHandler<dim>::active_cell_iterator
1659 * cell = dof_handler.begin_active();
1660 * cell!=dof_handler.end(); ++cell, ++cell_no)
1662 * Assert(cell_no<fibre_data.size(), ExcMessage("Trying to access fibre data not stored for this cell index"));
1663 * fe_values.reinit(cell);
1664 * fe_values.get_function_gradients (solution, u_grads);
1666 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1668 * Assert(q_point_cell<fibre_data[cell_no].size(), ExcMessage("Trying to access fibre data not stored for this cell and qp index"));
1670 * const SymmetricTensor<2,dim> strain_tensor = get_small_strain (u_grads[q_point_cell]);
1671 * MuscleFibre<dim> &fibre = fibre_data[cell_no][q_point_cell];
1672 * fibre.update_state(strain_tensor, dt);
1680 * <a name="Linear_active_muscle_model.cc-LinearMuscleModelProblemsetup_system"></a>
1681 * <h4>LinearMuscleModelProblem::setup_system</h4>
1687 * template <int dim>
1688 * void LinearMuscleModelProblem<dim>::setup_system ()
1690 * dof_handler.distribute_dofs (fe);
1691 * hanging_node_constraints.clear ();
1692 * DoFTools::make_hanging_node_constraints (dof_handler,
1693 * hanging_node_constraints);
1694 * hanging_node_constraints.close ();
1695 * sparsity_pattern.reinit (dof_handler.n_dofs(),
1696 * dof_handler.n_dofs(),
1697 * dof_handler.max_couplings_between_dofs());
1698 * DoFTools::make_sparsity_pattern (dof_handler, sparsity_pattern);
1700 * hanging_node_constraints.condense (sparsity_pattern);
1702 * sparsity_pattern.compress();
1704 * system_matrix.reinit (sparsity_pattern);
1706 * solution.reinit (dof_handler.n_dofs());
1707 * system_rhs.reinit (dof_handler.n_dofs());
1709 * std::cout << " Number of active cells: "
1710 * << triangulation.n_active_cells()
1713 * std::cout << " Number of degrees of freedom: "
1714 * << dof_handler.n_dofs()
1721 * <a name="Linear_active_muscle_model.cc-LinearMuscleModelProblemassemble_system"></a>
1722 * <h4>LinearMuscleModelProblem::assemble_system</h4>
1728 * template <int dim>
1729 * SymmetricTensor<4,dim>
1730 * LinearMuscleModelProblem<dim>::get_stiffness_tensor (const unsigned int cell,
1731 * const unsigned int q_point_cell) const
1733 * static const SymmetricTensor<2,dim> I = unit_symmetric_tensor<dim>();
1735 * Assert(cell<fibre_data.size(), ExcMessage("Trying to access fibre data not stored for this cell index"));
1736 * Assert(q_point_cell<fibre_data[cell].size(), ExcMessage("Trying to access fibre data not stored for this cell and qp index"));
1737 * const MuscleFibre<dim> &fibre = fibre_data[cell][q_point_cell];
1744 * const double lambda = MuscleMatrix::lambda;
1745 * const double mu = MuscleMatrix::mu;
1751 * const double m_p = fibre.get_m_p();
1752 * const double m_s = fibre.get_m_s();
1753 * const double beta = fibre.get_beta(dt);
1754 * AssertThrow(beta != 0.0, ExcInternalError());
1755 * const double Cf = T0*(m_p + m_s*(1.0 - m_s/beta));
1756 * const Tensor<1,dim> &M = fibre.get_M();
1758 * SymmetricTensor<4,dim> C;
1759 * for (unsigned int i=0; i < dim; ++i)
1760 * for (unsigned int j=i; j < dim; ++j)
1761 * for (unsigned int k=0; k < dim; ++k)
1762 * for (unsigned int l=k; l < dim; ++l)
1766 * Matrix contribution
1769 * C[i][j][k][l] = lambda * I[i][j]*I[k][l]
1770 * + mu * (I[i][k]*I[j][l] + I[i][l]*I[j][k]);
1774 * Fibre contribution (Passive + active branches)
1777 * C[i][j][k][l] += Cf * M[i]*M[j]*M[k]*M[l];
1783 * template <int dim>
1784 * SymmetricTensor<2,dim>
1785 * LinearMuscleModelProblem<dim>::get_rhs_tensor (const unsigned int cell,
1786 * const unsigned int q_point_cell) const
1788 * Assert(cell<fibre_data.size(), ExcMessage("Trying to access fibre data not stored for this cell index"));
1789 * Assert(q_point_cell<fibre_data[cell].size(), ExcMessage("Trying to access fibre data not stored for this cell and qp index"));
1790 * const MuscleFibre<dim> &fibre = fibre_data[cell][q_point_cell];
1792 * const double m_s = fibre.get_m_s();
1793 * const double beta = fibre.get_beta(dt);
1794 * const double gamma = fibre.get_gamma(dt);
1795 * AssertThrow(beta != 0.0, ExcInternalError());
1796 * const double Sf = T0*(m_s*gamma/beta);
1797 * const Tensor<1,dim> &M = fibre.get_M();
1799 * SymmetricTensor<2,dim> S;
1800 * for (unsigned int i=0; i < dim; ++i)
1801 * for (unsigned int j=i; j < dim; ++j)
1805 * Fibre contribution (Active branch)
1808 * S[i][j] = Sf * M[i]*M[j];
1817 * <a name="Linear_active_muscle_model.cc-LinearMuscleModelProblemassemble_system"></a>
1818 * <h4>LinearMuscleModelProblem::assemble_system</h4>
1824 * template <int dim>
1825 * void LinearMuscleModelProblem<dim>::assemble_system (const double time)
1832 * system_matrix = 0;
1835 * FEValues<dim> fe_values (fe, qf_cell,
1836 * update_values | update_gradients |
1837 * update_quadrature_points | update_JxW_values);
1838 * FEFaceValues<dim> fe_face_values (fe, qf_face,
1840 * update_quadrature_points | update_JxW_values);
1842 * const unsigned int dofs_per_cell = fe.dofs_per_cell;
1843 * const unsigned int n_q_points_cell = qf_cell.size();
1844 * const unsigned int n_q_points_face = qf_face.size();
1846 * FullMatrix<double> cell_matrix (dofs_per_cell, dofs_per_cell);
1847 * Vector<double> cell_rhs (dofs_per_cell);
1849 * std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);
1856 * std::vector<Vector<double> > body_force_values (n_q_points_cell,
1857 * Vector<double>(dim));
1858 * std::vector<Vector<double> > traction_values (n_q_points_face,
1859 * Vector<double>(dim));
1861 * unsigned int cell_no = 0;
1862 * for (typename DoFHandler<dim>::active_cell_iterator
1863 * cell = dof_handler.begin_active();
1864 * cell!=dof_handler.end(); ++cell, ++cell_no)
1869 * fe_values.reinit (cell);
1870 * body_force.vector_value_list (fe_values.get_quadrature_points(),
1871 * body_force_values);
1873 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1875 * const SymmetricTensor<4,dim> C = get_stiffness_tensor (cell_no, q_point_cell);
1876 * const SymmetricTensor<2,dim> R = get_rhs_tensor(cell_no, q_point_cell);
1878 * for (unsigned int I=0; I<dofs_per_cell; ++I)
1880 * const unsigned int
1881 * component_I = fe.system_to_component_index(I).first;
1883 * for (unsigned int J=0; J<dofs_per_cell; ++J)
1885 * const unsigned int
1886 * component_J = fe.system_to_component_index(J).first;
1888 * for (unsigned int k=0; k < dim; ++k)
1889 * for (unsigned int l=0; l < dim; ++l)
1891 * += (fe_values.shape_grad(I,q_point_cell)[k] *
1892 * C[component_I][k][component_J][l] *
1893 * fe_values.shape_grad(J,q_point_cell)[l]) *
1894 * fe_values.JxW(q_point_cell);
1898 * for (unsigned int I=0; I<dofs_per_cell; ++I)
1900 * const unsigned int
1901 * component_I = fe.system_to_component_index(I).first;
1904 * += fe_values.shape_value(I,q_point_cell) *
1905 * body_force_values[q_point_cell](component_I) *
1906 * fe_values.JxW(q_point_cell);
1908 * for (unsigned int k=0; k < dim; ++k)
1910 * += (fe_values.shape_grad(I,q_point_cell)[k] *
1911 * R[component_I][k]) *
1912 * fe_values.JxW(q_point_cell);
1916 * for (unsigned int face = 0; face <GeometryInfo<dim>::faces_per_cell; ++face)
1918 * if (cell->face(face)->at_boundary() == true &&
1919 * ((parameters.problem == "IsotonicContraction" &&
1920 * cell->face(face)->boundary_id() == parameters.bid_CC_neumann) ||
1921 * (parameters.problem == "BicepsBrachii" &&
1922 * cell->face(face)->boundary_id() == parameters.bid_BB_neumann)) )
1924 * fe_face_values.reinit(cell, face);
1925 * traction.vector_value_list (fe_face_values.get_quadrature_points(),
1930 * Scale applied traction according to time
1933 * const double ramp = (time <= t_ramp_end ? time/t_ramp_end : 1.0);
1934 * Assert(ramp >= 0.0 && ramp <= 1.0, ExcMessage("Invalid force ramp"));
1935 * for (unsigned int q_point_face = 0; q_point_face < n_q_points_face; ++q_point_face)
1936 * traction_values[q_point_face] *= ramp;
1938 * for (unsigned int q_point_face = 0; q_point_face < n_q_points_face; ++q_point_face)
1940 * for (unsigned int I=0; I<dofs_per_cell; ++I)
1942 * const unsigned int
1943 * component_I = fe.system_to_component_index(I).first;
1946 * += fe_face_values.shape_value(I,q_point_face)*
1947 * traction_values[q_point_face][component_I]*
1948 * fe_face_values.JxW(q_point_face);
1954 * cell->get_dof_indices (local_dof_indices);
1955 * for (unsigned int i=0; i<dofs_per_cell; ++i)
1957 * for (unsigned int j=0; j<dofs_per_cell; ++j)
1958 * system_matrix.add (local_dof_indices[i],
1959 * local_dof_indices[j],
1960 * cell_matrix(i,j));
1962 * system_rhs(local_dof_indices[i]) += cell_rhs(i);
1966 * hanging_node_constraints.condense (system_matrix);
1967 * hanging_node_constraints.condense (system_rhs);
1970 * template <int dim>
1971 * void LinearMuscleModelProblem<dim>::apply_boundary_conditions ()
1973 * std::map<types::global_dof_index,double> boundary_values;
1975 * if (parameters.problem == "IsotonicContraction")
1979 * Symmetry condition on -X faces
1983 * ComponentMask component_mask_x (dim, false);
1984 * component_mask_x.set(0, true);
1985 * VectorTools::interpolate_boundary_values (dof_handler,
1986 * parameters.bid_CC_dirichlet_symm_X,
1987 * Functions::ZeroFunction<dim>(dim),
1989 * component_mask_x);
1993 * Symmetry condition on -Z/+Z faces
1997 * ComponentMask component_mask_z (dim, false);
1998 * component_mask_z.set(2, true);
1999 * VectorTools::interpolate_boundary_values (dof_handler,
2000 * parameters.bid_CC_dirichlet_symm_Z,
2001 * Functions::ZeroFunction<dim>(dim),
2003 * component_mask_z);
2007 * Fixed point on -X face
2011 * const Point<dim> fixed_point (-parameters.half_length_x,0.0,0.0);
2012 * std::vector<types::global_dof_index> fixed_dof_indices;
2013 * bool found_point_of_interest = false;
2015 * for (typename DoFHandler<dim>::active_cell_iterator
2016 * cell = dof_handler.begin_active(),
2017 * endc = dof_handler.end(); cell != endc; ++cell)
2019 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2023 * We know that the fixed point is on the -X Dirichlet boundary
2026 * if (cell->face(face)->at_boundary() == true &&
2027 * cell->face(face)->boundary_id() == parameters.bid_CC_dirichlet_symm_X)
2029 * for (unsigned int face_vertex_index = 0; face_vertex_index < GeometryInfo<dim>::vertices_per_face; ++face_vertex_index)
2031 * if (cell->face(face)->vertex(face_vertex_index).distance(fixed_point) < 1e-6)
2033 * found_point_of_interest = true;
2034 * for (unsigned int index_component = 0; index_component < dim; ++index_component)
2035 * fixed_dof_indices.push_back(cell->face(face)->vertex_dof_index(face_vertex_index,
2036 * index_component));
2039 * if (found_point_of_interest == true) break;
2042 * if (found_point_of_interest == true) break;
2044 * if (found_point_of_interest == true) break;
2047 * Assert(found_point_of_interest == true, ExcMessage("Didn't find
point of interest
"));
2048 * AssertThrow(fixed_dof_indices.size() == dim, ExcMessage("Didn
't find the correct number of DoFs to fix"));
2050 * for (unsigned int i=0; i < fixed_dof_indices.size(); ++i)
2051 * boundary_values[fixed_dof_indices[i]] = 0.0;
2054 * else if (parameters.problem == "BicepsBrachii")
2056 * if (parameters.include_gravity == false)
2060 * Symmetry condition on -X surface
2064 * ComponentMask component_mask_x (dim, false);
2065 * component_mask_x.set(0, true);
2066 * VectorTools::interpolate_boundary_values (dof_handler,
2067 * parameters.bid_BB_dirichlet_X,
2068 * Functions::ZeroFunction<dim>(dim),
2070 * component_mask_x);
2075 * Fixed central point on -X surface
2079 * const Point<dim> fixed_point (0.0,0.0,0.0);
2080 * std::vector<types::global_dof_index> fixed_dof_indices;
2081 * bool found_point_of_interest = false;
2083 * for (typename DoFHandler<dim>::active_cell_iterator
2084 * cell = dof_handler.begin_active(),
2085 * endc = dof_handler.end(); cell != endc; ++cell)
2087 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2091 * We know that the fixed point is on the -X Dirichlet boundary
2094 * if (cell->face(face)->at_boundary() == true &&
2095 * cell->face(face)->boundary_id() == parameters.bid_BB_dirichlet_X)
2097 * for (unsigned int face_vertex_index = 0; face_vertex_index < GeometryInfo<dim>::vertices_per_face; ++face_vertex_index)
2099 * if (cell->face(face)->vertex(face_vertex_index).distance(fixed_point) < 1e-6)
2101 * found_point_of_interest = true;
2102 * for (unsigned int index_component = 0; index_component < dim; ++index_component)
2103 * fixed_dof_indices.push_back(cell->face(face)->vertex_dof_index(face_vertex_index,
2104 * index_component));
2107 * if (found_point_of_interest == true) break;
2110 * if (found_point_of_interest == true) break;
2112 * if (found_point_of_interest == true) break;
2115 * Assert(found_point_of_interest == true, ExcMessage("Didn't find
point of interest
"));
2116 * AssertThrow(fixed_dof_indices.size() == dim, ExcMessage("Didn
't find the correct number of DoFs to fix"));
2118 * for (unsigned int i=0; i < fixed_dof_indices.size(); ++i)
2119 * boundary_values[fixed_dof_indices[i]] = 0.0;
2126 * When we apply gravity, some additional constraints
2127 * are required to support the load of the muscle, as
2128 * the material response is more compliant than would
2129 * be the case in reality.
2133 * Symmetry condition on -X surface
2137 * ComponentMask component_mask_x (dim, true);
2138 * VectorTools::interpolate_boundary_values (dof_handler,
2139 * parameters.bid_BB_dirichlet_X,
2140 * Functions::ZeroFunction<dim>(dim),
2142 * component_mask_x);
2146 * Symmetry condition on -X surface
2150 * ComponentMask component_mask_x (dim, false);
2151 * component_mask_x.set(1, true);
2152 * component_mask_x.set(2, true);
2153 * VectorTools::interpolate_boundary_values (dof_handler,
2154 * parameters.bid_BB_neumann,
2155 * Functions::ZeroFunction<dim>(dim),
2157 * component_mask_x);
2163 * Roller condition at central point on +X face
2167 * const Point<dim> roller_point (parameters.axial_length*parameters.scale,0.0,0.0);
2168 * std::vector<types::global_dof_index> fixed_dof_indices;
2169 * bool found_point_of_interest = false;
2171 * for (typename DoFHandler<dim>::active_cell_iterator
2172 * cell = dof_handler.begin_active(),
2173 * endc = dof_handler.end(); cell != endc; ++cell)
2175 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2179 * We know that the fixed point is on the +X Neumann boundary
2182 * if (cell->face(face)->at_boundary() == true &&
2183 * cell->face(face)->boundary_id() == parameters.bid_BB_neumann)
2185 * for (unsigned int face_vertex_index = 0; face_vertex_index < GeometryInfo<dim>::vertices_per_face; ++face_vertex_index)
2187 * if (cell->face(face)->vertex(face_vertex_index).distance(roller_point) < 1e-6)
2189 * found_point_of_interest = true;
2190 * for (unsigned int index_component = 1; index_component < dim; ++index_component)
2191 * fixed_dof_indices.push_back(cell->face(face)->vertex_dof_index(face_vertex_index,
2192 * index_component));
2195 * if (found_point_of_interest == true) break;
2198 * if (found_point_of_interest == true) break;
2200 * if (found_point_of_interest == true) break;
2203 * Assert(found_point_of_interest == true, ExcMessage("Didn't find
point of interest
"));
2204 * AssertThrow(fixed_dof_indices.size() == dim-1, ExcMessage("Didn
't find the correct number of DoFs to fix"));
2206 * for (unsigned int i=0; i < fixed_dof_indices.size(); ++i)
2207 * boundary_values[fixed_dof_indices[i]] = 0.0;
2211 * AssertThrow(false, ExcNotImplemented());
2213 * MatrixTools::apply_boundary_values (boundary_values,
2223 * <a name="Linear_active_muscle_model.cc-LinearMuscleModelProblemsolve"></a>
2224 * <h4>LinearMuscleModelProblem::solve</h4>
2230 * template <int dim>
2231 * void LinearMuscleModelProblem<dim>::solve ()
2233 * SolverControl solver_control (system_matrix.m(), 1e-12);
2234 * SolverCG<> cg (solver_control);
2236 * PreconditionSSOR<> preconditioner;
2237 * preconditioner.initialize(system_matrix, 1.2);
2239 * cg.solve (system_matrix, solution, system_rhs,
2242 * hanging_node_constraints.distribute (solution);
2249 * <a name="Linear_active_muscle_model.cc-LinearMuscleModelProblemoutput_results"></a>
2250 * <h4>LinearMuscleModelProblem::output_results</h4>
2259 * template <int dim>
2260 * void LinearMuscleModelProblem<dim>::output_results (const unsigned int timestep,
2261 * const double time) const
2265 * Visual output: FEM results
2269 * std::string filename = "solution-";
2270 * filename += Utilities::int_to_string(timestep,4);
2271 * filename += ".vtk";
2272 * std::ofstream output (filename.c_str());
2274 * DataOut<dim> data_out;
2275 * data_out.attach_dof_handler (dof_handler);
2277 * std::vector<DataComponentInterpretation::DataComponentInterpretation>
2278 * data_component_interpretation(dim,
2279 * DataComponentInterpretation::component_is_part_of_vector);
2280 * std::vector<std::string> solution_name(dim, "displacement");
2282 * data_out.add_data_vector (solution, solution_name,
2283 * DataOut<dim>::type_dof_data,
2284 * data_component_interpretation);
2285 * data_out.build_patches ();
2286 * data_out.write_vtk (output);
2291 * Visual output: FEM data
2295 * std::string filename = "fibres-";
2296 * filename += Utilities::int_to_string(timestep,4);
2297 * filename += ".vtk";
2298 * std::ofstream output (filename.c_str());
2301 * << "# vtk DataFile Version 3.0" << std::endl
2302 * << "# " << std::endl
2303 * << "ASCII"<< std::endl
2304 * << "DATASET POLYDATA"<< std::endl << std::endl;
2308 * Extract fibre data from quadrature points
2311 * const unsigned int n_cells = triangulation.n_active_cells();
2312 * const unsigned int n_q_points_cell = qf_cell.size();
2316 * Data that we'll be outputting
2319 * std::vector<std::string> results_fibre_names;
2320 * results_fibre_names.push_back(
"alpha");
2321 * results_fibre_names.push_back(
"epsilon_f");
2322 * results_fibre_names.push_back(
"epsilon_c");
2323 * results_fibre_names.push_back(
"epsilon_c_dot");
2325 *
const unsigned int n_results = results_fibre_names.size();
2326 *
const unsigned int n_data_points =
n_cells*n_q_points_cell;
2327 * std::vector< Point<dim> > output_points(n_data_points);
2328 * std::vector< Tensor<1,dim> > output_displacements(n_data_points);
2329 * std::vector< Tensor<1,dim> > output_directions(n_data_points);
2330 * std::vector< std::vector<double> > output_values(n_results, std::vector<double>(n_data_points));
2337 * std::vector< Vector<double> > u_values (n_q_points_cell,
2344 * std::vector< std::vector< Tensor<1,dim> > > u_grads (n_q_points_cell,
2349 *
unsigned int cell_no = 0;
2350 *
unsigned int fibre_no = 0;
2352 * cell = dof_handler.begin_active();
2353 * cell != dof_handler.end();
2354 * ++cell, ++cell_no)
2356 * fe_values.reinit (cell);
2357 * fe_values.get_function_values (solution, u_values);
2358 * fe_values.get_function_gradients (solution, u_grads);
2360 *
for (
unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell, ++fibre_no)
2362 *
const MuscleFibre<dim> &fibre = fibre_data[cell_no][q_point_cell];
2363 * output_points[fibre_no] = fe_values.get_quadrature_points()[q_point_cell];
2364 *
for (
unsigned int d=0;
d<dim; ++
d)
2365 * output_displacements[fibre_no][d] = u_values[q_point_cell][d];
2368 * Direction (spatial configuration)
2371 * output_directions[fibre_no] = get_deformation_gradient(u_grads[q_point_cell])*fibre.get_M();
2372 * output_directions[fibre_no] /= output_directions[fibre_no].norm();
2379 * output_values[0][fibre_no] = fibre.get_alpha();
2380 * output_values[1][fibre_no] = fibre.get_epsilon_f();
2381 * output_values[2][fibre_no] = fibre.get_epsilon_c();
2382 * output_values[3][fibre_no] = fibre.get_epsilon_c_dot();
2394 * <<
" float" << std::endl;
2395 *
for (
unsigned int i=0; i < n_data_points; ++i)
2397 *
for (
unsigned int j=0; j < dim; ++j)
2399 * output << (output_points)[i][j] <<
"\t";
2401 * output << std::endl;
2406 * HEADER FOR POINT DATA
2409 * output <<
"\nPOINT_DATA "
2411 * << std::endl << std::endl;
2415 * FIBRE DISPLACEMENTS
2419 * <<
"VECTORS displacement float"
2421 *
for (
unsigned int i = 0; i < n_data_points; ++i)
2423 *
for (
unsigned int j=0; j < dim; ++j)
2425 * output << (output_displacements)[i][j] <<
"\t";
2427 * output << std::endl;
2429 * output << std::endl;
2437 * <<
"VECTORS direction float"
2439 *
for (
unsigned int i = 0; i < n_data_points; ++i)
2441 *
for (
unsigned int j=0; j < dim; ++j)
2443 * output << (output_directions)[i][j] <<
"\t";
2445 * output << std::endl;
2447 * output << std::endl;
2454 *
for (
unsigned int v=0; v < n_results; ++v)
2458 * << results_fibre_names[v]
2459 * <<
" float 1" << std::endl
2460 * <<
"LOOKUP_TABLE default "
2462 *
for (
unsigned int i=0; i<n_data_points; ++i)
2464 * output << (output_values)[v][i] <<
" ";
2466 * output << std::endl;
2472 * Output X-displacement at measured
point
2476 *
const Point<dim> meas_pt (parameters.problem ==
"IsotonicContraction" ?
2477 *
Point<dim>(parameters.half_length_x, 0.0, 0.0) :
2478 *
Point<dim>(parameters.axial_length*parameters.
scale, 0.0, 0.0) );
2481 *
const unsigned int index_of_interest = 0;
2482 *
bool found_point_of_interest =
false;
2486 * cell = dof_handler.begin_active(),
2487 * endc = dof_handler.end(); cell != endc; ++cell)
2489 *
for (
unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2493 * We know that the measurement
point is on the Neumann boundary
2496 *
if (cell->face(face)->at_boundary() ==
true &&
2497 * ((parameters.problem ==
"IsotonicContraction" &&
2498 * cell->face(face)->boundary_id() == parameters.bid_CC_neumann) ||
2499 * (parameters.problem ==
"BicepsBrachii" &&
2500 * cell->face(face)->boundary_id() == parameters.bid_BB_neumann)) )
2502 *
for (
unsigned int face_vertex_index = 0; face_vertex_index < GeometryInfo<dim>::vertices_per_face; ++face_vertex_index)
2504 *
if (cell->face(face)->vertex(face_vertex_index).distance(meas_pt) < 1
e-6)
2506 * found_point_of_interest =
true;
2507 * dof_of_interest = cell->face(face)->vertex_dof_index(face_vertex_index,
2508 * index_of_interest);
2511 *
if (found_point_of_interest ==
true)
break;
2514 *
if (found_point_of_interest ==
true)
break;
2516 *
if (found_point_of_interest ==
true)
break;
2519 *
Assert(found_point_of_interest ==
true, ExcMessage(
"Didn't find point of interest"));
2521 *
Assert(dof_of_interest < dof_handler.n_dofs(), ExcMessage(
"DoF index out of range"));
2523 *
const std::string filename =
"displacement_POI.csv";
2524 * std::ofstream output;
2525 *
if (timestep == 0)
2527 * output.open(filename.c_str(), std::ofstream::out);
2529 * <<
"Time [s]" <<
"," <<
"X-displacement [mm]" << std::endl;
2532 * output.open(filename.c_str(), std::ios_base::app);
2537 * << solution[dof_of_interest]*1e3
2547 * <a name=
"Linear_active_muscle_model.cc-LinearMuscleModelProblemrun"></a>
2548 * <h4>LinearMuscleModelProblem::run</h4>
2554 *
template <
int dim>
2555 *
void LinearMuscleModelProblem<dim>::run ()
2559 * setup_muscle_fibres ();
2563 *
const bool do_grid_refinement =
false;
2566 *
double time = 0.0;
2567 *
for (
unsigned int timestep=0; time<=t_end; ++timestep, time+=dt)
2570 * <<
"Timestep " << timestep
2571 * <<
" @ time " << time
2576 * First we update the fibre activation
level
2577 * based on the current time
2580 * update_fibre_activation(time);
2584 * Next we
assemble the system and enforce boundary
2586 * Here we assume that the system and fibres have
2587 * a fixed state, and we will
assemble based on how
2588 * epsilon_c will update given the current state of
2592 * assemble_system (time);
2593 * apply_boundary_conditions ();
2597 * Then we solve the linear system
2604 * Now we update the fibre state based on the
new
2605 * displacement solution and the constitutive
2606 * parameters assumed to govern the stiffness of
2607 * the fibres at the previous state. i.e. We
2608 * follow through with assumed update conditions
2609 * used in the assembly phase.
2612 * update_fibre_state();
2616 * Output some values to file
2619 * output_results (timestep, time);
2627 * <a name=
"Linear_active_muscle_model.cc-Thecodemaincodefunction"></a>
2628 * <h3>The <code>main</code> function</h3>
2638 * ::deallog.depth_console (0);
2639 *
const unsigned int dim = 3;
2641 * LMM::LinearMuscleModelProblem<dim> lmm_problem (
"parameters.prm");
2642 * lmm_problem.run ();
2644 *
catch (std::exception &exc)
2646 * std::cerr << std::endl << std::endl
2647 * <<
"----------------------------------------------------"
2649 * std::cerr <<
"Exception on processing: " << std::endl
2650 * << exc.what() << std::endl
2651 * <<
"Aborting!" << std::endl
2652 * <<
"----------------------------------------------------"
2659 * std::cerr << std::endl << std::endl
2660 * <<
"----------------------------------------------------"
2662 * std::cerr <<
"Unknown exception!" << std::endl
2663 * <<
"Aborting!" << std::endl
2664 * <<
"----------------------------------------------------"
virtual void vector_value_list(const std::vector< Point< dim > > &points, std::vector< Vector< RangeNumberType > > &values) const
virtual void vector_value(const Point< dim > &p, Vector< RangeNumberType > &values) const
numbers::NumberTraits< Number >::real_type norm() const
void refine_global(const unsigned int times=1)
cell_iterator end() const
active_cell_iterator begin_active(const unsigned int level=0) const
__global__ void set(Number *val, const Number s, const size_type N)
#define Assert(cond, exc)
#define AssertThrow(cond, exc)
typename ActiveSelector::active_cell_iterator active_cell_iterator
@ update_values
Shape function values.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
void approximate(const SynchronousIterators< std::tuple< typename DoFHandler< dim, spacedim >::active_cell_iterator, Vector< float >::iterator > > &cell, const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, const InputVector &solution, const unsigned int component)
void hyper_ball(Triangulation< dim > &tria, const Point< dim > ¢er=Point< dim >(), const double radius=1., const bool attach_spherical_manifold_on_boundary_cells=false)
void hyper_rectangle(Triangulation< dim, spacedim > &tria, const Point< dim > &p1, const Point< dim > &p2, const bool colorize=false)
void cylinder(Triangulation< dim > &tria, const double radius=1., const double half_length=1.)
void extrude_triangulation(const Triangulation< 2, 2 > &input, const unsigned int n_slices, const double height, Triangulation< 3, 3 > &result, const bool copy_manifold_ids=false, const std::vector< types::manifold_id > &manifold_priorities={})
void flatten_triangulation(const Triangulation< dim, spacedim1 > &in_tria, Triangulation< dim, spacedim2 > &out_tria)
@ matrix
Contents is actually a matrix.
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
SymmetricTensor< 2, dim, Number > E(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
Tensor< 2, dim, Number > F(const Tensor< 2, dim, Number > &Grad_u)
VectorType::value_type * end(VectorType &V)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
long double gamma(const unsigned int n)
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
int(& functions)(const void *v1, const void *v2)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
const types::global_dof_index invalid_dof_index
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Function &function, const unsigned int grainsize)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
DEAL_II_HOST constexpr SymmetricTensor< 2, dim, Number > unit_symmetric_tensor()