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