Reference documentation for deal.II version 9.4.1
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
Linear_Elastic_Active_Skeletal_Muscle_Model.h
Go to the documentation of this file.
1
269 *
270 * /*
271 * * Authors: Jean-Paul Pelteret, Tim Hamann,
272 * * University of Erlangen-Nuremberg, 2017
273 * *
274 * * The support of this work by the European Research Council (ERC) through
275 * * the Advanced Grant 289049 MOCOPOLY is gratefully acknowledged by the
276 * * first author.
277 * */
278 *
279 * @endcode
280 *
281 *
282 * <a name="Includefiles"></a>
283 * <h3>Include files</h3>
284 *
285
286 *
287 *
288 * @code
289 * #include <deal.II/base/quadrature_lib.h>
290 * #include <deal.II/base/function.h>
291 * #include <deal.II/base/logstream.h>
292 * #include <deal.II/base/parameter_handler.h>
293 * #include <deal.II/lac/affine_constraints.h>
294 * #include <deal.II/lac/vector.h>
295 * #include <deal.II/lac/full_matrix.h>
296 * #include <deal.II/lac/sparse_matrix.h>
297 * #include <deal.II/lac/solver_cg.h>
298 * #include <deal.II/lac/precondition.h>
299 * #include <deal.II/grid/grid_out.h>
300 * #include <deal.II/grid/manifold_lib.h>
301 * #include <deal.II/grid/tria.h>
302 * #include <deal.II/grid/grid_generator.h>
303 * #include <deal.II/grid/grid_refinement.h>
304 * #include <deal.II/grid/grid_tools.h>
305 * #include <deal.II/grid/tria_accessor.h>
306 * #include <deal.II/grid/tria_iterator.h>
307 * #include <deal.II/dofs/dof_handler.h>
308 * #include <deal.II/dofs/dof_accessor.h>
309 * #include <deal.II/dofs/dof_tools.h>
310 * #include <deal.II/fe/fe_values.h>
311 * #include <deal.II/fe/fe_system.h>
312 * #include <deal.II/fe/fe_q.h>
313 * #include <deal.II/numerics/vector_tools.h>
314 * #include <deal.II/numerics/matrix_tools.h>
315 * #include <deal.II/numerics/data_out.h>
316 * #include <deal.II/numerics/error_estimator.h>
317 * #include <deal.II/physics/transformations.h>
318 *
319 * #include <fstream>
320 * #include <iostream>
321 * #include <vector>
322 *
323 * namespace LMM
324 * {
325 * using namespace dealii;
326 *
327 * @endcode
328 *
329 *
330 * <a name="Runtimeparameters"></a>
331 * <h3>Run-time parameters</h3>
332 *
333
334 *
335 * There are several parameters that can be set in the code so we set up a
336 * ParameterHandler object to read in the choices at run-time.
337 *
338 * @code
339 * namespace Parameters
340 * {
341 * @endcode
342 *
343 *
344 * <a name="FiniteElementsystem"></a>
345 * <h4>Finite Element system</h4>
346 *
347
348 *
349 * Here we specify the polynomial order used to approximate the solution.
350 * The quadrature order should be adjusted accordingly.
351 *
352 * @code
353 * struct FESystem
354 * {
355 * unsigned int poly_degree;
356 * unsigned int quad_order;
357 *
358 * static void
359 * declare_parameters(ParameterHandler &prm);
360 *
361 * void
362 * parse_parameters(ParameterHandler &prm);
363 * };
364 *
365 * void FESystem::declare_parameters(ParameterHandler &prm)
366 * {
367 * prm.enter_subsection("Finite element system");
368 * {
369 * prm.declare_entry("Polynomial degree", "1",
371 * "Displacement system polynomial order");
372 *
373 * prm.declare_entry("Quadrature order", "2",
375 * "Gauss quadrature order");
376 * }
377 * prm.leave_subsection();
378 * }
379 *
380 * void FESystem::parse_parameters(ParameterHandler &prm)
381 * {
382 * prm.enter_subsection("Finite element system");
383 * {
384 * poly_degree = prm.get_integer("Polynomial degree");
385 * quad_order = prm.get_integer("Quadrature order");
386 * }
387 * prm.leave_subsection();
388 * }
389 *
390 * @endcode
391 *
392 *
393 * <a name="Problem"></a>
394 * <h4>Problem</h4>
395 *
396
397 *
398 * Choose which problem is going to be solved
399 *
400 * @code
401 * struct Problem
402 * {
403 * std::string problem;
404 *
405 * static void
406 * declare_parameters(ParameterHandler &prm);
407 *
408 * void
409 * parse_parameters(ParameterHandler &prm);
410 * };
411 *
412 * void Problem::declare_parameters(ParameterHandler &prm)
413 * {
414 * prm.enter_subsection("Problem");
415 * {
416 * prm.declare_entry("Problem", "IsotonicContraction",
417 * Patterns::Selection("IsotonicContraction|BicepsBrachii"),
418 * "The problem that is to be solved");
419 * }
420 * prm.leave_subsection();
421 * }
422 *
423 * void Problem::parse_parameters(ParameterHandler &prm)
424 * {
425 * prm.enter_subsection("Problem");
426 * {
427 * problem = prm.get("Problem");
428 * }
429 * prm.leave_subsection();
430 * }
431 *
432 * @endcode
433 *
434 *
435 * <a name="IsotonicContractionGeometry"></a>
436 * <h4>IsotonicContractionGeometry</h4>
437 *
438
439 *
440 * Make adjustments to the geometry and discretisation of the
441 * isotonic contraction model from Martins2006.
442 *
443
444 *
445 *
446 * @code
447 * struct IsotonicContraction
448 * {
449 * const double half_length_x = 10e-3/2.0;
450 * const double half_length_y = 10e-3/2.0;
451 * const double half_length_z = 1e-3/2.0;
452 * const types::boundary_id bid_CC_dirichlet_symm_X = 1;
453 * const types::boundary_id bid_CC_dirichlet_symm_Z = 2;
454 * const types::boundary_id bid_CC_neumann = 10;
455 *
456 * static void
457 * declare_parameters(ParameterHandler &prm);
458 *
459 * void
460 * parse_parameters(ParameterHandler &prm);
461 * };
462 *
463 * void IsotonicContraction::declare_parameters(ParameterHandler &/*prm*/)
464 * {
465 *
466 * }
467 *
468 * void IsotonicContraction::parse_parameters(ParameterHandler &/*prm*/)
469 * {
470 *
471 * }
472 *
473 * @endcode
474 *
475 *
476 * <a name="BicepsBrachiiGeometry"></a>
477 * <h4>BicepsBrachiiGeometry</h4>
478 *
479
480 *
481 * Make adjustments to the geometry and discretisation of the
482 * biceps model.
483 *
484
485 *
486 *
487 * @code
488 * struct BicepsBrachii
489 * {
490 * double axial_length;
491 * double radius_insertion_origin;
492 * double radius_midpoint;
493 * double scale;
494 * unsigned int elements_along_axis;
495 * unsigned int n_refinements_radial;
496 * bool include_gravity;
497 * double axial_force;
498 *
499 * const types::boundary_id bid_BB_dirichlet_X = 1;
500 * const types::boundary_id bid_BB_neumann = 10;
501 * const types::boundary_id mid_BB_radial = 100;
502 *
503 * static void
504 * declare_parameters(ParameterHandler &prm);
505 *
506 * void
507 * parse_parameters(ParameterHandler &prm);
508 * };
509 *
510 * void BicepsBrachii::declare_parameters(ParameterHandler &prm)
511 * {
512 * prm.enter_subsection("Biceps Brachii geometry");
513 * {
514 * prm.declare_entry("Axial length", "250",
515 * Patterns::Double(0),
516 * "Axial length of the muscle");
517 *
518 * prm.declare_entry("Radius insertion and origin", "5",
519 * Patterns::Double(0),
520 * "Insertion and origin radius");
521 *
522 * prm.declare_entry("Radius midpoint", "7.5",
523 * Patterns::Double(0),
524 * "Radius at the midpoint of the muscle");
525 *
526 * prm.declare_entry("Grid scale", "1e-3",
527 * Patterns::Double(0.0),
528 * "Global grid scaling factor");
529 *
530 * prm.declare_entry("Elements along axis", "32",
532 * "Number of elements along the muscle axis");
533 *
534 * prm.declare_entry("Radial refinements", "4",
536 * "Control the discretisation in the radial direction");
537 *
538 * prm.declare_entry("Gravity", "false",
539 * Patterns::Bool(),
540 * "Include the effects of gravity (in the y-direction; "
541 * " perpendicular to the muscle axis)");
542 *
543 * prm.declare_entry("Axial force", "1",
545 * "Applied distributed axial force (in Newtons)");
546 * }
547 * prm.leave_subsection();
548 * }
549 *
550 * void BicepsBrachii::parse_parameters(ParameterHandler &prm)
551 * {
552 * prm.enter_subsection("Biceps Brachii geometry");
553 * {
554 * axial_length = prm.get_double("Axial length");
555 * radius_insertion_origin = prm.get_double("Radius insertion and origin");
556 * radius_midpoint = prm.get_double("Radius midpoint");
557 * scale = prm.get_double("Grid scale");
558 * elements_along_axis = prm.get_integer("Elements along axis");
559 * n_refinements_radial = prm.get_integer("Radial refinements");
560 * include_gravity = prm.get_bool("Gravity");
561 * axial_force = prm.get_double("Axial force");
562 * }
563 * prm.leave_subsection();
564 *
565 * AssertThrow(radius_midpoint >= radius_insertion_origin,
566 * ExcMessage("Unrealistic geometry"));
567 * }
568 *
569 * @endcode
570 *
571 *
572 * <a name="Neurologicalsignal"></a>
573 * <h4>Neurological signal</h4>
574 *
575
576 *
577 *
578 * @code
579 * struct NeurologicalSignal
580 * {
581 * double neural_signal_start_time;
582 * double neural_signal_end_time;
583 *
584 * static void
585 * declare_parameters(ParameterHandler &prm);
586 *
587 * void
588 * parse_parameters(ParameterHandler &prm);
589 * };
590 *
591 * void NeurologicalSignal::declare_parameters(ParameterHandler &prm)
592 * {
593 * prm.enter_subsection("Neurological signal");
594 * {
595 * prm.declare_entry("Start time", "1.0",
596 * Patterns::Double(0),
597 * "Time at which to start muscle activation");
598 *
599 * prm.declare_entry("End time", "2.0",
600 * Patterns::Double(0),
601 * "Time at which to remove muscle activation signal");
602 * }
603 * prm.leave_subsection();
604 * }
605 *
606 * void NeurologicalSignal::parse_parameters(ParameterHandler &prm)
607 * {
608 * prm.enter_subsection("Neurological signal");
609 * {
610 * neural_signal_start_time = prm.get_double("Start time");
611 * neural_signal_end_time = prm.get_double("End time");
612 * }
613 * prm.leave_subsection();
614 *
615 * Assert(neural_signal_start_time < neural_signal_end_time,
616 * ExcMessage("Invalid neural signal times."));
617 * }
618 *
619 * @endcode
620 *
621 *
622 * <a name="Time"></a>
623 * <h4>Time</h4>
624 *
625
626 *
627 * Set the timestep size @f$ \varDelta t @f$ and the simulation end-time.
628 *
629 * @code
630 * struct Time
631 * {
632 * double delta_t;
633 * double end_time;
634 * double end_ramp_time;
635 *
636 * static void
637 * declare_parameters(ParameterHandler &prm);
638 *
639 * void
640 * parse_parameters(ParameterHandler &prm);
641 * };
642 *
643 * void Time::declare_parameters(ParameterHandler &prm)
644 * {
645 * prm.enter_subsection("Time");
646 * {
647 * prm.declare_entry("End time", "3",
648 * Patterns::Double(0),
649 * "End time");
650 *
651 * prm.declare_entry("End ramp time", "1",
652 * Patterns::Double(0),
653 * "Force ramp end time");
654 *
655 * prm.declare_entry("Time step size", "0.1",
656 * Patterns::Double(0),
657 * "Time step size");
658 * }
659 * prm.leave_subsection();
660 * }
661 *
662 * void Time::parse_parameters(ParameterHandler &prm)
663 * {
664 * prm.enter_subsection("Time");
665 * {
666 * end_time = prm.get_double("End time");
667 * end_ramp_time = prm.get_double("End ramp time");
668 * delta_t = prm.get_double("Time step size");
669 * }
670 * prm.leave_subsection();
671 * }
672 *
673 * @endcode
674 *
675 *
676 * <a name="Allparameters"></a>
677 * <h4>All parameters</h4>
678 *
679
680 *
681 * Finally we consolidate all of the above structures into a single container
682 * that holds all of our run-time selections.
683 *
684 * @code
685 * struct AllParameters : public FESystem,
686 * public Problem,
687 * public IsotonicContraction,
688 * public BicepsBrachii,
689 * public NeurologicalSignal,
690 * public Time
691 * {
692 * AllParameters(const std::string &input_file);
693 *
694 * static void
695 * declare_parameters(ParameterHandler &prm);
696 *
697 * void
698 * parse_parameters(ParameterHandler &prm);
699 * };
700 *
701 * AllParameters::AllParameters(const std::string &input_file)
702 * {
703 * ParameterHandler prm;
704 * declare_parameters(prm);
705 * prm.parse_input(input_file);
706 * parse_parameters(prm);
707 * }
708 *
709 * void AllParameters::declare_parameters(ParameterHandler &prm)
710 * {
711 * FESystem::declare_parameters(prm);
712 * Problem::declare_parameters(prm);
713 * IsotonicContraction::declare_parameters(prm);
714 * BicepsBrachii::declare_parameters(prm);
715 * NeurologicalSignal::declare_parameters(prm);
716 * Time::declare_parameters(prm);
717 * }
718 *
719 * void AllParameters::parse_parameters(ParameterHandler &prm)
720 * {
721 * FESystem::parse_parameters(prm);
722 * Problem::parse_parameters(prm);
723 * IsotonicContraction::parse_parameters(prm);
724 * BicepsBrachii::parse_parameters(prm);
725 * NeurologicalSignal::parse_parameters(prm);
726 * Time::parse_parameters(prm);
727 *
728 * @endcode
729 *
730 * Override time setting for test defined
731 * in the literature
732 *
733 * @code
734 * if (problem == "IsotonicContraction")
735 * {
736 * end_time = 3.0;
737 * end_ramp_time = 1.0;
738 * delta_t = 0.1;
739 *
740 * neural_signal_start_time = 1.0;
741 * neural_signal_end_time = 2.0;
742 * }
743 * }
744 * }
745 *
746 * @endcode
747 *
748 *
749 * <a name="Bodyforcevalues"></a>
750 * <h3>Body force values</h3>
751 *
752
753 *
754 *
755 * @code
756 * template <int dim>
757 * class BodyForce : public Function<dim>
758 * {
759 * public:
760 * BodyForce (const double rho,
761 * const Tensor<1,dim> direction);
762 * virtual ~BodyForce () {}
763 *
764 * virtual void vector_value (const Point<dim> &p,
765 * Vector<double> &values) const;
766 *
767 * virtual void vector_value_list (const std::vector<Point<dim> > &points,
768 * std::vector<Vector<double> > &value_list) const;
769 *
770 * const double rho;
771 * const double g;
772 * const Tensor<1,dim> M;
773 * };
774 *
775 *
776 * template <int dim>
777 * BodyForce<dim>::BodyForce (const double rho,
778 * const Tensor<1,dim> direction)
779 * :
780 * Function<dim> (dim),
781 * rho (rho),
782 * g (9.81),
783 * M (direction)
784 * {
785 * Assert(M.norm() == 1.0, ExcMessage("Direction vector is not a unit vector"));
786 * }
787 *
788 *
789 * template <int dim>
790 * inline
791 * void BodyForce<dim>::vector_value (const Point<dim> &/*p*/,
792 * Vector<double> &values) const
793 * {
794 * Assert (values.size() == dim,
795 * ExcDimensionMismatch (values.size(), dim));
796 * Assert (dim >= 2, ExcNotImplemented());
797 * for (unsigned int d=0; d<dim; ++d)
798 * {
799 * values(d) = rho*g*M[d];
800 * }
801 * }
802 *
803 *
804 * template <int dim>
805 * void BodyForce<dim>::vector_value_list (const std::vector<Point<dim> > &points,
806 * std::vector<Vector<double> > &value_list) const
807 * {
808 * Assert (value_list.size() == points.size(),
809 * ExcDimensionMismatch (value_list.size(), points.size()));
810 *
811 * const unsigned int n_points = points.size();
812 *
813 * for (unsigned int p=0; p<n_points; ++p)
814 * BodyForce<dim>::vector_value (points[p],
815 * value_list[p]);
816 * }
817 *
818 * template <int dim>
819 * class Traction : public Function<dim>
820 * {
821 * public:
822 * Traction (const double force,
823 * const double area);
824 * virtual ~Traction () {}
825 *
826 * virtual void vector_value (const Point<dim> &p,
827 * Vector<double> &values) const;
828 *
829 * virtual void vector_value_list (const std::vector<Point<dim> > &points,
830 * std::vector<Vector<double> > &value_list) const;
831 *
832 * const double t;
833 * };
834 *
835 *
836 * template <int dim>
837 * Traction<dim>::Traction (const double force,
838 * const double area)
839 * :
840 * Function<dim> (dim),
841 * t (force/area)
842 * {}
843 *
844 *
845 * template <int dim>
846 * inline
847 * void Traction<dim>::vector_value (const Point<dim> &/*p*/,
848 * Vector<double> &values) const
849 * {
850 * Assert (values.size() == dim,
851 * ExcDimensionMismatch (values.size(), dim));
852 * Assert (dim == 3, ExcNotImplemented());
853 *
854 * @endcode
855 *
856 * Assume uniform distributed load
857 *
858 * @code
859 * values(0) = t;
860 * values(1) = 0.0;
861 * values(2) = 0.0;
862 * }
863 *
864 *
865 * template <int dim>
866 * void Traction<dim>::vector_value_list (const std::vector<Point<dim> > &points,
867 * std::vector<Vector<double> > &value_list) const
868 * {
869 * Assert (value_list.size() == points.size(),
870 * ExcDimensionMismatch (value_list.size(), points.size()));
871 *
872 * const unsigned int n_points = points.size();
873 *
874 * for (unsigned int p=0; p<n_points; ++p)
875 * Traction<dim>::vector_value (points[p],
876 * value_list[p]);
877 * }
878 *
879 * @endcode
880 *
881 *
882 * <a name="Utilityfunctions"></a>
883 * <h3>Utility functions</h3>
884 *
885
886 *
887 *
888 * @code
889 * template <int dim>
890 * inline
891 * Tensor<2,dim> get_deformation_gradient (std::vector<Tensor<1,dim> > &grad)
892 * {
893 * Assert (grad.size() == dim, ExcInternalError());
894 *
895 * Tensor<2,dim> F (unit_symmetric_tensor<dim>());
896 * for (unsigned int i=0; i<dim; ++i)
897 * for (unsigned int j=0; j<dim; ++j)
898 * F[i][j] += grad[i][j];
899 * return F;
900 * }
901 *
902 * template <int dim>
903 * inline
904 * SymmetricTensor<2,dim> get_small_strain (std::vector<Tensor<1,dim> > &grad)
905 * {
906 * Assert (grad.size() == dim, ExcInternalError());
907 *
908 * SymmetricTensor<2,dim> strain;
909 * for (unsigned int i=0; i<dim; ++i)
910 * strain[i][i] = grad[i][i];
911 *
912 * for (unsigned int i=0; i<dim; ++i)
913 * for (unsigned int j=i+1; j<dim; ++j)
914 * strain[i][j] = (grad[i][j] + grad[j][i]) / 2;
915 * return strain;
916 * }
917 *
918 * @endcode
919 *
920 *
921 * <a name="Propertiesformusclematrix"></a>
922 * <h3>Properties for muscle matrix</h3>
923 *
924
925 *
926 *
927 * @code
928 * struct MuscleMatrix
929 * {
930 * static const double E; // Young's modulus
931 * static const double nu; // Poisson ratio
932 *
933 * static const double mu; // Shear modulus
934 * static const double lambda; // Lame parameter
935 * };
936 *
937 * const double MuscleMatrix::E = 26e3;
938 * const double MuscleMatrix::nu = 0.45;
939 * const double MuscleMatrix::mu = MuscleMatrix::E/(2.0*(1.0 + MuscleMatrix::nu));
940 * const double MuscleMatrix::lambda = 2.0*MuscleMatrix::mu *MuscleMatrix::nu/(1.0 - 2.0*MuscleMatrix::nu);
941 *
942 * @endcode
943 *
944 *
945 * <a name="Localdataformusclefibres"></a>
946 * <h3>Local data for muscle fibres</h3>
947 *
948
949 *
950 *
951 * @code
952 * #define convert_gf_to_N 1.0/101.97
953 * #define convert_gf_per_cm2_to_N_per_m2 convert_gf_to_N*1e2*1e2
954 * #define T0 6280.0*convert_gf_per_cm2_to_N_per_m2
955 *
956 * @endcode
957 *
958 * A struct that governs the functioning of a single muscle fibre
959 *
960 * @code
961 * template <int dim>
962 * struct MuscleFibre
963 * {
964 * MuscleFibre (void)
965 * : alpha (0.0),
966 * alpha_t1 (0.0),
967 * epsilon_f (0.0),
968 * epsilon_c (0.0),
969 * epsilon_c_t1 (0.0),
970 * epsilon_c_dot (0.0)
971 * {
972 *
973 * }
974 *
975 * MuscleFibre(const Tensor<1,dim> &direction)
976 * : M (direction),
977 * alpha (0.0),
978 * alpha_t1 (0.0),
979 * epsilon_f (0.0),
980 * epsilon_c (0.0),
981 * epsilon_c_t1 (0.0),
982 * epsilon_c_dot (0.0)
983 * {
984 * Assert(M.norm() == 1.0,
985 * ExcMessage("Fibre direction is not a unit vector"));
986 * }
987 *
988 * void update_alpha (const double u,
989 * const double dt);
990 *
991 * void update_state(const SymmetricTensor<2,dim> &strain_tensor,
992 * const double dt);
993 *
994 * const Tensor<1,dim> &get_M () const
995 * {
996 * return M;
997 * }
998 * double get_m_p () const;
999 * double get_m_s () const;
1000 * double get_beta (const double dt) const;
1001 * double get_gamma (const double dt) const;
1002 *
1003 * @endcode
1004 *
1005 * Postprocessing
1006 *
1007 * @code
1008 * const double &get_alpha() const
1009 * {
1010 * return alpha;
1011 * }
1012 * const double &get_epsilon_f() const
1013 * {
1014 * return epsilon_f;
1015 * }
1016 * const double &get_epsilon_c() const
1017 * {
1018 * return epsilon_c;
1019 * }
1020 * const double &get_epsilon_c_dot() const
1021 * {
1022 * return epsilon_c_dot;
1023 * }
1024 *
1025 * private:
1026 * Tensor<1,dim> M; // Direction
1027 *
1028 * double alpha; // Activation level at current timestep
1029 * double alpha_t1; // Activation level at previous timestep
1030 *
1031 * double epsilon_f; // Fibre strain at current timestep
1032 * double epsilon_c; // Contractile strain at current timestep
1033 * double epsilon_c_t1; // Contractile strain at previous timestep
1034 * double epsilon_c_dot; // Contractile velocity at previous timestep
1035 *
1036 * double get_f_c_L () const;
1037 * double get_m_c_V () const;
1038 * double get_c_c_V () const;
1039 * };
1040 *
1041 * template <int dim>
1042 * void MuscleFibre<dim>::update_alpha (const double u,
1043 * const double dt)
1044 * {
1045 * static const double tau_r = 0.15; // s
1046 * static const double tau_f = 0.15; // s
1047 * static const double alpha_min = 0;
1048 *
1049 * if (u == 1.0)
1050 * alpha = (alpha_t1*tau_r*tau_f + dt*tau_f) / (tau_r*tau_f + dt*tau_f);
1051 * else if (u == 0)
1052 * alpha = (alpha_t1*tau_r*tau_f + dt*alpha_min*tau_r) / (tau_r*tau_f + dt*tau_r);
1053 * else
1054 * {
1055 * const double b = 1.0/tau_r - 1.0/tau_f;
1056 * const double c = 1.0/tau_f;
1057 * const double d = alpha_min/tau_f;
1058 * const double f1 = 1.0/tau_r - alpha_min/tau_f;
1059 * const double p = b*u + c;
1060 * const double q = f1*u + d;
1061 *
1062 * alpha = (q*dt + alpha_t1)/(1.0 + p*dt);
1063 * }
1064 * }
1065 *
1066 *
1067 * template <int dim>
1068 * double MuscleFibre<dim>::get_m_p () const
1069 * {
1070 * static const double A = 8.568e-4*convert_gf_per_cm2_to_N_per_m2;
1071 * static const double a = 12.43;
1072 * if (epsilon_f >= 0.0)
1073 * {
1074 * @endcode
1075 *
1076 * 100 times more compliant than Martins2006
1077 *
1078 * @code
1079 * static const double m_p = 2.0*A*a/1e2;
1080 * return m_p;
1081 * }
1082 * else
1083 * return 0.0;
1084 * }
1085 *
1086 * template <int dim>
1087 * double MuscleFibre<dim>::get_m_s (void) const
1088 * {
1089 * const double epsilon_s = epsilon_f - epsilon_c; // Small strain assumption
1090 * if (epsilon_s >= -1e-6) // Tolerant check
1091 * return 10.0;
1092 * else
1093 * return 0.0;
1094 * }
1095 *
1096 * template <int dim>
1097 * double MuscleFibre<dim>::get_f_c_L (void) const
1098 * {
1099 * if (epsilon_c <= 0.5 && epsilon_c >= -0.5)
1100 * return 1.0;
1101 * else
1102 * return 0.0;
1103 * }
1104 *
1105 * template <int dim>
1106 * double MuscleFibre<dim>::get_m_c_V (void) const
1107 * {
1108 * if (epsilon_c_dot < -5.0)
1109 * return 0.0;
1110 * else if (epsilon_c_dot <= 3.0)
1111 * return 1.0/5.0;
1112 * else
1113 * return 0.0;
1114 * }
1115 *
1116 * template <int dim>
1117 * double MuscleFibre<dim>::get_c_c_V (void) const
1118 * {
1119 * if (epsilon_c_dot < -5.0)
1120 * return 0.0;
1121 * else if (epsilon_c_dot <= 3.0)
1122 * return 1.0;
1123 * else
1124 * return 1.6;
1125 * }
1126 *
1127 * template <int dim>
1128 * double MuscleFibre<dim>::get_beta(const double dt) const
1129 * {
1130 * return get_f_c_L()*get_m_c_V()*alpha/dt + get_m_s();
1131 * }
1132 *
1133 * template <int dim>
1134 * double MuscleFibre<dim>::get_gamma(const double dt) const
1135 * {
1136 * return get_f_c_L()*alpha*(get_m_c_V()*epsilon_c_t1/dt - get_c_c_V());
1137 * }
1138 *
1139 * template <int dim>
1140 * void MuscleFibre<dim>::update_state(const SymmetricTensor<2,dim> &strain_tensor,
1141 * const double dt)
1142 * {
1143 * @endcode
1144 *
1145 * Values from previous state
1146 * These were the values that were used in the assembly,
1147 * so we must use them in the update step to be consistant.
1148 * Need to compute these before we overwrite epsilon_c_t1
1149 *
1150 * @code
1151 * const double m_s = get_m_s();
1152 * const double beta = get_beta(dt);
1153 * const double gamma = get_gamma(dt);
1154 *
1155 * @endcode
1156 *
1157 * Update current state
1158 *
1159 * @code
1160 * alpha_t1 = alpha;
1161 * epsilon_f = M*static_cast< Tensor<2,dim> >(strain_tensor)*M;
1162 * epsilon_c_t1 = epsilon_c;
1163 * epsilon_c = (m_s*epsilon_f + gamma)/beta;
1164 * epsilon_c_dot = (epsilon_c - epsilon_c_t1)/dt;
1165 * }
1166 *
1167 *
1168 * @endcode
1169 *
1170 *
1171 * <a name="ThecodeLinearMuscleModelProblemcodeclasstemplate"></a>
1172 * <h3>The <code>LinearMuscleModelProblem</code> class template</h3>
1173 *
1174
1175 *
1176 *
1177 * @code
1178 * template <int dim>
1179 * class LinearMuscleModelProblem
1180 * {
1181 * public:
1182 * LinearMuscleModelProblem (const std::string &input_file);
1183 * ~LinearMuscleModelProblem ();
1184 * void run ();
1185 *
1186 * private:
1187 * void make_grid ();
1188 * void setup_muscle_fibres ();
1189 * double get_neural_signal (const double time);
1190 * void update_fibre_activation (const double time);
1191 * void update_fibre_state ();
1192 * void setup_system ();
1193 * void assemble_system (const double time);
1194 * void apply_boundary_conditions ();
1195 * void solve ();
1196 * void output_results (const unsigned int timestep,
1197 * const double time) const;
1198 *
1199 * Parameters::AllParameters parameters;
1200 *
1202 * DoFHandler<dim> dof_handler;
1203 *
1204 * FESystem<dim> fe;
1205 * QGauss<dim> qf_cell;
1206 * QGauss<dim-1> qf_face;
1207 *
1208 * AffineConstraints<double> hanging_node_constraints;
1209 *
1210 * SparsityPattern sparsity_pattern;
1211 * SparseMatrix<double> system_matrix;
1212 *
1213 * Vector<double> solution;
1214 * Vector<double> system_rhs;
1215 *
1216 * @endcode
1217 *
1218 * Time
1219 *
1220 * @code
1221 * const double t_end;
1222 * const double dt;
1223 * const double t_ramp_end; // Force ramp end time
1224 *
1225 * @endcode
1226 *
1227 * Loading
1228 *
1229 * @code
1230 * const BodyForce<dim> body_force;
1231 * const Traction<dim> traction;
1232 *
1233 * @endcode
1234 *
1235 * Local data
1236 *
1237 * @code
1238 * std::vector< std::vector<MuscleFibre<dim> > > fibre_data;
1239 *
1240 * @endcode
1241 *
1242 * Constitutive functions for assembly
1243 *
1244 * @code
1245 * SymmetricTensor<4,dim> get_stiffness_tensor (const unsigned int cell,
1246 * const unsigned int q_point_cell) const;
1247 * SymmetricTensor<2,dim> get_rhs_tensor (const unsigned int cell,
1248 * const unsigned int q_point_cell) const;
1249 * };
1250 *
1251 * @endcode
1252 *
1253 *
1254 * <a name="LinearMuscleModelProblemLinearMuscleModelProblem"></a>
1255 * <h4>LinearMuscleModelProblem::LinearMuscleModelProblem</h4>
1256 *
1257
1258 *
1259 *
1260 * @code
1261 * template <int dim>
1262 * LinearMuscleModelProblem<dim>::LinearMuscleModelProblem (const std::string &input_file)
1263 * :
1264 * parameters(input_file),
1265 * dof_handler (triangulation),
1266 * fe (FE_Q<dim>(parameters.poly_degree), dim),
1267 * qf_cell (parameters.quad_order),
1268 * qf_face (parameters.quad_order),
1269 * t_end (parameters.end_time),
1270 * dt (parameters.delta_t),
1271 * t_ramp_end(parameters.end_ramp_time),
1272 * body_force ((parameters.problem == "BicepsBrachii" &&parameters.include_gravity == true) ?
1273 * BodyForce<dim>(0.375*1000.0, Tensor<1,dim>({0,-1,0})) : // (reduced) Density and direction
1274 * BodyForce<dim>(0.0, Tensor<1,dim>({0,0,1})) ),
1275 * traction (parameters.problem == "BicepsBrachii" ?
1276 * Traction<dim>(parameters.axial_force, // Force, area
1277 * M_PI*std::pow(parameters.radius_insertion_origin *parameters.scale,2.0) ) :
1278 * Traction<dim>(4.9*convert_gf_to_N, // Force; Conversion of gf to N,
1279 * (2.0*parameters.half_length_y)*(2.0*parameters.half_length_z)) ) // Area
1280 * {
1281 * Assert(dim==3, ExcNotImplemented());
1282 * }
1283 *
1284 *
1285 * @endcode
1286 *
1287 *
1288 * <a name="LinearMuscleModelProblemLinearMuscleModelProblem"></a>
1289 * <h4>LinearMuscleModelProblem::~LinearMuscleModelProblem</h4>
1290 *
1291
1292 *
1293 *
1294 * @code
1295 * template <int dim>
1296 * LinearMuscleModelProblem<dim>::~LinearMuscleModelProblem ()
1297 * {
1298 * dof_handler.clear ();
1299 * }
1300 *
1301 *
1302 * @endcode
1303 *
1304 *
1305 * <a name="LinearMuscleModelProblemmake_grid"></a>
1306 * <h4>LinearMuscleModelProblem::make_grid</h4>
1307 *
1308
1309 *
1310 *
1311 * @code
1312 * template<int dim>
1313 * struct BicepsGeometry
1314 * {
1315 * BicepsGeometry(const double axial_length,
1316 * const double radius_ins_orig,
1317 * const double radius_mid)
1318 * :
1319 * ax_lgth (axial_length),
1320 * r_ins_orig (radius_ins_orig),
1321 * r_mid (radius_mid)
1322 * {}
1323 *
1324 * @endcode
1325 *
1326 * The radial profile of the muscle
1327 * This provides the new coordinates for points @p pt
1328 * on a cylinder of radius r_ins_orig and length
1329 * ax_lgth to be moved to in order to create the
1330 * physiologically representative geometry of
1331 * the muscle
1332 *
1333 * @code
1334 * Point<dim> profile (const Point<dim> &pt_0) const
1335 * {
1336 * Assert(pt_0[0] > -1e-6,
1337 * ExcMessage("All points must have x-coordinate > 0"));
1338 *
1339 * const double r_scale = get_radial_scaling_factor(pt_0[0]);
1340 * return pt_0 + Point<dim>(0.0, r_scale*pt_0[1], r_scale*pt_0[2]);
1341 * }
1342 *
1343 * Point<dim> operator() (const Point<dim> &pt) const
1344 * {
1345 * return profile(pt);
1346 * }
1347 *
1348 * @endcode
1349 *
1350 * Provides the muscle direction at the point @p pt
1351 * in the real geometry (one that has undergone the
1352 * transformation given by the profile() function)
1353 * and subequent grid rescaling.
1354 * The directions are given by the gradient of the
1355 * transformation function (i.e. the fibres are
1356 * orientated by the curvature of the muscle).
1357 *
1358
1359 *
1360 * So, being lazy, we transform the current point back
1361 * to the original point on the completely unscaled
1362 * cylindrical grid. We then evaluate the transformation
1363 * at two points (axially displaced) very close to the
1364 * point of interest. The normalised vector joining the
1365 * transformed counterparts of the perturbed points is
1366 * the gradient of the transformation function and,
1367 * thus, defines the fibre direction.
1368 *
1369 * @code
1370 * Tensor<1,dim> direction (const Point<dim> &pt_scaled,
1371 * const double &grid_scale) const
1372 * {
1373 * const Point<dim> pt = (1.0/grid_scale)*pt_scaled;
1374 * const Point<dim> pt_0 = inv_profile(pt);
1375 *
1376 * static const double eps = 1e-6;
1377 * const Point<dim> pt_0_eps_p = pt_0 + Point<dim>(+eps,0,0);
1378 * const Point<dim> pt_0_eps_m = pt_0 + Point<dim>(-eps,0,0);
1379 * const Point<dim> pt_eps_p = profile(pt_0_eps_p);
1380 * const Point<dim> pt_eps_m = profile(pt_0_eps_m);
1381 *
1382 * static const double tol = 1e-9;
1383 * Assert(profile(pt_0).distance(pt) < tol, ExcInternalError());
1384 * Assert(inv_profile(pt_eps_p).distance(pt_0_eps_p) < tol, ExcInternalError());
1385 * Assert(inv_profile(pt_eps_m).distance(pt_0_eps_m) < tol, ExcInternalError());
1386 *
1387 * Tensor<1,dim> dir = pt_eps_p-pt_eps_m;
1388 * dir /= dir.norm();
1389 * return dir;
1390 * }
1391 *
1392 * private:
1393 * const double ax_lgth;
1394 * const double r_ins_orig;
1395 * const double r_mid;
1396 *
1397 * double get_radial_scaling_factor (const double &x) const
1398 * {
1399 * @endcode
1400 *
1401 * Expect all grid points with X>=0, but we provide a
1402 * tolerant location for points "on" the Cartesian plane X=0
1403 *
1404 * @code
1405 * const double lgth_frac = std::max(x/ax_lgth,0.0);
1406 * const double amplitude = 0.25*(r_mid - r_ins_orig);
1407 * const double phase_shift = M_PI;
1408 * const double y_shift = 1.0;
1409 * const double wave_func = y_shift + std::cos(phase_shift + 2.0*M_PI*lgth_frac);
1410 * Assert(wave_func >= 0.0, ExcInternalError());
1411 * return std::sqrt(amplitude*wave_func);
1412 * }
1413 *
1414 * Point<dim> inv_profile (const Point<dim> &pt) const
1415 * {
1416 * Assert(pt[0] > -1e-6,
1417 * ExcMessage("All points must have x-coordinate > 0"));
1418 *
1419 * const double r_scale = get_radial_scaling_factor(pt[0]);
1420 * const double trans_inv_scale = 1.0/(1.0+r_scale);
1421 * return Point<dim>(pt[0], trans_inv_scale*pt[1], trans_inv_scale*pt[2]);
1422 * }
1423 * };
1424 *
1425 * template <int dim>
1426 * void LinearMuscleModelProblem<dim>::make_grid ()
1427 * {
1428 * Assert (dim == 3, ExcNotImplemented());
1429 *
1430 * if (parameters.problem == "IsotonicContraction")
1431 * {
1432 * const Point<dim> p1(-parameters.half_length_x,
1433 * -parameters.half_length_y,
1434 * -parameters.half_length_z);
1435 * const Point<dim> p2( parameters.half_length_x,
1436 * parameters.half_length_y,
1437 * parameters.half_length_z);
1438 *
1440 *
1442 * triangulation.begin_active(), endc = triangulation.end();
1443 * for (; cell != endc; ++cell)
1444 * {
1445 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
1446 * {
1447 * if (cell->face(face)->at_boundary() == true)
1448 * {
1449 * if (cell->face(face)->center()[0] == -parameters.half_length_x) // -X oriented face
1450 * cell->face(face)->set_boundary_id(parameters.bid_CC_dirichlet_symm_X); // Dirichlet
1451 * else if (cell->face(face)->center()[0] == parameters.half_length_x) // +X oriented face
1452 * cell->face(face)->set_boundary_id(parameters.bid_CC_neumann); // Neumann
1453 * else if (std::abs(cell->face(face)->center()[2]) == parameters.half_length_z) // -Z/+Z oriented face
1454 * cell->face(face)->set_boundary_id(parameters.bid_CC_dirichlet_symm_Z); // Dirichlet
1455 * }
1456 * }
1457 * }
1458 *
1459 * triangulation.refine_global (1);
1460 * }
1461 * else if (parameters.problem == "BicepsBrachii")
1462 * {
1463 * SphericalManifold<2> manifold_cap;
1464 * Triangulation<2> tria_cap;
1465 * GridGenerator::hyper_ball(tria_cap,
1466 * Point<2>(),
1467 * parameters.radius_insertion_origin);
1469 * cell = tria_cap.begin_active();
1470 * cell != tria_cap.end(); ++cell)
1471 * {
1472 * for (unsigned int face = 0; face < GeometryInfo<2>::faces_per_cell; ++face)
1473 * {
1474 * if (cell->face(face)->at_boundary() == true)
1475 * cell->face(face)->set_all_manifold_ids(0);
1476 * }
1477 * }
1478 * tria_cap.set_manifold (0, manifold_cap);
1479 * tria_cap.refine_global(parameters.n_refinements_radial);
1480 *
1481 * Triangulation<2> tria_cap_flat;
1482 * GridGenerator::flatten_triangulation(tria_cap, tria_cap_flat);
1483 *
1485 * parameters.elements_along_axis,
1486 * parameters.axial_length,
1487 * triangulation);
1488 *
1489 * struct GridRotate
1490 * {
1491 * Point<dim> operator() (const Point<dim> &in) const
1492 * {
1493 * static const Tensor<2,dim> rot_mat = Physics::Transformations::Rotations::rotation_matrix_3d(Tensor<1,dim>({0,1,0}), M_PI/2.0);
1494 * return Point<dim>(rot_mat*in);
1495 * }
1496 * };
1497 *
1498 * @endcode
1499 *
1500 * Rotate grid so that the length is axially
1501 * coincident and aligned with the X-axis
1502 *
1503 * @code
1504 * GridTools::transform (GridRotate(), triangulation);
1505 *
1506 * @endcode
1507 *
1508 * Deform the grid into something that vaguely
1509 * resemble's a Biceps Brachii
1510 *
1511 * @code
1512 * GridTools::transform (BicepsGeometry<dim>(parameters.axial_length,
1513 * parameters.radius_insertion_origin,
1514 * parameters.radius_midpoint), triangulation);
1515 *
1516 * @endcode
1517 *
1518 * Set boundary IDs
1519 *
1520 * @code
1521 * typename Triangulation<dim>::active_cell_iterator cell =
1522 * triangulation.begin_active(), endc = triangulation.end();
1523 * for (; cell != endc; ++cell)
1524 * {
1525 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
1526 * {
1527 * if (cell->face(face)->at_boundary() == true)
1528 * {
1529 * static const double tol =1e-6;
1530 * if (std::abs(cell->face(face)->center()[0]) < tol) // -X oriented face
1531 * cell->face(face)->set_boundary_id(parameters.bid_BB_dirichlet_X); // Dirichlet
1532 * else if (std::abs(cell->face(face)->center()[0] - parameters.axial_length) < tol) // +X oriented face
1533 * cell->face(face)->set_boundary_id(parameters.bid_BB_neumann); // Neumann
1534 * }
1535 * }
1536 * }
1537 *
1538 * @endcode
1539 *
1540 * Finally resize the grid
1541 *
1542 * @code
1543 * GridTools::scale (parameters.scale, triangulation);
1544 * }
1545 * else
1546 * AssertThrow(false, ExcNotImplemented());
1547 * }
1548 *
1549 * @endcode
1550 *
1551 *
1552 * <a name="LinearMuscleModelProblemsetup_muscle_fibres"></a>
1553 * <h4>LinearMuscleModelProblem::setup_muscle_fibres</h4>
1554 *
1555
1556 *
1557 *
1558 * @code
1559 * template <int dim>
1560 * void LinearMuscleModelProblem<dim>::setup_muscle_fibres ()
1561 * {
1562 * fibre_data.clear();
1563 * const unsigned int n_cells = triangulation.n_active_cells();
1564 * fibre_data.resize(n_cells);
1565 * const unsigned int n_q_points_cell = qf_cell.size();
1566 *
1567 * if (parameters.problem == "IsotonicContraction")
1568 * {
1569 * MuscleFibre<dim> fibre_template (Tensor<1,dim>({1,0,0}));
1570 *
1571 * for (unsigned int cell_no=0; cell_no<triangulation.n_active_cells(); ++cell_no)
1572 * {
1573 * fibre_data[cell_no].resize(n_q_points_cell);
1574 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1575 * {
1576 * fibre_data[cell_no][q_point_cell] = fibre_template;
1577 * }
1578 * }
1579 * }
1580 * else if (parameters.problem == "BicepsBrachii")
1581 * {
1582 * FEValues<dim> fe_values (fe, qf_cell, update_quadrature_points);
1583 * BicepsGeometry<dim> bicep_geom (parameters.axial_length,
1584 * parameters.radius_insertion_origin,
1585 * parameters.radius_midpoint);
1586 *
1587 * unsigned int cell_no = 0;
1588 * for (typename Triangulation<dim>::active_cell_iterator
1589 * cell = triangulation.begin_active();
1590 * cell != triangulation.end();
1591 * ++cell, ++cell_no)
1592 * {
1593 * Assert(cell_no<fibre_data.size(), ExcMessage("Trying to access fibre data not stored for this cell index"));
1594 * fe_values.reinit(cell);
1595 *
1596 * fibre_data[cell_no].resize(n_q_points_cell);
1597 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1598 * {
1599 * const Point<dim> pt = fe_values.get_quadrature_points()[q_point_cell];
1600 * fibre_data[cell_no][q_point_cell] = MuscleFibre<dim>(bicep_geom.direction(pt,parameters.scale));
1601 * }
1602 * }
1603 * }
1604 * else
1605 * AssertThrow(false, ExcNotImplemented());
1606 * }
1607 *
1608 * @endcode
1609 *
1610 *
1611 * <a name="LinearMuscleModelProblemupdate_fibre_state"></a>
1612 * <h4>LinearMuscleModelProblem::update_fibre_state</h4>
1613 *
1614
1615 *
1616 *
1617 * @code
1618 * template <int dim>
1619 * double LinearMuscleModelProblem<dim>::get_neural_signal (const double time)
1620 * {
1621 * @endcode
1622 *
1623 * Note: 40 times less force generated than Martins2006
1624 * This is necessary due to the (compliant) linear tissue model
1625 *
1626 * @code
1627 * return (time > parameters.neural_signal_start_time && time < parameters.neural_signal_end_time ?
1628 * 1.0/40.0 :
1629 * 0.0);
1630 * }
1631 *
1632 * template <int dim>
1633 * void LinearMuscleModelProblem<dim>::update_fibre_activation (const double time)
1634 * {
1635 * const double u = get_neural_signal(time);
1636 *
1637 * const unsigned int n_q_points_cell = qf_cell.size();
1638 * for (unsigned int cell=0; cell<triangulation.n_active_cells(); ++cell)
1639 * {
1640 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1641 * {
1642 * MuscleFibre<dim> &fibre = fibre_data[cell][q_point_cell];
1643 * fibre.update_alpha(u,dt);
1644 * }
1645 * }
1646 * }
1647 *
1648 * template <int dim>
1649 * void LinearMuscleModelProblem<dim>::update_fibre_state ()
1650 * {
1651 * const unsigned int n_q_points_cell = qf_cell.size();
1652 *
1653 * FEValues<dim> fe_values (fe, qf_cell, update_gradients);
1654 *
1655 * @endcode
1656 *
1657 * Displacement gradient
1658 *
1659 * @code
1660 * std::vector< std::vector< Tensor<1,dim> > > u_grads (n_q_points_cell,
1661 * std::vector<Tensor<1,dim> >(dim));
1662 *
1663 * unsigned int cell_no = 0;
1664 * for (typename DoFHandler<dim>::active_cell_iterator
1665 * cell = dof_handler.begin_active();
1666 * cell!=dof_handler.end(); ++cell, ++cell_no)
1667 * {
1668 * Assert(cell_no<fibre_data.size(), ExcMessage("Trying to access fibre data not stored for this cell index"));
1669 * fe_values.reinit(cell);
1670 * fe_values.get_function_gradients (solution, u_grads);
1671 *
1672 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1673 * {
1674 * Assert(q_point_cell<fibre_data[cell_no].size(), ExcMessage("Trying to access fibre data not stored for this cell and qp index"));
1675 *
1676 * const SymmetricTensor<2,dim> strain_tensor = get_small_strain (u_grads[q_point_cell]);
1677 * MuscleFibre<dim> &fibre = fibre_data[cell_no][q_point_cell];
1678 * fibre.update_state(strain_tensor, dt);
1679 * }
1680 * }
1681 * }
1682 *
1683 * @endcode
1684 *
1685 *
1686 * <a name="LinearMuscleModelProblemsetup_system"></a>
1687 * <h4>LinearMuscleModelProblem::setup_system</h4>
1688 *
1689
1690 *
1691 *
1692 * @code
1693 * template <int dim>
1694 * void LinearMuscleModelProblem<dim>::setup_system ()
1695 * {
1696 * dof_handler.distribute_dofs (fe);
1697 * hanging_node_constraints.clear ();
1698 * DoFTools::make_hanging_node_constraints (dof_handler,
1699 * hanging_node_constraints);
1700 * hanging_node_constraints.close ();
1701 * sparsity_pattern.reinit (dof_handler.n_dofs(),
1702 * dof_handler.n_dofs(),
1703 * dof_handler.max_couplings_between_dofs());
1704 * DoFTools::make_sparsity_pattern (dof_handler, sparsity_pattern);
1705 *
1706 * hanging_node_constraints.condense (sparsity_pattern);
1707 *
1708 * sparsity_pattern.compress();
1709 *
1710 * system_matrix.reinit (sparsity_pattern);
1711 *
1712 * solution.reinit (dof_handler.n_dofs());
1713 * system_rhs.reinit (dof_handler.n_dofs());
1714 *
1715 * std::cout << " Number of active cells: "
1716 * << triangulation.n_active_cells()
1717 * << std::endl;
1718 *
1719 * std::cout << " Number of degrees of freedom: "
1720 * << dof_handler.n_dofs()
1721 * << std::endl;
1722 * }
1723 *
1724 * @endcode
1725 *
1726 *
1727 * <a name="LinearMuscleModelProblemassemble_system"></a>
1728 * <h4>LinearMuscleModelProblem::assemble_system</h4>
1729 *
1730
1731 *
1732 *
1733 * @code
1734 * template <int dim>
1735 * SymmetricTensor<4,dim>
1736 * LinearMuscleModelProblem<dim>::get_stiffness_tensor (const unsigned int cell,
1737 * const unsigned int q_point_cell) const
1738 * {
1739 * static const SymmetricTensor<2,dim> I = unit_symmetric_tensor<dim>();
1740 *
1741 * Assert(cell<fibre_data.size(), ExcMessage("Trying to access fibre data not stored for this cell index"));
1742 * Assert(q_point_cell<fibre_data[cell].size(), ExcMessage("Trying to access fibre data not stored for this cell and qp index"));
1743 * const MuscleFibre<dim> &fibre = fibre_data[cell][q_point_cell];
1744 *
1745 * @endcode
1746 *
1747 * Matrix
1748 *
1749 * @code
1750 * const double lambda = MuscleMatrix::lambda;
1751 * const double mu = MuscleMatrix::mu;
1752 * @endcode
1753 *
1754 * Fibre
1755 *
1756 * @code
1757 * const double m_p = fibre.get_m_p();
1758 * const double m_s = fibre.get_m_s();
1759 * const double beta = fibre.get_beta(dt);
1760 * AssertThrow(beta != 0.0, ExcInternalError());
1761 * const double Cf = T0*(m_p + m_s*(1.0 - m_s/beta));
1762 * const Tensor<1,dim> &M = fibre.get_M();
1763 *
1764 * SymmetricTensor<4,dim> C;
1765 * for (unsigned int i=0; i < dim; ++i)
1766 * for (unsigned int j=i; j < dim; ++j)
1767 * for (unsigned int k=0; k < dim; ++k)
1768 * for (unsigned int l=k; l < dim; ++l)
1769 * {
1770 * @endcode
1771 *
1772 * Matrix contribution
1773 *
1774 * @code
1775 * C[i][j][k][l] = lambda * I[i][j]*I[k][l]
1776 * + mu * (I[i][k]*I[j][l] + I[i][l]*I[j][k]);
1777 *
1778 * @endcode
1779 *
1780 * Fibre contribution (Passive + active branches)
1781 *
1782 * @code
1783 * C[i][j][k][l] += Cf * M[i]*M[j]*M[k]*M[l];
1784 * }
1785 *
1786 * return C;
1787 * }
1788 *
1789 * template <int dim>
1790 * SymmetricTensor<2,dim>
1791 * LinearMuscleModelProblem<dim>::get_rhs_tensor (const unsigned int cell,
1792 * const unsigned int q_point_cell) const
1793 * {
1794 * Assert(cell<fibre_data.size(), ExcMessage("Trying to access fibre data not stored for this cell index"));
1795 * Assert(q_point_cell<fibre_data[cell].size(), ExcMessage("Trying to access fibre data not stored for this cell and qp index"));
1796 * const MuscleFibre<dim> &fibre = fibre_data[cell][q_point_cell];
1797 *
1798 * const double m_s = fibre.get_m_s();
1799 * const double beta = fibre.get_beta(dt);
1800 * const double gamma = fibre.get_gamma(dt);
1801 * AssertThrow(beta != 0.0, ExcInternalError());
1802 * const double Sf = T0*(m_s*gamma/beta);
1803 * const Tensor<1,dim> &M = fibre.get_M();
1804 *
1805 * SymmetricTensor<2,dim> S;
1806 * for (unsigned int i=0; i < dim; ++i)
1807 * for (unsigned int j=i; j < dim; ++j)
1808 * {
1809 * @endcode
1810 *
1811 * Fibre contribution (Active branch)
1812 *
1813 * @code
1814 * S[i][j] = Sf * M[i]*M[j];
1815 * }
1816 *
1817 * return S;
1818 * }
1819 *
1820 * @endcode
1821 *
1822 *
1823 * <a name="LinearMuscleModelProblemassemble_system"></a>
1824 * <h4>LinearMuscleModelProblem::assemble_system</h4>
1825 *
1826
1827 *
1828 *
1829 * @code
1830 * template <int dim>
1831 * void LinearMuscleModelProblem<dim>::assemble_system (const double time)
1832 * {
1833 * @endcode
1834 *
1835 * Reset system
1836 *
1837 * @code
1838 * system_matrix = 0;
1839 * system_rhs = 0;
1840 *
1841 * FEValues<dim> fe_values (fe, qf_cell,
1842 * update_values | update_gradients |
1843 * update_quadrature_points | update_JxW_values);
1844 * FEFaceValues<dim> fe_face_values (fe, qf_face,
1845 * update_values |
1846 * update_quadrature_points | update_JxW_values);
1847 *
1848 * const unsigned int dofs_per_cell = fe.dofs_per_cell;
1849 * const unsigned int n_q_points_cell = qf_cell.size();
1850 * const unsigned int n_q_points_face = qf_face.size();
1851 *
1852 * FullMatrix<double> cell_matrix (dofs_per_cell, dofs_per_cell);
1853 * Vector<double> cell_rhs (dofs_per_cell);
1854 *
1855 * std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell);
1856 *
1857 * @endcode
1858 *
1859 * Loading
1860 *
1861 * @code
1862 * std::vector<Vector<double> > body_force_values (n_q_points_cell,
1863 * Vector<double>(dim));
1864 * std::vector<Vector<double> > traction_values (n_q_points_face,
1865 * Vector<double>(dim));
1866 *
1867 * unsigned int cell_no = 0;
1868 * for (typename DoFHandler<dim>::active_cell_iterator
1869 * cell = dof_handler.begin_active();
1870 * cell!=dof_handler.end(); ++cell, ++cell_no)
1871 * {
1872 * cell_matrix = 0;
1873 * cell_rhs = 0;
1874 *
1875 * fe_values.reinit (cell);
1876 * body_force.vector_value_list (fe_values.get_quadrature_points(),
1877 * body_force_values);
1878 *
1879 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell)
1880 * {
1881 * const SymmetricTensor<4,dim> C = get_stiffness_tensor (cell_no, q_point_cell);
1882 * const SymmetricTensor<2,dim> R = get_rhs_tensor(cell_no, q_point_cell);
1883 *
1884 * for (unsigned int I=0; I<dofs_per_cell; ++I)
1885 * {
1886 * const unsigned int
1887 * component_I = fe.system_to_component_index(I).first;
1888 *
1889 * for (unsigned int J=0; J<dofs_per_cell; ++J)
1890 * {
1891 * const unsigned int
1892 * component_J = fe.system_to_component_index(J).first;
1893 *
1894 * for (unsigned int k=0; k < dim; ++k)
1895 * for (unsigned int l=0; l < dim; ++l)
1896 * cell_matrix(I,J)
1897 * += (fe_values.shape_grad(I,q_point_cell)[k] *
1898 * C[component_I][k][component_J][l] *
1899 * fe_values.shape_grad(J,q_point_cell)[l]) *
1900 * fe_values.JxW(q_point_cell);
1901 * }
1902 * }
1903 *
1904 * for (unsigned int I=0; I<dofs_per_cell; ++I)
1905 * {
1906 * const unsigned int
1907 * component_I = fe.system_to_component_index(I).first;
1908 *
1909 * cell_rhs(I)
1910 * += fe_values.shape_value(I,q_point_cell) *
1911 * body_force_values[q_point_cell](component_I) *
1912 * fe_values.JxW(q_point_cell);
1913 *
1914 * for (unsigned int k=0; k < dim; ++k)
1915 * cell_rhs(I)
1916 * += (fe_values.shape_grad(I,q_point_cell)[k] *
1917 * R[component_I][k]) *
1918 * fe_values.JxW(q_point_cell);
1919 * }
1920 * }
1921 *
1922 * for (unsigned int face = 0; face <GeometryInfo<dim>::faces_per_cell; ++face)
1923 * {
1924 * if (cell->face(face)->at_boundary() == true &&
1925 * ((parameters.problem == "IsotonicContraction" &&
1926 * cell->face(face)->boundary_id() == parameters.bid_CC_neumann) ||
1927 * (parameters.problem == "BicepsBrachii" &&
1928 * cell->face(face)->boundary_id() == parameters.bid_BB_neumann)) )
1929 * {
1930 * fe_face_values.reinit(cell, face);
1931 * traction.vector_value_list (fe_face_values.get_quadrature_points(),
1932 * traction_values);
1933 *
1934 * @endcode
1935 *
1936 * Scale applied traction according to time
1937 *
1938 * @code
1939 * const double ramp = (time <= t_ramp_end ? time/t_ramp_end : 1.0);
1940 * Assert(ramp >= 0.0 && ramp <= 1.0, ExcMessage("Invalid force ramp"));
1941 * for (unsigned int q_point_face = 0; q_point_face < n_q_points_face; ++q_point_face)
1942 * traction_values[q_point_face] *= ramp;
1943 *
1944 * for (unsigned int q_point_face = 0; q_point_face < n_q_points_face; ++q_point_face)
1945 * {
1946 * for (unsigned int I=0; I<dofs_per_cell; ++I)
1947 * {
1948 * const unsigned int
1949 * component_I = fe.system_to_component_index(I).first;
1950 *
1951 * cell_rhs(I)
1952 * += fe_face_values.shape_value(I,q_point_face)*
1953 * traction_values[q_point_face][component_I]*
1954 * fe_face_values.JxW(q_point_face);
1955 * }
1956 * }
1957 * }
1958 * }
1959 *
1960 * cell->get_dof_indices (local_dof_indices);
1961 * for (unsigned int i=0; i<dofs_per_cell; ++i)
1962 * {
1963 * for (unsigned int j=0; j<dofs_per_cell; ++j)
1964 * system_matrix.add (local_dof_indices[i],
1965 * local_dof_indices[j],
1966 * cell_matrix(i,j));
1967 *
1968 * system_rhs(local_dof_indices[i]) += cell_rhs(i);
1969 * }
1970 * }
1971 *
1972 * hanging_node_constraints.condense (system_matrix);
1973 * hanging_node_constraints.condense (system_rhs);
1974 * }
1975 *
1976 * template <int dim>
1977 * void LinearMuscleModelProblem<dim>::apply_boundary_conditions ()
1978 * {
1979 * std::map<types::global_dof_index,double> boundary_values;
1980 *
1981 * if (parameters.problem == "IsotonicContraction")
1982 * {
1983 * @endcode
1984 *
1985 * Symmetry condition on -X faces
1986 *
1987 * @code
1988 * {
1989 * ComponentMask component_mask_x (dim, false);
1990 * component_mask_x.set(0, true);
1991 * VectorTools::interpolate_boundary_values (dof_handler,
1992 * parameters.bid_CC_dirichlet_symm_X,
1993 * Functions::ZeroFunction<dim>(dim),
1994 * boundary_values,
1995 * component_mask_x);
1996 * }
1997 * @endcode
1998 *
1999 * Symmetry condition on -Z/+Z faces
2000 *
2001 * @code
2002 * {
2003 * ComponentMask component_mask_z (dim, false);
2004 * component_mask_z.set(2, true);
2005 * VectorTools::interpolate_boundary_values (dof_handler,
2006 * parameters.bid_CC_dirichlet_symm_Z,
2007 * Functions::ZeroFunction<dim>(dim),
2008 * boundary_values,
2009 * component_mask_z);
2010 * }
2011 * @endcode
2012 *
2013 * Fixed point on -X face
2014 *
2015 * @code
2016 * {
2017 * const Point<dim> fixed_point (-parameters.half_length_x,0.0,0.0);
2018 * std::vector<types::global_dof_index> fixed_dof_indices;
2019 * bool found_point_of_interest = false;
2020 *
2021 * for (typename DoFHandler<dim>::active_cell_iterator
2022 * cell = dof_handler.begin_active(),
2023 * endc = dof_handler.end(); cell != endc; ++cell)
2024 * {
2025 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2026 * {
2027 * @endcode
2028 *
2029 * We know that the fixed point is on the -X Dirichlet boundary
2030 *
2031 * @code
2032 * if (cell->face(face)->at_boundary() == true &&
2033 * cell->face(face)->boundary_id() == parameters.bid_CC_dirichlet_symm_X)
2034 * {
2035 * for (unsigned int face_vertex_index = 0; face_vertex_index < GeometryInfo<dim>::vertices_per_face; ++face_vertex_index)
2036 * {
2037 * if (cell->face(face)->vertex(face_vertex_index).distance(fixed_point) < 1e-6)
2038 * {
2039 * found_point_of_interest = true;
2040 * for (unsigned int index_component = 0; index_component < dim; ++index_component)
2041 * fixed_dof_indices.push_back(cell->face(face)->vertex_dof_index(face_vertex_index,
2042 * index_component));
2043 * }
2044 *
2045 * if (found_point_of_interest == true) break;
2046 * }
2047 * }
2048 * if (found_point_of_interest == true) break;
2049 * }
2050 * if (found_point_of_interest == true) break;
2051 * }
2052 *
2053 * Assert(found_point_of_interest == true, ExcMessage("Didn't find point of interest"));
2054 * AssertThrow(fixed_dof_indices.size() == dim, ExcMessage("Didn't find the correct number of DoFs to fix"));
2055 *
2056 * for (unsigned int i=0; i < fixed_dof_indices.size(); ++i)
2057 * boundary_values[fixed_dof_indices[i]] = 0.0;
2058 * }
2059 * }
2060 * else if (parameters.problem == "BicepsBrachii")
2061 * {
2062 * if (parameters.include_gravity == false)
2063 * {
2064 * @endcode
2065 *
2066 * Symmetry condition on -X surface
2067 *
2068 * @code
2069 * {
2070 * ComponentMask component_mask_x (dim, false);
2071 * component_mask_x.set(0, true);
2072 * VectorTools::interpolate_boundary_values (dof_handler,
2073 * parameters.bid_BB_dirichlet_X,
2074 * Functions::ZeroFunction<dim>(dim),
2075 * boundary_values,
2076 * component_mask_x);
2077 * }
2078 *
2079 * @endcode
2080 *
2081 * Fixed central point on -X surface
2082 *
2083 * @code
2084 * {
2085 * const Point<dim> fixed_point (0.0,0.0,0.0);
2086 * std::vector<types::global_dof_index> fixed_dof_indices;
2087 * bool found_point_of_interest = false;
2088 *
2089 * for (typename DoFHandler<dim>::active_cell_iterator
2090 * cell = dof_handler.begin_active(),
2091 * endc = dof_handler.end(); cell != endc; ++cell)
2092 * {
2093 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2094 * {
2095 * @endcode
2096 *
2097 * We know that the fixed point is on the -X Dirichlet boundary
2098 *
2099 * @code
2100 * if (cell->face(face)->at_boundary() == true &&
2101 * cell->face(face)->boundary_id() == parameters.bid_BB_dirichlet_X)
2102 * {
2103 * for (unsigned int face_vertex_index = 0; face_vertex_index < GeometryInfo<dim>::vertices_per_face; ++face_vertex_index)
2104 * {
2105 * if (cell->face(face)->vertex(face_vertex_index).distance(fixed_point) < 1e-6)
2106 * {
2107 * found_point_of_interest = true;
2108 * for (unsigned int index_component = 0; index_component < dim; ++index_component)
2109 * fixed_dof_indices.push_back(cell->face(face)->vertex_dof_index(face_vertex_index,
2110 * index_component));
2111 * }
2112 *
2113 * if (found_point_of_interest == true) break;
2114 * }
2115 * }
2116 * if (found_point_of_interest == true) break;
2117 * }
2118 * if (found_point_of_interest == true) break;
2119 * }
2120 *
2121 * Assert(found_point_of_interest == true, ExcMessage("Didn't find point of interest"));
2122 * AssertThrow(fixed_dof_indices.size() == dim, ExcMessage("Didn't find the correct number of DoFs to fix"));
2123 *
2124 * for (unsigned int i=0; i < fixed_dof_indices.size(); ++i)
2125 * boundary_values[fixed_dof_indices[i]] = 0.0;
2126 * }
2127 * }
2128 * else
2129 * {
2130 * @endcode
2131 *
2132 * When we apply gravity, some additional constraints
2133 * are required to support the load of the muscle, as
2134 * the material response is more compliant than would
2135 * be the case in reality.
2136 *
2137
2138 *
2139 * Symmetry condition on -X surface
2140 *
2141 * @code
2142 * {
2143 * ComponentMask component_mask_x (dim, true);
2144 * VectorTools::interpolate_boundary_values (dof_handler,
2145 * parameters.bid_BB_dirichlet_X,
2146 * Functions::ZeroFunction<dim>(dim),
2147 * boundary_values,
2148 * component_mask_x);
2149 * }
2150 * @endcode
2151 *
2152 * Symmetry condition on -X surface
2153 *
2154 * @code
2155 * {
2156 * ComponentMask component_mask_x (dim, false);
2157 * component_mask_x.set(1, true);
2158 * component_mask_x.set(2, true);
2159 * VectorTools::interpolate_boundary_values (dof_handler,
2160 * parameters.bid_BB_neumann,
2161 * Functions::ZeroFunction<dim>(dim),
2162 * boundary_values,
2163 * component_mask_x);
2164 * }
2165 * }
2166 *
2167 * @endcode
2168 *
2169 * Roller condition at central point on +X face
2170 *
2171 * @code
2172 * {
2173 * const Point<dim> roller_point (parameters.axial_length*parameters.scale,0.0,0.0);
2174 * std::vector<types::global_dof_index> fixed_dof_indices;
2175 * bool found_point_of_interest = false;
2176 *
2177 * for (typename DoFHandler<dim>::active_cell_iterator
2178 * cell = dof_handler.begin_active(),
2179 * endc = dof_handler.end(); cell != endc; ++cell)
2180 * {
2181 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2182 * {
2183 * @endcode
2184 *
2185 * We know that the fixed point is on the +X Neumann boundary
2186 *
2187 * @code
2188 * if (cell->face(face)->at_boundary() == true &&
2189 * cell->face(face)->boundary_id() == parameters.bid_BB_neumann)
2190 * {
2191 * for (unsigned int face_vertex_index = 0; face_vertex_index < GeometryInfo<dim>::vertices_per_face; ++face_vertex_index)
2192 * {
2193 * if (cell->face(face)->vertex(face_vertex_index).distance(roller_point) < 1e-6)
2194 * {
2195 * found_point_of_interest = true;
2196 * for (unsigned int index_component = 1; index_component < dim; ++index_component)
2197 * fixed_dof_indices.push_back(cell->face(face)->vertex_dof_index(face_vertex_index,
2198 * index_component));
2199 * }
2200 *
2201 * if (found_point_of_interest == true) break;
2202 * }
2203 * }
2204 * if (found_point_of_interest == true) break;
2205 * }
2206 * if (found_point_of_interest == true) break;
2207 * }
2208 *
2209 * Assert(found_point_of_interest == true, ExcMessage("Didn't find point of interest"));
2210 * AssertThrow(fixed_dof_indices.size() == dim-1, ExcMessage("Didn't find the correct number of DoFs to fix"));
2211 *
2212 * for (unsigned int i=0; i < fixed_dof_indices.size(); ++i)
2213 * boundary_values[fixed_dof_indices[i]] = 0.0;
2214 * }
2215 * }
2216 * else
2217 * AssertThrow(false, ExcNotImplemented());
2218 *
2219 * MatrixTools::apply_boundary_values (boundary_values,
2220 * system_matrix,
2221 * solution,
2222 * system_rhs);
2223 * }
2224 *
2225 *
2226 * @endcode
2227 *
2228 *
2229 * <a name="LinearMuscleModelProblemsolve"></a>
2230 * <h4>LinearMuscleModelProblem::solve</h4>
2231 *
2232
2233 *
2234 *
2235 * @code
2236 * template <int dim>
2237 * void LinearMuscleModelProblem<dim>::solve ()
2238 * {
2239 * SolverControl solver_control (system_matrix.m(), 1e-12);
2240 * SolverCG<> cg (solver_control);
2241 *
2242 * PreconditionSSOR<> preconditioner;
2243 * preconditioner.initialize(system_matrix, 1.2);
2244 *
2245 * cg.solve (system_matrix, solution, system_rhs,
2246 * preconditioner);
2247 *
2248 * hanging_node_constraints.distribute (solution);
2249 * }
2250 *
2251 *
2252 * @endcode
2253 *
2254 *
2255 * <a name="LinearMuscleModelProblemoutput_results"></a>
2256 * <h4>LinearMuscleModelProblem::output_results</h4>
2257 *
2258
2259 *
2260 *
2261
2262 *
2263 *
2264 * @code
2265 * template <int dim>
2266 * void LinearMuscleModelProblem<dim>::output_results (const unsigned int timestep,
2267 * const double time) const
2268 * {
2269 * @endcode
2270 *
2271 * Visual output: FEM results
2272 *
2273 * @code
2274 * {
2275 * std::string filename = "solution-";
2276 * filename += Utilities::int_to_string(timestep,4);
2277 * filename += ".vtk";
2278 * std::ofstream output (filename.c_str());
2279 *
2280 * DataOut<dim> data_out;
2281 * data_out.attach_dof_handler (dof_handler);
2282 *
2283 * std::vector<DataComponentInterpretation::DataComponentInterpretation>
2284 * data_component_interpretation(dim,
2285 * DataComponentInterpretation::component_is_part_of_vector);
2286 * std::vector<std::string> solution_name(dim, "displacement");
2287 *
2288 * data_out.add_data_vector (solution, solution_name,
2289 * DataOut<dim>::type_dof_data,
2290 * data_component_interpretation);
2291 * data_out.build_patches ();
2292 * data_out.write_vtk (output);
2293 * }
2294 *
2295 * @endcode
2296 *
2297 * Visual output: FEM data
2298 *
2299 * @code
2300 * {
2301 * std::string filename = "fibres-";
2302 * filename += Utilities::int_to_string(timestep,4);
2303 * filename += ".vtk";
2304 * std::ofstream output (filename.c_str());
2305 *
2306 * output
2307 * << "# vtk DataFile Version 3.0" << std::endl
2308 * << "# " << std::endl
2309 * << "ASCII"<< std::endl
2310 * << "DATASET POLYDATA"<< std::endl << std::endl;
2311 *
2312 * @endcode
2313 *
2314 * Extract fibre data from quadrature points
2315 *
2316 * @code
2317 * const unsigned int n_cells = triangulation.n_active_cells();
2318 * const unsigned int n_q_points_cell = qf_cell.size();
2319 *
2320 * @endcode
2321 *
2322 * Data that we'll be outputting
2323 *
2324 * @code
2325 * std::vector<std::string> results_fibre_names;
2326 * results_fibre_names.push_back("alpha");
2327 * results_fibre_names.push_back("epsilon_f");
2328 * results_fibre_names.push_back("epsilon_c");
2329 * results_fibre_names.push_back("epsilon_c_dot");
2330 *
2331 * const unsigned int n_results = results_fibre_names.size();
2332 * const unsigned int n_data_points = n_cells*n_q_points_cell;
2333 * std::vector< Point<dim> > output_points(n_data_points);
2334 * std::vector< Tensor<1,dim> > output_displacements(n_data_points);
2335 * std::vector< Tensor<1,dim> > output_directions(n_data_points);
2336 * std::vector< std::vector<double> > output_values(n_results, std::vector<double>(n_data_points));
2337 *
2338 * @endcode
2339 *
2340 * Displacement
2341 *
2342 * @code
2343 * std::vector< Vector<double> > u_values (n_q_points_cell,
2344 * Vector<double>(dim));
2345 * @endcode
2346 *
2347 * Displacement gradient
2348 *
2349 * @code
2350 * std::vector< std::vector< Tensor<1,dim> > > u_grads (n_q_points_cell,
2351 * std::vector<Tensor<1,dim> >(dim));
2352 *
2353 * FEValues<dim> fe_values (fe, qf_cell,
2355 * unsigned int cell_no = 0;
2356 * unsigned int fibre_no = 0;
2358 * cell = dof_handler.begin_active();
2359 * cell != dof_handler.end();
2360 * ++cell, ++cell_no)
2361 * {
2362 * fe_values.reinit (cell);
2363 * fe_values.get_function_values (solution, u_values);
2364 * fe_values.get_function_gradients (solution, u_grads);
2365 *
2366 * for (unsigned int q_point_cell=0; q_point_cell<n_q_points_cell; ++q_point_cell, ++fibre_no)
2367 * {
2368 * const MuscleFibre<dim> &fibre = fibre_data[cell_no][q_point_cell];
2369 * output_points[fibre_no] = fe_values.get_quadrature_points()[q_point_cell]; // Position
2370 * for (unsigned int d=0; d<dim; ++d)
2371 * output_displacements[fibre_no][d] = u_values[q_point_cell][d]; // Displacement
2372 * @endcode
2373 *
2374 * Direction (spatial configuration)
2375 *
2376 * @code
2377 * output_directions[fibre_no] = get_deformation_gradient(u_grads[q_point_cell])*fibre.get_M();
2378 * output_directions[fibre_no] /= output_directions[fibre_no].norm();
2379 *
2380 * @endcode
2381 *
2382 * Fibre values
2383 *
2384 * @code
2385 * output_values[0][fibre_no] = fibre.get_alpha();
2386 * output_values[1][fibre_no] = fibre.get_epsilon_f();
2387 * output_values[2][fibre_no] = fibre.get_epsilon_c();
2388 * output_values[3][fibre_no] = fibre.get_epsilon_c_dot();
2389 * }
2390 * }
2391 *
2392 * @endcode
2393 *
2394 * FIBRE POSITION
2395 *
2396 * @code
2397 * output
2398 * << "POINTS "
2399 * << n_data_points
2400 * << " float" << std::endl;
2401 * for (unsigned int i=0; i < n_data_points; ++i)
2402 * {
2403 * for (unsigned int j=0; j < dim; ++j)
2404 * {
2405 * output << (output_points)[i][j] << "\t";
2406 * }
2407 * output << std::endl;
2408 * }
2409 *
2410 * @endcode
2411 *
2412 * HEADER FOR POINT DATA
2413 *
2414 * @code
2415 * output << "\nPOINT_DATA "
2416 * << n_data_points
2417 * << std::endl << std::endl;
2418 *
2419 * @endcode
2420 *
2421 * FIBRE DISPLACEMENTS
2422 *
2423 * @code
2424 * output
2425 * << "VECTORS displacement float"
2426 * << std::endl;
2427 * for (unsigned int i = 0; i < n_data_points; ++i)
2428 * {
2429 * for (unsigned int j=0; j < dim; ++j)
2430 * {
2431 * output << (output_displacements)[i][j] << "\t";
2432 * }
2433 * output << std::endl;
2434 * }
2435 * output << std::endl;
2436 *
2437 * @endcode
2438 *
2439 * FIBRE DIRECTIONS
2440 *
2441 * @code
2442 * output
2443 * << "VECTORS direction float"
2444 * << std::endl;
2445 * for (unsigned int i = 0; i < n_data_points; ++i)
2446 * {
2447 * for (unsigned int j=0; j < dim; ++j)
2448 * {
2449 * output << (output_directions)[i][j] << "\t";
2450 * }
2451 * output << std::endl;
2452 * }
2453 * output << std::endl;
2454 *
2455 * @endcode
2456 *
2457 * POINT DATA
2458 *
2459 * @code
2460 * for (unsigned int v=0; v < n_results; ++v)
2461 * {
2462 * output
2463 * << "SCALARS "
2464 * << results_fibre_names[v]
2465 * << " float 1" << std::endl
2466 * << "LOOKUP_TABLE default "
2467 * << std::endl;
2468 * for (unsigned int i=0; i<n_data_points; ++i)
2469 * {
2470 * output << (output_values)[v][i] << " ";
2471 * }
2472 * output << std::endl;
2473 * }
2474 * }
2475 *
2476 * @endcode
2477 *
2478 * Output X-displacement at measured point
2479 *
2480 * @code
2481 * {
2482 * const Point<dim> meas_pt (parameters.problem == "IsotonicContraction" ?
2483 * Point<dim>(parameters.half_length_x, 0.0, 0.0) :
2484 * Point<dim>(parameters.axial_length*parameters.scale, 0.0, 0.0) );
2485 *
2486 *
2487 * const unsigned int index_of_interest = 0;
2488 * bool found_point_of_interest = false;
2490 *
2492 * cell = dof_handler.begin_active(),
2493 * endc = dof_handler.end(); cell != endc; ++cell)
2494 * {
2495 * for (unsigned int face = 0; face < GeometryInfo<dim>::faces_per_cell; ++face)
2496 * {
2497 * @endcode
2498 *
2499 * We know that the measurement point is on the Neumann boundary
2500 *
2501 * @code
2502 * if (cell->face(face)->at_boundary() == true &&
2503 * ((parameters.problem == "IsotonicContraction" &&
2504 * cell->face(face)->boundary_id() == parameters.bid_CC_neumann) ||
2505 * (parameters.problem == "BicepsBrachii" &&
2506 * cell->face(face)->boundary_id() == parameters.bid_BB_neumann)) )
2507 * {
2508 * for (unsigned int face_vertex_index = 0; face_vertex_index < GeometryInfo<dim>::vertices_per_face; ++face_vertex_index)
2509 * {
2510 * if (cell->face(face)->vertex(face_vertex_index).distance(meas_pt) < 1e-6)
2511 * {
2512 * found_point_of_interest = true;
2513 * dof_of_interest = cell->face(face)->vertex_dof_index(face_vertex_index,
2514 * index_of_interest);
2515 * }
2516 *
2517 * if (found_point_of_interest == true) break;
2518 * }
2519 * }
2520 * if (found_point_of_interest == true) break;
2521 * }
2522 * if (found_point_of_interest == true) break;
2523 * }
2524 *
2525 * Assert(found_point_of_interest == true, ExcMessage("Didn't find point of interest"));
2526 * Assert(dof_of_interest != numbers::invalid_dof_index, ExcMessage("Didn't find DoF of interest"));
2527 * Assert(dof_of_interest < dof_handler.n_dofs(), ExcMessage("DoF index out of range"));
2528 *
2529 * const std::string filename = "displacement_POI.csv";
2530 * std::ofstream output;
2531 * if (timestep == 0)
2532 * {
2533 * output.open(filename.c_str(), std::ofstream::out);
2534 * output
2535 * << "Time [s]" << "," << "X-displacement [mm]" << std::endl;
2536 * }
2537 * else
2538 * output.open(filename.c_str(), std::ios_base::app);
2539 *
2540 * output
2541 * << time
2542 * << ","
2543 * << solution[dof_of_interest]*1e3
2544 * << std::endl;
2545 * }
2546 * }
2547 *
2548 *
2549 *
2550 * @endcode
2551 *
2552 *
2553 * <a name="LinearMuscleModelProblemrun"></a>
2554 * <h4>LinearMuscleModelProblem::run</h4>
2555 *
2556
2557 *
2558 *
2559 * @code
2560 * template <int dim>
2561 * void LinearMuscleModelProblem<dim>::run ()
2562 * {
2563 * make_grid();
2564 * setup_system ();
2565 * setup_muscle_fibres ();
2566 *
2567 * @endcode
2568 *
2569 * const bool do_grid_refinement = false;
2570 *
2571 * @code
2572 * double time = 0.0;
2573 * for (unsigned int timestep=0; time<=t_end; ++timestep, time+=dt)
2574 * {
2575 * std::cout
2576 * << "Timestep " << timestep
2577 * << " @ time " << time
2578 * << std::endl;
2579 *
2580 * @endcode
2581 *
2582 * First we update the fibre activation level
2583 * based on the current time
2584 *
2585 * @code
2586 * update_fibre_activation(time);
2587 *
2588 * @endcode
2589 *
2590 * Next we assemble the system and enforce boundary
2591 * conditions.
2592 * Here we assume that the system and fibres have
2593 * a fixed state, and we will assemble based on how
2594 * epsilon_c will update given the current state of
2595 * the body.
2596 *
2597 * @code
2598 * assemble_system (time);
2599 * apply_boundary_conditions ();
2600 *
2601 * @endcode
2602 *
2603 * Then we solve the linear system
2604 *
2605 * @code
2606 * solve ();
2607 *
2608 * @endcode
2609 *
2610 * Now we update the fibre state based on the new
2611 * displacement solution and the constitutive
2612 * parameters assumed to govern the stiffness of
2613 * the fibres at the previous state. i.e. We
2614 * follow through with assumed update conditions
2615 * used in the assembly phase.
2616 *
2617 * @code
2618 * update_fibre_state();
2619 *
2620 * @endcode
2621 *
2622 * Output some values to file
2623 *
2624 * @code
2625 * output_results (timestep, time);
2626 * }
2627 * }
2628 * }
2629 *
2630 * @endcode
2631 *
2632 *
2633 * <a name="Thecodemaincodefunction"></a>
2634 * <h3>The <code>main</code> function</h3>
2635 *
2636
2637 *
2638 *
2639 * @code
2640 * int main ()
2641 * {
2642 * try
2643 * {
2645 * const unsigned int dim = 3;
2646 *
2647 * LMM::LinearMuscleModelProblem<dim> lmm_problem ("parameters.prm");
2648 * lmm_problem.run ();
2649 * }
2650 * catch (std::exception &exc)
2651 * {
2652 * std::cerr << std::endl << std::endl
2653 * << "----------------------------------------------------"
2654 * << std::endl;
2655 * std::cerr << "Exception on processing: " << std::endl
2656 * << exc.what() << std::endl
2657 * << "Aborting!" << std::endl
2658 * << "----------------------------------------------------"
2659 * << std::endl;
2660 *
2661 * return 1;
2662 * }
2663 * catch (...)
2664 * {
2665 * std::cerr << std::endl << std::endl
2666 * << "----------------------------------------------------"
2667 * << std::endl;
2668 * std::cerr << "Unknown exception!" << std::endl
2669 * << "Aborting!" << std::endl
2670 * << "----------------------------------------------------"
2671 * << std::endl;
2672 * return 1;
2673 * }
2674 *
2675 * return 0;
2676 * }
2677 * @endcode
2678
2679
2680*/
Definition: fe_q.h:549
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
unsigned int depth_console(const unsigned int n)
Definition: logstream.cc:350
virtual void parse_input(std::istream &input, const std::string &filename="input file", const std::string &last_line="", const bool skip_undefined=false)
Definition: point.h:111
Definition: tensor.h:503
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
Definition: vector.h:109
@ update_values
Shape function values.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
unsigned int level
Definition: grid_out.cc:4606
__global__ void set(Number *val, const Number s, const size_type N)
#define Assert(cond, exc)
Definition: exceptions.h:1473
#define AssertThrow(cond, exc)
Definition: exceptions.h:1583
typename ActiveSelector::active_cell_iterator active_cell_iterator
Definition: dof_handler.h:438
void set_manifold(const types::manifold_id number, const Manifold< dim, spacedim > &manifold_object)
LogStream deallog
Definition: logstream.cc:37
void approximate(SynchronousIterators< std::tuple< typename DoFHandler< dim, spacedim >::active_cell_iterator, Vector< float >::iterator > > const &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 > &center=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)
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2084
void transform(const Transformation &transformation, Triangulation< dim, spacedim > &triangulation)
@ matrix
Contents is actually a matrix.
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition: utilities.cc:190
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)
Tensor< 2, 3, Number > rotation_matrix_3d(const Tensor< 1, 3, Number > &axis, const Number &angle)
VectorType::value_type * end(VectorType &V)
void run(const Iterator &begin, const typename identity< Iterator >::type &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)
Definition: work_stream.h:474
long double gamma(const unsigned int n)
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
Definition: tria.cc:13734
int(&) functions(const void *v1, const void *v2)
void assemble(const MeshWorker::DoFInfoBox< dim, DOFINFO > &dinfo, A *assembler)
Definition: loop.h:71
const types::global_dof_index invalid_dof_index
Definition: types.h:216
void transform(const InputIterator &begin_in, const InputIterator &end_in, OutputIterator out, const Predicate &predicate, const unsigned int grainsize)
Definition: parallel.h:135
::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
const ::Triangulation< dim, spacedim > & tria