diff --git a/Documentation/Doxygen/building_a_plugin.dox b/Documentation/Doxygen/building_a_plugin.dox index 9441972a0..4a3066008 100644 --- a/Documentation/Doxygen/building_a_plugin.dox +++ b/Documentation/Doxygen/building_a_plugin.dox @@ -1,7 +1,7 @@ /** \page building_a_plugin Building a Plugin -In order to build a plugin you need to have the FEBio SDK (Software Development Kit). This SDK contains the header files and the pre-built libraries that you need to create a plugin. The SDK can be obtained from the febio website www.febio.org and is usually installed in the same location as FEBio usually in a subfolder named sdk). Next, you need a C++ compiler since the plugin has to be written in C++. We also recommend having an IDE (Integrated Development Environment) as this makes writing code much easier (e.g. Visual Studio on Windows, or XCode on Mac). Select one of the following links to learn more about setting up a plugin project for a specific operating system. +In order to build a plugin you need to have the FEBio SDK (Software Development Kit). This SDK contains the header files and the pre-built libraries that you need to create a plugin. The SDK is installed (optionally) as part of the FEBio Studio installation and is usually installed in the same location as FEBio in a subfolder named sdk). Next, you need a C++ compiler since the plugin has to be written in C++. We also recommend having an IDE (Integrated Development Environment) as this makes writing code much easier (e.g. Visual Studio on Windows, or XCode on Mac). Select one of the following links to learn more about setting up a plugin project for a specific operating system. \li \subpage create_plugin_vs \li \subpage create_plugin_osx diff --git a/Documentation/Doxygen/callback.dox b/Documentation/Doxygen/callback.dox index 720f2c312..ec6600a05 100644 --- a/Documentation/Doxygen/callback.dox +++ b/Documentation/Doxygen/callback.dox @@ -3,7 +3,7 @@ An easy, although somewhat limited, way to extend FEBio's capabilities is by defining callbacks. A callback is a function that is defined by the user and is called by the FEBio framework at specific places in the code. -FEBio uses this callback mechanism to accomplish several things. A callback is used to update the title of the shell window to display the progress, to query for user interruptions (ctrl+c), and to write the output to the log and plot file. +FEBio uses this callback mechanism to accomplish several things: A callback is used to update the title of the shell window to display the progress, to query for user interruptions (ctrl+c), and to write the output to the log and plot file. To register a callback function, call the FEModel::AddCallback function. diff --git a/Documentation/Doxygen/cb_plugin.dox b/Documentation/Doxygen/cb_plugin.dox index 535bd2fb0..99cadf3c9 100644 --- a/Documentation/Doxygen/cb_plugin.dox +++ b/Documentation/Doxygen/cb_plugin.dox @@ -68,7 +68,7 @@ In order to use a callback plugin, it must be registered with the framework. Thi REGISTER_FECORE_CLASS(MyCallbackPlugin, "my_callback"); \endcode -Once the plugin is registered, it can be reference in the FEBio input file. A special Code section can be added where the callbacks can be defined. +Once the plugin is registered, it can be referenced in the FEBio input file. A special Code section can be added where the callbacks can be defined. \code diff --git a/Documentation/Doxygen/create_plugin_vs.dox b/Documentation/Doxygen/create_plugin_vs.dox index f959063c3..5c6ba932b 100644 --- a/Documentation/Doxygen/create_plugin_vs.dox +++ b/Documentation/Doxygen/create_plugin_vs.dox @@ -23,6 +23,10 @@ Next, we'll need to tell Visual Studio where to find the FEBio header (.h) and l Locate the VC++ Directories in the Configuration Properties. In the Include Directories, add the path to the include files (e.g. "C:\Program Files\FEBio2\sdk\include"). To do this, select the "Include Directories" property and click the button on the right of the text edit field. Select "Edit..," from the popup menu. In the dialog box that pops up, the FEBio include folder can be added. Close OK when done. Then, add the path to the FEBio library files to the "Library Directories field" (e.g. "C:\Program Files\FEBio3\sdk\lib\"). When done, press the OK button. +It is also necessary to define the WIN32 preprocessor macro. This can be set in the Properties dialog box under the Configuration Properties\C/C++\Preprocessor. Then add WIN32 to the Preprocessor definitions. + +Note that the previous steps need to be done for both the Debug and Release configurations separately. Also make sure to link to the FEBio debug libraries when building the Debug configuration of your plugin, and similarly link to the FEBui release libraries when building the Release configuration. Using the wrong libraries may lead to build or runtime errors. Keep in mind that using the debug libraries may result in poor performance. This is to be expected. The debug libraries should only be used for initial testing and debugging. The release libraries should be used for the actual simulations. + \image html create_plugin_with_vs_step_4.png Now you are ready to write your plugin. diff --git a/Documentation/Doxygen/factory_classes.dox b/Documentation/Doxygen/factory_classes.dox index 4c3ee7cd7..c807b6432 100644 --- a/Documentation/Doxygen/factory_classes.dox +++ b/Documentation/Doxygen/factory_classes.dox @@ -5,7 +5,7 @@ Before a plugin class can be recognized by FEBio it must be registered with the \section init_plugin Using PluginInitialize -The PluginInitialize is one of the required functions and will be called by FEBio after it loads the plugin file. In this function a plugin can and allocate and initialize any resources it may need. In this function the plugin classes can be registered using the REGISTER_FECORE_CLASS macro. However, before this macro is used it is important to call FECoreKernel::SetInstance with the parameter that is passed to PluginInitialize. +The PluginInitialize is one of the required functions and will be called by FEBio after it loads the plugin file. In this function a plugin can allocate and initialize any resources it may need. In this function the plugin classes can be registered using the REGISTER_FECORE_CLASS macro. However, before this macro is used it is important to call FECoreKernel::SetInstance with the parameter that is passed to PluginInitialize. \code FECORE_EXPORT void PluginInitialize(FECoreKernel& fecore) @@ -18,7 +18,7 @@ FECORE_EXPORT void PluginInitialize(FECoreKernel& fecore) } \endcode -The first call the FECoreKernel::SetInstance is important to make sure that the plugin and FEBio are using the same kernel. Without this call, all classes will be registered with a local copy of the kernel and FEBio will not know of any new classes that are registered. +The first call the FECoreKernel::SetInstance is important to make sure that the plugin and FEBio are using the same kernel. Without this call, all classes will be registered to a local copy of the kernel and FEBio will not know of any new classes that are registered. The macro REGISTER_FECORE_CLASS takes two parameters. The first parameter is the name of a plugin class. The second parameter is a name that will be used to represent this class in the FEBio input file. diff --git a/Documentation/Doxygen/febio.dox b/Documentation/Doxygen/febio.dox index d9de7f5a9..3e92d6738 100644 --- a/Documentation/Doxygen/febio.dox +++ b/Documentation/Doxygen/febio.dox @@ -2,7 +2,7 @@ \page febio Overview of FEBio FEBio is a finite element solver that is specifically designed for biomechanical applications. It solves the nonlinear finite -element equations using a quasi-Newton method. It offers biologically relevant constitutive models and modeling scenarios. +element equations using a quasi-Newton method. It offers biologically relevant constitutive models and modeling scenarios. The source code is organized into different modules, each module implemented in a separate library. The following figure shows the relationship between the different modules. diff --git a/Documentation/Doxygen/febiolib.dox b/Documentation/Doxygen/febiolib.dox index e301d282c..5a22307cf 100644 --- a/Documentation/Doxygen/febiolib.dox +++ b/Documentation/Doxygen/febiolib.dox @@ -2,7 +2,7 @@ \page febiolib Extending the FEBio Library -Although the plugin framework is the recommended way for extending FEBio's feature set, people who so choose can also extend the FEBio library directly. Also, people who want to integrate FEBio in their own code, must work of the FEBio lirary. +Although the plugin framework is the recommended way for extending FEBio's feature set, people who so choose can also extend the FEBio library directly. Also, people who want to integrate FEBio in their own code, must work with the FEBio lirary. \li \subpage register \li \subpage callback diff --git a/Documentation/Doxygen/index.dox b/Documentation/Doxygen/index.dox index 8e568b198..0ed40f779 100644 --- a/Documentation/Doxygen/index.dox +++ b/Documentation/Doxygen/index.dox @@ -1,6 +1,6 @@ /** \mainpage FEBio Developer's Manual -The FEBio Developer's Manual describes how to extend the default feature set of FEBio. There are several ways in which this can be done. The source code is available for download so users can make their changes directly there. FEBio can also be used as a static library which makes it easy to use in other programs. FEBio also has a plugin mechanism that allows users to add new features without changing the source code or building the entire source code tree. +The FEBio Developer's Manual describes how to extend the default feature set of FEBio. There are several ways in which this can be done. The source code is available for download (https://github.com/febiosoftware/FEBio). Users can download or clone the github repo and make their changes directly in the source code. FEBio can also be used as a static library, which makes it easy to use FEBio in other codes. FEBio also has a plugin mechanism that allows users to add new features without changing the source code or building the entire source code tree. \li \subpage febio \li \subpage plugins @@ -9,5 +9,5 @@ The FEBio Developer's Manual describes how to extend the default feature set of The FEBio software is developed at the Musculoskeletal Research Laboratories at the University of Utah and at the Musculoskeletal Biomechanics Laboratory at Columbia University. -All rights reserved. Copyright (c) 2006 - 2021 +All rights reserved. Copyright (c) 2006 - 2022 */ diff --git a/Documentation/Doxygen/material.dox b/Documentation/Doxygen/material.dox index 5ef668e9d..975c003b5 100644 --- a/Documentation/Doxygen/material.dox +++ b/Documentation/Doxygen/material.dox @@ -5,7 +5,7 @@ In this section we will look at the details of setting up a plugin that implemen The basic procedure for creating a new material for FEBio requires the following steps. -1. Defining a new material class by deriving it from an available base class. +1. Defining a new material class by deriving it from an suitable base class. 2. Registering the material with FEBio's framework. 3. Defining the material parameters. 4. Implementing the Init() and Validate() functions (optional) @@ -277,14 +277,14 @@ FEBio will recognize the type identifier as the name of the MyFancyMaterial clas Material parameters are identified in a similar way. For each material parameter, the ADD_PARAMETER macro associates a name with the parameter. For example, imagine that for our new class MyFancyMaterial the following parameter is defined, \code -ADD_PARAMETER(m_a, "param_a"); +ADD_PARAMETER(m_a, "a"); \endcode The user can now enter a value for this parameter in the FEBio input file as follows, \code - 0.123 + 0.123 \endcode diff --git a/Documentation/Doxygen/restart.dox b/Documentation/Doxygen/restart.dox index c667e243b..42525b68e 100644 --- a/Documentation/Doxygen/restart.dox +++ b/Documentation/Doxygen/restart.dox @@ -1,7 +1,7 @@ /** \page restart Restart Capabilities -FEBio has several mechanism for restarting a problem. The "running restart" capability allows the model to recover from a fatal error during runtime and restart +FEBio has several mechanism for restarting a problem. The "running restart" capability allows the model to recover from an otherwise fatal error during runtime and restart from the last converged state. The "cold restart" allows the user to restart an analysis using a restart file. Again, the analysis will restart from the last converged state (for which a dump file was created). The "reset" feature allows a user to reset all data and restart the analysis from scratch. The following sections describe these features in more detail. diff --git a/Documentation/Doxygen/serialize.dox b/Documentation/Doxygen/serialize.dox index 4423f3527..f07671f9a 100644 --- a/Documentation/Doxygen/serialize.dox +++ b/Documentation/Doxygen/serialize.dox @@ -1,16 +1,15 @@ /** \page serialize Data Serialization -Data serialization refers to the process of reading and writing class data to or from an external file. This feature is used for the (cold) restart capability, that +Data serialization refers to the process of reading and writing class data to or from an external file. This feature is used for the restart capabilities, that allows an analysis to restart from a previous state. Most aspects of serialization is taken care of by the framework, however in some cases a class needs to implement additional support by implementing the \c Serialize member. -This function takes a single parameter, namely the so-called dump file. +This function takes a single parameter, namely the dump stream. \code -void MyClass::Serialize(DumpFile& ar) +void MyClass::Serialize(DumpStream& ar) { - FEModel& fem = *ar.GetFEModel(); if (ar.IsSaving()) { // write data using the << operator @@ -22,7 +21,52 @@ void MyClass::Serialize(DumpFile& ar) } \endcode -The FEModel that the class belongs to can be recovered from DumpFile::GetFEModel(). Data is written to the dump file using the << operators (just like when -using std::cout). Data is read from the dump file using the >> operators (just like using std::cin). Note that it is important that data is read in the same order -as it was written. +Data is written to the dump stream using the << operators (just like when using std::cout). Data is read from the dump file using the >> operators (just like using std::cin). Note that it is important that data is read in the same order as it was written. + +Alternatively, you can use the ampersand operator (&), which will write on saving and read on loading. + +For instance, consider a class, MyClass, that defines two parameters, m_a and m_b. You can serialize using either the explicit read and write operators. + +\code +void MyClass::Serialize(DumpStream& ar) +{ + if (ar.IsSaving()) + { + ar << m_a << m_b; + } + else + { + ar >> m_a >> m_b; + } +} +\endcode + +Alternatively, the following code is equivalent. + +\code +void MyClass::Serialize(DumpStream& ar) +{ + ar & m_a & m_b; +} +\endcode + +\section ser_sec1 Shallow vs Deep Serialization + +The serialization is used during running restarts and cold restarts. A running restart happens when a time step fails and the model's state needs to be restored to the last converged time step so that a new time step size can be tried. A cold restart happens when a model is restarted from a dump file (or restart input file). + +During a running restart, not all of the model data needs to be serialized. (For instance, initial nodal coordinates, constant material parameter, and other values that do not change during the solution process.) In this case, only a "shallow" copy of the model needs to be stored to the dumpstream. This is in contrast to the cold restart, when a "deep" copy needs to be read, since all model parameters need to be restored from the dumpstream. + +You can check whether a shallow or deep copy needs to be serialized using the \c DumpStream::IsShallow function. For instance, the following code illustrates how to serialize data for cold restarts. + +\code +void MyClass::Serialize(DumpStream& ar) +{ + if (ar.IsShallow() == false) + { + ar & m_a & m_b; + } +} +\endcode + + */ diff --git a/Documentation/Doxygen/task.dox b/Documentation/Doxygen/task.dox index 34b22093d..05defeda9 100644 --- a/Documentation/Doxygen/task.dox +++ b/Documentation/Doxygen/task.dox @@ -25,9 +25,9 @@ class MyTask : public FECoreTask public: MyTask(FEModel* pfem); - bool Init(const char* szfile); + bool Init(const char* szfile) override; - bool Run(); + bool Run() override; } \endcode @@ -46,9 +46,7 @@ This function should at least call the FEModel::Init function to initialize the after these changes. Once FEModel::Init is called, a task should not add to or remove any model components to the FEModel. \subsection task_sec13 Implement the Run function -After FEBio is done initializing the model data, it will call the selected task's Run function and passes the main execution loop to the task. The parameter passed to the Run -function is a (optional) filename that was passed on the command line after the -task=[task_name] command. Note that this will not be the model input file (specified with -i) and -this parameter can be NULL. +After FEBio is done initializing the model data, it will call the selected task's Run function and passes the main execution loop to the task. Inside the Run() function, the task can execute the code that implements the task. After completing, the Run() function must return a boolean indicating whether the task was executed successfully (true) or not (false). diff --git a/Documentation/Doxygen/using_plugins.dox b/Documentation/Doxygen/using_plugins.dox index bd67764cd..d31d2fe0c 100644 --- a/Documentation/Doxygen/using_plugins.dox +++ b/Documentation/Doxygen/using_plugins.dox @@ -19,7 +19,7 @@ If you wish to load many plugins, and these plugins are all located in the same $(PluginFolder)\plugin.dll \endcode -When FEBio starts it will read the configuration file and try to load all plugins listed therein. A message will be printed on the screen at the start of an FEBio analysis indicating if FEBio was successful in loading the plugin. +When FEBio starts, it will read the configuration file and try to load all plugins listed therein. A message will be printed on the screen at the start of an FEBio analysis indicating if FEBio was successful in loading the plugin. Alternatively, you can add the path to a plugin to the FEBio command line with the -import command line option. diff --git a/Documentation/FEBio3.bib b/Documentation/FEBio3.bib index a96bba5f8..65b676045 100644 --- a/Documentation/FEBio3.bib +++ b/Documentation/FEBio3.bib @@ -1,7 +1,7 @@ %% This BibTeX bibliography file was created using BibDesk. %% http://bibdesk.sourceforge.net/ -%% Created for Gerard Ateshian at 2022-02-16 17:30:32 -0500 +%% Created for Gerard Ateshian at 2022-04-16 18:28:43 -0400 %% Saved with string encoding Unicode (UTF-8) @@ -11,6 +11,43 @@ @comment{jabref-meta: +@article{Hunter98, + abstract = {A model of passive and active cardiac muscle mechanics is presented, suitable for use in continuum mechanics models of the whole heart. The model is based on an extensive review of experimental data from a variety of preparations (intact trabeculae, skinned fibres and myofibrils) and species (mainly rat and ferret) at temperatures from 20 to 27 degrees C. Experimental tests include isometric tension development, isotonic loading, quick-release/restretch, length step and sinusoidal perturbations. We show that all of these experiments can be interpreted with a four state variable model which includes (i) the passive elasticity of myocardial tissue, (ii) the rapid binding of Ca2+ to troponin C and its slower tension-dependent release, (iii) the kinetics of tropomyosin movement and availability of crossbridge binding sites and the length dependence of this process and (iv) the kinetics of crossbridge tension development under perturbations of myofilament length.}, + author = {Hunter, P J and McCulloch, A D and ter Keurs, H E}, + date-added = {2022-04-16 18:28:38 -0400}, + date-modified = {2022-04-16 18:28:38 -0400}, + doi = {10.1016/s0079-6107(98)00013-3}, + journal = {Prog Biophys Mol Biol}, + journal-full = {Progress in biophysics and molecular biology}, + mesh = {Actin Cytoskeleton; Animals; Biomechanical Phenomena; Calcium; Elasticity; Ferrets; Heart; In Vitro Techniques; Kinetics; Mathematics; Models, Cardiovascular; Myocardial Contraction; Myocardium; Rats; Troponin C}, + number = {2-3}, + pages = {289-331}, + pmid = {9785944}, + pst = {ppublish}, + title = {Modelling the mechanical properties of cardiac muscle}, + volume = {69}, + year = {1998}, + bdsk-url-1 = {https://doi.org/10.1016/s0079-6107(98)00013-3}} + +@article{Estrada20, + abstract = {A wide range of emerging therapies, from surgical restraint to biomaterial injection to tissue engineering, aim to improve heart function and limit adverse remodeling following myocardial infarction (MI). We previously showed that longitudinal surgical reinforcement of large anterior infarcts in dogs could significantly enhance systolic function without restricting diastolic function, but the underlying mechanisms for this improvement are poorly understood. The goal of this study was to construct a finite element model that could match our previously published data on changes in regional strains and left ventricular function following longitudinal surgical reinforcement, then use the model to explore potential mechanisms for the improvement in systolic function we observed. The model presented here, implemented in febio, matches all the key features of our experiments, including diastolic remodeling strains in the ischemic region, small shifts in the end-diastolic pressure-volume relationship (EDPVR), and large changes in the end-systolic pressure-volume relationship (ESPVR) in response to ischemia and to patch application. Detailed examination of model strains and stresses suggests that longitudinal reinforcement reduces peak diastolic fiber stretch and systolic fiber stress in the remote myocardium and shifts those peaks away from the endocardial surface by reshaping the left ventricle (LV). These findings could help to guide the development of novel therapies to improve post-MI function by providing specific design objectives.}, + author = {Estrada, Ana Cristina and Yoshida, Kyoko and Clarke, Samantha A and Holmes, Jeffrey W}, + date-added = {2022-04-16 16:45:14 -0400}, + date-modified = {2022-04-16 16:45:14 -0400}, + doi = {10.1115/1.4044030}, + journal = {J Biomech Eng}, + journal-full = {Journal of biomechanical engineering}, + mesh = {Animals; Diastole; Dogs; Myocardial Contraction; Myocardial Infarction; Ventricular Dysfunction, Left; Ventricular Function, Left}, + month = {02}, + number = {2}, + pmc = {PMC7104755}, + pmid = {31201738}, + pst = {ppublish}, + title = {Longitudinal Reinforcement of Acute Myocardial Infarcts Improves Function by Transmurally Redistributing Stretch and Stress}, + volume = {142}, + year = {2020}, + bdsk-url-1 = {https://doi.org/10.1115/1.4044030}} + @article{Aguilar08, author = {Aguilar, G and Gaspar, F and Lisbona, F and Rodrigo, C24558811158}, date-added = {2022-02-16 16:49:15 -0500}, @@ -36,30 +73,6 @@ @article{Malkin06 @book{Fung81, address = {New York}, - annote = {LDR 00902cam 2200289 i 4500 -001 4662757 -005 19860108000000.0 -008 800417s1981 nyua b 001 0 eng -035 $9(DLC) 80016532 -906 $a7$bcbc$corignew$d1$eocip$f19$gy-gencatlg -010 $a 80016532 -020 $a0387904727 -040 $aDLC$cDLC$dDLC -050 00 $aQP88$b.F87 -060 $aQT34 F981b -082 00 $a599.01/852 -100 1 $aFung, Y. C.$q(Yuan-cheng),$d1919- -245 10 $aBiomechanics :$bmechanical properties of living tissues /$cY.C. Fung. -260 $aNew York :$bSpringer-Verlag,$cc1981. -300 $axii, 433 p. :$bill. ;$c25 cm. -500 $aContinued by: Biodynamics. -504 $aIncludes bibliographies and indexes. -650 0 $aTissues. -650 0 $aBiomechanics. -650 0 $aRheology (Biology) -650 2 $aBiomechanics. -991 $bc-GenColl$hQP88$i.F87$p00008412960$tCopy 1$wBOOKS -}, author = {Fung, Y. C}, call-number = {QP88}, date-added = {2022-01-07 17:03:53 -0500}, @@ -74,31 +87,6 @@ @book{Fung81 @book{Fung72, address = {Englewood Cliffs, N.J.}, - annote = {LDR 01296cam 2200301 4500 -001 4159548 -005 19891018000000.0 -008 720204s1972 njua b 101 0 eng -035 $9(DLC) 78160253 -906 $a7$bcbc$corignew$d2$encip$f19$gy-gencatlg -010 $a 78160253 -020 $a013077149X -040 $aDLC$cDLC$dICU$dDLC -050 00 $aQP88$b.S92 1970 -082 00 $a612/.7 -111 2 $aSymposium on Biomechanics, its Foundations and Objectives$d(1970 :$cUniversity of California, San Diego) -245 10 $aBiomechanics, its foundations and objectives.$cEdited by Y. C. Fung, N. Perrone and M. Anliker. -260 $aEnglewood Cliffs, N.J.,$bPrentice-Hall$c[1972] -300 $axiii, 641 p.$billus.$c24 cm. -500 $aThe Symposium was held July 29-31, 1970. Sponsored by the University of California, San Diego and the United States Navy, Office of Naval Research. -504 $aIncludes bibliographical references. -650 0 $aBiomechanics$xCongresses. -700 1 $aFung, Y. C.$q(Yuan-cheng),$d1919-$eed. -700 1 $aPerrone, Nicholas,$d1930-$eed. -700 1 $aAnliker, M.$q(Max),$d1927-$eed. -710 2 $aUniversity of California, San Diego. -710 1 $aUnited States.$bOffice of Naval Research. -991 $bc-GenColl$hQP88$i.S92 1970$p00055296789$tCopy 1$wBOOKS -}, author = {Fung, Y. C and Perrone, Nicholas and Anliker, M}, call-number = {QP88}, date-added = {2022-01-07 16:34:55 -0500}, @@ -169,34 +157,6 @@ @article{Giannakopoulos89 @book{Wriggers06, address = {Berlin}, - annote = {LDR 01893cam 22003377a 4500 -001 14259318 -005 20080311111155.0 -008 060209s2006 gw a b 001 0 eng d -906 $a7$bcbc$ccopycat$d2$encip$f20$gy-gencatlg -925 0 $aacquire$b2 shelf copies$xpolicy default -955 $apc17 2006-02-09$ajp00 2006-08-21 jp43 2006-09-27 z-processor$ijp43 2006-09-29$ejp43 2006-09-29 to Dewey$aaa25 2006-11-15 -010 $a 2006922005 -020 $a9783540326083 (acid-free paper) -020 $a3540326081 (acid-free paper) -035 $a(CStRLIN)NYCXV5856186-B -035 $a(NIC)5856186 -040 $aTXA$cTXA$dDLC -042 $alccopycat -050 00 $aTA353$b.W75 2006 -082 00 $a620.1/05$222 -100 1 $aWriggers, P. -245 10 $aComputational contact mechanics /$cPeter Wriggers. -250 $a2nd ed. -260 $aBerlin ;$aNew York :$bSpringer,$cc2006. -300 $axii, 518 p. :$bill. ;$c24 cm. -504 $aIncludes bibliographical references (p. [487]-512) and index. -505 00 $aIntroduction to contact mechanics -- Continuum solid mechanics and weak forms -- Contact kinematics -- Constitutive equations for contact interfaces -- Contact boundary value problem and weak form -- Discretization of the continuum -- Discretization, small deformation contact --$tDiscretization, large deformation contact -- Solution algorithms -- Thermo-mechanical contact -- Beam contact -- Computation of critical points with contact constraints -- Adaptive finite element methods for contact problems. -650 0 $aContact mechanics$xMathematical models. -856 42 $3Publisher description$uhttp://www.loc.gov/catdir/enhancements/fy0663/2006922005-d.html -856 42 $3Contributor biographical information$uhttp://www.loc.gov/catdir/enhancements/fy0824/2006922005-b.html -856 41 $3Table of contents only$uhttp://www.loc.gov/catdir/enhancements/fy0824/2006922005-t.html -}, author = {Wriggers, P}, call-number = {TA353}, date-added = {2021-08-20 11:43:40 -0400}, @@ -261,28 +221,6 @@ @article{Poulios15 @book{Bertsekas82, address = {New York}, - annote = {LDR 00899pam 2200265 a 4500 -001 4679673 -005 19830126000000.0 -008 811008s1982 nyua b 001 0 eng -035 $9(DLC) 81017612 -906 $a7$bcbc$corignew$d1$eocip$f19$gy-gencatlg -010 $a 81017612 -020 $a0120934809 -040 $aDLC$cDLC$dDLC -050 00 $aQA402.5$b.B46 1982 -082 00 $a519.4$219 -100 1 $aBertsekas, Dimitri P. -245 10 $aConstrained optimization and Lagrange multiplier methods /$cDimitri P. Bertsekas. -260 $aNew York :$bAcademic Press,$c1982. -300 $axiii, 395 p. :$bill. ;$c24 cm. -440 0 $aComputer science and applied mathematics -504 $aBibliography: p. 383-392. -500 $aIncludes index. -650 0 $aMathematical optimization. -650 0 $aMultipliers (Mathematical analysis) -991 $bc-GenColl$hQA402.5$i.B46 1982$p00009887635$tCopy 1$wBOOKS -}, author = {Bertsekas, Dimitri P}, call-number = {QA402.5}, date-added = {2021-08-20 11:18:29 -0400}, @@ -307,35 +245,6 @@ @incollection{Curnier95 @book{Wriggers07, address = {Wien}, - annote = {LDR 01962cam 22003497a 4500 -001 15277998 -005 20090129082925.0 -008 080426s2007 au a b 000 0 eng d -906 $a7$bcbc$ccopycat$d2$eepcn$f20$gy-gencatlg -925 0 $aacquire$b2 shelf copies$xpolicy default -955 $ajp00 2008-05-23 z-processor to ASCD/CCPT$ijx12 2008-06-09$ejx12 2008-06-09 to BCCD -955 $apv19 2008-04-26 to ASCD$ajp00 2008-04-29 -010 $a 2008273250 -020 $a9783211772973 -020 $a3211772979 -035 $a(OCoLC)ocn192081393 -040 $aOHX$cOHX$dYDXCP$dBAKER$dGAT$dCOO$dDLC -042 $alccopycat -050 00 $aTA353$b.C64 2007 -082 04 $a620.105 -245 00 $aComputational contact mechanics /$cedited by Peter Wriggers, Tod A. Laursen. -260 $aWien ;$aNew York :$bSpringer,$cc2007. -300 $a248 p. :$bill. (some col.) ;$c25 cm. -490 1 $aCISM courses and lectures ;$vno. 498 -504 $aIncludes bibliographical references. -505 0 $aEmerging spatial and temporal discretization methods in contact and impact mechanics / T.A. Laursen -- Reliability of micromechanical contact models: a still open issue / G. Zavarise and M. Paggi -- Modern approaches on rolling contact / M. Brinkmeier, U. Nackenhorst and M. Ziefle -- Homogenization and multi-scale approaches for contact problems / P. Wriggers and J. Nettingsmeier -- Contact on multiprocessor environment: from mulitcontact problems to multiscale approaches / P. Alart -- Numerical soil mechanics experiments using discontinuous deformation analysis / J.L. P{\'e}rez Aparicio and R. B. Pareja. -650 0 $aContact mechanics$xMathematical models. -700 1 $aWriggers, P. -700 1 $aLaursen, Tod A. -830 0 $aCourses and lectures ;$vno. 498. -856 42 $3Publisher description$uhttp://www.loc.gov/catdir/enhancements/fy0904/2008273250-d.html -856 41 $3Table of contents only$uhttp://www.loc.gov/catdir/enhancements/fy0904/2008273250-t.html -}, author = {Wriggers, P and Laursen, Tod A}, call-number = {TA353}, date-added = {2021-08-20 11:15:46 -0400}, @@ -1080,28 +989,6 @@ @article{Ateshian12 @book{Bathe82, address = {Englewood Cliffs, N.J.}, - annote = {LDR 00952pam 2200265 a 4500 -001 2787910 -005 20160812093732.0 -008 810723s1982 njua b 001 0 eng -906 $a7$bcbc$corignew$d1$eocip$f19$gy-gencatlg -925 0 $aacquire$b1 shelf copy$xpolicy default -010 $a 81012067 -020 $a0133173054 -035 $9(DLC) 81012067 -040 $aDLC$cDLC$dDLC -050 00 $aTA347.F5$bB36 -082 00 $a620/.00422$219 -100 1 $aBathe, Klaus-J{\"u}rgen. -245 10 $aFinite element procedures in engineering analysis /$cKlaus-J{\"u}rgen Bathe. -260 $aEnglewood Cliffs, N.J. :$bPrentice-Hall,$cc1982. -300 $axiii, 735 p. :$bill. ;$c24 cm. -440 0 $aPrentice-Hall civil engineering and engineering mechanics series -504 $aIncludes bibliographical references and index. -650 0 $aFinite element method. -650 0 $aEngineering mathematics. -991 $bc-GenColl$hTA347.F5$iB36$p00009571851$tCopy 1$wBOOKS -}, author = {Bathe, Klaus-J{\"u}rgen}, call-number = {TA347.F5}, date-added = {2016-12-27 19:16:12 +0000}, @@ -1135,29 +1022,6 @@ @article{Azeloglu08 @book{Holzapfel00, address = {Chichester}, - annote = {LDR 01323cam 22002774a 4500 -001 11922034 -005 20030911201744.0 -008 000225s2000 enka b 001 0 eng -906 $a7$bcbc$corignew$d1$eocip$f20$gy-gencatlg -925 0 $aacquire$b1 shelf copies$xpolicy default -955 $ato ASCD pb11 02-25-00 RUSH; jp20 02-28-00 to subj; jp99 to SL 02-28-00; returned to Tech Team for completion of 050 field;jp85 to Dewey 2-29-00; aa07 03-01-00; bk rec'd, to CIP ver. ps15 05-06-00; jp00 07-28-00; CIP ver. jp25 08-07-00 to sl; jp90 to BCCD 08-08-00; jp10 ; to BCCD 10-31-00 -010 $a 00027315 -020 $a047182304X (acid-free paper) -020 $a0471823198 (acid-free paper) -040 $aDLC$cDLC$dDLC -042 $apcc -050 00 $aQA808.2$b.H655 2000 -082 00 $a531$221 -100 1 $aHolzapfel, Gerhard A. -245 10 $aNonlinear solid mechanics :$ba continuum approach for engineering /$cGerhard A. Holzapfel. -260 $aChichester ;$aNew York :$bWiley,$cc2000. -300 $axiv, 455 p. :$bill. ;$c25 cm. -504 $aIncludes bibliographical references (p. 415-433) and index. -650 0 $aContinuum mechanics. -856 42 $3Publisher description$uhttp://www.loc.gov/catdir/description/wiley035/00027315.html -856 4 $3Table of Contents$uhttp://www.loc.gov/catdir/toc/onix06/00027315.html -}, author = {Holzapfel, Gerhard A}, call-number = {QA808.2}, date-added = {2016-12-27 18:45:16 +0000}, @@ -1174,30 +1038,6 @@ @book{Holzapfel00 @book{Lai10, address = {Amsterdam}, - annote = {LDR 01115cam 2200289 a 4500 -001 15604001 -005 20091116193646.0 -008 090129s2010 ne a b 001 0 eng -906 $a7$bcbc$corignew$d1$eecip$f20$gy-gencatlg -925 0 $aacquire$b1 shelf copy$xpolicy default -955 $axh00 2009-01-29$ixh07 2009-01-29 to Dewey$ard11 2009-01-29$axe04 2009-10-23 1 copy rec'd., to CIP ver.$axh00 2009-10-29 to USPL/STM$fxh14 2009-11-16 Z-CipVer -010 $a 2009003607 -020 $a9780750685603 (hardcover) -020 $a0750685603 (hardcover) -035 $a(OCoLC)ocn300722280 -040 $aDLC$cDLC$dC#P$dBWX$dDLC -050 00 $aQA808.2$b.L3 2010 -082 00 $a531$222 -100 1 $aLai, W. Michael,$d1930- -245 10 $aIntroduction to continuum mechanics /$cW. Michael Lai, David Rubin, Erhard Krempl. -250 $a4th ed. -260 $aAmsterdam ;$aBoston :$bButterworth-Heinemann/Elsevier,$cc2010. -300 $axiv, 520 p. :$bill. ;$c25 cm. -504 $aIncludes bibliographical references and index. -650 0 $aContinuum mechanics. -700 1 $aRubin, David,$d1942- -700 1 $aKrempl, Erhard. -}, author = {Lai, W. Michael and Rubin, David and Krempl, Erhard}, call-number = {QA808.2}, date-added = {2016-12-27 18:43:23 +0000}, @@ -2286,3 +2126,12 @@ @article{BALZANI2012139 year = {2012}, bdsk-url-1 = {https://www.sciencedirect.com/science/article/pii/S0045782511003616}, bdsk-url-2 = {https://doi.org/10.1016/j.cma.2011.11.015}} + + @article{Birzle2019, + title={A coupled approach for identification of nonlinear and compressible material models for soft tissue based on different experimental setups – exemplified and detailed for Lung Parenchyma}, + volume={94}, + DOI={10.1016/j.jmbbm.2019.02.019}, + journal={Journal of the Mechanical Behavior of Biomedical Materials}, + author={Birzle, Anna M. and Martin, Christian and Uhlig, Stefan and Wall, Wolfgang A.}, + year={2019}, + pages={126–143}} diff --git a/Documentation/FEBio_Theory_Manual.lyx b/Documentation/FEBio_Theory_Manual.lyx index 3f6c95e23..f18a4f3de 100644 --- a/Documentation/FEBio_Theory_Manual.lyx +++ b/Documentation/FEBio_Theory_Manual.lyx @@ -179,11 +179,11 @@ status open \series default -Theory Manual Version 3.6 +Theory Manual Version 3.7 \end_layout \begin_layout Date -Last Updated: February 17, 2022 +Last Updated: June 14, 2022 \end_layout \begin_layout Paragraph* @@ -1383,7 +1383,7 @@ The Cartesian component forms of the operators The fourth order identity tensors are defined as: \begin_inset Formula \begin{equation} -\begin{aligned}\mathbf{A} & =\underline{\text{\mathcal{I}}}:\mathbf{A}\,,\\ +\begin{aligned}\mathbf{A} & =\underline{\mathcal{I}}:\mathbf{A}\,,\\ \mathbf{A}^{T} & =\overline{\mathcal{I}}:\mathbf{A}\,, \end{aligned} \label{eq25} @@ -1392,7 +1392,7 @@ The fourth order identity tensors are defined as: \end_inset where -\begin_inset Formula $\underline{\text{\mathcal{I}}}=\mathbf{I}\oslash\mathbf{I}$ +\begin_inset Formula $\underline{\mathcal{I}}=\mathbf{I}\oslash\mathbf{I}$ \end_inset and @@ -1429,7 +1429,7 @@ We may also define \end_inset is symmetric it follows that -\begin_inset Formula $\underline{\text{\mathcal{I}}}:\mathbf{A}=\boldsymbol{\mathcal{I}}:\mathbf{A}=\mathbf{A}$ +\begin_inset Formula $\underline{\mathcal{I}}:\mathbf{A}=\boldsymbol{\mathcal{I}}:\mathbf{A}=\mathbf{A}$ \end_inset . @@ -3459,7 +3459,7 @@ and the Cauchy stress \begin_inset Formula $\boldsymbol{\sigma}$ \end_inset - is given by Eq. + is given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:UC-Cauchy-stress" @@ -3755,7 +3755,7 @@ where \end_inset is the hydraulic permeability of the mixture. - When combined with Eq. + When combined with eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq106" @@ -5421,7 +5421,7 @@ relative deformation gradient \begin_inset Formula $\sigma$ \end_inset - by applying the chain rule to Eq. + by applying the chain rule to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-mixture-kinematics" @@ -5471,7 +5471,7 @@ postulated by constitutive assumption is a time-invariant spatial mapping. It follows that only one deformation gradient represents an independent state variable in a constrained mixture framework, whereas all others are - related to it via Eq. + related to it via eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-total-def-grad" @@ -5486,7 +5486,7 @@ noprefix "false" \end_inset 's may be selected, based on convenience. - In Eq. + In eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-total-def-grad" @@ -5499,7 +5499,7 @@ noprefix "false" the spatio-temporal arguments have been written explicitly for clarity. These dependencies are implied in the forthcoming sections and henceforth those arguments may be selectively suppressed. - Taking the determinant of Eq. + Taking the determinant of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-total-def-grad" @@ -5672,7 +5672,7 @@ This summation is carried out over all constituents. \end_inset remains constant over time. - Taking the material time derivative of Eq. + Taking the material time derivative of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-mass-balance" @@ -5682,7 +5682,7 @@ noprefix "false" \end_inset - and using Eq. + and using eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:mass-balance-alpha-1" @@ -5790,7 +5790,7 @@ In reactive frameworks where \begin_inset Formula $\rho_{r}^{\sigma}$ \end_inset - evolves according to Eq. + evolves according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:mass-balance-alpha-1" @@ -5808,7 +5808,7 @@ w^{\sigma}=\frac{\rho_{r}^{\sigma}}{\rho_{r}}\,,\label{eq:mass-fraction} \end_inset -in which case we may rewrite Eq. +in which case we may rewrite eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-free-energy" @@ -5836,7 +5836,7 @@ noprefix "false" \end_inset . - Based on Eq. + Based on eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-mass-balance" @@ -5863,7 +5863,7 @@ noprefix "false" \begin_inset Formula $\mathbf{F}^{\sigma}$ \end_inset -, we may use Eq. +, we may use eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-total-def-grad" @@ -5965,7 +5965,7 @@ tuent solids. \end_inset returns the actual contribution of that measure to the entire mixture. - Based on Eq. + Based on eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-jacobian-relation" @@ -6016,7 +6016,7 @@ These relations show that the Cauchy stress and spatial elasticity tensor \begin_inset Formula $\sigma$ \end_inset - in Eq. + in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:febio-mixture-stress" @@ -6035,7 +6035,7 @@ noprefix "false" \begin_inset Formula $\mathbf{X}^{\sigma}$ \end_inset -, as evidenced by Eq. +, as evidenced by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:febio-stress-function" @@ -6051,7 +6051,7 @@ noprefix "false" \begin_inset Formula $J^{\sigma s}$ \end_inset - as shown in Eq. + as shown in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:febio-mixture-sed" @@ -6161,7 +6161,7 @@ In the simplest type of non-reactive constrained mixtures of solids all \end_inset to the mixture. - Thus, the relation of Eq. + Thus, the relation of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:febio-mixture-stress" @@ -6315,7 +6315,7 @@ literal "false" \begin_inset Formula $\mathbf{F}^{\sigma s}\left(\mathbf{X}^{s}\right)=\mathbf{F}^{s}\left(\mathbf{X}^{s},t^{\sigma}\right)$ \end_inset - according to Eq. + according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-total-def-grad" @@ -6776,7 +6776,7 @@ where results exclusively from osmotic effects and ambient conditions (i.e., it does not depend on the loading history). - Thus, in analogy to Eq. + Thus, in analogy to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq118" @@ -6824,7 +6824,7 @@ The osmotic pressure \begin_inset Formula $\mathbf{t}=\mathbf{0}$ \end_inset -, the relation of Eq. +, the relation of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq141" @@ -6875,7 +6875,7 @@ where \begin_inset Formula $\varphi_{r}^{s}$ \end_inset - depend on the solid matrix deformation, thus Eq. + depend on the solid matrix deformation, thus eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq142" @@ -6897,7 +6897,7 @@ reference "eq142" \begin_inset Formula $-p\mathbf{I}$ \end_inset - in Eq. + in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq141" @@ -6987,7 +6987,7 @@ Consider a porous medium with an interstitial fluid that consists of a solvent \end_inset is the osmolarity of the external environment. - Using Eq. + Using eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq142" @@ -7024,7 +7024,7 @@ The reference configuration (the stress-free configuration of the solid) \end_inset in the reference state. - Therefore Eq. + Therefore eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq144" @@ -7039,7 +7039,7 @@ p=R\theta c^{\ast}\left(\frac{1-\varphi_{r}^{s}}{J-\varphi_{r}^{s}}\frac{c_{0}^{ \end_inset -and this expression may be substituted into Eq. +and this expression may be substituted into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq143" @@ -7061,7 +7061,7 @@ A perfect osmometer is a porous material whose interstitial fluid behaves \begin_inset Formula $p=0$ \end_inset - and Eq. + and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq145" @@ -7092,7 +7092,7 @@ This equation is known as the Boyle-van't Hoff relation for a perfect osmometer. \end_layout \begin_layout Standard -FEBio implements the relation of Eq. +FEBio implements the relation of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq145" @@ -7148,7 +7148,7 @@ perfect osmometer framework by simply increasing the mass of the intracellular solid matrix and membrane-impermeant solute. - This is achieved by using Eq. + This is achieved by using eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq144" @@ -7239,7 +7239,7 @@ where \end_inset . - Though this expression may be equated with Eq. + Though this expression may be equated with eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq142" @@ -7256,7 +7256,7 @@ reference "eq142" \begin_layout Standard However, since the number of charges fixed to the solid matrix is invariant, - we may manipulate Eq. + we may manipulate eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq142" @@ -7289,7 +7289,7 @@ p=R\theta\left(\sqrt{\left(\frac{1-\varphi_{r}^{s}}{J-\varphi_{r}^{s}}c_{r}^{F}\ \end_inset -This expression may be substituted into Eq. +This expression may be substituted into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq143" @@ -7365,14 +7365,14 @@ In a mixture containing a solid constituent (denoted by \end_inset -Substituting Eq. +Substituting eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq152" \end_inset - into Eq. + into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq150" @@ -7465,7 +7465,7 @@ For constituents constrained to move with the solid (denoted generically \begin_inset Formula $\forall\sigma)$ \end_inset -, the statement of mass balance in Eq. +, the statement of mass balance in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq153" @@ -7486,7 +7486,7 @@ This representation makes it easy to see that alterations in can occur only as a result of chemical reactions (such as synthesis, degradatio n, or binding). - In contrast, as seen in Eq. + In contrast, as seen in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq153" @@ -7560,7 +7560,7 @@ where is the referential solid volume fraction of solid constituents not explicitly modeled by solid-bound molecules (a user-defined parameter). - According to Eq. + According to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq154" @@ -7752,7 +7752,7 @@ The volume fraction of each constituent is given by \begin_inset Formula $\rho^{\alpha}=\varphi^{\alpha}\rho_{T}^{\alpha}$ \end_inset - into Eq. + into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq150" @@ -7783,14 +7783,14 @@ This mass balance relation for the mixture expresses the fact that the mixture \begin_inset Formula $\alpha$ \end_inset - would nullify the right-hand-side of Eq. + would nullify the right-hand-side of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq162" \end_inset - based on Eq. + based on eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq151" @@ -7832,7 +7832,7 @@ In the special case of the solvent ( \begin_inset Formula $\hat{\varphi}^{w}=\hat{\rho}^{w}/\hat{\rho}_{T}^{w}$ \end_inset -, which may be incorporated in Eq. +, which may be incorporated in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq163" @@ -8019,7 +8019,7 @@ reference "eq166" \begin_inset Formula $\hat{\rho}^{\alpha}=\left(1-\varphi^{s}\right)M^{\alpha}\nu^{\alpha}\hat{\zeta}$ \end_inset -, so that the constraint of Eq. +, so that the constraint of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq151" @@ -8038,7 +8038,7 @@ Thus, properly balancing a chemical reaction satisfies this constraint. \end_layout \begin_layout Standard -The mixture mass balance in Eq. +The mixture mass balance in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq163b" @@ -8078,21 +8078,21 @@ where \begin_inset Formula $\overline{\mathcal{V}}$ \end_inset - in Eq. + in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq170" \end_inset -; therefore, if one desires to model chemical reactions, Eq. +; therefore, if one desires to model chemical reactions, eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq165" \end_inset - or Eq. + or eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq168" @@ -8104,7 +8104,7 @@ reference "eq168" \begin_inset Formula $\hat{\varphi}^{w}=\left(1-\varphi^{s}\right)\hat{\zeta}\nu^{w}\mathcal{V}^{w}$ \end_inset -.) Similarly, the solute mass balance in Eq. +.) Similarly, the solute mass balance in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq161" @@ -8254,7 +8254,7 @@ Let \begin_inset Formula $\dot{J}=J\mathbf{F}^{-T}:\dot{\mathbf{F}}$ \end_inset - which, when combined with Eq. + which, when combined with eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:F-dot" @@ -8509,7 +8509,7 @@ where \begin_inset Formula $\mathbf{v}_{-}=\mathbf{v}_{\Gamma}$ \end_inset - for the solid, such that Eq. + for the solid, such that eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:mass-jump" @@ -8602,7 +8602,7 @@ reference "eq:elastic-pressure" \end_inset . - Thus, the mass jump in Eq. + Thus, the mass jump in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:mass-jump" @@ -8751,7 +8751,7 @@ For the specialized conditions of a viscous fluid at constant temperature \begin_inset Formula $\boldsymbol{\sigma}$ \end_inset - must have the form of Eq. + must have the form of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stress" @@ -8762,7 +8762,7 @@ reference "eq:stress" \begin_inset Formula $p$ \end_inset - is given by Eq. + is given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:elastic-pressure" @@ -8845,7 +8845,7 @@ reference "eq:elastic-pressure" \end_inset (heat leaving the system). - Now, the integral form of the energy balance in Eq. + Now, the integral form of the energy balance in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:energy-integral-redux" @@ -8861,7 +8861,7 @@ reference "eq:energy-integral-redux" \end_inset A comparison of this statement with the statement of virtual work, presented - below in Eq. + below in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:virtual work" @@ -9212,7 +9212,7 @@ where \begin_inset Formula $\mathbf{a}^{f}$ \end_inset - is given in Eq. + is given in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:fsi-fluid-acceleration-redux" @@ -9914,7 +9914,7 @@ Since the finite element implementation requires all material time derivatives \begin_inset Formula $\mathbf{v}^{f}$ \end_inset - is not a nodal degree of freedom, we use Eq. + is not a nodal degree of freedom, we use eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-fluid-flux" @@ -10116,7 +10116,7 @@ also implying that \end_inset . - Given Eq. + Given eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-Jf" @@ -10203,7 +10203,7 @@ Finally, another relation which is sufficient to satisfy the jump condition \end_inset -This jump condition Eq. +This jump condition eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-fluid-mtm-jump" @@ -10252,7 +10252,7 @@ noprefix "false" \begin_inset Formula $\varphi^{f}\to0$ \end_inset -), in which case the mixture momentum jump in Eq. +), in which case the mixture momentum jump in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-mix-mtm-jump" @@ -10282,7 +10282,7 @@ Letting \begin_inset Formula $J^{f}$ \end_inset - be nodal DOFs automatically enforces the jump conditions Eq. + be nodal DOFs automatically enforces the jump conditions eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-Jf-jump" @@ -10292,7 +10292,7 @@ noprefix "false" \end_inset - and Eq. + and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-fluid-flux-jump" @@ -10308,7 +10308,7 @@ noprefix "false" \end_inset . - Finally, subtracting Eq. + Finally, subtracting eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-fluid-mtm-jump" @@ -10318,7 +10318,7 @@ noprefix "false" \end_inset - from Eq. + from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-mix-mtm-jump" @@ -10365,7 +10365,7 @@ However, when the biphasic domain interfaces with a non-porous solid domain \begin_inset Formula $\Gamma^{bs}$ \end_inset -, the jump conditions Eq. +, the jump conditions eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-Jf-jump" @@ -10379,7 +10379,7 @@ noprefix "false" \begin_inset Formula $J^{f}$ \end_inset - and Eq. + and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-solid-mtm-jump" @@ -10394,7 +10394,7 @@ noprefix "false" \end_inset don't apply. - In that case, the jump condition Eq. + In that case, the jump condition eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:bfsi-fluid-flux-jump" @@ -10532,7 +10532,7 @@ reference "eq171" \begin_layout Standard To linearize the finite element equations, the directional derivative of - the virtual work in Eq. + the virtual work in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq171" @@ -11352,7 +11352,7 @@ where \end_inset . - In the expression of Eq. + In the expression of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq194" @@ -11378,7 +11378,7 @@ name "subsec:Biphasic-linearization" \end_layout \begin_layout Standard -Since the system of equations in Eq. +Since the system of equations in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq194" @@ -11511,7 +11511,7 @@ where \end_inset . - Based on the relation of Eq. + Based on the relation of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq104" @@ -11667,7 +11667,7 @@ Note that letting in the above equations recovers the virtual work relations for nonlinear elasticity of compressible solids. - The resulting simplified equation emerging from Eq. + The resulting simplified equation emerging from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq199" @@ -11898,7 +11898,7 @@ literal "false" \end_inset -instead of Eq. +instead of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq107" @@ -11946,7 +11946,7 @@ where \begin_inset Formula $\mathbf{w}$ \end_inset - to the virtual work expression in Eq. + to the virtual work expression in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq194" @@ -12041,7 +12041,7 @@ where \begin_inset Formula $\delta W_{int}$ \end_inset - in Eq. + in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq197" @@ -20147,7 +20147,7 @@ Now, the discretized form of \begin_inset Formula $\delta W_{int}$ \end_inset -, using Eq. +, using eq. \begin_inset space ~ \end_inset @@ -20356,7 +20356,7 @@ k_{ab}^{JJ}= & \int_{\Omega^{b}}\alpha_{f}N_{a}\frac{1}{J^{f}}\left(\left(\varph \end_inset - for external virtual work in Eq. + for external virtual work in eq. \begin_inset space ~ \end_inset @@ -20470,7 +20470,7 @@ The virtual work \begin_inset Formula $\delta F$ \end_inset - on a biphasic-FSI interface was given in Eq. + on a biphasic-FSI interface was given in eq. \begin_inset space ~ \end_inset @@ -31323,7 +31323,7 @@ generation weak bonds, which evolves over time as described below. \end_inset . - Based on Eq. + Based on eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:febio-mixture-stress" @@ -31474,7 +31474,7 @@ and \end_inset generation starts breaking and reforming. - In the recursive expression of Eq. + In the recursive expression of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq498" @@ -31566,7 +31566,7 @@ The finite element implementation of reactive viscoelasticity stores the \begin_inset Formula $w^{u}$ \end_inset - in Eq. + in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq498" @@ -31580,7 +31580,7 @@ noprefix "false" \begin_inset Formula $\mathbf{F}^{v}\left(\mathbf{X},t\right)$ \end_inset - in Eq. + in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq492" @@ -31744,7 +31744,7 @@ literal "false" \end_inset -When substituted into Eq. +When substituted into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:rrf-g-continuous-spectrum" @@ -31857,7 +31857,7 @@ In the limit as \begin_inset Formula $\beta\to1$ \end_inset -, the expression of Eq. +, the expression of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:rrf-Malkin" @@ -31867,7 +31867,7 @@ noprefix "false" \end_inset - reduces to Eq. + reduces to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:rrf-Fung-72" @@ -32052,7 +32052,7 @@ w^{\alpha}=\frac{\rho_{r}^{\alpha}}{\rho_{r}}\,.\label{eq:dmg-mass-fraction} \end_inset -Now, the mixture mass balance in Eq. +Now, the mixture mass balance in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-mass-balance" @@ -32074,7 +32074,7 @@ w^{i}+w^{b}=1\,.\label{eq:dmg-massfraction-balance} \end_inset -We may also rewrite the mixture free energy density in Eq. +We may also rewrite the mixture free energy density in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-FED" @@ -32092,7 +32092,7 @@ noprefix "false" \end_inset -where we have made use of Eq. +where we have made use of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-massfraction-balance" @@ -32147,7 +32147,7 @@ To further clarify this equivalence, we may let \end_inset represent the free energy density of an intact elastic solid, such that - Eq. + eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-FED-redux" @@ -32162,7 +32162,7 @@ noprefix "false" \end_inset . - Similarly, Eq. + Similarly, eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-stress" @@ -32203,7 +32203,7 @@ noprefix "false" \end_inset -), the strain energy density of the intact material has the form of Eq. +), the strain energy density of the intact material has the form of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:UC-SED" @@ -32245,7 +32245,7 @@ uncoupled damage \begin_inset Formula $\boldsymbol{\sigma}=\left(1-D\right)\dev\tilde{\boldsymbol{\sigma}}_{0}+p\mathbf{I}$ \end_inset -, consistent with Eq. +, consistent with eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:UC-Cauchy-stress" @@ -32263,7 +32263,7 @@ noprefix "false" \begin_inset Formula $\tilde{\Psi}_{0}\left(\tilde{\mathbf{C}}\right)$ \end_inset - as given in Eq. + as given in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:UC-Cauchy-stress-tilde" @@ -32281,7 +32281,7 @@ noprefix "false" \begin_inset Formula $U\left(J\right)$ \end_inset - as given in Eq. + as given in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:UC-p" @@ -32526,7 +32526,7 @@ where \end_inset -Substituting these expressions into Eq. +Substituting these expressions into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-mass-balance-alpha" @@ -32619,7 +32619,7 @@ Since \end_inset is always positive when the damage is increasing, and zero otherwise as - per Eq. + per eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-Xsi-dot" @@ -32638,7 +32638,7 @@ noprefix "false" \begin_inset Formula $r=-\dot{F}\left(\Xi_{m}\right)\psi\left(\mathbf{F}\right)$ \end_inset - in Eq. + in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-heat-supply" @@ -32694,7 +32694,7 @@ This damage measure is valid for isotropic or anisotropic materials, since \begin_inset Formula $\Psi_{r}$ \end_inset - must satisfy the frame-invariance of Eq. + must satisfy the frame-invariance of eq. \begin_inset CommandInset ref LatexCommand pageref reference "eq:dmg-criterion-invariance" @@ -32746,7 +32746,7 @@ This damage measure is valid for isotropic or anisotropic materials, since \begin_inset Formula $\Psi_{r}$ \end_inset - must satisfy the frame-invariance of Eq. + must satisfy the frame-invariance of eq. \begin_inset CommandInset ref LatexCommand pageref reference "eq:dmg-criterion-invariance" @@ -32765,7 +32765,7 @@ noprefix "false" \end_inset -where we have used the result of Eq. +where we have used the result of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-model-SED-N" @@ -32814,7 +32814,7 @@ This damage measure is valid for isotropic or anisotropic materials, since \begin_inset Formula $\Psi_{r}$ \end_inset - must satisfy the frame-invariance of Eq. + must satisfy the frame-invariance of eq. \begin_inset CommandInset ref LatexCommand pageref reference "eq:dmg-criterion-invariance" @@ -32833,7 +32833,7 @@ noprefix "false" \end_inset -where we have used the result of Eq. +where we have used the result of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-model-SED-N" @@ -32883,7 +32883,7 @@ where \end_inset -From the hyperelasticity relation in Eq. +From the hyperelasticity relation in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-stress" @@ -32927,7 +32927,7 @@ where \end_inset -From the von Mises criterion in Eq. +From the von Mises criterion in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-model-VMS" @@ -32965,7 +32965,7 @@ noprefix "false" \end_inset - into Eq. + into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dmg-N-redux" @@ -33240,7 +33240,7 @@ The Lagrange strain tensor \begin_inset Formula $\mathbf{F}$ \end_inset - via Eq. + via eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Lagrange-strain-tensor" @@ -33308,7 +33308,7 @@ and \begin_inset Formula $\mathbf{E}$ \end_inset - is given in Eq. + is given in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Lagrange-strain-tensor" @@ -33492,7 +33492,7 @@ yield measure \end_inset . - Thus, according to Eq. + Thus, according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-total-def-grad" @@ -33638,7 +33638,7 @@ is the unit tensor along \end_inset is a non-dimensional scalar which may be determined analytically by enforcing - the plastic consistency condition in Eq. + the plastic consistency condition in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:plastic-consistency-condition" @@ -33671,7 +33671,7 @@ generation is in the elastic regime; therefore, \begin_inset Formula $\mathbf{F}^{us}=\mathbf{I}$ \end_inset - at the start of the recursive relation in Eq. + at the start of the recursive relation in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:plasticity-Fvsi-normality" @@ -33685,7 +33685,7 @@ noprefix "false" \end_layout \begin_layout Standard -The stress response of this solid mixture is given generically by Eq. +The stress response of this solid mixture is given generically by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-mixture-stress-redux" @@ -33752,7 +33752,7 @@ where \begin_inset Formula $\sigma=u,v$ \end_inset -) and Eq. +) and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:plasticity-Fvsi-normality" @@ -33766,7 +33766,7 @@ noprefix "false" \begin_inset Formula $\boldsymbol{\sigma}_{0}$ \end_inset - is given in Eq. + is given in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:febio-stress-function" @@ -34031,7 +34031,7 @@ bond families \begin_inset Formula $\mathbf{F}_{\beta}^{\sigma s}$ \end_inset - in the updated form of Eq. + in the updated form of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-total-def-grad" @@ -34041,7 +34041,7 @@ noprefix "false" \end_inset -, such as that given in Eq. +, such as that given in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:plasticity-Fvsi-normality" @@ -34088,7 +34088,7 @@ The referential mass density of bond family \begin_inset Formula $\sum_{\sigma}\rho_{r\beta}^{\sigma}=\rho_{r\beta}$ \end_inset -, as per Eq. +, as per eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:general-mass-balance" @@ -34193,7 +34193,7 @@ where the summation runs over all possible yielded generations \begin_inset Formula $t=u$ \end_inset -, Eq. +, eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:hardening-yielded-mass-fraction" @@ -34234,7 +34234,7 @@ noprefix "false" \end_inset -Then the mixture stress in Eq. +Then the mixture stress in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:multiplebonds-mixture-stress" @@ -34777,7 +34777,7 @@ The relationships between \begin_inset Formula $\Phi_{m\beta}$ \end_inset - embodied in Eq. + embodied in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:hardening-phi-model-no-r" @@ -35551,7 +35551,7 @@ noprefix "false" \begin_inset Formula $w_{\beta}^{s}=1-w_{\beta}^{b}$ \end_inset - all yield, following the reaction in Eq. + all yield, following the reaction in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:hardening-yielded-rxn" @@ -35720,7 +35720,7 @@ w_{\beta}^{b} & =F^{e}\left(\Xi_{m\beta}^{e}\right) \end_inset -and hence the mass balance of Eq. +and hence the mass balance of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:multiplebonds-bond-species-mass-fractions" @@ -35898,7 +35898,7 @@ Strain Energy Density, Stress, and Damage \begin_layout Standard Recognizing that damaged (broken) bonds do not store free energy, the referentia -l mixture free energy density in Eq. +l mixture free energy density in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:multiplebonds-mixture-energy" @@ -35949,7 +35949,7 @@ noprefix "false" \end_inset . - Similarly, the mixture stress may be evaluated from Eq. + Similarly, the mixture stress may be evaluated from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:multiplebonds-mixture-stress" @@ -35971,7 +35971,7 @@ where the stresses \begin_inset Formula $\boldsymbol{\sigma}_{0}$ \end_inset - are given by the standard hyperelasticity relation in Eq. + are given by the standard hyperelasticity relation in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:multiplebonds-mixture-stress" @@ -37196,10 +37196,10 @@ literal "true" was added to the transversely isotropic materials. When active contraction is activated, the total Cauchy stress -\begin_inset Formula $\mathbf{\sigma}$ +\begin_inset Formula $\boldsymbol{\sigma}$ \end_inset -is defined as the sum of the active stress tensor + is defined as the sum of the active stress tensor \begin_inset Formula $\boldsymbol{\sigma}^{a}=T^{a}\mathbf{a}\otimes\mathbf{a}$ \end_inset @@ -42299,7 +42299,7 @@ where \end_inset -Eq. +eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact_int" @@ -42414,7 +42414,7 @@ Furthermore, the elemental area on \end_inset -Therefore the contact integral of Eq. +Therefore the contact integral of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact_int" @@ -42584,7 +42584,7 @@ literal "true" \end_layout \begin_layout Standard -The projection approach of Eq. +The projection approach of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_x2" @@ -42633,7 +42633,7 @@ literal "true" \end_inset ). - The benefits associated with a projection method such as Eq. + The benefits associated with a projection method such as eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_x2" @@ -42906,7 +42906,7 @@ on, by definition \begin_layout Standard We now use these relations to produce a more practical formulation of the slip velocity for our frictional contact implementation. - Taking the material time derivative of Eq. + Taking the material time derivative of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_x2" @@ -42981,7 +42981,7 @@ where \begin_inset Formula $\gamma^{\left(1\right)}$ \end_inset -, evaluated from Eq. +, evaluated from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:n" @@ -43032,7 +43032,7 @@ Previous authors have utilized \begin_inset Formula $\mathbf{v}^{r}=\dot{\eta}_{(2)}^{\alpha}\mathbf{g}_{\alpha}^{(2)}$ \end_inset - directly instead of the right-hand-side of Eq. + directly instead of the right-hand-side of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:vr" @@ -43058,7 +43058,7 @@ literal "true" \end_inset . - The relative velocity measure on the right-hand-side of Eq. + The relative velocity measure on the right-hand-side of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:vr" @@ -43259,7 +43259,7 @@ where \begin_inset Formula $\varepsilon$ \end_inset - is the penalty parameter and we have employed Eq. + is the penalty parameter and we have employed eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick_gap" @@ -43272,7 +43272,7 @@ reference "eq:stick_gap" \begin_layout Standard During slip, we first calculate the normal component of the contact traction - by penalizing the normal gap of Eq. + by penalizing the normal gap of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_gap" @@ -43432,7 +43432,7 @@ where \begin_inset Formula $t_{n}$ \end_inset - is given by Eq. + is given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL_tn" @@ -43499,7 +43499,7 @@ The Lagrange multipliers \end_inset ), and the other is considered passive and is derived from the active multiplier. - The contact status is determined via Eq. + The contact status is determined via eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-criterion" @@ -43697,14 +43697,14 @@ Determination of whether stick or slip is active is accomplished by a trial \begin_inset Formula $\tilde{\mathbf{t}}^{(1)}$ \end_inset - assuming stick, utilizing either Eq. + assuming stick, utilizing either eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick_traction" \end_inset - or Eq. + or eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL_stick_traction" @@ -43752,14 +43752,14 @@ where \begin_inset Formula $t_{n}$ \end_inset - is given by either Eq. + is given by either eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_tn" \end_inset - or Eq. + or eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL_tn" @@ -43806,7 +43806,7 @@ Computationally, care must be taken to ensure that augmentation does not \begin_inset Formula $\boldsymbol{\lambda}_{s}=\varepsilon\mathbf{g}_{s}$ \end_inset - according to Eq. + according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL-stick" @@ -43822,7 +43822,7 @@ reference "eq:AL-stick" \begin_inset Formula $\mathbf{t}^{(1)}=\boldsymbol{\lambda}_{s}+\varepsilon\mathbf{g}_{s}=2\varepsilon\mathbf{g}_{s}$ \end_inset - according to Eq. + according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL_stick_traction" @@ -43855,7 +43855,7 @@ name "subsec:SE-Linearization" \end_layout \begin_layout Standard -To evaluate the linearization in Eq. +To evaluate the linearization in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dgc" @@ -44033,7 +44033,7 @@ noprefix "false" \end_inset -, along with the relations of Eq. +, along with the relations of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick_xv_linearizations" @@ -44052,7 +44052,7 @@ D\mathbf{t}^{(1)}=\varepsilon\left(\Delta\mathbf{u}^{(2)}-\Delta\mathbf{u}^{(1)} \end_inset The linearization operator may be brought inside the contact integral of - Eq. + eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-invariant" @@ -44082,7 +44082,7 @@ where we recall that \begin_inset Formula $D\delta\mathbf{v}^{(1)}=D\delta\mathbf{v}^{(2)}=\mathbf{0}$ \end_inset - from Eq. + from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick_xv_linearizations" @@ -44128,7 +44128,7 @@ As in stick, the contact integral over \begin_inset Formula $\mathbf{n}^{(1)}$ \end_inset -, in accordance with Eq. +, in accordance with eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_x2" @@ -44256,7 +44256,7 @@ In this expression, \begin_inset Formula $a^{\alpha\beta}\to\mathbf{g}_{(2)}^{\alpha}\cdot\mathbf{g}_{(1)}^{\beta}$ \end_inset - (see the discussion following Eq.(40) in + (see the discussion following eq.(40) in \begin_inset CommandInset citation LatexCommand citep key "Ateshian10" @@ -44271,7 +44271,7 @@ literal "true" \end_layout \begin_layout Standard -From Eq. +From eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_traction" @@ -44289,7 +44289,7 @@ D\mathbf{t}^{(1)}=Dt_{n}\left(\mathbf{n}+\mu\mathbf{s}^{(1)}\right)+t_{n}\left(D \end_inset -By Eq. +By eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_tn" @@ -44312,7 +44312,7 @@ noprefix "false" \end_inset -Applying the linearization operator to Eq. +Applying the linearization operator to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:s1" @@ -44334,7 +44334,7 @@ where \begin_inset Formula $D\mathbf{v}^{r}=Dg\,\dot{\mathbf{n}}^{(1)}+g\,D\dot{\mathbf{n}}^{(1)}+D\left(\partial\mathbf{x}^{\left(1\right)}/\partial t\right)-D\left(\partial\mathbf{x}^{\left(2\right)}/\partial t\right)$ \end_inset - according to Eq. + according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:vr" @@ -44506,7 +44506,7 @@ Stick \end_layout \begin_layout Standard -Applying the discretization to Eq. +Applying the discretization to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-invariant" @@ -44538,7 +44538,7 @@ and \begin_inset Formula $\mathbf{t}^{(1)}$ \end_inset - is defined by Eq. + is defined by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick_traction" @@ -44548,7 +44548,7 @@ noprefix "false" \end_inset - in the penalty case and Eq. + in the penalty case and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL_stick_traction" @@ -44560,7 +44560,7 @@ noprefix "false" when augmented Lagrangian regularization is used. Individual terms may now be discretized and placed into matrix notation, - facilitating their substitution into Eq. + facilitating their substitution into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-linearized-2" @@ -44568,14 +44568,14 @@ reference "eq:stick-linearized-2" \end_inset . - A straightforward application of Eq. + A straightforward application of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:u-v-discretization" \end_inset - to Eq. + to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dgcov_Djeta" @@ -44629,7 +44629,7 @@ and \end_inset . - Furthermore, discretizing Eq. + Furthermore, discretizing eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dt_stick" @@ -44646,28 +44646,28 @@ D\mathbf{t}^{(1)}=\begin{bmatrix}\sum_{c}-\varepsilon N_{c}^{(1)}\mathbf{I} & \s \end_inset -Substituting Eq. +Substituting eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Djeta-discretized" \end_inset - and Eq. + and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dt-stick-discretized" \end_inset - into Eq. + into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-linearized-2" \end_inset - and applying the discretization of Eq. + and applying the discretization of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:u-v-discretization" @@ -44693,7 +44693,7 @@ reference "eq:u-v-discretization" \end_inset - An examination of Eq. + An examination of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-stiffness" @@ -44706,7 +44706,7 @@ reference "eq:stick-stiffness" \end_layout \begin_layout Standard -Although the stiffness matrix of Eq. +Although the stiffness matrix of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-stiffness" @@ -44757,7 +44757,7 @@ Slip \end_layout \begin_layout Standard -In the case of slip, the contact integral of Eq. +In the case of slip, the contact integral of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-invariant" @@ -44808,7 +44808,7 @@ and \begin_inset Formula $t_{n}$ \end_inset - is given by Eq. + is given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_tn" @@ -44818,7 +44818,7 @@ noprefix "false" \end_inset - in the penalty formulation and Eq. + in the penalty formulation and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL_tn" @@ -44835,7 +44835,7 @@ noprefix "false" For the following linearization and discretization the normal and tangential components, representing frictionless and frictional contributions to the contact integral, will be treated separately and may then be added together - as in Eq. + as in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-contact-int-split" @@ -44861,7 +44861,7 @@ The linearization of the frictionless contribution \begin_inset Formula $\delta G_{c}^{n}$ \end_inset - makes use of Eq. + makes use of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip_xv_linearizations" @@ -44888,7 +44888,7 @@ reference "eq:slip_xv_linearizations" \end_inset -Evaluating Eq. +Evaluating eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:frictionless-int-linearization" @@ -44974,14 +44974,14 @@ with the definitions \end_inset -Applying the discretization in Eq. +Applying the discretization in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:u-v-discretization" \end_inset - to Eq. + to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:frictionless-int-linearization" @@ -45045,7 +45045,7 @@ G_{bc} & =ga^{\alpha\beta}\frac{\partial N_{b}}{\partial\eta_{(2)}^{\alpha}}\fra and it is apparent that the resulting frictionless stiffness matrix is also nonsymmetric. - Eq. + eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:frictionless-stiffness" @@ -45084,7 +45084,7 @@ name "subsec:SE-Frictional-Terms" \begin_layout Standard The linearization of the frictional contribution follows from the second - term of Eq. + term of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-contact-int-split" @@ -45115,7 +45115,7 @@ The remaining quantity to be determined in this expression is the linearization \begin_inset Formula $D\mathbf{s}^{(1)}$ \end_inset -; according to Eq. +; according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Ds" @@ -45135,7 +45135,7 @@ reference "eq:Ds" \begin_inset Formula $\dot{\mathbf{g}}_{\alpha}^{(1)}$ \end_inset - via Eq. + via eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:n_dot" @@ -45151,7 +45151,7 @@ noprefix "false" \end_layout \begin_layout Standard -In a similar fashion to Eq. +In a similar fashion to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Euler-integration" @@ -45180,7 +45180,7 @@ where \end_inset from the previous time step. - A temporally discretized form of Eq. + A temporally discretized form of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:n_dot" @@ -45238,7 +45238,7 @@ and \begin_inset Formula $\bar{\mathbf{A}}_{c}^{(1)}$ \end_inset - is defined by analogy with Eq. + is defined by analogy with eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Ac" @@ -45279,7 +45279,7 @@ reference "eq:ndot-euler" \end_inset - in Eq. + in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:vr" @@ -45297,7 +45297,7 @@ noprefix "false" \end_inset -and thus Eq. +and thus eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Ds" @@ -45327,7 +45327,7 @@ where \end_inset -In Eq. +In eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:delta-h" @@ -45420,7 +45420,7 @@ where \end_inset The stiffness matrix of the frictional contribution to the virtual work, - Eq. + eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:frictional-stiffness" @@ -45428,14 +45428,14 @@ reference "eq:frictional-stiffness" \end_inset , is nonsymmetric. - Summing Eq. + Summing eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:frictionless-stiffness" \end_inset - and Eq. + and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:frictional-stiffness" @@ -45460,14 +45460,14 @@ name "subsec:SE-Integration-Scheme" \begin_layout Standard In this formulation, a Gaussian quadrature integration scheme is adopted. The general form of the contact integral (e.g. - Eq. + eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-discretized" \end_inset - or Eq. + or eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-discretized-2" @@ -45598,7 +45598,7 @@ noprefix "false" \begin_inset Formula $\gamma^{(2)}$ \end_inset - as defined by either Eq. + as defined by either eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick_x2" @@ -45643,7 +45643,7 @@ where the matrix of tensors \end_inset is a general representation of the stiffness terms given explicitly in - either Eq. + either eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-stiffness" @@ -45901,7 +45901,7 @@ where \end_inset . - Casting Eq. + Casting eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int" @@ -45969,7 +45969,7 @@ name "subsec:Biphasic-Frictional-Formulation" \end_layout \begin_layout Standard -An examination of Eq. +An examination of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-invariant-1" @@ -46038,7 +46038,7 @@ Here, \begin_inset Formula $\mu_{\text{eff}}$ \end_inset - is given by Eq. + is given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:mueff-biphasic" @@ -46423,7 +46423,7 @@ literal "false" \end_inset . - Taking the material time derivative of Eq. + Taking the material time derivative of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-x2" @@ -46489,7 +46489,7 @@ where \begin_inset Formula $\dot{\mathbf{n}}^{(1)}$ \end_inset - is evaluated from Eq. + is evaluated from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:n-1" @@ -46512,7 +46512,7 @@ Here, \begin_inset Formula $\mathbf{g}_{\alpha}^{(1)}$ \end_inset - in the material frame, evaluated from Eq. + in the material frame, evaluated from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:basis-vectors" @@ -46586,7 +46586,7 @@ where \begin_inset Formula $\varepsilon$ \end_inset - is the contact penalty parameter and we have utilized Eq. + is the contact penalty parameter and we have utilized eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-gap" @@ -46609,7 +46609,7 @@ During slip, the normal component of the contact traction is first calculated \begin_inset Formula $g$ \end_inset - of the gap, given by Eq. + of the gap, given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-gap" @@ -46639,7 +46639,7 @@ where \begin_inset Formula $\mathbf{s}^{(1)}$ \end_inset - is the unit vector in the slip direction, given by Eq. + is the unit vector in the slip direction, given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:s-def" @@ -46650,7 +46650,7 @@ noprefix "false" \end_inset . - We note that Eq. + We note that eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-traction" @@ -46850,14 +46850,14 @@ noprefix "false" \begin_inset Formula $w_{n}$ \end_inset - from Eq. + from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:wn" \end_inset - using the contact kinematics determined by Eq. + using the contact kinematics determined by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-criterion-1" @@ -46980,7 +46980,7 @@ where \end_inset -where Eq. +where eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL-tn" @@ -47012,7 +47012,7 @@ literal "false" . Here it suffices to note that by augmenting only the normal gap and employing - Eq. + eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:augmented-t" @@ -47099,7 +47099,7 @@ literal "false" \end_inset is not dependent on the stick-slip status. - However, as noted before, Eq. + However, as noted before, eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL-wn" @@ -47137,14 +47137,14 @@ literal "false" \begin_inset Formula $\tilde{\mathbf{t}}^{(1)}$ \end_inset -, utilizing either Eq. +, utilizing either eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-traction" \end_inset - or Eq. + or eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL-stick-traction" @@ -47192,14 +47192,14 @@ where \begin_inset Formula $t_{n}$ \end_inset - is given by either Eq. + is given by either eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-tn" \end_inset - or Eq. + or eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL-tn" @@ -47438,7 +47438,7 @@ name "sec:SB-Definitions-Notation" \end_layout \begin_layout Standard -Evaluating the linearizations of Eq. +Evaluating the linearizations of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-invariant-1" @@ -47806,7 +47806,7 @@ D\delta p^{(1)} & =0 & D\delta p^{(2)} & =0 \end_inset -From the definitions of Eq. +From the definitions of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-gap" @@ -47816,7 +47816,7 @@ noprefix "false" \end_inset - and Eq. + and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-traction" @@ -47826,7 +47826,7 @@ noprefix "false" \end_inset -, and utilizing Eq. +, and utilizing eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-stick-linearization" @@ -47841,7 +47841,7 @@ D\mathbf{t}^{(1)}=\varepsilon\left(\Delta\mathbf{u}^{(2)}-\Delta\mathbf{u}^{(1)} \end_inset -Similarly, application of Eq. +Similarly, application of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-stick-linearization" @@ -47876,7 +47876,7 @@ Dw_{n}=\varepsilon_{p}\left(\Delta p^{(1)}-\Delta p^{(2)}\right)\label{eq:biph-s \end_inset -The biphasic contact integral of Eq. +The biphasic contact integral of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int" @@ -47905,7 +47905,7 @@ noprefix "false" \end_inset -Note that for convenience, terms in Eq. +Note that for convenience, terms in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biph-cont-int-linearized" @@ -47915,7 +47915,7 @@ noprefix "false" \end_inset - have been grouped differently than in Eq. + have been grouped differently than in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:D-contact-int" @@ -48025,14 +48025,14 @@ where \end_layout \begin_layout Standard -Inserting the discretization of Eq. +Inserting the discretization of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-stick-var-discretization" \end_inset - into Eq. + into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-invariant-1" @@ -48071,7 +48071,7 @@ and \begin_inset Formula $\mathbf{t}^{(1)}$ \end_inset - is obtained from Eq. + is obtained from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-traction" @@ -48081,7 +48081,7 @@ noprefix "false" \end_inset - in the penalty case and from Eq. + in the penalty case and from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL-stick-traction" @@ -48096,7 +48096,7 @@ noprefix "false" \begin_inset Formula $w_{n}$ \end_inset - is calculated from either Eq. + is calculated from either eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:wn" @@ -48106,7 +48106,7 @@ noprefix "false" \end_inset - or Eq. + or eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL-wn" @@ -48122,7 +48122,7 @@ noprefix "false" \begin_layout Standard We may now discretize individual terms and place them into matrix notation, - anticipating their substitution into Eq. + anticipating their substitution into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biph-cont-int-linearized" @@ -48130,7 +48130,7 @@ reference "eq:biph-cont-int-linearized" \end_inset . - By placing Eq. + By placing eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biph-stick-int-disc" @@ -48151,7 +48151,7 @@ reference "eq:biph-stick-Dwn" \end_inset - and inserting the resulting linearizations into Eq. + and inserting the resulting linearizations into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biph-cont-int-linearized" @@ -48211,7 +48211,7 @@ and \end_inset -In Eq. +In eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-stick-stiffness" @@ -48336,7 +48336,7 @@ th element face of \begin_inset Formula $X^{(2)}$ \end_inset - obtained from Eq. + obtained from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:stick-x2" @@ -48367,7 +48367,7 @@ noprefix "false" on sliding-elastic frictional contact, we split the contact stiffness matrices in a different way, which allowed us to clearly separate like terms. Here, due to the complexity of the biphasic contact formulation, it was - determined that the form of Eq. + determined that the form of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-stick-stiffness" @@ -48429,7 +48429,7 @@ During slip, the contact integral over \begin_inset Formula $\mathbf{n}^{(1)}$ \end_inset -, in accordance with Eq. +, in accordance with eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-gap" @@ -48517,7 +48517,7 @@ literal "false" \end_inset . - From Eq. + From eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:mueff-biphasic" @@ -48539,7 +48539,7 @@ where \begin_inset Formula $Dt_{n}=\varepsilon Dg$ \end_inset - according to Eq. + according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-tn" @@ -48549,7 +48549,7 @@ noprefix "false" \end_inset -; this term has been provided previously in Eq. +; this term has been provided previously in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dg_slip" @@ -48599,7 +48599,7 @@ D\mathbf{t}^{(1)}=Dt_{n}\left(\no+\mueff\so\right)+t_{n}\left(D\no+\left(D\mueff \end_inset -Finally, from Eq. +Finally, from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:wn" @@ -48613,7 +48613,7 @@ noprefix "false" \begin_inset Formula $\mathbf{x}^{\left(2\right)}$ \end_inset - determined by Eq. + determined by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-x2" @@ -48623,7 +48623,7 @@ noprefix "false" \end_inset -) and Eq. +) and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-slip-linearization" @@ -48642,7 +48642,7 @@ Note that the form of \begin_inset Formula $Dw_{n}$ \end_inset - given in Eq. + given in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dwn" @@ -48652,7 +48652,7 @@ noprefix "false" \end_inset - contains additional terms not present in Eq. + contains additional terms not present in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biph-stick-Dwn" @@ -48674,7 +48674,7 @@ noprefix "false" \end_inset is determined by the stick-slip status. - Per the discussion following Eq. + Per the discussion following eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:pi-biphasic-penalty" @@ -48707,7 +48707,7 @@ ed over each element face according to \end_inset -In the case of slip, the contact integral of Eq. +In the case of slip, the contact integral of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:contact-int-invariant-1" @@ -48811,7 +48811,7 @@ noprefix "false" \begin_inset Formula $w_{n}$ \end_inset - is given by Eq. + is given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:wn" @@ -48821,7 +48821,7 @@ noprefix "false" \end_inset - or Eq. + or eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:AL-wn" @@ -48835,7 +48835,7 @@ noprefix "false" For the following linearization and discretization the normal and tangential components, representing frictionless and frictional contributions to the contact integral, will be treated separately and may then be added together - as in Eq. + as in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-slip-discretized" @@ -48851,14 +48851,14 @@ Frictionless Terms \end_layout \begin_layout Standard -The linearization of the frictional part of Eq. +The linearization of the frictional part of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-slip-discretized" \end_inset - makes use of Eq. + makes use of eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-slip-linearization" @@ -48899,7 +48899,7 @@ w_{n} where we note that the virtual variables on the secondary surface now enter the linearization, as parametric coordinates on the secondary surface vary - during slip according to Eq. + during slip according to eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:slip-gap" @@ -48914,14 +48914,14 @@ noprefix "false" \begin_inset Formula $Dw_{n}$ \end_inset -, and it follows from placing Eq. +, and it follows from placing eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-slip-var-discretization" \end_inset - into Eq. + into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dwn" @@ -48978,7 +48978,7 @@ Directional derivatives of virtual variables on the secondary surface will \end_inset -In Eq. +In eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dNb-deta" @@ -48992,7 +48992,7 @@ noprefix "false" In an effort to keep the expression more compact, we have not included these variables. However, this expression could easily be cast into the form of e.g. - Eq. + eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:dp-deta" @@ -49003,7 +49003,7 @@ noprefix "false" \end_inset by adding zeros where necessary. - Discretizing Eq. + Discretizing eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dgc-biph-fricless-slip" @@ -49133,7 +49133,7 @@ Frictional Terms \begin_layout Standard Linearizing the frictional contribution follows from the second term of - Eq. + eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-slip-discretized" @@ -49177,14 +49177,14 @@ The remaining quantity in this expression to be determined is the discretization \begin_inset Formula $D\mueff$ \end_inset -; from Eq. +; from eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dmueff" \end_inset - and Eq. + and eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-slip-var-discretization" @@ -49214,7 +49214,7 @@ where we made the definition \end_inset -just to be used in Eq. +just to be used in eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dmueff-discrete" @@ -49239,7 +49239,7 @@ reference "eq:Dmueff-discrete" \end_inset - into Eq. + into eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:Dgc-biph-fric-slip" @@ -49304,7 +49304,7 @@ and \end_inset -In Eq. +In eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-fric-slip-solid-stiffness" @@ -49347,7 +49347,7 @@ noprefix "false" . The stiffness matrix of the frictional contribution to the virtual work, - given by Eq. + given by eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-fric-slip-stiffness" @@ -49399,7 +49399,7 @@ noprefix "false" \end_inset contains the solid-solid stiffness terms. - Comparing Eq. + Comparing eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:biphasic-fric-slip-solid-stiffness" @@ -49409,7 +49409,7 @@ noprefix "false" \end_inset - with Eq. + with eq. \begin_inset CommandInset ref LatexCommand eqref reference "eq:frictional-stiffness" @@ -55494,6 +55494,2663 @@ tau parameter. \end_layout +\begin_layout Chapter +\start_of_appendix +Tensor Calculus +\end_layout + +\begin_layout Section +Second-Order Tensors +\end_layout + +\begin_layout Subsection +Definition +\end_layout + +\begin_layout Standard +Let +\begin_inset Formula $\mathbf{T}$ +\end_inset + + be a transformation, which transforms any vector into another vector, e.g., + +\begin_inset Formula +\[ +\mathbf{T}\cdot\mathbf{a}=\mathbf{b}\quad\mathbf{T}\cdot\mathbf{c}=\mathbf{d} +\] + +\end_inset + + If +\begin_inset Formula $\mathbf{T}$ +\end_inset + + has the following properties, +\begin_inset Formula +\begin{equation} +\mathbf{T}\cdot\left(\mathbf{a}+\mathbf{c}\right)=\mathbf{T}\cdot\mathbf{a}+\mathbf{T}\cdot\mathbf{c}\label{eq6-1} +\end{equation} + +\end_inset + + +\begin_inset Formula +\begin{equation} +\mathbf{T}\cdot\left(\alpha\mathbf{a}\right)=\alpha\mathbf{T}\cdot\mathbf{a}\label{eq7-1} +\end{equation} + +\end_inset + + where +\begin_inset Formula $\mathbf{a}$ +\end_inset + + and +\begin_inset Formula $\mathbf{c}$ +\end_inset + + are arbitrary vectors, and +\begin_inset Formula $\alpha$ +\end_inset + + is an arbitrary scalar, then +\begin_inset Formula $\mathbf{T}$ +\end_inset + + is called a +\shape italic +linear transformation +\shape default +, a +\shape italic +second-order tensor +\shape default +, or simply a +\shape italic +tensor +\shape default +. + Vectors are first-order tensors and scalars are zeroth-order tensors. + +\end_layout + +\begin_layout Subsection +Cartesian Components of a Tensor +\end_layout + +\begin_layout Standard +Let +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + form an orthonormal basis in a Cartesian coordinate system +\begin_inset Formula $x_{1},x_{2},x_{3}$ +\end_inset + +. + Then the Cartesian components of +\begin_inset Formula $\mathbf{a}$ +\end_inset + + are +\begin_inset Formula +\[ +a_{1}=\mathbf{e}_{1}\cdot\mathbf{a},\quad a_{2}=\mathbf{e}_{2}\cdot\mathbf{a},\quad a_{3}=\mathbf{e}_{3}\cdot\mathbf{a} +\] + +\end_inset + + or equivalently, +\begin_inset Formula +\begin{equation} +\boxed{a_{j}=\mathbf{e}_{j}\cdot\mathbf{a}}\label{eq7b} +\end{equation} + +\end_inset + + (Recall that +\begin_inset Formula $\mathbf{a}=a_{i}\mathbf{e}_{i}$ +\end_inset + +, thus +\begin_inset Formula $\mathbf{a}\cdot\mathbf{e}_{j}=a_{i}\mathbf{e}_{i}\cdot\mathbf{e}_{j}=a_{i}\delta_{ij}=a_{j}$ +\end_inset + +.) +\end_layout + +\begin_layout Standard +The Cartesian components of a tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + + are obtained as follows. + Let +\begin_inset Formula $\mathbf{T}\cdot\mathbf{a}=\mathbf{b}$ +\end_inset + +. + The components of +\begin_inset Formula $\mathbf{b}$ +\end_inset + + are given by +\begin_inset Formula $b_{i}=\mathbf{e}_{i}\cdot\mathbf{b}=\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{a}$ +\end_inset + +. + But +\begin_inset Formula $\mathbf{a}=a_{j}\mathbf{e}_{j}$ +\end_inset + +, so +\begin_inset Formula $b_{i}=a_{j}\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{j}$ +\end_inset + +. + Note that +\begin_inset Formula $\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{j}$ +\end_inset + + is the component along +\begin_inset Formula $\mathbf{e}_{i}$ +\end_inset + + of the vector +\begin_inset Formula $\mathbf{T}\cdot\mathbf{e}_{j}$ +\end_inset + +. + By convention, we denote this component as +\end_layout + +\begin_layout Standard +\begin_inset Formula +\begin{equation} +\boxed{T_{ij}=\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{j}}\quad\text{components of tensor }\mathbf{T}\label{eq7c} +\end{equation} + +\end_inset + + components of tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + +. +\end_layout + +\begin_layout Standard +Thus, +\begin_inset Formula $\mathbf{b}=\mathbf{T}\cdot\mathbf{a}=a_{j}\mathbf{T}\cdot\mathbf{e}_{j}=b_{k}\mathbf{e}_{k}$ +\end_inset + +. + Taking the dot product on both sides with +\begin_inset Formula $\mathbf{e}_{i}$ +\end_inset + + yields +\begin_inset Formula $a_{j}\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{j}=a_{j}T_{ij}=b_{k}\mathbf{e}_{i}\cdot\mathbf{e}_{k}=b_{k}\delta_{ik}=b_{i}$ +\end_inset + +, or +\begin_inset Formula +\[ +\boxed{b_{i}=T_{ij}a_{j}} +\] + +\end_inset + + in indicial form. + In matrix form, +\begin_inset Formula +\[ +\left[\begin{array}{c} +b_{1}\\ +b_{2}\\ +b_{3} +\end{array}\right]=\left[\begin{array}{ccc} +T_{11} & T_{12} & T_{13}\\ +T_{21} & T_{22} & T_{23}\\ +T_{31} & T_{32} & T_{33} +\end{array}\right]\left[\begin{array}{c} +a_{1}\\ +a_{2}\\ +a_{3} +\end{array}\right] +\] + +\end_inset + + The matrix of tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + + with respect to +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + can also be denoted by +\begin_inset Formula $\left[\mathbf{T}\right]$ +\end_inset + + or +\begin_inset Formula $\left[T_{ij}\right]$ +\end_inset + +. + The columns of +\begin_inset Formula $\left[\mathbf{T}\right]$ +\end_inset + + are given by +\begin_inset Formula $\mathbf{T}\cdot\mathbf{e}_{i}$ +\end_inset + +, e.g., +\begin_inset Formula +\[ +\left[\mathbf{T}\cdot\mathbf{e}_{2}\right]=\left[T_{j2}\mathbf{e}_{2}\right]=\left[\begin{array}{ccc} +T_{11} & T_{12} & T_{13}\\ +T_{21} & T_{22} & T_{23}\\ +T_{31} & T_{32} & T_{33} +\end{array}\right]\left[\begin{array}{c} +0\\ +1\\ +0 +\end{array}\right]=\left[\begin{array}{c} +T_{12}\\ +T_{22}\\ +T_{32} +\end{array}\right] +\] + +\end_inset + + This result, when generalized, leads to the useful identity +\begin_inset Formula +\begin{equation} +\boxed{\mathbf{T}\cdot\mathbf{e}_{i}=T_{ji}\mathbf{e}_{j}}=T_{1i}\mathbf{e}_{1}+T_{2i}\mathbf{e}_{2}+T_{3i}\mathbf{e}_{3}\label{eq8-1} +\end{equation} + +\end_inset + + +\end_layout + +\begin_layout Example +Scaling transformation +\end_layout + +\begin_layout Example +A scaling transformation +\begin_inset Formula $\mathbf{T}$ +\end_inset + + with different scale factors along +\begin_inset Formula $x_{1},x_{2},x_{3}$ +\end_inset + + should satisfy the following relations by definition: +\begin_inset Formula +\[ +\mathbf{T}\cdot\mathbf{a}=s_{1}\left(\mathbf{a}\cdot\mathbf{e}_{1}\right)\mathbf{e}_{1}+s_{2}\left(\mathbf{a}\cdot\mathbf{e}_{2}\right)\mathbf{e}_{2}+s_{3}\left(\mathbf{a}\cdot\mathbf{e}_{3}\right)\mathbf{e}_{3} +\] + +\end_inset + +Verify that +\begin_inset Formula $\mathbf{T}$ +\end_inset + + is a tensor. + Also find the matrix of +\begin_inset Formula $\mathbf{T}$ +\end_inset + + in +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + +. +\end_layout + +\begin_layout Example + +\shape italic +Solution +\shape default +. + Is +\begin_inset Formula $\mathbf{T}$ +\end_inset + + a tensor? Let any +\begin_inset Formula $\mathbf{a}=a_{i}\mathbf{e}_{i}$ +\end_inset + + and +\begin_inset Formula $\mathbf{b}=b_{i}\mathbf{e}_{i}$ +\end_inset + +, then +\begin_inset Formula +\[ +\begin{aligned}\mathbf{T}\cdot\left(\alpha\mathbf{a}\right) & =s_{1}\left(\alpha\mathbf{a}\cdot\mathbf{e}_{1}\right)\mathbf{e}_{1}+s_{2}\left(\alpha\mathbf{a}\cdot\mathbf{e}_{2}\right)\mathbf{e}_{2}+s_{3}\left(\alpha\mathbf{a}\cdot\mathbf{e}_{3}\right)\mathbf{e}_{3}\\ + & =\alpha\left(s_{1}\left(\mathbf{a}\cdot\mathbf{e}_{1}\right)\mathbf{e}_{1}+s_{2}\left(\mathbf{a}\cdot\mathbf{e}_{2}\right)\mathbf{e}_{2}+s_{3}\left(\mathbf{a}\cdot\mathbf{e}_{3}\right)\mathbf{e}_{3}\right)\\ + & =\alpha\mathbf{T}\cdot\mathbf{a} +\end{aligned} +\] + +\end_inset + +and +\begin_inset Formula +\[ +\begin{aligned}\mathbf{T}\cdot\left(\mathbf{a}+\mathbf{b}\right) & =s_{1}\left(\left(\mathbf{a}+\mathbf{b}\right)\cdot\mathbf{e}_{1}\right)\mathbf{e}_{1}+s_{2}\left(\left(\mathbf{a}+\mathbf{b}\right)\cdot\mathbf{e}_{2}\right)\mathbf{e}_{2}+s_{3}\left(\left(\mathbf{a}+\mathbf{b}\right)\cdot\mathbf{e}_{3}\right)\mathbf{e}_{3}\\ + & =s_{1}\left(\mathbf{a}\cdot\mathbf{e}_{1}\right)\mathbf{e}_{1}+s_{2}\left(\mathbf{a}\cdot\mathbf{e}_{2}\right)\mathbf{e}_{2}+s_{3}\left(\mathbf{a}\cdot\mathbf{e}_{3}\right)\mathbf{e}_{3}\\ + & +s_{1}\left(\mathbf{b}\cdot\mathbf{e}_{1}\right)\mathbf{e}_{1}+s_{2}\left(\mathbf{b}\cdot\mathbf{e}_{2}\right)\mathbf{e}_{2}+s_{3}\left(\mathbf{b}\cdot\mathbf{e}_{3}\right)\mathbf{e}_{3}\\ + & =\mathbf{T}\cdot\mathbf{a}+\mathbf{T}\cdot\mathbf{b} +\end{aligned} +\] + +\end_inset + + +\end_layout + +\begin_layout Example +Now that we have demonstrated that +\begin_inset Formula $\mathbf{T}$ +\end_inset + + is a tensor, its components are given by +\begin_inset Formula $T_{ij}=\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{j}$ +\end_inset + +, thus +\begin_inset Formula +\[ +\begin{gathered}\left[T_{i1}\right]=\left[\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{1}\right]=\left[\mathbf{e}_{i}\cdot s_{1}\mathbf{e}_{1}\right]=\left[s_{1}\delta_{i1}\right]=\left[\begin{array}{c} +s_{1}\\ +0\\ +0 +\end{array}\right]\\ +\left[T_{i2}\right]=\left[\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{2}\right]=\left[\mathbf{e}_{i}\cdot s_{2}\mathbf{e}_{2}\right]=\left[s_{2}\delta_{i2}\right]=\left[\begin{array}{c} +0\\ +s_{2}\\ +0 +\end{array}\right]\\ +\left[T_{i3}\right]=\left[\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{3}\right]=\left[\mathbf{e}_{i}\cdot s_{3}\mathbf{e}_{3}\right]=\left[s_{3}\delta_{i3}\right]=\left[\begin{array}{c} +0\\ +0\\ +s_{3} +\end{array}\right] +\end{gathered} +\] + +\end_inset + + Then, the matrix of +\begin_inset Formula $\mathbf{T}$ +\end_inset + + is given by +\begin_inset Formula +\[ +\left[\mathbf{T}\right]=\left[\begin{array}{ccc} +s_{1} & 0 & 0\\ +0 & s_{2} & 0\\ +0 & 0 & s_{3} +\end{array}\right] +\] + +\end_inset + + +\end_layout + +\begin_layout Subsection +Sum of Tensors +\end_layout + +\begin_layout Standard +The sum of two tensors +\begin_inset Formula $\mathbf{T}$ +\end_inset + + and +\begin_inset Formula $\mathbf{S}$ +\end_inset + + is denoted by +\begin_inset Formula $\mathbf{T}+\mathbf{S}$ +\end_inset + + and defined by +\begin_inset Formula +\begin{equation} +\boxed{\left(\mathbf{T}+\mathbf{S}\right)\cdot\mathbf{a}=\mathbf{T}\cdot\mathbf{a}+\mathbf{S}\cdot\mathbf{a}}\label{eq9-1} +\end{equation} + +\end_inset + + for any vector +\begin_inset Formula $\mathbf{a}$ +\end_inset + +. + Thus +\begin_inset Formula $\mathbf{T}+\mathbf{S}$ +\end_inset + + is also a tensor, whose components are +\begin_inset Formula +\[ +\left(\mathbf{T}+\mathbf{S}\right)_{ij}=\mathbf{e}_{i}\cdot\left(\mathbf{T}+\mathbf{S}\right)\cdot\mathbf{e}_{j}=\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{j}+\mathbf{e}_{i}\cdot\mathbf{S}\cdot\mathbf{e}_{j}=T_{ij}+S_{ij} +\] + +\end_inset + + In matrix notation, +\begin_inset Formula $\left[\mathbf{T}+\mathbf{S}\right]=\left[\mathbf{T}\right]+\left[\mathbf{S}\right]$ +\end_inset + +. + +\end_layout + +\begin_layout Subsection +Dyadic Product of Vectors +\end_layout + +\begin_layout Standard +The dyadic product of two vectors +\begin_inset Formula $\mathbf{a}$ +\end_inset + + and +\begin_inset Formula $\mathbf{b}$ +\end_inset + + is denoted by +\begin_inset Formula $\mathbf{a}\otimes\mathbf{b}$ +\end_inset + + (or +\begin_inset Formula $\mathbf{ab}$ +\end_inset + +) and defined as the transformation which satisfies +\begin_inset Formula +\begin{equation} +\boxed{\left(\mathbf{a}\otimes\mathbf{b}\right)\cdot\mathbf{c}=\left(\mathbf{b}\cdot\mathbf{c}\right)\mathbf{a}}\label{eq10-1} +\end{equation} + +\end_inset + + For any +\begin_inset Formula $\mathbf{c}$ +\end_inset + +, +\begin_inset Formula $\mathbf{d}$ +\end_inset + +, +\begin_inset Formula $\alpha$ +\end_inset + + and +\begin_inset Formula $\beta$ +\end_inset + +, we have +\begin_inset Formula +\[ +\begin{gathered}\left(\mathbf{a}\otimes\mathbf{b}\right)\cdot\left(\alpha\mathbf{c}+\beta\mathbf{d}\right)=\left(\mathbf{b}\cdot\left(\alpha\mathbf{c}+\beta\mathbf{d}\right)\right)\mathbf{a}=\left(\mathbf{b}\cdot\alpha\mathbf{c}\right)\mathbf{a}+\left(\mathbf{b}\cdot\beta\mathbf{d}\right)\mathbf{a}\\ +=\alpha\left(\mathbf{b}\cdot\mathbf{c}\right)\mathbf{a}+\beta\left(\mathbf{b}\cdot\mathbf{d}\right)\mathbf{a}=\alpha\left(\mathbf{a}\otimes\mathbf{b}\right)\cdot\mathbf{c}+\beta\left(\mathbf{a}\otimes\mathbf{b}\right)\cdot\mathbf{d} +\end{gathered} +\] + +\end_inset + + thus +\begin_inset Formula $\mathbf{a}\otimes\mathbf{b}$ +\end_inset + + is a tensor. + Its Cartesian components with respect to +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + are +\begin_inset Formula +\[ +\left(\mathbf{a}\otimes\mathbf{b}\right)_{ij}=\mathbf{e}_{i}\cdot\left(\mathbf{a}\otimes\mathbf{b}\right)\cdot\mathbf{e}_{j}=\mathbf{e}_{i}\cdot\left(\mathbf{b}\cdot\mathbf{e}_{j}\right)\mathbf{a}=b_{j}\mathbf{e}_{i}\cdot\mathbf{a}=a_{i}b_{j} +\] + +\end_inset + + In matrix form, +\begin_inset Formula +\[ +\left[\mathbf{a}\otimes\mathbf{b}\right]=\left[\begin{array}{ccc} +a_{1}b_{1} & a_{1}b_{2} & a_{1}b_{3}\\ +a_{2}b_{1} & a_{2}b_{2} & a_{2}b_{3}\\ +a_{3}b_{1} & a_{3}b_{2} & a_{3}b_{3} +\end{array}\right]=\left[\begin{array}{c} +a_{1}\\ +a_{2}\\ +a_{3} +\end{array}\right]\left[\begin{array}{ccc} +b_{1} & b_{2} & b_{3}\end{array}\right]=\left[\mathbf{a}\right]\left[\mathbf{b}\right]^{T} +\] + +\end_inset + + Note that in general, +\begin_inset Formula $\mathbf{a}\otimes\mathbf{b}\ne\mathbf{b}\otimes\mathbf{a}$ +\end_inset + +, i.e., the dyadic product is +\shape italic +not commutative +\shape default +. + Also note that +\begin_inset Formula +\[ +\left[\mathbf{e}_{1}\otimes\mathbf{e}_{1}\right]=\left[\begin{array}{ccc} +1 & 0 & 0\\ +0 & 0 & 0\\ +0 & 0 & 0 +\end{array}\right],\quad\left[\mathbf{e}_{1}\otimes\mathbf{e}_{2}\right]=\left[\begin{array}{ccc} +0 & 1 & 0\\ +0 & 0 & 0\\ +0 & 0 & 0 +\end{array}\right],\quad\left[\mathbf{e}_{1}\otimes\mathbf{e}_{3}\right]=\left[\begin{array}{ccc} +0 & 0 & 1\\ +0 & 0 & 0\\ +0 & 0 & 0 +\end{array}\right]\quad\text{etc.} +\] + +\end_inset + +thus it is possible to represent a second-order tensor in terms of its Cartesian + components in +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + as +\begin_inset Formula $\mathbf{T}=T_{11}\mathbf{e}_{1}\otimes\mathbf{e}_{1}+T_{12}\mathbf{e}_{1}\otimes\mathbf{e}_{2}+T_{13}\mathbf{e}_{1}\otimes\mathbf{e}_{3}+\ldots+T_{33}\mathbf{e}_{3}\otimes\mathbf{e}_{3}$ +\end_inset + +, or +\begin_inset Formula +\begin{equation} +\boxed{\mathbf{T}=T_{ij}\mathbf{e}_{i}\otimes\mathbf{e}_{j}}\label{eq11-1} +\end{equation} + +\end_inset + +This turns out to be an important result that can be generalized to higher + order tensors, e.g., third-order tensors can be represented in terms of their + Cartesian components as +\begin_inset Formula $\mathbb{T}=T_{ijk}\mathbf{e}_{i}\otimes\mathbf{e}_{j}\otimes\mathbf{e}_{k}$ +\end_inset + +, and similarly for higher orders. + +\end_layout + +\begin_layout Example +The scaling transformation derived in a previous example can be represented + as +\begin_inset Formula +\[ +\mathbf{T}=s_{1}\mathbf{e}_{1}\otimes\mathbf{e}_{1}+s_{2}\mathbf{e}_{2}\otimes\mathbf{e}_{2}+s_{3}\mathbf{e}_{3}\otimes\mathbf{e}_{3} +\] + +\end_inset + + +\end_layout + +\begin_layout Subsection +Trace of a Second-Order Tensor +\end_layout + +\begin_layout Standard +The trace of any dyad +\begin_inset Formula $\mathbf{a}\otimes\mathbf{b}$ +\end_inset + + is defined by +\begin_inset Formula +\[ +\boxed{\tr\left(\mathbf{a}\otimes\mathbf{b}\right)=\mathbf{a}\cdot\mathbf{b}} +\] + +\end_inset + + and +\begin_inset Formula +\[ +\boxed{\tr\left(\alpha\mathbf{a}\otimes\mathbf{b}+\beta\mathbf{c}\otimes\mathbf{d}\right)=\alpha\tr\left(\mathbf{a}\otimes\mathbf{b}\right)+\beta\tr\left(\mathbf{c}\otimes\mathbf{d}\right)} +\] + +\end_inset + +The trace operator yields a scalar function. + In component form, +\begin_inset Formula +\[ +\tr\left(a_{i}b_{j}\right)=a_{i}b_{i} +\] + +\end_inset + + For any tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, we can write +\begin_inset Formula $\mathbf{T}=T_{ij}\mathbf{e}_{i}\otimes\mathbf{e}_{j}$ +\end_inset + +, thus +\begin_inset Formula +\[ +\tr\mathbf{T}=T_{ij}\tr\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\right)=T_{ij}\mathbf{e}_{i}\cdot\mathbf{e}_{j}=T_{ij}\delta_{ij}=T_{ii}=T_{11}+T_{22}+T_{33} +\] + +\end_inset + + The trace of a tensor is the sum of its diagonal components. + +\end_layout + +\begin_layout Subsection +Product of Two Tensors +\end_layout + +\begin_layout Standard +The products of two tensors +\begin_inset Formula $\mathbf{T}$ +\end_inset + + and +\begin_inset Formula $\mathbf{S}$ +\end_inset + + are denoted by +\begin_inset Formula $\mathbf{T}\cdot\mathbf{S}$ +\end_inset + + and +\begin_inset Formula $\mathbf{S}\cdot\mathbf{T}$ +\end_inset + + and defined respectively by +\begin_inset Formula +\begin{equation} +\boxed{\left(\mathbf{T}\cdot\mathbf{S}\right)\cdot\mathbf{a}=\mathbf{T}\cdot\left(\mathbf{S}\cdot\mathbf{a}\right)}\label{eq12-1} +\end{equation} + +\end_inset + + and +\begin_inset Formula +\begin{equation} +\boxed{\left(\mathbf{S}\cdot\mathbf{T}\right)\cdot\mathbf{a}=\mathbf{S}\cdot\left(\mathbf{T}\cdot\mathbf{a}\right)}\label{eq12b} +\end{equation} + +\end_inset + +Clearly, +\begin_inset Formula $\mathbf{T}\cdot\mathbf{S}$ +\end_inset + + and +\begin_inset Formula $\mathbf{S}\cdot\mathbf{T}$ +\end_inset + + are tensors as well. + Their components in +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + are given by +\begin_inset Formula +\[ +\left(\mathbf{T}\cdot\mathbf{S}\right)_{ij}=\mathbf{e}_{i}\cdot\left(\mathbf{T}\cdot\mathbf{S}\right)\cdot\mathbf{e}_{j}=\mathbf{e}_{i}\cdot\mathbf{T}\cdot\left(\mathbf{S}\cdot\mathbf{e}_{j}\right)=\mathbf{e}_{i}\cdot\mathbf{T}\cdot\left(S_{kj}\mathbf{e}_{k}\right)=S_{kj}\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{k}=T_{ik}S_{kj} +\] + +\end_inset + + In matrix form, +\begin_inset Formula $\left[\mathbf{T}\cdot\mathbf{S}\right]=\left[\mathbf{T}\right]\left[\mathbf{S}\right]$ +\end_inset + +. + Similarly, +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +\left(\mathbf{S}\cdot\mathbf{T}\right)_{ij}=S_{ik}T_{kj}\quad\text{and}\quad\left[\mathbf{S}\cdot\mathbf{T}\right]=\left[\mathbf{S}\right]\left[\mathbf{T}\right] +\] + +\end_inset + + In general, +\begin_inset Formula $\mathbf{T}\cdot\mathbf{S}\ne\mathbf{S}\cdot\mathbf{T}$ +\end_inset + +, however +\begin_inset Formula $\left(\mathbf{T}\cdot\mathbf{S}\right)\cdot\mathbf{V}=\mathbf{T}\cdot\left(\mathbf{S}\cdot\mathbf{V}\right)$ +\end_inset + +, i.e., the tensor product is +\shape italic +associative +\shape default + but +\shape italic +not commutative +\shape default +. + +\end_layout + +\begin_layout Subsection +Identity Tensor and Tensor Inverse +\end_layout + +\begin_layout Standard +The identity tensor, denoted by +\begin_inset Formula $\mathbf{I}$ +\end_inset + +, is defined by +\begin_inset Formula +\begin{equation} +\boxed{\mathbf{I}\cdot\mathbf{a}=\mathbf{a}}\label{eq13-1} +\end{equation} + +\end_inset + + for any vector +\begin_inset Formula $\mathbf{a}$ +\end_inset + +. + The Cartesian components o f +\begin_inset Formula $\mathbf{I}$ +\end_inset + + in +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + are given by +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +I_{ij}=\mathbf{e}_{i}\cdot\mathbf{I}\cdot\mathbf{e}_{j}=\mathbf{e}_{i}\cdot\mathbf{e}_{j}=\delta_{ij} +\] + +\end_inset + + or +\begin_inset Formula +\[ +\left[\mathbf{I}\right]=\left[\begin{array}{ccc} +1 & 0 & 0\\ +0 & 1 & 0\\ +0 & 0 & 1 +\end{array}\right] +\] + +\end_inset + +Given +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, if +\begin_inset Formula $\mathbf{S}$ +\end_inset + + exists such that +\begin_inset Formula $\mathbf{S}\cdot\mathbf{T}=\mathbf{I}$ +\end_inset + +, we call +\begin_inset Formula $\mathbf{S}$ +\end_inset + + the +\emph on +inverse +\emph default + of +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, and +\begin_inset Formula $\mathbf{S}=\mathbf{T}^{-1}$ +\end_inset + +. + The inverse exists as long as +\begin_inset Formula $\det\mathbf{T}\neq0$ +\end_inset + +. + Also note that +\begin_inset Formula $\left(\mathbf{T}^{-1}\right)^{-1}=\mathbf{T}$ +\end_inset + + and +\begin_inset Formula $\mathbf{T}^{-1}\cdot\mathbf{T}=\mathbf{T}\cdot\mathbf{T}^{-1}=\mathbf{I}$ +\end_inset + +. + Also note that +\begin_inset Formula +\[ +\boxed{\left(\mathbf{U}\cdot\mathbf{V}\right)^{-1}=\mathbf{V}^{-1}\cdot\mathbf{U}^{-1}}\,. +\] + +\end_inset + + +\end_layout + +\begin_layout Subsection +Transpose of a Tensor +\end_layout + +\begin_layout Standard +Given a tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, its transpose is denoted by +\begin_inset Formula $\mathbf{T}^{T}$ +\end_inset + + which is defined by +\begin_inset Formula +\begin{equation} +\boxed{\mathbf{a}\cdot\left(\mathbf{T}\cdot\mathbf{b}\right)=\mathbf{b}\cdot\left(\mathbf{T}^{T}\cdot\mathbf{\mathbf{a}}\right)}\label{eq14-1} +\end{equation} + +\end_inset + + In component form, +\begin_inset Formula +\[ +T_{ij}^{T}=\mathbf{e}_{i}\cdot\mathbf{T}^{T}\cdot\mathbf{e}_{j}=\mathbf{e}_{j}\cdot\mathbf{T}\cdot\mathbf{e}_{i}=T_{ji} +\] + +\end_inset + + Also note that +\begin_inset Formula +\begin{equation} +\boxed{\left(\mathbf{S}\cdot\mathbf{T}\right)^{T}=\mathbf{T}^{T}\cdot\mathbf{S}^{T}}\label{eq15-1} +\end{equation} + +\end_inset + +and +\begin_inset Formula $\left(\mathbf{S}^{T}\right)^{T}=\mathbf{S}$ +\end_inset + + and +\begin_inset Formula $\left(\mathbf{S}+\mathbf{T}\right)^{T}=\mathbf{S}^{T}+\mathbf{T}^{T}$ +\end_inset + +. +\end_layout + +\begin_layout Subsection +Double Product of Tensors +\end_layout + +\begin_layout Standard +The double product of tensors is analogous to the dot product of vectors. + Given two tensors +\begin_inset Formula $\mathbf{S}$ +\end_inset + + and +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, the double product (or +\shape italic +double contraction +\shape default +) is defined as +\begin_inset Formula +\begin{equation} +\boxed{\mathbf{S}:\mathbf{T}=\tr\left(\mathbf{S}^{T}\cdot\mathbf{T}\right)}\label{eq16-1} +\end{equation} + +\end_inset + + Thus, for any tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, +\begin_inset Formula $\tr\mathbf{T}=\mathbf{I}:\mathbf{T}$ +\end_inset + +. + In component form, +\begin_inset Formula +\[ +\mathbf{S}:\mathbf{T}=S_{ij}T_{ij} +\] + +\end_inset + +The double product of second order tensors is commutative. + +\end_layout + +\begin_layout Example +Show that +\begin_inset Formula $\mathbf{a}\cdot\mathbf{T}\cdot\mathbf{b}=\mathbf{T}:\left(\mathbf{a}\otimes\mathbf{b}\right)$ +\end_inset + + and +\begin_inset Formula $\left(\mathbf{a}\otimes\mathbf{b}\right):\left(\mathbf{c}\otimes\mathbf{d}\right)=\left(\mathbf{a}\cdot\mathbf{c}\right)\left(\mathbf{b}\cdot\mathbf{d}\right)$ +\end_inset + +. + +\end_layout + +\begin_layout Example +Using indicial notation, +\begin_inset Formula +\[ +\mathbf{a}\cdot\mathbf{T}\cdot\mathbf{b}=a_{i}T_{ij}b_{j}=T_{ij}a_{i}b_{j}=\mathbf{T}:\left(\mathbf{a}\otimes\mathbf{b}\right)\,, +\] + +\end_inset + +and +\begin_inset Formula +\[ +\left(\mathbf{a}\otimes\mathbf{b}\right):\left(\mathbf{c}\otimes\mathbf{d}\right)=a_{i}b_{j}c_{i}d_{j}=\left(a_{i}c_{i}\right)\left(b_{j}d_{j}\right)=\left(\mathbf{a}\cdot\mathbf{c}\right)\left(\mathbf{b}\cdot\mathbf{d}\right)\,. +\] + +\end_inset + + +\end_layout + +\begin_layout Subsection +Determinant of a Tensor +\begin_inset CommandInset label +LatexCommand label +name "subsubsec:determinant" + +\end_inset + + +\end_layout + +\begin_layout Standard +The determinant of a tensor is equal to the determinant of its components + in +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + +, +\begin_inset Formula +\begin{equation} +\det\mathbf{T}=\det\left[\mathbf{T}\right]_{\mathbf{e}_{i}}=\left|\begin{array}{ccc} +T_{11} & T_{12} & T_{13}\\ +T_{21} & T_{22} & T_{23}\\ +T_{31} & T_{32} & T_{33} +\end{array}\right|=\left(\mathbf{T}\cdot\mathbf{e}_{1}\times\mathbf{T}\cdot\mathbf{e}_{2}\right)\cdot\mathbf{T}\cdot\mathbf{e}_{3}=\varepsilon_{ijk}T_{i1}T_{j2}T_{k3}\label{eq17-1} +\end{equation} + +\end_inset + + In particular, the determinant of a diagonal matrix is the product of the + diagonal components, +\begin_inset Formula +\begin{equation} +\det\left[\mathbf{T}\right]_{\mathbf{e}_{i}}=\left|\begin{array}{ccc} +T_{11} & 0 & 0\\ +0 & T_{22} & 0\\ +0 & 0 & T_{33} +\end{array}\right|=\varepsilon_{123}T_{11}T_{22}T_{33}=T_{11}T_{22}T_{33}\label{eq18-1} +\end{equation} + +\end_inset + + The determinant satisfies the following relations, +\begin_inset Formula +\begin{equation} +\det\mathbf{T}^{-1}=\frac{1}{\det\mathbf{T}}\label{eq19-1} +\end{equation} + +\end_inset + + +\begin_inset Formula +\begin{equation} +\det\left(\mathbf{S}\cdot\mathbf{T}\right)=\left(\det\mathbf{S}\right)\left(\det\mathbf{T}\right)\label{eq20-1} +\end{equation} + +\end_inset + + +\end_layout + +\begin_layout Subsection +Orthogonal Tensor +\end_layout + +\begin_layout Standard +An orthogonal tensor +\begin_inset Formula $\mathbf{Q}$ +\end_inset + + is a linear transformation which preserves the length of a vector and the + angle between vectors. + Thus, by definition, +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +\left|\mathbf{Q}\cdot\mathbf{a}\right|=\left|\mathbf{a}\right|\quad\text{and}\quad\cos\left(\mathbf{Q}\cdot\mathbf{a},\mathbf{Q}\cdot\mathbf{b}\right)=\cos\left(\mathbf{a},\mathbf{b}\right) +\] + +\end_inset + + for any vectors +\begin_inset Formula $\mathbf{a}$ +\end_inset + + and +\begin_inset Formula $\mathbf{b}$ +\end_inset + +. + It follows from this definition and the definition of the dot product of + vectors ( +\begin_inset Formula $\mathbf{a}\cdot\mathbf{b}=\left|\mathbf{a}\right|\left|\mathbf{b}\right|\cos\left(\mathbf{a},\mathbf{b}\right))$ +\end_inset + +, that +\begin_inset Formula +\[ +\left(\mathbf{Q}\cdot\mathbf{a}\right)\cdot\left(\mathbf{Q}\cdot\mathbf{b}\right)=\mathbf{a}\cdot\mathbf{b} +\] + +\end_inset + + But +\begin_inset Formula $\left(\mathbf{Q}\cdot\mathbf{a}\right)\cdot\left(\mathbf{Q}\cdot\mathbf{b}\right)=\mathbf{b}\cdot\left(\mathbf{Q}^{T}\cdot\mathbf{Q}\right)\mathbf{a}=\mathbf{a}\cdot\mathbf{b}=\mathbf{b}\cdot\mathbf{I}\cdot\mathbf{a}$ +\end_inset + +, which implies that +\begin_inset Formula $\mathbf{b}\cdot\left(\mathbf{Q}^{T}\cdot\mathbf{Q}-\mathbf{I}\right)\cdot\mathbf{a}=0$ +\end_inset + +. + Since +\begin_inset Formula $\mathbf{a}$ +\end_inset + + and +\begin_inset Formula $\mathbf{b}$ +\end_inset + + are arbitrary, an orthogonal tensor must satisfy +\begin_inset Formula $\mathbf{Q}^{T}\cdot\mathbf{Q}=\mathbf{I}$ +\end_inset + +. + In indicial form, +\begin_inset Formula $Q_{im}^{T}Q_{mj}=Q_{mi}Q_{mj}=\delta_{ij}$ +\end_inset + +, and in matrix form, +\begin_inset Formula $\left[\mathbf{Q}\right]^{T}\left[\mathbf{Q}\right]=\left[\mathbf{I}\right]$ +\end_inset + +. + +\end_layout + +\begin_layout Standard +Note that +\begin_inset Formula $\mathbf{Q}^{T}\cdot\mathbf{Q}=\mathbf{I}$ +\end_inset + + implies that +\begin_inset Formula $\mathbf{Q}^{T}=\mathbf{Q}^{-1}$ +\end_inset + +, i.e., the transpose of an orthogonal tensor is equal to its inverse, since + +\begin_inset Formula $\mathbf{Q}^{-1}\cdot\mathbf{Q}=\mathbf{Q}\cdot\mathbf{Q}^{-1}=\mathbf{I}$ +\end_inset + +. + It follows that +\begin_inset Formula +\begin{equation} +\boxed{\mathbf{Q}^{T}\cdot\mathbf{Q}=\mathbf{Q}\cdot\mathbf{Q}^{T}=\mathbf{I}}\label{eq21-1} +\end{equation} + +\end_inset + + The determinant of an orthogonal tensor is given by +\begin_inset Formula +\[ +\det\mathbf{Q}=\left(\mathbf{Q}\cdot\mathbf{e}_{1}\times\mathbf{Q}\cdot\mathbf{e}_{2}\right)\cdot\mathbf{Q}\cdot\mathbf{e}_{3}=\left(\mathbf{e}'_{1}\times\mathbf{e}'_{2}\right)\cdot\mathbf{e}'_{3}=\pm\mathbf{e}'_{3}\cdot\mathbf{e}'_{3}=\pm1 +\] + +\end_inset + + Here, +\begin_inset Formula $\left\{ \mathbf{e}'_{1},\mathbf{e}'_{2},\mathbf{e}'_{3}\right\} $ +\end_inset + + is the orthonormal basis resulting from the transformation of +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + by +\begin_inset Formula $\mathbf{Q}$ +\end_inset + +. + If +\begin_inset Formula $\mathbf{Q}$ +\end_inset + + maintains the handedness of +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + (e.g., if both +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + and +\begin_inset Formula $\left\{ \mathbf{e}'_{1},\mathbf{e}'_{2},\mathbf{e}'_{3}\right\} $ +\end_inset + + form a right-handed basis), then +\begin_inset Formula $\det\mathbf{Q}=+1$ +\end_inset + + and +\begin_inset Formula $\mathbf{Q}$ +\end_inset + + is called a +\shape italic +proper +\shape default + orthogonal transformation (also equivalent to a rigid body rotation). + Otherwise, in the case of a reflection which reverses the handedness of + the basis vectors, +\begin_inset Formula $\det\mathbf{Q}=-1$ +\end_inset + + and +\begin_inset Formula $\mathbf{Q}$ +\end_inset + + is called +\shape italic +improper +\shape default + (e.g., +\begin_inset Formula $\mathbf{e}'_{1}=\mathbf{e}_{1},\,\mathbf{e}'_{2}=-\mathbf{e}_{2},\,\mathbf{e}'_{3}=\mathbf{e}_{3}$ +\end_inset + +). + +\end_layout + +\begin_layout Subsection +Transformation Laws for Cartesian Components of Vectors and Tensors +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename Figures/FigOrthoBases.png + lyxscale 50 + width 1.39in + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Orthonormal bases +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + and +\begin_inset Formula $\left\{ \mathbf{e}'_{1},\mathbf{e}'_{2},\mathbf{e}'_{3}\right\} $ +\end_inset + +. +\begin_inset CommandInset label +LatexCommand label +name "fig3" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + +Let +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + and +\begin_inset Formula $\left\{ \mathbf{e}'_{1},\mathbf{e}'_{2},\mathbf{e}'_{3}\right\} $ +\end_inset + + be two orthogonal bases in a Cartesian coordinate system. + +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + could be made to coincide with +\begin_inset Formula $\left\{ \mathbf{e}'_{1},\mathbf{e}'_{2},\mathbf{e}'_{3}\right\} $ +\end_inset + + through a rigid body rotation (i.e., a transformation that preserves vector + length and angles), +\begin_inset Formula +\[ +\mathbf{e}'_{i}=\mathbf{Q}\cdot\mathbf{e}_{i}=Q_{mi}\mathbf{e}_{m} +\] + +\end_inset + + where +\begin_inset Formula $Q_{mi}Q_{mj}=Q_{im}Q_{jm}=\delta_{ij}$ +\end_inset + +. + Since +\begin_inset Formula $Q_{mi}=\mathbf{e}_{m}\cdot\mathbf{Q}\cdot\mathbf{e}_{i}=\mathbf{e}_{m}\cdot\mathbf{e}'_{i}=\cos\left(\mathbf{e}_{m},\mathbf{e}'_{i}\right)$ +\end_inset + +, the components of +\begin_inset Formula $\mathbf{Q}$ +\end_inset + + are direction cosines between +\begin_inset Formula $\mathbf{e}_{m}$ +\end_inset + + and +\begin_inset Formula $\mathbf{e}'_{i}$ +\end_inset + +. + +\end_layout + +\begin_layout Example +Rotation about +\begin_inset Formula $x_{3}$ +\end_inset + + +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Plain Layout +\begin_inset Graphics + filename Figures/FigRotationAboutX3.png + lyxscale 50 + width 2.58in + +\end_inset + + +\end_layout + +\begin_layout Plain Layout +\begin_inset Caption Standard + +\begin_layout Plain Layout +Rotation about +\begin_inset Formula $x_{3}$ +\end_inset + +. +\begin_inset CommandInset label +LatexCommand label +name "fig36" + +\end_inset + + +\end_layout + +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Formula +\[ +\left[\mathbf{Q}\right]=\left[\begin{array}{ccc} +\cos\theta & -\sin\theta & 0\\ +\sin\theta & \cos\theta & 0\\ +0 & 0 & 1 +\end{array}\right] +\] + +\end_inset + + +\end_layout + +\begin_layout Example +Reflection about +\begin_inset Formula $x_{2}-x_{3}$ +\end_inset + + plane, +\begin_inset Formula $\mathbf{e}'_{1}=\mathbf{Q}\cdot\mathbf{e}_{1}=-\mathbf{e}_{1},\,\mathbf{e}'_{2}=\mathbf{Q}\cdot\mathbf{e}_{2}=\mathbf{e}_{2},\,\mathbf{e}'_{3}=\mathbf{Q}\cdot\mathbf{e}_{3}=\mathbf{e}_{3}$ +\end_inset + +. +\begin_inset Formula +\[ +\left[\mathbf{Q}\right]=\left[\begin{array}{ccc} +-1 & 0 & 0\\ +0 & 1 & 0\\ +0 & 0 & 1 +\end{array}\right] +\] + +\end_inset + + +\end_layout + +\begin_layout Standard +For any vector +\begin_inset Formula $\mathbf{a}$ +\end_inset + +, its components with respect to +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + and +\begin_inset Formula $\left\{ \mathbf{e}'_{1},\mathbf{e}'_{2},\mathbf{e}'_{3}\right\} $ +\end_inset + + are +\begin_inset Formula $a_{i}=\mathbf{e}_{i}\cdot\mathbf{a}$ +\end_inset + + and +\begin_inset Formula $a'_{i}=\mathbf{e}'_{i}\cdot\mathbf{a}$ +\end_inset + +, respectively. + Using the above relation, +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +a'_{i}=\mathbf{e}'_{i}\cdot\mathbf{a}=\mathbf{a}\cdot\mathbf{Q}\cdot\mathbf{e}_{i}=Q_{mi}\mathbf{a}\cdot\mathbf{e}_{m}=Q_{mi}a_{m}, +\] + +\end_inset + + or +\begin_inset Formula +\begin{equation} +\boxed{a'_{i}=Q_{mi}a_{m}}\label{eq22-1} +\end{equation} + +\end_inset + + In matrix form, +\begin_inset Formula +\[ +\left[\begin{array}{c} +a'_{1}\\ +a'_{2}\\ +a'_{3} +\end{array}\right]_{\mathbf{e'}_{i}}=\left[\begin{array}{ccc} +Q_{11} & Q_{21} & Q_{31}\\ +Q_{12} & Q_{22} & Q_{32}\\ +Q_{13} & Q_{23} & Q_{33} +\end{array}\right]\left[\begin{array}{c} +a_{1}\\ +a_{2}\\ +a_{3} +\end{array}\right]_{\mathbf{e}_{i}} +\] + +\end_inset + +or +\begin_inset Formula +\[ +\left[\mathbf{a}\right]^{\prime}=\left[\mathbf{Q}\right]^{T}\left[\mathbf{a}\right]\quad\text{or}\quad\left[\mathbf{a}\right]_{\mathbf{e'}_{i}}=\left[\mathbf{Q}\right]^{T}\left[\mathbf{a}\right]_{\mathbf{e}_{i}} +\] + +\end_inset + +Here +\begin_inset Formula $\left[\mathbf{a}\right]^{\prime}$ +\end_inset + + and +\begin_inset Formula $\left[\mathbf{a}\right]$ +\end_inset + + are matrices of the +\shape italic +same +\shape default + vector, expressed in two different coordinate systems. + This is +\shape italic +not the same +\shape default + as +\begin_inset Formula $\mathbf{a}'=\mathbf{Q}^{T}\cdot\mathbf{a}$ +\end_inset + +, where +\begin_inset Formula $\mathbf{a}'$ +\end_inset + + is the linear transformation of +\begin_inset Formula $\mathbf{a}$ +\end_inset + + by +\begin_inset Formula $\mathbf{Q}^{T}$ +\end_inset + +. + +\end_layout + +\begin_layout Standard +Now consider a tensors +\begin_inset Formula $\mathbf{T}$ +\end_inset + +. + Its components with respect to +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + and +\begin_inset Formula $\left\{ \mathbf{e}'_{1},\mathbf{e}'_{2},\mathbf{e}'_{3}\right\} $ +\end_inset + + are given by +\begin_inset Formula $T_{ij}=\mathbf{e}_{i}\cdot\mathbf{T}\cdot\mathbf{e}_{j}$ +\end_inset + + and +\begin_inset Formula $T'_{ij}=\mathbf{e}'_{i}\cdot\mathbf{T}\cdot\mathbf{e}'_{j}$ +\end_inset + +, respectively. + Thus, +\begin_inset Formula $T'_{ij}=\left(\mathbf{Q}\cdot\mathbf{e}_{i}\right)\cdot\mathbf{T}\cdot\left(\mathbf{Q}\cdot\mathbf{e}_{j}\right)=Q_{mi}\mathbf{e}_{m}\cdot\mathbf{T}\cdot Q_{nj}\mathbf{e}_{n}=Q_{mi}Q_{nj}\mathbf{e}_{m}\cdot\mathbf{T}\cdot\mathbf{e}_{n}=Q_{mi}Q_{nj}T_{mn}$ +\end_inset + +, or +\begin_inset Formula +\begin{equation} +\boxed{T'_{ij}=Q_{mi}Q_{nj}T_{mn}}\label{eq23-1} +\end{equation} + +\end_inset + + In matrix form, +\begin_inset Formula $\left[\mathbf{T}\right]^{\prime}=\left[\mathbf{Q}\right]^{T}\left[\mathbf{T}\right]\left[\mathbf{Q}\right]$ +\end_inset + +, or +\begin_inset Formula +\[ +\left[\begin{array}{ccc} +T'_{11} & T'_{12} & T'_{13}\\ +T'_{21} & T'_{22} & T'_{23}\\ +T'_{31} & T'_{32} & T'_{33} +\end{array}\right]=\left[\begin{array}{ccc} +Q_{11} & Q_{21} & Q_{31}\\ +Q_{12} & Q_{22} & Q_{32}\\ +Q_{13} & Q_{23} & Q_{33} +\end{array}\right]\left[\begin{array}{ccc} +T_{11} & T_{12} & T_{13}\\ +T_{21} & T_{22} & T_{23}\\ +T_{31} & T_{32} & T_{33} +\end{array}\right]\left[\begin{array}{ccc} +Q_{11} & Q_{12} & Q_{13}\\ +Q_{21} & Q_{22} & Q_{23}\\ +Q_{31} & Q_{32} & Q_{33} +\end{array}\right] +\] + +\end_inset + + Equivalently, we can show that +\begin_inset Formula +\begin{equation} +\boxed{T_{ij}=Q_{im}Q_{jn}T'_{mn}}\label{eq24-1} +\end{equation} + +\end_inset + + or +\begin_inset Formula $\left[\mathbf{T}\right]=\left[\mathbf{Q}\right]\left[\mathbf{T}\right]^{\prime}\left[\mathbf{Q}\right]^{T}$ +\end_inset + +. + As for vectors, we note that +\begin_inset Formula $\left[\mathbf{T}\right]$ +\end_inset + + and +\begin_inset Formula $\left[\mathbf{T}\right]^{\prime}$ +\end_inset + + are the matrices of the +\shape italic +same +\shape default + tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, with respect to two different coordinate systems. + This is +\shape italic +not the same +\shape default + as +\begin_inset Formula $\mathbf{T}'=\mathbf{Q}^{T}\cdot\mathbf{T}\cdot\mathbf{Q}$ +\end_inset + +. + +\end_layout + +\begin_layout Subsection +Symmetric and Antisymmetric Tensors +\begin_inset CommandInset label +LatexCommand label +name "subsubsec:symmetric" + +\end_inset + + +\end_layout + +\begin_layout Standard +A +\shape italic +symmetric +\shape default + tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + + satisfies +\begin_inset Formula $\mathbf{T}^{T}=\mathbf{T}$ +\end_inset + +, i.e., +\begin_inset Formula $T_{ji}=T_{ij}$ +\end_inset + +, or in matrix form, +\begin_inset Formula +\[ +\left[\mathbf{T}\right]=\left[\begin{array}{ccc} +T_{11} & T_{12} & T_{13}\\ +T_{12} & T_{22} & T_{23}\\ +T_{13} & T_{23} & T_{33} +\end{array}\right] +\] + +\end_inset + + An +\shape italic +antisymmetric +\shape default + (or +\shape italic +skew-symmetric +\shape default +) tensor +\begin_inset Formula $\boldsymbol{\Omega}$ +\end_inset + + satisfies +\begin_inset Formula $\boldsymbol{\Omega}^{T}=-\boldsymbol{\Omega}$ +\end_inset + +, i.e., +\begin_inset Formula $\Omega_{ji}=-\Omega_{ij}$ +\end_inset + + and thus +\begin_inset Formula $\Omega_{11}=\Omega_{22}=\Omega_{33}=0$ +\end_inset + +, +\begin_inset Formula +\[ +\left[\boldsymbol{\Omega}\right]=\left[\begin{array}{ccc} +0 & \Omega_{12} & -\Omega_{31}\\ +-\Omega_{12} & 0 & \Omega_{23}\\ +\Omega_{31} & -\Omega_{23} & 0 +\end{array}\right] +\] + +\end_inset + +Any tensor can be written as the sum of a symmetric and antisymmetric tensor, + +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +\mathbf{T}=\mathbf{T}^{S}+\mathbf{T}^{A}\quad\text{where}\quad\mathbf{T}^{S}=\frac{1}{2}\left(\mathbf{T}+\mathbf{T}^{T}\right)\quad\text{and}\quad\mathbf{T}^{A}=\frac{1}{2}\left(\mathbf{T}-\mathbf{T}^{T}\right) +\] + +\end_inset + +This is a unique decomposition. + It can be checked that +\begin_inset Formula $\mathbf{T}^{S}$ +\end_inset + + is symmetric and +\begin_inset Formula $\mathbf{T}^{A}$ +\end_inset + + is antisymmetric. + +\end_layout + +\begin_layout Standard +The +\shape italic +dual vector +\shape default + +\begin_inset Formula $\boldsymbol{\omega}$ +\end_inset + + of an antisymmetric tensor +\begin_inset Formula $\boldsymbol{\Omega}$ +\end_inset + + satisfies +\begin_inset Formula +\begin{equation} +\boxed{\boldsymbol{\Omega}\cdot\mathbf{a}=\boldsymbol{\omega}\times\mathbf{a}}\label{eq25-1} +\end{equation} + +\end_inset + + for any vector +\begin_inset Formula $\mathbf{a}$ +\end_inset + +. + Thus +\begin_inset Formula $\Omega_{ij}=\mathbf{e}_{i}\cdot\boldsymbol{\Omega}\cdot\mathbf{e}_{j}=\mathbf{e}_{i}\cdot\left(\boldsymbol{\omega}\times\mathbf{e}_{j}\right)=\omega_{k}\mathbf{e}_{i}\cdot\left(\mathbf{e}_{k}\times\mathbf{e}_{j}\right)=\omega_{k}\mathbf{e}_{i}\cdot\varepsilon_{kjl}\mathbf{e}_{l}=\omega_{k}\varepsilon_{kjl}\delta_{il}$ +\end_inset + + or +\begin_inset Formula +\begin{equation} +\boxed{\Omega_{ij}=-\varepsilon_{ijk}\omega_{k}}\label{eq26-1} +\end{equation} + +\end_inset + +In matrix form, +\begin_inset Formula +\[ +\left[\boldsymbol{\Omega}\right]=\left[\begin{array}{ccc} +0 & -\omega_{3} & \omega_{2}\\ +\omega_{3} & 0 & -\omega_{1}\\ +-\omega_{2} & \omega_{1} & 0 +\end{array}\right] +\] + +\end_inset + +Conversely, it can also be shown that +\begin_inset Formula +\begin{equation} +\boxed{\omega_{i}=-\frac{1}{2}\varepsilon_{ijk}\Omega_{jk}}\label{eq27-1} +\end{equation} + +\end_inset + +As a homework problem, it may be shown that +\begin_inset Formula $\varepsilon_{ijk}T_{jk}=\varepsilon_{ijk}T_{jk}^{A}$ +\end_inset + +, since +\begin_inset Formula $\varepsilon_{ijk}T_{jk}^{S}=0$ +\end_inset + + for any symmetric tensor +\begin_inset Formula $\mathbf{T}^{S}$ +\end_inset + +. +\end_layout + +\begin_layout Subsection +Eigenvalues and Eigenvectors of Real Symmetric Tensors +\end_layout + +\begin_layout Standard +A second-order tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + + has three pairs of eigenvalues +\begin_inset Formula $\lambda$ +\end_inset + + and eigenvectors +\begin_inset Formula $\mathbf{v}$ +\end_inset + + that each satisfy +\begin_inset Formula +\begin{equation} +\mathbf{T}\cdot\mathbf{v}=\lambda\mathbf{v}\label{eq:eigen-def} +\end{equation} + +\end_inset + +The eigenvalues +\begin_inset Formula $\lambda$ +\end_inset + + are the roots of the characteristic equation of +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, which is the cubic polynomial produced by setting +\begin_inset Formula $\det\left(\mathbf{T}-\lambda\mathbf{I}\right)=0$ +\end_inset + +, +\begin_inset Formula +\begin{equation} +-\lambda^{3}+I_{1}\lambda^{2}-I_{2}\lambda+I_{3}=0\label{eq:eigen-char-eqn} +\end{equation} + +\end_inset + +where +\begin_inset Formula +\begin{equation} +\begin{aligned}I_{1} & =\tr\mathbf{T}\\ +I_{2} & =\frac{1}{2}\left(I_{1}^{2}-\tr\mathbf{T}^{2}\right)\\ +I_{3} & =\det\mathbf{T} +\end{aligned} +\label{eq:eigen-invariants} +\end{equation} + +\end_inset + +are called +\emph on +invariants +\emph default + of +\begin_inset Formula $\mathbf{T}$ +\end_inset + +. +\end_layout + +\begin_layout Standard +According to the Cayley-Hamilton theorem, a tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + + satisfies its own characteristic equation, +\begin_inset Formula +\begin{equation} +-\mathbf{T}^{3}+I_{1}\mathbf{T}^{2}-I_{2}\mathbf{T}+I_{3}\mathbf{I}=\mathbf{0}\label{eq:Cayley-Hamilton-theorem} +\end{equation} + +\end_inset + +Therefore, the cubic power of +\begin_inset Formula $\mathbf{T}$ +\end_inset + + can be expressed in terms of its lower powers according to +\begin_inset Formula $\mathbf{T}^{3}=I_{1}\mathbf{T}^{2}-I_{2}\mathbf{T}+I_{3}\mathbf{I}$ +\end_inset + +. + Taking the trace of this equation allows us to solve for +\begin_inset Formula $I_{3}$ +\end_inset + + as +\begin_inset Formula +\begin{equation} +\begin{aligned}I_{3} & =\frac{1}{3}\left(\tr\mathbf{T}^{3}-I_{1}\tr\mathbf{T}^{2}+I_{2}\tr\mathbf{T}\right)\\ + & =\frac{1}{3}\left(\tr\mathbf{T}^{3}-I_{1}^{3}+3I_{1}I_{2}\right) +\end{aligned} +\label{eq:eigen-I3-soln} +\end{equation} + +\end_inset + +Multiplying eq. +\begin_inset CommandInset ref +LatexCommand eqref +reference "eq:Cayley-Hamilton-theorem" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + by +\begin_inset Formula $\mathbf{T}^{-1}$ +\end_inset + + also produces +\begin_inset Formula +\[ +I_{3}\mathbf{T}^{-1}=\mathbf{T}^{2}-I_{1}\mathbf{T}+I_{2}\mathbf{I} +\] + +\end_inset + +Using all these relations, we may differentiate the three invariants of + +\begin_inset Formula $\mathbf{T}$ +\end_inset + + with respect to +\begin_inset Formula $\mathbf{T}$ +\end_inset + + to get +\begin_inset Formula +\begin{equation} +\begin{aligned}\frac{\partial I_{1}}{\partial\mathbf{T}} & =\mathbf{I}\\ +\frac{\partial I_{2}}{\partial\mathbf{T}} & =I_{1}\mathbf{I}-\mathbf{T}^{T}\\ +\frac{\partial I_{3}}{\partial\mathbf{T}} & =I_{3}\mathbf{T}^{-T} +\end{aligned} +\label{eq:eigen-dinv-dT} +\end{equation} + +\end_inset + + +\end_layout + +\begin_layout Theorem* +The eigenvalues of real symmetric tensors are real (proof not provided here). + +\end_layout + +\begin_deeper +\begin_layout Theorem* +If the eigenvalues of a real symmetric tensor are all distinct, the eigenvectors + are orthogonal to each other. + +\end_layout + +\end_deeper +\begin_layout Standard + +\shape italic +Proof: +\shape default + Given +\begin_inset Formula $\mathbf{T}\cdot\mathbf{v}_{1}=\lambda_{1}\mathbf{v}_{1}$ +\end_inset + +, +\begin_inset Formula $\mathbf{T}\cdot\mathbf{v}_{2}=\lambda_{2}\mathbf{v}_{2}$ +\end_inset + +, +\begin_inset Formula $\lambda_{1}\ne\lambda_{2}$ +\end_inset + + , then +\begin_inset Formula $\mathbf{v}_{2}\cdot\mathbf{T}\cdot\mathbf{v}_{1}=\lambda_{1}\mathbf{v}_{1}\cdot\mathbf{v}_{2}$ +\end_inset + + and +\begin_inset Formula $\mathbf{v}_{1}\cdot\mathbf{T}\cdot\mathbf{v}_{2}=\lambda_{2}\mathbf{v}_{1}\cdot\mathbf{v}_{2}=\mathbf{v}_{2}\cdot\mathbf{T}^{T}\cdot\mathbf{v}_{1}=\mathbf{v}_{2}\cdot\mathbf{T}\cdot\mathbf{v}_{1}$ +\end_inset + + , +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +\Rightarrow\lambda_{1}\mathbf{v}_{1}\cdot\mathbf{v}_{2}=\lambda_{2}\mathbf{v}_{1}\cdot\mathbf{v}_{2}\quad\text{or}\quad\left(\lambda_{1}-\lambda_{2}\right)\mathbf{v}_{1}\cdot\mathbf{v}_{2}=0\quad\Rightarrow\mathbf{v}_{1}\cdot\mathbf{v}_{2}=0 +\] + +\end_inset + + +\end_layout + +\begin_layout Standard +When two of the eigenvalues are repeated (a double root of the characteristic + equation), the resulting eigenvectors are not necessarily orthogonal to + each other; however, they remain orthogonal to the third eigenvector. + This means that any vector lying in the plane normal to the third eigenvector + is an eigenvector corresponding to the double root. + Similarly, when all three eigenvalues are repeated (a triple root), any + vector becomes an eigenvector of +\begin_inset Formula $\mathbf{T}$ +\end_inset + +. + +\end_layout + +\begin_layout Example +In hydrostatics the stress tensor is +\begin_inset Formula $\mathbf{T}=-p\mathbf{I}$ +\end_inset + +, where +\begin_inset Formula $p$ +\end_inset + + is the hydrostatic pressure. + In this case, +\begin_inset Formula $-p$ +\end_inset + + is a triple root of the characteristic equation of +\begin_inset Formula $\mathbf{T}$ +\end_inset + +. + Any vector +\begin_inset Formula $\mathbf{v}$ +\end_inset + + satisfies +\begin_inset Formula $\mathbf{T}\cdot\mathbf{v}=-p\mathbf{v}$ +\end_inset + +, and is thus an eigenvector of +\begin_inset Formula $\mathbf{T}$ +\end_inset + +. +\end_layout + +\begin_layout Standard +In continuum mechanics the eigenvectors +\begin_inset Formula $\mathbf{v}$ +\end_inset + + of a tensor are generally normalized, +\begin_inset Formula +\[ +\mathbf{n}\equiv\frac{\mathbf{v}}{\left|\mathbf{v}\right|} +\] + +\end_inset + +Thus, we can always find a set of three orthonormal eigenvectors +\begin_inset Formula $\left\{ \mathbf{n}_{1},\mathbf{n}_{2},\mathbf{n}_{3}\right\} $ +\end_inset + + for any real symmetric tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + +, even when the eigenvalues are repeated. + Given a tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + + with eigenvalues +\begin_inset Formula $\lambda_{1},\lambda_{2},\lambda_{3}$ +\end_inset + + and eigenvectors +\begin_inset Formula $\mathbf{n}_{1},\mathbf{n}_{2},\mathbf{n}_{3}$ +\end_inset + +, the components of +\begin_inset Formula $\mathbf{T}$ +\end_inset + + in the orthonormal basis +\begin_inset Formula $\left\{ \mathbf{n}_{1},\mathbf{n}_{2},\mathbf{n}_{3}\right\} $ +\end_inset + + can be obtained from +\begin_inset Formula +\[ +T_{i1}=\mathbf{v}_{i}\cdot\mathbf{T}\cdot\mathbf{n}_{1}=\lambda_{1}\mathbf{n}_{i}\cdot\mathbf{n}_{1}=\lambda_{1}\delta_{i1}\quad T_{i2}=\lambda_{2}\delta_{i2}T_{i3}=\lambda_{3}\delta_{i3} +\] + +\end_inset + + Thus, +\begin_inset Formula +\[ +\left[\mathbf{T}\right]_{\mathbf{n}_{i}}=\left[\begin{array}{ccc} +\lambda_{1} & 0 & 0\\ +0 & \lambda_{2} & 0\\ +0 & 0 & \lambda_{3} +\end{array}\right]=\left[\begin{array}{ccc} +T_{1} & 0 & 0\\ +0 & T_{2} & 0\\ +0 & 0 & T_{3} +\end{array}\right] +\] + +\end_inset + + Since +\begin_inset Formula $\mathbf{T}=T_{ij}\mathbf{n}_{i}\otimes\mathbf{n}_{j}=T_{i1}\mathbf{n}_{i}\otimes\mathbf{n}_{1}+T_{i2}\mathbf{n}_{i}\otimes\mathbf{n}_{2}+T_{i3}\mathbf{n}_{i}\otimes\mathbf{n}_{3}$ +\end_inset + +, we find that +\begin_inset Formula +\begin{equation} +\mathbf{T}=\lambda_{1}\mathbf{n}_{1}\otimes\mathbf{n}_{1}+\lambda_{2}\mathbf{n}_{2}\otimes\mathbf{n}_{2}+\lambda_{3}\mathbf{n}_{3}\otimes\mathbf{n}_{3}\label{eq:eigen-spectral-rep} +\end{equation} + +\end_inset + + This is known as the +\shape italic +spectral representation +\shape default + of the tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + +. + In particular, since the eigenvalues of the identity tensor are +\begin_inset Formula $\lambda_{1}=\lambda_{2}=\lambda_{3}=1$ +\end_inset + +, and since any vector is an eigenvector of +\begin_inset Formula $\mathbf{I}$ +\end_inset + +, we can select the basis vectors +\begin_inset Formula $\mathbf{e}_{1},\,\mathbf{e}_{2},\,\mathbf{e}_{3}$ +\end_inset + + so that the spectral representation of +\begin_inset Formula $\mathbf{I}$ +\end_inset + + may be given by +\begin_inset Formula +\begin{equation} +\mathbf{I}=\mathbf{e}_{i}\otimes\mathbf{e}_{i}=\mathbf{e}_{1}\otimes\mathbf{e}_{1}+\mathbf{e}_{2}\otimes\mathbf{e}_{2}+\mathbf{e}_{3}\otimes\mathbf{e}_{3}\label{eq:eigen-identity-spectral} +\end{equation} + +\end_inset + + +\end_layout + +\begin_layout Subsection +Orthogonal Transformation of Tensors +\end_layout + +\begin_layout Standard +An orthogonal transformation +\begin_inset Formula $\mathbf{Q}$ +\end_inset + + transforms any vector +\begin_inset Formula $\mathbf{a}$ +\end_inset + + into the vector +\begin_inset Formula $\mathbf{Q}\cdot\mathbf{a}$ +\end_inset + +, which we may denote as +\begin_inset Formula +\begin{equation} +\mathbf{a}^{*}=\mathbf{Q}\cdot\mathbf{a}\label{eq:OT-vector} +\end{equation} + +\end_inset + +Recall that a tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + + may be expressed in its spectral representation as per eq. +\begin_inset CommandInset ref +LatexCommand eqref +reference "eq:eigen-spectral-rep" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. + Each of its eigenvectors +\begin_inset Formula $\mathbf{n}$ +\end_inset + + is transformed by +\begin_inset Formula $\mathbf{Q}$ +\end_inset + + into +\begin_inset Formula $\mathbf{n}^{*}=\mathbf{Q}\cdot\mathbf{n}$ +\end_inset + +. + Since eigenvalues of +\begin_inset Formula $\mathbf{T}$ +\end_inset + + are invariant to orthogonal transformations, it follows that +\begin_inset Formula +\[ +\begin{aligned}\mathbf{T}^{*} & =\lambda_{1}\mathbf{n}_{1}^{*}\otimes\mathbf{n}_{1}^{*}+\lambda_{2}\mathbf{n}_{2}^{*}\otimes\mathbf{n}_{2}^{*}+\lambda_{3}\mathbf{n}_{3}^{*}\otimes\mathbf{n}_{3}^{*}\\ + & =\lambda_{1}\left(\mathbf{Q}\cdot\mathbf{n}_{1}\right)\otimes\left(\mathbf{Q}\cdot\mathbf{n}_{1}\right)+\lambda_{2}\left(\mathbf{Q}\cdot\mathbf{n}_{2}\right)\otimes\left(\mathbf{Q}\cdot\mathbf{n}_{2}\right)+\lambda_{3}\left(\mathbf{Q}\cdot\mathbf{n}_{3}\right)\otimes\left(\mathbf{Q}\cdot\mathbf{n}_{3}\right)\\ + & =\mathbf{Q}\cdot\left(\lambda_{1}\mathbf{n}_{1}\otimes\mathbf{n}_{1}+\lambda_{2}\mathbf{n}_{2}\otimes\mathbf{n}_{2}+\lambda_{3}\mathbf{n}_{3}\otimes\mathbf{n}_{3}\right)\cdot\mathbf{Q}^{T}\\ + & =\mathbf{Q}\cdot\mathbf{T}\cdot\mathbf{Q}^{T} +\end{aligned} +\] + +\end_inset + +Thus, the transformation of the second-order tensor +\begin_inset Formula $\mathbf{T}$ +\end_inset + + by +\begin_inset Formula $\mathbf{Q}$ +\end_inset + + is +\begin_inset Formula $\mathbf{T}^{*}=\mathbf{Q}\cdot\mathbf{T}\cdot\mathbf{Q}^{T}$ +\end_inset + +. +\end_layout + +\begin_layout Section +Higher Order Tensors +\end_layout + +\begin_layout Standard +Note that +\begin_inset Formula $\mathbf{a}\cdot\mathbf{T}\cdot\mathbf{b}=\mathbf{a}\otimes\mathbf{b}:\mathbf{T}=\mathbf{T}:\mathbf{a}\otimes\mathbf{b}$ +\end_inset + +, and +\begin_inset Formula $\mathbf{a}\otimes\mathbf{b}:\mathbf{c}\otimes\mathbf{d}=\left(\mathbf{a}\cdot\mathbf{c}\right)\left(\mathbf{b}\cdot\mathbf{d}\right)$ +\end_inset + +. + Similarly, +\begin_inset Formula $\left(\mathbf{a}\otimes\mathbf{b}\right)\cdot\left(\mathbf{c}\otimes\mathbf{d}\right)=\left(\mathbf{b}\cdot\mathbf{c}\right)\mathbf{a}\otimes\mathbf{d}$ +\end_inset + +. + We will be using generalizations of these relations when examining higher + order tensors. +\end_layout + +\begin_layout Subsection +Third-Order Tensors +\end_layout + +\begin_layout Standard +A third-order tensor +\begin_inset Formula $\mathbb{T}$ +\end_inset + + is a linear transformation that transforms any vector +\begin_inset Formula $\mathbf{a}$ +\end_inset + + into a second-order tensor +\begin_inset Formula $\mathbf{S}$ +\end_inset + +, +\begin_inset Formula +\begin{equation} +\boxed{\mathbb{T}\cdot\mathbf{a}=\mathbf{S}}\label{eq62-1} +\end{equation} + +\end_inset + +In general, the dyadic product of three vectors is a third-order tensor + which satisfies +\begin_inset Formula +\begin{equation} +\boxed{\left(\mathbf{a}\otimes\mathbf{b}\otimes\mathbf{c}\right)\cdot\left(\alpha\mathbf{u}+\beta\mathbf{v}\right)=\left(\alpha\mathbf{c}\cdot\mathbf{u}+\beta\mathbf{c}\cdot\mathbf{v}\right)\left(\mathbf{a}\otimes\mathbf{b}\right)}\quad\forall\,\mathbf{u},\mathbf{v}\,.\label{eq62b} +\end{equation} + +\end_inset + +Any third-order tensor +\begin_inset Formula $\mathbb{T}$ +\end_inset + + can be expressed in terms of its Cartesian components +\begin_inset Formula $T_{ijk}$ +\end_inset + + as +\begin_inset Formula +\begin{equation} +\boxed{\mathbb{T}=T_{ijk}\mathbf{e}_{i}\otimes\mathbf{e}_{j}\otimes\mathbf{e}_{k}}\label{eq62d} +\end{equation} + +\end_inset + +and the Cartesian components of a third-order tensor may be evaluated from +\begin_inset Formula +\begin{equation} +\boxed{T_{ijk}=\mathbf{e}_{i}\cdot\left(\mathbb{T}\cdot\mathbf{e}_{k}\right)\cdot\mathbf{e}_{j}}\label{eq62c} +\end{equation} + +\end_inset + +It follows from Eqs. +\begin_inset CommandInset ref +LatexCommand eqref +reference "eq62b" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + and +\begin_inset CommandInset ref +LatexCommand eqref +reference "eq62d" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + that +\begin_inset Formula +\[ +\mathbb{T}\cdot\mathbf{a}=T_{ijk}\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\otimes\mathbf{e}_{k}\right)\cdot\mathbf{a}=T_{ijk}\left(\mathbf{e}_{k}\cdot\mathbf{a}\right)\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\right)=T_{ijk}a_{k}\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\right)=\mathbf{S}=S_{ij}\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\right) +\] + +\end_inset + +so that the indicial form of eq. +\begin_inset CommandInset ref +LatexCommand eqref +reference "eq62-1" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + is +\begin_inset Formula +\begin{equation} +T_{ijk}a_{k}=S_{ij}\label{eq62e} +\end{equation} + +\end_inset + +In particular, +\begin_inset Formula +\begin{equation} +\mathbb{T}\cdot\mathbf{e}_{k}=T_{ijk}\mathbf{e}_{i}\otimes\mathbf{e}_{j}\label{eq62f} +\end{equation} + +\end_inset + + +\end_layout + +\begin_layout Standard +The double dot product of a third-order tensor with a second-order tensor + is defined by +\begin_inset Formula +\[ +\boxed{\left(\mathbf{a}\otimes\mathbf{b}\otimes\mathbf{c}\right):\left(\mathbf{d}\otimes\mathbf{e}\right)=\left(\mathbf{b}\cdot\mathbf{d}\right)\left(\mathbf{c}\cdot\mathbf{e}\right)\mathbf{a}}\,, +\] + +\end_inset + +and +\begin_inset Formula +\[ +\boxed{\left(\mathbf{a}\otimes\mathbf{b}\right):\left(\mathbf{c}\otimes\mathbf{d}\otimes\mathbf{e}\right)=\left(\mathbf{a}\cdot\mathbf{c}\right)\left(\mathbf{b}\cdot\mathbf{d}\right)\mathbf{e}}\,. +\] + +\end_inset + +Therefore, the double dot product of a third-order tensor with a second-order + tensor is a vector given by +\begin_inset Formula +\begin{equation} +\mathbb{T}:\left(\mathbf{a}\otimes\mathbf{b}\right)=\left(\mathbb{T}\cdot\mathbf{b}\right)\cdot\mathbf{a}\,.\label{eq63f} +\end{equation} + +\end_inset + +Proof: Using +\begin_inset Formula $\mathbb{T}\cdot\mathbf{b}=T_{ijk}b_{k}\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\right)$ +\end_inset + +, we find that +\begin_inset Formula $\left(\mathbb{T}\cdot\mathbf{b}\right)\cdot\mathbf{a}=T_{ijk}b_{k}\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\right)\cdot\mathbf{a}=T_{ijk}b_{k}\left(\mathbf{a}\cdot\mathbf{e}_{j}\right)\mathbf{e}_{i}=T_{ijk}a_{j}b_{k}\mathbf{e}_{i}$ +\end_inset + +. + Similarly, +\begin_inset Formula $\mathbb{T}:\left(\mathbf{a}\otimes\mathbf{b}\right)=T_{ijk}\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\otimes\mathbf{e}_{k}\right):\left(\mathbf{a}\otimes\mathbf{b}\right)=T_{ijk}\left(\mathbf{e}_{j}\cdot\mathbf{a}\right)\left(\mathbf{e}_{k}\cdot\mathbf{b}\right)\mathbf{e}_{i}=T_{ijk}a_{j}b_{k}\mathbf{e}_{i}$ +\end_inset + +, thus completing the proof. + +\end_layout + +\begin_layout Standard +For any second-order tensor +\begin_inset Formula $\mathbf{S}$ +\end_inset + +, it also follows that +\begin_inset Formula +\[ +\mathbb{T}:\mathbf{S}=T_{ijk}S_{jk}\mathbf{e}_{i}\,. +\] + +\end_inset + + +\end_layout + +\begin_layout Example +If we introduce the notation +\begin_inset Formula $\mathbb{E}$ +\end_inset + + as the third-order (pseudo-)tensor of Cartesian components +\begin_inset Formula $\varepsilon_{ijk}$ +\end_inset + +, the relation between an antisymmetric tensor and its dual vector can also + be written as +\begin_inset Formula +\begin{equation} +\boxed{\boldsymbol{\Omega}=-\mathbb{E}\cdot\boldsymbol{\omega}}\label{eq26b} +\end{equation} + +\end_inset + +Similarly, +\begin_inset Formula +\begin{equation} +\boxed{\boldsymbol{\omega}=-\frac{1}{2}\mathbb{E}:\boldsymbol{\Omega}}\label{eq27b} +\end{equation} + +\end_inset + + +\end_layout + +\begin_layout Subsection +Fourth-Order Tensors +\begin_inset CommandInset label +LatexCommand label +name "subsec:Fourth-Order-Tensors" + +\end_inset + + +\end_layout + +\begin_layout Standard +The dyadic product of four vectors is a fourth-order tensor +\begin_inset Formula $\mathbf{a}\otimes\mathbf{b}\otimes\mathbf{c}\otimes\mathbf{d}$ +\end_inset + +, defined as +\begin_inset Formula +\begin{equation} +\left(\mathbf{a}\otimes\mathbf{b}\otimes\mathbf{c}\otimes\mathbf{d}\right)\cdot\mathbf{v}=\left(\mathbf{d}\cdot\mathbf{v}\right)\left(\mathbf{a}\otimes\mathbf{b}\otimes\mathbf{c}\right)\label{eq:63g} +\end{equation} + +\end_inset + +The Cartesian components of a fourth-order tensor +\begin_inset Formula $\mathcal{T}$ +\end_inset + + are given by +\begin_inset Formula +\begin{equation} +T_{ijkl}=\left(\mathbf{e}_{i}\otimes\mathbf{e}_{j}\right):\mathcal{T}:\left(\mathbf{e}_{k}\otimes\mathbf{e}_{l}\right)\label{eq:63h} +\end{equation} + +\end_inset + +such that +\begin_inset Formula +\begin{equation} +\mathcal{T}=T_{ijkl}\mathbf{e}_{i}\otimes\mathbf{e}_{j}\otimes\mathbf{e}_{k}\otimes\mathbf{e}_{l}\label{eq:63i} +\end{equation} + +\end_inset + +Therefore, a fourth-order tensor transforms a vector into a third-order + tensor, +\begin_inset Formula +\begin{equation} +\mathcal{T}\cdot\mathbf{a}=\left(T_{ijkl}\mathbf{e}_{i}\otimes\mathbf{e}_{j}\otimes\mathbf{e}_{k}\otimes\mathbf{e}_{l}\right)\cdot\mathbf{a}=T_{ijkl}a_{l}\mathbf{e}_{i}\otimes\mathbf{e}_{j}\otimes\mathbf{e}_{k}\equiv S_{ijk}\mathbf{e}_{i}\otimes\mathbf{e}_{j}\otimes\mathbf{e}_{k}=\mathbb{S}\label{eq:63j} +\end{equation} + +\end_inset + +The double dot product of a fourth-order tensor with a second-order tensor + is a second-order tensor defined as +\begin_inset Formula +\begin{equation} +\boxed{\mathcal{T}:\left(\mathbf{a}\otimes\mathbf{b}\right)=\left(\mathcal{T}\cdot\mathbf{b}\right)\cdot\mathbf{a}}\label{eq:63k} +\end{equation} + +\end_inset + +from which it can be shown that +\begin_inset Formula +\begin{equation} +\mathcal{T}:\mathbf{S}=T_{ijmn}S_{mn}\mathbf{e}_{i}\otimes\mathbf{e}_{j}\label{eq:63l} +\end{equation} + +\end_inset + +or equivalently, +\begin_inset Formula $\left(\mathcal{T}:\mathbf{S}\right)_{ij}=T_{ijkl}S_{kl}$ +\end_inset + +. +\end_layout + +\begin_layout Standard +A fourth-order tensor can exhibit three levels of symmetry, which can be + represented using Cartesian components as +\begin_inset Formula +\begin{equation} +\begin{aligned}T_{ijkl} & =T_{jikl} & \text{left minor symmetry}\\ +T_{ijkl} & =T_{ijlk} & \text{right minor symmetry}\\ +T_{ijkl} & =T_{klij} & \text{major symmetry} +\end{aligned} +\label{eq:tens4-symmetries} +\end{equation} + +\end_inset + +Whereas a general fourth-order tensor may have 81 distinct components, a + tensor with one minor symmetry has 54 distinct components; a tensor with + both minor symmetries has 36 distinct components; and a tensor with minor + and major symmetries has 21distinct components. + We may represent the major symmetry of +\begin_inset Formula $\mathcal{T}$ +\end_inset + + as +\begin_inset Formula $\mathcal{T}=\mathcal{T}^{T}$ +\end_inset + +, whose Cartesian representation is provided above. + It follows from this definition that +\begin_inset Formula +\[ +\begin{aligned}\mathbf{S}:\mathcal{T} & =\mathcal{T}^{T}:\mathbf{S}\\ +\left(\mathbf{S}:\mathcal{T}\right)_{ij} & =S_{kl}T_{klij}=T_{ijkl}^{T}S_{kl} +\end{aligned} +\] + +\end_inset + + +\end_layout + +\begin_layout Subsection +Additional Tensor Products +\end_layout + +\begin_layout Standard +Earlier we saw that the dyadic product of vectors can produce tensors. + Similarly, we can define dyadic products of tensors which produce higher-order + tensors. + In particular, the following products of second-order tensors +\begin_inset Formula $\mathbf{A}$ +\end_inset + + and +\begin_inset Formula $\mathbf{B}$ +\end_inset + + produce fouth-order tensors, satisfying +\begin_inset Formula +\begin{equation} +\begin{aligned}\left(\mathbf{A}\otimes\mathbf{B}\right):\mathbf{S} & =\left(\mathbf{B}:\mathbf{S}\right)\mathbf{A}\\ +\left(\mathbf{A}\oslash\mathbf{B}\right):\mathbf{S} & =\mathbf{A}\cdot\mathbf{S}\cdot\mathbf{B}^{T}\\ +\left(\mathbf{A}\obslash\mathbf{B}\right):\mathbf{S} & =\mathbf{A}\cdot\mathbf{S}^{T}\cdot\mathbf{B}^{T}\\ +\left(\mathbf{A}\odot\mathbf{B}\right):\mathbf{S} & =\frac{1}{2}\left(\mathbf{A}\oslash\mathbf{B}+\mathbf{A}\obslash\mathbf{B}\right):\mathbf{S}=\frac{1}{2}\left(\mathbf{A}\cdot\mathbf{S}\cdot\mathbf{B}^{T}+\mathbf{A}\cdot\mathbf{S}^{T}\cdot\mathbf{B}^{T}\right) +\end{aligned} +\label{eq:tensor-products} +\end{equation} + +\end_inset + +where +\begin_inset Formula $\mathbf{S}$ +\end_inset + + is any second-order tensor. + Using Cartesian components of tensors, the indicial form of these tensor + products are +\begin_inset Formula +\begin{equation} +\begin{aligned}\left(\mathbf{A}\otimes\mathbf{B}\right)_{ijkl} & =A_{ij}B_{kl}\\ +\left(\mathbf{A}\oslash\mathbf{B}\right)_{ijkl} & =A_{ik}B_{jl}\\ +\left(\mathbf{A}\obslash\mathbf{B}\right)_{ijkl} & =A_{il}B_{jk}\\ +\left(\mathbf{A}\odot\mathbf{B}\right)_{ijkl} & =\frac{1}{2}\left(A_{ik}B_{jl}+A_{il}B_{jk}\right) +\end{aligned} +\label{eq:tensor-products-Cartesian} +\end{equation} + +\end_inset + + +\end_layout + \begin_layout Standard \begin_inset CommandInset bibtex LatexCommand bibtex diff --git a/Documentation/FEBio_Theory_Manual.pdf b/Documentation/FEBio_Theory_Manual.pdf index d092a9fbe..4d9055c81 100644 Binary files a/Documentation/FEBio_Theory_Manual.pdf and b/Documentation/FEBio_Theory_Manual.pdf differ diff --git a/Documentation/FEBio_User_Manual.lyx b/Documentation/FEBio_User_Manual.lyx index 1585047b9..f4e2a5fe1 100644 --- a/Documentation/FEBio_User_Manual.lyx +++ b/Documentation/FEBio_User_Manual.lyx @@ -6,13 +6,6 @@ \origin unavailable \textclass extbook \begin_preamble -% Converted from Microsoft Word to LaTeX -% by Chikrii Softlab Word2TeX converter (version 5.0) -% Copyright (C) 1999-2011 Chikrii Softlab. All rights reserved. -% http://www.chikrii.com -% mailto: support@chikrii.com -% License: CSL#005010 - \usepackage{latexsym} \hypersetup{colorlinks=true,citecolor=blue,filecolor=blue,urlcolor=blue,linkcolor=blue} \end_preamble @@ -169,13 +162,13 @@ status open \end_inset -User's Manual Version 3.6 +User's Manual Version 3.7 \end_layout \begin_layout Date \series bold -Last Updated: February 17, 2022 +Last Updated: June 14, 2022 \end_layout \begin_layout Standard @@ -4059,8 +4052,12 @@ With the optional arguments, the complete syntax would be: \begin_layout Standard The dump level can set to 1 (= write dump file after each converged time - step), or 2 (= write dump file after each completed step). - + step), 2 (= write dump file after each completed step), or 3 (= write + dump file after each converged +\shape italic + must-point +\shape default + ). \end_layout \begin_layout Standard @@ -7914,7 +7911,7 @@ element sets the parameters that control the FEBio auto-time stepper. \begin_inset Tabular - + @@ -8072,7 +8069,7 @@ Maximum number of times a time step is restarted. - + \begin_inset Text \begin_layout Plain Layout @@ -8081,22 +8078,51 @@ aggressiveness \end_inset - + \begin_inset Text \begin_layout Plain Layout -Algorithm for cutting the time step size after a failed time step +Algorithm for cutting the time step size after a failed time step (4) \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout 0 \end_layout +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +cutback +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Time step scale factor, used when aggressiveness = 1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +0.5 +\end_layout + \end_inset @@ -8271,6 +8297,62 @@ parameter is set to PLOT_MUST_POINTS, then only the three defined time points will be stored to the plotfile. \end_layout +\end_deeper +\begin_layout Enumerate +When FEBio fails to converge a time step, the time step size is reduced + and then FEBio tries to solve the time step again. + The algorithm for determining the reduced time step size, depends on the + +\emph on +aggressiveness +\emph default +parameter. + +\end_layout + +\begin_deeper +\begin_layout Enumerate + +\emph on +aggressiveness = 0 +\emph default + (default): +\begin_inset Formula $\Delta t_{k+1}=\Delta t_{k}-(\Delta t_{k}/m_{r})$ +\end_inset + +, where +\begin_inset Formula $m_{r}$ +\end_inset + +is the max numer of retries (set by the +\emph on +max_retries +\emph default +parameter). +\end_layout + +\begin_layout Enumerate + +\emph on +aggressiveness = 1: +\emph default + +\begin_inset Formula $\Delta t_{k+1}=\gamma\Delta t_{k}$ +\end_inset + +, where +\begin_inset Formula $\gamma$ +\end_inset + + is the cutback factor (i.e. + the +\emph on +cutback +\emph default +parameter). + +\end_layout + \end_deeper \begin_layout Subsection Common Solver Parameters @@ -19791,6 +19873,221 @@ lc attribute is omitted a constant traction load is applied. \end_layout +\begin_layout Subsubsection +Surface Force +\begin_inset CommandInset label +LatexCommand label +name "subsec:Surface-Force" + +\end_inset + + +\end_layout + +\begin_layout Standard +A surface force applies an equivalent uniform traction load to a surface. + The direction of the force remains unchanged as the mesh deforms. +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1.0 +\end_layout + +\begin_layout LyX-Code + 0,0,1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +The force vector is determined by two quantities. + The direction and magnitude is defined by the +\shape italic +force +\shape default +element. + In addition, the magnitude can be scaled using the +\shape italic +scale +\shape default +element. + An optional load curve can be defined for the +\shape italic +scale +\shape default +element using the +\shape italic +lc +\shape default +attribute. + This allows the surface force to become time dependent. + If the +\shape italic +lc +\shape default +attribute is omitted a constant force is applied. +\end_layout + +\begin_layout Subsubsection +Bearing Load +\begin_inset CommandInset label +LatexCommand label +name "subsec:Bearing-Load" + +\end_inset + + +\end_layout + +\begin_layout Standard +A bearing load can be applied on a cylindrical surface that represents a + journal bearing. + This load gets prescribed as a non-uniform compressive pressure distribution + on that surface, representing the radial component of the bearing load. + (The axial component of a bearing load may be prescribed using the surface + force presented in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Surface-Force" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +.) The non-uniform pressure distribution may be sinusoidal or parabolic. + It gets distributed over a ±90 degree arc relative to the loading direction, + which is specified as a force vector. + The user is expected to specify the bearing force in a plane perpendicular + to the axis of the cylindrical bearing surface. + Otherwise, only the projection of the bearing force onto that plane will + be prescribed as the radial bearing load. + For example, a bearing load may be specified as +\end_layout + +\begin_layout Standard + +\end_layout + +\begin_layout LyX-Code + 1000.0 +\end_layout + +\begin_layout LyX-Code + 0.707107,0.707107,0 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +In this example the bearing load is in the xy-plane, oriented at 45 degrees + from the x-axis. + The surface +\emph on +BearingSurface1 +\emph default + should be a cylinder with its axis along the z-direction. + The pressure distribution is parabolic (profile=1), and the alternative + option is sinusoidal (profile=0). + In general, a parabolic distribution produces a higher (often more realistic) + central peak pressure on the bearing surface. + An optional loadcurve can be associated with the +\emph on +scale +\emph default + as shown in this example, to scale the prescribed bearing force as a function + of time. + Alternatively, the user may assign a loadcurve to the +\emph on +force +\emph default +. + +\end_layout + +\begin_layout Standard +Additional options are available for a bearing load, including +\emph on +symmetric_stiffness +\emph default +, +\emph on +linear +\emph default + and +\emph on +shell_bottom +\emph default + as outlined in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Pressure-Load" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. + When the +\emph on +linear +\emph default + flag is set to false, the pressure prescribed on the bearing surface is + adjusted to account for the change in area and orientation of each face, + caused by the finite deformation of the bearing surface. + However, the bearing radial force direction remains unchanged with deformation. + It is recommended to set the +\emph on +symmetric_stiffness +\emph default + flag to false when performing a finite deformation analysis. +\end_layout + +\begin_layout Standard +The bearing load is always prescribed as a compressive load on the selected + bearing surface. + Therefore, it is recommended to select a complete cylindrical surface on + which the bearing load is prescribed; the solver automatically determines + which faces of the selected surface must be loaded in compression and which + of those have zero pressure prescribed on them, based on the vectorial + orientation of the bearing +\emph on +force +\emph default +. + If the user selects a semi-cylindrical surface as the bearing surface, + it becomes the user's responsibility to ensure that the prescribed bearing + force bisects the 180 degree arc of that surface. + Otherwise, the analysis may produce unexpected results, due to unevenness + of the pressure distribution about the force's line of action. + If the user selects a surface with a smaller arc than ±90 degrees, the + pressure will not reduce to zero at the straight edges of the surface, + though the pressure will be scaled to produce the prescribed force magnitude + along the bearing force direction. + +\end_layout + \begin_layout Subsubsection Mixture Normal Traction \begin_inset CommandInset label @@ -20495,6 +20792,98 @@ type area in current configuration. \end_layout +\begin_layout Subsubsection +Solute Natural Flux +\begin_inset CommandInset label +LatexCommand label +name "subsec:Solute-Natural-Flux" + +\end_inset + + +\end_layout + +\begin_layout Standard +This surface load can be prescribed on a boundary where a natural solute + flux is desired. + On this boundary, the solute is convected with the solvent according to + +\begin_inset Formula $j_{n}=cw_{n}$ +\end_inset + +. + The implication of this surface load is that there is no diffusive hindrance + to solute transport on the external side of the boundary. + Here, +\begin_inset Formula $c$ +\end_inset + + is the average solute concentration and +\begin_inset Formula $\mathbf{w}$ +\end_inset + + is the average solvent volumetric flux in the finite element connected + to the boundary face on which this surface load is prescribed. + The normal solvent flux +\begin_inset Formula $w_{n}$ +\end_inset + + is evaluated as +\begin_inset Formula $\mathbf{w}\cdot\mathbf{n}$ +\end_inset + + using the normal +\begin_inset Formula $\mathbf{n}$ +\end_inset + + on the boundary. + There are no user-specified parameters in this surface load (other than + specifying the solute for which it applies, and whether the boundary is + the bottom of a shell domain). + To prescribe a solute natural flux on a surface, use: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +The optional parameter +\shape italic +solute_id +\shape default + specifies to which solute this flux condition applies, referencing the + corresponding list in the Globals section (Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solutes" + +\end_inset + +). + If +\shape italic +solute_id +\shape default + is not defined, the default value is 1. +\end_layout + \begin_layout Subsubsection Heat Flux \begin_inset CommandInset label @@ -27962,6 +28351,140 @@ maxaug . \end_layout +\begin_layout Subsection +Fixed Normal Displacement +\begin_inset CommandInset label +LatexCommand label +name "subsec:Fixed-Normal-Displacement" + +\end_inset + + +\end_layout + +\begin_layout Standard +A fixed normal displacement constraint enforces zero solid displacement + normal to a user-selected surface. + This constraint is prescribed on a deformable surface of the model and + is enforced for every node on that surface. + It uses the local surface normal in the selected surface's reference configurat +ion. + If the selected surface is planar, the functionality of this constraint + is equivalent to the Symmetry Plane constraint described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Symmetry-Plane" +plural "false" +caps "false" +noprefix "false" + +\end_inset + +. +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + 1000 +\end_layout + +\begin_layout LyX-Code + 0.2 +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + 10 +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +The +\emph on +surface +\emph default + (FixedNormalDisplacement01 in this example), is defined in the +\emph on +Mesh +\emph default + section. + Let +\begin_inset Formula $\mathbf{u}$ +\end_inset + + denote the nodal displacement vector and let +\begin_inset Formula $\mathbf{n}$ +\end_inset + + denote the unit normal at each node of the surface; the fixed normal displaceme +nt constraint enforces +\begin_inset Formula $u_{n}\equiv\mathbf{u}\cdot\mathbf{n}=0$ +\end_inset + + using a penalty method, optionally with augmented Lagrangian. + The reaction force needed to enforce this constraint is evaluated as +\begin_inset Formula $\varepsilon u_{n}$ +\end_inset + +, where +\begin_inset Formula $\varepsilon$ +\end_inset + + is the user-specified +\emph on +penalty +\emph default + parameter (with units of force per length). + To use the augmented Lagrangian method, set +\emph on +laugon +\emph default + to 1, and the Lagrange multiplier +\begin_inset Formula $\lambda$ +\end_inset + + will be augmented as +\begin_inset Formula $\lambda\leftarrow\lambda+\varepsilon u_{n}$ +\end_inset + +. + Augmentations terminate when the relative change in +\begin_inset Formula $\lambda$ +\end_inset + + is less than the user-specified tolerance +\emph on +tol +\emph default +, or when the number of augmentations exceeds +\emph on +maxaug +\emph default +. +\end_layout + \begin_layout Subsection Normal Fluid Velocity Constraint \begin_inset CommandInset label @@ -35938,7 +36461,7 @@ An asterisk (*) in the Category column denotes that the attribute is required \begin_inset Tabular - + @@ -39619,6 +40142,36 @@ Fraction of weak bonds available to break and reform in reactive viscoelastic \begin_inset Text +\begin_layout Plain Layout +RVE strain +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Element +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Strain measure used in strain-dependent reactive viscoelastic relaxation + and weak bond recruitment +\end_layout + +\end_inset + + + + +\begin_inset Text + \begin_layout Plain Layout sbm concentration \end_layout @@ -46186,7 +46739,7 @@ trans iso Mooney-Rivlin \begin_inset Tabular - + @@ -46415,7 +46968,7 @@ Fiber stretch for straightened fibers - + \begin_inset Text \begin_layout Plain Layout @@ -46424,7 +46977,7 @@ Fiber stretch for straightened fibers \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -46433,7 +46986,36 @@ Fiber distribution option \end_inset - + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Optional active contraction +\end_layout + +\end_inset + + \begin_inset Text \begin_layout Plain Layout @@ -46614,177 +47196,22 @@ reference "subsec:Specifying-Fiber-Orientation" \end_inset . - Active stress along the fiber direction can be simulated using an active - contraction model. - To use this feature you need to define the -\shape italic -active_contraction -\shape default -material. - This material has a -\emph on -ascl -\emph default - property that takes an optional attribute, -\shape italic -lc -\shape default -, which defines the loadcurve. - There are also several options: -\end_layout - -\begin_layout Standard -\align center -\begin_inset Tabular - - - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Activation scale factor (default=0) -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Intracellular calcium concentration (default=1) -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Maximum peak intracellular calcium concentration (default=ca0) -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -tension-sarcomere length relation constant -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -No tension sarcomere length -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Unloaded sarcomere length -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - + An optional active contraction model can also be defined for this material. + See Section +\begin_inset space ~ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Isometric tension under maximal activation at camax (default=1) -\end_layout -\end_inset - - - +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Fiber-Active-Contraction" +plural "false" +caps "false" +noprefix "false" \end_inset - + for more details. \end_layout \begin_layout Standard @@ -46836,34 +47263,6 @@ This example defines a transversely isotropic material with a Mooney-Rivlin 1,0,0 \end_layout -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1 -\end_layout - -\begin_layout LyX-Code - 4.35 -\end_layout - -\begin_layout LyX-Code - 4.75 -\end_layout - -\begin_layout LyX-Code - 1.58 -\end_layout - -\begin_layout LyX-Code - 2.04 -\end_layout - -\begin_layout LyX-Code - -\end_layout - \begin_layout LyX-Code \end_layout @@ -46919,7 +47318,7 @@ literal "true" \begin_inset Tabular - + @@ -47144,7 +47543,7 @@ Fiber stretch for straightened fibers - + \begin_inset Text \begin_layout Plain Layout @@ -47153,7 +47552,7 @@ Fiber stretch for straightened fibers \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -47162,7 +47561,36 @@ Fiber distribution option. \end_inset - + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Optional active contraction +\end_layout + +\end_inset + + \begin_inset Text \begin_layout Plain Layout @@ -47211,19 +47639,22 @@ reference "subsec:Specifying-Fiber-Orientation" \end_inset . - An active contraction model can also be defined for this material. - See the transversely isotropic Mooney-Rivlin model for more details (Section + An optional active contraction model can also be defined for this material. + See Section \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Transversely-Isotropic-Mooney-Rivlin" +reference "subsec:Fiber-Active-Contraction" +plural "false" +caps "false" +noprefix "false" \end_inset -). + for more details. \end_layout \begin_layout Standard @@ -48688,7 +49119,7 @@ This example defines a thin soft tissue material where fibers are distributed \end_layout \begin_layout Subsubsection -Kamensky uncoupled +isotropic Lee-Sacks uncoupled \begin_inset CommandInset label LatexCommand label name "subsec:Kamensky-uncoupled" @@ -48703,7 +49134,11 @@ This material implements a Fung-type material, as presented in Kamensy, CMAME 2018. The material formulation is selected by setting the type attribute to " \family typewriter -Kamensky uncoupled +uncoupled +\family default + +\family typewriter +isotropic Lee-Sacks \family default ". It defines the following parameters: @@ -48933,7 +49368,15 @@ Example: \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code @@ -48964,10 +49407,10 @@ Example: \end_layout \begin_layout Subsection -Unconstrained Materials +Fiber Active Contraction \begin_inset CommandInset label LatexCommand label -name "subsec:Unconstrained-Materials" +name "subsec:Fiber-Active-Contraction" \end_inset @@ -48975,7 +49418,7 @@ name "subsec:Unconstrained-Materials" \end_layout \begin_layout Standard -Unlike the materials in Section +Some of the material models described in Section \begin_inset space ~ \end_inset @@ -48983,22 +49426,22 @@ Unlike the materials in Section \begin_inset CommandInset ref LatexCommand ref reference "subsec:Uncoupled-Materials" +plural "false" +caps "false" +noprefix "false" \end_inset -, these materials do not necessarily assume an additive decomposition of - the bulk and deviatoric parts of the strain energy or stress. - Further, these materials can only be used with the standard displacement-based - finite element formulation, rather than the three-field element formulatoin. - They should not be used for nearly-incompressible material behavior due - to the potential for element locking. + which include a fiber model may provide the option to specify an active + contraction along that fiber. + This section lists the types of fiber active contraction models. \end_layout \begin_layout Subsubsection -Carter-Hayes +Active Contraction \begin_inset CommandInset label LatexCommand label -name "subsec:Carter-Hayes" +name "subsec:Active-Contraction" \end_inset @@ -49006,32 +49449,102 @@ name "subsec:Carter-Hayes" \end_layout \begin_layout Standard -The material type for a Carter-Hayes material is -\shape italic -Carter-Hayes -\shape default +The default active contraction model is +\begin_inset Quotes eld +\end_inset + + +\emph on +active_contraction +\emph default + +\begin_inset Quotes erd +\end_inset + . - The following parameters must be defined: + It is based on the formulation of Guccione et al. + +\begin_inset CommandInset citation +LatexCommand citep +key "Guccione93" +literal "false" + +\end_inset + + and reviewed in the +\begin_inset ERT +status open + +\begin_layout Plain Layout + + +\backslash +href{https://febio.org/knowledgebase/}{ +\backslash +emph{FEBio Theory Manual}} \end_layout -\begin_layout Standard -\align center -\begin_inset VSpace defskip \end_inset +. + The active stress is evaluated as +\begin_inset Formula $T^{a}\mathbf{a}\otimes\mathbf{a}$ +\end_inset + +, where +\begin_inset Formula $\mathbf{a}$ +\end_inset + + is the unit vector along the fiber in the current configuration, and +\begin_inset Formula +\[ +T^{a}=T_{\max}\frac{Ca_{0}^{2}}{Ca_{0}^{2}+ECa_{50}^{2}}C\left(t\right) +\] + +\end_inset + +where +\begin_inset Formula +\[ +ECa_{50}=\frac{\left(\text{Ca}_{0}\right)_{\max}}{\sqrt{\exp\left[\beta\left(\lambda\left(t\right)l_{r}-l_{0}\right)\right]-1}} +\] + +\end_inset + +In this expression, +\begin_inset Formula $\lambda\left(t\right)$ +\end_inset + + is the fiber stretch ratio at the current time. + The activation curve +\begin_inset Formula $C\left(t\right)$ +\end_inset + + is represented by the +\emph on +ascl +\emph default + property that takes an optional attribute, +\shape italic +lc +\shape default +, which defines the loadcurve. + The list of parameters required for this model is as follows. +\end_layout +\begin_layout Standard +\align center \begin_inset Tabular - + - \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -49040,69 +49553,59 @@ Carter-Hayes \begin_inset Text \begin_layout Plain Layout -Young's modulus at reference density -\begin_inset Formula $E_{0}$ +Activation scale factor +\begin_inset Formula $C\left(t\right)$ \end_inset - + \end_layout \end_inset - + + + \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] + \end_layout \end_inset - - - + \begin_inset Text \begin_layout Plain Layout - +Intracellular calcium concentration +\begin_inset Formula $Ca_{0}$ +\end_inset + + (default=1) \end_layout \end_inset - + + + \begin_inset Text \begin_layout Plain Layout -reference density -\begin_inset Formula $\rho_{0}$ -\end_inset - - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ -\series bold -M -\series default -/ -\series bold -L -\series default - -\begin_inset Formula $^{\mathrm{3}}$ +Maximum peak intracellular calcium concentration +\begin_inset Formula $\left(\text{Ca}_{0}\right)_{\max}$ \end_inset -] + (default=ca0) \end_layout \end_inset @@ -49113,7 +49616,7 @@ L \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -49122,21 +49625,11 @@ L \begin_inset Text \begin_layout Plain Layout -exponent of solid-bound molecule density for calculation of Young's modulus - -\begin_inset Formula $\gamma$ +tension-sarcomere length relation constant +\begin_inset Formula $\beta$ \end_inset - -\end_layout - -\end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ ] \end_layout \end_inset @@ -49147,7 +49640,7 @@ exponent of solid-bound molecule density for calculation of Young's modulus \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -49156,169 +49649,69 @@ exponent of solid-bound molecule density for calculation of Young's modulus \begin_inset Text \begin_layout Plain Layout -Poisson's ratio -\begin_inset Formula $\nu$ +No tension sarcomere length +\begin_inset Formula $l_{0}$ \end_inset - -\end_layout - -\end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ ] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -index of solid bound molecule -\end_layout - +Unloaded sarcomere length +\begin_inset Formula $l_{r}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ ] + \end_layout \end_inset - - -\end_inset - - -\begin_inset VSpace defskip -\end_inset - + + +\begin_inset Text +\begin_layout Plain Layout + \end_layout -\begin_layout Standard -This model describes an unconstrained neo-Hookean material -\begin_inset CommandInset citation -LatexCommand citep -key "Bonet97" -literal "true" - -\end_inset - - whose Young's modulus is a power-law function of the referential apparent - density -\begin_inset Formula $\rho_{r}^{\sigma}$ -\end_inset - - of a solid-bound molecule. - It is derived from the following hyperelastic strain-energy function: -\begin_inset Formula -\[ -\Psi_{r}=\frac{E_{Y}}{2\left(1+\nu\right)}\left[\frac{1}{2}\left(\tr\mathbf{C}-3\right)-\ln J+\frac{\nu}{1-2\nu}\left(\ln J\right)^{2}\right]. -\] - -\end_inset - -Here, -\begin_inset Formula $\mathbf{C}$ \end_inset + + +\begin_inset Text - is the right Cauchy-Green deformation tensor and -\begin_inset Formula $J$ +\begin_layout Plain Layout +Isometric tension under maximal activation at camax +\begin_inset Formula $T_{\max}$ \end_inset - is the determinant of the deformation gradient tensor. + (default=1) \end_layout -\begin_layout Standard -Young's modulus depends on -\begin_inset Formula $\rho_{r}^{\sigma}$ -\end_inset - - according to a power law -\begin_inset CommandInset citation -LatexCommand citep -key "Carter76,Carter77" -literal "true" - -\end_inset - -, -\begin_inset Formula -\[ -E_{Y}=E_{0}\left(\frac{\rho_{r}^{\sigma}}{\rho_{0}}\right)^{\gamma}\,. -\] - -\end_inset - -This type of material references a solid-bound molecule that belongs to - a multiphasic mixture. - Therefore this material may only be used as the solid (or a component of - the solid) in a multiphasic mixture (Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "sec:Triphasic-Multiphasic-Materials" - -\end_inset - -). - The solid-bound molecule must be defined in the section (Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Solid-Bound-Molecules" - -\end_inset - -) and must be included in the multiphasic mixture using a - tag. - The parameter -\shape italic -sbm -\shape default - must refer to the global index of that solid-bound molecule. - The value of -\begin_inset Formula $\rho_{r}^{\sigma}$ \end_inset + + + - is specified within the tag. - If a chemical reaction is defined within that multiphasic mixture that - alters the value of -\begin_inset Formula $\rho_{r}^{\sigma}$ \end_inset -, lower and upper bounds may be specified for this referential density within - the tag to prevent -\begin_inset Formula $E_{Y}$ -\end_inset - from reducing to zero or achieving excessively elevated values. \end_layout \begin_layout Standard @@ -49327,187 +49720,259 @@ sbm Example: \end_layout -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1 +\begin_layout Standard +This example defines a transversely isotropic material with a Mooney-Rivlin + basis. + It defines a homogeneous fiber direction and uses the active fiber contraction + feature. \end_layout \begin_layout LyX-Code - 0.1 + \end_layout \begin_layout LyX-Code - 5 + 13.85 \end_layout \begin_layout LyX-Code - + 0.0 \end_layout \begin_layout LyX-Code - 0 + 2.07 \end_layout \begin_layout LyX-Code - + 61.44 \end_layout \begin_layout LyX-Code - 1 + 640.7 \end_layout \begin_layout LyX-Code - 10000 + 100.0 \end_layout \begin_layout LyX-Code - 1 + 1.03 \end_layout \begin_layout LyX-Code - 2.0 + 1,0,0 \end_layout \begin_layout LyX-Code - 0 + \end_layout \begin_layout LyX-Code - + 1 \end_layout \begin_layout LyX-Code - + 4.35 \end_layout \begin_layout LyX-Code - 1 + 4.75 \end_layout \begin_layout LyX-Code - + 1.58 \end_layout \begin_layout LyX-Code - + 2.04 \end_layout \begin_layout LyX-Code - 1 + \end_layout \begin_layout LyX-Code - + \end_layout -\begin_layout LyX-Code - -\end_layout +\begin_layout Subsubsection +Force-Velocity Active Contraction +\begin_inset CommandInset label +LatexCommand label +name "subsec:Force-Velocity-Active-Contractio" -\begin_layout LyX-Code - 0 -\end_layout +\end_inset -\begin_layout LyX-Code - 1 -\end_layout -\begin_layout LyX-Code - \end_layout -\begin_layout LyX-Code - 1 -\end_layout +\begin_layout Standard +This material model was formulated by Estrada et al. + +\begin_inset CommandInset citation +LatexCommand citep +key "Estrada20" +literal "false" -\begin_layout LyX-Code - 0.01 -\end_layout +\end_inset -\begin_layout LyX-Code - -\end_layout + and is called +\begin_inset Quotes eld +\end_inset -\begin_layout LyX-Code - -\end_layout -\begin_layout LyX-Code - -\end_layout +\emph on +force-velocity-Estrada +\emph default -\begin_layout Standard -\begin_inset Newpage newpage +\begin_inset Quotes erd \end_inset +. + It is a modification of the +\begin_inset Quotes eld +\end_inset -\end_layout -\begin_layout Subsubsection -Cell Growth -\begin_inset CommandInset label -LatexCommand label -name "subsec:Cell-Growth" +\emph on +active_contraction +\emph default +\begin_inset Quotes erd \end_inset + material based on the formulation of Guccione et al. + +\begin_inset CommandInset citation +LatexCommand citep +key "Guccione93" +literal "false" -\end_layout +\end_inset -\begin_layout Standard -The material type for cell growth is -\begin_inset Quotes eld + described in Section +\begin_inset space ~ \end_inset -\shape italic -cell growth -\shape default +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Active-Contraction" +plural "false" +caps "false" +noprefix "false" -\begin_inset Quotes erd \end_inset +, based on the fading-memory formulation poroposed by Hunter et al. \begin_inset CommandInset citation LatexCommand citep -key "Ateshian2012" -literal "true" +key "Hunter98" +literal "false" \end_inset . - The following material parameters need to be defined: -\end_layout - -\begin_layout Standard -\align center -\begin_inset VSpace defskip + The active stress is evaluated as +\begin_inset Formula $T^{a}\mathbf{a}\otimes\mathbf{a}$ \end_inset +, where +\begin_inset Formula $\mathbf{a}$ +\end_inset + is the unit vector along the fiber in the current configuration, and +\begin_inset Formula +\[ +T^{a}=e\left(t\right)\underbrace{T_{\max}\frac{Ca_{0}^{2}}{Ca_{0}^{2}+ECa_{50}^{2}}}_{\begin{array}{c} +\text{instantaneous length}\\ +\text{dependence} +\end{array}}\underbrace{\frac{1+aQ\left(t,\lambda\left(t\right)\right)}{1-Q\left(t,\lambda\left(t\right)\right)}}_{\text{force-velocity}} +\] + +\end_inset + +where +\begin_inset Formula +\[ +ECa_{50}=\frac{\left(\text{Ca}_{0}\right)_{\max}}{\sqrt{\exp\left[\beta\left(\lambda\left(t\right)l_{r}-l_{0}\right)\right]-1}} +\] + +\end_inset + +and +\begin_inset Formula +\[ +Q\left(t,\lambda\left(t\right)\right)=\sum_{k=1}^{3}A_{k}\int_{-\infty}^{t}e^{-\alpha_{k}\left(t-\tau\right)}\dot{\lambda}\left(\tau\right)\,d\tau +\] + +\end_inset + +In these expressions, +\begin_inset Formula $\lambda\left(t\right)$ +\end_inset + + is the fiber stretch ratio at the current time. + Here, +\begin_inset Formula $T^{a}$ +\end_inset + + +\begin_inset Quotes eld +\end_inset + +is the product of three distinct components: a time-varying normalized activatio +n, +\begin_inset Formula $e\left(t\right)$ +\end_inset + +, that defines the time course of force generation throughout the cardiac + cycle; an instantaneous length-dependent term that scales the peak possible + isometric tension based on the current fiber stretch; and a force-velocity + term that dampens the instantaneous force generation based on the rate + of shortening of the fibers +\begin_inset Quotes erd +\end_inset + + +\begin_inset CommandInset citation +LatexCommand citep +key "Estrada20" +literal "false" + +\end_inset + +. + The activation curve +\begin_inset Formula $e\left(t\right)$ +\end_inset + + is represented by the +\emph on +ascl +\emph default + property that takes an optional attribute, +\shape italic +lc +\shape default +, which defines the time-dependent loadcurve. + The list of parameters required for this model is as follows. +\end_layout + +\begin_layout Standard +\align center \begin_inset Tabular - + - \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -49516,9 +49981,8 @@ literal "true" \begin_inset Text \begin_layout Plain Layout -intracellular solid volume fraction in reference (strain-free) configuration, - -\begin_inset Formula $\varphi_{r}^{s}$ +Activation scale factor +\begin_inset Formula $e\left(t\right)$ \end_inset @@ -49526,11 +49990,50 @@ intracellular solid volume fraction in reference (strain-free) configuration, \end_inset - + + + \begin_inset Text \begin_layout Plain Layout -[ ] + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Intracellular calcium concentration +\begin_inset Formula $Ca_{0}$ +\end_inset + + (default=1) +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Maximum peak intracellular calcium concentration +\begin_inset Formula $\left(\text{Ca}_{0}\right)_{\max}$ +\end_inset + + (default=ca0) \end_layout \end_inset @@ -49541,7 +50044,7 @@ intracellular solid volume fraction in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -49550,54 +50053,56 @@ intracellular solid volume fraction in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout -intracellular molar content of membrane-impermeant solute (moles per volume - of the cell in the reference configuration), -\begin_inset Formula $c_{r}$ +tension-sarcomere length relation constant +\begin_inset Formula $\beta$ \end_inset - + \end_layout \end_inset - + + + \begin_inset Text \begin_layout Plain Layout -[ -\series bold -n -\series default -/ -\series bold -L -\series default + +\end_layout -\begin_inset Formula $^{\mathrm{3}}$ \end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +No tension sarcomere length +\begin_inset Formula $l_{0}$ +\end_inset + -] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -extracellular osmolarity, -\begin_inset Formula $c_{e}$ +Unloaded sarcomere length +\begin_inset Formula $l_{r}$ \end_inset @@ -49605,224 +50110,283 @@ extracellular osmolarity, \end_inset - + + + \begin_inset Text \begin_layout Plain Layout -[ -\series bold -n -\series default -/ -\series bold -L -\series default + +\end_layout -\begin_inset Formula $^{\mathrm{3}}$ \end_inset + + +\begin_inset Text -] +\begin_layout Plain Layout +Isometric tension under maximal activation at camax +\begin_inset Formula $T_{\max}$ +\end_inset + + (default=1) \end_layout \end_inset - + + +\begin_inset Text + +\begin_layout Plain Layout +, , +\end_layout \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +Parameters +\begin_inset Formula $A_{k}$ +\end_inset -\begin_inset VSpace defskip + for +\begin_inset Formula $k=1,2,3$ \end_inset \end_layout -\begin_layout Standard -The Cauchy stress for this material is -\begin_inset Formula -\[ -\boldsymbol{\sigma}=-\pi\mathbf{I}, -\] - \end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +, , +\end_layout -where -\begin_inset Formula $\pi$ \end_inset + + +\begin_inset Text - is the osmotic pressure, given by -\begin_inset Formula -\[ -\pi=RT\left(\frac{c_{r}}{J-\varphi_{r}^{s}}-c_{e}\right), -\] +\begin_layout Plain Layout +Parameters +\begin_inset Formula $\alpha_{k}$ +\end_inset + for +\begin_inset Formula $k=1,2,3$ \end_inset -where -\begin_inset Formula $J=\det\mathbf{F}$ + +\end_layout + \end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout - is the relative volume. - The values of the universal gas constant -\begin_inset Formula $R$ \end_inset + + +\begin_inset Text - and absolute temperature -\begin_inset Formula $T$ +\begin_layout Plain Layout +Parameter +\begin_inset Formula $a$ \end_inset - must be specified as global constants. + \end_layout -\begin_layout Standard -Cell growth may be modeled by simply increasing the mass of the intracellular - solid matrix and membrane-impermeant solute. - This is achieved by allowing the parameters -\begin_inset Formula $\varphi_{r}^{s}$ \end_inset + + + + +\begin_inset Text - and -\begin_inset Formula $c_{r}$ -\end_inset +\begin_layout Plain Layout + +\end_layout - to increase over time as a result of growth, by associating them with user-defi -ned load curves. - Since cell growth is often accompanied by cell division, and since daughter - cells typically achieve the same solid and solute content as their parent, - it may be convenient to assume that -\begin_inset Formula $\varphi_{r}^{s}$ \end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Set to true (1) by default. + Set to false (0) to turn off the force-velocity term +\end_layout - and -\begin_inset Formula $c_{r}$ \end_inset + + + - increase proportionally, though this is not an obligatory relationship. - To ensure that the initial configuration is a stress-free reference configurati -on, let -\begin_inset Formula $c_{r}=\left(1-\varphi_{r}^{s}\right)c_{e}$ \end_inset - in the initial state prior to growth. + \end_layout \begin_layout Standard \shape italic -Example (using units of mm, N, s, nmol, K) -\shape default -: +Example: \end_layout -\begin_layout LyX-Code - +\begin_layout Standard +This example defines a transversely isotropic material with a Mooney-Rivlin + basis. + It defines a homogeneous fiber direction and uses the active fiber contraction + feature. \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 298 + 13.85 \end_layout \begin_layout LyX-Code - 8.314e-06 + 0.0 \end_layout \begin_layout LyX-Code - 0 + 2.07 \end_layout \begin_layout LyX-Code - + 61.44 \end_layout \begin_layout LyX-Code - + 640.7 \end_layout \begin_layout LyX-Code - + 100.0 \end_layout \begin_layout LyX-Code - + 1.03 \end_layout \begin_layout LyX-Code - 1 + 1,0,0 \end_layout \begin_layout LyX-Code - 1 + \end_layout \begin_layout LyX-Code - 300 + 1 \end_layout \begin_layout LyX-Code - + 4.35 \end_layout \begin_layout LyX-Code - + 4.75 \end_layout \begin_layout LyX-Code - + 1.58 \end_layout \begin_layout LyX-Code - + 1.58 \end_layout \begin_layout LyX-Code - 0,0.3 + 135.7 \end_layout \begin_layout LyX-Code - 1,0.6 + 30.30303 \end_layout \begin_layout LyX-Code - + 50 \end_layout \begin_layout LyX-Code - + 0.5 \end_layout \begin_layout LyX-Code - 0,210 + 1 \end_layout \begin_layout LyX-Code - 1,420 + \end_layout \begin_layout LyX-Code - + \end_layout -\begin_layout LyX-Code - +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsection +Unconstrained Materials +\begin_inset CommandInset label +LatexCommand label +name "subsec:Unconstrained-Materials" + +\end_inset + + \end_layout \begin_layout Standard -\begin_inset Newpage newpage +Unlike the materials in Section +\begin_inset space ~ \end_inset +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Uncoupled-Materials" + +\end_inset + +, these materials do not necessarily assume an additive decomposition of + the bulk and deviatoric parts of the strain energy or stress. + Further, these materials can only be used with the standard displacement-based + finite element formulation, rather than the three-field element formulatoin. + They should not be used for nearly-incompressible material behavior due + to the potential for element locking. \end_layout \begin_layout Subsubsection -Cubic CLE +Carter-Hayes \begin_inset CommandInset label LatexCommand label -name "subsec:Cubic-CLE" +name "subsec:Carter-Hayes" \end_inset @@ -49830,10 +50394,9 @@ name "subsec:Cubic-CLE" \end_layout \begin_layout Standard -The material type for a conewise linear elastic (CLE) material with cubic - symmetry is +The material type for a Carter-Hayes material is \shape italic -cubic CLE +Carter-Hayes \shape default . The following parameters must be defined: @@ -49846,17 +50409,17 @@ cubic CLE \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -49865,11 +50428,11 @@ cubic CLE \begin_inset Text \begin_layout Plain Layout -Tensile diagonal first Lamé coefficient -\begin_inset Formula $\lambda_{+1}$ +Young's modulus at reference density +\begin_inset Formula $E_{0}$ \end_inset - + \end_layout \end_inset @@ -49893,7 +50456,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -49902,11 +50465,11 @@ P \begin_inset Text \begin_layout Plain Layout -Compressive diagonal first Lamé coefficient -\begin_inset Formula $\lambda_{-1}$ +reference density +\begin_inset Formula $\rho_{0}$ \end_inset - + \end_layout \end_inset @@ -49917,8 +50480,16 @@ Compressive diagonal first Lamé coefficient \begin_layout Plain Layout [ \series bold -P +M +\series default +/ +\series bold +L \series default + +\begin_inset Formula $^{\mathrm{3}}$ +\end_inset + ] \end_layout @@ -49930,7 +50501,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -49939,11 +50510,12 @@ P \begin_inset Text \begin_layout Plain Layout -Off-diagonal first Lamé coefficient -\begin_inset Formula $\lambda_{2}$ +exponent of solid-bound molecule density for calculation of Young's modulus + +\begin_inset Formula $\gamma$ \end_inset - + \end_layout \end_inset @@ -49952,35 +50524,51 @@ Off-diagonal first Lamé coefficient \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[ ] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Second Lamé coefficient -\begin_inset Formula $\mu$ +Poisson's ratio +\begin_inset Formula $\nu$ \end_inset + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text +\begin_layout Plain Layout + \end_layout \end_inset @@ -49989,11 +50577,16 @@ Second Lamé coefficient \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +index of solid bound molecule +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] \end_layout \end_inset @@ -50011,88 +50604,231 @@ P \end_layout \begin_layout Standard -This bimodular elastic material is specialized from the orthotropic conewise - linear elastic material described by Curnier et al. - +This model describes an unconstrained neo-Hookean material \begin_inset CommandInset citation LatexCommand citep -key "Curnier94" +key "Bonet97" literal "true" \end_inset -, to the case of cubic symmetry. - It is derived from the following hyperelastic strain-energy function: -\begin_inset Formula -\[ -\Psi_{r}=\mu\mathbf{I}:\mathbf{E}^{2}+\sum\limits _{a=1}^{3}\frac{1}{2}\lambda_{1}\left[\mathbf{A}_{a}^{r}:\mathbf{E}\right]\left(\mathbf{A}_{a}^{r}:\mathbf{E}\right)^{2}+\frac{1}{2}\lambda_{2}\sum\limits _{\begin{array}{c} -b=1\\ -b\ne a -\end{array}}^{3}\left(\mathbf{A}_{a}^{r}:\mathbf{E}\right)\left(\mathbf{A}_{b}^{r}:\mathbf{E}\right)\,, -\] - + whose Young's modulus is a power-law function of the referential apparent + density +\begin_inset Formula $\rho_{r}^{\sigma}$ \end_inset -where + of a solid-bound molecule. + It is derived from the following hyperelastic strain-energy function: \begin_inset Formula \[ -\lambda_{1}\left[\mathbf{A}_{a}^{r}:\mathbf{E}\right]=\begin{cases} -\lambda_{+1} & \mathbf{A}_{a}^{r}:\mathbf{E}\geqslant0\\ -\lambda_{-1} & \mathbf{A}_{a}^{r}:\mathbf{\,}.E<0 -\end{cases} +\Psi_{r}=\frac{E_{Y}}{2\left(1+\nu\right)}\left[\frac{1}{2}\left(\tr\mathbf{C}-3\right)-\ln J+\frac{\nu}{1-2\nu}\left(\ln J\right)^{2}\right]. \] \end_inset Here, -\begin_inset Formula ${\mathbf{E}\ensuremath{}}$ -\end_inset - - is the Lagrangian strain tensor and -\begin_inset Formula $\mathbf{A}_{a}^{r}=\mathbf{a}_{a}^{r}\otimes\mathbf{a}_{a}^{r}$ -\end_inset - -, where -\begin_inset Formula $\mathbf{a}_{a}^{r}$ +\begin_inset Formula $\mathbf{C}$ \end_inset - ( -\begin_inset Formula $a=1,2,3$ + is the right Cauchy-Green deformation tensor and +\begin_inset Formula $J$ \end_inset - ) are orthonormal vectors aligned with the material axes. - This material response was originally formulated for infinitesimal strain - analyses; its behavior under finite strains may not be physically realistic. + is the determinant of the deformation gradient tensor. \end_layout \begin_layout Standard +Young's modulus depends on +\begin_inset Formula $\rho_{r}^{\sigma}$ +\end_inset -\shape italic -Example: -\end_layout + according to a power law +\begin_inset CommandInset citation +LatexCommand citep +key "Carter76,Carter77" +literal "true" -\begin_layout LyX-Code - -\end_layout +\end_inset -\begin_layout LyX-Code - 1 +, +\begin_inset Formula +\[ +E_{Y}=E_{0}\left(\frac{\rho_{r}^{\sigma}}{\rho_{0}}\right)^{\gamma}\,. +\] + +\end_inset + +This type of material references a solid-bound molecule that belongs to + a multiphasic mixture. + Therefore this material may only be used as the solid (or a component of + the solid) in a multiphasic mixture (Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Triphasic-Multiphasic-Materials" + +\end_inset + +). + The solid-bound molecule must be defined in the section (Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solid-Bound-Molecules" + +\end_inset + +) and must be included in the multiphasic mixture using a + tag. + The parameter +\shape italic +sbm +\shape default + must refer to the global index of that solid-bound molecule. + The value of +\begin_inset Formula $\rho_{r}^{\sigma}$ +\end_inset + + is specified within the tag. + If a chemical reaction is defined within that multiphasic mixture that + alters the value of +\begin_inset Formula $\rho_{r}^{\sigma}$ +\end_inset + +, lower and upper bounds may be specified for this referential density within + the tag to prevent +\begin_inset Formula $E_{Y}$ +\end_inset + + from reducing to zero or achieving excessively elevated values. +\end_layout + +\begin_layout Standard + +\shape italic +Example: \end_layout \begin_layout LyX-Code - 13.01 + \end_layout \begin_layout LyX-Code - 0.49 + 0 \end_layout \begin_layout LyX-Code - 0.66 + \end_layout \begin_layout LyX-Code - 0.16 + 1 +\end_layout + +\begin_layout LyX-Code + 0.1 +\end_layout + +\begin_layout LyX-Code + 5 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 10000 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 2.0 +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 0.01 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + \end_layout \begin_layout LyX-Code @@ -50107,10 +50843,10 @@ Example: \end_layout \begin_layout Subsubsection -Donnan Equilibrium Swelling +Cell Growth \begin_inset CommandInset label LatexCommand label -name "subsec:Donnan-Equilibrium-Swelling" +name "subsec:Cell-Growth" \end_inset @@ -50118,57 +50854,26 @@ name "subsec:Donnan-Equilibrium-Swelling" \end_layout \begin_layout Standard -The material type for a Donnan equilibrium swelling pressure is +The material type for cell growth is \begin_inset Quotes eld \end_inset \shape italic -Donnan equilibrium +cell growth \shape default \begin_inset Quotes erd \end_inset -. - The swelling pressure is described by the equations for ideal Donnan equilibriu -m, assuming that the material is porous, with a charged solid matrix, and - the external bathing environment consists of a salt solution of monovalent - counter-ions + \begin_inset CommandInset citation LatexCommand citep -key "OVERBEEK56,Lai91" +key "Ateshian2012" literal "true" \end_inset -. - Since osmotic swelling must be resisted by a solid matrix, this material - is not stable on its own. - It must be combined with an elastic material that resists the swelling, - using a -\begin_inset Quotes eld -\end_inset - - -\shape italic -solid mixture -\shape default - -\begin_inset Quotes erd -\end_inset - - container as described in Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Solid-Mixture" - -\end_inset - . The following material parameters need to be defined: \end_layout @@ -50180,7 +50885,7 @@ reference "subsec:Solid-Mixture" \begin_inset Tabular - + @@ -50190,7 +50895,7 @@ reference "subsec:Solid-Mixture" \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -50199,9 +50904,9 @@ reference "subsec:Solid-Mixture" \begin_inset Text \begin_layout Plain Layout -gel porosity (fluid volume fraction) in reference (strain-free) configuration, +intracellular solid volume fraction in reference (strain-free) configuration, -\begin_inset Formula $\varphi_{0}^{w}$ +\begin_inset Formula $\varphi_{r}^{s}$ \end_inset @@ -50224,7 +50929,7 @@ gel porosity (fluid volume fraction) in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -50233,11 +50938,12 @@ gel porosity (fluid volume fraction) in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout -fixed-charge density in reference (strain-free) configuration, -\begin_inset Formula $c_{0}^{F}$ +intracellular molar content of membrane-impermeant solute (moles per volume + of the cell in the reference configuration), +\begin_inset Formula $c_{r}$ \end_inset - + \end_layout \end_inset @@ -50265,21 +50971,21 @@ L - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -external bath osmolarity, -\begin_inset Formula $\bar{c}^{\ast}$ +extracellular osmolarity, +\begin_inset Formula $c_{e}$ \end_inset @@ -50287,7 +50993,7 @@ external bath osmolarity, \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -50306,39 +51012,6 @@ L ] \end_layout -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -osmotic coefficient, -\begin_inset Formula $\Phi$ -\end_inset - - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -[] -\end_layout - \end_inset @@ -50354,16 +51027,7 @@ osmotic coefficient, \end_layout \begin_layout Standard -The Cauchy stress for this material is the stress from the Donnan equilibrium - response -\begin_inset CommandInset citation -LatexCommand citep -key "Ateshian09a" -literal "true" - -\end_inset - -: +The Cauchy stress for this material is \begin_inset Formula \[ \boldsymbol{\sigma}=-\pi\mathbf{I}, @@ -50378,20 +51042,7 @@ where is the osmotic pressure, given by \begin_inset Formula \[ -\pi=RT\Phi\left(\sqrt{\left(c^{F}\right)^{2}+\left(\bar{c}^{\ast}\right)^{2}}-\bar{c}^{\ast}\right), -\] - -\end_inset - -and -\begin_inset Formula $c^{F}$ -\end_inset - - is the fixed-charge density in the current configuration, related to the - reference configuration via -\begin_inset Formula -\[ -c^{F}=\frac{\varphi_{0}^{w}}{J-1+\varphi_{0}^{w}}c_{0}^{F}, +\pi=RT\left(\frac{c_{r}}{J-\varphi_{r}^{s}}-c_{e}\right), \] \end_inset @@ -50410,26 +51061,170 @@ where \end_inset must be specified as global constants. - For ideal Donnan law, use -\begin_inset Formula $\Phi=1$ +\end_layout + +\begin_layout Standard +Cell growth may be modeled by simply increasing the mass of the intracellular + solid matrix and membrane-impermeant solute. + This is achieved by allowing the parameters +\begin_inset Formula $\varphi_{r}^{s}$ \end_inset -. + and +\begin_inset Formula $c_{r}$ +\end_inset + + to increase over time as a result of growth, by associating them with user-defi +ned load curves. + Since cell growth is often accompanied by cell division, and since daughter + cells typically achieve the same solid and solute content as their parent, + it may be convenient to assume that +\begin_inset Formula $\varphi_{r}^{s}$ +\end_inset + + and +\begin_inset Formula $c_{r}$ +\end_inset + + increase proportionally, though this is not an obligatory relationship. + To ensure that the initial configuration is a stress-free reference configurati +on, let +\begin_inset Formula $c_{r}=\left(1-\varphi_{r}^{s}\right)c_{e}$ +\end_inset + + in the initial state prior to growth. \end_layout \begin_layout Standard -Note that -\begin_inset Formula $c_{0}^{F}$ + +\shape italic +Example (using units of mm, N, s, nmol, K) +\shape default +: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 298 +\end_layout + +\begin_layout LyX-Code + 8.314e-06 +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 300 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0,0.3 +\end_layout + +\begin_layout LyX-Code + 1,0.6 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0,210 +\end_layout + +\begin_layout LyX-Code + 1,420 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage \end_inset - may be negative or positive; the gel porosity is unitless and must be in - the range -\begin_inset Formula $0<\varphi_{0}^{w}<1$ + +\end_layout + +\begin_layout Subsubsection +Cubic CLE +\begin_inset CommandInset label +LatexCommand label +name "subsec:Cubic-CLE" + \end_inset + +\end_layout + +\begin_layout Standard +The material type for a conewise linear elastic (CLE) material with cubic + symmetry is +\shape italic +cubic CLE +\shape default . - A self-consistent set of units must be used for this model. - For example: + The following parameters must be defined: \end_layout \begin_layout Standard @@ -50439,7 +51234,7 @@ Note that \begin_inset Tabular - + @@ -50449,7 +51244,7 @@ Note that \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -50458,7 +51253,11 @@ Note that \begin_inset Text \begin_layout Plain Layout -(m, N, s, mol, K) +Tensile diagonal first Lamé coefficient +\begin_inset Formula $\lambda_{+1}$ +\end_inset + + \end_layout \end_inset @@ -50467,7 +51266,11 @@ Note that \begin_inset Text \begin_layout Plain Layout -(mm, N, s, nmol, K) +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -50478,10 +51281,7 @@ Note that \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $R$ -\end_inset - - + \end_layout \end_inset @@ -50490,11 +51290,11 @@ Note that \begin_inset Text \begin_layout Plain Layout -8.314 J/mol -\begin_inset Formula $\cdot$ +Compressive diagonal first Lamé coefficient +\begin_inset Formula $\lambda_{-1}$ \end_inset -K + \end_layout \end_inset @@ -50503,15 +51303,11 @@ K \begin_inset Text \begin_layout Plain Layout -8.314×10 -\begin_inset Formula $^{\mathrm{-6}}$ -\end_inset - - mJ/nmol -\begin_inset Formula $\cdot$ -\end_inset - -K +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -50522,56 +51318,8 @@ K \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $T$ -\end_inset - - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -K -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -K -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $c_{0}^{F}$ -\end_inset - - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Eq/m -\begin_inset Formula $^{\mathrm{3}}$ -\end_inset - -= mEq/L -\end_layout + +\end_layout \end_inset @@ -50579,38 +51327,11 @@ Eq/m \begin_inset Text \begin_layout Plain Layout -nEq/mm -\begin_inset Formula $^{\mathrm{3}}$ -\end_inset - -= mEq/L -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $\bar{c}^{\ast}$ -\end_inset - - -\end_layout - +Off-diagonal first Lamé coefficient +\begin_inset Formula $\lambda_{2}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -mol/m -\begin_inset Formula $^{\mathrm{3}}$ -\end_inset -= mM \end_layout \end_inset @@ -50619,54 +51340,32 @@ mol/m \begin_inset Text \begin_layout Plain Layout -nmol/mm -\begin_inset Formula $^{\mathrm{3}}$ -\end_inset - -= mM +[ +\series bold +P +\series default +] \end_layout \end_inset - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $\xi_{i}$ -\end_inset - - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Pa -\end_layout - -\end_inset - - + \begin_inset Text \begin_layout Plain Layout -MPa + \end_layout \end_inset - - - + \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\pi$ +Second Lamé coefficient +\begin_inset Formula $\mu$ \end_inset @@ -50678,16 +51377,11 @@ MPa \begin_inset Text \begin_layout Plain Layout -Pa -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -MPa +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -50705,159 +51399,94 @@ MPa \end_layout \begin_layout Standard -Though this material is porous, this is not a full-fledged biphasic material - as described in Section -\begin_inset space ~ -\end_inset +This bimodular elastic material is specialized from the orthotropic conewise + linear elastic material described by Curnier et al. + +\begin_inset CommandInset citation +LatexCommand citep +key "Curnier94" +literal "true" +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "sec:Biphasic-Materials" +, to the case of cubic symmetry. + It is derived from the following hyperelastic strain-energy function: +\begin_inset Formula +\[ +\Psi_{r}=\mu\mathbf{I}:\mathbf{E}^{2}+\sum\limits _{a=1}^{3}\frac{1}{2}\lambda_{1}\left[\mathbf{A}_{a}^{r}:\mathbf{E}\right]\left(\mathbf{A}_{a}^{r}:\mathbf{E}\right)^{2}+\frac{1}{2}\lambda_{2}\sum\limits _{\begin{array}{c} +b=1\\ +b\ne a +\end{array}}^{3}\left(\mathbf{A}_{a}^{r}:\mathbf{E}\right)\left(\mathbf{A}_{b}^{r}:\mathbf{E}\right)\,, +\] \end_inset - for example. - The behavior described by this material is strictly valid only after the - transient response of interstitial fluid and ion fluxes has subsided (thus - Donnan -\shape italic -equilibrium -\shape default -). -\end_layout +where +\begin_inset Formula +\[ +\lambda_{1}\left[\mathbf{A}_{a}^{r}:\mathbf{E}\right]=\begin{cases} +\lambda_{+1} & \mathbf{A}_{a}^{r}:\mathbf{E}\geqslant0\\ +\lambda_{-1} & \mathbf{A}_{a}^{r}:\mathbf{\,}.E<0 +\end{cases} +\] -\begin_layout Standard -Donnan osmotic swelling reduces to zero when either -\begin_inset Formula $c_{0}^{F}=0$ \end_inset - or -\begin_inset Formula $\bar{c}^{\ast}\to\infty$ +Here, +\begin_inset Formula ${\mathbf{E}\ensuremath{}}$ \end_inset -. - Therefore, entering any other values for -\begin_inset Formula $c_{0}^{F}$ + is the Lagrangian strain tensor and +\begin_inset Formula $\mathbf{A}_{a}^{r}=\mathbf{a}_{a}^{r}\otimes\mathbf{a}_{a}^{r}$ \end_inset - and -\begin_inset Formula $\bar{c}^{\ast}$ +, where +\begin_inset Formula $\mathbf{a}_{a}^{r}$ \end_inset - at the initial time point of an analysis produces an instantaneous, non-zero - swelling pressure. - Depending on the magnitude of this pressure relative to the solid matrix - stiffness, the nonlinear analysis may not converge due to this sudden swelling. - Therefore, it is recommended to prescribe a load curve for either - or , to ease into the initial swelling prior to the application of - other loading conditions. + ( +\begin_inset Formula $a=1,2,3$ +\end_inset + + ) are orthonormal vectors aligned with the material axes. + This material response was originally formulated for infinitesimal strain + analyses; its behavior under finite strains may not be physically realistic. \end_layout \begin_layout Standard \shape italic -Example (using units of mm, N, s, nmol, K) -\shape default -: -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0,0,0 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0.8 -\end_layout - -\begin_layout LyX-Code - 1 +Example: \end_layout \begin_layout LyX-Code - 300 + \end_layout \begin_layout LyX-Code - + 1 \end_layout \begin_layout LyX-Code - + 13.01 \end_layout \begin_layout LyX-Code - 0.01,0.01,0.01 + 0.49 \end_layout \begin_layout LyX-Code - 3,3,3 + 0.66 \end_layout \begin_layout LyX-Code - + 0.16 \end_layout \begin_layout LyX-Code \end_layout -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0,0 -\end_layout - -\begin_layout LyX-Code - 1,150 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 8.314e-6 -\end_layout - -\begin_layout LyX-Code - 310 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - \begin_layout Standard \begin_inset Newpage newpage \end_inset @@ -50866,10 +51495,10 @@ Example (using units of mm, N, s, nmol, K) \end_layout \begin_layout Subsubsection -Ellipsoidal Fiber Distribution +Donnan Equilibrium Swelling \begin_inset CommandInset label LatexCommand label -name "subsec:Ellipsoidal-Fiber-Distribution" +name "subsec:Donnan-Equilibrium-Swelling" \end_inset @@ -50877,23 +51506,35 @@ name "subsec:Ellipsoidal-Fiber-Distribution" \end_layout \begin_layout Standard -The material type for an ellipsoidal continuous fiber distribution is +The material type for a Donnan equilibrium swelling pressure is \begin_inset Quotes eld \end_inset \shape italic -ellipsoidal fiber distribution +Donnan equilibrium \shape default \begin_inset Quotes erd \end_inset . - Since fibers can only sustain tension, this material is not stable on its - own. - It must be combined with a stable compressible material that acts as a - ground matrix, using a + The swelling pressure is described by the equations for ideal Donnan equilibriu +m, assuming that the material is porous, with a charged solid matrix, and + the external bathing environment consists of a salt solution of monovalent + counter-ions +\begin_inset CommandInset citation +LatexCommand citep +key "OVERBEEK56,Lai91" +literal "true" + +\end_inset + +. + Since osmotic swelling must be resisted by a solid matrix, this material + is not stable on its own. + It must be combined with an elastic material that resists the swelling, + using a \begin_inset Quotes eld \end_inset @@ -50927,17 +51568,17 @@ reference "subsec:Solid-Mixture" \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -50946,8 +51587,9 @@ reference "subsec:Solid-Mixture" \begin_inset Text \begin_layout Plain Layout -parameters -\begin_inset Formula $\left({\beta_{1},\beta_{2},\beta_{3}}\right)$ +gel porosity (fluid volume fraction) in reference (strain-free) configuration, + +\begin_inset Formula $\varphi_{0}^{w}$ \end_inset @@ -50966,21 +51608,21 @@ parameters - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -parameters -\begin_inset Formula $\left({\xi_{1},\xi_{2},\xi_{3}}\right)$ +fixed-charge density in reference (strain-free) configuration, +\begin_inset Formula $c_{0}^{F}$ \end_inset @@ -50988,217 +51630,194 @@ parameters \end_inset - + \begin_inset Text \begin_layout Plain Layout [ \series bold -P +n \series default +/ +\series bold +L +\series default + +\begin_inset Formula $^{\mathrm{3}}$ +\end_inset + ] \end_layout \end_inset - + + +\begin_inset Text -\end_inset +\begin_layout Plain Layout + +\end_layout +\end_inset + + +\begin_inset Text -\begin_inset VSpace defskip +\begin_layout Plain Layout +external bath osmolarity, +\begin_inset Formula $\bar{c}^{\ast}$ \end_inset \end_layout -\begin_layout Standard -The Cauchy stress for this fibrous material is given by -\begin_inset CommandInset citation -LatexCommand citep -key "Lanir83,Ateshian07a,Ateshian09a" -literal "true" +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +n +\series default +/ +\series bold +L +\series default +\begin_inset Formula $^{\mathrm{3}}$ \end_inset -: -\begin_inset Formula -\[ -\boldsymbol{\sigma}=\int_{0}^{2\pi}\int_{0}^{\pi}H\left(I_{n}-1\right)\sigma_{n}\left(\mathbf{n}\right)\sin\varphi\,d\varphi\,d\theta. -\] +] +\end_layout \end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout -Here, -\begin_inset Formula $I_{n}=\lambda_{n}^{2}=\mathbf{N}\cdot\mathbf{C}\cdot\mathbf{N}$ \end_inset + + +\begin_inset Text - is the square of the fiber stretch -\begin_inset Formula $\lambda_{n}$ +\begin_layout Plain Layout +osmotic coefficient, +\begin_inset Formula $\Phi$ \end_inset -, -\begin_inset Formula $\mathbf{N}$ + +\end_layout + \end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[] +\end_layout - is the unit vector along the fiber direction, in the reference configuration, - which in spherical angles is directed along -\begin_inset Formula $\left(\theta,\varphi\right)$ \end_inset + + + -, -\begin_inset Formula $\mathbf{n}=\mathbf{F}\cdot\mathbf{N}/\lambda_{n}$ \end_inset -, and -\begin_inset Formula $H\left(.\right)$ + +\begin_inset VSpace defskip \end_inset -is the unit step function that enforces the tension-only contribution. + \end_layout \begin_layout Standard -The fiber stress is determined from a fiber strain energy function, -\begin_inset Formula -\[ -\sigma_{n}=\frac{2I_{n}}{J}\frac{\partial\Psi}{\partial I_{n}}\mathbf{n}\otimes\mathbf{n}, -\] +The Cauchy stress for this material is the stress from the Donnan equilibrium + response +\begin_inset CommandInset citation +LatexCommand citep +key "Ateshian09a" +literal "true" \end_inset -where in this material, +: \begin_inset Formula \[ -\Psi\left(\mathbf{n},I_{n}\right)=\xi\left(\mathbf{n}\right)\left(I_{n}-1\right)^{\beta\left(\mathbf{n}\right)}. +\boldsymbol{\sigma}=-\pi\mathbf{I}, \] \end_inset -The materials parameters -\begin_inset Formula $\beta$ +where +\begin_inset Formula $\pi$ \end_inset -and -\begin_inset Formula $\xi$ + is the osmotic pressure, given by +\begin_inset Formula +\[ +\pi=RT\Phi\left(\sqrt{\left(c^{F}\right)^{2}+\left(\bar{c}^{\ast}\right)^{2}}-\bar{c}^{\ast}\right), +\] + \end_inset -are assumed to vary ellipsoidally with -\begin_inset Formula $\mathbf{n}$ +and +\begin_inset Formula $c^{F}$ \end_inset -, according to + is the fixed-charge density in the current configuration, related to the + reference configuration via \begin_inset Formula \[ -\begin{aligned}\xi\left(\mathbf{n}\right) & =\left(\frac{\cos^{2}\theta\sin^{2}\varphi}{\xi_{1}^{2}}+\frac{\sin^{2}\theta\sin^{2}\varphi}{\xi_{2}^{2}}+\frac{\cos^{2}\varphi}{\xi_{3}^{2}}\right)^{-1/2}\\ -\beta\left(\mathbf{n}\right) & =\left(\frac{\cos^{2}\theta\sin^{2}\varphi}{\beta_{1}^{2}}+\frac{\sin^{2}\theta\sin^{2}\varphi}{\beta_{2}^{2}}+\frac{\cos^{2}\varphi}{\beta_{3}^{2}}\right)^{-1/2} -\end{aligned} -\,. +c^{F}=\frac{\varphi_{0}^{w}}{J-1+\varphi_{0}^{w}}c_{0}^{F}, \] \end_inset -The orientation of the material axis can be defined as explained in detail - in Section -\begin_inset space ~ +where +\begin_inset Formula $J=\det\mathbf{F}$ \end_inset + is the relative volume. + The values of the universal gas constant +\begin_inset Formula $R$ +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Specifying-Fiber-Orientation" + and absolute temperature +\begin_inset Formula $T$ +\end_inset + must be specified as global constants. + For ideal Donnan law, use +\begin_inset Formula $\Phi=1$ \end_inset . \end_layout \begin_layout Standard +Note that +\begin_inset Formula $c_{0}^{F}$ +\end_inset -\shape italic -Example -\shape default -: -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0,0,0 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1000.0 -\end_layout - -\begin_layout LyX-Code - 0.45 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 10, 12, 15 -\end_layout - -\begin_layout LyX-Code - 2.5, 3, 3 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout Standard -\begin_inset Newpage newpage -\end_inset - - -\end_layout - -\begin_layout Subsubsection -Ellipsoidal Fiber Distribution Neo-Hookean -\begin_inset CommandInset label -LatexCommand label -name "subsec:EFD-Neo-Hookean" - -\end_inset - - -\end_layout - -\begin_layout Standard -The material type for a Neo-Hookean material with an ellipsoidal continuous - fiber distribution is -\begin_inset Quotes eld -\end_inset - - -\shape italic -EFD neo-Hookean -\shape default - -\begin_inset Quotes erd -\end_inset + may be negative or positive; the gel porosity is unitless and must be in + the range +\begin_inset Formula $0<\varphi_{0}^{w}<1$ +\end_inset . - The following material parameters need to be defined: + A self-consistent set of units must be used for this model. + For example: \end_layout \begin_layout Standard @@ -51208,7 +51827,7 @@ EFD neo-Hookean \begin_inset Tabular - + @@ -51218,7 +51837,7 @@ EFD neo-Hookean \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -51227,7 +51846,7 @@ EFD neo-Hookean \begin_inset Text \begin_layout Plain Layout -Young's modulus +(m, N, s, mol, K) \end_layout \end_inset @@ -51236,11 +51855,7 @@ Young's modulus \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +(mm, N, s, nmol, K) \end_layout \end_inset @@ -51251,16 +51866,10 @@ P \begin_inset Text \begin_layout Plain Layout - -\end_layout - +\begin_inset Formula $R$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Poisson's ratio + \end_layout \end_inset @@ -51269,18 +51878,11 @@ Poisson's ratio \begin_inset Text \begin_layout Plain Layout -[ ] -\end_layout - +8.314 J/mol +\begin_inset Formula $\cdot$ \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout - +K \end_layout \end_inset @@ -51289,209 +51891,29 @@ Poisson's ratio \begin_inset Text \begin_layout Plain Layout -parameters -\begin_inset Formula $\left(\beta_{1},\beta_{2},\beta_{3}\right)$ +8.314×10 +\begin_inset Formula $^{\mathrm{-6}}$ \end_inset - -\end_layout - + mJ/nmol +\begin_inset Formula $\cdot$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ ] +K \end_layout \end_inset - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -parameters -\begin_inset Formula $\left(\xi_{1},\xi_{2},\xi_{3}\right)$ -\end_inset - - -\end_layout - -\end_inset - - + \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] -\end_layout - -\end_inset - - - - -\end_inset - - -\begin_inset VSpace defskip -\end_inset - - -\end_layout - -\begin_layout Standard -The Cauchy stress for this material is given by, -\begin_inset Formula -\[ -\boldsymbol{\sigma}=\boldsymbol{\sigma}_{NH}+\boldsymbol{\sigma}_{f}. -\] - -\end_inset - -Here, -\begin_inset Formula $\boldsymbol{\sigma}_{NH}$ -\end_inset - - is the stress from the Neo-Hookean basis (Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Neo-Hookean" - -\end_inset - -), and -\begin_inset Formula $\boldsymbol{\sigma}_{f}$ -\end_inset - - is the stress contribution from the fibers (Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Ellipsoidal-Fiber-Distribution" - -\end_inset - -). -\end_layout - -\begin_layout Standard - -\shape italic -Example -\shape default -: -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1 -\end_layout - -\begin_layout LyX-Code - 0.3 -\end_layout - -\begin_layout LyX-Code - 4.5,4.5,4.5 -\end_layout - -\begin_layout LyX-Code - 1,1,1 -\end_layout - -\begin_layout LyX-Code - 0,0,0 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout Standard -\begin_inset Newpage newpage -\end_inset - - -\end_layout - -\begin_layout Subsubsection -Ellipsoidal Fiber Distribution with Donnan Equilibrium Swelling -\begin_inset CommandInset label -LatexCommand label -name "subsec:EFD-Donnan-Equilibrium" - -\end_inset - - -\end_layout - -\begin_layout Standard -The material type for a swelling pressure combined with an ellipsoidal continuou -s fiber distribution is -\begin_inset Quotes eld -\end_inset - - -\shape italic -EFD Donnan equilibrium -\shape default - -\begin_inset Quotes erd -\end_inset - -. - The swelling pressure is described by the equations for ideal Donnan equilibriu -m, assuming that the material is porous, with a charged solid matrix, and - the external bathing environment consists of a salt solution of monovalent - counter-ions. - The following material parameters need to be defined: -\end_layout - -\begin_layout Standard -\align center -\begin_inset VSpace defskip +\begin_inset Formula $T$ \end_inset -\begin_inset Tabular - - - - - - - -\begin_inset Text - -\begin_layout Plain Layout - \end_layout \end_inset @@ -51500,12 +51922,7 @@ m, assuming that the material is porous, with a charged solid matrix, and \begin_inset Text \begin_layout Plain Layout -gel porosity (fluid volume fraction) in reference (strain-free) configuration, - -\begin_inset Formula $\varphi_{0}^{w}$ -\end_inset - - +K \end_layout \end_inset @@ -51514,7 +51931,7 @@ gel porosity (fluid volume fraction) in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout -[ ] +K \end_layout \end_inset @@ -51525,7 +51942,10 @@ gel porosity (fluid volume fraction) in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout - +\begin_inset Formula $c_{0}^{F}$ +\end_inset + + \end_layout \end_inset @@ -51534,11 +51954,11 @@ gel porosity (fluid volume fraction) in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout -fixed-charge density in reference (strain-free) configuration, -\begin_inset Formula $c_{0}^{F}$ +Eq/m +\begin_inset Formula $^{\mathrm{3}}$ \end_inset - += mEq/L \end_layout \end_inset @@ -51547,19 +51967,11 @@ fixed-charge density in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout -[ -\series bold -n -\series default -/ -\series bold -L -\series default - +nEq/mm \begin_inset Formula $^{\mathrm{3}}$ \end_inset -] += mEq/L \end_layout \end_inset @@ -51570,7 +51982,10 @@ L \begin_inset Text \begin_layout Plain Layout - +\begin_inset Formula $\bar{c}^{\ast}$ +\end_inset + + \end_layout \end_inset @@ -51579,11 +51994,11 @@ L \begin_inset Text \begin_layout Plain Layout -external bath osmolarity, -\begin_inset Formula $\bar{c}^{\ast}$ +mol/m +\begin_inset Formula $^{\mathrm{3}}$ \end_inset - += mM \end_layout \end_inset @@ -51592,19 +52007,11 @@ external bath osmolarity, \begin_inset Text \begin_layout Plain Layout -[ -\series bold -n -\series default -/ -\series bold -L -\series default - +nmol/mm \begin_inset Formula $^{\mathrm{3}}$ \end_inset -] += mM \end_layout \end_inset @@ -51615,7 +52022,10 @@ L \begin_inset Text \begin_layout Plain Layout - +\begin_inset Formula $\xi_{i}$ +\end_inset + + \end_layout \end_inset @@ -51624,11 +52034,7 @@ L \begin_inset Text \begin_layout Plain Layout -parameters -\begin_inset Formula $\left(\beta_{1},\beta_{2},\beta_{3}\right)$ -\end_inset - - +Pa \end_layout \end_inset @@ -51637,7 +52043,7 @@ parameters \begin_inset Text \begin_layout Plain Layout -[ ] +MPa \end_layout \end_inset @@ -51648,7 +52054,10 @@ parameters \begin_inset Text \begin_layout Plain Layout - +\begin_inset Formula $\pi$ +\end_inset + + \end_layout \end_inset @@ -51657,11 +52066,7 @@ parameters \begin_inset Text \begin_layout Plain Layout -parameters -\begin_inset Formula $\left(\xi_{1},\xi_{2},\xi_{3}\right)$ -\end_inset - - +Pa \end_layout \end_inset @@ -51670,11 +52075,7 @@ parameters \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +MPa \end_layout \end_inset @@ -51692,46 +52093,53 @@ P \end_layout \begin_layout Standard -The Cauchy stress for this material is given by, -\begin_inset Formula -\[ -\boldsymbol{\sigma}=\boldsymbol{\sigma}_{DE}+\boldsymbol{\sigma}_{f}\,. -\] - -\end_inset - - -\begin_inset Formula $\boldsymbol{\sigma}_{f}$ -\end_inset - - is the stress contribution from the fibers, as described in Section +Though this material is porous, this is not a full-fledged biphasic material + as described in Section \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Specifying-Fiber-Orientation" +reference "sec:Biphasic-Materials" \end_inset -. - -\begin_inset Formula $\boldsymbol{\sigma}_{DE}$ -\end_inset + for example. + The behavior described by this material is strictly valid only after the + transient response of interstitial fluid and ion fluxes has subsided (thus + Donnan +\shape italic +equilibrium +\shape default +). +\end_layout - is the stress from the Donnan equilibrium response, as described in Section -\begin_inset space ~ +\begin_layout Standard +Donnan osmotic swelling reduces to zero when either +\begin_inset Formula $c_{0}^{F}=0$ \end_inset + or +\begin_inset Formula $\bar{c}^{\ast}\to\infty$ +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Donnan-Equilibrium-Swelling" - +. + Therefore, entering any other values for +\begin_inset Formula $c_{0}^{F}$ \end_inset + and +\begin_inset Formula $\bar{c}^{\ast}$ +\end_inset + at the initial time point of an analysis produces an instantaneous, non-zero + swelling pressure. + Depending on the magnitude of this pressure relative to the solid matrix + stiffness, the nonlinear analysis may not converge due to this sudden swelling. + Therefore, it is recommended to prescribe a load curve for either + or , to ease into the initial swelling prior to the application of + other loading conditions. \end_layout \begin_layout Standard @@ -51743,31 +52151,47 @@ Example (using units of mm, N, s, nmol, K) \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 0.8 + 0,0,0 \end_layout \begin_layout LyX-Code - 1 + \end_layout \begin_layout LyX-Code - 300 + 0.8 \end_layout \begin_layout LyX-Code - 3,3,3 + 1 \end_layout \begin_layout LyX-Code - 0.01,0.01,0.01 + 300 \end_layout \begin_layout LyX-Code - 0,0,0 + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0.01,0.01,0.01 +\end_layout + +\begin_layout LyX-Code + 3,3,3 +\end_layout + +\begin_layout LyX-Code + \end_layout \begin_layout LyX-Code @@ -51830,10 +52254,10 @@ Example (using units of mm, N, s, nmol, K) \end_layout \begin_layout Subsubsection -Fung Orthotropic Compressible +Ellipsoidal Fiber Distribution \begin_inset CommandInset label LatexCommand label -name "subsec:Fung-Orthotropic-Compressible" +name "subsec:Ellipsoidal-Fiber-Distribution" \end_inset @@ -51841,48 +52265,67 @@ name "subsec:Fung-Orthotropic-Compressible" \end_layout \begin_layout Standard -The material type for unconstrained orthotropic Fung elasticity -\begin_inset CommandInset citation -LatexCommand citep -key "Fung79,Fung93" -literal "true" - -\end_inset - - is +The material type for an ellipsoidal continuous fiber distribution is \begin_inset Quotes eld \end_inset \shape italic -Fung-ortho-compressible +ellipsoidal fiber distribution +\shape default + \begin_inset Quotes erd \end_inset +. + Since fibers can only sustain tension, this material is not stable on its + own. + It must be combined with a stable compressible material that acts as a + ground matrix, using a +\begin_inset Quotes eld +\end_inset + +\shape italic +solid mixture \shape default -. - The following material parameters must be defined: -\end_layout -\begin_layout Standard -\align center -\begin_inset VSpace defskip +\begin_inset Quotes erd \end_inset - + container as described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solid-Mixture" + +\end_inset + +. + The following material parameters need to be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -51891,10 +52334,11 @@ Fung-ortho-compressible \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $E_{1}$ +parameters +\begin_inset Formula $\left({\beta_{1},\beta_{2},\beta_{3}}\right)$ \end_inset - Young's modulus + \end_layout \end_inset @@ -51903,39 +52347,36 @@ Fung-ortho-compressible \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[ ] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $E_{2}$ +parameters +\begin_inset Formula $\left({\xi_{1},\xi_{2},\xi_{3}}\right)$ \end_inset - Young's modulus + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -51943,194 +52384,229 @@ P \series bold P \series default -] +] \end_layout \end_inset - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $E_{3}$ + +\begin_inset VSpace defskip \end_inset - Young's modulus + \end_layout +\begin_layout Standard +The Cauchy stress for this fibrous material is given by +\begin_inset CommandInset citation +LatexCommand citep +key "Lanir83,Ateshian07a,Ateshian09a" +literal "true" + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] -\end_layout +: +\begin_inset Formula +\[ +\boldsymbol{\sigma}=\int_{0}^{2\pi}\int_{0}^{\pi}H\left(I_{n}-1\right)\sigma_{n}\left(\mathbf{n}\right)\sin\varphi\,d\varphi\,d\theta. +\] \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout - -\end_layout +Here, +\begin_inset Formula $I_{n}=\lambda_{n}^{2}=\mathbf{N}\cdot\mathbf{C}\cdot\mathbf{N}$ +\end_inset + is the square of the fiber stretch +\begin_inset Formula $\lambda_{n}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $G_{12}$ +, +\begin_inset Formula $\mathbf{N}$ \end_inset - shear modulus -\end_layout + is the unit vector along the fiber direction, in the reference configuration, + which in spherical angles is directed along +\begin_inset Formula $\left(\theta,\varphi\right)$ +\end_inset +, +\begin_inset Formula $\mathbf{n}=\mathbf{F}\cdot\mathbf{N}/\lambda_{n}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] +, and +\begin_inset Formula $H\left(.\right)$ +\end_inset + +is the unit step function that enforces the tension-only contribution. \end_layout +\begin_layout Standard +The fiber stress is determined from a fiber strain energy function, +\begin_inset Formula +\[ +\sigma_{n}=\frac{2I_{n}}{J}\frac{\partial\Psi}{\partial I_{n}}\mathbf{n}\otimes\mathbf{n}, +\] + \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout - -\end_layout +where in this material, +\begin_inset Formula +\[ +\Psi\left(\mathbf{n},I_{n}\right)=\xi\left(\mathbf{n}\right)\left(I_{n}-1\right)^{\beta\left(\mathbf{n}\right)}. +\] \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $G_{23}$ +The materials parameters +\begin_inset Formula $\beta$ \end_inset - shear modulus -\end_layout +and +\begin_inset Formula $\xi$ +\end_inset +are assumed to vary ellipsoidally with +\begin_inset Formula $\mathbf{n}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] -\end_layout +, according to +\begin_inset Formula +\[ +\begin{aligned}\xi\left(\mathbf{n}\right) & =\left(\frac{\cos^{2}\theta\sin^{2}\varphi}{\xi_{1}^{2}}+\frac{\sin^{2}\theta\sin^{2}\varphi}{\xi_{2}^{2}}+\frac{\cos^{2}\varphi}{\xi_{3}^{2}}\right)^{-1/2}\\ +\beta\left(\mathbf{n}\right) & =\left(\frac{\cos^{2}\theta\sin^{2}\varphi}{\beta_{1}^{2}}+\frac{\sin^{2}\theta\sin^{2}\varphi}{\beta_{2}^{2}}+\frac{\cos^{2}\varphi}{\beta_{3}^{2}}\right)^{-1/2} +\end{aligned} +\,. +\] \end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout +The orientation of the material axis can be defined as explained in detail + in Section +\begin_inset space ~ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $G_{31}$ + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Specifying-Fiber-Orientation" + \end_inset - shear modulus +. \end_layout -\end_inset - - -\begin_inset Text +\begin_layout Standard -\begin_layout Plain Layout -[ -\series bold -P -\series default -] +\shape italic +Example +\shape default +: \end_layout -\end_inset - - - - -\begin_inset Text +\begin_layout LyX-Code + +\end_layout -\begin_layout Plain Layout - +\begin_layout LyX-Code + 0,0,0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1000.0 +\end_layout + +\begin_layout LyX-Code + 0.45 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 10, 12, 15 +\end_layout + +\begin_layout LyX-Code + 2.5, 3, 3 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + \end_layout +\begin_layout Standard +\begin_inset Newpage newpage \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -\begin_inset Formula $\nu_{12}$ + +\end_layout + +\begin_layout Subsubsection +Ellipsoidal Fiber Distribution Neo-Hookean +\begin_inset CommandInset label +LatexCommand label +name "subsec:EFD-Neo-Hookean" + \end_inset - Poisson's ratio + \end_layout +\begin_layout Standard +The material type for a Neo-Hookean material with an ellipsoidal continuous + fiber distribution is +\begin_inset Quotes eld \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ ] + +\shape italic +EFD neo-Hookean +\shape default + +\begin_inset Quotes erd +\end_inset + +. + The following material parameters need to be defined: \end_layout +\begin_layout Standard +\align center +\begin_inset VSpace defskip \end_inset - - + + +\begin_inset Tabular + + + + + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52139,10 +52615,7 @@ P \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\nu_{23}$ -\end_inset - - Poisson's ratio +Young's modulus \end_layout \end_inset @@ -52151,7 +52624,11 @@ P \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -52162,7 +52639,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52171,10 +52648,7 @@ P \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\nu_{31}$ -\end_inset - - Poisson's ratio +Poisson's ratio \end_layout \end_inset @@ -52183,7 +52657,7 @@ P \begin_inset Text \begin_layout Plain Layout -[ ] +[ ] \end_layout \end_inset @@ -52194,7 +52668,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52203,10 +52677,11 @@ P \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $c$ +parameters +\begin_inset Formula $\left(\beta_{1},\beta_{2},\beta_{3}\right)$ \end_inset - coefficient + \end_layout \end_inset @@ -52215,11 +52690,7 @@ P \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[ ] \end_layout \end_inset @@ -52230,7 +52701,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52239,10 +52710,11 @@ P \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\kappa$ +parameters +\begin_inset Formula $\left(\xi_{1},\xi_{2},\xi_{3}\right)$ \end_inset - bulk modulus + \end_layout \end_inset @@ -52255,7 +52727,7 @@ P \series bold P \series default -] +] \end_layout \end_inset @@ -52273,125 +52745,45 @@ P \end_layout \begin_layout Standard -The hyperelastic strain energy function is given by -\begin_inset CommandInset citation -LatexCommand citep -key "Ateshian09" -literal "true" - -\end_inset - -, -\begin_inset Formula -\[ -\Psi=\frac{1}{2}c\left(e^{Q}-1\right)+U\left(J\right), -\] - -\end_inset - -where, -\begin_inset Formula -\[ -Q=c^{-1}\sum\limits _{a=1}^{3}\left[2\mu_{a}\mathbf{M}_{a}:\mathbf{E}^{2}+\sum\limits _{b=1}^{3}\lambda_{ab}\left(\mathbf{M}_{a}:\mathbf{E}\right)\left(\mathbf{M}_{b}:\mathbf{E}\right)\right], -\] - -\end_inset - -and +The Cauchy stress for this material is given by, \begin_inset Formula \[ -U\left(J\right)=\frac{\kappa}{2}\left(\ln J\right)^{2}\,. +\boldsymbol{\sigma}=\boldsymbol{\sigma}_{NH}+\boldsymbol{\sigma}_{f}. \] \end_inset Here, -\begin_inset Formula $\mathbf{E}=\left(\mathbf{C}-\mathbf{I}\right)/2$ -\end_inset - - and -\begin_inset Formula $\mathbf{M}_{a}=\mathbf{V}_{a}\otimes\mathbf{V}_{a}$ -\end_inset - -where -\begin_inset Formula $\mathbf{V}_{a}$ -\end_inset - - defines the initial direction of material axis -\begin_inset Formula $a$ +\begin_inset Formula $\boldsymbol{\sigma}_{NH}$ \end_inset -. - See Section + is the stress from the Neo-Hookean basis (Section \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Orthotropic-Materials" - -\end_inset - - on how to define the material axes for orthotropic materials. - The Lamé constants -\begin_inset Formula $\mu_{a}$ -\end_inset - - ( -\begin_inset Formula $a=1,2,3)$ -\end_inset - - and -\begin_inset Formula $\lambda_{ab}$ -\end_inset - - ( -\begin_inset Formula $a,b=1,2,3$ -\end_inset +reference "subsec:Neo-Hookean" -, -\begin_inset Formula $\lambda_{ba}=\lambda_{ab})$ \end_inset - are related to Young's moduli -\begin_inset Formula $E_{a}$ +), and +\begin_inset Formula $\boldsymbol{\sigma}_{f}$ \end_inset -, shear moduli -\begin_inset Formula $G_{ab}$ + is the stress contribution from the fibers (Section +\begin_inset space ~ \end_inset - and Poisson's ratios -\begin_inset Formula $\nu_{ab}$ -\end_inset - via -\begin_inset Formula -\[ -\begin{aligned} & \left[\begin{array}{cccccc} -\lambda_{11}+2\mu_{1} & \lambda_{12} & \lambda_{13} & 0 & 0 & 0\\ -\lambda_{12} & \lambda_{22}+2\mu_{2} & \lambda_{23} & 0 & 0 & 0\\ -\lambda_{13} & \lambda_{23} & \lambda_{33}+2\mu_{3} & 0 & 0 & 0\\ -0 & 0 & 0 & \frac{1}{2}\left(\mu_{1}+\mu_{2}\right) & 0 & 0\\ -0 & 0 & 0 & 0 & \frac{1}{2}\left(\mu_{2}+\mu_{3}\right) & 0\\ -0 & 0 & 0 & 0 & 0 & \frac{1}{2}\left(\mu_{1}+\mu_{3}\right) -\end{array}\right]^{-1}\\ - & =\left[\begin{array}{cccccc} -\frac{1}{E_{1}} & -\frac{\nu_{12}}{E_{1}} & -\frac{\nu_{13}}{E_{1}} & 0 & 0 & 0\\ --\frac{\nu_{21}}{E_{2}} & \frac{1}{E_{2}} & -\frac{\nu_{23}}{E_{2}} & 0 & 0 & 0\\ --\frac{\nu_{31}}{E_{3}} & -\frac{\nu_{32}}{E_{3}} & \frac{1}{E_{3}} & 0 & 0 & 0\\ -0 & 0 & 0 & \frac{1}{G_{12}} & 0 & 0\\ -0 & 0 & 0 & 0 & \frac{1}{G_{23}} & 0\\ -0 & 0 & 0 & 0 & 0 & \frac{1}{G_{31}} -\end{array}\right] -\end{aligned} -\] +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Ellipsoidal-Fiber-Distribution" \end_inset -The orthotropic Lamé parameters should produce a positive definite stiffness - matrix. +). \end_layout \begin_layout Standard @@ -52403,77 +52795,71 @@ Example \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 124 + 1 \end_layout \begin_layout LyX-Code - 124 + 0.3 \end_layout \begin_layout LyX-Code - 36 + 4.5,4.5,4.5 \end_layout \begin_layout LyX-Code - 67 + 1,1,1 \end_layout \begin_layout LyX-Code - 40 + 0,0,0 \end_layout \begin_layout LyX-Code - 40 + \end_layout -\begin_layout LyX-Code - -0.075 -\end_layout +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset -\begin_layout LyX-Code - 0.87 -\end_layout -\begin_layout LyX-Code - 0.26 \end_layout -\begin_layout LyX-Code - 1 -\end_layout +\begin_layout Subsubsection +Ellipsoidal Fiber Distribution with Donnan Equilibrium Swelling +\begin_inset CommandInset label +LatexCommand label +name "subsec:EFD-Donnan-Equilibrium" + +\end_inset + -\begin_layout LyX-Code - 120 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout Subsubsection -Gent Compressible \end_layout \begin_layout Standard -The compressible Gent material is defined using the -\emph on - +The material type for a swelling pressure combined with an ellipsoidal continuou +s fiber distribution is \begin_inset Quotes eld \end_inset -compressible Gent + +\shape italic +EFD Donnan equilibrium +\shape default + \begin_inset Quotes erd \end_inset - -\emph default - type string. - It defines the following parameters. - +. + The swelling pressure is described by the equations for ideal Donnan equilibriu +m, assuming that the material is porous, with a charged solid matrix, and + the external bathing environment consists of a salt solution of monovalent + counter-ions. + The following material parameters need to be defined: \end_layout \begin_layout Standard @@ -52483,17 +52869,17 @@ compressible Gent \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52502,7 +52888,12 @@ compressible Gent \begin_inset Text \begin_layout Plain Layout -Shear modulus +gel porosity (fluid volume fraction) in reference (strain-free) configuration, + +\begin_inset Formula $\varphi_{0}^{w}$ +\end_inset + + \end_layout \end_inset @@ -52511,11 +52902,7 @@ Shear modulus \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[ ] \end_layout \end_inset @@ -52526,7 +52913,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52535,15 +52922,8 @@ P \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $J_{m}=I_{m}-1$ -\end_inset - -, with -\begin_inset Formula $I_{m}$ -\end_inset - - max value for first invariant -\begin_inset Formula $I_{1}$ +fixed-charge density in reference (strain-free) configuration, +\begin_inset Formula $c_{0}^{F}$ \end_inset @@ -52557,172 +52937,28 @@ P \begin_layout Plain Layout [ \series bold -P +n \series default -] -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Bulk modulus -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -[ +/ \series bold -P +L \series default -] -\end_layout - -\end_inset - - - - -\end_inset - - -\begin_inset VSpace defskip -\end_inset - - -\end_layout - -\begin_layout Standard -The strain energy of this material is defined as follows, -\end_layout - -\begin_layout Standard -\begin_inset Formula -\[ -\Psi_{r}=-\frac{\mu J_{m}}{2}\ln\left(1-\frac{I_{1}-3}{J_{m}}\right)+\frac{\kappa}{2}\left(\frac{J^{2}-1}{2}-\ln J\right)^{4} -\] - -\end_inset - - -\end_layout - -\begin_layout Standard -Here, -\begin_inset Formula $\mu$ -\end_inset - - is the shear modulus. - -\end_layout - -\begin_layout Standard - -\shape italic -Example: -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 3.14 -\end_layout - -\begin_layout LyX-Code - 1.5 -\end_layout - -\begin_layout LyX-Code - 1e5 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout Subsubsection -Holmes-Mow -\begin_inset CommandInset label -LatexCommand label -name "subsec:Holmes-Mow" - -\end_inset - - -\end_layout - -\begin_layout Standard -The material type for the Holmes-Mow material -\begin_inset CommandInset citation -LatexCommand citep -key "Holmes90" -literal "true" - -\end_inset - - is -\shape italic -Holmes-Mow -\shape default -. - This isotropic hyperelastic material has been used to represent the solid - matrix of articular cartilage -\begin_inset CommandInset citation -LatexCommand citep -key "Holmes90,Ateshian97" -literal "true" - -\end_inset - - and intervertebral disc -\begin_inset CommandInset citation -LatexCommand citep -key "Iatridis98" -literal "true" +\begin_inset Formula $^{\mathrm{3}}$ \end_inset -. - The following material parameters must be defined: +] \end_layout -\begin_layout Standard -\align center -\begin_inset VSpace defskip \end_inset - - -\begin_inset Tabular - - - - - + + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52731,7 +52967,11 @@ literal "true" \begin_inset Text \begin_layout Plain Layout -Young's modulus +external bath osmolarity, +\begin_inset Formula $\bar{c}^{\ast}$ +\end_inset + + \end_layout \end_inset @@ -52742,8 +52982,16 @@ Young's modulus \begin_layout Plain Layout [ \series bold -P +n +\series default +/ +\series bold +L \series default + +\begin_inset Formula $^{\mathrm{3}}$ +\end_inset + ] \end_layout @@ -52755,7 +53003,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52764,7 +53012,11 @@ P \begin_inset Text \begin_layout Plain Layout -Poisson's ratio +parameters +\begin_inset Formula $\left(\beta_{1},\beta_{2},\beta_{3}\right)$ +\end_inset + + \end_layout \end_inset @@ -52784,7 +53036,7 @@ Poisson's ratio \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52793,7 +53045,11 @@ Poisson's ratio \begin_inset Text \begin_layout Plain Layout -Exponential stiffening coefficient +parameters +\begin_inset Formula $\left(\xi_{1},\xi_{2},\xi_{3}\right)$ +\end_inset + + \end_layout \end_inset @@ -52802,7 +53058,11 @@ Exponential stiffening coefficient \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -52820,93 +53080,136 @@ Exponential stiffening coefficient \end_layout \begin_layout Standard -The coupled hyperelastic strain-energy function for this material is given - by -\begin_inset CommandInset citation -LatexCommand citep -key "Holmes90" -literal "true" - -\end_inset - -: +The Cauchy stress for this material is given by, \begin_inset Formula \[ -W\left(I_{1},I_{2},J\right)=\frac{1}{2}c\left(e^{Q}-1\right), +\boldsymbol{\sigma}=\boldsymbol{\sigma}_{DE}+\boldsymbol{\sigma}_{f}\,. \] \end_inset -where -\begin_inset Formula $I_{1}$ -\end_inset - and -\begin_inset Formula $I_{2}$ +\begin_inset Formula $\boldsymbol{\sigma}_{f}$ \end_inset - are the first and second invariants of the right Cauchy-Green tensor and - -\begin_inset Formula $J$ + is the stress contribution from the fibers, as described in Section +\begin_inset space ~ \end_inset -is the jacobian of the deformation gradient. - Furthermore, -\begin_inset Formula -\[ -\begin{aligned}Q & =\frac{\beta}{\lambda+2\mu}\left[\left(2\mu-\lambda\right)\left(I_{1}-3\right)+\lambda\left(I_{2}-3\right)-\left(\lambda+2\mu\right)\ln J^{2}\right]\\ -c & =\frac{\lambda+2\mu}{2\beta} -\end{aligned} -\,, -\] + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Specifying-Fiber-Orientation" \end_inset -and -\begin_inset Formula $\lambda$ +. + +\begin_inset Formula $\boldsymbol{\sigma}_{DE}$ \end_inset - and -\begin_inset Formula $\mu$ + is the stress from the Donnan equilibrium response, as described in Section +\begin_inset space ~ \end_inset - are the Lamé parameters which are related to the more familiar Young's - modulus and Poisson's ratio in the usual manner: -\begin_inset Formula -\[ -\begin{aligned}\lambda & =\frac{E}{\left(1+\nu\right)\left(1-2\nu\right)}\\ -\mu & =\frac{E}{2\left(1+\nu\right)} -\end{aligned} -\,. -\] + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Donnan-Equilibrium-Swelling" \end_inset +\end_layout + +\begin_layout Standard + \shape italic -Example: +Example (using units of mm, N, s, nmol, K) +\shape default +: \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 1 + 0.8 \end_layout \begin_layout LyX-Code - 0.35 + 1 \end_layout \begin_layout LyX-Code - 0.25 + 300 +\end_layout + +\begin_layout LyX-Code + 3,3,3 +\end_layout + +\begin_layout LyX-Code + 0.01,0.01,0.01 +\end_layout + +\begin_layout LyX-Code + 0,0,0 \end_layout \begin_layout LyX-Code \end_layout +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0,0 +\end_layout + +\begin_layout LyX-Code + 1,150 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 8.314e-6 +\end_layout + +\begin_layout LyX-Code + 310 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + \begin_layout Standard \begin_inset Newpage newpage \end_inset @@ -52915,10 +53218,10 @@ Example: \end_layout \begin_layout Subsubsection -Holzapfel-Gasser-Ogden Unconstrained +Fung Orthotropic Compressible \begin_inset CommandInset label LatexCommand label -name "subsec:HGO-Unconstrained" +name "subsec:Fung-Orthotropic-Compressible" \end_inset @@ -52926,19 +53229,26 @@ name "subsec:HGO-Unconstrained" \end_layout \begin_layout Standard -The material type for the unconstrained Holzapfel-Gasser-Ogden material - +The material type for unconstrained orthotropic Fung elasticity \begin_inset CommandInset citation LatexCommand citep -key "Gasser06" +key "Fung79,Fung93" literal "true" \end_inset is -\emph on -HGO unconstrained -\emph default +\begin_inset Quotes eld +\end_inset + + +\shape italic +Fung-ortho-compressible +\begin_inset Quotes erd +\end_inset + + +\shape default . The following material parameters must be defined: \end_layout @@ -52950,17 +53260,17 @@ HGO unconstrained \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -52969,7 +53279,10 @@ HGO unconstrained \begin_inset Text \begin_layout Plain Layout -Shear modulus of ground matrix +\begin_inset Formula $E_{1}$ +\end_inset + + Young's modulus \end_layout \end_inset @@ -52993,7 +53306,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53002,7 +53315,10 @@ P \begin_inset Text \begin_layout Plain Layout -Fiber modulus +\begin_inset Formula $E_{2}$ +\end_inset + + Young's modulus \end_layout \end_inset @@ -53026,7 +53342,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53035,7 +53351,10 @@ P \begin_inset Text \begin_layout Plain Layout -Fiber exponential coefficient +\begin_inset Formula $E_{3}$ +\end_inset + + Young's modulus \end_layout \end_inset @@ -53055,35 +53374,34 @@ P - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Fiber mean orientation angle -\begin_inset Formula $\gamma$ +\begin_inset Formula $G_{12}$ \end_inset - + shear modulus \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout [ \series bold -deg +P \series default ] \end_layout @@ -53092,54 +53410,64 @@ deg - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Fiber dispersion +\begin_inset Formula $G_{23}$ +\end_inset + + shear modulus \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[] +[ +\series bold +P +\series default +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Bulk modulus +\begin_inset Formula $G_{31}$ +\end_inset + + shear modulus \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -53153,266 +53481,108 @@ P \end_inset - - -\end_inset + + +\begin_inset Text +\begin_layout Plain Layout + +\end_layout -\begin_inset VSpace defskip \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +\begin_inset Formula $\nu_{12}$ +\end_inset + Poisson's ratio \end_layout -\begin_layout Standard -The strain-energy function is given by: -\begin_inset Formula -\[ -\begin{aligned}\Psi_{r} & =\frac{c}{2}\left(I_{1}-3\right)-c\ln J+\frac{k_{1}}{2k_{2}}\sum_{\alpha}\left(\exp\left(k_{2}\left\langle E_{\alpha}\right\rangle ^{2}\right)-1\right)\\ - & +\frac{K_{0}}{2}\left(\frac{J^{2}-1}{2}-\ln J\right) -\end{aligned} -\] - -\end_inset - -The fiber strain is -\begin_inset Formula -\[ -E_{\alpha}=\kappa\left(I_{1}-3\right)+\left(1-3\kappa\right)\left(I_{4\alpha}-1\right) -\] - -\end_inset - -where -\begin_inset Formula $I_{1}=\tr\mathbf{C}$ -\end_inset - - and -\begin_inset Formula $I_{4\alpha}=\mathbf{a}_{\alpha r}\cdot\mathbf{C}\cdot\mathbf{a}_{\alpha r}$ -\end_inset - -. - The Macaulay brackets around -\begin_inset Formula $\left\langle \tilde{E}_{\alpha}\right\rangle $ -\end_inset - - indicate that this term is zero when -\begin_inset Formula $E_{\alpha}<0$ -\end_inset - - and equal to -\begin_inset Formula $E_{\alpha}$ \end_inset + + +\begin_inset Text - when this strain is positive. +\begin_layout Plain Layout +[ ] \end_layout -\begin_layout Standard -There are two fiber families along the vectors -\begin_inset Formula $\mathbf{a}_{\alpha r}$ -\end_inset - - ( -\begin_inset Formula $\alpha=1,2$ -\end_inset - -), lying in the -\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2}\right\} $ -\end_inset - - plane of the local material axes -\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ -\end_inset - -, making an angle -\begin_inset Formula $\pm\gamma$ -\end_inset - - with respect to -\begin_inset Formula $\mathbf{e}_{1}$ -\end_inset - -. - Each fiber family has a dispersion -\begin_inset Formula $\kappa$ -\end_inset - -, where -\begin_inset Formula $0\le\kappa\le\frac{1}{3}$ -\end_inset - -. - When -\begin_inset Formula $\kappa=0$ -\end_inset - - there is no fiber dispersion, implying that all the fibers in that family - act along the angle -\begin_inset Formula $\pm\gamma$ -\end_inset - -; the value -\begin_inset Formula $\kappa=\frac{1}{3}$ -\end_inset - - represents an isotropic fiber dispersion. - All other intermediate values of -\begin_inset Formula $\kappa$ -\end_inset - - produce a -\begin_inset Formula $\pi-$ -\end_inset - -periodic von Mises fiber distribution, as described in -\begin_inset CommandInset citation -LatexCommand citep -key "Gasser06" -literal "true" - -\end_inset - -. - -\begin_inset Formula $c$ -\end_inset - - is the shear modulus of the ground matrix; -\begin_inset Formula $k_{1}$ -\end_inset - - is the fiber modulus and -\begin_inset Formula $k_{2}$ \end_inset + + + + +\begin_inset Text - is the exponential coefficient. +\begin_layout Plain Layout + \end_layout -\begin_layout Standard -Unlike the uncoupled Holzapfel-Gasser-Ogden material presented in Section -\begin_inset space ~ \end_inset + + +\begin_inset Text - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Holzapfel-Gasser-Ogden" - +\begin_layout Plain Layout +\begin_inset Formula $\nu_{23}$ \end_inset -, this unconstrained version does not enforce isochoric deformation. - This unconstrained model may be used to describe the porous solid matrix - of a biphasic or multiphasic tissue model, where pore volume may change - in response to influx or efflux of interstitial fluid. -\end_layout - -\begin_layout Standard - -\shape italic -Example: -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 7.64 -\end_layout - -\begin_layout LyX-Code - 996.6 -\end_layout - -\begin_layout LyX-Code - 524.6 -\end_layout - -\begin_layout LyX-Code - 49.98 -\end_layout - -\begin_layout LyX-Code - 0.226 -\end_layout - -\begin_layout LyX-Code - 7.64e3 -\end_layout - -\begin_layout LyX-Code - + Poisson's ratio \end_layout -\begin_layout Standard -\begin_inset Newpage newpage \end_inset + + +\begin_inset Text - +\begin_layout Plain Layout +[ ] \end_layout -\begin_layout Subsubsection -Isotropic Elastic -\begin_inset CommandInset label -LatexCommand label -name "subsec:Isotropic-Elastic" - \end_inset + + + + +\begin_inset Text - +\begin_layout Plain Layout + \end_layout -\begin_layout Standard -The material type for isotropic elasticity is -\shape italic -isotropic elastic -\shape default - -\begin_inset Foot -status collapsed +\end_inset + + +\begin_inset Text \begin_layout Plain Layout - This material replaces the now-obsolete -\shape italic -linear elastic -\shape default -and -\shape italic -St.Venant-Kirchhoff -\shape default - materials. - These materials are still available for backward compatibility although - it is recommended to use the -\shape italic -isotropic elastic -\shape default - material instead. -\end_layout - +\begin_inset Formula $\nu_{31}$ \end_inset -. - The following material parameters must be defined: + Poisson's ratio \end_layout -\begin_layout Standard -\align center -\begin_inset VSpace defskip \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +[ ] +\end_layout -\begin_inset Tabular - - - - - +\end_inset + + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53421,7 +53591,10 @@ isotropic elastic \begin_inset Text \begin_layout Plain Layout -Young's modulus +\begin_inset Formula $c$ +\end_inset + + coefficient \end_layout \end_inset @@ -53434,7 +53607,7 @@ Young's modulus \series bold P \series default -] +] \end_layout \end_inset @@ -53445,7 +53618,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53454,7 +53627,10 @@ P \begin_inset Text \begin_layout Plain Layout -Poisson's ratio +\begin_inset Formula $\kappa$ +\end_inset + + bulk modulus \end_layout \end_inset @@ -53463,7 +53639,11 @@ Poisson's ratio \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -53481,174 +53661,207 @@ Poisson's ratio \end_layout \begin_layout Standard -This material is an implementation of a hyperelastic constitutive material - that reduces to the classical linear elastic material for small strains, - but is objective for large deformations and rotations. - The hyperelastic strain-energy function is given by: -\begin_inset Formula -\[ -W=\frac{1}{2}\lambda\left(\tr\mathbf{E}\right)^{2}+\mu\mathbf{E}:\mathbf{E}. -\] - -\end_inset - -Here, -\series bold +The hyperelastic strain energy function is given by +\begin_inset CommandInset citation +LatexCommand citep +key "Ateshian09" +literal "true" -\begin_inset Formula $\mathbf{E}$ \end_inset +, +\begin_inset Formula +\[ +\Psi=\frac{1}{2}c\left(e^{Q}-1\right)+U\left(J\right), +\] -\series default - is the Euler-Lagrange strain tensor and -\begin_inset Formula $\lambda$ -\end_inset - - and -\begin_inset Formula $\mu$ \end_inset - are the Lamé parameters, which are related to the more familiar Young's - modulus -\begin_inset Formula $E$ -\end_inset +where, +\begin_inset Formula +\[ +Q=c^{-1}\sum\limits _{a=1}^{3}\left[2\mu_{a}\mathbf{M}_{a}:\mathbf{E}^{2}+\sum\limits _{b=1}^{3}\lambda_{ab}\left(\mathbf{M}_{a}:\mathbf{E}\right)\left(\mathbf{M}_{b}:\mathbf{E}\right)\right], +\] - and Poisson's ratio -\begin_inset Formula $\nu$ \end_inset - as follows: +and \begin_inset Formula \[ -\lambda=\frac{\nu E}{\left(1+\nu\right)\left(1-2\nu\right)},\mu=\frac{E}{2\left(1+\nu\right)}\,. +U\left(J\right)=\frac{\kappa}{2}\left(\ln J\right)^{2}\,. \] \end_inset -It is often convenient to express the material properties using the bulk - modulus -\begin_inset Formula $K$ +Here, +\begin_inset Formula $\mathbf{E}=\left(\mathbf{C}-\mathbf{I}\right)/2$ \end_inset - and shear modulus -\begin_inset Formula $G$ + and +\begin_inset Formula $\mathbf{M}_{a}=\mathbf{V}_{a}\otimes\mathbf{V}_{a}$ \end_inset -. - To convert to Young's modulus and Poisson's ratio, use the following formulas: - -\begin_inset Formula -\[ -E=\frac{9KG}{3K+G},\quad\nu=\frac{3K-2G}{6K+2G}\,. -\] - +where +\begin_inset Formula $\mathbf{V}_{a}$ \end_inset + defines the initial direction of material axis +\begin_inset Formula $a$ +\end_inset -\shape italic -Remark: -\shape default -Note that although this material is objective, it is not advised to use - this model for large strains since the behavior may be unphysical. - For example, it can be shown that for a uniaxial tension the stress grows - unbounded and the volume tends to zero for finite strains. - Also for large strains, the Young's modulus and Poisson's ratio input values - have little relationship to the actual material parameters. - Therefore it is advisable to use this material only for small strains and/or - large rotations. - To represent isotropic elastic materials under large strain and rotation, - it is best to use some of the other available nonlinear material models - described in this chapter, such as the Holmes-Mow material in Section +. + See Section \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Holmes-Mow" +reference "subsec:Orthotropic-Materials" \end_inset -, the neo-Hookean material in Section -\begin_inset space ~ + on how to define the material axes for orthotropic materials. + The Lamé constants +\begin_inset Formula $\mu_{a}$ \end_inset + ( +\begin_inset Formula $a=1,2,3)$ +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Neo-Hookean" + and +\begin_inset Formula $\lambda_{ab}$ +\end_inset + ( +\begin_inset Formula $a,b=1,2,3$ \end_inset -, or the unconstrained Ogden material in Section -\begin_inset space ~ +, +\begin_inset Formula $\lambda_{ba}=\lambda_{ab})$ \end_inset + are related to Young's moduli +\begin_inset Formula $E_{a}$ +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Ogden-Unconstrained" +, shear moduli +\begin_inset Formula $G_{ab}$ +\end_inset + and Poisson's ratios +\begin_inset Formula $\nu_{ab}$ \end_inset -. + via +\begin_inset Formula +\[ +\begin{aligned} & \left[\begin{array}{cccccc} +\lambda_{11}+2\mu_{1} & \lambda_{12} & \lambda_{13} & 0 & 0 & 0\\ +\lambda_{12} & \lambda_{22}+2\mu_{2} & \lambda_{23} & 0 & 0 & 0\\ +\lambda_{13} & \lambda_{23} & \lambda_{33}+2\mu_{3} & 0 & 0 & 0\\ +0 & 0 & 0 & \frac{1}{2}\left(\mu_{1}+\mu_{2}\right) & 0 & 0\\ +0 & 0 & 0 & 0 & \frac{1}{2}\left(\mu_{2}+\mu_{3}\right) & 0\\ +0 & 0 & 0 & 0 & 0 & \frac{1}{2}\left(\mu_{1}+\mu_{3}\right) +\end{array}\right]^{-1}\\ + & =\left[\begin{array}{cccccc} +\frac{1}{E_{1}} & -\frac{\nu_{12}}{E_{1}} & -\frac{\nu_{13}}{E_{1}} & 0 & 0 & 0\\ +-\frac{\nu_{21}}{E_{2}} & \frac{1}{E_{2}} & -\frac{\nu_{23}}{E_{2}} & 0 & 0 & 0\\ +-\frac{\nu_{31}}{E_{3}} & -\frac{\nu_{32}}{E_{3}} & \frac{1}{E_{3}} & 0 & 0 & 0\\ +0 & 0 & 0 & \frac{1}{G_{12}} & 0 & 0\\ +0 & 0 & 0 & 0 & \frac{1}{G_{23}} & 0\\ +0 & 0 & 0 & 0 & 0 & \frac{1}{G_{31}} +\end{array}\right] +\end{aligned} +\] + +\end_inset + +The orthotropic Lamé parameters should produce a positive definite stiffness + matrix. \end_layout \begin_layout Standard \shape italic -Example: +Example +\shape default +: \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 1000.0 + 124 \end_layout \begin_layout LyX-Code - 0.45 + 124 \end_layout \begin_layout LyX-Code - + 36 \end_layout -\begin_layout Standard -\begin_inset Newpage newpage -\end_inset +\begin_layout LyX-Code + 67 +\end_layout +\begin_layout LyX-Code + 40 +\end_layout +\begin_layout LyX-Code + 40 \end_layout -\begin_layout Subsubsection -Orthotropic Elastic -\begin_inset CommandInset label -LatexCommand label -name "subsec:Orthotropic-Elastic" +\begin_layout LyX-Code + -0.075 +\end_layout -\end_inset +\begin_layout LyX-Code + 0.87 +\end_layout + +\begin_layout LyX-Code + 0.26 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 120 +\end_layout +\begin_layout LyX-Code + +\end_layout +\begin_layout Subsubsection +Gent Compressible \end_layout \begin_layout Standard -The material type for orthotropic elasticity is +The compressible Gent material is defined using the +\emph on + \begin_inset Quotes eld \end_inset - -\shape italic -orthotropic elastic +compressible Gent \begin_inset Quotes erd \end_inset -\shape default -. - The following material parameters must be defined: +\emph default + type string. + It defines the following parameters. + \end_layout \begin_layout Standard @@ -53658,7 +53871,7 @@ orthotropic elastic \begin_inset Tabular - + @@ -53668,7 +53881,7 @@ orthotropic elastic \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53677,7 +53890,7 @@ orthotropic elastic \begin_inset Text \begin_layout Plain Layout -Young's modulus in the x-direction +Shear modulus \end_layout \end_inset @@ -53690,7 +53903,7 @@ Young's modulus in the x-direction \series bold P \series default -] +] \end_layout \end_inset @@ -53701,7 +53914,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53710,7 +53923,18 @@ P \begin_inset Text \begin_layout Plain Layout -Young's modulus in the y-direction +\begin_inset Formula $J_{m}=I_{m}-1$ +\end_inset + +, with +\begin_inset Formula $I_{m}$ +\end_inset + + max value for first invariant +\begin_inset Formula $I_{1}$ +\end_inset + + \end_layout \end_inset @@ -53723,32 +53947,32 @@ Young's modulus in the y-direction \series bold P \series default -] +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Young's modulus in the z-direction +Bulk modulus \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -53756,117 +53980,137 @@ Young's modulus in the z-direction \series bold P \series default -] +] \end_layout \end_inset - - -\begin_inset Text + -\begin_layout Plain Layout - -\end_layout +\end_inset + +\begin_inset VSpace defskip \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Shear modulus in the xy-plane + +\end_layout + +\begin_layout Standard +The strain energy of this material is defined as follows, \end_layout +\begin_layout Standard +\begin_inset Formula +\[ +\Psi_{r}=-\frac{\mu J_{m}}{2}\ln\left(1-\frac{I_{1}-3}{J_{m}}\right)+\frac{\kappa}{2}\left(\frac{J^{2}-1}{2}-\ln J\right)^{4} +\] + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] + \end_layout +\begin_layout Standard +Here, +\begin_inset Formula $\mu$ \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout - + is the shear modulus. + \end_layout -\end_inset - - -\begin_inset Text +\begin_layout Standard -\begin_layout Plain Layout -Shear modulus in the yz-plane +\shape italic +Example: \end_layout -\end_inset - - -\begin_inset Text +\begin_layout LyX-Code + +\end_layout -\begin_layout Plain Layout -[ -\series bold -P -\series default -] +\begin_layout LyX-Code + 3.14 \end_layout -\end_inset - - - - -\begin_inset Text +\begin_layout LyX-Code + 1.5 +\end_layout -\begin_layout Plain Layout - +\begin_layout LyX-Code + 1e5 +\end_layout + +\begin_layout LyX-Code + \end_layout +\begin_layout Subsubsection +Holmes-Mow +\begin_inset CommandInset label +LatexCommand label +name "subsec:Holmes-Mow" + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Shear modulus in the xz-plane + \end_layout +\begin_layout Standard +The material type for the Holmes-Mow material +\begin_inset CommandInset citation +LatexCommand citep +key "Holmes90" +literal "true" + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] + is +\shape italic +Holmes-Mow +\shape default +. + This isotropic hyperelastic material has been used to represent the solid + matrix of articular cartilage +\begin_inset CommandInset citation +LatexCommand citep +key "Holmes90,Ateshian97" +literal "true" + +\end_inset + + and intervertebral disc +\begin_inset CommandInset citation +LatexCommand citep +key "Iatridis98" +literal "true" + +\end_inset + +. + The following material parameters must be defined: \end_layout +\begin_layout Standard +\align center +\begin_inset VSpace defskip \end_inset - - + + +\begin_inset Tabular + + + + + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53875,7 +54119,7 @@ P \begin_inset Text \begin_layout Plain Layout -Poisson's ratio between x- and y-direction +Young's modulus \end_layout \end_inset @@ -53884,7 +54128,11 @@ Poisson's ratio between x- and y-direction \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -53895,7 +54143,7 @@ Poisson's ratio between x- and y-direction \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53904,7 +54152,7 @@ Poisson's ratio between x- and y-direction \begin_inset Text \begin_layout Plain Layout -Poisson's ratio between y- and z-direction +Poisson's ratio \end_layout \end_inset @@ -53924,7 +54172,7 @@ Poisson's ratio between y- and z-direction \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -53933,7 +54181,7 @@ Poisson's ratio between y- and z-direction \begin_inset Text \begin_layout Plain Layout -Poisson's ratio between z- and x-direction +Exponential stiffening coefficient \end_layout \end_inset @@ -53960,111 +54208,87 @@ Poisson's ratio between z- and x-direction \end_layout \begin_layout Standard -The stress-strain relation for this material is given by +The coupled hyperelastic strain-energy function for this material is given + by +\begin_inset CommandInset citation +LatexCommand citep +key "Holmes90" +literal "true" + +\end_inset + +: \begin_inset Formula \[ -\left[\begin{array}{c} -E_{11}\\ -E_{22}\\ -E_{33}\\ -2E_{23}\\ -2E_{31}\\ -2E_{12} -\end{array}\right]=\left[\begin{array}{cccccc} -1/E_{1} & -\nu_{21}/E_{2} & -\nu_{31}/E_{3} & 0 & 0 & 0\\ --\nu_{12}/E_{1} & 1/E_{2} & -\nu_{32}/E_{3} & 0 & 0 & 0\\ --\nu_{13}/E_{1} & -\nu_{23}/E_{2} & 1/E_{3} & 0 & 0 & 0\\ -0 & 0 & 0 & 1/G_{23} & 0 & 0\\ -0 & 0 & 0 & 0 & 1/G_{31} & 0\\ -0 & 0 & 0 & 0 & 0 & 1/G_{12} -\end{array}\right]\left[\begin{array}{c} -T_{11}\\ -T_{22}\\ -T_{33}\\ -T_{23}\\ -T_{31}\\ -T_{12} -\end{array}\right] +W\left(I_{1},I_{2},J\right)=\frac{1}{2}c\left(e^{Q}-1\right), \] \end_inset -Material axes may be specified as described in Section -\begin_inset space ~ +where +\begin_inset Formula $I_{1}$ \end_inset - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Orthotropic-Materials" - + and +\begin_inset Formula $I_{2}$ \end_inset -. -\end_layout - -\begin_layout Standard - -\shape italic -Example -\shape default -: -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout + are the first and second invariants of the right Cauchy-Green tensor and + +\begin_inset Formula $J$ +\end_inset -\begin_layout LyX-Code - 0.866,0.5,0 -\end_layout +is the jacobian of the deformation gradient. + Furthermore, +\begin_inset Formula +\[ +\begin{aligned}Q & =\frac{\beta}{\lambda+2\mu}\left[\left(2\mu-\lambda\right)\left(I_{1}-3\right)+\lambda\left(I_{2}-3\right)-\left(\lambda+2\mu\right)\ln J^{2}\right]\\ +c & =\frac{\lambda+2\mu}{2\beta} +\end{aligned} +\,, +\] -\begin_layout LyX-Code - -0.5,0.866,0 -\end_layout +\end_inset -\begin_layout LyX-Code - -\end_layout +and +\begin_inset Formula $\lambda$ +\end_inset -\begin_layout LyX-Code - 1 -\end_layout + and +\begin_inset Formula $\mu$ +\end_inset -\begin_layout LyX-Code - 2 -\end_layout + are the Lamé parameters which are related to the more familiar Young's + modulus and Poisson's ratio in the usual manner: +\begin_inset Formula +\[ +\begin{aligned}\lambda & =\frac{E}{\left(1+\nu\right)\left(1-2\nu\right)}\\ +\mu & =\frac{E}{2\left(1+\nu\right)} +\end{aligned} +\,. +\] -\begin_layout LyX-Code - 3 -\end_layout +\end_inset -\begin_layout LyX-Code - 0 -\end_layout -\begin_layout LyX-Code - 0 +\shape italic +Example: \end_layout \begin_layout LyX-Code - 0 + \end_layout \begin_layout LyX-Code - 1 + 1 \end_layout \begin_layout LyX-Code - 1 + 0.35 \end_layout \begin_layout LyX-Code - 1 + 0.25 \end_layout \begin_layout LyX-Code @@ -54079,10 +54303,10 @@ Example \end_layout \begin_layout Subsubsection -Orthotropic CLE +Holzapfel-Gasser-Ogden Unconstrained \begin_inset CommandInset label LatexCommand label -name "subsec:Orthotropic-CLE" +name "subsec:HGO-Unconstrained" \end_inset @@ -54090,13 +54314,21 @@ name "subsec:Orthotropic-CLE" \end_layout \begin_layout Standard -The material type for a conewise linear elastic (CLE) material with orthtropic - symmetry is -\shape italic -orthotropic CLE -\shape default +The material type for the unconstrained Holzapfel-Gasser-Ogden material + +\begin_inset CommandInset citation +LatexCommand citep +key "Gasser06" +literal "true" + +\end_inset + + is +\emph on +HGO unconstrained +\emph default . - The following parameters must be defined: + The following material parameters must be defined: \end_layout \begin_layout Standard @@ -54106,7 +54338,7 @@ orthotropic CLE \begin_inset Tabular - + @@ -54116,7 +54348,7 @@ orthotropic CLE \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54125,11 +54357,7 @@ orthotropic CLE \begin_inset Text \begin_layout Plain Layout -Tensile diagonal first Lamé coefficient along direction 1 -\begin_inset Formula $\lambda_{+11}$ -\end_inset - - +Shear modulus of ground matrix \end_layout \end_inset @@ -54142,7 +54370,7 @@ Tensile diagonal first Lamé coefficient along direction 1 \series bold P \series default -] +] \end_layout \end_inset @@ -54153,7 +54381,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54162,11 +54390,7 @@ P \begin_inset Text \begin_layout Plain Layout -Tensile diagonal first Lamé coefficient along direction 2 -\begin_inset Formula $\lambda_{+22}$ -\end_inset - - +Fiber modulus \end_layout \end_inset @@ -54179,7 +54403,7 @@ Tensile diagonal first Lamé coefficient along direction 2 \series bold P \series default -] +] \end_layout \end_inset @@ -54190,7 +54414,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54199,11 +54423,7 @@ P \begin_inset Text \begin_layout Plain Layout -Tensile diagonal first Lamé coefficient along direction 3 -\begin_inset Formula $\lambda_{+33}$ -\end_inset - - +Fiber exponential coefficient \end_layout \end_inset @@ -54216,28 +54436,28 @@ Tensile diagonal first Lamé coefficient along direction 3 \series bold P \series default -] +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Compressive diagonal first Lamé coefficient along direction 1 -\begin_inset Formula $\lambda_{-11}$ +Fiber mean orientation angle +\begin_inset Formula $\gamma$ \end_inset @@ -54245,81 +54465,69 @@ Compressive diagonal first Lamé coefficient along direction 1 \end_inset - + \begin_inset Text \begin_layout Plain Layout [ \series bold -P +deg \series default -] +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Compressive diagonal first Lamé coefficient along direction 2 -\begin_inset Formula $\lambda_{-22}$ -\end_inset - - +Fiber dispersion \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Compressive diagonal first Lamé coefficient along direction 3 -\begin_inset Formula $\lambda_{-33}$ -\end_inset - - +Bulk modulus \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -54327,166 +54535,272 @@ Compressive diagonal first Lamé coefficient along direction 3 \series bold P \series default -] +] \end_layout \end_inset - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Off-diagonal first Lamé coefficient in 1-2 plane -\begin_inset Formula $\lambda_{12}$ + +\begin_inset VSpace defskip \end_inset \end_layout +\begin_layout Standard +The strain-energy function is given by: +\begin_inset Formula +\[ +\begin{aligned}\Psi_{r} & =\frac{c}{2}\left(I_{1}-3\right)-c\ln J+\frac{k_{1}}{2k_{2}}\sum_{\alpha}\left(\exp\left(k_{2}\left\langle E_{\alpha}\right\rangle ^{2}\right)-1\right)\\ + & +\frac{K_{0}}{2}\left(\frac{J^{2}-1}{2}-\ln J\right) +\end{aligned} +\] + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] -\end_layout +The fiber strain is +\begin_inset Formula +\[ +E_{\alpha}=\kappa\left(I_{1}-3\right)+\left(1-3\kappa\right)\left(I_{4\alpha}-1\right) +\] \end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout +where +\begin_inset Formula $I_{1}=\tr\mathbf{C}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Off-diagonal first Lamé coefficient in 2-3 plane -\begin_inset Formula $\lambda_{23}$ + and +\begin_inset Formula $I_{4\alpha}=\mathbf{a}_{\alpha r}\cdot\mathbf{C}\cdot\mathbf{a}_{\alpha r}$ \end_inset +. + The Macaulay brackets around +\begin_inset Formula $\left\langle \tilde{E}_{\alpha}\right\rangle $ +\end_inset -\end_layout + indicate that this term is zero when +\begin_inset Formula $E_{\alpha}<0$ +\end_inset + and equal to +\begin_inset Formula $E_{\alpha}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] + when this strain is positive. \end_layout +\begin_layout Standard +There are two fiber families along the vectors +\begin_inset Formula $\mathbf{a}_{\alpha r}$ \end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout + ( +\begin_inset Formula $\alpha=1,2$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Off-diagonal first Lamé coefficient in 3-1 plane -\begin_inset Formula $\lambda_{31}$ +), lying in the +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2}\right\} $ \end_inset + plane of the local material axes +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset -\end_layout +, making an angle +\begin_inset Formula $\pm\gamma$ +\end_inset + with respect to +\begin_inset Formula $\mathbf{e}_{1}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] -\end_layout +. + Each fiber family has a dispersion +\begin_inset Formula $\kappa$ +\end_inset +, where +\begin_inset Formula $0\le\kappa\le\frac{1}{3}$ \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout - +. + When +\begin_inset Formula $\kappa=0$ +\end_inset + + there is no fiber dispersion, implying that all the fibers in that family + act along the angle +\begin_inset Formula $\pm\gamma$ +\end_inset + +; the value +\begin_inset Formula $\kappa=\frac{1}{3}$ +\end_inset + + represents an isotropic fiber dispersion. + All other intermediate values of +\begin_inset Formula $\kappa$ +\end_inset + + produce a +\begin_inset Formula $\pi-$ +\end_inset + +periodic von Mises fiber distribution, as described in +\begin_inset CommandInset citation +LatexCommand citep +key "Gasser06" +literal "true" + +\end_inset + +. + +\begin_inset Formula $c$ +\end_inset + + is the shear modulus of the ground matrix; +\begin_inset Formula $k_{1}$ +\end_inset + + is the fiber modulus and +\begin_inset Formula $k_{2}$ +\end_inset + + is the exponential coefficient. \end_layout +\begin_layout Standard +Unlike the uncoupled Holzapfel-Gasser-Ogden material presented in Section +\begin_inset space ~ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Second Lamé coefficient along direction 1 -\begin_inset Formula $\mu_{1}$ + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Holzapfel-Gasser-Ogden" + +\end_inset + +, this unconstrained version does not enforce isochoric deformation. + This unconstrained model may be used to describe the porous solid matrix + of a biphasic or multiphasic tissue model, where pore volume may change + in response to influx or efflux of interstitial fluid. +\end_layout + +\begin_layout Standard + +\shape italic +Example: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 7.64 +\end_layout + +\begin_layout LyX-Code + 996.6 +\end_layout + +\begin_layout LyX-Code + 524.6 +\end_layout + +\begin_layout LyX-Code + 49.98 +\end_layout + +\begin_layout LyX-Code + 0.226 +\end_layout + +\begin_layout LyX-Code + 7.64e3 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage \end_inset \end_layout +\begin_layout Subsubsection +Isotropic Elastic +\begin_inset CommandInset label +LatexCommand label +name "subsec:Isotropic-Elastic" + \end_inset - - -\begin_inset Text + + +\end_layout + +\begin_layout Standard +The material type for isotropic elasticity is +\shape italic +isotropic elastic +\shape default + +\begin_inset Foot +status collapsed \begin_layout Plain Layout -[ -\series bold -P -\series default -] + This material replaces the now-obsolete +\shape italic +linear elastic +\shape default +and +\shape italic +St.Venant-Kirchhoff +\shape default + materials. + These materials are still available for backward compatibility although + it is recommended to use the +\shape italic +isotropic elastic +\shape default + material instead. \end_layout \end_inset - - + +. + The following material parameters must be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54495,11 +54809,7 @@ P \begin_inset Text \begin_layout Plain Layout -Second Lamé coefficient along direction 2 -\begin_inset Formula $\mu_{2}$ -\end_inset - - +Young's modulus \end_layout \end_inset @@ -54523,7 +54833,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54532,11 +54842,7 @@ P \begin_inset Text \begin_layout Plain Layout -Second Lamé coefficient along direction 3 -\begin_inset Formula $\mu_{3}$ -\end_inset - - +Poisson's ratio \end_layout \end_inset @@ -54545,11 +54851,7 @@ Second Lamé coefficient along direction 3 \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[ ] \end_layout \end_inset @@ -54567,124 +54869,135 @@ P \end_layout \begin_layout Standard -This bimodular elastic material is the orthotropic conewise linear elastic - material described by Curnier et al. - -\begin_inset CommandInset citation -LatexCommand citep -key "Curnier94" -literal "true" - -\end_inset - -. - It is derived from the following hyperelastic strain-energy function: +This material is an implementation of a hyperelastic constitutive material + that reduces to the classical linear elastic material for small strains, + but is objective for large deformations and rotations. + The hyperelastic strain-energy function is given by: \begin_inset Formula \[ -\Psi_{r}=\sum\limits _{a=1}^{3}\mu_{a}\mathbf{A}_{a}^{r}:\mathbf{E}^{2}+\frac{1}{2}\lambda_{aa}\left[\mathbf{A}_{a}^{r}:\mathbf{E}\right]\left(\mathbf{A}_{a}^{r}:\mathbf{E}\right)^{2}+\sum\limits _{\begin{array}{c} -b=1\\ -b\ne a -\end{array}}^{3}\frac{1}{2}\lambda_{ab}\left(\mathbf{A}_{a}^{r}:\mathbf{E}\right)\left(\mathbf{A}_{b}^{r}:\mathbf{E}\right) +W=\frac{1}{2}\lambda\left(\tr\mathbf{E}\right)^{2}+\mu\mathbf{E}:\mathbf{E}. \] \end_inset -where -\begin_inset Formula $\lambda_{ba}=\lambda_{ab}$ +Here, +\series bold + +\begin_inset Formula $\mathbf{E}$ +\end_inset + + +\series default + is the Euler-Lagrange strain tensor and +\begin_inset Formula $\lambda$ \end_inset and +\begin_inset Formula $\mu$ +\end_inset + + are the Lamé parameters, which are related to the more familiar Young's + modulus +\begin_inset Formula $E$ +\end_inset + + and Poisson's ratio +\begin_inset Formula $\nu$ +\end_inset + + as follows: \begin_inset Formula \[ -\lambda_{aa}\left[\mathbf{A}_{a}^{r}:\mathbf{E}\right]=\begin{cases} -\lambda_{+aa} & \mathbf{A}_{a}^{r}:\mathbf{E}\geqslant0\\ -\lambda_{-aa} & \mathbf{A}_{a}^{r}:\mathbf{E}<0 -\end{cases},\quad a=1,2,3 +\lambda=\frac{\nu E}{\left(1+\nu\right)\left(1-2\nu\right)},\mu=\frac{E}{2\left(1+\nu\right)}\,. \] \end_inset -Here, -\begin_inset Formula $\mathbf{E}$ +It is often convenient to express the material properties using the bulk + modulus +\begin_inset Formula $K$ \end_inset - is the Lagrangian strain tensor and -\begin_inset Formula $\mathbf{A}_{a}^{r}=\mathbf{a}_{a}^{r}\otimes\mathbf{a}_{a}^{r}$ + and shear modulus +\begin_inset Formula $G$ \end_inset -, where -\begin_inset Formula $\mathbf{a}_{a}^{r}$ +. + To convert to Young's modulus and Poisson's ratio, use the following formulas: + +\begin_inset Formula +\[ +E=\frac{9KG}{3K+G},\quad\nu=\frac{3K-2G}{6K+2G}\,. +\] + \end_inset - ( -\begin_inset Formula $a=1,2,3)$ + +\shape italic +Remark: +\shape default +Note that although this material is objective, it is not advised to use + this model for large strains since the behavior may be unphysical. + For example, it can be shown that for a uniaxial tension the stress grows + unbounded and the volume tends to zero for finite strains. + Also for large strains, the Young's modulus and Poisson's ratio input values + have little relationship to the actual material parameters. + Therefore it is advisable to use this material only for small strains and/or + large rotations. + To represent isotropic elastic materials under large strain and rotation, + it is best to use some of the other available nonlinear material models + described in this chapter, such as the Holmes-Mow material in Section +\begin_inset space ~ \end_inset - are orthonormal vectors aligned with the material axes. - This material response was originally formulated for infinitesimal strain - analyses; its behavior under finite strains may not be physically realistic. -\end_layout -\begin_layout Standard +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Holmes-Mow" -\shape italic -Example: -\end_layout +\end_inset -\begin_layout LyX-Code - -\end_layout +, the neo-Hookean material in Section +\begin_inset space ~ +\end_inset -\begin_layout LyX-Code - 1 -\end_layout -\begin_layout LyX-Code - 13.01 -\end_layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Neo-Hookean" -\begin_layout LyX-Code - 13.01 -\end_layout +\end_inset -\begin_layout LyX-Code - 13.01 -\end_layout +, or the unconstrained Ogden material in Section +\begin_inset space ~ +\end_inset -\begin_layout LyX-Code - 0.49 -\end_layout -\begin_layout LyX-Code - 0.49 -\end_layout +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Ogden-Unconstrained" -\begin_layout LyX-Code - 0.49 -\end_layout +\end_inset -\begin_layout LyX-Code - 0.66 +. \end_layout -\begin_layout LyX-Code - 0.66 -\end_layout +\begin_layout Standard -\begin_layout LyX-Code - 0.66 +\shape italic +Example: \end_layout \begin_layout LyX-Code - 0.16 + \end_layout \begin_layout LyX-Code - 0.16 + 1000.0 \end_layout \begin_layout LyX-Code - 0.16 + 0.45 \end_layout \begin_layout LyX-Code @@ -54699,10 +55012,10 @@ Example: \end_layout \begin_layout Subsubsection -Osmotic Pressure from Virial Expansion +Orthotropic Elastic \begin_inset CommandInset label LatexCommand label -name "subsec:Osmotic-Pressure-Virial" +name "subsec:Orthotropic-Elastic" \end_inset @@ -54710,20 +55023,20 @@ name "subsec:Osmotic-Pressure-Virial" \end_layout \begin_layout Standard -The material type for osmotic pressure from virial expansion is +The material type for orthotropic elasticity is \begin_inset Quotes eld \end_inset \shape italic -osmotic virial expansion -\shape default - +orthotropic elastic \begin_inset Quotes erd \end_inset + +\shape default . - The following material parameters need to be defined: + The following material parameters must be defined: \end_layout \begin_layout Standard @@ -54733,17 +55046,17 @@ osmotic virial expansion \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54752,11 +55065,7 @@ osmotic virial expansion \begin_inset Text \begin_layout Plain Layout -Fluid volume fraction in reference (strain-free) configuration, -\begin_inset Formula $\varphi_{r}^{w}$ -\end_inset - - +Young's modulus in the x-direction \end_layout \end_inset @@ -54765,7 +55074,11 @@ Fluid volume fraction in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -54776,7 +55089,7 @@ Fluid volume fraction in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54785,12 +55098,7 @@ Fluid volume fraction in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout -Concentration of interstitial solute causing the osmotic pressure (moles - per volume of the mixture in the reference configuration), -\begin_inset Formula $c_{r}$ -\end_inset - - +Young's modulus in the y-direction \end_layout \end_inset @@ -54801,16 +55109,8 @@ Concentration of interstitial solute causing the osmotic pressure (moles \begin_layout Plain Layout [ \series bold -n -\series default -/ -\series bold -L +P \series default - -\begin_inset Formula $^{\mathrm{3}}$ -\end_inset - ] \end_layout @@ -54822,7 +55122,7 @@ L \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54831,11 +55131,7 @@ L \begin_inset Text \begin_layout Plain Layout -First virial coefficient -\begin_inset Formula $c_{1}$ -\end_inset - - +Young's modulus in the z-direction \end_layout \end_inset @@ -54846,19 +55142,7 @@ First virial coefficient \begin_layout Plain Layout [ \series bold -F -\series default - -\begin_inset Formula $\cdot$ -\end_inset - - -\series bold -L -\series default -/ -\series bold -n +P \series default ] \end_layout @@ -54871,7 +55155,7 @@ n \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -54880,11 +55164,7 @@ n \begin_inset Text \begin_layout Plain Layout -Second virial coefficient -\begin_inset Formula $c_{2}$ -\end_inset - - +Shear modulus in the xy-plane \end_layout \end_inset @@ -54895,28 +55175,8 @@ Second virial coefficient \begin_layout Plain Layout [ \series bold -F -\series default - -\begin_inset Formula $\cdot$ -\end_inset - - -\series bold -L -\series default - -\begin_inset Formula $^{\mathrm{4}}$ -\end_inset - -/ -\series bold -n +P \series default - -\begin_inset Formula $^{\mathrm{2}}$ -\end_inset - ] \end_layout @@ -54924,111 +55184,211 @@ n - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Third virial coefficient -\begin_inset Formula $c_{3}$ -\end_inset - - +Shear modulus in the yz-plane \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout [ \series bold -F +P \series default +] +\end_layout -\begin_inset Formula $\cdot$ \end_inset + + + + +\begin_inset Text +\begin_layout Plain Layout + +\end_layout -\series bold -L -\series default +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Shear modulus in the xz-plane +\end_layout -\begin_inset Formula $^{\mathrm{7}}$ \end_inset + + +\begin_inset Text -/ +\begin_layout Plain Layout +[ \series bold -n +P \series default +] +\end_layout -\begin_inset Formula $^{\mathrm{3}}$ \end_inset + + + + +\begin_inset Text -] +\begin_layout Plain Layout + \end_layout \end_inset - - + +\begin_inset Text + +\begin_layout Plain Layout +Poisson's ratio between x- and y-direction +\end_layout \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +[ ] +\end_layout -\begin_inset VSpace defskip \end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout +\end_inset + + +\begin_inset Text +\begin_layout Plain Layout +Poisson's ratio between y- and z-direction \end_layout -\begin_layout Standard -The Cauchy stress for this material is -\begin_inset Formula -\[ -\boldsymbol{\sigma}=-\pi\mathbf{I}, -\] +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout \end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout -where -\begin_inset Formula $\pi$ \end_inset + + +\begin_inset Text - is the osmotic pressure, given by -\begin_inset Formula -\[ -\pi=c_{1}c+c_{2}c^{2}+c_{3}c^{3},\quad c=\frac{\varphi_{r}^{w}c_{r}}{J-1+\varphi_{r}^{w}}\,, -\] +\begin_layout Plain Layout +Poisson's ratio between z- and x-direction +\end_layout \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +[ ] +\end_layout -\begin_inset Formula $c$ \end_inset + + + - is the solute concentration in the current configuration, and -\begin_inset Formula $J=\det\mathbf{F}$ \end_inset - is the relative volume. + +\begin_inset VSpace defskip +\end_inset + + \end_layout \begin_layout Standard -This osmotic swelling pressure in the interstitial fluid of a porous material - represents an entropic mechanism whose magnitude is independent of the - external bath osmolarity. - Typically, this material should be used in a solid mixture where the swelling - pressure is resisted by a solid matrix in tension. +The stress-strain relation for this material is given by +\begin_inset Formula +\[ +\left[\begin{array}{c} +E_{11}\\ +E_{22}\\ +E_{33}\\ +2E_{23}\\ +2E_{31}\\ +2E_{12} +\end{array}\right]=\left[\begin{array}{cccccc} +1/E_{1} & -\nu_{21}/E_{2} & -\nu_{31}/E_{3} & 0 & 0 & 0\\ +-\nu_{12}/E_{1} & 1/E_{2} & -\nu_{32}/E_{3} & 0 & 0 & 0\\ +-\nu_{13}/E_{1} & -\nu_{23}/E_{2} & 1/E_{3} & 0 & 0 & 0\\ +0 & 0 & 0 & 1/G_{23} & 0 & 0\\ +0 & 0 & 0 & 0 & 1/G_{31} & 0\\ +0 & 0 & 0 & 0 & 0 & 1/G_{12} +\end{array}\right]\left[\begin{array}{c} +T_{11}\\ +T_{22}\\ +T_{33}\\ +T_{23}\\ +T_{31}\\ +T_{12} +\end{array}\right] +\] + +\end_inset + +Material axes may be specified as described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Orthotropic-Materials" + +\end_inset + +. \end_layout \begin_layout Standard @@ -55040,75 +55400,63 @@ Example \end_layout \begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0.8 + \end_layout \begin_layout LyX-Code - 100 + \end_layout \begin_layout LyX-Code - 2.436e-6 + 0.866,0.5,0 \end_layout \begin_layout LyX-Code - 0 + -0.5,0.866,0 \end_layout \begin_layout LyX-Code - 0 + \end_layout \begin_layout LyX-Code - + 1 \end_layout \begin_layout LyX-Code - + 2 \end_layout \begin_layout LyX-Code - + 3 \end_layout \begin_layout LyX-Code - + 0 \end_layout \begin_layout LyX-Code - + 0 \end_layout \begin_layout LyX-Code - + 0 \end_layout \begin_layout LyX-Code - 0,0 + 1 \end_layout \begin_layout LyX-Code - 1,1 + 1 \end_layout \begin_layout LyX-Code - + 1 \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout Standard @@ -55119,10 +55467,10 @@ Example \end_layout \begin_layout Subsubsection -Natural Neo-Hookean +Orthotropic CLE \begin_inset CommandInset label LatexCommand label -name "subsec:Natural-Neo-Hookean" +name "subsec:Orthotropic-CLE" \end_inset @@ -55130,9 +55478,10 @@ name "subsec:Natural-Neo-Hookean" \end_layout \begin_layout Standard -The material type for a natural Neo-Hookean material is +The material type for a conewise linear elastic (CLE) material with orthtropic + symmetry is \shape italic -natural neo-Hookean +orthotropic CLE \shape default . The following parameters must be defined: @@ -55145,7 +55494,7 @@ natural neo-Hookean \begin_inset Tabular - + @@ -55155,7 +55504,7 @@ natural neo-Hookean \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -55164,8 +55513,8 @@ natural neo-Hookean \begin_inset Text \begin_layout Plain Layout -Young's modulus -\begin_inset Formula $E$ +Tensile diagonal first Lamé coefficient along direction 1 +\begin_inset Formula $\lambda_{+11}$ \end_inset @@ -55181,28 +55530,28 @@ Young's modulus \series bold P \series default -] +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Poisson's ratio -\begin_inset Formula $\nu$ +Tensile diagonal first Lamé coefficient along direction 2 +\begin_inset Formula $\lambda_{+22}$ \end_inset @@ -55210,185 +55559,211 @@ Poisson's ratio \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset - + + +\begin_inset Text -\end_inset +\begin_layout Plain Layout + +\end_layout +\end_inset + + +\begin_inset Text -\begin_inset VSpace defskip +\begin_layout Plain Layout +Tensile diagonal first Lamé coefficient along direction 3 +\begin_inset Formula $\lambda_{+33}$ \end_inset \end_layout -\begin_layout Standard -This model describes an unconstrained Neo-Hookean material using the natural - strain tensor -\begin_inset CommandInset citation -LatexCommand citep -key "Criscione00" -literal "true" - \end_inset + + +\begin_inset Text -. - It has a non-linear stress-strain behavior, but reduces to the classical - linear elasticity model for small strains -\shape italic -and -\shape default - small rotations. - It is derived from the following hyperelastic strain-energy function: -\begin_inset Formula -\[ -W=\frac{\kappa}{2}K_{1}^{2}+\mu K_{2}^{2}, -\] +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout \end_inset + + + + +\begin_inset Text -where -\begin_inset Formula $\kappa$ -\end_inset +\begin_layout Plain Layout + +\end_layout - is the bulk modulus and -\begin_inset Formula $\mu$ \end_inset + + +\begin_inset Text - is the shear modulus, -\begin_inset Formula -\[ -\kappa=\frac{E}{3\left(1-2\nu\right)}\,,\quad\mu=\frac{E}{2\left(1+\nu\right)} -\] - +\begin_layout Plain Layout +Compressive diagonal first Lamé coefficient along direction 1 +\begin_inset Formula $\lambda_{-11}$ \end_inset -Here, -\begin_inset Formula $K_{1}$ -\end_inset - and -\begin_inset Formula $K_{2}$ +\end_layout + \end_inset + + +\begin_inset Text - are the first and second invariants of the left natural (Hencky) strain - tensor +\begin_layout Plain Layout +[ \series bold +P +\series default +] +\end_layout -\begin_inset Formula $\boldsymbol{\eta}=\ln\mathbf{V}$ \end_inset + + + + +\begin_inset Text +\begin_layout Plain Layout + +\end_layout -\series default - where -\begin_inset Formula $\mathbf{V}$ \end_inset + + +\begin_inset Text - is the left stretch tensor in the polar decomposition -\begin_inset Formula $\mathbf{F}=\mathbf{V}\cdot\mathbf{R}$ +\begin_layout Plain Layout +Compressive diagonal first Lamé coefficient along direction 2 +\begin_inset Formula $\lambda_{-22}$ \end_inset -. + \end_layout -\begin_layout Standard -This material model uses a standard displacement-based element formulation, - so care must be taken when modeling materials with nearly-incompressible - material behavior to avoid element locking. - For this case, use the -\shape italic -Mooney-Rivlin -\shape default -material described in Section -\begin_inset space ~ \end_inset + + +\begin_inset Text - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Mooney-Rivlin" +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout \end_inset + + + + +\begin_inset Text -. +\begin_layout Plain Layout + \end_layout -\begin_layout Standard +\end_inset + + +\begin_inset Text -\shape italic -Example: -\end_layout +\begin_layout Plain Layout +Compressive diagonal first Lamé coefficient along direction 3 +\begin_inset Formula $\lambda_{-33}$ +\end_inset -\begin_layout LyX-Code - -\end_layout -\begin_layout LyX-Code - 200e3 \end_layout -\begin_layout LyX-Code - 0.3 -\end_layout +\end_inset + + +\begin_inset Text -\begin_layout LyX-Code - +\begin_layout Plain Layout +[ +\series bold +P +\series default +] \end_layout -\begin_layout Standard -\begin_inset Newpage newpage \end_inset + + + + +\begin_inset Text - +\begin_layout Plain Layout + \end_layout -\begin_layout Subsubsection -Neo-Hookean -\begin_inset CommandInset label -LatexCommand label -name "subsec:Neo-Hookean" - \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +Off-diagonal first Lamé coefficient in 1-2 plane +\begin_inset Formula $\lambda_{12}$ +\end_inset -\end_layout -\begin_layout Standard -The material type for a Neo-Hookean material is -\shape italic -neo-Hookean -\shape default -. - The following parameters must be defined: \end_layout -\begin_layout Standard -\align center -\begin_inset VSpace defskip \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout -\begin_inset Tabular - - - - - +\end_inset + + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -55397,7 +55772,11 @@ neo-Hookean \begin_inset Text \begin_layout Plain Layout -Young's modulus +Off-diagonal first Lamé coefficient in 2-3 plane +\begin_inset Formula $\lambda_{23}$ +\end_inset + + \end_layout \end_inset @@ -55417,220 +55796,63 @@ P - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Poisson's ratio +Off-diagonal first Lamé coefficient in 3-1 plane +\begin_inset Formula $\lambda_{31}$ +\end_inset + + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset - + + +\begin_inset Text -\end_inset +\begin_layout Plain Layout + +\end_layout +\end_inset + + +\begin_inset Text -\begin_inset VSpace defskip +\begin_layout Plain Layout +Second Lamé coefficient along direction 1 +\begin_inset Formula $\mu_{1}$ \end_inset \end_layout -\begin_layout Standard -This model describes an unconstrained Neo-Hookean material -\begin_inset CommandInset citation -LatexCommand citep -key "Bonet97" -literal "true" - -\end_inset - -. - It has a non-linear stress-strain behavior, but reduces to the classical - linear elasticity model for small strains -\shape italic -and -\shape default - small rotations. - It is derived from the following hyperelastic strain-energy function: -\begin_inset Formula -\[ -W=\frac{\mu}{2}\left(I_{1}-3\right)-\mu\ln J+\frac{\lambda}{2}\left(\ln J\right)^{2}. -\] - -\end_inset - -Here, -\begin_inset Formula $I_{1}$ -\end_inset - - and -\begin_inset Formula $I_{2}$ -\end_inset - - are the first and second invariants of the right Cauchy-Green deformation - tensor -\series bold - -\begin_inset Formula $\mathbf{C}$ -\end_inset - - -\series default - and -\begin_inset Formula $J$ -\end_inset - - is the determinant of the deformation gradient tensor. - The relationship between the material parameters, E, and v, and the parameters - used in the strain-energy function, is as follows. - -\end_layout - -\begin_layout Standard -\begin_inset Formula -\[ -\mu=\dfrac{E}{2(1+\nu)} -\] - -\end_inset - - -\end_layout - -\begin_layout Standard -\begin_inset Formula -\[ -\lambda=\dfrac{\nu E}{(1+\nu)(1-2\nu)} -\] - -\end_inset - - -\end_layout - -\begin_layout Standard -This material model uses a standard displacement-based element formulation, - so care must be taken when modeling materials with nearly-incompressible - material behavior to avoid element locking. - For this case, use the -\shape italic -Mooney-Rivlin -\shape default -material described in Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Mooney-Rivlin" - -\end_inset - -. -\end_layout - -\begin_layout Standard - -\shape italic -Example: -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1000.0 -\end_layout - -\begin_layout LyX-Code - 0.45 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout Standard -\begin_inset Newpage newpage -\end_inset - - -\end_layout - -\begin_layout Subsubsection -Coupled Mooney-Rivlin -\begin_inset CommandInset label -LatexCommand label -name "subsec:Coupled-Mooney-Rivlin" - -\end_inset - - -\end_layout - -\begin_layout Standard -The coupled Mooney-Rivlin material describes an unconstrained formulation - of the Mooney-Rivlin material. - The material type for this material is -\shape italic -coupled Mooney-Rivlin -\shape default -. - The following material parameters can be defined. -\end_layout - -\begin_layout Standard -\align center -\begin_inset VSpace defskip -\end_inset - - -\begin_inset Tabular - - - - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Mooney-Rivlin c1 parameter -\end_layout - \end_inset @@ -55652,7 +55874,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -55661,7 +55883,11 @@ P \begin_inset Text \begin_layout Plain Layout -Mooney-Rivlin c2 parameter +Second Lamé coefficient along direction 2 +\begin_inset Formula $\mu_{2}$ +\end_inset + + \end_layout \end_inset @@ -55685,7 +55911,7 @@ P \begin_inset Text \begin_layout Plain Layout -k + \end_layout \end_inset @@ -55694,11 +55920,8 @@ k \begin_inset Text \begin_layout Plain Layout -\begin_inset Quotes eld -\end_inset - -Bulk-modulus -\begin_inset Quotes erd +Second Lamé coefficient along direction 3 +\begin_inset Formula $\mu_{3}$ \end_inset @@ -55732,81 +55955,124 @@ P \end_layout \begin_layout Standard -The strain-energy function is given by the following expression. +This bimodular elastic material is the orthotropic conewise linear elastic + material described by Curnier et al. +\begin_inset CommandInset citation +LatexCommand citep +key "Curnier94" +literal "true" + +\end_inset + +. + It is derived from the following hyperelastic strain-energy function: \begin_inset Formula \[ -W=c_{1}\left(I_{1}-3\right)+c_{2}\left(I_{2}-3\right)-2\left(c_{1}+2c_{2}\right)\ln J+\frac{\lambda}{2}\left(\ln J\right)^{2} +\Psi_{r}=\sum\limits _{a=1}^{3}\mu_{a}\mathbf{A}_{a}^{r}:\mathbf{E}^{2}+\frac{1}{2}\lambda_{aa}\left[\mathbf{A}_{a}^{r}:\mathbf{E}\right]\left(\mathbf{A}_{a}^{r}:\mathbf{E}\right)^{2}+\sum\limits _{\begin{array}{c} +b=1\\ +b\ne a +\end{array}}^{3}\frac{1}{2}\lambda_{ab}\left(\mathbf{A}_{a}^{r}:\mathbf{E}\right)\left(\mathbf{A}_{b}^{r}:\mathbf{E}\right) \] \end_inset -Here, -\begin_inset Formula $I_{1}$ +where +\begin_inset Formula $\lambda_{ba}=\lambda_{ab}$ \end_inset and -\begin_inset Formula $I_{2}$ +\begin_inset Formula +\[ +\lambda_{aa}\left[\mathbf{A}_{a}^{r}:\mathbf{E}\right]=\begin{cases} +\lambda_{+aa} & \mathbf{A}_{a}^{r}:\mathbf{E}\geqslant0\\ +\lambda_{-aa} & \mathbf{A}_{a}^{r}:\mathbf{E}<0 +\end{cases},\quad a=1,2,3 +\] + \end_inset - are the first and second invariants of the right Cauchy-Green deformation - tensor -\series bold +Here, +\begin_inset Formula $\mathbf{E}$ +\end_inset -\begin_inset Formula $\mathbf{C}$ + is the Lagrangian strain tensor and +\begin_inset Formula $\mathbf{A}_{a}^{r}=\mathbf{a}_{a}^{r}\otimes\mathbf{a}_{a}^{r}$ \end_inset +, where +\begin_inset Formula $\mathbf{a}_{a}^{r}$ +\end_inset -\series default - and -\begin_inset Formula $J$ + ( +\begin_inset Formula $a=1,2,3)$ \end_inset - is the determinant of the deformation gradient tensor. + are orthonormal vectors aligned with the material axes. + This material response was originally formulated for infinitesimal strain + analyses; its behavior under finite strains may not be physically realistic. \end_layout \begin_layout Standard -This material model uses a standard displacement-based element formulation, - so care must be taken when modeling materials with nearly-incompressible - material behavior to avoid element locking. - For (nearly-) incompressible materials, use the + \shape italic -Mooney-Rivlin -\shape default -material described in Section -\begin_inset space ~ -\end_inset +Example: +\end_layout + +\begin_layout LyX-Code + +\end_layout +\begin_layout LyX-Code + 1 +\end_layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Mooney-Rivlin" +\begin_layout LyX-Code + 13.01 +\end_layout -\end_inset +\begin_layout LyX-Code + 13.01 +\end_layout -. +\begin_layout LyX-Code + 13.01 \end_layout -\begin_layout Standard +\begin_layout LyX-Code + 0.49 +\end_layout -\shape italic -Example: +\begin_layout LyX-Code + 0.49 \end_layout \begin_layout LyX-Code - + 0.49 \end_layout \begin_layout LyX-Code - 10.0 + 0.66 \end_layout \begin_layout LyX-Code - 1.0 + 0.66 \end_layout \begin_layout LyX-Code - 100.0 + 0.66 +\end_layout + +\begin_layout LyX-Code + 0.16 +\end_layout + +\begin_layout LyX-Code + 0.16 +\end_layout + +\begin_layout LyX-Code + 0.16 \end_layout \begin_layout LyX-Code @@ -55821,10 +56087,10 @@ Example: \end_layout \begin_layout Subsubsection -Coupled Veronda-Westmann +Osmotic Pressure from Virial Expansion \begin_inset CommandInset label LatexCommand label -name "subsec:Coupled-Veronda-Westmann" +name "subsec:Osmotic-Pressure-Virial" \end_inset @@ -55832,12 +56098,20 @@ name "subsec:Coupled-Veronda-Westmann" \end_layout \begin_layout Standard -The material type for the coupled Veronda-Westmann material is +The material type for osmotic pressure from virial expansion is +\begin_inset Quotes eld +\end_inset + + \shape italic -coupled Veronda-Westmann +osmotic virial expansion \shape default + +\begin_inset Quotes erd +\end_inset + . - The following material parameters can be defined. + The following material parameters need to be defined: \end_layout \begin_layout Standard @@ -55847,17 +56121,17 @@ coupled Veronda-Westmann \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -55866,7 +56140,11 @@ coupled Veronda-Westmann \begin_inset Text \begin_layout Plain Layout -Veronda-Westmann c1 parameter +Fluid volume fraction in reference (strain-free) configuration, +\begin_inset Formula $\varphi_{r}^{w}$ +\end_inset + + \end_layout \end_inset @@ -55875,11 +56153,7 @@ Veronda-Westmann c1 parameter \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[ ] \end_layout \end_inset @@ -55890,7 +56164,7 @@ P \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -55899,7 +56173,12 @@ P \begin_inset Text \begin_layout Plain Layout -Veronda-Westmann c2 parameter +Concentration of interstitial solute causing the osmotic pressure (moles + per volume of the mixture in the reference configuration), +\begin_inset Formula $c_{r}$ +\end_inset + + \end_layout \end_inset @@ -55910,8 +56189,16 @@ Veronda-Westmann c2 parameter \begin_layout Plain Layout [ \series bold -P +n +\series default +/ +\series bold +L \series default + +\begin_inset Formula $^{\mathrm{3}}$ +\end_inset + ] \end_layout @@ -55919,38 +56206,47 @@ P - + \begin_inset Text \begin_layout Plain Layout -k + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -\begin_inset Quotes eld -\end_inset - -Bulk-modulus -\begin_inset Quotes erd +First virial coefficient +\begin_inset Formula $c_{1}$ \end_inset - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout [ \series bold -P +F +\series default + +\begin_inset Formula $\cdot$ +\end_inset + + +\series bold +L +\series default +/ +\series bold +n \series default ] \end_layout @@ -55958,130 +56254,276 @@ P \end_inset - - -\end_inset + + +\begin_inset Text +\begin_layout Plain Layout + +\end_layout -\begin_inset VSpace defskip \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +Second virial coefficient +\begin_inset Formula $c_{2}$ +\end_inset -\end_layout - -\begin_layout Standard -The coupled Veronda-Westmann material is an unconstrained formulation of - the Veronda-Westmann material and is defined by the following strain-energy - function. -\begin_inset Formula -\[ -W=c_{1}\left(e^{c_{2}\left(I_{1}-3\right)}-1\right)-\frac{c_{1}c_{2}}{2}\left(I_{2}-3\right)+\frac{\lambda}{2}\left(\ln J\right)^{2} -\] +\end_layout \end_inset + + +\begin_inset Text -Here, -\begin_inset Formula $I_{1}$ -\end_inset +\begin_layout Plain Layout +[ +\series bold +F +\series default - and -\begin_inset Formula $I_{2}$ +\begin_inset Formula $\cdot$ \end_inset - are the first and second invariants of the right Cauchy-Green deformation - tensor + \series bold -C +L \series default - and -\begin_inset Formula $J$ -\end_inset - -is the determinant of the deformation gradient tensor. -\end_layout -\begin_layout Standard -This material model uses a standard displacement-based element formulation, - so care must be taken when modeling materials with nearly-incompressible - material behavior to avoid element locking. - For (nearly-) incompressible materials, use the -\shape italic -Veronda-Westmann -\shape default -material described in Section -\begin_inset space ~ +\begin_inset Formula $^{\mathrm{4}}$ \end_inset +/ +\series bold +n +\series default -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Veronda-Westmann" - +\begin_inset Formula $^{\mathrm{2}}$ \end_inset -. +] \end_layout -\begin_layout Standard +\end_inset + + + + +\begin_inset Text -\shape italic -Example: +\begin_layout Plain Layout + \end_layout -\begin_layout LyX-Code - -\end_layout +\end_inset + + +\begin_inset Text -\begin_layout LyX-Code - 10.0 -\end_layout +\begin_layout Plain Layout +Third virial coefficient +\begin_inset Formula $c_{3}$ +\end_inset -\begin_layout LyX-Code - 1.0 + \end_layout -\begin_layout LyX-Code - 100.0 -\end_layout +\end_inset + + +\begin_inset Text -\begin_layout LyX-Code - -\end_layout +\begin_layout Plain Layout +[ +\series bold +F +\series default -\begin_layout Standard -\begin_inset Newpage newpage +\begin_inset Formula $\cdot$ \end_inset -\end_layout - -\begin_layout Subsubsection -Ogden Unconstrained -\begin_inset CommandInset label -LatexCommand label -name "subsec:Ogden-Unconstrained" +\series bold +L +\series default + +\begin_inset Formula $^{\mathrm{7}}$ +\end_inset + +/ +\series bold +n +\series default + +\begin_inset Formula $^{\mathrm{3}}$ +\end_inset + +] +\end_layout + +\end_inset + + + + +\end_inset + +\begin_inset VSpace defskip \end_inset \end_layout \begin_layout Standard -This material describes an unconstrained hyperelastic Ogden material -\size small - -\begin_inset CommandInset citation -LatexCommand citep -key "Simo91" -literal "true" +The Cauchy stress for this material is +\begin_inset Formula +\[ +\boldsymbol{\sigma}=-\pi\mathbf{I}, +\] \end_inset +where +\begin_inset Formula $\pi$ +\end_inset -\size default + is the osmotic pressure, given by +\begin_inset Formula +\[ +\pi=c_{1}c+c_{2}c^{2}+c_{3}c^{3},\quad c=\frac{\varphi_{r}^{w}c_{r}}{J-1+\varphi_{r}^{w}}\,, +\] + +\end_inset + + +\begin_inset Formula $c$ +\end_inset + + is the solute concentration in the current configuration, and +\begin_inset Formula $J=\det\mathbf{F}$ +\end_inset + + is the relative volume. +\end_layout + +\begin_layout Standard +This osmotic swelling pressure in the interstitial fluid of a porous material + represents an entropic mechanism whose magnitude is independent of the + external bath osmolarity. + Typically, this material should be used in a solid mixture where the swelling + pressure is resisted by a solid matrix in tension. +\end_layout + +\begin_layout Standard + +\shape italic +Example +\shape default +: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0.8 +\end_layout + +\begin_layout LyX-Code + 100 +\end_layout + +\begin_layout LyX-Code + 2.436e-6 +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0,0 +\end_layout + +\begin_layout LyX-Code + 1,1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Natural Neo-Hookean +\begin_inset CommandInset label +LatexCommand label +name "subsec:Natural-Neo-Hookean" + +\end_inset + + +\end_layout + +\begin_layout Standard +The material type for a natural Neo-Hookean material is +\shape italic +natural neo-Hookean +\shape default . - The following material parameters must be defined: + The following parameters must be defined: \end_layout \begin_layout Standard @@ -56091,7 +56533,7 @@ literal "true" \begin_inset Tabular - + @@ -56101,7 +56543,7 @@ literal "true" \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -56110,11 +56552,11 @@ literal "true" \begin_inset Text \begin_layout Plain Layout -Coefficient of n -\begin_inset Formula $^{\mathrm{th}}$ +Young's modulus +\begin_inset Formula $E$ \end_inset - term, where n can range from 1 to 6 + \end_layout \end_inset @@ -56127,146 +56569,163 @@ Coefficient of n \series bold P \series default -] +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Exponent of n -\begin_inset Formula $^{\mathrm{th\thinspace}}$ +Poisson's ratio +\begin_inset Formula $\nu$ \end_inset -term, where n can range from 1 to 6 + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ ] +[ ] \end_layout \end_inset - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -Bulk-like modulus -\end_layout +\begin_inset VSpace defskip \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ -\series bold -P -\series default -] + \end_layout -\end_inset - - - +\begin_layout Standard +This model describes an unconstrained Neo-Hookean material using the natural + strain tensor +\begin_inset CommandInset citation +LatexCommand citep +key "Criscione00" +literal "true" \end_inset +. + It has a non-linear stress-strain behavior, but reduces to the classical + linear elasticity model for small strains +\shape italic +and +\shape default + small rotations. + It is derived from the following hyperelastic strain-energy function: +\begin_inset Formula +\[ +W=\frac{\kappa}{2}K_{1}^{2}+\mu K_{2}^{2}, +\] -\begin_inset VSpace defskip \end_inset +where +\begin_inset Formula $\kappa$ +\end_inset -\end_layout + is the bulk modulus and +\begin_inset Formula $\mu$ +\end_inset -\begin_layout Standard -The hyperelastic strain energy function for this material is given in terms - of the eigenvalues of the right or left stretch tensor: + is the shear modulus, \begin_inset Formula \[ -W\left(\lambda_{1},\lambda_{2},\lambda_{3}\right)=\frac{1}{2}c_{p}\left(J-1\right)^{2}+\sum\limits _{i=1}^{N}\frac{c_{i}}{m_{i}^{2}}\left(\lambda_{1}^{m_{i}}+\lambda_{2}^{m_{i}}+\lambda_{3}^{m_{i}}-3-m_{i}\ln J\right). +\kappa=\frac{E}{3\left(1-2\nu\right)}\,,\quad\mu=\frac{E}{2\left(1+\nu\right)} \] \end_inset Here, -\begin_inset Formula $\lambda_{i}^{2}$ +\begin_inset Formula $K_{1}$ \end_inset - are the eigenvalues of the right or left Cauchy deformation tensor, -\begin_inset Formula $c_{p}$ + and +\begin_inset Formula $K_{2}$ \end_inset -, -\begin_inset Formula $c_{i}$ + are the first and second invariants of the left natural (Hencky) strain + tensor +\series bold + +\begin_inset Formula $\boldsymbol{\eta}=\ln\mathbf{V}$ \end_inset - and -\begin_inset Formula $m_{i}$ + +\series default + where +\begin_inset Formula $\mathbf{V}$ \end_inset -are material coefficients and -\begin_inset Formula $N$ + is the left stretch tensor in the polar decomposition +\begin_inset Formula $\mathbf{F}=\mathbf{V}\cdot\mathbf{R}$ \end_inset - ranges from 1 to 6. - Any material parameters that are not specified by the user are assumed - to be zero. +. \end_layout \begin_layout Standard - +This material model uses a standard displacement-based element formulation, + so care must be taken when modeling materials with nearly-incompressible + material behavior to avoid element locking. + For this case, use the \shape italic -Example +Mooney-Rivlin \shape default -: +material described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Mooney-Rivlin" + +\end_inset + +. \end_layout -\begin_layout LyX-Code - +\begin_layout Standard + +\shape italic +Example: \end_layout \begin_layout LyX-Code - 2.4 + \end_layout \begin_layout LyX-Code - 1 + 200e3 \end_layout \begin_layout LyX-Code - 2 + 0.3 \end_layout \begin_layout LyX-Code @@ -56281,10 +56740,10 @@ Example \end_layout \begin_layout Subsubsection -Perfect Osmometer Equilibrium Osmotic Pressure +Neo-Hookean \begin_inset CommandInset label LatexCommand label -name "subsec:Perfect-Osmometer-Equilibrium" +name "subsec:Neo-Hookean" \end_inset @@ -56292,55 +56751,12 @@ name "subsec:Perfect-Osmometer-Equilibrium" \end_layout \begin_layout Standard -The material type for a perfect osmometer equilibrium swelling pressure - is -\begin_inset Quotes eld -\end_inset - - -\shape italic -perfect osmometer -\shape default - -\begin_inset Quotes erd -\end_inset - -. - The swelling pressure is described by the equations for a perfect osmometer, - assuming that the material is porous, containing an interstitial solution - whose solutes cannot be exchanged with the external bathing environment; - similarly, solutes in the external bathing solution cannot be exchanged - with the interstitial fluid of the porous material. - Therefore, osmotic pressurization occurs when there is an imbalance between - the interstitial and bathing solution osmolarities. - Since osmotic swelling must be resisted by a solid matrix, this material - is not stable on its own. - It must be combined with an elastic material that resists the swelling, - using a -\begin_inset Quotes eld -\end_inset - - +The material type for a Neo-Hookean material is \shape italic -solid mixture +neo-Hookean \shape default - -\begin_inset Quotes erd -\end_inset - - container as described in Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Solid-Mixture" - -\end_inset - . - The following material parameters need to be defined: + The following parameters must be defined: \end_layout \begin_layout Standard @@ -56350,51 +56766,17 @@ reference "subsec:Solid-Mixture" \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -gel porosity (fluid volume fraction) in reference (strain-free) configuration, - -\begin_inset Formula $\varphi_{0}^{w}$ -\end_inset - - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -[ ] -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - + \end_layout \end_inset @@ -56403,11 +56785,7 @@ gel porosity (fluid volume fraction) in reference (strain-free) configuration, \begin_inset Text \begin_layout Plain Layout -interstitial fluid osmolarity in reference configuration, -\begin_inset Formula $\bar{c}_{0}$ -\end_inset - - +Young's modulus \end_layout \end_inset @@ -56418,16 +56796,8 @@ interstitial fluid osmolarity in reference configuration, \begin_layout Plain Layout [ \series bold -n -\series default -/ -\series bold -L +P \series default - -\begin_inset Formula $^{\mathrm{3}}$ -\end_inset - ] \end_layout @@ -56439,7 +56809,7 @@ L \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -56448,11 +56818,7 @@ L \begin_inset Text \begin_layout Plain Layout -external bath osmolarity, -\begin_inset Formula $\bar{c}^{\ast}$ -\end_inset - - +Poisson's ratio \end_layout \end_inset @@ -56461,19 +56827,7 @@ external bath osmolarity, \begin_inset Text \begin_layout Plain Layout -[ -\series bold -n -\series default -/ -\series bold -L -\series default - -\begin_inset Formula $^{\mathrm{3}}$ -\end_inset - -] +[ ] \end_layout \end_inset @@ -56491,179 +56845,122 @@ L \end_layout \begin_layout Standard -The Cauchy stress for this material is the stress from the perfect osmometer - equilibrium response: +This model describes an unconstrained Neo-Hookean material +\begin_inset CommandInset citation +LatexCommand citep +key "Bonet97" +literal "true" + +\end_inset + +. + It has a non-linear stress-strain behavior, but reduces to the classical + linear elasticity model for small strains +\shape italic +and +\shape default + small rotations. + It is derived from the following hyperelastic strain-energy function: \begin_inset Formula \[ -\boldsymbol{\sigma}=-\pi\mathbf{I}, +W=\frac{\mu}{2}\left(I_{1}-3\right)-\mu\ln J+\frac{\lambda}{2}\left(\ln J\right)^{2}. \] \end_inset -where -\begin_inset Formula $\pi$ +Here, +\begin_inset Formula $I_{1}$ \end_inset - is the osmotic pressure, given by -\begin_inset Formula -\[ -\pi=RT\left(\bar{c}-\bar{c}^{\ast}\right)\,. -\] + and +\begin_inset Formula $I_{2}$ +\end_inset + + are the first and second invariants of the right Cauchy-Green deformation + tensor +\series bold +\begin_inset Formula $\mathbf{C}$ \end_inset -\begin_inset Formula $\bar{c}$ +\series default + and +\begin_inset Formula $J$ \end_inset - is the interstitial fluid in the current configuration, related to the - reference configuration via + is the determinant of the deformation gradient tensor. + The relationship between the material parameters, E, and v, and the parameters + used in the strain-energy function, is as follows. + +\end_layout + +\begin_layout Standard \begin_inset Formula \[ -\bar{c}=\frac{\varphi_{0}^{w}}{J-1+\varphi_{0}^{w}}\bar{c}_{0}\,, +\mu=\dfrac{E}{2(1+\nu)} \] \end_inset -where -\begin_inset Formula $J=\det\mathbf{F}$ -\end_inset - is the relative volume. - The values of the universal gas constant -\begin_inset Formula $R$ -\end_inset +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +\lambda=\dfrac{\nu E}{(1+\nu)(1-2\nu)} +\] - and absolute temperature -\begin_inset Formula $T$ \end_inset - must be specified as global constants. + \end_layout \begin_layout Standard -Though this material is porous, this is not a full-fledged biphasic material - as described in Section +This material model uses a standard displacement-based element formulation, + so care must be taken when modeling materials with nearly-incompressible + material behavior to avoid element locking. + For this case, use the +\shape italic +Mooney-Rivlin +\shape default +material described in Section \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "sec:Biphasic-Materials" +reference "subsec:Mooney-Rivlin" \end_inset - for example. - The behavior described by this material is strictly valid only after the - transient response of interstitial fluid and solute fluxes has subsided. +. \end_layout \begin_layout Standard \shape italic -Example (using units of mm, N, s, nmol, K) -\shape default -: -\end_layout - -\begin_layout Standard -Hyperosmotic loading of a cell with a membrane-impermeant solute, starting - from isotonic conditions. -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0.8 -\end_layout - -\begin_layout LyX-Code - 300 -\end_layout - -\begin_layout LyX-Code - 1 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - +Example: \end_layout \begin_layout LyX-Code - 1.0 + \end_layout \begin_layout LyX-Code - 0 + 1000.0 \end_layout \begin_layout LyX-Code - + 0.45 \end_layout \begin_layout LyX-Code \end_layout -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0,300 -\end_layout - -\begin_layout LyX-Code - 1,1500 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 8.314e-6 -\end_layout - -\begin_layout LyX-Code - 310 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - \begin_layout Standard \begin_inset Newpage newpage \end_inset @@ -56672,54 +56969,25 @@ Hyperosmotic loading of a cell with a membrane-impermeant solute, starting \end_layout \begin_layout Subsubsection -Porous Neo-Hookean +Coupled Mooney-Rivlin \begin_inset CommandInset label LatexCommand label -name "subsec:Porous-Neo-Hookean" - -\end_inset - - -\end_layout - -\begin_layout Standard -The material type for a porous neo-Hookean solid is -\begin_inset Quotes eld -\end_inset - - -\emph on -porous neo-Hookean -\emph default - -\begin_inset Quotes erd -\end_inset +name "subsec:Coupled-Mooney-Rivlin" -. - This material describes a porous neo-Hookean material with referential - solid volume fraction -\begin_inset Formula $\varphi_{r}^{s}$ \end_inset - (i.e., porosity -\begin_inset Formula $\varphi_{r}^{w}=1-\varphi_{r}^{s}$ -\end_inset -). - The pores are compressible but the skeleton is intrinsically incompressible. - Thus, upon pore closure, the material behavior needs to switch from compressibl -e to incompressible. - This material may be used to model the porous solid matrix of a biphasic - or multiphasic material. \end_layout \begin_layout Standard -The material type for a porous Neo-Hookean material is +The coupled Mooney-Rivlin material describes an unconstrained formulation + of the Mooney-Rivlin material. + The material type for this material is \shape italic -porous neo-Hookean +coupled Mooney-Rivlin \shape default . - The following parameters must be defined: + The following material parameters can be defined. \end_layout \begin_layout Standard @@ -56729,7 +56997,7 @@ porous neo-Hookean \begin_inset Tabular - + @@ -56739,7 +57007,7 @@ porous neo-Hookean \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -56748,7 +57016,7 @@ porous neo-Hookean \begin_inset Text \begin_layout Plain Layout -Young's modulus +Mooney-Rivlin c1 parameter \end_layout \end_inset @@ -56768,189 +57036,140 @@ P - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Referential solid volume fraction ( -\begin_inset Formula $0\le\varphi_{r}^{s}<1$ -\end_inset - -) +Mooney-Rivlin c2 parameter \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset - - -\end_inset - - -\begin_inset VSpace defskip -\end_inset - + + +\begin_inset Text +\begin_layout Plain Layout +k \end_layout -\begin_layout Standard -This model is derived from the following hyperelastic strain-energy function: - -\begin_inset Formula -\[ -W=\frac{\mu}{2}\left(\bar{I}_{1}-3\right)-\mu\ln\bar{J}\,, -\] - \end_inset + + +\begin_inset Text -where -\begin_inset Formula $\bar{J}$ +\begin_layout Plain Layout +\begin_inset Quotes eld \end_inset - represents the pore volume ratio, evaluated from -\begin_inset Formula -\[ -\bar{J}=\frac{J-\varphi_{r}^{s}}{1-\varphi_{r}^{s}}\,, -\] - +Bulk-modulus +\begin_inset Quotes erd \end_inset -and -\begin_inset Formula $\bar{I}_{1}=\text{tr}\bar{\mathbf{C}}$ -\end_inset -, with -\begin_inset Formula -\[ -\bar{\mathbf{F}}=\left(\frac{\bar{J}}{J}\right)^{1/3}\mathbf{F}\,,\quad\bar{\mathbf{C}}=\bar{\mathbf{F}}^{T}\cdot\bar{\mathbf{F}}=\left(\frac{\bar{J}}{J}\right)^{2/3}\mathbf{C}\,, -\] +\end_layout \end_inset + + +\begin_inset Text -and -\begin_inset Formula $\bar{J}=\det\bar{\mathbf{F}}$ -\end_inset +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout -. - The porosity -\begin_inset Formula $\varphi^{w}$ \end_inset + + + - in the current configuration evolves with the volume ratio -\begin_inset Formula $J$ \end_inset - according to -\begin_inset Formula -\[ -\varphi^{w}=\frac{J-1+\varphi_{r}^{w}}{J}=\frac{J-\varphi_{r}^{s}}{J}=\bar{J}\left(1-\varphi_{r}^{s}\right)\,. -\] - -\end_inset -Thus, pore closure occurs when -\begin_inset Formula $J=\varphi_{r}^{s}$ +\begin_inset VSpace defskip \end_inset - and -\begin_inset Formula $\bar{J}=0$ -\end_inset -. \end_layout \begin_layout Standard -By comparison to a standard neo-Hookean material, this porous neo-Hookean - material has an effective Young's modulus equal to -\begin_inset Formula -\[ -E=\frac{3\mu}{1+\frac{1}{2}\left(\varphi_{r}^{w}\right)^{2}}\,, -\] - -\end_inset - -and an effective Poisson's ratio equal to +The strain-energy function is given by the following expression. + \begin_inset Formula \[ -\nu=\frac{1-\left(\varphi_{r}^{w}\right)^{2}}{2+\left(\varphi_{r}^{w}\right)^{2}}\,. +W=c_{1}\left(I_{1}-3\right)+c_{2}\left(I_{2}-3\right)-2\left(c_{1}+2c_{2}\right)\ln J+\frac{\lambda}{2}\left(\ln J\right)^{2} \] \end_inset -Therefore, the two material properties that need to be provided are -\begin_inset Formula $E$ -\end_inset - - and the referential porosity -\begin_inset Formula $\varphi_{r}^{s}=1-\varphi_{r}^{w}$ -\end_inset - -. - Poisson's ratio in the limit of infinitesimal strains is dictated by the - porosity according to the above formula. - In particular, a highly porous material ( -\begin_inset Formula $\varphi_{r}^{w}\to1$ +Here, +\begin_inset Formula $I_{1}$ \end_inset -) has an effective Poisson ratio that approaches zero ( -\begin_inset Formula $\nu\to0$ + and +\begin_inset Formula $I_{2}$ \end_inset -) and -\begin_inset Formula $E\to2\mu$ -\end_inset + are the first and second invariants of the right Cauchy-Green deformation + tensor +\series bold - in the range of infinitesimal strains. - A low porosity material ( -\begin_inset Formula $\varphi_{r}^{w}\to0$ +\begin_inset Formula $\mathbf{C}$ \end_inset -) has -\begin_inset Formula $\nu\to\frac{1}{2}$ -\end_inset +\series default and -\begin_inset Formula $E\to3\mu$ +\begin_inset Formula $J$ \end_inset -, which is the expected behavior of an incompressible neo-Hookean solid. - Note that setting -\begin_inset Formula $\varphi_{r}^{w}=0$ -\end_inset + is the determinant of the deformation gradient tensor. +\end_layout - ( -\begin_inset Formula $\varphi_{r}^{s}=1$ +\begin_layout Standard +This material model uses a standard displacement-based element formulation, + so care must be taken when modeling materials with nearly-incompressible + material behavior to avoid element locking. + For (nearly-) incompressible materials, use the +\shape italic +Mooney-Rivlin +\shape default +material described in Section +\begin_inset space ~ \end_inset -) would not produce good numerical behavior, since the Cauchy stress in - an incompressible material would need to be supplemented by a hydrostatic - pressure term (a Lagrange multiplier that enforces the incompressibility - constraint). - Nevertheless, this compressible porous neo-Hookean material behaves well - even for values of -\begin_inset Formula $\varphi^{w}$ -\end_inset - as low as -\begin_inset Formula $\sim0.015$ +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Mooney-Rivlin" + \end_inset . @@ -56963,19 +57182,19 @@ Example: \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 1.0 + 10.0 \end_layout \begin_layout LyX-Code - 1.0 + 1.0 \end_layout \begin_layout LyX-Code - 0.2 + 100.0 \end_layout \begin_layout LyX-Code @@ -56990,10 +57209,10 @@ Example: \end_layout \begin_layout Subsubsection -Solid Mixture +Coupled Veronda-Westmann \begin_inset CommandInset label LatexCommand label -name "subsec:Solid-Mixture" +name "subsec:Coupled-Veronda-Westmann" \end_inset @@ -57001,34 +57220,12 @@ name "subsec:Solid-Mixture" \end_layout \begin_layout Standard -The material type for a constrained mixture of solids is -\begin_inset Quotes eld -\end_inset - - -\emph on -solid mixture -\emph default - -\begin_inset Quotes erd -\end_inset - -. - This material describes a mixture of elastic solids that share the same - reference configuration and same deformation gradient. - It is a container for any combination of the unconstrained elastic materials - described in Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Unconstrained-Materials" - -\end_inset - +The material type for the coupled Veronda-Westmann material is +\shape italic +coupled Veronda-Westmann +\shape default . + The following material parameters can be defined. \end_layout \begin_layout Standard @@ -57038,151 +57235,202 @@ reference "subsec:Unconstrained-Materials" \begin_inset Tabular - + + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Container tag for unconstrained solid material +Veronda-Westmann c1 parameter \end_layout \end_inset - - - -\end_inset + +\begin_inset Text +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout -\begin_inset VSpace defskip \end_inset + + + + +\begin_inset Text - +\begin_layout Plain Layout + \end_layout -\begin_layout Standard -The mixture may consist of any number of solids. - The stress tensor for the solid mixture is the sum of the stresses for - all the solids. -\end_layout +\end_inset + + +\begin_inset Text -\begin_layout Standard -Material axes may be optionally specified within the level, as - well as within each . - Within the level, these represent the local element axes relative - to the global coordinate system. - Within the , they represent local material axes relative to the - element. - If material axes are specified at both levels, they are properly compounded - to produce local material axes relative to the global coordinate system. - Material axes specified in the section are equivalent to - a specification at the level: they correspond to local element - axes relative to the global system. +\begin_layout Plain Layout +Veronda-Westmann c2 parameter \end_layout -\begin_layout Standard +\end_inset + + +\begin_inset Text -\shape italic -Example -\shape default -: +\begin_layout Plain Layout +[ +\series bold +P +\series default +] \end_layout -\begin_layout LyX-Code - -\end_layout +\end_inset + + + + +\begin_inset Text -\begin_layout LyX-Code - +\begin_layout Plain Layout +k \end_layout -\begin_layout LyX-Code - 1000.0 -\end_layout +\end_inset + + +\begin_inset Text -\begin_layout LyX-Code - 0.45 -\end_layout +\begin_layout Plain Layout +\begin_inset Quotes eld +\end_inset -\begin_layout LyX-Code - -\end_layout +Bulk-modulus +\begin_inset Quotes erd +\end_inset -\begin_layout LyX-Code - -\end_layout -\begin_layout LyX-Code - \end_layout -\begin_layout LyX-Code - 0.8660254, 0.5, 0 -\end_layout +\end_inset + + +\begin_inset Text -\begin_layout LyX-Code - 0,0,1 +\begin_layout Plain Layout +[ +\series bold +P +\series default +] \end_layout -\begin_layout LyX-Code - -\end_layout +\end_inset + + + -\begin_layout LyX-Code - 5, 1, 1 -\end_layout +\end_inset -\begin_layout LyX-Code - 2.5, 3, 3 -\end_layout -\begin_layout LyX-Code - -\end_layout +\begin_inset VSpace defskip +\end_inset + -\begin_layout LyX-Code - \end_layout -\begin_layout LyX-Code - +\begin_layout Standard +The coupled Veronda-Westmann material is an unconstrained formulation of + the Veronda-Westmann material and is defined by the following strain-energy + function. + +\begin_inset Formula +\[ +W=c_{1}\left(e^{c_{2}\left(I_{1}-3\right)}-1\right)-\frac{c_{1}c_{2}}{2}\left(I_{2}-3\right)+\frac{\lambda}{2}\left(\ln J\right)^{2} +\] + +\end_inset + +Here, +\begin_inset Formula $I_{1}$ +\end_inset + + and +\begin_inset Formula $I_{2}$ +\end_inset + + are the first and second invariants of the right Cauchy-Green deformation + tensor +\series bold +C +\series default + and +\begin_inset Formula $J$ +\end_inset + +is the determinant of the deformation gradient tensor. \end_layout -\begin_layout LyX-Code - 0.8660254,-0.5, 0 +\begin_layout Standard +This material model uses a standard displacement-based element formulation, + so care must be taken when modeling materials with nearly-incompressible + material behavior to avoid element locking. + For (nearly-) incompressible materials, use the +\shape italic +Veronda-Westmann +\shape default +material described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Veronda-Westmann" + +\end_inset + +. \end_layout -\begin_layout LyX-Code - 0,0,1 +\begin_layout Standard + +\shape italic +Example: \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 5, 1, 1 + 10.0 \end_layout \begin_layout LyX-Code - 2.5, 3, 3 + 1.0 \end_layout \begin_layout LyX-Code - + 100.0 \end_layout \begin_layout LyX-Code @@ -57197,10 +57445,10 @@ Example \end_layout \begin_layout Subsubsection -Spherical Fiber Distribution +Ogden Unconstrained \begin_inset CommandInset label LatexCommand label -name "subsec:Spherical-Fiber-Distribution" +name "subsec:Ogden-Unconstrained" \end_inset @@ -57208,48 +57456,20 @@ name "subsec:Spherical-Fiber-Distribution" \end_layout \begin_layout Standard -The material type for a spherical (isotropic) continuous fiber distribution - is -\begin_inset Quotes eld -\end_inset - - -\shape italic -spherical fiber distribution -\shape default - -\begin_inset Quotes erd -\end_inset - -. - Since fibers can only sustain tension, this material is not stable on its - own. - It must be combined with a stable compressible material that acts as a - ground matrix, using a -\begin_inset Quotes eld -\end_inset - - -\shape italic -solid mixture -\shape default - -\begin_inset Quotes erd -\end_inset +This material describes an unconstrained hyperelastic Ogden material +\size small + +\begin_inset CommandInset citation +LatexCommand citep +key "Simo91" +literal "true" - container as described in Section -\begin_inset space ~ \end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Solid-Mixture" - -\end_inset - +\size default . - The following material parameters need to be defined: + The following material parameters must be defined: \end_layout \begin_layout Standard @@ -57269,7 +57489,7 @@ reference "subsec:Solid-Mixture" \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -57278,11 +57498,11 @@ reference "subsec:Solid-Mixture" \begin_inset Text \begin_layout Plain Layout -parameter -\begin_inset Formula $\alpha$ +Coefficient of n +\begin_inset Formula $^{\mathrm{th}}$ \end_inset - + term, where n can range from 1 to 6 \end_layout \end_inset @@ -57291,7 +57511,11 @@ parameter \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -57302,7 +57526,7 @@ parameter \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -57311,11 +57535,11 @@ parameter \begin_inset Text \begin_layout Plain Layout -parameter -\begin_inset Formula $\beta$ +Exponent of n +\begin_inset Formula $^{\mathrm{th\thinspace}}$ \end_inset - +term, where n can range from 1 to 6 \end_layout \end_inset @@ -57335,7 +57559,7 @@ parameter \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -57344,11 +57568,7 @@ parameter \begin_inset Text \begin_layout Plain Layout -parameters -\begin_inset Formula $\xi$ -\end_inset - - +Bulk-like modulus \end_layout \end_inset @@ -57379,110 +57599,38 @@ P \end_layout \begin_layout Standard -The Cauchy stress for this fibrous material is given by -\begin_inset CommandInset citation -LatexCommand citep -key "Lanir83,Ateshian07a,Ateshian09a" -literal "true" - -\end_inset - -: +The hyperelastic strain energy function for this material is given in terms + of the eigenvalues of the right or left stretch tensor: \begin_inset Formula \[ -\boldsymbol{\sigma}=\int_{0}^{2\pi}\int_{0}^{\pi}H\left(I_{n}-1\right)\sigma_{n}\left(\mathbf{n}\right)\sin\varphi\,d\varphi\,d\theta\,. +W\left(\lambda_{1},\lambda_{2},\lambda_{3}\right)=\frac{1}{2}c_{p}\left(J-1\right)^{2}+\sum\limits _{i=1}^{N}\frac{c_{i}}{m_{i}^{2}}\left(\lambda_{1}^{m_{i}}+\lambda_{2}^{m_{i}}+\lambda_{3}^{m_{i}}-3-m_{i}\ln J\right). \] \end_inset Here, -\begin_inset Formula $I_{n}=\lambda_{n}^{2}=\mathbf{N}\cdot\mathbf{C}\cdot\mathbf{N}$ -\end_inset - - is the square of the fiber stretch -\begin_inset Formula $\lambda_{n}$ -\end_inset - -, -\begin_inset Formula $\mathbf{N}$ -\end_inset - - is the unit vector along the fiber direction, in the reference configuration, - which in spherical angles is directed along -\begin_inset Formula $\left(\theta,\varphi\right)$ -\end_inset - -, -\begin_inset Formula $\mathbf{n}=\mathbf{F}\cdot\mathbf{N}/\lambda_{n}$ -\end_inset - -, and -\begin_inset Formula $H\left(.\right)$ -\end_inset - - is the unit step function that enforces the tension-only contribution. -\end_layout - -\begin_layout Standard -The fiber stress is determined from a fiber strain energy function, -\begin_inset Formula -\[ -\sigma_{n}=\frac{2I_{n}}{J}\frac{\partial\Psi}{\partial I_{n}}\mathbf{n}\otimes\mathbf{n}\,, -\] - -\end_inset - -where in this material, the fiber strain energy density is given by -\begin_inset Formula -\[ -\Psi=\frac{\xi}{\alpha}\left(\exp\left[\alpha\left(I_{n}-1\right)^{\beta}\right]-1\right)\,, -\] - +\begin_inset Formula $\lambda_{i}^{2}$ \end_inset -where -\begin_inset Formula $\xi>0$ + are the eigenvalues of the right or left Cauchy deformation tensor, +\begin_inset Formula $c_{p}$ \end_inset , -\begin_inset Formula $\alpha\geqslant0$ -\end_inset - -, and -\begin_inset Formula $\beta\geqslant2$ -\end_inset - -. -\end_layout - -\begin_layout Standard -Note: In the limit when -\begin_inset Formula $\alpha\to0$ -\end_inset - -, this expressions produces a power law, -\begin_inset Formula -\[ -\lim\limits _{\alpha\to0}\Psi=\xi\left(I_{n}-1\right)^{\beta} -\] - -\end_inset - -Note: When -\begin_inset Formula $\beta>2$ +\begin_inset Formula $c_{i}$ \end_inset -, the fiber modulus is zero at the strain origin ( -\begin_inset Formula $I_{n}=1)$ + and +\begin_inset Formula $m_{i}$ \end_inset -. - Therefore, use -\begin_inset Formula $\beta>2$ +are material coefficients and +\begin_inset Formula $N$ \end_inset - when a smooth transition in the stress is desired from compression to tension. - + ranges from 1 to 6. + Any material parameters that are not specified by the user are assumed + to be zero. \end_layout \begin_layout Standard @@ -57494,43 +57642,19 @@ Example \end_layout \begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1000.0 -\end_layout - -\begin_layout LyX-Code - 0.45 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 10 + \end_layout \begin_layout LyX-Code - 0 + 2.4 \end_layout \begin_layout LyX-Code - 2.5 + 1 \end_layout \begin_layout LyX-Code - + 2 \end_layout \begin_layout LyX-Code @@ -57545,10 +57669,10 @@ Example \end_layout \begin_layout Subsubsection -Spherical Fiber Distribution from Solid-Bound Molecule +Perfect Osmometer Equilibrium Osmotic Pressure \begin_inset CommandInset label LatexCommand label -name "subsec:Spherical-Fiber-Distribution-SBM" +name "subsec:Perfect-Osmometer-Equilibrium" \end_inset @@ -57556,24 +57680,31 @@ name "subsec:Spherical-Fiber-Distribution-SBM" \end_layout \begin_layout Standard -The material type for a spherical (isotropic) continuous fiber distribution - with fiber modulus dependent on solid-bound molecule content is +The material type for a perfect osmometer equilibrium swelling pressure + is \begin_inset Quotes eld \end_inset \shape italic -spherical fiber distribution sbm +perfect osmometer \shape default \begin_inset Quotes erd \end_inset . - Since fibers can only sustain tension, this material is not stable on its - own. - It must be combined with a stable compressible material that acts as a - ground matrix, using a + The swelling pressure is described by the equations for a perfect osmometer, + assuming that the material is porous, containing an interstitial solution + whose solutes cannot be exchanged with the external bathing environment; + similarly, solutes in the external bathing solution cannot be exchanged + with the interstitial fluid of the porous material. + Therefore, osmotic pressurization occurs when there is an imbalance between + the interstitial and bathing solution osmolarities. + Since osmotic swelling must be resisted by a solid matrix, this material + is not stable on its own. + It must be combined with an elastic material that resists the swelling, + using a \begin_inset Quotes eld \end_inset @@ -57607,17 +57738,17 @@ reference "subsec:Solid-Mixture" \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -57626,8 +57757,9 @@ reference "subsec:Solid-Mixture" \begin_inset Text \begin_layout Plain Layout -parameter -\begin_inset Formula $\alpha$ +gel porosity (fluid volume fraction) in reference (strain-free) configuration, + +\begin_inset Formula $\varphi_{0}^{w}$ \end_inset @@ -57650,20 +57782,7 @@ parameter \begin_inset Text \begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -parameter -\begin_inset Formula $\beta$ -\end_inset - - + \end_layout \end_inset @@ -57672,31 +57791,11 @@ parameter \begin_inset Text \begin_layout Plain Layout -[ ] -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - +interstitial fluid osmolarity in reference configuration, +\begin_inset Formula $\bar{c}_{0}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -fiber modulus -\begin_inset Formula $\xi_{0}$ -\end_inset - \end_layout \end_inset @@ -57707,77 +57806,52 @@ fiber modulus \begin_layout Plain Layout [ \series bold -P +n +\series default +/ +\series bold +L \series default -] -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -fiber modulus exponent -\begin_inset Formula $\gamma$ -\end_inset - - -\end_layout +\begin_inset Formula $^{\mathrm{3}}$ \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ ] +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -fiber mass density -\begin_inset Formula $\rho_{0}$ +external bath osmolarity, +\begin_inset Formula $\bar{c}^{\ast}$ \end_inset - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout [ \series bold -M +n \series default / \series bold @@ -57793,297 +57867,189 @@ L \end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -sbm -\end_layout - -\end_inset - - -\begin_inset Text + -\begin_layout Plain Layout -index of solid-bound molecule -\begin_inset Formula $\sigma$ \end_inset - -\end_layout +\begin_inset VSpace defskip \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ ] + \end_layout -\end_inset - - - +\begin_layout Standard +The Cauchy stress for this material is the stress from the perfect osmometer + equilibrium response: +\begin_inset Formula +\[ +\boldsymbol{\sigma}=-\pi\mathbf{I}, +\] \end_inset - -\begin_inset VSpace defskip +where +\begin_inset Formula $\pi$ \end_inset + is the osmotic pressure, given by +\begin_inset Formula +\[ +\pi=RT\left(\bar{c}-\bar{c}^{\ast}\right)\,. +\] -\end_layout +\end_inset -\begin_layout Standard -The Cauchy stress for this fibrous material is given by -\begin_inset CommandInset citation -LatexCommand citep -key "Lanir83,Ateshian07a,Ateshian09a" -literal "true" +\begin_inset Formula $\bar{c}$ \end_inset -: + is the interstitial fluid in the current configuration, related to the + reference configuration via \begin_inset Formula \[ -\boldsymbol{\sigma}=\int_{0}^{2\pi}\int_{0}^{\pi}H\left(I_{n}-1\right)\sigma_{n}\left(\mathbf{n}\right)\sin\varphi\,d\varphi\,d\theta\,. +\bar{c}=\frac{\varphi_{0}^{w}}{J-1+\varphi_{0}^{w}}\bar{c}_{0}\,, \] \end_inset -Here, -\begin_inset Formula $I_{n}=\lambda_{n}^{2}=\mathbf{N}\cdot\mathbf{C}\cdot\mathbf{N}$ +where +\begin_inset Formula $J=\det\mathbf{F}$ \end_inset - is the square of the fiber stretch -\begin_inset Formula $\lambda_{n}$ + is the relative volume. + The values of the universal gas constant +\begin_inset Formula $R$ \end_inset -, -\begin_inset Formula $\mathbf{N}$ + and absolute temperature +\begin_inset Formula $T$ \end_inset - is the unit vector along the fiber direction, in the reference configuration, - which in spherical angles is directed along -\begin_inset Formula $\left(\theta,\varphi\right)$ -\end_inset - -, -\begin_inset Formula $\mathbf{n}=\mathbf{F}\cdot\mathbf{N}/\lambda_{n}$ -\end_inset - -, and -\begin_inset Formula $H\left(.\right)$ -\end_inset - - is the unit step function that enforces the tension-only contribution. -\end_layout - -\begin_layout Standard -The fiber stress is determined from a fiber strain energy function, -\begin_inset Formula -\[ -\sigma_{n}=\frac{2I_{n}}{J}\frac{\partial\Psi}{\partial I_{n}}\mathbf{n}\otimes\mathbf{n}\,, -\] - -\end_inset - -where in this material, the fiber strain energy density is given by -\begin_inset Formula -\[ -\Psi=\frac{\xi}{\alpha}\left(\exp\left[\alpha\left(I_{n}-1\right)^{\beta}\right]-1\right)\,, -\] - -\end_inset - -where -\begin_inset Formula $\xi>0$ -\end_inset - -, -\begin_inset Formula $\alpha\geqslant0$ -\end_inset - -, and -\begin_inset Formula $\beta\geqslant2$ -\end_inset - -. - The fiber modulus is dependent on the solid-bound molecule referential - density -\begin_inset Formula $\rho_{r}^{\sigma}$ -\end_inset - - according to the power law relation -\begin_inset Formula -\[ -\xi=\xi_{0}\left(\frac{\rho_{r}^{\sigma}}{\rho_{0}}\right)^{\gamma}\,, -\] - -\end_inset - -where -\begin_inset Formula $\rho_{0}$ -\end_inset - - is the density at which -\begin_inset Formula $\xi=\xi_{0}$ -\end_inset - -. + must be specified as global constants. \end_layout \begin_layout Standard -This type of material references a solid-bound molecule that belongs to - a multiphasic mixture. - Therefore this material may only be used as the solid (or a component of - the solid) in a multiphasic mixture (Section +Though this material is porous, this is not a full-fledged biphasic material + as described in Section \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "sec:Triphasic-Multiphasic-Materials" - -\end_inset +reference "sec:Biphasic-Materials" -). - The solid-bound molecule must be defined in the section (Section -\begin_inset space ~ \end_inset + for example. + The behavior described by this material is strictly valid only after the + transient response of interstitial fluid and solute fluxes has subsided. +\end_layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Solid-Bound-Molecules" - -\end_inset +\begin_layout Standard -) and must be included in the multiphasic mixture using a - tag. - The parameter \shape italic -sbm +Example (using units of mm, N, s, nmol, K) \shape default - must refer to the global index of that solid-bound molecule. - The value of -\begin_inset Formula $\rho_{r}^{\sigma}$ -\end_inset - - is specified within the tag. - If a chemical reaction is defined within that multiphasic mixture that - alters the value of -\begin_inset Formula $\rho_{r}^{\sigma}$ -\end_inset - -, lower and upper bounds may be specified for this referential density within - the tag to prevent -\begin_inset Formula $\xi$ -\end_inset - - from reducing to zero or achieving excessively elevated values. +: \end_layout \begin_layout Standard -Note: In the limit when -\begin_inset Formula $\alpha\to0$ -\end_inset +Hyperosmotic loading of a cell with a membrane-impermeant solute, starting + from isotonic conditions. +\end_layout -, the expression for -\begin_inset Formula $\Psi$ -\end_inset +\begin_layout LyX-Code + +\end_layout - produces a power law, -\begin_inset Formula -\[ -\lim\limits _{\alpha\to0}\Psi=\xi\left(I_{n}-1\right)^{\beta} -\] +\begin_layout LyX-Code + +\end_layout -\end_inset +\begin_layout LyX-Code + 0.8 +\end_layout -Note: When -\begin_inset Formula $\beta>2$ -\end_inset +\begin_layout LyX-Code + 300 +\end_layout -, the fiber modulus is zero at the strain origin ( -\begin_inset Formula $I_{n}=1)$ -\end_inset +\begin_layout LyX-Code + 1 +\end_layout -. - Therefore, use -\begin_inset Formula $\beta>2$ -\end_inset +\begin_layout LyX-Code + +\end_layout - when a smooth transition in the stress is desired from compression to tension. - +\begin_layout LyX-Code + \end_layout -\begin_layout Standard +\begin_layout LyX-Code + 1.0 +\end_layout -\shape italic -Example -\shape default -: +\begin_layout LyX-Code + 0 \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 1000.0 + \end_layout \begin_layout LyX-Code - 0.45 + \end_layout \begin_layout LyX-Code - + 0,300 \end_layout \begin_layout LyX-Code - + 1,1500 \end_layout \begin_layout LyX-Code - 0 + \end_layout \begin_layout LyX-Code - 2.5 + \end_layout \begin_layout LyX-Code - 10 + \end_layout \begin_layout LyX-Code - 2 + \end_layout \begin_layout LyX-Code - 1 + 8.314e-6 \end_layout \begin_layout LyX-Code - 1 + 310 \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout Standard @@ -58094,10 +58060,10 @@ Example \end_layout \begin_layout Subsubsection -Coupled Transversely Isotropic Mooney-Rivlin +Porous Neo-Hookean \begin_inset CommandInset label LatexCommand label -name "subsec:Coupled-Transversely-Isotropic-MR" +name "subsec:Porous-Neo-Hookean" \end_inset @@ -58105,14 +58071,43 @@ name "subsec:Coupled-Transversely-Isotropic-MR" \end_layout \begin_layout Standard -This material describes a transversely isotropic Mooney-Rivlin material - using a fully-coupled formulation. - It is define through the +The material type for a porous neo-Hookean solid is +\begin_inset Quotes eld +\end_inset + + +\emph on +porous neo-Hookean +\emph default + +\begin_inset Quotes erd +\end_inset + +. + This material describes a porous neo-Hookean material with referential + solid volume fraction +\begin_inset Formula $\varphi_{r}^{s}$ +\end_inset + + (i.e., porosity +\begin_inset Formula $\varphi_{r}^{w}=1-\varphi_{r}^{s}$ +\end_inset + +). + The pores are compressible but the skeleton is intrinsically incompressible. + Thus, upon pore closure, the material behavior needs to switch from compressibl +e to incompressible. + This material may be used to model the porous solid matrix of a biphasic + or multiphasic material. +\end_layout + +\begin_layout Standard +The material type for a porous Neo-Hookean material is \shape italic -coupled trans-iso Mooney-Rivlin +porous neo-Hookean \shape default -material type. - The following material parameters must be defined. +. + The following parameters must be defined: \end_layout \begin_layout Standard @@ -58122,7 +58117,7 @@ material type. \begin_inset Tabular - + @@ -58132,7 +58127,7 @@ material type. \begin_inset Text \begin_layout Plain Layout -c1 + \end_layout \end_inset @@ -58141,11 +58136,7 @@ c1 \begin_inset Text \begin_layout Plain Layout -Mooney-Rivlin -\begin_inset Formula $c_{1}$ -\end_inset - - parameter. +Young's modulus \end_layout \end_inset @@ -58165,48 +58156,266 @@ P - + \begin_inset Text \begin_layout Plain Layout -c2 + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Mooney-Rivlin -\begin_inset Formula $c_{2}$ +Referential solid volume fraction ( +\begin_inset Formula $0\le\varphi_{r}^{s}<1$ \end_inset - parameter. +) \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[ ] \end_layout \end_inset + + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard +This model is derived from the following hyperelastic strain-energy function: + +\begin_inset Formula +\[ +W=\frac{\mu}{2}\left(\bar{I}_{1}-3\right)-\mu\ln\bar{J}\,, +\] + +\end_inset + +where +\begin_inset Formula $\bar{J}$ +\end_inset + + represents the pore volume ratio, evaluated from +\begin_inset Formula +\[ +\bar{J}=\frac{J-\varphi_{r}^{s}}{1-\varphi_{r}^{s}}\,, +\] + +\end_inset + +and +\begin_inset Formula $\bar{I}_{1}=\text{tr}\bar{\mathbf{C}}$ +\end_inset + +, with +\begin_inset Formula +\[ +\bar{\mathbf{F}}=\left(\frac{\bar{J}}{J}\right)^{1/3}\mathbf{F}\,,\quad\bar{\mathbf{C}}=\bar{\mathbf{F}}^{T}\cdot\bar{\mathbf{F}}=\left(\frac{\bar{J}}{J}\right)^{2/3}\mathbf{C}\,, +\] + +\end_inset + +and +\begin_inset Formula $\bar{J}=\det\bar{\mathbf{F}}$ +\end_inset + +. + The porosity +\begin_inset Formula $\varphi^{w}$ +\end_inset + + in the current configuration evolves with the volume ratio +\begin_inset Formula $J$ +\end_inset + + according to +\begin_inset Formula +\[ +\varphi^{w}=\frac{J-1+\varphi_{r}^{w}}{J}=\frac{J-\varphi_{r}^{s}}{J}=\bar{J}\left(1-\varphi_{r}^{s}\right)\,. +\] + +\end_inset + +Thus, pore closure occurs when +\begin_inset Formula $J=\varphi_{r}^{s}$ +\end_inset + + and +\begin_inset Formula $\bar{J}=0$ +\end_inset + +. +\end_layout + +\begin_layout Standard +By comparison to a standard neo-Hookean material, this porous neo-Hookean + material has an effective Young's modulus equal to +\begin_inset Formula +\[ +E=\frac{3\mu}{1+\frac{1}{2}\left(\varphi_{r}^{w}\right)^{2}}\,, +\] + +\end_inset + +and an effective Poisson's ratio equal to +\begin_inset Formula +\[ +\nu=\frac{1-\left(\varphi_{r}^{w}\right)^{2}}{2+\left(\varphi_{r}^{w}\right)^{2}}\,. +\] + +\end_inset + +Therefore, the two material properties that need to be provided are +\begin_inset Formula $E$ +\end_inset + + and the referential porosity +\begin_inset Formula $\varphi_{r}^{s}=1-\varphi_{r}^{w}$ +\end_inset + +. + Poisson's ratio in the limit of infinitesimal strains is dictated by the + porosity according to the above formula. + In particular, a highly porous material ( +\begin_inset Formula $\varphi_{r}^{w}\to1$ +\end_inset + +) has an effective Poisson ratio that approaches zero ( +\begin_inset Formula $\nu\to0$ +\end_inset + +) and +\begin_inset Formula $E\to2\mu$ +\end_inset + + in the range of infinitesimal strains. + A low porosity material ( +\begin_inset Formula $\varphi_{r}^{w}\to0$ +\end_inset + +) has +\begin_inset Formula $\nu\to\frac{1}{2}$ +\end_inset + + and +\begin_inset Formula $E\to3\mu$ +\end_inset + +, which is the expected behavior of an incompressible neo-Hookean solid. + Note that setting +\begin_inset Formula $\varphi_{r}^{w}=0$ +\end_inset + + ( +\begin_inset Formula $\varphi_{r}^{s}=1$ +\end_inset + +) would not produce good numerical behavior, since the Cauchy stress in + an incompressible material would need to be supplemented by a hydrostatic + pressure term (a Lagrange multiplier that enforces the incompressibility + constraint). + Nevertheless, this compressible porous neo-Hookean material behaves well + even for values of +\begin_inset Formula $\varphi^{w}$ +\end_inset + + as low as +\begin_inset Formula $\sim0.015$ +\end_inset + +. +\end_layout + +\begin_layout Standard + +\shape italic +Example: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1.0 +\end_layout + +\begin_layout LyX-Code + 1.0 +\end_layout + +\begin_layout LyX-Code + 0.2 +\end_layout + +\begin_layout LyX-Code + +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Lung Material +\begin_inset CommandInset label +LatexCommand label +name "subsec:LungMaterial" + +\end_inset + + +\end_layout + +\begin_layout Standard +This is a material used for modeling human lung tissue as described by Birzle +\begin_inset CommandInset citation +LatexCommand citep +key "Birzle2019" +literal "false" + +\end_inset + +. + The following parameters must be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + \begin_inset Text \begin_layout Plain Layout -c3 + \end_layout \end_inset @@ -58215,7 +58424,11 @@ c3 \begin_inset Text \begin_layout Plain Layout -exponential multiplier +Young's modulus, +\begin_inset Formula $E$ +\end_inset + + \end_layout \end_inset @@ -58228,7 +58441,7 @@ exponential multiplier \series bold P \series default -] +] \end_layout \end_inset @@ -58239,7 +58452,7 @@ P \begin_inset Text \begin_layout Plain Layout -c4 + \end_layout \end_inset @@ -58248,7 +58461,11 @@ c4 \begin_inset Text \begin_layout Plain Layout -fiber scale factor +Poisson's ratio, +\begin_inset Formula $\nu$ +\end_inset + + \end_layout \end_inset @@ -58264,25 +58481,29 @@ fiber scale factor - + \begin_inset Text \begin_layout Plain Layout -c5 + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -fiber modulus in linear region +Birzle-Wall c1 parameter, +\begin_inset Formula $c_{1}$ +\end_inset + + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -58290,69 +58511,110 @@ fiber modulus in linear region \series bold P \series default -] +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -lam_max + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -maximum fiber straightening stretch +Birzle-Wall c3 parameter, +\begin_inset Formula $c_{3}$ +\end_inset + + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -k + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -bulk-like modulus +Birzle-Wall exponential d1 parameter, +\begin_inset Formula $d_{1}$ +\end_inset + + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Birzle-Wall exponential d3 parameter, +\begin_inset Formula $d_{3}$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[] \end_layout \end_inset @@ -58370,47 +58632,66 @@ P \end_layout \begin_layout Standard -The strain-energy function for this constitutive model is defined by +This model is derived from the following hyperelastic strain-energy function: + +\end_layout + +\begin_layout Standard \begin_inset Formula \[ -W=c_{1}\left(I_{1}-3\right)+c_{2}\left(I_{2}-3\right)-2\left(c_{1}+2c_{2}\right)\ln J+F\left(\lambda\right)+U\left(J\right) +W=c\left(I_{1}-3\right)+\frac{c}{\beta}\left(I_{3}^{-\beta}-1\right)+c_{1}\left(I_{3}^{-\frac{1}{3}}I_{1}-3\right)^{d_{1}}+c_{3}\left(I_{3}^{\frac{1}{3}}-1\right)^{d_{3}}, \] \end_inset -The first three terms define the coupled Mooney-Rivlin matrix response. - The third term is the fiber response which is a function of the fiber stretch - -\begin_inset Formula $\lambda$ -\end_inset - and is defined as in -\begin_inset CommandInset citation -LatexCommand citep -key "Weiss96" -literal "true" +\end_layout +\begin_layout Standard +where +\begin_inset Formula $I_{1}$ \end_inset -. - For -\begin_inset Formula $U$ + and +\begin_inset Formula $I_{2}$ \end_inset -, the following form is chosen in FEBio. - + are the first and second invariants of the right Cauchy-Green deformation + tensor +\series bold + +\begin_inset Formula $\mathbf{C}$ +\end_inset + + +\series default +, +\end_layout + +\begin_layout Standard \begin_inset Formula \[ -U\left(J\right)=\frac{1}{2}k\left(\ln J\right)^{2} +c=\frac{E}{4\left(1+\nu\right)}, \] \end_inset -where -\begin_inset Formula $J=\det\mathbf{F}$ + +\end_layout + +\begin_layout Standard +and +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +\beta=\frac{\nu}{1-2\nu}. +\] + \end_inset -is the Jacobian of the deformation. + \end_layout \begin_layout Standard @@ -58420,35 +58701,35 @@ Example: \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 1 + 1 \end_layout \begin_layout LyX-Code - 0.1 + 1913.7 \end_layout \begin_layout LyX-Code - 1 + 0.3413 \end_layout \begin_layout LyX-Code - 1 + 278.2 \end_layout \begin_layout LyX-Code - 1.34 + 5.766 \end_layout \begin_layout LyX-Code - 1.3 + 3 \end_layout \begin_layout LyX-Code - 100 + 6 \end_layout \begin_layout LyX-Code @@ -58463,10 +58744,10 @@ Example: \end_layout \begin_layout Subsubsection -Coupled Transversely Isotropic Veronda-Westmann +Solid Mixture \begin_inset CommandInset label LatexCommand label -name "subsec:Coupled-Transversely-Isotropic-VW" +name "subsec:Solid-Mixture" \end_inset @@ -58474,14 +58755,34 @@ name "subsec:Coupled-Transversely-Isotropic-VW" \end_layout \begin_layout Standard -This material describes a transversely isotropic Veronda-Westmann material - using a fully-coupled formulation. - It is define through the -\shape italic -coupled trans-iso Veronda-Westmann -\shape default -material type. - The following material parameters must be defined. +The material type for a constrained mixture of solids is +\begin_inset Quotes eld +\end_inset + + +\emph on +solid mixture +\emph default + +\begin_inset Quotes erd +\end_inset + +. + This material describes a mixture of elastic solids that share the same + reference configuration and same deformation gradient. + It is a container for any combination of the unconstrained elastic materials + described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Unconstrained-Materials" + +\end_inset + +. \end_layout \begin_layout Standard @@ -58491,149 +58792,238 @@ material type. \begin_inset Tabular - + - - + \begin_inset Text \begin_layout Plain Layout -c1 + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -Veronda-Westmann -\begin_inset Formula $c_{1}$ -\end_inset - - parameter. +Container tag for unconstrained solid material \end_layout \end_inset - -\begin_inset Text + + + +\end_inset -\begin_layout Plain Layout -[ -\series bold -P -\series default -] -\end_layout +\begin_inset VSpace defskip \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout -c2 + \end_layout -\end_inset - - -\begin_inset Text +\begin_layout Standard +The mixture may consist of any number of solids. + The stress tensor for the solid mixture is the sum of the stresses for + all the solids. +\end_layout -\begin_layout Plain Layout -Veronda-Westmann -\begin_inset Formula $c_{2}$ -\end_inset +\begin_layout Standard +Material axes may be optionally specified within the level, as + well as within each . + Within the level, these represent the local element axes relative + to the global coordinate system. + Within the , they represent local material axes relative to the + element. + If material axes are specified at both levels, they are properly compounded + to produce local material axes relative to the global coordinate system. + Material axes specified in the section are equivalent to + a specification at the level: they correspond to local element + axes relative to the global system. +\end_layout - parameter. +\begin_layout Standard + +\shape italic +Example +\shape default +: \end_layout -\end_inset - - -\begin_inset Text +\begin_layout LyX-Code + +\end_layout -\begin_layout Plain Layout -[ ] +\begin_layout LyX-Code + \end_layout -\end_inset - - - - -\begin_inset Text +\begin_layout LyX-Code + 1000.0 +\end_layout -\begin_layout Plain Layout -c3 +\begin_layout LyX-Code + 0.45 \end_layout -\end_inset - - -\begin_inset Text +\begin_layout LyX-Code + +\end_layout -\begin_layout Plain Layout -exponential multiplier +\begin_layout LyX-Code + \end_layout -\end_inset - - -\begin_inset Text +\begin_layout LyX-Code + +\end_layout -\begin_layout Plain Layout -[ -\series bold -P -\series default -] +\begin_layout LyX-Code + 0.8660254, 0.5, 0 +\end_layout + +\begin_layout LyX-Code + 0,0,1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 5, 1, 1 +\end_layout + +\begin_layout LyX-Code + 2.5, 3, 3 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0.8660254,-0.5, 0 +\end_layout + +\begin_layout LyX-Code + 0,0,1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 5, 1, 1 +\end_layout + +\begin_layout LyX-Code + 2.5, 3, 3 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + \end_layout +\begin_layout Standard +\begin_inset Newpage newpage \end_inset - - - - -\begin_inset Text -\begin_layout Plain Layout -c4 + \end_layout +\begin_layout Subsubsection +Spherical Fiber Distribution +\begin_inset CommandInset label +LatexCommand label +name "subsec:Spherical-Fiber-Distribution" + \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -fiber scale factor + \end_layout +\begin_layout Standard +The material type for a spherical (isotropic) continuous fiber distribution + is +\begin_inset Quotes eld \end_inset - - -\begin_inset Text -\begin_layout Plain Layout -[ ] + +\shape italic +spherical fiber distribution +\shape default + +\begin_inset Quotes erd +\end_inset + +. + Since fibers can only sustain tension, this material is not stable on its + own. + It must be combined with a stable compressible material that acts as a + ground matrix, using a +\begin_inset Quotes eld +\end_inset + + +\shape italic +solid mixture +\shape default + +\begin_inset Quotes erd +\end_inset + + container as described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solid-Mixture" + +\end_inset + +. + The following material parameters need to be defined: \end_layout +\begin_layout Standard +\align center +\begin_inset VSpace defskip \end_inset - - + + +\begin_inset Tabular + + + + + \begin_inset Text \begin_layout Plain Layout -c5 + \end_layout \end_inset @@ -58642,7 +59032,11 @@ c5 \begin_inset Text \begin_layout Plain Layout -fiber modulus in linear region +parameter +\begin_inset Formula $\alpha$ +\end_inset + + \end_layout \end_inset @@ -58651,11 +59045,7 @@ fiber modulus in linear region \begin_inset Text \begin_layout Plain Layout -[ -\series bold -P -\series default -] +[ ] \end_layout \end_inset @@ -58666,7 +59056,7 @@ P \begin_inset Text \begin_layout Plain Layout -lam_max + \end_layout \end_inset @@ -58675,7 +59065,11 @@ lam_max \begin_inset Text \begin_layout Plain Layout -maximum fiber straightening stretch +parameter +\begin_inset Formula $\beta$ +\end_inset + + \end_layout \end_inset @@ -58695,7 +59089,7 @@ maximum fiber straightening stretch \begin_inset Text \begin_layout Plain Layout -k + \end_layout \end_inset @@ -58704,7 +59098,11 @@ k \begin_inset Text \begin_layout Plain Layout -bulk-like modulus +parameters +\begin_inset Formula $\xi$ +\end_inset + + \end_layout \end_inset @@ -58735,85 +59133,158 @@ P \end_layout \begin_layout Standard -The strain-energy function for this constitutive model is defined by -\begin_inset Formula -\[ -W=c_{1}\left(e^{c_{2}\left(I_{1}-3\right)}-1\right)-\frac{1}{2}c_{1}c_{2}\left(I_{2}-3\right)+F\left(\lambda\right)+U\left(J\right)\,. -\] - -\end_inset - -The first two terms define the coupled Veronda-Westmann matrix response. - The third term is the fiber response which is a function of the fiber stretch - -\begin_inset Formula $\lambda$ -\end_inset - - and is defined as in +The Cauchy stress for this fibrous material is given by \begin_inset CommandInset citation LatexCommand citep -key "Weiss96" +key "Lanir83,Ateshian07a,Ateshian09a" literal "true" \end_inset -. - For -\begin_inset Formula $U$ -\end_inset - -, the following form is chosen in FEBio. - +: \begin_inset Formula \[ -U\left(J\right)=\frac{1}{2}k\left(\ln J\right)^{2} +\boldsymbol{\sigma}=\int_{0}^{2\pi}\int_{0}^{\pi}H\left(I_{n}-1\right)\sigma_{n}\left(\mathbf{n}\right)\sin\varphi\,d\varphi\,d\theta\,. \] \end_inset -where -\begin_inset Formula $J=\det\mathbf{F}$ +Here, +\begin_inset Formula $I_{n}=\lambda_{n}^{2}=\mathbf{N}\cdot\mathbf{C}\cdot\mathbf{N}$ \end_inset -is the Jacobian of the deformation. -\end_layout - -\begin_layout Standard + is the square of the fiber stretch +\begin_inset Formula $\lambda_{n}$ +\end_inset + +, +\begin_inset Formula $\mathbf{N}$ +\end_inset + + is the unit vector along the fiber direction, in the reference configuration, + which in spherical angles is directed along +\begin_inset Formula $\left(\theta,\varphi\right)$ +\end_inset + +, +\begin_inset Formula $\mathbf{n}=\mathbf{F}\cdot\mathbf{N}/\lambda_{n}$ +\end_inset + +, and +\begin_inset Formula $H\left(.\right)$ +\end_inset + + is the unit step function that enforces the tension-only contribution. +\end_layout + +\begin_layout Standard +The fiber stress is determined from a fiber strain energy function, +\begin_inset Formula +\[ +\sigma_{n}=\frac{2I_{n}}{J}\frac{\partial\Psi}{\partial I_{n}}\mathbf{n}\otimes\mathbf{n}\,, +\] + +\end_inset + +where in this material, the fiber strain energy density is given by +\begin_inset Formula +\[ +\Psi=\frac{\xi}{\alpha}\left(\exp\left[\alpha\left(I_{n}-1\right)^{\beta}\right]-1\right)\,, +\] + +\end_inset + +where +\begin_inset Formula $\xi>0$ +\end_inset + +, +\begin_inset Formula $\alpha\geqslant0$ +\end_inset + +, and +\begin_inset Formula $\beta\geqslant2$ +\end_inset + +. +\end_layout + +\begin_layout Standard +Note: In the limit when +\begin_inset Formula $\alpha\to0$ +\end_inset + +, this expressions produces a power law, +\begin_inset Formula +\[ +\lim\limits _{\alpha\to0}\Psi=\xi\left(I_{n}-1\right)^{\beta} +\] + +\end_inset + +Note: When +\begin_inset Formula $\beta>2$ +\end_inset + +, the fiber modulus is zero at the strain origin ( +\begin_inset Formula $I_{n}=1)$ +\end_inset + +. + Therefore, use +\begin_inset Formula $\beta>2$ +\end_inset + + when a smooth transition in the stress is desired from compression to tension. + +\end_layout + +\begin_layout Standard \shape italic -Example: +Example +\shape default +: \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 1 + \end_layout \begin_layout LyX-Code - 0.1 + 1000.0 \end_layout \begin_layout LyX-Code - 1 + 0.45 \end_layout \begin_layout LyX-Code - 1 + \end_layout \begin_layout LyX-Code - 1.34 + \end_layout \begin_layout LyX-Code - 1.3 + 10 \end_layout \begin_layout LyX-Code - 100 + 0 +\end_layout + +\begin_layout LyX-Code + 2.5 +\end_layout + +\begin_layout LyX-Code + \end_layout \begin_layout LyX-Code @@ -58828,10 +59299,10 @@ Example: \end_layout \begin_layout Subsubsection -Large Poisson's Ratio Ligament +Spherical Fiber Distribution from Solid-Bound Molecule \begin_inset CommandInset label LatexCommand label -name "subsec:Large-Poisson's-Ratio" +name "subsec:Spherical-Fiber-Distribution-SBM" \end_inset @@ -58839,18 +59310,48 @@ name "subsec:Large-Poisson's-Ratio" \end_layout \begin_layout Standard -This material describes a coupled, transversely isotropic material that - will conform to a particular Poisson's ratio when stretched along the fiber - direction -\begin_inset CommandInset citation -LatexCommand citep -key "Swedberg2014" -literal "true" +The material type for a spherical (isotropic) continuous fiber distribution + with fiber modulus dependent on solid-bound molecule content is +\begin_inset Quotes eld +\end_inset + +\shape italic +spherical fiber distribution sbm +\shape default + +\begin_inset Quotes erd \end_inset . - The following material parameters must be defined: + Since fibers can only sustain tension, this material is not stable on its + own. + It must be combined with a stable compressible material that acts as a + ground matrix, using a +\begin_inset Quotes eld +\end_inset + + +\shape italic +solid mixture +\shape default + +\begin_inset Quotes erd +\end_inset + + container as described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solid-Mixture" + +\end_inset + +. + The following material parameters need to be defined: \end_layout \begin_layout Standard @@ -58860,16 +59361,17 @@ literal "true" \begin_inset Tabular - + + \begin_inset Text \begin_layout Plain Layout -c1 + \end_layout \end_inset @@ -58878,11 +59380,20 @@ c1 \begin_inset Text \begin_layout Plain Layout -Fiber coefficient -\begin_inset Formula $c_{\mathrm{1}}$ +parameter +\begin_inset Formula $\alpha$ \end_inset - + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] \end_layout \end_inset @@ -58893,7 +59404,7 @@ Fiber coefficient \begin_inset Text \begin_layout Plain Layout -c2 + \end_layout \end_inset @@ -58902,11 +59413,20 @@ c2 \begin_inset Text \begin_layout Plain Layout -Fiber coefficient -\begin_inset Formula $c_{\mathrm{2}}$ +parameter +\begin_inset Formula $\beta$ \end_inset - + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] \end_layout \end_inset @@ -58917,7 +59437,7 @@ Fiber coefficient \begin_inset Text \begin_layout Plain Layout -mu + \end_layout \end_inset @@ -58926,13 +59446,26 @@ mu \begin_inset Text \begin_layout Plain Layout -Matrix coefficient -\begin_inset Formula $\mu$ +fiber modulus +\begin_inset Formula $\xi_{0}$ \end_inset \end_layout +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout + \end_inset @@ -58941,7 +59474,7 @@ Matrix coefficient \begin_inset Text \begin_layout Plain Layout -v0 + \end_layout \end_inset @@ -58950,11 +59483,20 @@ v0 \begin_inset Text \begin_layout Plain Layout -Poisson's ratio parameter -\begin_inset Formula $v_{\mathrm{0}}$ +fiber modulus exponent +\begin_inset Formula $\gamma$ \end_inset - + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] \end_layout \end_inset @@ -58965,7 +59507,7 @@ Poisson's ratio parameter \begin_inset Text \begin_layout Plain Layout -m + \end_layout \end_inset @@ -58974,13 +59516,34 @@ m \begin_inset Text \begin_layout Plain Layout -Poisson's ratio parameter -\begin_inset Formula $m$ +fiber mass density +\begin_inset Formula $\rho_{0}$ \end_inset \end_layout +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +M +\series default +/ +\series bold +L +\series default + +\begin_inset Formula $^{\mathrm{3}}$ +\end_inset + +] +\end_layout + \end_inset @@ -58989,7 +59552,7 @@ Poisson's ratio parameter \begin_inset Text \begin_layout Plain Layout -k +sbm \end_layout \end_inset @@ -58998,13 +59561,22 @@ k \begin_inset Text \begin_layout Plain Layout -Volumetric penalty coefficient -\begin_inset Formula $\kappa$ +index of solid-bound molecule +\begin_inset Formula $\sigma$ \end_inset \end_layout +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + \end_inset @@ -59020,433 +59592,650 @@ Volumetric penalty coefficient \end_layout \begin_layout Standard -The strain energy function for this constitutive model is a three part expressio -n: -\begin_inset Formula -\[ -W=W_{\text{fiber}}+W_{\text{matrix}}+W_{\text{vol}}, -\] +The Cauchy stress for this fibrous material is given by +\begin_inset CommandInset citation +LatexCommand citep +key "Lanir83,Ateshian07a,Ateshian09a" +literal "true" \end_inset -where: +: \begin_inset Formula \[ -\begin{aligned}W_{\text{fiber}} & =\frac{1}{2}\frac{c_{1}}{c_{2}}\left(e^{c_{2}\left({\lambda-1}\right)^{2}-1}\right),\\ -W_{\text{matrix}} & =\frac{\mu}{2}\left(I_{1}-3\right)-\mu\ln\left(\sqrt{I_{3}}\right),\\ -W_{\text{vol}} & =\frac{\kappa}{2}\left(\ln\left(\frac{I_{5}-I_{1}I_{4}+I_{2}}{I_{4}^{2(m-v_{0})}e^{-4m\left(\lambda-1\right)}}\right)\right)^{2}. -\end{aligned} +\boldsymbol{\sigma}=\int_{0}^{2\pi}\int_{0}^{\pi}H\left(I_{n}-1\right)\sigma_{n}\left(\mathbf{n}\right)\sin\varphi\,d\varphi\,d\theta\,. \] \end_inset -In the equations above, -\begin_inset Formula $\lambda$ +Here, +\begin_inset Formula $I_{n}=\lambda_{n}^{2}=\mathbf{N}\cdot\mathbf{C}\cdot\mathbf{N}$ \end_inset - is the stretch ratio of the material along the fiber direction. - The desired Poisson's ratio must first be selected based on available data - for uniaxial tension along the fiber direction. - The function with which to fit the Poisson's ratio data is: -\begin_inset Formula -\[ -v=-\frac{\lambda^{m-v_{0}}e^{-m\left(\lambda-1\right)}-1}{\lambda-1}\,. -\] - + is the square of the fiber stretch +\begin_inset Formula $\lambda_{n}$ \end_inset -The volumetric penalty coefficient -\begin_inset Formula $\kappa$ +, +\begin_inset Formula $\mathbf{N}$ \end_inset - must be selected to be large enough to enforce the Poisson's function above. - If this material is to be used in a biphasic representation, -\begin_inset Formula $\kappa$ + is the unit vector along the fiber direction, in the reference configuration, + which in spherical angles is directed along +\begin_inset Formula $\left(\theta,\varphi\right)$ \end_inset - must be selected based on experimental stress-relaxation data, since -\begin_inset Formula $\kappa$ +, +\begin_inset Formula $\mathbf{n}=\mathbf{F}\cdot\mathbf{N}/\lambda_{n}$ \end_inset - has an effect on the biphasic behavior of the material. - Once -\begin_inset Formula $\kappa$ +, and +\begin_inset Formula $H\left(.\right)$ \end_inset -, -\begin_inset Formula $v_{0}$ + is the unit step function that enforces the tension-only contribution. +\end_layout + +\begin_layout Standard +The fiber stress is determined from a fiber strain energy function, +\begin_inset Formula +\[ +\sigma_{n}=\frac{2I_{n}}{J}\frac{\partial\Psi}{\partial I_{n}}\mathbf{n}\otimes\mathbf{n}\,, +\] + \end_inset -, and -\begin_inset Formula $m$ +where in this material, the fiber strain energy density is given by +\begin_inset Formula +\[ +\Psi=\frac{\xi}{\alpha}\left(\exp\left[\alpha\left(I_{n}-1\right)^{\beta}\right]-1\right)\,, +\] + \end_inset - are chosen, -\begin_inset Formula $c_{\mathrm{1}}$ +where +\begin_inset Formula $\xi>0$ \end_inset , -\begin_inset Formula $c_{\mathrm{2}}$ +\begin_inset Formula $\alpha\geqslant0$ \end_inset - and -\begin_inset Formula $\mu$ +, and +\begin_inset Formula $\beta\geqslant2$ \end_inset - should be selected by fitting the stress-strain behavior of the material - to experimental data. - The Cauchy stress of the material is given by: +. + The fiber modulus is dependent on the solid-bound molecule referential + density +\begin_inset Formula $\rho_{r}^{\sigma}$ +\end_inset + + according to the power law relation \begin_inset Formula \[ -\boldsymbol{\sigma}=\frac{2}{J}\left(\left(W_{1}+I_{1}W_{2}\right)\mathbf{B}-W_{2}\mathbf{B}^{2}+W_{3}\left(I_{3}\mathbf{1}\right)+W_{4}I_{4}\left(\mathbf{a}\otimes\mathbf{a}\right)+W_{5}I_{4}\left(\mathbf{a}\otimes\mathbf{a}\cdot\mathbf{B}+\mathbf{B}\cdot\mathbf{a}\otimes\mathbf{a}\right)\right) +\xi=\xi_{0}\left(\frac{\rho_{r}^{\sigma}}{\rho_{0}}\right)^{\gamma}\,, \] \end_inset where -\begin_inset Formula $J$ +\begin_inset Formula $\rho_{0}$ \end_inset - is the jacobian of the deformation gradient -\begin_inset Formula $\mathbf{F}$ + is the density at which +\begin_inset Formula $\xi=\xi_{0}$ \end_inset -, -\series bold +. +\end_layout -\begin_inset Formula $\mathbf{B}=\mathbf{F}\cdot\mathbf{F}^{T}$ +\begin_layout Standard +This type of material references a solid-bound molecule that belongs to + a multiphasic mixture. + Therefore this material may only be used as the solid (or a component of + the solid) in a multiphasic mixture (Section +\begin_inset space ~ \end_inset -\series default - is the left Cauchy-Green deformation tensor, -\series bold +\begin_inset CommandInset ref +LatexCommand ref +reference "sec:Triphasic-Multiphasic-Materials" -\begin_inset Formula $\mathbf{1}$ \end_inset +). + The solid-bound molecule must be defined in the section (Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solid-Bound-Molecules" -\series default - is the -\begin_inset Formula $3\times3$ \end_inset - identity tensor -\series bold -, -\begin_inset Formula $\mathbf{a}$ +) and must be included in the multiphasic mixture using a + tag. + The parameter +\shape italic +sbm +\shape default + must refer to the global index of that solid-bound molecule. + The value of +\begin_inset Formula $\rho_{r}^{\sigma}$ +\end_inset + + is specified within the tag. + If a chemical reaction is defined within that multiphasic mixture that + alters the value of +\begin_inset Formula $\rho_{r}^{\sigma}$ +\end_inset + +, lower and upper bounds may be specified for this referential density within + the tag to prevent +\begin_inset Formula $\xi$ +\end_inset + + from reducing to zero or achieving excessively elevated values. +\end_layout + +\begin_layout Standard +Note: In the limit when +\begin_inset Formula $\alpha\to0$ +\end_inset + +, the expression for +\begin_inset Formula $\Psi$ +\end_inset + + produces a power law, +\begin_inset Formula +\[ +\lim\limits _{\alpha\to0}\Psi=\xi\left(I_{n}-1\right)^{\beta} +\] + +\end_inset + +Note: When +\begin_inset Formula $\beta>2$ +\end_inset + +, the fiber modulus is zero at the strain origin ( +\begin_inset Formula $I_{n}=1)$ +\end_inset + +. + Therefore, use +\begin_inset Formula $\beta>2$ \end_inset + when a smooth transition in the stress is desired from compression to tension. -\series default -is the fiber orientation vector in the deformed configuration. \end_layout \begin_layout Standard \shape italic -Example: +Example +\shape default +: \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 90 + \end_layout \begin_layout LyX-Code - 160 + 1000.0 \end_layout \begin_layout LyX-Code - 0.025 + 0.45 \end_layout \begin_layout LyX-Code - 5.85 + \end_layout \begin_layout LyX-Code - -100 + \end_layout \begin_layout LyX-Code - 1.55 + 0 \end_layout \begin_layout LyX-Code - + 2.5 \end_layout -\begin_layout Standard -\begin_inset Newpage newpage -\end_inset - - +\begin_layout LyX-Code + 10 \end_layout -\begin_layout Section -Fibers -\begin_inset CommandInset label -LatexCommand label -name "subsec:Fibers" +\begin_layout LyX-Code + 2 +\end_layout -\end_inset +\begin_layout LyX-Code + 1 +\end_layout +\begin_layout LyX-Code + 1 +\end_layout +\begin_layout LyX-Code + \end_layout -\begin_layout Standard -Fiber materials are used to model one-dimensional structures oriented along - a unit vector. - The associated strain energy density is a function of the normal strain - along that vector. - These fiber models are constructed such that the strain energy is non-zero - only when the fiber is in tension, under the idealized assumption that - fibers do not sustain any load in compression. - This assumption produces an inherent instability in the material response - of fibers, therefore such models must be combined with elastic materials - that can sustain compression and tension, thus serving as models of a ground - matrix. +\begin_layout LyX-Code + \end_layout \begin_layout Standard -FEBio accommodates fiber models that can be combined with unconstrained - or uncoupled models of the ground matrix. - Historically, unconstrained models of a ground matrix have been combined - with unconstrained fiber models, whereas uncoupled models of a ground matrix - have been combined with uncoupled fiber models. - The manual sections presented below follow this conventional approach. +\begin_inset Newpage newpage +\end_inset + + \end_layout -\begin_layout Standard -However, it should be noted that some authors have expressed concerns about - using uncoupled fiber formulations in fiber-matrix material models -\begin_inset CommandInset citation -LatexCommand citep -key "Sansour08,Helfenstein10,Gultekin19" -literal "true" +\begin_layout Subsubsection +Coupled Transversely Isotropic Mooney-Rivlin +\begin_inset CommandInset label +LatexCommand label +name "subsec:Coupled-Transversely-Isotropic-MR" \end_inset -, due to two fundamental concerns: When highly nonlinear fibers become much - stiffer than the ground matrix upon loading, it may become difficult to - enforce an isochoric deformation, as would be expected in an uncoupled - formulation. - Furthermore, in an uncoupled formulation, the strain is split into its - deviatoric (isochoric) and volumetric parts and the fiber strain is evaluated - only from the deviatoric part. - This deviatoric fiber strain is not the true fiber strain, yet it is used - to determine whether the fiber is in tension. - These factors may result in non-physical deformations, as described by - Helfenstein et al. - -\begin_inset CommandInset citation -LatexCommand citep -key "Helfenstein10" -literal "true" -\end_inset +\end_layout -. +\begin_layout Standard +This material describes a transversely isotropic Mooney-Rivlin material + using a fully-coupled formulation. + It is define through the +\shape italic +coupled trans-iso Mooney-Rivlin +\shape default +material type. + The following material parameters must be defined. \end_layout \begin_layout Standard -The solution advocated by these investigators has been to use an uncoupled - formulation for the ground matrix only, while the fiber models should remain - unconstrained -\begin_inset CommandInset citation -LatexCommand citep -key "Sansour08,Helfenstein10,Gultekin19" -literal "true" +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +c1 +\end_layout \end_inset + + +\begin_inset Text -. - This can be done in FEBio by using a -\begin_inset Quotes eld +\begin_layout Plain Layout +Mooney-Rivlin +\begin_inset Formula $c_{1}$ \end_inset + parameter. +\end_layout -\shape italic -uncoupled solid mixture -\shape default +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout -\begin_inset Quotes erd \end_inset + + + + +\begin_inset Text - container as described in Section -\begin_inset space ~ +\begin_layout Plain Layout +c2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Mooney-Rivlin +\begin_inset Formula $c_{2}$ \end_inset + parameter. +\end_layout + +\end_inset + + +\begin_inset Text -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Uncoupled-Solid-Mixture" +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout \end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +c3 +\end_layout -, where the material representing the ground matrix is taken from the list - of uncoupled materials in Section -\begin_inset space ~ \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +exponential multiplier +\end_layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Uncoupled-Materials" +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout \end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +c4 +\end_layout -, whereas fiber models are taken from the list of unconstrained models in - Section -\begin_inset space ~ \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +fiber scale factor +\end_layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Unconstrained-Fiber-Models" +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout \end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +c5 +\end_layout - or Section -\begin_inset space ~ \end_inset + + +\begin_inset Text +\begin_layout Plain Layout +fiber modulus in linear region +\end_layout -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Unconstrained-Continuous-Fiber" +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout \end_inset + + + + +\begin_inset Text -. +\begin_layout Plain Layout +lam_max \end_layout -\begin_layout Standard -\begin_inset Newpage newpage \end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +maximum fiber straightening stretch +\end_layout +\end_inset + + +\begin_inset Text +\begin_layout Plain Layout +[ ] \end_layout -\begin_layout Subsection -Unconstrained Fiber Models -\begin_inset CommandInset label -LatexCommand label -name "subsec:Unconstrained-Fiber-Models" +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +k +\end_layout \end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +bulk-like modulus +\end_layout +\end_inset + + +\begin_inset Text +\begin_layout Plain Layout +[ +\series bold +P +\series default +] \end_layout -\begin_layout Standard -Since fibers can only sustain tension, the materials listed here are not - stable on their own. - They must be combined with a stable material that acts as a ground matrix, - using a -\begin_inset Quotes eld \end_inset + + + +\end_inset -\shape italic -solid mixture -\shape default -\begin_inset Quotes erd +\begin_inset VSpace defskip \end_inset - container as described in Section -\begin_inset space ~ + +\end_layout + +\begin_layout Standard +The strain-energy function for this constitutive model is defined by +\begin_inset Formula +\[ +W=c_{1}\left(I_{1}-3\right)+c_{2}\left(I_{2}-3\right)-2\left(c_{1}+2c_{2}\right)\ln J+F\left(\lambda\right)+U\left(J\right) +\] + \end_inset +The first three terms define the coupled Mooney-Rivlin matrix response. + The third term is the fiber response which is a function of the fiber stretch + +\begin_inset Formula $\lambda$ +\end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Solid-Mixture" + and is defined as in +\begin_inset CommandInset citation +LatexCommand citep +key "Weiss96" +literal "true" \end_inset -, within a tag. - These fiber models may also be used in continuous fiber distribution models - as described in Section -\begin_inset space ~ +. + For +\begin_inset Formula $U$ \end_inset +, the following form is chosen in FEBio. + +\begin_inset Formula +\[ +U\left(J\right)=\frac{1}{2}k\left(\ln J\right)^{2} +\] -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Unconstrained-Continuous-Fiber" +\end_inset +where +\begin_inset Formula $J=\det\mathbf{F}$ \end_inset -, within a tag. +is the Jacobian of the deformation. \end_layout \begin_layout Standard -\begin_inset Newpage newpage -\end_inset +\shape italic +Example: +\end_layout +\begin_layout LyX-Code + \end_layout -\begin_layout Subsubsection -Fiber with Exponential-Power Law -\begin_inset CommandInset label -LatexCommand label -name "subsec:fiber-exp-pow" +\begin_layout LyX-Code + 1 +\end_layout -\end_inset +\begin_layout LyX-Code + 0.1 +\end_layout +\begin_layout LyX-Code + 1 +\end_layout +\begin_layout LyX-Code + 1 \end_layout -\begin_layout Standard -The material type for a single fiber with an exponential-power law is -\begin_inset Quotes eld -\end_inset +\begin_layout LyX-Code + 1.34 +\end_layout +\begin_layout LyX-Code + 1.3 +\end_layout -\shape italic -fiber-exp-pow -\shape default +\begin_layout LyX-Code + 100 +\end_layout -\begin_inset Quotes erd -\end_inset +\begin_layout LyX-Code + +\end_layout -. - Since fibers can only sustain tension, this material is not stable on its - own. - It must be combined with a stable compressible material that acts as a - ground matrix, using a -\begin_inset Quotes eld +\begin_layout Standard +\begin_inset Newpage newpage \end_inset -\shape italic -solid mixture -\shape default +\end_layout -\begin_inset Quotes erd -\end_inset +\begin_layout Subsubsection +Coupled Transversely Isotropic Veronda-Westmann +\begin_inset CommandInset label +LatexCommand label +name "subsec:Coupled-Transversely-Isotropic-VW" - container as described in Section -\begin_inset space ~ \end_inset -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Solid-Mixture" - -\end_inset +\end_layout -. - The following material parameters need to be defined: +\begin_layout Standard +This material describes a transversely isotropic Veronda-Westmann material + using a fully-coupled formulation. + It is define through the +\shape italic +coupled trans-iso Veronda-Westmann +\shape default +material type. + The following material parameters must be defined. \end_layout \begin_layout Standard @@ -59456,17 +60245,17 @@ reference "subsec:Solid-Mixture" \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - +c1 \end_layout \end_inset @@ -59475,10 +60264,11 @@ reference "subsec:Solid-Mixture" \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\xi,$ +Veronda-Westmann +\begin_inset Formula $c_{1}$ \end_inset - representing a measure of the fiber modulus + parameter. \end_layout \end_inset @@ -59491,7 +60281,7 @@ reference "subsec:Solid-Mixture" \series bold P \series default -] +] \end_layout \end_inset @@ -59502,7 +60292,7 @@ P \begin_inset Text \begin_layout Plain Layout - +c2 \end_layout \end_inset @@ -59511,10 +60301,11 @@ P \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\alpha,$ +Veronda-Westmann +\begin_inset Formula $c_{2}$ \end_inset - coefficient of exponential argument + parameter. \end_layout \end_inset @@ -59523,7 +60314,7 @@ P \begin_inset Text \begin_layout Plain Layout -[ ] +[ ] \end_layout \end_inset @@ -59534,7 +60325,7 @@ P \begin_inset Text \begin_layout Plain Layout - +c3 \end_layout \end_inset @@ -59543,10 +60334,1870 @@ P \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\beta,$ +exponential multiplier +\end_layout + \end_inset + + +\begin_inset Text - power of exponential argument +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +c4 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +fiber scale factor +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +c5 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +fiber modulus in linear region +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +lam_max +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +maximum fiber straightening stretch +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +k +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +bulk-like modulus +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard +The strain-energy function for this constitutive model is defined by +\begin_inset Formula +\[ +W=c_{1}\left(e^{c_{2}\left(I_{1}-3\right)}-1\right)-\frac{1}{2}c_{1}c_{2}\left(I_{2}-3\right)+F\left(\lambda\right)+U\left(J\right)\,. +\] + +\end_inset + +The first two terms define the coupled Veronda-Westmann matrix response. + The third term is the fiber response which is a function of the fiber stretch + +\begin_inset Formula $\lambda$ +\end_inset + + and is defined as in +\begin_inset CommandInset citation +LatexCommand citep +key "Weiss96" +literal "true" + +\end_inset + +. + For +\begin_inset Formula $U$ +\end_inset + +, the following form is chosen in FEBio. + +\begin_inset Formula +\[ +U\left(J\right)=\frac{1}{2}k\left(\ln J\right)^{2} +\] + +\end_inset + +where +\begin_inset Formula $J=\det\mathbf{F}$ +\end_inset + +is the Jacobian of the deformation. +\end_layout + +\begin_layout Standard + +\shape italic +Example: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 0.1 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 1.34 +\end_layout + +\begin_layout LyX-Code + 1.3 +\end_layout + +\begin_layout LyX-Code + 100 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Large Poisson's Ratio Ligament +\begin_inset CommandInset label +LatexCommand label +name "subsec:Large-Poisson's-Ratio" + +\end_inset + + +\end_layout + +\begin_layout Standard +This material describes a coupled, transversely isotropic material that + will conform to a particular Poisson's ratio when stretched along the fiber + direction +\begin_inset CommandInset citation +LatexCommand citep +key "Swedberg2014" +literal "true" + +\end_inset + +. + The following material parameters must be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +c1 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Fiber coefficient +\begin_inset Formula $c_{\mathrm{1}}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +c2 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Fiber coefficient +\begin_inset Formula $c_{\mathrm{2}}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +mu +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Matrix coefficient +\begin_inset Formula $\mu$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +v0 +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Poisson's ratio parameter +\begin_inset Formula $v_{\mathrm{0}}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +m +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Poisson's ratio parameter +\begin_inset Formula $m$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +k +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Volumetric penalty coefficient +\begin_inset Formula $\kappa$ +\end_inset + + +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard +The strain energy function for this constitutive model is a three part expressio +n: +\begin_inset Formula +\[ +W=W_{\text{fiber}}+W_{\text{matrix}}+W_{\text{vol}}, +\] + +\end_inset + +where: +\begin_inset Formula +\[ +\begin{aligned}W_{\text{fiber}} & =\frac{1}{2}\frac{c_{1}}{c_{2}}\left(e^{c_{2}\left({\lambda-1}\right)^{2}-1}\right),\\ +W_{\text{matrix}} & =\frac{\mu}{2}\left(I_{1}-3\right)-\mu\ln\left(\sqrt{I_{3}}\right),\\ +W_{\text{vol}} & =\frac{\kappa}{2}\left(\ln\left(\frac{I_{5}-I_{1}I_{4}+I_{2}}{I_{4}^{2(m-v_{0})}e^{-4m\left(\lambda-1\right)}}\right)\right)^{2}. +\end{aligned} +\] + +\end_inset + +In the equations above, +\begin_inset Formula $\lambda$ +\end_inset + + is the stretch ratio of the material along the fiber direction. + The desired Poisson's ratio must first be selected based on available data + for uniaxial tension along the fiber direction. + The function with which to fit the Poisson's ratio data is: +\begin_inset Formula +\[ +v=-\frac{\lambda^{m-v_{0}}e^{-m\left(\lambda-1\right)}-1}{\lambda-1}\,. +\] + +\end_inset + +The volumetric penalty coefficient +\begin_inset Formula $\kappa$ +\end_inset + + must be selected to be large enough to enforce the Poisson's function above. + If this material is to be used in a biphasic representation, +\begin_inset Formula $\kappa$ +\end_inset + + must be selected based on experimental stress-relaxation data, since +\begin_inset Formula $\kappa$ +\end_inset + + has an effect on the biphasic behavior of the material. + Once +\begin_inset Formula $\kappa$ +\end_inset + +, +\begin_inset Formula $v_{0}$ +\end_inset + +, and +\begin_inset Formula $m$ +\end_inset + + are chosen, +\begin_inset Formula $c_{\mathrm{1}}$ +\end_inset + +, +\begin_inset Formula $c_{\mathrm{2}}$ +\end_inset + + and +\begin_inset Formula $\mu$ +\end_inset + + should be selected by fitting the stress-strain behavior of the material + to experimental data. + The Cauchy stress of the material is given by: +\begin_inset Formula +\[ +\boldsymbol{\sigma}=\frac{2}{J}\left(\left(W_{1}+I_{1}W_{2}\right)\mathbf{B}-W_{2}\mathbf{B}^{2}+W_{3}\left(I_{3}\mathbf{1}\right)+W_{4}I_{4}\left(\mathbf{a}\otimes\mathbf{a}\right)+W_{5}I_{4}\left(\mathbf{a}\otimes\mathbf{a}\cdot\mathbf{B}+\mathbf{B}\cdot\mathbf{a}\otimes\mathbf{a}\right)\right) +\] + +\end_inset + +where +\begin_inset Formula $J$ +\end_inset + + is the jacobian of the deformation gradient +\begin_inset Formula $\mathbf{F}$ +\end_inset + +, +\series bold + +\begin_inset Formula $\mathbf{B}=\mathbf{F}\cdot\mathbf{F}^{T}$ +\end_inset + + +\series default + is the left Cauchy-Green deformation tensor, +\series bold + +\begin_inset Formula $\mathbf{1}$ +\end_inset + + +\series default + is the +\begin_inset Formula $3\times3$ +\end_inset + + identity tensor +\series bold +, +\begin_inset Formula $\mathbf{a}$ +\end_inset + + +\series default +is the fiber orientation vector in the deformed configuration. +\end_layout + +\begin_layout Standard + +\shape italic +Example: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 90 +\end_layout + +\begin_layout LyX-Code + 160 +\end_layout + +\begin_layout LyX-Code + 0.025 +\end_layout + +\begin_layout LyX-Code + 5.85 +\end_layout + +\begin_layout LyX-Code + -100 +\end_layout + +\begin_layout LyX-Code + 1.55 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Shenoy-Wang material +\end_layout + +\begin_layout Standard +This material implements the constitutive model by Wang et al. + (Biophysical Journal, 107, 2014, pp:2592 - 2603), which proposes a mechanism + for long-range force transmission in fibrous matrices enabled by tension-driven + alignment of fibers. + +\end_layout + +\begin_layout Standard +It defines the following parameters. + +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +mu +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +matrix shear modulus +\begin_inset Formula $\mu$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +k +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +matrix bulk modulus +\begin_inset Formula $k$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +Ef +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Fiber stiffness modulus +\begin_inset Formula $E_{f}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +lam_c +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +transition point +\begin_inset Formula $\lambda_{c}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +lam_t +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +transition interval size +\begin_inset Formula $\lambda_{t}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +n +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +strain hardening exponent +\emph on +n +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +m +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +strain hardening exponent +\emph on +m +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard +The strain-energy density function is given by, +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +W=W_{\text{b}}+W_{\text{f}}, +\] + +\end_inset + +where: +\begin_inset Formula +\[ +\begin{aligned}W_{\text{b}} & =\frac{\mu}{2}\left(\overline{I}_{1}-3\right)+\frac{\kappa}{2}\left(J-1\right)^{2},\\ +W_{\text{f}} & =\stackrel[a=1]{3}{\sum}f\left(\lambda_{a}\right), +\end{aligned} +\] + +\end_inset + + +\end_layout + +\begin_layout Standard +and +\begin_inset Formula $f$ +\end_inset + +is defined via its derivative, +\end_layout + +\begin_layout Standard +\begin_inset Formula +\[ +\frac{\partial f}{\partial\lambda_{a}}\left(\lambda_{a}\right)=\begin{cases} +0, & \lambda_{a}<\lambda_{1}\\ +\frac{E_{f}\left(\frac{\lambda_{a}-\lambda_{1}}{\lambda_{2}-\lambda_{1}}\right)^{n}\left(\lambda_{a}-\lambda_{1}\right)}{n+1}, & \lambda_{1}\leq\lambda_{a}<\lambda_{2}\\ +E_{f}\left[\frac{\lambda_{2}-\lambda_{1}}{n+1}+\frac{\left(1+\lambda_{a}-\lambda_{2}\right)^{m+1}-1}{m+1}\right], & \lambda_{a}\geq\lambda_{2} +\end{cases} +\] + +\end_inset + + +\end_layout + +\begin_layout Standard +Finally, the parameters +\begin_inset Formula $\lambda_{1}$ +\end_inset + +and +\begin_inset Formula $\lambda_{2}$ +\end_inset + +are given as follows. + +\end_layout + +\begin_layout Standard +\begin_inset Formula +\begin{align*} +\lambda_{1} & =\lambda_{c}-\lambda_{t}/2\\ +\lambda_{2} & =\lambda_{c}+\lambda_{t}/2 +\end{align*} + +\end_inset + + +\end_layout + +\begin_layout Standard +Example: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 0.7692 +\end_layout + +\begin_layout LyX-Code + 1.667 +\end_layout + +\begin_layout LyX-Code + 134.6 +\end_layout + +\begin_layout LyX-Code + 1.02 +\end_layout + +\begin_layout LyX-Code + 0.255 +\end_layout + +\begin_layout LyX-Code + 5 +\end_layout + +\begin_layout LyX-Code + 30 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Section +Fibers +\begin_inset CommandInset label +LatexCommand label +name "subsec:Fibers" + +\end_inset + + +\end_layout + +\begin_layout Standard +Fiber materials are used to model one-dimensional structures oriented along + a unit vector. + The associated strain energy density is a function of the normal strain + along that vector. + These fiber models are constructed such that the strain energy is non-zero + only when the fiber is in tension, under the idealized assumption that + fibers do not sustain any load in compression. + This assumption produces an inherent instability in the material response + of fibers, therefore such models must be combined with elastic materials + that can sustain compression and tension, thus serving as models of a ground + matrix. +\end_layout + +\begin_layout Standard +FEBio accommodates fiber models that can be combined with unconstrained + or uncoupled models of the ground matrix. + Historically, unconstrained models of a ground matrix have been combined + with unconstrained fiber models, whereas uncoupled models of a ground matrix + have been combined with uncoupled fiber models. + The manual sections presented below follow this conventional approach. +\end_layout + +\begin_layout Standard +However, it should be noted that some authors have expressed concerns about + using uncoupled fiber formulations in fiber-matrix material models +\begin_inset CommandInset citation +LatexCommand citep +key "Sansour08,Helfenstein10,Gultekin19" +literal "true" + +\end_inset + +, due to two fundamental concerns: When highly nonlinear fibers become much + stiffer than the ground matrix upon loading, it may become difficult to + enforce an isochoric deformation, as would be expected in an uncoupled + formulation. + Furthermore, in an uncoupled formulation, the strain is split into its + deviatoric (isochoric) and volumetric parts and the fiber strain is evaluated + only from the deviatoric part. + This deviatoric fiber strain is not the true fiber strain, yet it is used + to determine whether the fiber is in tension. + These factors may result in non-physical deformations, as described by + Helfenstein et al. + +\begin_inset CommandInset citation +LatexCommand citep +key "Helfenstein10" +literal "true" + +\end_inset + +. +\end_layout + +\begin_layout Standard +The solution advocated by these investigators has been to use an uncoupled + formulation for the ground matrix only, while the fiber models should remain + unconstrained +\begin_inset CommandInset citation +LatexCommand citep +key "Sansour08,Helfenstein10,Gultekin19" +literal "true" + +\end_inset + +. + This can be done in FEBio by using a +\begin_inset Quotes eld +\end_inset + + +\shape italic +uncoupled solid mixture +\shape default + +\begin_inset Quotes erd +\end_inset + + container as described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Uncoupled-Solid-Mixture" + +\end_inset + +, where the material representing the ground matrix is taken from the list + of uncoupled materials in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Uncoupled-Materials" + +\end_inset + +, whereas fiber models are taken from the list of unconstrained models in + Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Unconstrained-Fiber-Models" + +\end_inset + + or Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Unconstrained-Continuous-Fiber" + +\end_inset + +. +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsection +Unconstrained Fiber Models +\begin_inset CommandInset label +LatexCommand label +name "subsec:Unconstrained-Fiber-Models" + +\end_inset + + +\end_layout + +\begin_layout Standard +Since fibers can only sustain tension, the materials listed here are not + stable on their own. + They must be combined with a stable material that acts as a ground matrix, + using a +\begin_inset Quotes eld +\end_inset + + +\shape italic +solid mixture +\shape default + +\begin_inset Quotes erd +\end_inset + + container as described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solid-Mixture" + +\end_inset + +, within a tag. + These fiber models may also be used in continuous fiber distribution models + as described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Unconstrained-Continuous-Fiber" + +\end_inset + +, within a tag. +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Fiber with Exponential-Power Law +\begin_inset CommandInset label +LatexCommand label +name "subsec:fiber-exp-pow" + +\end_inset + + +\end_layout + +\begin_layout Standard +The material type for a single fiber with an exponential-power law is +\begin_inset Quotes eld +\end_inset + + +\shape italic +fiber-exp-pow +\shape default + +\begin_inset Quotes erd +\end_inset + +. + Since fibers can only sustain tension, this material is not stable on its + own. + It must be combined with a stable compressible material that acts as a + ground matrix, using a +\begin_inset Quotes eld +\end_inset + + +\shape italic +solid mixture +\shape default + +\begin_inset Quotes erd +\end_inset + + container as described in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solid-Mixture" + +\end_inset + +. + The following material parameters need to be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\xi,$ +\end_inset + + representing a measure of the fiber modulus +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\alpha,$ +\end_inset + + coefficient of exponential argument +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\beta,$ +\end_inset + + power of exponential argument +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\lambda_{0},$ +\end_inset + + stretch threshold for tensile response +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard +The fiber is oriented along the unit vector +\begin_inset Formula $\mathbf{e}_{1}$ +\end_inset + +, where +\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ +\end_inset + + are orthonormal basis vectors representing the local element coordinate + system when specified (Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Specifying-Fiber-Orientation" + +\end_inset + +), or else the global Cartesian coordinate system. + The Cauchy stress for this fibrous material is given by +\begin_inset Formula +\[ +\boldsymbol{\sigma}=H\left(I_{n}-I_{0}\right)\frac{2I_{n}}{J}\frac{\partial\Psi}{\partial I_{n}}\mathbf{n}\otimes\mathbf{n}, +\] + +\end_inset + +where +\begin_inset Formula $I_{n}=\lambda_{n}^{2}=\mathbf{n}_{r}\cdot\mathbf{C}\cdot\mathbf{n}_{r}$ +\end_inset + + is the square of the fiber stretch, +\begin_inset Formula $\mathbf{n}=\mathbf{F}\cdot\mathbf{n}_{r}/\lambda_{n}$ +\end_inset + +, +\begin_inset Formula $I_{0}=\lambda_{0}^{2}$ +\end_inset + + is the square of the stretch threshold for the tensile response ( +\begin_inset Formula $\lambda_{0}=1$ +\end_inset + + by default) and +\begin_inset Formula $H\left(.\right)$ +\end_inset + + is the unit step function that enforces the tension-only contribution. + The fiber strain energy density is given by +\begin_inset Formula +\[ +\Psi=\frac{\xi}{\alpha\beta}\left(\exp\left[\alpha\left(I_{n}-I_{0}\right)^{\beta}\right]-1\right)\,, +\] + +\end_inset + +where +\begin_inset Formula $\xi>0$ +\end_inset + +, +\begin_inset Formula $\alpha\geqslant0$ +\end_inset + +, and +\begin_inset Formula $\beta\geqslant2$ +\end_inset + +. +\end_layout + +\begin_layout Standard +Note: In the limit when +\begin_inset Formula $\alpha\to0$ +\end_inset + +, this expressions produces a power law, +\begin_inset Formula +\[ +\lim\limits _{\alpha\to0}\,\Psi=\frac{\xi}{\beta}\left(I_{n}-I_{0}\right)^{\beta} +\] + +\end_inset + +Note: When +\begin_inset Formula $\beta>2$ +\end_inset + +, the fiber modulus is zero at the strain origin ( +\begin_inset Formula $I_{n}=I_{0})$ +\end_inset + +. + Therefore, use +\begin_inset Formula $\beta>2$ +\end_inset + + when a smooth transition in the stress is desired from compression to tension. +\end_layout + +\begin_layout Standard + +\shape italic +Example +\shape default +: +\end_layout + +\begin_layout Standard +Single fiber oriented along +\begin_inset Formula $\mathbf{e}_{1}$ +\end_inset + +, embedded in a neo-Hookean ground matrix. +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0,0,0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1000.0 +\end_layout + +\begin_layout LyX-Code + 0.45 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 5 +\end_layout + +\begin_layout LyX-Code + 20 +\end_layout + +\begin_layout LyX-Code + 3 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0 +\end_layout + +\begin_layout LyX-Code + 90 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard + +\shape italic +Example +\shape default +: +\end_layout + +\begin_layout Standard +Two fibers in the plane orthogonal to +\begin_inset Formula $\mathbf{e}_{1}$ +\end_inset + +, oriented at ±25 degrees relative to +\begin_inset Formula $\mathbf{e}_{3}$ +\end_inset + +, embedded in a neo-Hookean ground matrix. +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0,0,0 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1000.0 +\end_layout + +\begin_layout LyX-Code + 0.45 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 5 +\end_layout + +\begin_layout LyX-Code + 20 +\end_layout + +\begin_layout LyX-Code + 3 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 90 +\end_layout + +\begin_layout LyX-Code + 25 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 5 +\end_layout + +\begin_layout LyX-Code + 20 +\end_layout + +\begin_layout LyX-Code + 3 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + -90 +\end_layout + +\begin_layout LyX-Code + 25 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Fiber with Neo-Hookean Law +\begin_inset CommandInset label +LatexCommand label +name "subsec:Fiber-with-Neo-Hookean" + +\end_inset + + +\end_layout + +\begin_layout Standard +This material type is +\begin_inset Quotes eld +\end_inset + + +\shape italic +fiber-NH +\shape default + +\begin_inset Quotes erd +\end_inset + +. + The following material parameters need to be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\mu,$ +\end_inset + + representing a measure of the fiber modulus +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +P +\series default +] +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard +The fiber strain energy density is given by +\begin_inset Formula +\[ +\Psi_{n}\left(I_{n}\right)=\frac{\mu}{4}\left(I_{n}-1\right)^{2}\,, +\] + +\end_inset + +where +\begin_inset Formula $\mu>0$ +\end_inset + +. +\end_layout + +\begin_layout Standard + +\shape italic +Example +\shape default +: +\end_layout + +\begin_layout Standard +Fiber model as specified in a continuous fiber distribution (Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Unconstrained-Continuous-Fiber" + +\end_inset + +) +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Fiber with Natural Neo-Hookean Law +\begin_inset CommandInset label +LatexCommand label +name "subsec:Fiber-with-Neo-Hookean-1" + +\end_inset + + +\end_layout + +\begin_layout Standard +This material type is +\begin_inset Quotes eld +\end_inset + + +\shape italic +fiber-natural-NH +\shape default + +\begin_inset Quotes erd +\end_inset + +. + The following material parameters need to be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\xi,$ +\end_inset + + fiber modulus \end_layout \end_inset @@ -59555,7 +62206,11 @@ P \begin_inset Text \begin_layout Plain Layout -[ ] +[ +\series bold +P +\series default +] \end_layout \end_inset @@ -59605,60 +62260,10 @@ P \end_layout \begin_layout Standard -The fiber is oriented along the unit vector -\begin_inset Formula $\mathbf{e}_{1}$ -\end_inset - -, where -\begin_inset Formula $\left\{ \mathbf{e}_{1},\mathbf{e}_{2},\mathbf{e}_{3}\right\} $ -\end_inset - - are orthonormal basis vectors representing the local element coordinate - system when specified (Section -\begin_inset space ~ -\end_inset - - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Specifying-Fiber-Orientation" - -\end_inset - -), or else the global Cartesian coordinate system. - The Cauchy stress for this fibrous material is given by -\begin_inset Formula -\[ -\boldsymbol{\sigma}=H\left(I_{n}-I_{0}\right)\frac{2I_{n}}{J}\frac{\partial\Psi}{\partial I_{n}}\mathbf{n}\otimes\mathbf{n}, -\] - -\end_inset - -where -\begin_inset Formula $I_{n}=\lambda_{n}^{2}=\mathbf{n}_{r}\cdot\mathbf{C}\cdot\mathbf{n}_{r}$ -\end_inset - - is the square of the fiber stretch, -\begin_inset Formula $\mathbf{n}=\mathbf{F}\cdot\mathbf{n}_{r}/\lambda_{n}$ -\end_inset - -, -\begin_inset Formula $I_{0}=\lambda_{0}^{2}$ -\end_inset - - is the square of the stretch threshold for the tensile response ( -\begin_inset Formula $\lambda_{0}=1$ -\end_inset - - by default) and -\begin_inset Formula $H\left(.\right)$ -\end_inset - - is the unit step function that enforces the tension-only contribution. - The fiber strain energy density is given by +The fiber strain energy density is given by \begin_inset Formula \[ -\Psi=\frac{\xi}{\alpha\beta}\left(\exp\left[\alpha\left(I_{n}-I_{0}\right)^{\beta}\right]-1\right)\,, +\Psi_{n}\left(\lambda_{n}\right)=\frac{\xi}{2}H\left(\ln\frac{\lambda_{n}}{\lambda_{0}}\right)\left(\ln\frac{\lambda_{n}}{\lambda_{0}}\right)^{2}\,, \] \end_inset @@ -59667,44 +62272,31 @@ where \begin_inset Formula $\xi>0$ \end_inset -, -\begin_inset Formula $\alpha\geqslant0$ -\end_inset - -, and -\begin_inset Formula $\beta\geqslant2$ + and +\begin_inset Formula $\lambda_{0}\ge1$ \end_inset . -\end_layout - -\begin_layout Standard -Note: In the limit when -\begin_inset Formula $\alpha\to0$ -\end_inset - -, this expressions produces a power law, -\begin_inset Formula -\[ -\lim\limits _{\alpha\to0}\,\Psi=\frac{\xi}{\beta}\left(I_{n}-I_{0}\right)^{\beta} -\] - + The tensile response engages at the tensile stretch ratio +\begin_inset Formula $\lambda_{0}$ \end_inset -Note: When -\begin_inset Formula $\beta>2$ + ( +\begin_inset Formula $\lambda_{0}=1$ \end_inset -, the fiber modulus is zero at the strain origin ( -\begin_inset Formula $I_{n}=I_{0})$ + by default).The natural (logarithmic or Hencky) strain along the fiber is + +\begin_inset Formula $\ln\lambda_{n}$ \end_inset -. - Therefore, use -\begin_inset Formula $\beta>2$ +, whereas +\begin_inset Formula $\ln\frac{\lambda_{n}}{\lambda_{0}}=\ln\lambda_{n}-\ln\lambda_{0}$ \end_inset - when a smooth transition in the stress is desired from compression to tension. + is the natural strain relative to the tensile stretch threshold. + This model produces a stress response which varies linearly with the natural + strain. \end_layout \begin_layout Standard @@ -59716,103 +62308,29 @@ Example \end_layout \begin_layout Standard -Single fiber oriented along -\begin_inset Formula $\mathbf{e}_{1}$ +Fiber model as specified in a solid mixture (Section +\begin_inset space ~ \end_inset -, embedded in a neo-Hookean ground matrix. -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0,0,0 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1000.0 -\end_layout - -\begin_layout LyX-Code - 0.45 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 5 -\end_layout - -\begin_layout LyX-Code - 20 -\end_layout - -\begin_layout LyX-Code - 3 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0 -\end_layout - -\begin_layout LyX-Code - 90 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout Standard - -\shape italic -Example -\shape default -: -\end_layout -\begin_layout Standard -Two fibers in the plane orthogonal to -\begin_inset Formula $\mathbf{e}_{1}$ -\end_inset +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Solid-Mixture" +plural "false" +caps "false" +noprefix "false" -, oriented at ±25 degrees relative to -\begin_inset Formula $\mathbf{e}_{3}$ \end_inset -, embedded in a neo-Hookean ground matrix. +) \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 0,0,0 + 1 \end_layout \begin_layout LyX-Code @@ -59820,47 +62338,11 @@ Two fibers in the plane orthogonal to \end_layout \begin_layout LyX-Code - 1000.0 -\end_layout - -\begin_layout LyX-Code - 0.45 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 5 -\end_layout - -\begin_layout LyX-Code - 20 -\end_layout - -\begin_layout LyX-Code - 3 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 90 -\end_layout - -\begin_layout LyX-Code - 25 + 0.13 \end_layout \begin_layout LyX-Code - + 0.3 \end_layout \begin_layout LyX-Code @@ -59868,35 +62350,19 @@ Two fibers in the plane orthogonal to \end_layout \begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 5 -\end_layout - -\begin_layout LyX-Code - 20 -\end_layout - -\begin_layout LyX-Code - 3 -\end_layout - -\begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - -90 + 1 \end_layout \begin_layout LyX-Code - 25 + 1.25 \end_layout \begin_layout LyX-Code - + 0,0,1 \end_layout \begin_layout LyX-Code @@ -59915,10 +62381,10 @@ Two fibers in the plane orthogonal to \end_layout \begin_layout Subsubsection -Fiber with Neo-Hookean Law +Fiber with Toe-Linear Response \begin_inset CommandInset label LatexCommand label -name "subsec:Fiber-with-Neo-Hookean" +name "subsec:Fiber-Pow-Linear" \end_inset @@ -59932,7 +62398,7 @@ This material type is \shape italic -fiber-NH +fiber-pow-linear \shape default \begin_inset Quotes erd @@ -59949,34 +62415,38 @@ fiber-NH \begin_inset Tabular - + - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\mu,$ +\begin_inset Formula $E,$ \end_inset - representing a measure of the fiber modulus + the fiber modulus in the linear range ( +\begin_inset Formula $E\geqslant0)$ +\end_inset + + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -59987,6 +62457,79 @@ P ] \end_layout +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\beta,$ +\end_inset + + the power-law exponent in the toe region ( +\begin_inset Formula $\beta\geqslant2)$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\lambda_{0},$ +\end_inset + + the stretch ratio when the toe region transitions to the linear region + ( +\begin_inset Formula $\lambda_{0}>1)$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + \end_inset @@ -60005,16 +62548,34 @@ P The fiber strain energy density is given by \begin_inset Formula \[ -\Psi_{n}\left(I_{n}\right)=\frac{\mu}{4}\left(I_{n}-1\right)^{2}\,, +\Psi_{n}\left(I_{n}\right)=\begin{cases} +0 & I_{n}<1\\ +\frac{\xi}{\beta}\left(I_{n}-1\right)^{\beta} & 1\leqslant I_{n}\leqslant I_{0}\\ +B\left(I_{n}-I_{0}\right)-E\left(I_{n}^{1/2}-I_{0}^{1/2}\right)+\frac{\xi}{\beta}\left(I_{0}-1\right)^{\beta} & I_{0}0$ +\begin_inset Formula $I_{0}=\lambda_{0}^{2}$ +\end_inset + +, +\begin_inset Formula +\[ +\xi=\frac{E}{4\left(\beta-1\right)}I_{0}^{-3/2}\left(I_{0}-1\right)^{2-\beta},\,B=\xi\left(I_{0}-1\right)^{\beta-1}+\frac{E}{2}I_{0}^{-1/2} +\] + +\end_inset + +For this material type, the fiber elasticity at the strain origin reduces + to zero unless +\begin_inset Formula $\beta=2$ \end_inset . + \end_layout \begin_layout Standard @@ -60026,14 +62587,14 @@ Example \end_layout \begin_layout Standard -Fiber model as specified in a continuous fiber distribution (Section +Fiber model as specified in a solid mixture (Section \begin_inset space ~ \end_inset \begin_inset CommandInset ref LatexCommand ref -reference "subsec:Unconstrained-Continuous-Fiber" +reference "subsec:Solid-Mixture" \end_inset @@ -60041,15 +62602,39 @@ reference "subsec:Unconstrained-Continuous-Fiber" \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - 1 + \end_layout \begin_layout LyX-Code - + 20 +\end_layout + +\begin_layout LyX-Code + 90 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 2.5 +\end_layout + +\begin_layout LyX-Code + 1.06 +\end_layout + +\begin_layout LyX-Code + \end_layout \begin_layout Standard @@ -60060,10 +62645,10 @@ reference "subsec:Unconstrained-Continuous-Fiber" \end_layout \begin_layout Subsubsection -Fiber with Natural Neo-Hookean Law +Fiber with Exp-Pow-Linear Response \begin_inset CommandInset label LatexCommand label -name "subsec:Fiber-with-Neo-Hookean-1" +name "subsec:Fiber-Exp-Pow-Linear" \end_inset @@ -60077,7 +62662,7 @@ This material type is \shape italic -fiber-natural-NH +fiber-exp-pow-linear \shape default \begin_inset Quotes erd @@ -60094,17 +62679,17 @@ fiber-natural-NH \begin_inset Tabular - + - + \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -60113,10 +62698,14 @@ fiber-natural-NH \begin_inset Text \begin_layout Plain Layout -\begin_inset Formula $\xi,$ +\begin_inset Formula $E,$ \end_inset - fiber modulus + the fiber modulus in the linear range ( +\begin_inset Formula $E\geqslant0)$ +\end_inset + + \end_layout \end_inset @@ -60136,7 +62725,75 @@ P - + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\alpha,$ +\end_inset + + coefficient of exponential argument +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $\beta,$ +\end_inset + + the power-law exponent in the toe region ( +\begin_inset Formula $\beta\geqslant2)$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + \begin_inset Text \begin_layout Plain Layout @@ -60145,19 +62802,24 @@ P \end_inset - + \begin_inset Text \begin_layout Plain Layout \begin_inset Formula $\lambda_{0},$ \end_inset - stretch threshold for tensile response + the stretch ratio when the toe region transitions to the linear region + ( +\begin_inset Formula $\lambda_{0}>1)$ +\end_inset + + \end_layout \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -60182,312 +62844,93 @@ P The fiber strain energy density is given by \begin_inset Formula \[ -\Psi_{n}\left(\lambda_{n}\right)=\frac{\xi}{2}H\left(\ln\frac{\lambda_{n}}{\lambda_{0}}\right)\left(\ln\frac{\lambda_{n}}{\lambda_{0}}\right)^{2}\,, +\Psi_{n}=\begin{cases} +0 & I_{n}<1\\ +\frac{\xi}{\alpha\beta}\left(\exp\left[\alpha\left(I_{n}-1\right)^{\beta}\right]-1\right) & 1\le I_{n}\le I_{0}\\ +B\left(I_{n}-I_{0}\right)-E\left(I_{n}^{1/2}-I_{0}^{1/2}\right)+\frac{\xi}{\alpha\beta}\left(\exp\left[\alpha\left(I_{0}-1\right)^{\beta}\right]-1\right) & I_{n}>I_{0} +\end{cases} \] \end_inset where -\begin_inset Formula $\xi>0$ +\begin_inset Formula $I_{0}=\lambda_{0}^{2}$ \end_inset - and -\begin_inset Formula $\lambda_{0}\ge1$ -\end_inset +, +\begin_inset Formula +\[ +\xi=\frac{E\left(I_{0}-1\right)^{2-\beta}\exp\left[-\alpha\left(I_{0}-1\right)^{\beta}\right]}{4I_{0}^{3/2}\left(\beta-1+\alpha\beta\left(I_{0}-1\right)^{\beta}\right)} +\] -. - The tensile response engages at the tensile stretch ratio -\begin_inset Formula $\lambda_{0}$ \end_inset - ( -\begin_inset Formula $\lambda_{0}=1$ -\end_inset +and +\begin_inset Formula +\[ +B=E\frac{2I_{0}\left(\beta-\frac{1}{2}+\alpha\beta\left(I_{0}-1\right)^{\beta}\right)-1}{4I_{0}^{3/2}\left(\beta-1+\alpha\beta\left(I_{0}-1\right)^{\beta}\right)} +\] - by default).The natural (logarithmic or Hencky) strain along the fiber is - -\begin_inset Formula $\ln\lambda_{n}$ \end_inset -, whereas -\begin_inset Formula $\ln\frac{\lambda_{n}}{\lambda_{0}}=\ln\lambda_{n}-\ln\lambda_{0}$ -\end_inset - is the natural strain relative to the tensile stretch threshold. - This model produces a stress response which varies linearly with the natural - strain. \end_layout \begin_layout Standard - -\shape italic -Example -\shape default -: -\end_layout - -\begin_layout Standard -Fiber model as specified in a solid mixture (Section -\begin_inset space ~ +For this material type, the fiber elasticity at the strain origin reduces + to zero unless +\begin_inset Formula $\beta=2$ \end_inset - -\begin_inset CommandInset ref -LatexCommand ref -reference "subsec:Solid-Mixture" -plural "false" -caps "false" -noprefix "false" - -\end_inset - -) -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0.13 -\end_layout - -\begin_layout LyX-Code - 0.3 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 1 -\end_layout - -\begin_layout LyX-Code - 1.25 -\end_layout - -\begin_layout LyX-Code - 0,0,1 -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - -\end_layout - -\begin_layout Standard -\begin_inset Newpage newpage -\end_inset - - -\end_layout - -\begin_layout Subsubsection -Fiber with Toe-Linear Response -\begin_inset CommandInset label -LatexCommand label -name "subsec:Fiber-Pow-Linear" - -\end_inset - - -\end_layout - -\begin_layout Standard -This material type is +. + This model reduces to \begin_inset Quotes eld \end_inset -\shape italic +\emph on fiber-pow-linear -\shape default +\emph default \begin_inset Quotes erd \end_inset -. - The following material parameters need to be defined: -\end_layout - -\begin_layout Standard -\align center -\begin_inset VSpace defskip -\end_inset - - -\begin_inset Tabular - - - - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $E,$ -\end_inset - - the fiber modulus in the linear range ( -\begin_inset Formula $E\geqslant0)$ -\end_inset - - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -[ -\series bold -P -\series default -] -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $\beta,$ -\end_inset - - the power-law exponent in the toe region ( -\begin_inset Formula $\beta\geqslant2)$ -\end_inset - - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -[ ] -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout - -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $\lambda_{0},$ -\end_inset - - the stretch ratio when the toe region transitions to the linear region - ( -\begin_inset Formula $\lambda_{0}>1)$ -\end_inset - - -\end_layout - + when +\begin_inset Formula $\alpha=0$ \end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -[ ] -\end_layout +. + Alternatively, in the limit when +\begin_inset Formula $I_{0}=1$ \end_inset - - - +, the above parameters reduce to +\begin_inset Formula $\xi=0$ \end_inset - -\begin_inset VSpace defskip + and +\begin_inset Formula $B=E/2$ \end_inset - -\end_layout - -\begin_layout Standard -The fiber strain energy density is given by + and the strain energy density takes the quadratic form \begin_inset Formula \[ -\Psi_{n}\left(I_{n}\right)=\begin{cases} +\Psi_{n}=\begin{cases} 0 & I_{n}<1\\ -\frac{\xi}{\beta}\left(I_{n}-1\right)^{\beta} & 1\leqslant I_{n}\leqslant I_{0}\\ -B\left(I_{n}-I_{0}\right)-E\left(I_{n}^{1/2}-I_{0}^{1/2}\right)+\frac{\xi}{\beta}\left(I_{0}-1\right)^{\beta} & I_{0}1 +\end{cases} \] \end_inset where -\begin_inset Formula $I_{0}=\lambda_{0}^{2}$ +\begin_inset Formula $I_{n}^{1/2}=\lambda_{n}$ \end_inset -, -\begin_inset Formula -\[ -\xi=\frac{E}{4\left(\beta-1\right)}I_{0}^{-3/2}\left(I_{0}-1\right)^{2-\beta},\,B=\xi\left(I_{0}-1\right)^{\beta-1}+\frac{E}{2}I_{0}^{-1/2} -\] - -\end_inset + is the stretch ratio along the fiber. +\end_layout +\begin_layout Standard \shape italic Example @@ -60511,39 +62954,38 @@ reference "subsec:Solid-Mixture" \end_layout \begin_layout LyX-Code - + \end_layout \begin_layout LyX-Code - + 1080 \end_layout \begin_layout LyX-Code - 20 + 1400 \end_layout \begin_layout LyX-Code - 90 + 2.73 \end_layout \begin_layout LyX-Code - + 1.012 \end_layout \begin_layout LyX-Code - 1 + 0,0,1 \end_layout \begin_layout LyX-Code - 2.5 + \end_layout -\begin_layout LyX-Code - 1.06 -\end_layout +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + -\begin_layout LyX-Code - \end_layout \begin_layout Subsubsection @@ -65468,7 +67910,7 @@ uncoupled reactive viscoelastic \begin_inset Tabular - + @@ -65660,7 +68102,7 @@ Weak bond material - + \begin_inset Text \begin_layout Plain Layout @@ -65669,7 +68111,7 @@ Weak bond material \end_inset - + \begin_inset Text \begin_layout Plain Layout @@ -65678,7 +68120,36 @@ Reduced relaxation function \end_inset - + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Weak bond recruitment function +\end_layout + +\end_inset + + \begin_inset Text \begin_layout Plain Layout @@ -65757,6 +68228,21 @@ reference "subsec:Relaxation-Functions" \end_inset +. + The material may be selected from the list provided in Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Cumulative-Distribution-Function" +plural "false" +caps "false" +noprefix "false" + +\end_inset + . \end_layout @@ -65870,6 +68356,26 @@ Example \end_layout +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 30 +\end_layout + +\begin_layout LyX-Code + 2 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + \begin_layout LyX-Code \end_layout @@ -66995,7 +69501,240 @@ t \begin_inset Text \begin_layout Plain Layout - + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Characteristic relaxation time +\begin_inset Formula $\tau_{2}$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +t +\series default +] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Power exponent +\begin_inset Formula $\beta$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard +These parameters must satisfy +\begin_inset Formula $\tau_{2}>\tau_{1}>0$ +\end_inset + +. + When +\begin_inset Formula $\beta\ne1$ +\end_inset + +, the reduced relaxation function for this material type is given by +\begin_inset Formula +\[ +g\left(t\right)=\frac{\left(\beta-1\right)t^{1-\beta}}{\tau_{1}^{1-\beta}-\tau_{2}^{1-\beta}}\left[\Gamma\left(\beta-1,\frac{t}{\tau_{2}}\right)-\Gamma\left(\beta-1,\frac{t}{\tau_{1}}\right)\right] +\] + +\end_inset + +where +\begin_inset Formula $\Gamma\left(a,z\right)$ +\end_inset + + is the incomplete gamma function. + In the limit as +\begin_inset Formula $\beta\to1$ +\end_inset + + this function reduces to the form given by +\begin_inset CommandInset citation +LatexCommand citep +key "Fung72" +literal "false" + +\end_inset + +, +\begin_inset Formula +\[ +g\left(t\right)=\frac{\Gamma\left(0,\frac{t}{\tau_{2}}\right)-\Gamma\left(0,\frac{t}{\tau_{1}}\right)}{\ln\frac{\tau_{2}}{\tau_{1}}}=\frac{\Ei\left(-\frac{t}{\tau_{2}}\right)-\Ei\left(-\frac{t}{\tau_{1}}\right)}{\ln\frac{\tau_{1}}{\tau_{2}}} +\] + +\end_inset + +where +\begin_inset Formula $\Ei\left(z\right)$ +\end_inset + + is the exponential integral function. +\end_layout + +\begin_layout Subsubsection +Malkin Distortional +\begin_inset CommandInset label +LatexCommand label +name "subsec:Malkin-distortional" + +\end_inset + + +\end_layout + +\begin_layout Standard +See Section +\begin_inset space ~ +\end_inset + + +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Malkin" +plural "false" +caps "false" +noprefix "false" + +\end_inset + + for the description of this relaxation function. + When the material parameters vary with the distortional strain +\begin_inset Formula $K_{2}$ +\end_inset + + according to +\begin_inset Formula +\[ +\begin{aligned}\tau_{1}\left(K_{2}\right) & =\tau_{10}+\tau_{11}\exp\left(-\frac{K_{2}}{s_{1}}\right)\\ +\tau_{2}\left(K_{2}\right) & =\tau_{20}+\tau_{21}\exp\left(-\frac{K_{2}}{s_{2}}\right) +\end{aligned} +\] + +\end_inset + + the material type is +\begin_inset Quotes eld +\end_inset + +relaxation-Malkin-distortion +\begin_inset Quotes erd +\end_inset + +. + The following material parameters need to be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\begin_inset Formula $\tau_{10}$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +t +\series default +] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + \end_layout \end_inset @@ -67004,8 +69743,8 @@ t \begin_inset Text \begin_layout Plain Layout -Characteristic relaxation time -\begin_inset Formula $\tau_{2}$ +Parameter +\begin_inset Formula $\tau_{11}$ \end_inset @@ -67024,6 +69763,146 @@ t ] \end_layout +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\begin_inset Formula $s_{1}$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\begin_inset Formula $\tau_{20}$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +t +\series default +] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\begin_inset Formula $\tau_{21}$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\series bold +t +\series default +] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\begin_inset Formula $s_{2}$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + \end_inset @@ -67041,11 +69920,11 @@ t \begin_inset Text \begin_layout Plain Layout -Power exponent +Poiwer exponent \begin_inset Formula $\beta$ \end_inset - + \end_layout \end_inset @@ -67054,7 +69933,7 @@ Power exponent \begin_inset Text \begin_layout Plain Layout -[ ] +[ ] \end_layout \end_inset @@ -67072,53 +69951,37 @@ Power exponent \end_layout \begin_layout Standard -These parameters must satisfy -\begin_inset Formula $\tau_{2}>\tau_{1}>0$ +The definition of +\begin_inset Formula $K_{2}$ \end_inset -. - When -\begin_inset Formula $\beta\ne1$ + is given in Section +\begin_inset space ~ \end_inset -, the reduced relaxation function for this material type is given by -\begin_inset Formula -\[ -g\left(t\right)=\frac{\left(\beta-1\right)t^{1-\beta}}{\tau_{1}^{1-\beta}-\tau_{2}^{1-\beta}}\left[\Gamma\left(\beta-1,\frac{t}{\tau_{2}}\right)-\Gamma\left(\beta-1,\frac{t}{\tau_{1}}\right)\right] -\] - -\end_inset -where -\begin_inset Formula $\Gamma\left(a,z\right)$ -\end_inset +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Exp-Dist-User" - is the incomplete gamma function. - In the limit as -\begin_inset Formula $\beta\to1$ \end_inset - this function reduces to the form given by -\begin_inset CommandInset citation -LatexCommand citep -key "Fung72" -literal "false" - +. + See Section +\begin_inset space ~ \end_inset -, -\begin_inset Formula -\[ -g\left(t\right)=\frac{\Gamma\left(0,\frac{t}{\tau_{2}}\right)-\Gamma\left(0,\frac{t}{\tau_{1}}\right)}{\ln\frac{\tau_{2}}{\tau_{1}}}=\frac{\Ei\left(-\frac{t}{\tau_{2}}\right)-\Ei\left(-\frac{t}{\tau_{1}}\right)}{\ln\frac{\tau_{1}}{\tau_{2}}} -\] -\end_inset +\begin_inset CommandInset ref +LatexCommand ref +reference "subsec:Exp-Dist-User" +plural "false" +caps "false" +noprefix "false" -where -\begin_inset Formula $\Ei\left(z\right)$ \end_inset - is the exponential integral function. + for examples of how to specify these functions. \end_layout \begin_layout Subsubsection @@ -69319,7 +72182,7 @@ Cumulative distribution functions provide the function Simo \begin_inset CommandInset label LatexCommand label -name "subsec:Simo" +name "subsec:CDF-Simo" \end_inset @@ -69556,7 +72419,7 @@ Example: Log-Normal \begin_inset CommandInset label LatexCommand label -name "subsec:Log-Normal" +name "subsec:CDF-log-normal" \end_inset @@ -69812,7 +72675,7 @@ Example: Weibull \begin_inset CommandInset label LatexCommand label -name "subsec:Weibull" +name "subsec:CDF-Weibull" \end_inset @@ -70072,7 +72935,7 @@ Example: Quintic Polynomial \begin_inset CommandInset label LatexCommand label -name "subsec:Quintic-Polynomial" +name "subsec:CDF-quintic" \end_inset @@ -70240,41 +73103,233 @@ For this material the c.d.f. is given by \begin_inset Formula \[ -F\left(\Xi\right)=\begin{cases} -0 & \Xi\leqslant\mu_{\min}\\ -x^{3}\left(10-15x+6x^{2}\right) & \mu_{\min}<\Xi\leqslant\mu_{\max}\\ -1 & \mu_{\max}<\Xi -\end{cases}\,,\quad x=\frac{\Xi-\mu_{\min}}{\mu_{\max}-\mu_{\min}}\,. -\] - -\end_inset - -Note that -\begin_inset Formula -\[ -F\left(\frac{1}{2}\left(\mu_{\min}+\mu_{\max}\right)\right)=\frac{1}{2}\,, +F\left(\Xi\right)=\begin{cases} +0 & \Xi\leqslant\mu_{\min}\\ +x^{3}\left(10-15x+6x^{2}\right) & \mu_{\min}<\Xi\leqslant\mu_{\max}\\ +1 & \mu_{\max}<\Xi +\end{cases}\,,\quad x=\frac{\Xi-\mu_{\min}}{\mu_{\max}-\mu_{\min}}\,. +\] + +\end_inset + +Note that +\begin_inset Formula +\[ +F\left(\frac{1}{2}\left(\mu_{\min}+\mu_{\max}\right)\right)=\frac{1}{2}\,, +\] + +\end_inset + +which shows that +\begin_inset Formula $\left(\mu_{\min}+\mu_{\max}\right)/2$ +\end_inset + + is the value of +\begin_inset Formula $\Xi$ +\end_inset + + at which half of the bonds break. + The range +\begin_inset Formula $\mu_{\max}-\mu_{\min}$ +\end_inset + + regulates the rate at which damage increases with increasing +\begin_inset Formula $\Xi$ +\end_inset + +, with a narrower range producing a more rapid increase. +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Graphics + filename Figures/FigDamageCDFQuintic.png + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard + +\shape italic +Example: +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 0.3 +\end_layout + +\begin_layout LyX-Code + 1.7 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout Standard +\begin_inset Newpage newpage +\end_inset + + +\end_layout + +\begin_layout Subsubsection +Step +\begin_inset CommandInset label +LatexCommand label +name "subsec:CDF-Step" + +\end_inset + + +\end_layout + +\begin_layout Standard +The material type for a step c.d.f. + is +\begin_inset Quotes eld +\end_inset + + +\shape italic +CDF step +\begin_inset Quotes erd +\end_inset + + +\shape default +. + The following material parameters must be defined: +\end_layout + +\begin_layout Standard +\align center +\begin_inset VSpace defskip +\end_inset + + +\begin_inset Tabular + + + + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\begin_inset Formula $\mu$ +\end_inset + + (same units as +\begin_inset Formula $\Xi)$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ +\begin_inset Formula $\Xi$ +\end_inset + +] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Maximum allowable damage (optional, default is 1) +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\end_inset + + +\begin_inset VSpace defskip +\end_inset + + +\end_layout + +\begin_layout Standard +For this material the c.d.f. + is given by +\begin_inset Formula +\[ +F\left(\Xi\right)=H\left(\Xi\right)\quad, \] \end_inset -which shows that -\begin_inset Formula $\left(\mu_{\min}+\mu_{\max}\right)/2$ -\end_inset - - is the value of -\begin_inset Formula $\Xi$ -\end_inset - - at which half of the bonds break. - The range -\begin_inset Formula $\mu_{\max}-\mu_{\min}$ -\end_inset - - regulates the rate at which damage increases with increasing -\begin_inset Formula $\Xi$ +where +\begin_inset Formula $H\left(\cdot\right)$ \end_inset -, with a narrower range producing a more rapid increase. + is the Heaviside unit step function. + The step c.d.f. + may be used to model fracture. \end_layout \begin_layout Standard @@ -70284,7 +73339,7 @@ which shows that \begin_inset Graphics - filename Figures/FigDamageCDFQuintic.png + filename Figures/FigDamageCDFStep.png \end_inset @@ -70302,15 +73357,11 @@ Example: \end_layout \begin_layout LyX-Code - -\end_layout - -\begin_layout LyX-Code - 0.3 + \end_layout \begin_layout LyX-Code - 1.7 + 1.0 \end_layout \begin_layout LyX-Code @@ -70329,10 +73380,10 @@ Example: \end_layout \begin_layout Subsubsection -Step +Power \begin_inset CommandInset label LatexCommand label -name "subsec:Step" +name "subsec:CDF-power" \end_inset @@ -70340,14 +73391,14 @@ name "subsec:Step" \end_layout \begin_layout Standard -The material type for a step c.d.f. +The material type for a power c.d.f. is \begin_inset Quotes eld \end_inset \shape italic -CDF step +CDF power \begin_inset Quotes erd \end_inset @@ -70364,7 +73415,7 @@ CDF step \begin_inset Tabular - + @@ -70374,7 +73425,7 @@ CDF step \begin_inset Text \begin_layout Plain Layout - + \end_layout \end_inset @@ -70384,11 +73435,40 @@ CDF step \begin_layout Plain Layout Parameter -\begin_inset Formula $\mu$ +\begin_inset Formula $\mu_{0}$ \end_inset - (same units as -\begin_inset Formula $\Xi)$ + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\begin_inset Formula $\mu_{1}$ \end_inset @@ -70396,7 +73476,73 @@ Parameter \end_inset - + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Power exponent +\begin_inset Formula $\alpha$ +\end_inset + + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +[ ] +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout + +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Scale factor +\begin_inset Formula $s$ +\end_inset + + +\end_layout + +\end_inset + + \begin_inset Text \begin_layout Plain Layout @@ -70404,7 +73550,7 @@ Parameter \begin_inset Formula $\Xi$ \end_inset -] +] \end_layout \end_inset @@ -70433,7 +73579,7 @@ Maximum allowable damage (optional, default is 1) \begin_inset Text \begin_layout Plain Layout -[ ] +[ ] \end_layout \end_inset @@ -70455,50 +73601,38 @@ For this material the c.d.f. is given by \begin_inset Formula \[ -F\left(\Xi\right)=H\left(\Xi\right)\quad, +F\left(\Xi\right)=\mu_{0}+\mu_{1}\left(\frac{\Xi}{s}\right)^{\alpha}. \] \end_inset -where -\begin_inset Formula $H\left(\cdot\right)$ -\end_inset - is the Heaviside unit step function. - The step c.d.f. - may be used to model fracture. \end_layout \begin_layout Standard -\align center -\begin_inset VSpace defskip -\end_inset - - -\begin_inset Graphics - filename Figures/FigDamageCDFStep.png - -\end_inset - - -\begin_inset VSpace defskip -\end_inset +\shape italic +Example: +\end_layout +\begin_layout LyX-Code + \end_layout -\begin_layout Standard +\begin_layout LyX-Code + 0.1 +\end_layout -\shape italic -Example: +\begin_layout LyX-Code + 10 \end_layout \begin_layout LyX-Code - + 0.5 \end_layout \begin_layout LyX-Code - 1.0 + 100 \end_layout \begin_layout LyX-Code @@ -73405,6 +76539,72 @@ Example: Steel (in-lbf-s units) \end_layout +\begin_layout Standard + +\shape italic +Example: elastic-perfectly plastic response, using PFC math flow curve +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 200000 +\end_layout + +\begin_layout LyX-Code + 0.3 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 0.001 +\end_layout + +\begin_layout LyX-Code + 1 +\end_layout + +\begin_layout LyX-Code + 200 +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + \begin_layout LyX-Code \end_layout @@ -96690,6 +99890,36 @@ This defines the data function as a function of time. \end_layout +\begin_layout Standard +As another example, the following creates a stress-strain curve for a single + solid element, using the left Hencky (logarithmic) strain component along + the z-axis (denoted by +\emph on +hz +\emph default +), and the Cauchy normal stress component along z-axis (denoted by +\emph on +sz +\emph default +) in element number 1, +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code + +\end_layout + \begin_layout Subsubsection The target model \end_layout diff --git a/Documentation/FEBio_User_Manual.pdf b/Documentation/FEBio_User_Manual.pdf index 684079edd..c3274507a 100644 Binary files a/Documentation/FEBio_User_Manual.pdf and b/Documentation/FEBio_User_Manual.pdf differ diff --git a/Documentation/Figures/FigOrthoBases.png b/Documentation/Figures/FigOrthoBases.png new file mode 100644 index 000000000..61279255b Binary files /dev/null and b/Documentation/Figures/FigOrthoBases.png differ diff --git a/Documentation/Figures/FigRotationAboutX3.png b/Documentation/Figures/FigRotationAboutX3.png new file mode 100644 index 000000000..c661e3664 Binary files /dev/null and b/Documentation/Figures/FigRotationAboutX3.png differ diff --git a/Documentation/ReleaseNotes.txt b/Documentation/ReleaseNotes.txt index 2301cfce8..0b919b4cc 100644 --- a/Documentation/ReleaseNotes.txt +++ b/Documentation/ReleaseNotes.txt @@ -39,6 +39,124 @@ the FEBio User's Manual for a more detailed description of the new features. To report any bugs or request new features, please visit the FEBio forum at https://forums.febio.org/. +=========================================================================== + + R E L E A S E 3.7 6/15/2022 + +=========================================================================== + +* Added support for setting solver parameters via restart input file. +* Clarified error message when a property fails to initialize. +* Improved speed of initialization of FSI problems. +* Aded lung material and documentation. +* Added warning that nonzero value for dtmax will be ignored when must points were defined. +* Fixed some issues related to reset of contact problems. This bug could have affected outcome of parameter optimization for certain contact problems. +* Modified the reset test to print out some useful stats. +* Allowed export to specific domains for domain plot variables. Previously this was only supported for some surface plot variables. +* Made a change to HGOCoronary so that fiber vector plot variable works for this material. +* Contact potential now outputs nonzero values for contact pressure and contact area. +* Implemented parameter scaling option for constrained levmar. To enable parameter scaling, set the control parameter "scale_parameter" to 1. +* Box constraints are now enforced explicitly in constrained levmar. +* Added model log data classes. Added log variable for printing solution vector norm. +* For prestrain materials, the density now takes the prestrain into account. +* Added Shenoy material and documented it in user manual. +* Local coordinate system is now taken into account in FEHGOCoronary. +* Updated reactive viscoelastic materials to properly account for damage when the elastic bond material is modeled with either a reactive damage or a reactive fatigue material. +* Added integral of solute concentration log data. +* Added log output option for printing integral of sbm concentration. +* Fixed serialization of contact material point data. +* Fixed issue with reallocation of linear system during restart. +* Implemented missing Serialize functions for FELinearElasticFluid and FENonlinearElasticFluid. +* Added serialization of FEBiphasicFSIDomain3D::m_btrans. +* Added missing serialization of generic hyperelastic materials. +* Fixed serialization of FEBearingLoad. +* Fixed restart and serialization issues with linear constraints. +* Fixed serialization issues for model parameters. Added missing serialization of FEInSituStretchGradient. +* Added missing Serialize to FEReactivePlasticity. +* Minor change to FEUT4Domain::Create to avoid problem with restart. +* Added serialization for FEMathFunction. +* Added missing serialization of FEBiphasicSolidDomain::m_nodePressure. +* Added "test" solver, which doesn't solve anything, just returns zeroes. (Added to facilitate debugging of large problems.) +* Fixed issue with allocation of default "elastic" property of FEFluid. +* Implemented HGO-coronary material. +* Added "facet area" plot variable. +* Added small clarification about elasticity of some fiber models at strain origin. +* Updated User Manual to include description of solute natural flux, CDF power, and plot variable RVE strain +* Added new 'solute natural flux' surface load for biphasic-solute and multiphasic domains which prescribes a solute molar flux equal to (solute concentration)*(solvent volumetric flux) on a boundary, where concentration and fluid flux are averaged from the element underneath the selected boundary face. This allows a solute to naturally flow out of a boundary without the user having to prescribe a solute concentration or specific value of solute flux on that boundary. Current implementation has a barebones stiffness matrix, may need to be fully populated in future implementation. +* Minor cleaning up of reactive viscoelastic code. +* Added a scaling parameter to FEDamageCDFPower. +* E parameter of FEFiberPowLinearUncoupled a FEParamDouble. +* Added description of auto time step algorithm for reducing the time step size in user manual. +* Expanded user manual entry for fiber-exp-pow-linear +* Fixed user manual entry for definition of formulas related to fiber-exp-pow-linear +* Fixed bug in newly introduced fiber-exp-pow-linear, to enforce continuity of the elasticity at the exp-pow-linear transition. +* Added FEGlobalVariable to prevent memory leak when adding global variables. Global variables are now also copied in FEModel::CopyFrom. +* Added feature for developers, to plot scalar value of prescribed surface load. Modified FEBearingLoad and FEFluidNormalVelocity to test it out. +* Updated User Manual to describe new bearing load +* Added functionality to prescribed a radial bearing load on a cylindrical surface (FEBearingLoad). Copied and adapted Quadric and QuadricFit functions from FEBioStudio to fit bearing surface and detect its axial and radial directions. Updated vec3d and matrix to reproduce missing functionalities that are available in their FEBioStudio equivalents. Updated surface element traits to include/return parametric coordinates of the surface centroid (in parametric space). +* Added serialization of surface pairs. +* Added operators for mat3d+/-/* mat3da and for mat3d+/-mat3ds operation +* Added description of surface force load in User Manual +* Added functionality for prescribing a force on a surface which is converted to a uniform traction. +* Added description of fixed normal displacement constraint +* Added functionality for prescribing a fixed normal displacement constraint. +* Cleaned up FEForceVelocityMaterialPoint and provided missing default values for some of the material parameters. +* Updated User Manual to describe the force-velocity-Estrada active fiber contraction model +* Modified FERVEDamageMaterial to a working version +* Fixed one more item to make FEDamageMaterialUC more consistent with FEDamageMaterial. +* Added description of fiber-exp-pow-linear material +* Added symbolic derivative for H (Heavyside function). +* Modified FEDamageMaterialUC to be consistent with FEDamageMaterial. Replaced FEFiberPowerLinear (which was duplicate of FEFiberPowLinear) with FEFiberExpPowLinear, which uses exponential-power law in the toe region. +* Deleted old (invalid) FEFatigueMaterial +* Derived FEPolynomialHyperElastic from FEElasticMaterial instead of FEUncoupledMaterial, since this material won't work with the three-field formulation. +* Fixed base class call in FEActiveFiberContraction::Init. +* Added pre-stretch functions to FEElasticFiberMaterial to replicate capabilities previously implemented in FEElasticFiberMaterialUC +* Added another example of parameter optimization specification in user manual. +* Fixed trans iso materials that use active fiber contraction to not crash when active fiber contraction is not included. +* Updated FETransIsoMooney-Rivlin and FETransIsoVerandaWestmann to use FEActiveContractionMaterial class to accommodate multiple active fiber contraction materials. +* Derived FEActiveFiberContraction from FEActiveContractionMaterial. +* Added Ana Estrada's model for force-velocity contraction of the cardiac muscle, superposed on a trans iso Mooney-Rivlin material. +* Added new materials "reactive fatigue" and "uncoupled reactive fatigue". +* Added check for repeated time coordinates in load curves. +* Added "infinitesimal strain" plot variable. +* Modified plot parameter so that it maps directly for FMT_MULT data maps without projecting to nodes. +* Fixed bug in closest-point-projection and FESurfaceElement::facet_edge. +* Added getter for FEDataMap to FEMappedValue. +* Fixed some issues with the MDerive operator. +* Fixed issue with evaluating math expression's derivatives. +* Implemented (uncoupled) polynomial hyperelastic material. +* Created missing UpdateSpecializedMaterialPoints function for FEBiphasic, FEBiphasicSolute, FETriphasic and FEMultiphasic materials. Also updated Init() function for these materials. +* Fixed output issue when reporting boolean load parameter values. +* Modified plot logic so that for multi-step analysis, first state is written after first step activation. +* Now checking if the contact interface is active when writing contact plot variables. +* Added support for shells in "density" plot variable. +* Fixed bug in FELogElemSolidStress. +* Implemented support for shells in "Lagrange Strain". +* The "relative volume" plot variable now also supports shells. +* Fixed bad cast issue in FEMassDamping::force. +* Added method to store and plot correct value of uncoupled pressure (for uncoupled materials), including when using 3-field formulation. +* Added trace-free neo-Hookean material, which can be used in ground matrix of solid component of biphasic materials, for equivalence with Mooney-Rivlin material when comparing short-term biphasic and uncoupled elastic responses. +* Fixed bug when passing material point array data in uncoupled elastic mixtures. +* Added FEBondRelaxationMalkinDist continuous spectrum relaxation function with distortional strain-dependent time constants. Added FEDamageCDFPower power-law (pseudo-)damage CDF, which can be useful for specifying weak bond recruitment in reactive viscoelastic materials. +* Fixed issues with CopyFrom for discrete domains. +* Fixed bug reading dump level from cmd + dump at must-points (#37) +* Added log variables for solid stress. +* Added log output for permeability. +* Renamed the "general spring" to "nonlinear spring" +* Implemented new general spring material. +* Added example for reactive plasticity with PFC math flow curve +* Added regression coefficient (R2) as output of parameter optimization analyses (linear regression between y=fitted and x=data). Added ability to fit the y-value of points on point functions representing material parameters. +* Added recruitment module to reactive viscoelastic and uncoupled reactive viscoelastic materials to further accommodate nonlinear viscoelastic response with increasing strain. Added plot variable RVE strain to report the strain measure used for recruitment. Extended Weibull CDF to incorporate location parameter. +* Fixed bug with assignment operator of model parameters. +* Fixed issue with allocation and serialization of discrete element sets. +* Fixed bug in ParseBCFix when reading comma-separated list of dofs. +* Added Appendix A in Theory Manual as review of tensor calculus +* Added scale parameter to nonlinear spring. +* Added log options to output discrete element stretch, elongation, force. +* Added mesh_adaptor property to FEModel. +* Added option to repeat must-points. + + =========================================================================== R E L E A S E 3.6 2/18/2022 diff --git a/FEBio3/FEBioApp.cpp b/FEBio3/FEBioApp.cpp index 9119de96b..04473bfbd 100644 --- a/FEBio3/FEBioApp.cpp +++ b/FEBio3/FEBioApp.cpp @@ -288,8 +288,8 @@ bool FEBioApp::ParseCmdLine(int nargs, char* argv[]) else if (strncmp(sz, "-dump", 5) == 0) { ops.dumpLevel = FE_DUMP_MAJOR_ITRS; - if (sz[8] == '=') ops.dumpLevel = atoi(sz + 9); - if ((ops.dumpLevel < 0) || (ops.dumpLevel > 2)) + if (sz[5] == '=') ops.dumpLevel = atoi(sz + 6); + if ((ops.dumpLevel < 0) || (ops.dumpLevel > 3)) { fprintf(stderr, "FATAL ERROR: invalid restart level.\n"); return false; diff --git a/FEBio3/FEBioCommand.cpp b/FEBio3/FEBioCommand.cpp index dece7e0ff..6605083fd 100644 --- a/FEBio3/FEBioCommand.cpp +++ b/FEBio3/FEBioCommand.cpp @@ -158,9 +158,10 @@ int FEBioCmd_Restart::run(int nargs, char** argv) printf("Restart level set to: "); switch (dumpLevel) { - case FE_DUMP_NEVER : printf("NEVER (0)\n"); break; - case FE_DUMP_MAJOR_ITRS: printf("MAJOR_ITRS (1)\n"); break; - case FE_DUMP_STEP : printf("STEP (2)\n"); break; + case FE_DUMP_NEVER : printf("NEVER (0)\n"); break; + case FE_DUMP_MAJOR_ITRS : printf("MAJOR_ITRS (1)\n"); break; + case FE_DUMP_STEP : printf("STEP (2)\n"); break; + case FE_DUMP_MUST_POINTS: printf("MUST POINTS (3)\n"); break; default: printf("(unknown value)\n"); break; diff --git a/FEBioFluid/FEBioFluidPlot.cpp b/FEBioFluid/FEBioFluidPlot.cpp index ac59e07a6..758562ee0 100644 --- a/FEBioFluid/FEBioFluidPlot.cpp +++ b/FEBioFluid/FEBioFluidPlot.cpp @@ -153,9 +153,6 @@ bool FEPlotFluidSurfaceForce::Save(FESurface &surf, FEDataStream &a) FESurface* pcs = &surf; if (pcs == 0) return false; - // Evaluate this field only for a specific domain, by checking domain name - if (pcs->GetName() != GetDomainName()) return false; - int NF = pcs->Elements(); vec3d fn(0,0,0); // initialize @@ -252,9 +249,6 @@ bool FEPlotFluidSurfaceTractionPower::Save(FESurface &surf, FEDataStream &a) { FESurface* pcs = &surf; if (pcs == 0) return false; - - // Evaluate this field only for a specific domain, by checking domain name - if (pcs->GetName() != GetDomainName()) return false; int NF = pcs->Elements(); double fn = 0; // initialize @@ -313,9 +307,6 @@ bool FEPlotFluidSurfaceEnergyFlux::Save(FESurface &surf, FEDataStream &a) { FESurface* pcs = &surf; if (pcs == 0) return false; - - // Evaluate this field only for a specific domain, by checking domain name - if (pcs->GetName() != GetDomainName()) return false; int NF = pcs->Elements(); double fn = 0; // initialize @@ -374,9 +365,6 @@ bool FEPlotFluidMassFlowRate::Save(FESurface &surf, FEDataStream &a) { FESurface* pcs = &surf; if (pcs == 0) return false; - - // Evaluate this field only for a specific domain, by checking domain name - if (pcs->GetName() != GetDomainName()) return false; FEModel* fem = GetFEModel(); int dofWX = fem->GetDOFIndex("wx"); @@ -442,9 +430,6 @@ bool FEPlotFluidFlowRate::Save(FESurface &surf, FEDataStream &a) FESurface* pcs = &surf; if (pcs == 0) return false; - // Evaluate this field only for a specific domain, by checking domain name - if (pcs->GetName() != GetDomainName()) return false; - int NF = pcs->Elements(); double fn = 0; // initialize diff --git a/FEBioFluid/FEBiphasicFSIDomain3D.cpp b/FEBioFluid/FEBiphasicFSIDomain3D.cpp index ad364c40c..0f8f43f2f 100644 --- a/FEBioFluid/FEBiphasicFSIDomain3D.cpp +++ b/FEBioFluid/FEBiphasicFSIDomain3D.cpp @@ -1091,5 +1091,5 @@ void FEBiphasicFSIDomain3D::ElementInertialForce(FESolidElement& el, vectorGetGlobalConstant("T"); if (m_pElastic == nullptr) { - m_pElastic = new FELinearElasticFluid(GetFEModel()); + m_pElastic = fecore_alloc(FELinearElasticFluid, GetFEModel()); } FELinearElasticFluid* pLN = dynamic_cast(m_pElastic); FENonlinearElasticFluid* pNL = dynamic_cast(m_pElastic); diff --git a/FEBioFluid/FEFluidNormalVelocity.cpp b/FEBioFluid/FEFluidNormalVelocity.cpp index 560d738fa..2e6e048b2 100644 --- a/FEBioFluid/FEFluidNormalVelocity.cpp +++ b/FEBioFluid/FEFluidNormalVelocity.cpp @@ -71,6 +71,7 @@ double FEFluidNormalVelocity::NormalVelocity(FESurfaceMaterialPoint& mp) FESurfaceElement& el = *mp.SurfaceElement(); double vn = 0; double* N = mp.m_shape; + if (N == nullptr) return 0; int neln = el.Nodes(); for (int i = 0; im_timeController == nullptr) bout = (pstep->m_nplotRange[0] == 0) || (pstep->m_bplotZero); + // for multi-step analyses, some plot variables can't be plot until the first step + // is activated. So, in that case, we'll wait. + if ((nevent == CB_INIT) && (Steps() > 1)) bout = false; + // store initial time step (i.e. time step zero) + if (bout) + { + double time = GetTime().currentTime; + m_plot->Write((float)time); + } + } + } + else + { + // for multi-step analyses, we did not write the initial time step during CB_INIT + // so we'll do it during the activation of the first step. + if ((nevent == CB_STEP_ACTIVE) && (Steps() > 1) && (GetCurrentStepIndex() == 0)) + { double time = GetTime().currentTime; - if (bout) m_plot->Write((float)time); + m_plot->Write((float)time); } } } @@ -587,12 +610,21 @@ void FEBioModel::WriteData(unsigned int nevent) //! Dump state to archive for restarts void FEBioModel::DumpData(int nevent) { + // get the current step + FEAnalysis* pstep = GetCurrentStep(); int ndump = GetDumpLevel(); if (ndump == FE_DUMP_NEVER) return; bool bdump = false; - if ((nevent == CB_STEP_SOLVED) && (ndump == FE_DUMP_STEP)) bdump = true; - if ((nevent == CB_MAJOR_ITERS) && (ndump == FE_DUMP_MAJOR_ITRS)) bdump = true; + switch (nevent) + { + case CB_MAJOR_ITERS: + if (ndump == FE_DUMP_MAJOR_ITRS) bdump = true; + if ((ndump == FE_DUMP_MUST_POINTS) && (pstep->m_timeController) && (pstep->m_timeController->m_nmust >= 0)) bdump = true; + break; + case CB_STEP_SOLVED: if (ndump == FE_DUMP_STEP) bdump = true; break; + } + if (bdump) { DumpFile ar(*this); @@ -1468,10 +1500,10 @@ bool FEBioModel::Reset() } } - m_ntimeSteps = 0; - m_ntotalIters = 0; - m_ntotalRHS = 0; - m_ntotalReforms = 0; + m_stats.ntimeSteps = 0; + m_stats.ntotalIters = 0; + m_stats.ntotalRHS = 0; + m_stats.ntotalReforms = 0; // do the callback DoCallback(CB_INIT); @@ -1494,10 +1526,10 @@ void FEBioModel::on_cb_solved() if (Steps() > 1) { feLog("\n\n N O N L I N E A R I T E R A T I O N S U M M A R Y\n\n"); - feLog("\tNumber of time steps completed .................... : %d\n\n", m_ntimeSteps); - feLog("\tTotal number of equilibrium iterations ............ : %d\n\n", m_ntotalIters); - feLog("\tTotal number of right hand evaluations ............ : %d\n\n", m_ntotalRHS); - feLog("\tTotal number of stiffness reformations ............ : %d\n\n", m_ntotalReforms); + feLog("\tNumber of time steps completed .................... : %d\n\n", m_stats.ntimeSteps); + feLog("\tTotal number of equilibrium iterations ............ : %d\n\n", m_stats.ntotalIters); + feLog("\tTotal number of right hand evaluations ............ : %d\n\n", m_stats.ntotalRHS); + feLog("\tTotal number of stiffness reformations ............ : %d\n\n", m_stats.ntotalReforms); } // get and print elapsed time @@ -1605,8 +1637,8 @@ void FEBioModel::on_cb_stepSolved() } // add to stats - m_ntimeSteps += step->m_ntimesteps; - m_ntotalIters += step->m_ntotiter; - m_ntotalRHS += step->m_ntotrhs; - m_ntotalReforms += step->m_ntotref; + m_stats.ntimeSteps += step->m_ntimesteps; + m_stats.ntotalIters += step->m_ntotiter; + m_stats.ntotalRHS += step->m_ntotrhs; + m_stats.ntotalReforms += step->m_ntotref; } diff --git a/FEBioLib/FEBioModel.h b/FEBioLib/FEBioModel.h index 349ede01b..24032d21b 100644 --- a/FEBioLib/FEBioModel.h +++ b/FEBioLib/FEBioModel.h @@ -40,7 +40,16 @@ SOFTWARE.*/ enum FE_Dump_Level { FE_DUMP_NEVER, // never write a dump file FE_DUMP_MAJOR_ITRS, // create a dump file at the end of each converged time step - FE_DUMP_STEP // create a dump file at the end of an analysis step + FE_DUMP_STEP, // create a dump file at the end of an analysis step + FE_DUMP_MUST_POINTS // create a dump file only on must-points +}; + +//----------------------------------------------------------------------------- +struct ModelStats { + int ntimeSteps; //!< total nr of time steps + int ntotalIters; //!< total nr of equilibrium iterations + int ntotalRHS; //!< total nr of right hand side evaluations + int ntotalReforms; //!< total nr of stiffness reformations }; //----------------------------------------------------------------------------- @@ -171,6 +180,9 @@ class FEBIOLIB_API FEBioModel : public FEMechModel //! Set the log level void SetLogLevel(int logLevel); + //! Get the stats + ModelStats GetModelStats() const; + private: void print_parameter(FEParam& p, int level = 0); void print_parameter_list(FEParameterList& pl, int level = 0); @@ -196,10 +208,7 @@ class FEBIOLIB_API FEBioModel : public FEMechModel private: // accumulative statistics - int m_ntimeSteps; //!< total nr of time steps - int m_ntotalIters; //!< total nr of equilibrium iterations - int m_ntotalRHS; //!< total nr of right hand side evaluations - int m_ntotalReforms; //!< total nr of stiffness reformations + ModelStats m_stats; protected: // file names std::string m_sfile_title; //!< input file title diff --git a/FEBioLib/FEBioStdSolver.cpp b/FEBioLib/FEBioStdSolver.cpp index 55a052518..ab8317e17 100644 --- a/FEBioLib/FEBioStdSolver.cpp +++ b/FEBioLib/FEBioStdSolver.cpp @@ -33,6 +33,7 @@ SOFTWARE.*/ #include #include #include +#include //----------------------------------------------------------------------------- FEBioStdSolver::FEBioStdSolver(FEModel* pfem) : FECoreTask(pfem) {} @@ -190,3 +191,31 @@ bool FEBioRCISolver::Run() return true; } + +//========================================================================== +FEBioTestSuiteTask::FEBioTestSuiteTask(FEModel* fem) : FECoreTask(fem) {} + +//! initialization +bool FEBioTestSuiteTask::Init(const char* szfile) +{ + FEModel* fem = GetFEModel(); assert(fem); + if (fem == nullptr) return false; + + // See if the model defines any data records + DataStore& data = fem->GetDataStore(); + if (data.Size() == 0) + { + FEModelDataRecord* rec = new FEModelDataRecord(fem, nullptr); + rec->SetData("solution_norm"); + rec->SetName("solution_norm"); + data.AddRecord(rec); + } + + return (GetFEModel() ? GetFEModel()->Init() : false); +} + +//! Run the FE model +bool FEBioTestSuiteTask::Run() +{ + return (GetFEModel() ? GetFEModel()->Solve() : false); +} diff --git a/FEBioLib/FEBioStdSolver.h b/FEBioLib/FEBioStdSolver.h index ddc7bb197..f112fe320 100644 --- a/FEBioLib/FEBioStdSolver.h +++ b/FEBioLib/FEBioStdSolver.h @@ -71,3 +71,17 @@ class FEBioRCISolver : public FECoreTask //! Run the FE model bool Run() override; }; + +//----------------------------------------------------------------------------- +// Configures the model for running in the nightly test suite. +class FEBioTestSuiteTask : public FECoreTask +{ +public: + FEBioTestSuiteTask(FEModel* fem); + + //! initialization + bool Init(const char* szfile) override; + + //! Run the FE model + bool Run() override; +}; diff --git a/FEBioLib/febiolib.cpp b/FEBioLib/febiolib.cpp index 43573c818..0254727e1 100644 --- a/FEBioLib/febiolib.cpp +++ b/FEBioLib/febiolib.cpp @@ -62,6 +62,7 @@ void InitLibrary() REGISTER_FECORE_CLASS(FEBioStdSolver, "solve"); REGISTER_FECORE_CLASS(FEBioRestart , "restart"); REGISTER_FECORE_CLASS(FEBioRCISolver, "rci_solve"); + REGISTER_FECORE_CLASS(FEBioTestSuiteTask, "test"); FECore::InitModule(); FEAMR::InitModule(); diff --git a/FEBioMech/FE3FieldElasticShellDomain.cpp b/FEBioMech/FE3FieldElasticShellDomain.cpp index 0c5fdd044..ebff38f7a 100644 --- a/FEBioMech/FE3FieldElasticShellDomain.cpp +++ b/FEBioMech/FE3FieldElasticShellDomain.cpp @@ -489,6 +489,7 @@ void FE3FieldElasticShellDomain::UpdateElementStress(int iel) { FEMaterialPoint& mp = *el.GetMaterialPoint(n); FEElasticMaterialPoint& pt = *(mp.ExtractData()); + pt.m_p = ed.ep; // material point coordinates // TODO: I'm not entirly happy with this solution diff --git a/FEBioMech/FE3FieldElasticSolidDomain.cpp b/FEBioMech/FE3FieldElasticSolidDomain.cpp index 0a39b9b2f..579bdaf3f 100644 --- a/FEBioMech/FE3FieldElasticSolidDomain.cpp +++ b/FEBioMech/FE3FieldElasticSolidDomain.cpp @@ -535,6 +535,7 @@ void FE3FieldElasticSolidDomain::UpdateElementStress(int iel, const FETimeInfo& { FEMaterialPoint& mp = *el.GetMaterialPoint(n); FEElasticMaterialPoint& pt = *(mp.ExtractData()); + pt.m_p = ed.ep; // material point coordinates // TODO: I'm not entirly happy with this solution diff --git a/FEBioMech/FEActiveContractionMaterial.cpp b/FEBioMech/FEActiveContractionMaterial.cpp new file mode 100644 index 000000000..575aebc45 --- /dev/null +++ b/FEBioMech/FEActiveContractionMaterial.cpp @@ -0,0 +1,29 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + +#include "stdafx.h" +#include "FEActiveContractionMaterial.h" diff --git a/FEBioMech/FEActiveContractionMaterial.h b/FEBioMech/FEActiveContractionMaterial.h new file mode 100644 index 000000000..7d23ac041 --- /dev/null +++ b/FEBioMech/FEActiveContractionMaterial.h @@ -0,0 +1,52 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#pragma once +#include +#include +#include "febiomech_api.h" + +//----------------------------------------------------------------------------- +//! A material class describing the active fiber contraction model of Estrada et al. in doi: 10.1115/1.4044030 +class FEBIOMECH_API FEActiveContractionMaterial : public FEMaterial +{ +public: + FEActiveContractionMaterial(FEModel* pfem) : FEMaterial(pfem) {} + virtual ~FEActiveContractionMaterial(){} + + //! calculate the active contractile stress + virtual mat3ds ActiveStress(FEMaterialPoint& mp, const vec3d& a0) = 0; + + //! active contraction stiffness contribution + virtual tens4ds ActiveStiffness(FEMaterialPoint& mp, const vec3d& a0) = 0; + + virtual FEMaterialPoint* CreateMaterialPointData(FEMaterialPoint& mp) { return nullptr; } + + //! update force-velocity material point + virtual void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp, const vec3d& a0) {} +}; diff --git a/FEBioMech/FEActiveFiberContraction.cpp b/FEBioMech/FEActiveFiberContraction.cpp index 389c43c08..5ba7b7dd9 100644 --- a/FEBioMech/FEActiveFiberContraction.cpp +++ b/FEBioMech/FEActiveFiberContraction.cpp @@ -32,7 +32,7 @@ SOFTWARE.*/ #include //----------------------------------------------------------------------------- -BEGIN_FECORE_CLASS(FEActiveFiberContraction, FEMaterial); +BEGIN_FECORE_CLASS(FEActiveFiberContraction, FEActiveContractionMaterial); ADD_PARAMETER(m_ascl , "ascl"); ADD_PARAMETER(m_Tmax , "Tmax"); ADD_PARAMETER(m_ca0 , "ca0"); @@ -43,7 +43,7 @@ BEGIN_FECORE_CLASS(FEActiveFiberContraction, FEMaterial); END_FECORE_CLASS(); //----------------------------------------------------------------------------- -FEActiveFiberContraction::FEActiveFiberContraction(FEModel* pfem) : FEMaterial(pfem) +FEActiveFiberContraction::FEActiveFiberContraction(FEModel* pfem) : FEActiveContractionMaterial(pfem) { m_ascl = 0; m_Tmax = 1.0; @@ -54,7 +54,7 @@ FEActiveFiberContraction::FEActiveFiberContraction(FEModel* pfem) : FEMaterial(p //----------------------------------------------------------------------------- bool FEActiveFiberContraction::Init() { - if (FEMaterial::Init() == false) return false; + if (FEActiveContractionMaterial::Init() == false) return false; // for backward compatibility we set m_camax to m_ca0 if it is not defined if (m_camax == 0.0) m_camax = m_ca0; @@ -64,7 +64,7 @@ bool FEActiveFiberContraction::Init() } //----------------------------------------------------------------------------- -mat3ds FEActiveFiberContraction::FiberStress(const vec3d& a0, FEMaterialPoint& mp) +mat3ds FEActiveFiberContraction::ActiveStress(FEMaterialPoint& mp, const vec3d& a0) { FEElasticMaterialPoint& pt = *mp.ExtractData(); @@ -110,7 +110,7 @@ mat3ds FEActiveFiberContraction::FiberStress(const vec3d& a0, FEMaterialPoint& m } //----------------------------------------------------------------------------- -tens4ds FEActiveFiberContraction::FiberStiffness(const vec3d& a0, FEMaterialPoint& mp) +tens4ds FEActiveFiberContraction::ActiveStiffness(FEMaterialPoint& mp, const vec3d& a0) { FEElasticMaterialPoint& pt = *mp.ExtractData(); diff --git a/FEBioMech/FEActiveFiberContraction.h b/FEBioMech/FEActiveFiberContraction.h index bf80c3acd..12cc9d149 100644 --- a/FEBioMech/FEActiveFiberContraction.h +++ b/FEBioMech/FEActiveFiberContraction.h @@ -27,12 +27,11 @@ SOFTWARE.*/ #pragma once -#include -#include "FEElasticMaterial.h" +#include "FEActiveContractionMaterial.h" //----------------------------------------------------------------------------- //! A material class describing the active fiber contraction -class FEActiveFiberContraction : public FEMaterial +class FEActiveFiberContraction : public FEActiveContractionMaterial { public: FEActiveFiberContraction(FEModel* pfem); @@ -41,10 +40,10 @@ class FEActiveFiberContraction : public FEMaterial bool Init() override; //! calculate the fiber stress - mat3ds FiberStress(const vec3d& a0, FEMaterialPoint& mp); + mat3ds ActiveStress(FEMaterialPoint& mp, const vec3d& a0) override; //! active contraction stiffness contribution - tens4ds FiberStiffness(const vec3d& a0, FEMaterialPoint& mp); + tens4ds ActiveStiffness(FEMaterialPoint& mp, const vec3d& a0) override; protected: double m_ascl; //!< activation scale factor diff --git a/FEBioMech/FEBearingLoad.cpp b/FEBioMech/FEBearingLoad.cpp new file mode 100644 index 000000000..3ae9f14c5 --- /dev/null +++ b/FEBioMech/FEBearingLoad.cpp @@ -0,0 +1,335 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FEBearingLoad.h" +#include "FEBioMech.h" +#include +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------------- +// Parameter block for bearing loads +BEGIN_FECORE_CLASS(FEBearingLoad, FESurfaceLoad) + ADD_PARAMETER(m_scale , "scale"); + ADD_PARAMETER(m_force , "force"); + ADD_PARAMETER(m_bsymm , "symmetric_stiffness"); + ADD_PARAMETER(m_blinear , "linear"); + ADD_PARAMETER(m_bshellb , "shell_bottom"); + ADD_PARAMETER(m_profile , "profile"); +END_FECORE_CLASS() + +//----------------------------------------------------------------------------- +//! constructor +FEBearingLoad::FEBearingLoad(FEModel* pfem) : FESurfaceLoad(pfem) +{ + m_scale = 1.0; + m_force = vec3d(0,0,0); + m_bsymm = true; + m_bshellb = false; + m_blinear = false; + m_profile = P_SINE; +} + +//----------------------------------------------------------------------------- +bool FEBearingLoad::Init() +{ + // get the degrees of freedom + m_dof.Clear(); + if (m_bshellb == false) + { + m_dof.AddVariable(FEBioMech::GetVariableName(FEBioMech::DISPLACEMENT)); + } + else + { + m_dof.AddVariable(FEBioMech::GetVariableName(FEBioMech::SHELL_DISPLACEMENT)); + } + if (m_dof.IsEmpty()) return false; + + if (FESurfaceLoad::Init() == false) return false; + + std::vector pc; + + FESurface& surf = GetSurface(); + surf.SetShellBottom(m_bshellb); + FENodeList nl = surf.GetNodeList(); + FEMesh* mesh = surf.GetMesh(); + + // figure out the pressure load distribution on the bearing surface. + // 1. Fit a quadric to the bearing surface + // 2. Confirm that the quadric is a cylinder + // 3. Set the cylinder axis ez and create local coordinate system + // based on orientation of bearing force (er) + // 4. For each face of bearing surface, get cosine of angle theta of its normal relative to er (cq) + // 5. Use cq to evaluate the pressure profile and projected area, scale to match prescribed force + + // collect all the surface nodal positions into pc + if (m_bshellb == false) { + for (int i=0; iNode(nl[i]).m_r0); + } + else { + for (int i=0; iNode(nl[i]).m_s0()); + } + + // find the best fit quadric + QuadricFit* fit = new QuadricFit(); + fit->Fit(pc); + + QuadricFit::Q_TYPE qtype = fit->GetType(); + + bool cylindrical = qtype & (QuadricFit::Q_CIRCULAR_CYLINDER | + QuadricFit::Q_ELLIPTIC_CYLINDER | + QuadricFit::Q_PARABOLIC_CYLINDER| + QuadricFit::Q_HYPERBOLIC_CYLINDER); + + if (cylindrical == false) { + std::string quadric = fit->GetStringType(qtype); + feLogError("Bearing load surface is %s, not cylindrical!\n",quadric.c_str()); + return false; + } + + // extract cylinder parameters +// vec3d c = fit->m_rc; // cylinder origin +// double R = sqrt(1./fit->m_c2.x); // radius + vec3d ez = fit->m_ax[2]; // cylinder axis + vec3d et = (ez ^ m_force).normalized(); + m_er = (et ^ ez).normalized(); // radial force direction + + // evaluate dot product of bearing force and axis + double dp = m_force*ez; + double eps = 1e-3; + if (fabs(dp) > m_force.norm()*eps) { + feLogWarning("Axial component of bearing force (%g) is ignored!\n",dp); + } + + // create surface map for prescribed pressure + m_pc = new FESurfaceMap(FE_DOUBLE); + m_pc->Create(surf.GetFacetSet(), 0.0, FMT_MULT); + int m = m_pc->MaxNodes(); + + // evaluate projected area, which is needed to evaluate peak pressure + double A = 0; // effective projected area + for (int i=0; i 0) { + // face projected area + double parea = area*cq; + // add to effective projected area + switch (m_profile) { + case P_SINE: A += cq*parea; break; + case P_PARA: A += pow(cq,2)*parea; break; + default: break; + } + } + } + // evaluate peak pressure p0 for a unit force magnitude + double p0 = 1.0/A; + + // prescribe bearing pressure on each face + for (int i=0; i 0) { + double p = p0; + switch (m_profile) { + case P_SINE: p *= cq; break; + case P_PARA: p *= pow(cq,2); break; + default: p = 0; break; + } + for (int j = 0; j < m; ++j) + m_pc->setValue(el.m_lid, j, p); + } + } + + return true; +} + +//----------------------------------------------------------------------------- +//! update projected area of bearing surface when nonlinear flag is set +void FEBearingLoad::Update() +{ + if (m_blinear == false) { + FESurface& surf = GetSurface(); + surf.SetShellBottom(m_bshellb); + int m = m_pc->MaxNodes(); + + // evaluate projected area, which is needed to evaluate peak pressure + double A = 0; // effective projected area + for (int i=0; i 0) { + // face projected area + double parea = area*cq; + // add to effective projected area + switch (m_profile) { + case P_SINE: A += cq*parea; break; + case P_PARA: A += pow(cq,2)*parea; break; + default: break; + } + } + } + // evaluate peak pressure p0 for a unit force magnitude + double p0 = 1.0/A; + + // prescribe bearing pressure on each face + for (int i=0; i 0) { + double p = p0; + switch (m_profile) { + case P_SINE: p *= cq; break; + case P_PARA: p *= pow(cq,2); break; + default: p = 0; break; + } + for (int j = 0; j < m; ++j) + m_pc->setValue(el.m_lid, j, p); + } + } + } +} + +//----------------------------------------------------------------------------- +void FEBearingLoad::Serialize(DumpStream& ar) +{ + FESurfaceLoad::Serialize(ar); + if (ar.IsShallow() == false) + { + ar & m_er; + + if (ar.IsSaving()) + m_pc->Serialize(ar); + else + { + m_pc = new FESurfaceMap(FE_DOUBLE); + m_pc->Serialize(ar); + } + } +} + +//----------------------------------------------------------------------------- +//! evaluate bearing pressure +double FEBearingLoad::ScalarLoad(FESurfaceMaterialPoint& mp) +{ + // evaluate pressure at this material point + double P = m_pc->value(mp)*m_scale*m_force.norm(); + return P; +} + +//----------------------------------------------------------------------------- +void FEBearingLoad::LoadVector(FEGlobalVector& R, const FETimeInfo& tp) +{ + FESurface& surf = GetSurface(); + surf.SetShellBottom(m_bshellb); + + // evaluate the integral + surf.LoadVector(R, m_dof, m_blinear, [&](FESurfaceMaterialPoint& pt, const FESurfaceDofShape& dof_a, std::vector& val) { + + // evaluate pressure at this material point + double P = -ScalarLoad(pt); + if (m_bshellb) P = -P; + + double J = (pt.dxr ^ pt.dxs).norm(); + + // force vector + vec3d N = (pt.dxr ^ pt.dxs); N.unit(); + vec3d t = N*P; + + double H_u = dof_a.shape; + + val[0] = H_u*t.x*J; + val[1] = H_u*t.y*J; + val[2] = H_u*t.z*J; + }); +} + +//----------------------------------------------------------------------------- +void FEBearingLoad::StiffnessMatrix(FELinearSystem& LS, const FETimeInfo& tp) +{ + // Don't calculate stiffness for a linear load + if (m_blinear) return; + + FESurface& surf = GetSurface(); + surf.SetShellBottom(m_bshellb); + + // evaluate the integral + surf.LoadStiffness(LS, m_dof, m_dof, [&](FESurfaceMaterialPoint& mp, const FESurfaceDofShape& dof_a, const FESurfaceDofShape& dof_b, matrix& kab) { + + // evaluate pressure at this material point + double P = -ScalarLoad(mp); + if (m_bshellb) P = -P; + + double H_i = dof_a.shape; + double Gr_i = dof_a.shape_deriv_r; + double Gs_i = dof_a.shape_deriv_s; + + double H_j = dof_b.shape; + double Gr_j = dof_b.shape_deriv_r; + double Gs_j = dof_b.shape_deriv_s; + + vec3d vab(0,0,0); + if (m_bsymm) + vab = (mp.dxr*(H_j * Gs_i - H_i * Gs_j) - mp.dxs*(H_j * Gr_i - H_i * Gr_j)) * 0.5*P; + else + vab = (mp.dxs*Gr_j - mp.dxr*Gs_j)*(P*H_i); + + mat3da K(vab); + kab.set(0, 0, K); + }); +} diff --git a/FEBioMech/FEBearingLoad.h b/FEBioMech/FEBearingLoad.h new file mode 100644 index 000000000..ee9116153 --- /dev/null +++ b/FEBioMech/FEBearingLoad.h @@ -0,0 +1,82 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#pragma once +#include +#include +#include + +//----------------------------------------------------------------------------- +//! The bearing load is a surface domain that sustains a parabolic or sinusoidal pressure boundary +//! condition that simulates the contact pressure in a bearing. +//! +class FEBearingLoad : public FESurfaceLoad +{ +public: + enum P_PROFILE { + P_SINE, // sinusoidal pressure distribution + P_PARA // parabolic pressure distribution + }; + +public: + //! constructor + FEBearingLoad(FEModel* pfem); + + //! initialization + bool Init() override; + + //! update + void Update() override; + + //! evaluate bearing pressure + double ScalarLoad(FESurfaceMaterialPoint& mp) override; + + //! serialization + void Serialize(DumpStream& ar) override; + +public: + //! calculate residual + void LoadVector(FEGlobalVector& R, const FETimeInfo& tp) override; + + //! calculate stiffness + void StiffnessMatrix(FELinearSystem& LS, const FETimeInfo& tp) override; + +protected: + double m_scale; //!< scale factor for bearing load + vec3d m_force; //!< bearing load + bool m_bsymm; //!< use symmetric formulation + bool m_blinear; //!< is the load linear (i.e. it will be calculated in the reference frame and assummed deformation independent) + bool m_bshellb; //!< flag for prescribing pressure on shell bottom + int m_profile; //!< profile of pressure distribution + +private: + vec3d m_er; //!< unit vector along radial direction of bearing surface + FESurfaceMap* m_pc; //!< pressure value + + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FEBioMechData.cpp b/FEBioMech/FEBioMechData.cpp index c5e01bc90..a9c7cab89 100644 --- a/FEBioMech/FEBioMechData.cpp +++ b/FEBioMech/FEBioMechData.cpp @@ -44,6 +44,7 @@ SOFTWARE.*/ #include "FERigidConnector.h" #include "FEVolumeConstraint.h" #include "FEContactSurface.h" +#include "FEDiscreteElasticMaterial.h" //----------------------------------------------------------------------------- double FENodeXPos::value(int nnode) @@ -1738,6 +1739,72 @@ double FELogOctahedralPlasticStrain::value(FEElement& el) return D; } +//----------------------------------------------------------------------------- +double FELogDiscreteElementStretch::value(FEElement& el) +{ + if (dynamic_cast(&el) == nullptr) return 0.0; + + FEDiscreteElement& del = dynamic_cast(el); + + FEMesh& mesh = GetFEModel()->GetMesh(); + + vec3d ra0 = mesh.Node(del.m_node[0]).m_r0; + vec3d ra1 = mesh.Node(del.m_node[0]).m_rt; + vec3d rb0 = mesh.Node(del.m_node[1]).m_r0; + vec3d rb1 = mesh.Node(del.m_node[1]).m_rt; + + double L0 = (rb0 - ra0).norm(); + double Lt = (rb1 - ra1).norm(); + + double l = Lt / L0; + + return l; +} + +//----------------------------------------------------------------------------- +double FELogDiscreteElementElongation::value(FEElement& el) +{ + if (dynamic_cast(&el) == nullptr) return 0.0; + + FEDiscreteElement& del = dynamic_cast(el); + + FEMesh& mesh = GetFEModel()->GetMesh(); + + vec3d ra0 = mesh.Node(del.m_node[0]).m_r0; + vec3d ra1 = mesh.Node(del.m_node[0]).m_rt; + vec3d rb0 = mesh.Node(del.m_node[1]).m_r0; + vec3d rb1 = mesh.Node(del.m_node[1]).m_rt; + + double L0 = (rb0 - ra0).norm(); + double Lt = (rb1 - ra1).norm(); + + double Dl = Lt - L0; + + return Dl; +} + +//----------------------------------------------------------------------------- +double FELogDiscreteElementForce::value(FEElement& el) +{ + if (dynamic_cast(&el) == nullptr) return 0.0; + + FEDiscreteElement& del = dynamic_cast(el); + FEMesh& mesh = GetFEModel()->GetMesh(); + + // get the (one) material point data + FEDiscreteElasticMaterialPoint& mp = dynamic_cast(*el.GetMaterialPoint(0)); + + vec3d ra1 = mesh.Node(del.m_node[0]).m_rt; + vec3d rb1 = mesh.Node(del.m_node[1]).m_rt; + vec3d e = rb1 - ra1; e.unit(); + + vec3d F = mp.m_Ft; + + double Fm = F * e; + + return Fm; +} + //----------------------------------------------------------------------------- double FELogRigidBodyR11::value(FERigidBody& rb) { return (rb.GetRotation().RotationMatrix()(0,0)); } double FELogRigidBodyR12::value(FERigidBody& rb) { return (rb.GetRotation().RotationMatrix()(0, 1)); } diff --git a/FEBioMech/FEBioMechData.h b/FEBioMech/FEBioMechData.h index a1e0a4f6d..6fe43f381 100644 --- a/FEBioMech/FEBioMechData.h +++ b/FEBioMech/FEBioMechData.h @@ -968,6 +968,33 @@ class FELogOctahedralPlasticStrain : public FELogElemData double value(FEElement& el); }; +//----------------------------------------------------------------------------- +//! Discrete element stretch +class FELogDiscreteElementStretch : public FELogElemData +{ +public: + FELogDiscreteElementStretch(FEModel* fem) : FELogElemData(fem) {} + double value(FEElement& el); +}; + +//----------------------------------------------------------------------------- +//! Discrete element elongation +class FELogDiscreteElementElongation : public FELogElemData +{ +public: + FELogDiscreteElementElongation(FEModel* fem) : FELogElemData(fem) {} + double value(FEElement& el); +}; + +//----------------------------------------------------------------------------- +//! Discrete element force +class FELogDiscreteElementForce : public FELogElemData +{ +public: + FELogDiscreteElementForce(FEModel* fem) : FELogElemData(fem) {} + double value(FEElement& el); +}; + //============================================================================= // R I G I D B O D Y D A T A //============================================================================= diff --git a/FEBioMech/FEBioMechModule.cpp b/FEBioMech/FEBioMechModule.cpp index c075d1d97..291e2a6af 100644 --- a/FEBioMech/FEBioMechModule.cpp +++ b/FEBioMech/FEBioMechModule.cpp @@ -33,6 +33,7 @@ SOFTWARE.*/ #include "FE2DFiberNeoHookean.h" #include "FE2DTransIsoMooneyRivlin.h" #include "FE2DTransIsoVerondaWestmann.h" +#include "FEActiveFiberContraction.h" #include "FEArrudaBoyce.h" #include "FECarreauYasudaViscousSolid.h" #include "FECarterHayesOld.h" @@ -52,7 +53,6 @@ SOFTWARE.*/ #include "FEElasticMixture.h" #include "FEElasticMultigeneration.h" #include "FEEllipsoidalFiberDistribution.h" -#include "FEFatigueMaterial.h" #include "FEFiberExpPow.h" #include "FEFiberExpPowUncoupled.h" #include "FEFiberNaturalNeoHookean.h" @@ -63,6 +63,7 @@ SOFTWARE.*/ #include "FEFiberExponentialPowerUC.h" #include "FEFiberNHUC.h" #include "FEFiberKiousisUncoupled.h" +#include "FEForceVelocityContraction.h" #include "FEFungOrthoCompressible.h" #include "FEFungOrthotropic.h" #include "FEHolmesMow.h" @@ -86,13 +87,17 @@ SOFTWARE.*/ #include "FEOrthotropicCLE.h" #include "FEOsmoticVirialExpansion.h" #include "FEPerfectOsmometer.h" +#include "FEReactiveFatigue.h" +#include "FEUncoupledReactiveFatigue.h" #include "FERemodelingElasticMaterial.h" #include "FERigidMaterial.h" #include "FESphericalFiberDistribution.h" #include "FEStVenantKirchhoff.h" #include "FETCNonlinearOrthotropic.h" #include "FETendonMaterial.h" +#include "FETraceFreeNeoHookean.h" #include "FETransIsoMooneyRivlin.h" +#include "FETransIsoMREstrada.h" #include "FETransIsoVerondaWestmann.h" #include "FETrussMaterial.h" #include "FEUncoupledActiveContraction.h" @@ -113,7 +118,9 @@ SOFTWARE.*/ #include "FEFiberIntegrationTriangle.h" #include "FECoupledTransIsoMooneyRivlin.h" #include "FECoupledTransIsoVerondaWestmann.h" +#include "FEHGOCoronary.h" #include "FESpringMaterial.h" +#include "FENonlinearSpring.h" #include "FEDiscreteElementMaterial.h" #include "FEElasticMultigeneration.h" #include "FEPRLig.h" @@ -147,11 +154,16 @@ SOFTWARE.*/ #include "FEActiveFiberStress.h" #include "FEActiveFiberStressUC.h" #include "FEContinuousElasticDamage.h" -#include "FEKamensky.h" -#include "FEKamenskyUncoupled.h" +#include "FEIsotropicLeeSacks.h" +#include "FEIsotropicLeeSacksUncoupled.h" +#include "FEPolynomialHyperElastic.h" +#include "FEShenoyMaterial.h" +#include "FELungMaterial.h" #include "FEPressureLoad.h" #include "FETractionLoad.h" +#include "FESurfaceForceUniform.h" +#include "FEBearingLoad.h" #include "FEGenericBodyForce.h" #include "FECentrifugalBodyForce.h" #include "FEPointBodyForce.h" @@ -196,6 +208,7 @@ SOFTWARE.*/ #include "FEDiscreteContact.h" #include "FERigidFollowerForce.h" #include "FERigidFollowerMoment.h" +#include "FEFixedNormalDisplacement.h" #include "FESolidSolver.h" #include "FESolidSolver2.h" @@ -288,6 +301,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FENaturalNeoHookean, "natural neo-Hookean"); REGISTER_FECORE_CLASS(FENeoHookean, "neo-Hookean"); REGISTER_FECORE_CLASS(FENeoHookeanTransIso, "neo-Hookean transiso"); + REGISTER_FECORE_CLASS(FETraceFreeNeoHookean, "trace-free neo-Hookean"); REGISTER_FECORE_CLASS(FENewtonianViscousSolid, "Newtonian viscous solid"); REGISTER_FECORE_CLASS(FEOgdenUnconstrained, "Ogden unconstrained"); REGISTER_FECORE_CLASS(FEOrthoElastic, "orthotropic elastic"); @@ -308,6 +322,8 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEDamageFiberPower, "damage fiber power"); REGISTER_FECORE_CLASS(FEDamageFiberExponential, "damage fiber exponential"); REGISTER_FECORE_CLASS(FEDamageFiberExpLinear, "damage fiber exp-linear"); + REGISTER_FECORE_CLASS(FEHGOCoronary, "HGO-coronary"); + REGISTER_FECORE_CLASS(FELungMaterial, "lung"); // These materials are derived from FEElasticMaterial and use FEElasticMaterials REGISTER_FECORE_CLASS(FEElasticMixture, "solid mixture"); @@ -315,7 +331,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEReactiveViscoelasticMaterial, "reactive viscoelastic"); REGISTER_FECORE_CLASS(FEDamageMaterial, "elastic damage"); REGISTER_FECORE_CLASS(FERVEDamageMaterial, "reactive viscoelastic damage"); - REGISTER_FECORE_CLASS(FEFatigueMaterial, "reactive fatigue"); + REGISTER_FECORE_CLASS(FEReactiveFatigue, "reactive fatigue"); REGISTER_FECORE_CLASS(FEReactivePlasticity, "reactive plasticity"); REGISTER_FECORE_CLASS(FEReactivePlasticDamage, "reactive plastic damage"); @@ -339,6 +355,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FETCNonlinearOrthotropic, "TC nonlinear orthotropic"); REGISTER_FECORE_CLASS(FETendonMaterial, "tendon material"); REGISTER_FECORE_CLASS(FETransIsoMooneyRivlin, "trans iso Mooney-Rivlin"); + REGISTER_FECORE_CLASS(FETransIsoMREstrada, "trans iso MR-Estrada"); REGISTER_FECORE_CLASS(FETransIsoVerondaWestmann, "trans iso Veronda-Westmann"); REGISTER_FECORE_CLASS(FEUncoupledElasticMixture, "uncoupled solid mixture"); REGISTER_FECORE_CLASS(FEVerondaWestmann, "Veronda-Westmann"); @@ -349,10 +366,13 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEPRLig, "PRLig"); REGISTER_FECORE_CLASS(FEUncoupledReactiveViscoelasticMaterial, "uncoupled reactive viscoelastic"); REGISTER_FECORE_CLASS(FEDamageMaterialUC, "uncoupled elastic damage"); + REGISTER_FECORE_CLASS(FEUncoupledReactiveFatigue, "uncoupled reactive fatigue"); REGISTER_FECORE_CLASS(FEGenericHyperelasticUC, "uncoupled hyperelastic"); REGISTER_FECORE_CLASS(FEGenericTransIsoHyperelasticUC, "uncoupled trans-iso hyperelastic"); - REGISTER_FECORE_CLASS(FEKamensky, "Kamensky"); - REGISTER_FECORE_CLASS(FEKamenskyUncoupled, "Kamensky uncoupled"); + REGISTER_FECORE_CLASS(FEIsotropicLeeSacks, "isotropic Lee-Sacks"); + REGISTER_FECORE_CLASS(FEIsotropicLeeSacksUncoupled, "uncoupled isotropic Lee-Sacks"); + REGISTER_FECORE_CLASS(FEPolynomialHyperElastic, "polynomial"); + REGISTER_FECORE_CLASS(FEShenoyMaterial, "Shenoy"); // Fiber materials REGISTER_FECORE_CLASS(FEFiberExpPow, "fiber-exp-pow"); @@ -364,7 +384,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEFiberNH, "fiber-NH"); REGISTER_FECORE_CLASS(FEFiberNaturalNH, "fiber-natural-NH"); REGISTER_FECORE_CLASS(FEFiberNHUC, "fiber-NH-uncoupled"); - REGISTER_FECORE_CLASS(FEFiberPowerLinear, "fiber-power-linear"); + REGISTER_FECORE_CLASS(FEFiberExpPowLinear, "fiber-exp-pow-linear"); REGISTER_FECORE_CLASS(FEFiberExpLinear, "fiber-exp-linear"); REGISTER_FECORE_CLASS(FEUncoupledFiberExpLinear, "uncoupled fiber-exp-linear"); REGISTER_FECORE_CLASS(FEFiberKiousisUncoupled, "fiber-Kiousis-uncoupled"); @@ -398,6 +418,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FETrussMaterial, "linear truss"); REGISTER_FECORE_CLASS(FEHuiskesSupply, "Huiskes-supply"); REGISTER_FECORE_CLASS(FEActiveFiberContraction, "active_contraction"); + REGISTER_FECORE_CLASS(FEForceVelocityContraction, "force-velocity-Estrada"); REGISTER_FECORE_CLASS(FEWrinkleOgdenMaterial, "wrinkle Ogden"); REGISTER_FECORE_CLASS(FEElasticMembrane, "elastic membrane"); @@ -416,7 +437,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FECompositeDiscreteMaterial, "discrete composite"); REGISTER_FECORE_CLASS(FELinearSpring, "linear spring"); REGISTER_FECORE_CLASS(FETensionOnlyLinearSpring, "tension-only linear spring"); - REGISTER_FECORE_CLASS(FENonLinearSpring, "nonlinear spring"); + REGISTER_FECORE_CLASS(FENonlinearSpringMaterial, "nonlinear spring"); REGISTER_FECORE_CLASS(FEExperimentalSpring, "experimental spring"); REGISTER_FECORE_CLASS(FEDiscreteContractileMaterial, "Hill"); REGISTER_FECORE_CLASS(FETorsionalSpring, "torsion spring"); @@ -435,6 +456,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEBondRelaxationCarreau, "relaxation-Carreau"); REGISTER_FECORE_CLASS(FEBondRelaxationProny, "relaxation-Prony"); REGISTER_FECORE_CLASS(FEBondRelaxationMalkin, "relaxation-Malkin"); + REGISTER_FECORE_CLASS(FEBondRelaxationMalkinDist, "relaxation-Malkin-distortion"); REGISTER_FECORE_CLASS(FEBondRelaxationMalkinDistUser, "relaxation-Malkin-dist-user"); REGISTER_FECORE_CLASS(FEBondRelaxationCSexp, "relaxation-CSexp"); REGISTER_FECORE_CLASS(FEBondRelaxationCSexpDistUser, "relaxation-CSexp-dist-user"); @@ -447,6 +469,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEDamageCDFPQP, "CDF quintic"); REGISTER_FECORE_CLASS(FEDamageCDFGamma, "CDF gamma"); REGISTER_FECORE_CLASS(FEDamageCDFUser, "CDF user"); + REGISTER_FECORE_CLASS(FEDamageCDFPower, "CDF power"); // damage criterion (used by damage and plastic materials) REGISTER_FECORE_CLASS(FEDamageCriterionSimo, "DC Simo"); @@ -512,6 +535,8 @@ void FEBioMech::InitModule() // classes derived from FESurfaceLoad REGISTER_FECORE_CLASS(FEPressureLoad, "pressure"); REGISTER_FECORE_CLASS(FETractionLoad, "traction"); + REGISTER_FECORE_CLASS(FESurfaceForceUniform, "force"); + REGISTER_FECORE_CLASS(FEBearingLoad, "bearing load"); //----------------------------------------------------------------------------- // classes derived from FEBodyForce @@ -548,6 +573,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEGPAConstraint, "prestrain"); REGISTER_FECORE_CLASS(FEInSituStretchConstraint, "in-situ stretch"); REGISTER_FECORE_CLASS(FEAzimuthConstraint, "azimuth constraint"); + REGISTER_FECORE_CLASS(FEFixedNormalDisplacement, "fixed normal displacement"); // Lagrange multiplier constraints REGISTER_FECORE_CLASS(FENodeToNodeConstraint, "node-on-node"); @@ -605,6 +631,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEPlotElementUncoupledPressure, "uncoupled pressure"); REGISTER_FECORE_CLASS(FEPlotElementElasticity, "elasticity"); REGISTER_FECORE_CLASS(FEPlotRelativeVolume, "relative volume"); + REGISTER_FECORE_CLASS(FEPlotShellRelativeVolume, "shell relative volume"); // NOTE: deprecated REGISTER_FECORE_CLASS(FEPlotFiberVector, "fiber vector"); REGISTER_FECORE_CLASS(FEPlotFiberStretch, "fiber stretch"); REGISTER_FECORE_CLASS(FEPlotDevFiberStretch, "deviatoric fiber stretch"); @@ -614,13 +641,12 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEPlotDamage, "damage"); REGISTER_FECORE_CLASS(FEPlotNestedDamage, "nested damage"); REGISTER_FECORE_CLASS(FEPlotIntactBondFraction, "intact bond fraction"); + REGISTER_FECORE_CLASS(FEPlotFatigueBondFraction, "fatigue bond fraction"); REGISTER_FECORE_CLASS(FEPlotYieldedBondFraction, "yielded bond fraction"); REGISTER_FECORE_CLASS(FEPlotOctahedralPlasticStrain, "octahedral plastic strain"); REGISTER_FECORE_CLASS(FEPlotReactivePlasticityHeatSupply, "plasticity heat supply density"); REGISTER_FECORE_CLASS(FEPlotMixtureVolumeFraction, "volume fraction"); REGISTER_FECORE_CLASS(FEPlotUT4NodalStresses, "ut4 nodal stress"); - REGISTER_FECORE_CLASS(FEPlotShellStrain, "shell strain"); - REGISTER_FECORE_CLASS(FEPlotShellRelativeVolume, "shell relative volume"); REGISTER_FECORE_CLASS(FEPlotContactGap, "contact gap"); REGISTER_FECORE_CLASS(FEPlotNodalContactGap, "nodal contact gap"); REGISTER_FECORE_CLASS(FEPlotVectorGap, "vector gap"); @@ -638,7 +664,9 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEPlotSPRLinearStresses, "SPR-P1 stress"); REGISTER_FECORE_CLASS(FEPlotSPRPrincStresses, "SPR principal stress"); REGISTER_FECORE_CLASS(FEPlotNodalStresses, "nodal stress"); + REGISTER_FECORE_CLASS(FEPlotShellStrain, "shell strain"); // NOTE: Deprecated REGISTER_FECORE_CLASS(FEPlotLagrangeStrain, "Lagrange strain"); + REGISTER_FECORE_CLASS(FEPlotInfStrain, "infinitesimal strain"); REGISTER_FECORE_CLASS(FEPlotSPRLagrangeStrain, "SPR Lagrange strain"); REGISTER_FECORE_CLASS(FEPlotRightStretch, "right stretch"); REGISTER_FECORE_CLASS(FEPlotLeftStretch, "left stretch"); @@ -650,6 +678,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEPlotNodalSurfaceTraction, "nodal surface traction"); REGISTER_FECORE_CLASS(FEPlotEnclosedVolume, "enclosed volume"); REGISTER_FECORE_CLASS(FEPlotSurfaceArea, "surface area"); + REGISTER_FECORE_CLASS(FEPlotFacetArea, "facet area"); REGISTER_FECORE_CLASS(FEPlotStrainEnergyDensity, "strain energy density"); REGISTER_FECORE_CLASS(FEPlotDevStrainEnergyDensity, "deviatoric strain energy density"); REGISTER_FECORE_CLASS(FEPlotSpecificStrainEnergy, "specific strain energy"); @@ -681,6 +710,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEPlotRigidKineticEnergy, "rigid kinetic energy"); REGISTER_FECORE_CLASS(FEPlotRigidEuler, "Euler angle"); REGISTER_FECORE_CLASS(FEPlotRigidRotationVector, "rigid rotation vector"); + REGISTER_FECORE_CLASS(FEPlotScalarSurfaceLoad, "scalar surface load"); REGISTER_FECORE_CLASS(FEPlotStressError, "stress error"); REGISTER_FECORE_CLASS(FEPlotFiberTargetStretch, "in-situ target stretch"); REGISTER_FECORE_CLASS(FEPlotPreStrainStretch, "prestrain stretch"); @@ -705,6 +735,7 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FEPlotContinuousDamage_D2beta, "continuous damage D2beta"); REGISTER_FECORE_CLASS(FEPlotRVEgenerations, "RVE generations"); REGISTER_FECORE_CLASS(FEPlotRVEbonds, "RVE reforming bonds"); + REGISTER_FECORE_CLASS(FEPlotRVEstrain, "RVE strain"); REGISTER_FECORE_CLASS(FEPlotStrongBondSED, "strong bond SED"); REGISTER_FECORE_CLASS(FEPlotWeakBondSED, "weak bond SED"); REGISTER_FECORE_CLASS(FEPlotStrongBondDevSED, "deviatoric strong bond SED"); @@ -862,6 +893,9 @@ void FEBioMech::InitModule() REGISTER_FECORE_CLASS(FELogElemFiberVectorZ, "fiber_z"); REGISTER_FECORE_CLASS(FELogDamage, "D"); REGISTER_FECORE_CLASS(FELogOctahedralPlasticStrain, "ops"); + REGISTER_FECORE_CLASS(FELogDiscreteElementStretch , "discrete element stretch"); + REGISTER_FECORE_CLASS(FELogDiscreteElementElongation, "discrete element elongation"); + REGISTER_FECORE_CLASS(FELogDiscreteElementForce , "discrete element force" ); //----------------------------------------------------------------------------- // Derived from FELogObjectData diff --git a/FEBioMech/FEBioMechPlot.cpp b/FEBioMech/FEBioMechPlot.cpp index 95191ea26..5d9f0dd0c 100644 --- a/FEBioMech/FEBioMechPlot.cpp +++ b/FEBioMech/FEBioMechPlot.cpp @@ -30,7 +30,7 @@ SOFTWARE.*/ #include "FEBioMechPlot.h" #include "FEDamageNeoHookean.h" #include "FEDamageTransIsoMooneyRivlin.h" -#include "FEFatigueMaterial.h" +#include "FEReactiveFatigue.h" #include "FEReactivePlasticity.h" #include "FEReactivePlasticDamage.h" #include "FERemodelingElasticMaterial.h" @@ -64,6 +64,8 @@ SOFTWARE.*/ #include "FESlidingElasticInterface.h" #include "FETiedContactSurface.h" #include "FEReactiveVEMaterialPoint.h" +#include +#include //============================================================================= // N O D E D A T A @@ -165,49 +167,56 @@ bool FEPlotContactGap::Save(FESurface& surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - // NOTE: the sliding surface does not use material points, so we need this little hack. - FESlidingSurface* ss = dynamic_cast(pcs); - if (ss) + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) { - for (int i = 0; i < ss->Elements(); ++i) + // NOTE: the sliding surface does not use material points, so we need this little hack. + FESlidingSurface* ss = dynamic_cast(pcs); + if (ss) { - FEElement& el = ss->Element(i); - double g = 0.0; - for (int j = 0; j < el.Nodes(); ++j) + for (int i = 0; i < ss->Elements(); ++i) { - double gj = ss->m_data[el.m_lnode[j]].m_gap; - g += gj; + FEElement& el = ss->Element(i); + double g = 0.0; + for (int j = 0; j < el.Nodes(); ++j) + { + double gj = ss->m_data[el.m_lnode[j]].m_gap; + g += gj; + } + g /= el.Nodes(); + a << g; } - g /= el.Nodes(); - a << g; + return true; } - return true; - } - FETiedContactSurface* ts = dynamic_cast(pcs); - if (ts) - { - for (int i = 0; i < ts->Elements(); ++i) + FETiedContactSurface* ts = dynamic_cast(pcs); + if (ts) { - FEElement& el = ts->Element(i); - double g = 0.0; - for (int j = 0; j < el.Nodes(); ++j) + for (int i = 0; i < ts->Elements(); ++i) { - double gj = ts->m_data[el.m_lnode[j]].m_gap; - g += gj; + FEElement& el = ts->Element(i); + double g = 0.0; + for (int j = 0; j < el.Nodes(); ++j) + { + double gj = ts->m_data[el.m_lnode[j]].m_gap; + g += gj; + } + g /= el.Nodes(); + a << g; } - g /= el.Nodes(); - a << g; + return true; } + + writeAverageElementValue(surf, a, [=](const FEMaterialPoint& mp) { + const FEContactMaterialPoint* pt = mp.ExtractData(); + return (pt ? pt->m_gap : 0.0); + }); + return true; } - - writeAverageElementValue(surf, a, [=](const FEMaterialPoint& mp) { - const FEContactMaterialPoint* pt = mp.ExtractData(); - return (pt ? pt->m_gap : 0.0); - }); - - return true; + else return false; } //----------------------------------------------------------------------------- @@ -217,12 +226,19 @@ bool FEPlotVectorGap::Save(FESurface& surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - writeElementValue(surf, a, [=](int nface) { - vec3d gn; - pcs->GetVectorGap(nface, gn); - return gn; - }); - return true; + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + writeElementValue(surf, a, [=](int nface) { + vec3d gn; + pcs->GetVectorGap(nface, gn); + return gn; + }); + return true; + } + return false; } //----------------------------------------------------------------------------- @@ -232,31 +248,37 @@ bool FEPlotContactPressure::Save(FESurface &surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - // NOTE: the sliding surface does not use material points, so we need this little hack. - FESlidingSurface* ss = dynamic_cast(pcs); - if (ss) + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) { - for (int i = 0; i < ss->Elements(); ++i) + // NOTE: the sliding surface does not use material points, so we need this little hack. + FESlidingSurface* ss = dynamic_cast(pcs); + if (ss) { - FEElement& el = ss->Element(i); - double Lm = 0.0; - for (int j = 0; j < el.Nodes(); ++j) + for (int i = 0; i < ss->Elements(); ++i) { - double Lmj = ss->m_data[el.m_lnode[j]].m_Ln; - Lm += Lmj; + FEElement& el = ss->Element(i); + double Lm = 0.0; + for (int j = 0; j < el.Nodes(); ++j) + { + double Lmj = ss->m_data[el.m_lnode[j]].m_Ln; + Lm += Lmj; + } + Lm /= el.Nodes(); + a << Lm; } - Lm /= el.Nodes(); - a << Lm; + return true; } + + writeAverageElementValue(surf, a, [](const FEMaterialPoint& mp) { + const FEContactMaterialPoint* pt = mp.ExtractData(); + return (pt ? pt->m_Ln : 0.0); + }); return true; } - - writeAverageElementValue(surf, a, [](const FEMaterialPoint& mp) { - const FEContactMaterialPoint* pt = mp.ExtractData(); - return (pt ? pt->m_Ln : 0.0); - }); - - return true; + return false; } //----------------------------------------------------------------------------- @@ -265,13 +287,20 @@ bool FEPlotContactTraction::Save(FESurface &surf, FEDataStream& a) { FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - - writeElementValue(surf, a, [=](int nface) { - vec3d tn; - pcs->GetContactTraction(nface, tn); - return tn; - }); - return true; + + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + writeElementValue(surf, a, [=](int nface) { + vec3d tn; + pcs->GetContactTraction(nface, tn); + return tn; + }); + return true; + } + return false; } //----------------------------------------------------------------------------- @@ -281,27 +310,34 @@ bool FEPlotNodalContactGap::Save(FESurface& surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - // NOTE: the sliding surface does not use material points, so we need this little hack. - FESlidingSurface* ss = dynamic_cast(pcs); - if (ss) + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) { - for (int i = 0; i < ss->Elements(); ++i) + // NOTE: the sliding surface does not use material points, so we need this little hack. + FESlidingSurface* ss = dynamic_cast(pcs); + if (ss) { - FEElement& el = ss->Element(i); - for (int j = 0; j < el.Nodes(); ++j) + for (int i = 0; i < ss->Elements(); ++i) { - double gap = ss->m_data[el.m_lnode[j]].m_gap; - a << gap; + FEElement& el = ss->Element(i); + for (int j = 0; j < el.Nodes(); ++j) + { + double gap = ss->m_data[el.m_lnode[j]].m_gap; + a << gap; + } } + return true; } + + writeNodalProjectedElementValues(surf, a, [](const FEMaterialPoint& mp) { + const FEContactMaterialPoint* pt = mp.ExtractData(); + return (pt ? pt->m_gap : 0.0); + }); return true; } - - writeNodalProjectedElementValues(surf, a, [](const FEMaterialPoint& mp) { - const FEContactMaterialPoint* pt = mp.ExtractData(); - return (pt ? pt->m_gap : 0.0); - }); - return true; + return false; } //----------------------------------------------------------------------------- @@ -311,19 +347,26 @@ bool FEPlotNodalVectorGap::Save(FESurface &surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - int NF = pcs->Elements(); - vec3d gn[FEElement::MAX_NODES]; - for (int j=0; jElement(j); - pcs->GetNodalVectorGap(j, gn); - - // store in archive - int ne = el.Nodes(); - for (int k=0; kGetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + int NF = pcs->Elements(); + vec3d gn[FEElement::MAX_NODES]; + for (int j = 0; j < NF; ++j) + { + FESurfaceElement& el = pcs->Element(j); + pcs->GetNodalVectorGap(j, gn); + + // store in archive + int ne = el.Nodes(); + for (int k = 0; k < ne; ++k) a << gn[k]; + } + + return true; + } + return false; } //----------------------------------------------------------------------------- @@ -333,12 +376,19 @@ bool FEPlotNodalContactPressure::Save(FESurface &surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - writeNodalProjectedElementValues(surf, a, [](const FEMaterialPoint& mp) { - const FEContactMaterialPoint* pt = mp.ExtractData(); - return (pt ? pt->m_Ln : 0.0); - }); + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + writeNodalProjectedElementValues(surf, a, [](const FEMaterialPoint& mp) { + const FEContactMaterialPoint* pt = mp.ExtractData(); + return (pt ? pt->m_Ln : 0.0); + }); - return true; + return true; + } + return false; } //----------------------------------------------------------------------------- @@ -348,19 +398,26 @@ bool FEPlotNodalContactTraction::Save(FESurface &surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - int NF = pcs->Elements(); - vec3d tn[FEElement::MAX_NODES]; - for (int j=0; jGetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) { - FESurfaceElement& el = pcs->Element(j); - pcs->GetNodalContactTraction(j, tn); + int NF = pcs->Elements(); + vec3d tn[FEElement::MAX_NODES]; + for (int j = 0; j < NF; ++j) + { + FESurfaceElement& el = pcs->Element(j); + pcs->GetNodalContactTraction(j, tn); - // store in archive - int ne = el.Nodes(); - for (int k=0; k(&surf); if (pcs == 0) return false; - writeElementValue(surf, a, [=](int nface) { - vec3d tn; - pcs->GetSurfaceTraction(nface, tn); - return tn; - }); - - return true; + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + + writeElementValue(surf, a, [=](int nface) { + vec3d tn; + pcs->GetSurfaceTraction(nface, tn); + return tn; + }); + + return true; + } + return false; } //----------------------------------------------------------------------------- @@ -386,19 +451,26 @@ bool FEPlotNodalSurfaceTraction::Save(FESurface &surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - int NF = pcs->Elements(); - vec3d tn[FEElement::MAX_NODES]; - for (int j=0; jElement(j); - pcs->GetNodalSurfaceTraction(j, tn); - - // store in archive - int ne = el.Nodes(); - for (int k=0; kGetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + int NF = pcs->Elements(); + vec3d tn[FEElement::MAX_NODES]; + for (int j = 0; j < NF; ++j) + { + FESurfaceElement& el = pcs->Element(j); + pcs->GetNodalSurfaceTraction(j, tn); + + // store in archive + int ne = el.Nodes(); + for (int k = 0; k < ne; ++k) a << tn[k]; + } + + return true; + } + return false; } //----------------------------------------------------------------------------- @@ -408,13 +480,20 @@ bool FEPlotStickStatus::Save(FESurface& surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - writeElementValue(surf, a, [=](int nface) { - double gn; - pcs->GetStickStatus(nface, gn); - return gn; - }); + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + writeElementValue(surf, a, [=](int nface) { + double gn; + pcs->GetStickStatus(nface, gn); + return gn; + }); - return true; + return true; + } + return false; } //----------------------------------------------------------------------------- @@ -423,10 +502,16 @@ bool FEPlotContactForce::Save(FESurface &surf, FEDataStream &a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - vec3d fn = pcs->GetContactForce(); - a << fn; - - return true; + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + vec3d fn = pcs->GetContactForce(); + a << fn; + return true; + } + return false; } //----------------------------------------------------------------------------- @@ -436,38 +521,49 @@ bool FEPlotContactArea::Save(FESurface &surf, FEDataStream& a) FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - double area = pcs->GetContactArea(); - a << area; - - return true; + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) + { + double area = pcs->GetContactArea(); + a << area; + return true; + } + return false; } //----------------------------------------------------------------------------- // Plot contact penalty parameter bool FEPlotContactPenalty::Save(FESurface& surf, FEDataStream& a) { - FEContactSurface* pcs = dynamic_cast(&surf); if (pcs == 0) return false; - FEFacetSlidingSurface* ps = dynamic_cast(&surf); - if (ps) + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = pcs->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) { - writeAverageElementValue(surf, a, [](const FEMaterialPoint& mp) { - const FEFacetSlidingSurface::Data& pt = *mp.ExtractData(); - return pt.m_eps; - }); - return true; - } + FEFacetSlidingSurface* ps = dynamic_cast(&surf); + if (ps) + { + writeAverageElementValue(surf, a, [](const FEMaterialPoint& mp) { + const FEFacetSlidingSurface::Data& pt = *mp.ExtractData(); + return pt.m_eps; + }); + return true; + } - FESlidingElasticSurface* pse = dynamic_cast(&surf); - if (pse) - { - writeAverageElementValue(surf, a, [](const FEMaterialPoint& mp) { - const FESlidingElasticSurface::Data& pt = *mp.ExtractData(); - return pt.m_epsn; - }); - return true; + FESlidingElasticSurface* pse = dynamic_cast(&surf); + if (pse) + { + writeAverageElementValue(surf, a, [](const FEMaterialPoint& mp) { + const FESlidingElasticSurface::Data& pt = *mp.ExtractData(); + return pt.m_epsn; + }); + return true; + } } return false; @@ -479,24 +575,31 @@ bool FEPlotContactStatus::Save(FESurface& surf, FEDataStream& a) FEFacetSlidingSurface* ps = dynamic_cast(&surf); if (ps == nullptr) return false; - int NF = ps->Elements(); - for (int i = 0; i < NF; ++i) + // make sure the corresponding contact interface is active + // (in case the parent was not set, we'll proceed regardless) + FEContactInterface* pci = ps->GetContactInterface(); assert(pci); + if ((pci == 0) || pci->IsActive()) { - FESurfaceElement& el = ps->Element(i); - double nc = 0.0; - int nint = el.GaussPoints(); - for (int j = 0; j < nint; ++j) + int NF = ps->Elements(); + for (int i = 0; i < NF; ++i) { - FEMaterialPoint& mp = *el.GetMaterialPoint(j); - FEFacetSlidingSurface::Data& pt = *mp.ExtractData(); + FESurfaceElement& el = ps->Element(i); + double nc = 0.0; + int nint = el.GaussPoints(); + for (int j = 0; j < nint; ++j) + { + FEMaterialPoint& mp = *el.GetMaterialPoint(j); + FEFacetSlidingSurface::Data& pt = *mp.ExtractData(); + + if (pt.m_pme) nc++; + } - if (pt.m_pme) nc++; + a << nc; } - a << nc; + return true; } - - return true; + return false; } //----------------------------------------------------------------------------- @@ -521,9 +624,6 @@ bool FEPlotEnclosedVolume::Save(FESurface &surf, FEDataStream &a) FESurface* pcs = &surf; if (pcs == 0) return false; - // Evaluate this field only for a specific domain, by checking domain name - if (pcs->GetName() != GetDomainName()) return false; - writeIntegratedElementValue(surf, a, [=](const FEMaterialPoint& mp) { FESurfaceElement& el = static_cast(*mp.m_elem); int n = mp.m_index; @@ -541,9 +641,6 @@ bool FEPlotSurfaceArea::Save(FESurface &surf, FEDataStream &a) FESurface* pcs = &surf; if (pcs == 0) return false; - // Evaluate this field only for a specific domain, by checking domain name - if (pcs->GetName() != GetDomainName()) return false; - writeIntegratedElementValue(surf, a, [=](const FEMaterialPoint& mp) { FESurfaceElement& el = static_cast(*mp.m_elem); int n = mp.m_index; @@ -554,6 +651,45 @@ bool FEPlotSurfaceArea::Save(FESurface &surf, FEDataStream &a) return true; } +//----------------------------------------------------------------------------- +bool FEPlotFacetArea::Save(FESurface& surf, FEDataStream& a) +{ + FESurface* pcs = &surf; + if (pcs == 0) return false; + + writeElementValue(surf, a, [=](int nface) { + double A = pcs->CurrentFaceArea(pcs->Element(nface)); + return A; + }); + return true; +} + +//----------------------------------------------------------------------------- +// Plot scalar surface load +bool FEPlotScalarSurfaceLoad::Save(FESurface &surf, FEDataStream& a) +{ + FEModel* fem = GetFEModel(); + int nsl = fem->SurfaceLoads(); + FESurfaceLoad* psl = nullptr; + for (int i = 0; iSurfaceLoad(i); + if (&psl->GetSurface() == &surf) break; + } + + if (psl == nullptr) return false; + + if (psl->IsActive()) { + writeAverageElementValue(surf, a, [=](const FEMaterialPoint& mp) { + const FESurfaceMaterialPoint* pt = mp.ExtractData(); + FESurfaceMaterialPoint pnc(*pt); + return (pt ? psl->ScalarLoad(pnc) : 0.0); + }); + return true; + } + return false; +} + //============================================================================= // D O M A I N D A T A //============================================================================= @@ -741,7 +877,7 @@ bool FEPlotElementUncoupledPressure::Save(FEDomain& dom, FEDataStream& a) writeAverageElementValue(dom, a, [=](const FEMaterialPoint& mp) { const FEElasticMaterialPoint* pt = mp.ExtractData(); if (pt == 0) return 0.0; - return -pmu->UJ(pt->m_J); // use negative sign to get positive pressure in compression + return -pt->m_p; // use negative sign to get positive pressure in compression }); return true; @@ -1009,6 +1145,14 @@ bool FEPlotDensity::Save(FEDomain &dom, FEDataStream& a) return true; } } + else if (dom.Class() == FE_DOMAIN_SHELL) + { + FEElasticMaterial* em = dynamic_cast(dom.GetMaterial()); + if (em == 0) return false; + FEDensity dens(em); + writeAverageElementValue(dom, a, dens); + return true; + } return false; } @@ -1349,10 +1493,6 @@ bool FEPlotCurrentElementKineticEnergy::Save(FEDomain &dom, FEDataStream& a) //----------------------------------------------------------------------------- bool FEPlotCurrentElementCenterOfMass::Save(FEDomain &dom, FEDataStream& a) { - const int dof_SX = GetFEModel()->GetDOFIndex("sx"); - const int dof_SY = GetFEModel()->GetDOFIndex("sy"); - const int dof_SZ = GetFEModel()->GetDOFIndex("sz"); - FEMesh& mesh = *dom.GetMesh(); FEElasticMaterial* pme = dom.GetMaterial()->ExtractProperty(); if (pme == nullptr) return false; @@ -1517,9 +1657,6 @@ bool FEPlotCurrentElementLinearMomentum::Save(FEDomain &dom, FEDataStream& a) //----------------------------------------------------------------------------- bool FEPlotCurrentElementAngularMomentum::Save(FEDomain &dom, FEDataStream& a) { - const int dof_SX = GetFEModel()->GetDOFIndex("sx"); - const int dof_SY = GetFEModel()->GetDOFIndex("sy"); - const int dof_SZ = GetFEModel()->GetDOFIndex("sz"); const int dof_VX = GetFEModel()->GetDOFIndex("vx"); const int dof_VY = GetFEModel()->GetDOFIndex("vy"); const int dof_VZ = GetFEModel()->GetDOFIndex("vz"); @@ -1612,12 +1749,72 @@ bool FEPlotCurrentElementAngularMomentum::Save(FEDomain &dom, FEDataStream& a) //----------------------------------------------------------------------------- bool FEPlotRelativeVolume::Save(FEDomain &dom, FEDataStream& a) { - if (dom.Class() != FE_DOMAIN_SOLID) return false; + if (dom.Class() == FE_DOMAIN_SOLID) + { + writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { + const FEElasticMaterialPoint* pt = mp.ExtractData(); + return (pt ? pt->m_J : 0.0); + }); + } + else if (dom.Class() == FE_DOMAIN_SHELL) + { + FEShellDomain* sd = dynamic_cast(&dom); assert(sd); + + // a filter to get J from a strain tensor + auto getJfromE = [](const mat3ds& E) { + mat3ds C = mat3dd(1) + E * 2; + return sqrt(C.det()); + }; + + FEShellDomainNew* newsd = dynamic_cast(sd); + FEElasticEASShellDomain* easd = dynamic_cast(newsd); + FEElasticANSShellDomain* ansd = dynamic_cast(newsd); + if (easd || ansd) { + writeAverageElementValue(dom, a, [](FEElement& el, int ip) { + FEShellElementNew& se = static_cast(el); + return se.m_E[ip]; + }, getJfromE); + } + else { + writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { + const FEElasticMaterialPoint* pt = mp.ExtractData(); + return (pt ? pt->m_J : 0.0); + }); + } + return true; + } + else return false; - writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { - const FEElasticMaterialPoint* pt = mp.ExtractData(); - return (pt ? pt->m_J : 0.0); - }); + return true; +} + +//----------------------------------------------------------------------------- +bool FEPlotShellRelativeVolume::Save(FEDomain& dom, FEDataStream& a) +{ + FEShellDomain* sd = dynamic_cast(&dom); assert(sd); + if (sd == nullptr) return false; + + // a filter to get J from a strain tensor + auto getJfromE = [](const mat3ds& E) { + mat3ds C = mat3dd(1) + E * 2; + return sqrt(C.det()); + }; + + FEShellDomainNew* newsd = dynamic_cast(sd); + FEElasticEASShellDomain* easd = dynamic_cast(newsd); + FEElasticANSShellDomain* ansd = dynamic_cast(newsd); + if (easd || ansd) { + writeAverageElementValue(dom, a, [](FEElement& el, int ip) { + FEShellElementNew& se = static_cast(el); + return se.m_E[ip]; + }, getJfromE); + } + else { + writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { + const FEElasticMaterialPoint* pt = mp.ExtractData(); + return (pt ? pt->m_J : 0.0); + }); + } return true; } @@ -1760,11 +1957,6 @@ class FEDevFiberStretch { const FEElasticMaterialPoint& pt = *mp.ExtractData(); - // get the deformation gradient - const mat3d& F = pt.m_F; - double J = pt.m_J; - double Jm13 = pow(J, -1.0 / 3.0); - mat3d Q = m_mat->GetLocalCS(mp); // get the material fiber axis @@ -1855,7 +2047,90 @@ bool FEPlotLagrangeStrain::Save(FEDomain& dom, FEDataStream& a) { FEElasticMaterial* pme = dom.GetMaterial()->ExtractProperty(); if (pme == nullptr) return false; - writeAverageElementValue(dom, a, FELagrangeStrain()); + + if (dom.Class() == FE_DOMAIN_SOLID) + { + writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { + const FEElasticMaterialPoint& pt = *mp.ExtractData(); + return pt.Strain(); + }); + } + else if (dom.Class() == FE_DOMAIN_SHELL) + { + FEShellDomain* sd = dynamic_cast(&dom); assert(sd); + + FEElasticEASShellDomain* easd = dynamic_cast(&dom); + FEElasticANSShellDomain* ansd = dynamic_cast(&dom); + if (easd || ansd) + { + writeAverageElementValue(dom, a, [](FEElement& el, int ip) { + FEShellElementNew& se = static_cast(el); + return se.m_E[ip]; + }); + } + else + { + writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { + const FEElasticMaterialPoint& pt = *mp.ExtractData(); + return pt.Strain(); + }); + } + } + else return false; + + return true; +} + +bool FEPlotShellStrain::Save(FEDomain& dom, FEDataStream& a) +{ + FEElasticMaterial* pme = dom.GetMaterial()->ExtractProperty(); + if (pme == nullptr) return false; + + FEShellDomain* sd = dynamic_cast(&dom); + if (sd == nullptr) return false; + + FEElasticEASShellDomain* easd = dynamic_cast(&dom); + FEElasticANSShellDomain* ansd = dynamic_cast(&dom); + if (easd || ansd) + { + writeAverageElementValue(dom, a, [](FEElement& el, int ip) { + FEShellElementNew& se = static_cast(el); + return se.m_E[ip]; + }); + } + else + { + writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { + const FEElasticMaterialPoint& pt = *mp.ExtractData(); + return pt.Strain(); + }); + } + + return true; +} + +//----------------------------------------------------------------------------- +bool FEPlotInfStrain::Save(FEDomain& dom, FEDataStream& a) +{ + FEElasticMaterial* pme = dom.GetMaterial()->ExtractProperty(); + if (pme == nullptr) return false; + + if (dom.Class() == FE_DOMAIN_SOLID) + { + writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { + const FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // displacement tensor + mat3d U = pt.m_F - mat3dd(1.0); + + // evaluate small strain tensor eij = 0.5*(Uij + Uji) + mat3ds e = U.sym(); + + return e; + }); + } + else return false; + return true; } @@ -2085,9 +2360,16 @@ bool FEPlotDamage::Save(FEDomain &dom, FEDataStream& a) for (int k=0; kExtractData(); - FEFatigueMaterialPoint* ppf = pt.GetPointData(k)->ExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pt.GetPointData(k)->ExtractData(); + FEReactiveViscoelasticMaterialPoint* pve = pt.GetPointData(k)->ExtractData(); if (ppd) D += (float) ppd->m_D; - else if (ppf) D += (float) ppf->m_D; + else if (ppr) D += (float) ppr->m_D; + else if (pve) { + FEDamageMaterialPoint* pd = pve->GetPointData(0)->ExtractData(); + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pd) D += (float) pd->m_D; + else if (pr) D += (float) pr->m_D; + } } } D /= (float) nint; @@ -2110,19 +2392,33 @@ bool FEPlotDamage::Save(FEDomain &dom, FEDataStream& a) for (int k=0; kExtractData(); - FEFatigueMaterialPoint* ppf = pt.GetPointData(k)->ExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pt.GetPointData(k)->ExtractData(); + FEReactiveViscoelasticMaterialPoint* pve = pt.GetPointData(k)->ExtractData(); FEElasticMixtureMaterialPoint* pem = pt.GetPointData(k)->ExtractData(); if (ppd) D += (float) ppd->m_D; - else if (ppf) D += (float) ppf->m_D; + else if (ppr) D += (float) ppr->m_D; + else if (pve) { + FEDamageMaterialPoint* pd = pve->GetPointData(0)->ExtractData(); + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pd) D += (float) pd->m_D; + else if (pr) D += (float) pr->m_D; + } else if (pem) { int NE = (int)pem->m_w.size(); for (int l=0; lGetPointData(l)->ExtractData(); - FEFatigueMaterialPoint* ppf = pem->GetPointData(l)->ExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pem->GetPointData(l)->ExtractData(); + FEReactiveViscoelasticMaterialPoint* pve = pt.GetPointData(k)->ExtractData(); if (ppd) D += (float) ppd->m_D; - else if (ppf) D += (float) ppf->m_D; + else if (ppr) D += (float) ppr->m_D; + else if (pve) { + FEDamageMaterialPoint* pd = pve->GetPointData(0)->ExtractData(); + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pd) D += (float) pd->m_D; + else if (pr) D += (float) pr->m_D; + } } } } @@ -2143,11 +2439,18 @@ bool FEPlotDamage::Save(FEDomain &dom, FEDataStream& a) { FEMaterialPoint& pt = *el.GetMaterialPoint(j); FEDamageMaterialPoint* ppd = pt.ExtractData(); - FEFatigueMaterialPoint* ppf = pt.ExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pt.ExtractData(); FEReactivePlasticDamageMaterialPoint* prd = pt.ExtractData(); + FEReactiveViscoelasticMaterialPoint* pve = pt.ExtractData(); if (ppd) D += (float) ppd->m_D; - else if (ppf) D += (float) ppf->m_D; + else if (ppr) D += (float) ppr->m_D; else if (prd) D += (float) prd->m_D; + else if (pve) { + FEDamageMaterialPoint* pd = pve->GetPointData(0)->ExtractData(); + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pd) D += (float) pd->m_D; + else if (pr) D += (float) pr->m_D; + } } D /= (float) nint; a.push_back(D); @@ -2167,7 +2470,6 @@ bool FEPlotNestedDamage::SetFilter(int nmat) //----------------------------------------------------------------------------- bool FEPlotNestedDamage::Save(FEDomain &dom, FEDataStream& a) { - int N = dom.Elements(); FESolidMaterial* pmat = dom.GetMaterial()->ExtractProperty(); if (dynamic_cast(pmat)||dynamic_cast(pmat)) { @@ -2178,10 +2480,10 @@ bool FEPlotNestedDamage::Save(FEDomain &dom, FEDataStream& a) FEMaterialPoint& mp_noconst = const_cast(mp); FEElasticMixtureMaterialPoint& pt = *mp_noconst.ExtractData(); FEDamageMaterialPoint* ppd = pt.GetPointData(m_nmat)->ExtractData(); - FEFatigueMaterialPoint* ppf = pt.GetPointData(m_nmat)->ExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pt.GetPointData(m_nmat)->ExtractData(); double D = 0.0; if (ppd) D += (float)ppd->m_D; - else if (ppf) D += (float)ppf->m_D; + else if (ppr) D += (float)ppr->m_D; return D; }); } @@ -2196,21 +2498,21 @@ bool FEPlotNestedDamage::Save(FEDomain &dom, FEDataStream& a) FEMaterialPoint& mp_noconst = const_cast(mp); FEMultigenerationMaterialPoint& pt = *mp_noconst.ExtractData(); FEDamageMaterialPoint* ppd = pt.GetPointData(m_nmat)->ExtractData(); - FEFatigueMaterialPoint* ppf = pt.GetPointData(m_nmat)->ExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pt.GetPointData(m_nmat)->ExtractData(); FEElasticMixtureMaterialPoint* pem = pt.GetPointData(m_nmat)->ExtractData(); double D = 0.0; if (ppd) D += (float)ppd->m_D; - else if (ppf) D += (float)ppf->m_D; + else if (ppr) D += (float)ppr->m_D; else if (pem) { int NE = (int)pem->m_w.size(); for (int l = 0; lGetPointData(l)->ExtractData(); - FEFatigueMaterialPoint* ppf = pem->GetPointData(l)->ExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pem->GetPointData(l)->ExtractData(); if (ppd) D += (float)ppd->m_D; - else if (ppf) D += (float)ppf->m_D; + else if (ppr) D += (float)ppr->m_D; } } @@ -2222,10 +2524,10 @@ bool FEPlotNestedDamage::Save(FEDomain &dom, FEDataStream& a) { writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { const FEDamageMaterialPoint* ppd = mp.ExtractData(); - const FEFatigueMaterialPoint* ppf = mp.ExtractData(); + const FEReactiveFatigueMaterialPoint* ppr = mp.ExtractData(); double D = 0.0; if (ppd) D += (float)ppd->m_D; - else if (ppf) D += (float)ppf->m_D; + else if (ppr) D += (float)ppr->m_D; return D; }); } @@ -2251,14 +2553,19 @@ bool FEPlotIntactBondFraction::Save(FEDomain &dom, FEDataStream& a) FEElasticMixtureMaterialPoint& pt = *el.GetMaterialPoint(j)->ExtractData(); for (int k=0; kExtractData(); FEReactivePlasticityMaterialPoint* prp = pt.GetPointData(k)->ExtractData(); FEReactivePlasticDamageMaterialPoint* prd = pt.GetPointData(k)->ExtractData(); FEDamageMaterialPoint* ppd = pt.GetPointData(k)->ExtractData(); - if (ppf) D += (float) ppf->m_wit; - else if (prp) D += (float) (1.0 - prp->YieldedBonds()); + FEReactiveFatigueMaterialPoint* ppr = pt.GetPointData(k)->ExtractData(); + FEReactiveViscoelasticMaterialPoint* pve = pt.GetPointData(k)->ExtractData(); + if (prp) D += (float) (1.0 - prp->YieldedBonds()); else if (prd) D += (float) prd->IntactBonds(); else if (ppd) D += (float) (1.0 - ppd->m_D); + else if (ppr) D += (float) ppr->m_wit; + else if (pve) { + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pr) D += (float) pr->m_wit; + } } } D /= (float) nint; @@ -2280,28 +2587,38 @@ bool FEPlotIntactBondFraction::Save(FEDomain &dom, FEDataStream& a) FEMultigenerationMaterialPoint& pt = *el.GetMaterialPoint(j)->ExtractData(); for (int k=0; kExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pt.GetPointData(k)->ExtractData(); FEReactivePlasticityMaterialPoint* prp = pt.GetPointData(k)->ExtractData(); FEReactivePlasticDamageMaterialPoint* prd = pt.GetPointData(k)->ExtractData(); FEElasticMixtureMaterialPoint* pem = pt.GetPointData(k)->ExtractData(); FEDamageMaterialPoint* ppd = pt.GetPointData(k)->ExtractData(); - if (ppf) D += (float) ppf->m_wit; - else if (prp) D += (float) (1 - prp->YieldedBonds()); + FEReactiveViscoelasticMaterialPoint* pve = pt.GetPointData(k)->ExtractData(); + if (prp) D += (float) (1 - prp->YieldedBonds()); else if (prd) D += (float) prd->IntactBonds(); else if (ppd) D += (float) (1 - ppd->m_D); + else if (ppr) D += (float) ppr->m_wit; + else if (pve) { + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pr) D += (float) pr->m_wit; + } else if (pem) { int NE = (int)pem->m_w.size(); for (int l=0; lGetPointData(l)->ExtractData(); + FEReactiveFatigueMaterialPoint* ppr = pem->GetPointData(l)->ExtractData(); FEReactivePlasticityMaterialPoint* prp = pt.GetPointData(k)->ExtractData(); FEReactivePlasticDamageMaterialPoint* prd = pt.GetPointData(k)->ExtractData(); FEDamageMaterialPoint* ppd = pem->GetPointData(l)->ExtractData(); - if (ppf) D += (float) ppf->m_wit; - else if (prp) D += (float) (1-prp->YieldedBonds()); + FEReactiveViscoelasticMaterialPoint* pve = pt.GetPointData(k)->ExtractData(); + if (prp) D += (float) (1-prp->YieldedBonds()); else if (prd) D += (float) prd->IntactBonds(); else if (ppd) D += (float) (1 - ppd->m_D); + else if (ppr) D += (float) ppr->m_wit; + else if (pve) { + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pr) D += (float) pr->m_wit; + } } } } @@ -2321,14 +2638,19 @@ bool FEPlotIntactBondFraction::Save(FEDomain &dom, FEDataStream& a) for (int j=0; j(); + FEReactiveFatigueMaterialPoint* ppr = pt.ExtractData(); FEReactivePlasticityMaterialPoint* prp = pt.ExtractData(); FEReactivePlasticDamageMaterialPoint* prd = pt.ExtractData(); FEDamageMaterialPoint* ppd = pt.ExtractData(); - if (ppf) D += (float) ppf->m_wit; - else if (prp) D += (float) (1-prp->YieldedBonds()); + FEReactiveViscoelasticMaterialPoint* pve = pt.ExtractData(); + if (prp) D += (float) (1-prp->YieldedBonds()); else if (prd) D += (float) prd->IntactBonds(); else if (ppd) D += (float) (1 - ppd->m_D); + else if (ppr) D += (float) ppr->m_wit; + else if (pve) { + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pr) D += (float) pr->m_wit; + } } D /= (float) nint; a.push_back(D); @@ -2337,6 +2659,102 @@ bool FEPlotIntactBondFraction::Save(FEDomain &dom, FEDataStream& a) return true; } +//----------------------------------------------------------------------------- +bool FEPlotFatigueBondFraction::Save(FEDomain &dom, FEDataStream& a) +{ + int N = dom.Elements(); + FEElasticMaterial* pmat = dom.GetMaterial()->ExtractProperty(); + if (dynamic_cast(pmat)||dynamic_cast(pmat)) + { + int NC = pmat->Properties(); + for (int i=0; iExtractData(); + for (int k=0; kExtractData(); + FEReactiveViscoelasticMaterialPoint* pve = pt.GetPointData(k)->ExtractData(); + if (ppr) wf += (float) ppr->m_wft; + else if (pve) { + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pr) wf += (float) pr->m_wft; + } + } + } + wf /= (float) nint; + a.push_back(wf); + } + } + else if (dynamic_cast(pmat)) + { + FEElasticMultigeneration* pmg = dynamic_cast(pmat); + int NC = pmg->Properties(); + for (int i=0; iExtractData(); + for (int k=0; kExtractData(); + FEElasticMixtureMaterialPoint* pem = pt.GetPointData(k)->ExtractData(); + FEReactiveViscoelasticMaterialPoint* pve = pt.GetPointData(k)->ExtractData(); + if (ppr) wf += (float) ppr->m_wft; + else if (pve) { + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pr) wf += (float) pr->m_wft; + } + else if (pem) + { + int NE = (int)pem->m_w.size(); + for (int l=0; lGetPointData(l)->ExtractData(); + if (ppr) wf += (float) ppr->m_wft; + } + } + } + } + wf /= (float) nint; + a.push_back(wf); + } + } + else + { + for (int i=0; i(); + FEReactiveViscoelasticMaterialPoint* pve = pt.ExtractData(); + if (ppr) wf += (float) ppr->m_wft; + else if (pve) { + FEReactiveFatigueMaterialPoint* pr = pve->GetPointData(0)->ExtractData(); + if (pr) wf += (float) pr->m_wft; + } + } + wf /= (float) nint; + a.push_back(wf); + } + } + return true; +} + //----------------------------------------------------------------------------- bool FEPlotYieldedBondFraction::Save(FEDomain &dom, FEDataStream& a) { @@ -2625,64 +3043,6 @@ bool FEPlotUT4NodalStresses::Save(FEDomain& dom, FEDataStream& a) return true; } -//----------------------------------------------------------------------------- -bool FEPlotShellStrain::Save(FEDomain &dom, FEDataStream &a) -{ - FEShellDomain* sd = dynamic_cast(&dom); - if (sd == 0) return false; - - FEShellDomainNew* newsd = dynamic_cast(sd); - FEElasticEASShellDomain* easd = dynamic_cast(newsd); - FEElasticANSShellDomain* ansd = dynamic_cast(newsd); - int NE = sd->Elements(); - if (easd || ansd) - { - writeAverageElementValue(dom, a, [](FEElement& el, int ip) { - FEShellElementNew& se = static_cast(el); - return se.m_E[ip]; - }); - } - else - { - writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { - const FEElasticMaterialPoint& pt = *mp.ExtractData(); - return pt.Strain(); - }); - } - return true; -} - -//----------------------------------------------------------------------------- -bool FEPlotShellRelativeVolume::Save(FEDomain &dom, FEDataStream &a) -{ - FEShellDomain* sd = dynamic_cast(&dom); - if (sd == 0) return false; - - // a filter to get J from a strain tensor - auto getJfromE = [](const mat3ds& E) { - mat3ds C = mat3dd(1) + E * 2; - return sqrt(C.det()); - }; - - FEShellDomainNew* newsd = dynamic_cast(sd); - FEElasticEASShellDomain* easd = dynamic_cast(newsd); - FEElasticANSShellDomain* ansd = dynamic_cast(newsd); - int NE = sd->Elements(); - if (easd || ansd) { - writeAverageElementValue(dom, a, [](FEElement& el, int ip) { - FEShellElementNew& se = static_cast(el); - return se.m_E[ip]; - }, getJfromE); - } - else { - writeAverageElementValue(dom, a, [](const FEMaterialPoint& mp) { - const FEElasticMaterialPoint& pt = *mp.ExtractData(); - return pt.Strain(); - }, getJfromE); - } - return true; -} - //============================================================================== // R I G I D B O D Y D A T A //============================================================================== @@ -2988,7 +3348,6 @@ bool FEPlotFiberTargetStretch::Save(FEDomain& dom, FEDataStream& a) for (int j = 0; jGetPointData(0); - FEElasticMaterialPoint& ep = *mp.ExtractData(); FEPrestrainMaterialPoint& pp = *mp.ExtractData(); mat3d Fp = pp.initialPrestrain(); @@ -3227,7 +3586,6 @@ bool FEPlotPreStrainCompatibility::Save(FEDomain& dom, FEDataStream& a) // get the domain FESolidDomain& sd = static_cast(dom); - int NN = sd.Nodes(); int NE = sd.Elements(); // STEP 1 - first we do an SPR recovery of the pre-strain gradient @@ -3423,7 +3781,6 @@ bool FEPlotDiscreteElementForce::Save(FEDomain& dom, FEDataStream& a) if (pdiscreteDomain == nullptr) return false; FEDiscreteElasticDomain& discreteDomain = *pdiscreteDomain; - FEMesh& mesh = *dom.GetMesh(); int NE = discreteDomain.Elements(); for (int i = 0; i < NE; ++i) { @@ -3447,7 +3804,6 @@ bool FEPlotDiscreteElementStrainEnergy::Save(FEDomain& dom, FEDataStream& a) FEDiscreteElasticMaterial* discreteMaterial = dynamic_cast(discreteDomain.GetMaterial()); - FEMesh& mesh = *dom.GetMesh(); int NE = discreteDomain.Elements(); for (int i = 0; i < NE; ++i) { @@ -3494,7 +3850,6 @@ bool FEPlotContinuousDamage_::Save(FEDomain& dom, FEDataStream& a) } if (mat == nullptr) return false; - FEMesh& mesh = *dom.GetMesh(); int NE = dom.Elements(); for (int i = 0; i < NE; ++i) { @@ -3658,6 +4013,76 @@ bool FEPlotRVEbonds::Save(FEDomain& dom, FEDataStream& a) return true; } +//----------------------------------------------------------------------------- +bool FEPlotRVEstrain::Save(FEDomain& dom, FEDataStream& a) +{ + int N = dom.Elements(); + FEElasticMaterial* pmat = dom.GetMaterial()->ExtractProperty(); + if (pmat == nullptr) return false; + FEReactiveViscoelasticMaterial* rvmat = dynamic_cast(pmat); + FEUncoupledReactiveViscoelasticMaterial* rumat = dynamic_cast(pmat); + if (rvmat) { + for (int iel=0; ielScalarStrain(*rvmat->GetBondMaterialPoint(*el.GetMaterialPoint(j))); + a << bmf/nint; + } + } + else if (rumat) { + for (int iel=0; ielScalarStrain(*rumat->GetBondMaterialPoint(*el.GetMaterialPoint(j))); + a << bmf/nint; + } + } + else { + int NC = pmat->Properties(); + // check all elements + for (int iel=0; ielGetProperty(ic)->ExtractProperty(); + FEUncoupledReactiveViscoelasticMaterial* rumat = dynamic_cast(pmat); + if (rvmat) { + int nint = el.GaussPoints(); + for (int j=0; jScalarStrain(*rvmat->GetBondMaterialPoint(*el.GetMaterialPoint(j)->GetPointData(ic))); + ++n; + } + } + else if (rumat) { + int nint = el.GaussPoints(); + for (int j=0; jScalarStrain(*rumat->GetBondMaterialPoint(*el.GetMaterialPoint(j)->GetPointData(ic))); + ++n; + } + } + } + if (n > 0) bmf /= n; + a << bmf; + } + } + + return true; +} + //----------------------------------------------------------------------------- class FEStrongBondSED { diff --git a/FEBioMech/FEBioMechPlot.h b/FEBioMech/FEBioMechPlot.h index 514361855..604fb764f 100644 --- a/FEBioMech/FEBioMechPlot.h +++ b/FEBioMech/FEBioMechPlot.h @@ -255,6 +255,33 @@ class FEPlotSurfaceArea : public FEPlotSurfaceData bool Save(FESurface& surf, FEDataStream& a); }; +//----------------------------------------------------------------------------- +//! Surface facet area +//! +class FEPlotFacetArea : public FEPlotSurfaceData +{ +private: + FEModel* m_pfem; + bool m_binit; + vector m_elem; + vector m_area; + +public: + FEPlotFacetArea(FEModel* pfem) : FEPlotSurfaceData(pfem, PLT_FLOAT, FMT_ITEM) { m_binit = true; } + bool Save(FESurface& surf, FEDataStream& a); +}; + + +//----------------------------------------------------------------------------- +//! Scalar surface load +//! +class FEPlotScalarSurfaceLoad : public FEPlotSurfaceData +{ +public: + FEPlotScalarSurfaceLoad(FEModel* pfem) : FEPlotSurfaceData(pfem, PLT_FLOAT, FMT_ITEM){} + bool Save(FESurface& surf, FEDataStream& a); +}; + //============================================================================= // D O M A I N D A T A //============================================================================= @@ -486,6 +513,14 @@ class FEPlotRelativeVolume : public FEPlotDomainData bool Save(FEDomain& dom, FEDataStream& a); }; +// NOTE: Deprecated, but maintained for backward compatibility +class FEPlotShellRelativeVolume : public FEPlotDomainData +{ +public: + FEPlotShellRelativeVolume(FEModel* pfem) : FEPlotDomainData(pfem, PLT_FLOAT, FMT_ITEM) {} + bool Save(FEDomain& dom, FEDataStream& a); +}; + //----------------------------------------------------------------------------- //! Material fibers class FEPlotFiberVector : public FEPlotDomainData @@ -591,6 +626,15 @@ class FEPlotIntactBondFraction : public FEPlotDomainData bool Save(FEDomain& m, FEDataStream& a); }; +//----------------------------------------------------------------------------- +//! Fatigue bond fraction (fatigue) +class FEPlotFatigueBondFraction : public FEPlotDomainData +{ +public: + FEPlotFatigueBondFraction(FEModel* pfem) : FEPlotDomainData(pfem, PLT_FLOAT, FMT_ITEM){} + bool Save(FEDomain& m, FEDataStream& a); +}; + //----------------------------------------------------------------------------- //! Yielded bond fraction (fatigue) class FEPlotYieldedBondFraction : public FEPlotDomainData @@ -636,24 +680,6 @@ class FEPlotUT4NodalStresses : public FEPlotDomainData bool Save(FEDomain& dom, FEDataStream& a); }; -//----------------------------------------------------------------------------- -//! Store shell strains -class FEPlotShellStrain : public FEPlotDomainData -{ -public: - FEPlotShellStrain(FEModel* pfem) : FEPlotDomainData(pfem, PLT_MAT3FS, FMT_ITEM){} - bool Save(FEDomain& dom, FEDataStream& a); -}; - -//----------------------------------------------------------------------------- -//! Shell relative volume -class FEPlotShellRelativeVolume : public FEPlotDomainData -{ -public: - FEPlotShellRelativeVolume(FEModel* pfem) : FEPlotDomainData(pfem, PLT_FLOAT, FMT_ITEM){} - bool Save(FEDomain& dom, FEDataStream& a); -}; - //----------------------------------------------------------------------------- //! class the projects stresses from integration points to nodes using //! SPR (superconvergergent patch recovery) @@ -802,6 +828,23 @@ class FEPlotLagrangeStrain : public FEPlotDomainData bool Save(FEDomain& dom, FEDataStream& a); }; +//! NOTE: Deprecated, but maintained for backward compatibility +class FEPlotShellStrain : public FEPlotDomainData +{ +public: + FEPlotShellStrain(FEModel* pfem) : FEPlotDomainData(pfem, PLT_MAT3FS, FMT_ITEM) {} + bool Save(FEDomain& dom, FEDataStream& a); +}; + +//----------------------------------------------------------------------------- +// Infinitesimal strain +class FEPlotInfStrain : public FEPlotDomainData +{ +public: + FEPlotInfStrain(FEModel* pfem) : FEPlotDomainData(pfem, PLT_MAT3FS, FMT_ITEM) {} + bool Save(FEDomain& dom, FEDataStream& a); +}; + //----------------------------------------------------------------------------- //! Lagrange strains class FEPlotSPRLagrangeStrain : public FEPlotDomainData @@ -1046,6 +1089,15 @@ class FEPlotRVEbonds : public FEPlotDomainData bool Save(FEDomain& dom, FEDataStream& a); }; +//----------------------------------------------------------------------------- +//! Reactive viscoelastic strain measure for bond-breaking trigger and bond recruitment +class FEPlotRVEstrain : public FEPlotDomainData +{ +public: + FEPlotRVEstrain(FEModel* pfem) : FEPlotDomainData(pfem, PLT_FLOAT, FMT_ITEM) {} + bool Save(FEDomain& dom, FEDataStream& a); +}; + //----------------------------------------------------------------------------- //! Strain energy density of strong bonds in reactive viscoelastic material point class FEPlotStrongBondSED : public FEPlotDomainData diff --git a/FEBioMech/FEBondRelaxation.cpp b/FEBioMech/FEBondRelaxation.cpp index cdff79cc3..447afc46c 100644 --- a/FEBioMech/FEBondRelaxation.cpp +++ b/FEBioMech/FEBondRelaxation.cpp @@ -619,6 +619,75 @@ double FEBondRelaxationMalkin::Relaxation(FEMaterialPoint& mp, const double t, c return g; } +/////////////////////////////////////////////////////////////////////////////// +// +// FEBondRelaxationMalkinDist +// +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// define the material parameters +BEGIN_FECORE_CLASS(FEBondRelaxationMalkinDist, FEBondRelaxation) + ADD_PARAMETER(m_t1c0 , FE_RANGE_GREATER(0.0), "t1c0"); + ADD_PARAMETER(m_t1c1 , "t1c1"); + ADD_PARAMETER(m_t1s0 , FE_RANGE_GREATER(0.0), "t1s0"); + ADD_PARAMETER(m_t2c0 , FE_RANGE_GREATER(0.0), "t2c0"); + ADD_PARAMETER(m_t2c1 , "t2c1"); + ADD_PARAMETER(m_t2s0 , FE_RANGE_GREATER(0.0), "t2s0"); + ADD_PARAMETER(m_beta , FE_RANGE_GREATER(0.0), "beta"); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +//! Constructor. +FEBondRelaxationMalkinDist::FEBondRelaxationMalkinDist(FEModel* pfem) : FEBondRelaxation(pfem) +{ + m_t1c0 = 0; + m_t1c1 = 0; + m_t1s0 = 1; + m_t2c0 = 0; + m_t2c1 = 0; + m_t2s0 = 1; + m_beta = 1; +} + +//----------------------------------------------------------------------------- +//! Relaxation function +double FEBondRelaxationMalkinDist::Relaxation(FEMaterialPoint& mp, const double t, const mat3ds D) +{ + double g = 1.0; + if (t == 0) return g; + + // get the elastic material point data + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // evaluate spatial Hencky (logarithmic) strain + mat3ds h = pt.LeftHencky(); + + // evaluate distortion magnitude (always positive) + double K2 = (h.dev()).norm(); + + double tau1 = m_t1c0(mp) + m_t1c1(mp)*exp(-K2/m_t1s0(mp)); + double tau2 = m_t2c0(mp) + m_t2c1(mp)*exp(-K2/m_t2s0(mp)); + double beta = m_beta(mp); + + if (beta != 1) { + double bm1 = beta - 1; +#ifdef __APPLE__ + double Ga = tgamma(bm1); +#else + double Ga = gamma(bm1); +#endif + double Q1 = gamma_inc_Q(bm1, t/tau1); + double G1 = Ga*Q1; + double Q2 = gamma_inc_Q(bm1, t/tau2); + double G2 = Ga*Q2; + g = bm1*pow(t,-bm1)/(pow(tau1, -bm1) - pow(tau2, -bm1))*(G2-G1); + } + else { + g = (expint_Ei(-t/tau2) - expint_Ei(-t/tau1))/(log(tau1/tau2)); + } + return g; +} + /////////////////////////////////////////////////////////////////////////////// // // FEBondRelaxationMalkinDistUser diff --git a/FEBioMech/FEBondRelaxation.h b/FEBioMech/FEBondRelaxation.h index 66920207b..c5f784e88 100644 --- a/FEBioMech/FEBondRelaxation.h +++ b/FEBioMech/FEBondRelaxation.h @@ -340,6 +340,31 @@ class FEBondRelaxationMalkin : public FEBondRelaxation //----------------------------------------------------------------------------- // This class implements a Malkin relaxation with adjustable relaxation time +class FEBondRelaxationMalkinDist : public FEBondRelaxation +{ +public: + //! constructor + FEBondRelaxationMalkinDist(FEModel* pfem); + + //! relaxation + double Relaxation(FEMaterialPoint& pt, const double t, const mat3ds D) override; + +public: + FEParamDouble m_t1c0; //!< constant coefficient of lower relaxation time + FEParamDouble m_t1c1; //!< coefficient of exponential for lower relaxation time + FEParamDouble m_t1s0; //!< time constant of exponential for lower relaxation time + FEParamDouble m_t2c0; //!< constant coefficient of upper relaxation time + FEParamDouble m_t2c1; //!< coefficient of exponential for upper relaxation time + FEParamDouble m_t2s0; //!< time constant of exponential for upper relaxation time + FEParamDouble m_beta; //!< exponent + + // declare parameter list + DECLARE_FECORE_CLASS(); +}; + +//----------------------------------------------------------------------------- +// This class implements a Malkin relaxation with user-adjustable relaxation time + class FEBondRelaxationMalkinDistUser : public FEBondRelaxation { public: diff --git a/FEBioMech/FEContactPotential.cpp b/FEBioMech/FEContactPotential.cpp index 86427913a..e3725cb29 100644 --- a/FEBioMech/FEContactPotential.cpp +++ b/FEBioMech/FEContactPotential.cpp @@ -93,6 +93,28 @@ void FEContactPotentialSurface::GetContactTraction(int nelem, vec3d& tc) tc /= (double)el.GaussPoints(); } +double FEContactPotentialSurface::GetContactArea() +{ + double area = 0.0; + for (int i = 0; i < Elements(); ++i) + { + FESurfaceElement& el = Element(i); + double* gw = el.GaussWeights(); + for (int n = 0; n < el.GaussPoints(); ++n) + { + FECPContactPoint& mp = static_cast(*el.GetMaterialPoint(n)); + if (mp.m_tc.norm2() != 0.0) + { + vec3d dA = mp.dxr ^ mp.dxs; + double da = dA.norm(); + area += da * gw[n]; + } + } + } + return area; +} + + BEGIN_FECORE_CLASS(FEContactPotential, FEContactInterface) ADD_PARAMETER(m_kc, "kc"); ADD_PARAMETER(m_p, "p"); @@ -103,6 +125,9 @@ END_FECORE_CLASS(); FEContactPotential::FEContactPotential(FEModel* fem) : m_surf1(fem), m_surf2(fem) { + m_surf1.SetContactInterface(this); + m_surf2.SetContactInterface(this); + m_kc = 0.0; m_p = 4; m_Rin = 1.0; @@ -224,6 +249,9 @@ class Grid int ix = (int)(m_nx * (r.x - box.r0.x) / box.width()); int iy = (int)(m_ny * (r.y - box.r0.y) / box.height()); int iz = (int)(m_nz * (r.z - box.r0.z) / box.depth()); + if (ix == m_nx) ix--; + if (iy == m_ny) iy--; + if (iz == m_nz) iz--; int icell = iz * (m_nx * m_ny) + iy * m_nx + ix; Cell* c = m_cell + icell; @@ -543,6 +571,7 @@ void FEContactPotential::LoadVector(FEGlobalVector& R, const FETimeInfo& tp) for (int n = 0; n < el.GaussPoints(); ++n) { FECPContactPoint& cp = static_cast(*el.GetMaterialPoint(n)); + cp.m_Ln = 0.0; cp.m_tc = vec3d(0, 0, 0); } } @@ -552,6 +581,7 @@ void FEContactPotential::LoadVector(FEGlobalVector& R, const FETimeInfo& tp) for (int n = 0; n < el.GaussPoints(); ++n) { FECPContactPoint& cp = static_cast(*el.GetMaterialPoint(n)); + cp.m_Ln = 0.0; cp.m_tc = vec3d(0, 0, 0); } } @@ -597,6 +627,26 @@ void FEContactPotential::LoadVector(FEGlobalVector& R, const FETimeInfo& tp) R.Assemble(lm, fe); } } + + // update contact pressures (only needed for plot output) + for (int i = 0; i < m_surf1.Elements(); ++i) + { + FESurfaceElement& el = m_surf1.Element(i); + for (int n = 0; n < el.GaussPoints(); ++n) + { + FECPContactPoint& cp = static_cast(*el.GetMaterialPoint(n)); + cp.m_Ln = cp.m_tc.norm(); + } + } + for (int i = 0; i < m_surf2.Elements(); ++i) + { + FESurfaceElement& el = m_surf2.Element(i); + for (int n = 0; n < el.GaussPoints(); ++n) + { + FECPContactPoint& cp = static_cast(*el.GetMaterialPoint(n)); + cp.m_Ln = cp.m_tc.norm(); + } + } } void FEContactPotential::ElementForce(FESurfaceElement& el1, FESurfaceElement& el2, vector& fe) diff --git a/FEBioMech/FEContactPotential.h b/FEBioMech/FEContactPotential.h index 0bc477246..0a4a68370 100644 --- a/FEBioMech/FEContactPotential.h +++ b/FEBioMech/FEContactPotential.h @@ -36,6 +36,12 @@ class FEContactPotentialSurface : public FEContactSurface { public: vec3d m_tc; + + void Serialize(DumpStream& ar) override + { + FEContactMaterialPoint::Serialize(ar); + ar & m_tc; + } }; public: @@ -43,6 +49,8 @@ class FEContactPotentialSurface : public FEContactSurface void GetContactTraction(int nelem, vec3d& tc) override; + double GetContactArea() override; + FEMaterialPoint* CreateMaterialPoint() override; }; diff --git a/FEBioMech/FEContactSurface.h b/FEBioMech/FEContactSurface.h index 8641ec340..8f0f8e6c4 100644 --- a/FEBioMech/FEContactSurface.h +++ b/FEBioMech/FEContactSurface.h @@ -55,6 +55,12 @@ class FEBIOMECH_API FEContactMaterialPoint : public FESurfaceMaterialPoint m_pmep = nullptr; } + void Serialize(DumpStream& ar) + { + FESurfaceMaterialPoint::Serialize(ar); + ar & m_gap & m_Ln; + } + public: double m_gap; //!< gap function at integration points double m_Ln; //!< net contact pressure diff --git a/FEBioMech/FEDamageCDF.cpp b/FEBioMech/FEDamageCDF.cpp index 4e9ee74f3..a01f49a97 100644 --- a/FEBioMech/FEDamageCDF.cpp +++ b/FEBioMech/FEDamageCDF.cpp @@ -161,13 +161,15 @@ double FEDamageCDFLogNormal::pdf(const double X) BEGIN_FECORE_CLASS(FEDamageCDFWeibull, FEDamageCDF) ADD_PARAMETER(m_alpha, FE_RANGE_GREATER_OR_EQUAL(0.0), "alpha"); ADD_PARAMETER(m_mu , FE_RANGE_GREATER_OR_EQUAL(0.0), "mu"); + ADD_PARAMETER(m_ploc, "ploc"); END_FECORE_CLASS(); //----------------------------------------------------------------------------- //! Constructor. FEDamageCDFWeibull::FEDamageCDFWeibull(FEModel* pfem) : FEDamageCDF(pfem) { - m_alpha = m_mu; + m_alpha = m_mu = 1; + m_ploc = 0; } //----------------------------------------------------------------------------- @@ -177,8 +179,8 @@ double FEDamageCDFWeibull::cdf(const double X) double cdf = 0; // this CDF only admits positive values - if (X > 0) - cdf = 1 - exp(-pow(X/m_mu,m_alpha)); + if (X > m_ploc) + cdf = 1 - exp(-pow((X-m_ploc)/m_mu,m_alpha)); return cdf; } @@ -189,10 +191,10 @@ double FEDamageCDFWeibull::pdf(const double X) double pdf = 0; // this CDF only admits positive values - if ((m_alpha > 1) && (X > 0)) - pdf = exp(-pow(X/m_mu,m_alpha))*m_alpha*pow(X, m_alpha-1)/pow(m_mu, m_alpha); - else if (m_alpha == 1) - pdf = exp(-X/m_mu)/m_mu; + if ((m_alpha > 1) && (X > m_ploc)) + pdf = exp(-pow((X-m_ploc)/m_mu,m_alpha))*m_alpha*pow(X-m_ploc, m_alpha-1)/pow(m_mu, m_alpha); + else if ((m_alpha == 1) && (X > m_ploc)) + pdf = exp(-(X-m_ploc)/m_mu)/m_mu; return pdf; } @@ -361,3 +363,101 @@ double FEDamageCDFUser::pdf(const double X) return m_cdf->derive(X); } +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// define the material parameters +BEGIN_FECORE_CLASS(FEDamageCDFPower, FEDamageCDF) + ADD_PARAMETER(m_alpha, FE_RANGE_GREATER_OR_EQUAL(1.0), "alpha" ); + ADD_PARAMETER(m_mu0 , FE_RANGE_GREATER_OR_EQUAL(0.0), "mu0" ); + ADD_PARAMETER(m_mu1 , "mu1" ); + ADD_PARAMETER(m_s , FE_RANGE_GREATER(0.0) , "scale" ); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +//! Constructor. +FEDamageCDFPower::FEDamageCDFPower(FEModel* pfem) : FEDamageCDF(pfem) +{ + m_alpha = 2; + m_mu0 = 1; + m_mu1 = 0; + m_s = 1; +} + +//----------------------------------------------------------------------------- +//! Parameter validation +bool FEDamageCDFPower::Validate() { + if (m_mu0 + m_mu1 < 0) { + feLogError("mu0 + mu1 = %f must be non-negative", m_mu0 + m_mu1); + return false; + } + return true; +} + +//----------------------------------------------------------------------------- +// Power cumulative distribution function +double FEDamageCDFPower::cdf(const double X) +{ + double cdf = 0; + + // this CDF only admits positive values + if (X > 0) + cdf = m_mu0 + m_mu1*pow(X/m_s,m_alpha); + + return cdf; +} + +// Power probability density function +double FEDamageCDFPower::pdf(const double X) +{ + double pdf = 0; + + // this CDF only admits positive values + if (X > 0) + pdf = m_mu1*m_alpha/m_s*pow(X/m_s,m_alpha-1); + + return pdf; +} + +/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- +// define the material parameters +BEGIN_FECORE_CLASS(FEDamageCDFPoly2, FEDamageCDF) + ADD_PARAMETER(m_mu0 , FE_RANGE_GREATER_OR_EQUAL(0.0), "mu0" ); + ADD_PARAMETER(m_mu1 , "mu1" ); + ADD_PARAMETER(m_mu2 , "mu2" ); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +//! Constructor. +FEDamageCDFPoly2::FEDamageCDFPoly2(FEModel* pfem) : FEDamageCDF(pfem) +{ + m_mu0 = 1; + m_mu1 = 0; + m_mu2 = 0; +} + +//----------------------------------------------------------------------------- +// Poly2 cumulative distribution function +double FEDamageCDFPoly2::cdf(const double X) +{ + double cdf = 0; + + // this CDF only admits positive arguments + if (X > 0) + cdf = m_mu0 + m_mu1*X + m_mu2*X*X; + + return cdf; +} + +// Poly2 probability density function +double FEDamageCDFPoly2::pdf(const double X) +{ + double pdf = 0; + + // this PDF only admits positive arguments + if (X > 0) + pdf = m_mu1 + 2*m_mu2*X; + + return pdf; +} + diff --git a/FEBioMech/FEDamageCDF.h b/FEBioMech/FEDamageCDF.h index 5d596aebb..0cf05327b 100644 --- a/FEBioMech/FEDamageCDF.h +++ b/FEBioMech/FEDamageCDF.h @@ -119,6 +119,7 @@ class FEDamageCDFWeibull : public FEDamageCDF public: double m_alpha; //!< exponent alpha double m_mu; //!< mean mu + double m_ploc; //!< location parameter // declare parameter list DECLARE_FECORE_CLASS(); @@ -215,3 +216,55 @@ class FEDamageCDFUser : public FEDamageCDF // declare parameter list DECLARE_FECORE_CLASS(); }; + +//----------------------------------------------------------------------------- +// Power law cumulative distribution function + +class FEDamageCDFPower : public FEDamageCDF +{ +public: + FEDamageCDFPower(FEModel* pfem); + ~FEDamageCDFPower() {} + + bool Validate() override; + + //! cumulative distribution function + double cdf(const double X) override; + + //! probability density function + double pdf(const double X) override; + +public: + double m_alpha; //!< power exponent alpha + double m_mu0; //!< constant coeff + double m_mu1; //!< coeff of power + double m_s; //!< scale factor for argument + + // declare parameter list + DECLARE_FECORE_CLASS(); +}; + +//----------------------------------------------------------------------------- +// Quadratic polynomial cumulative distribution function + +class FEDamageCDFPoly2 : public FEDamageCDF +{ +public: + FEDamageCDFPoly2(FEModel* pfem); + ~FEDamageCDFPoly2() {} + + //! cumulative distribution function + double cdf(const double X) override; + + //! probability density function + double pdf(const double X) override; + +public: + double m_mu0; //!< constant coeff + double m_mu1; //!< coeff of linear term + double m_mu2; //!< coeff of quadratic term + + // declare parameter list + DECLARE_FECORE_CLASS(); +}; + diff --git a/FEBioMech/FEDamageMaterialPoint.h b/FEBioMech/FEDamageMaterialPoint.h index d485406ff..92fec7829 100644 --- a/FEBioMech/FEDamageMaterialPoint.h +++ b/FEBioMech/FEDamageMaterialPoint.h @@ -40,12 +40,12 @@ class FEDamageMaterialPoint : public FEMaterialPoint public: FEDamageMaterialPoint(FEMaterialPoint *pt) : FEMaterialPoint(pt) {} - FEMaterialPoint* Copy(); + FEMaterialPoint* Copy() override; - void Init(); - void Update(const FETimeInfo& timeInfo); + void Init() override; + void Update(const FETimeInfo& timeInfo) override; - void Serialize(DumpStream& ar); + void Serialize(DumpStream& ar) override; public: double m_Etrial; //!< trial damage criterion at time t diff --git a/FEBioMech/FEDamageMaterialUC.cpp b/FEBioMech/FEDamageMaterialUC.cpp index 10b2afdc6..98011b4ee 100644 --- a/FEBioMech/FEDamageMaterialUC.cpp +++ b/FEBioMech/FEDamageMaterialUC.cpp @@ -55,19 +55,19 @@ FEMaterialPoint* FEDamageMaterialUC::CreateMaterialPointData() return new FEDamageMaterialPoint(m_pBase->CreateMaterialPointData()); } +//----------------------------------------------------------------------------- +//! Initialization. +bool FEDamageMaterialUC::Init() +{ + return FEUncoupledMaterial::Init(); +} + //----------------------------------------------------------------------------- //! calculate stress at material point mat3ds FEDamageMaterialUC::DevStress(FEMaterialPoint& pt) { - // get the damage material point data - FEDamageMaterialPoint& pd = *pt.ExtractData(); - - // evaluate the trial value of the damage criterion - // this must be done before evaluating the damage - pd.m_Etrial = m_pCrit->DamageCriterion(pt); - // evaluate the damage - double d = m_pDamg->Damage(pt); + double d = Damage(pt); // evaluate the stress mat3ds s = m_pBase->DevStress(pt); @@ -80,15 +80,8 @@ mat3ds FEDamageMaterialUC::DevStress(FEMaterialPoint& pt) //! calculate tangent stiffness at material point tens4ds FEDamageMaterialUC::DevTangent(FEMaterialPoint& pt) { - // get the damage material point data - FEDamageMaterialPoint& pd = *pt.ExtractData(); - - // evaluate the trial value of the damage criterion - // this must be done before evaluating the damage - pd.m_Etrial = m_pCrit->DamageCriterion(pt); - // evaluate the damage - double d = m_pDamg->Damage(pt); + double d = Damage(pt); // evaluate the tangent tens4ds c = m_pBase->DevTangent(pt); @@ -101,15 +94,8 @@ tens4ds FEDamageMaterialUC::DevTangent(FEMaterialPoint& pt) //! calculate strain energy density at material point double FEDamageMaterialUC::DevStrainEnergyDensity(FEMaterialPoint& pt) { - // get the damage material point data - FEDamageMaterialPoint& pd = *pt.ExtractData(); - - // evaluate the trial value of the damage criterion - // this must be done before evaluating the damage - pd.m_Etrial = m_pCrit->DamageCriterion(pt); - // evaluate the damage - double d = m_pDamg->Damage(pt); + double d = Damage(pt); // evaluate the strain energy density double sed = m_pBase->DevStrainEnergyDensity(pt); @@ -131,6 +117,7 @@ double FEDamageMaterialUC::Damage(FEMaterialPoint& pt) // evaluate the damage double d = m_pDamg->Damage(pt); - + pd.m_D = d; + return d; } diff --git a/FEBioMech/FEDamageMaterialUC.h b/FEBioMech/FEDamageMaterialUC.h index 441fed5c5..a5d5a554c 100644 --- a/FEBioMech/FEDamageMaterialUC.h +++ b/FEBioMech/FEDamageMaterialUC.h @@ -53,6 +53,9 @@ class FEDamageMaterialUC : public FEUncoupledMaterial //! damage double Damage(FEMaterialPoint& pt); + //! data initialization and checking + bool Init() override; + // returns a pointer to a new material point object FEMaterialPoint* CreateMaterialPointData() override; diff --git a/FEBioMech/FEDiscreteElasticMaterial.cpp b/FEBioMech/FEDiscreteElasticMaterial.cpp index 369734b7b..0ee0a12ea 100644 --- a/FEBioMech/FEDiscreteElasticMaterial.cpp +++ b/FEBioMech/FEDiscreteElasticMaterial.cpp @@ -26,6 +26,14 @@ SOFTWARE.*/ #include "stdafx.h" #include "FEDiscreteElasticMaterial.h" +FEMaterialPoint* FEDiscreteElasticMaterialPoint::Copy() +{ + FEDiscreteElasticMaterialPoint* pt = new FEDiscreteElasticMaterialPoint(*this); + if (m_pNext) pt->m_pNext = m_pNext->Copy(); + return pt; +} + +//============================================================================= FEDiscreteElasticMaterial::FEDiscreteElasticMaterial(FEModel* pfem) : FEDiscreteMaterial(pfem) { diff --git a/FEBioMech/FEDiscreteElasticMaterial.h b/FEBioMech/FEDiscreteElasticMaterial.h index f27ecf4f5..6346b60f5 100644 --- a/FEBioMech/FEDiscreteElasticMaterial.h +++ b/FEBioMech/FEDiscreteElasticMaterial.h @@ -29,6 +29,9 @@ SOFTWARE.*/ class FEBIOMECH_API FEDiscreteElasticMaterialPoint : public FEDiscreteMaterialPoint { +public: + FEMaterialPoint* Copy() override; + public: vec3d m_Ft; // current force }; diff --git a/FEBioMech/FEElasticFiberMaterial.cpp b/FEBioMech/FEElasticFiberMaterial.cpp index c5e45c532..dea4b323e 100644 --- a/FEBioMech/FEElasticFiberMaterial.cpp +++ b/FEBioMech/FEElasticFiberMaterial.cpp @@ -47,6 +47,8 @@ FEElasticFiberMaterial::FEElasticFiberMaterial(FEModel* pfem) : FEElasticMateria { // initialize the fiber vector m_fiber = vec3d(1, 0, 0); + m_Us = mat3dd(1); + m_bUs = false; } //----------------------------------------------------------------------------- @@ -61,6 +63,22 @@ vec3d FEElasticFiberMaterial::FiberVector(FEMaterialPoint& mp) // convert to global coordinates vec3d a0 = Q*fiber; + + // account for prior deformation in multigenerational formulation + vec3d a = FiberPreStretch(a0); + + return a; +} - return a0; +//----------------------------------------------------------------------------- +vec3d FEElasticFiberMaterial::FiberPreStretch(const vec3d a0) +{ + // account for prior deformation in multigenerational formulation + if (m_bUs) { + vec3d a = (m_Us*a0); + a.unit(); + return a; + } + else + return a0; } diff --git a/FEBioMech/FEElasticFiberMaterial.h b/FEBioMech/FEElasticFiberMaterial.h index 5d81dcf89..3f266d1e4 100644 --- a/FEBioMech/FEElasticFiberMaterial.h +++ b/FEBioMech/FEElasticFiberMaterial.h @@ -51,6 +51,11 @@ class FEElasticFiberMaterial : public FEElasticMaterial //! Strain energy density virtual double FiberStrainEnergyDensity(FEMaterialPoint& mp, const vec3d& a0) = 0; + // Set or clear pre-stretch, as needed in multigenerational materials (e.g., reactive viscoelasticity) + void SetPreStretch(const mat3ds Us) { m_Us = Us; m_bUs = true; } + void ResetPreStretch() { m_bUs = false; } + vec3d FiberPreStretch(const vec3d a0); + private: // These are made private since fiber materials should implement the functions above instead. // The functions can still be reached when a fiber material is used in an elastic mixture. @@ -59,6 +64,10 @@ class FEElasticFiberMaterial : public FEElasticMaterial tens4ds Tangent(FEMaterialPoint& mp) final { return FiberTangent(mp, FiberVector(mp)); } double StrainEnergyDensity(FEMaterialPoint& mp) final { return FiberStrainEnergyDensity(mp, FiberVector(mp)); } +private: + mat3ds m_Us; //!< pre-stretch tensor for fiber + bool m_bUs; //!< flag for pre-stretch + public: FEParamVec3 m_fiber; //!< fiber orientation diff --git a/FEBioMech/FEElasticMaterialPoint.cpp b/FEBioMech/FEElasticMaterialPoint.cpp index 53d92fdd5..7a850f26e 100644 --- a/FEBioMech/FEElasticMaterialPoint.cpp +++ b/FEBioMech/FEElasticMaterialPoint.cpp @@ -38,6 +38,7 @@ FEElasticMaterialPoint::FEElasticMaterialPoint() m_v = m_a = m_gradJ = vec3d(0, 0, 0); m_buncoupled = false; m_Wt = m_Wp = 0; + m_p = 0; } //----------------------------------------------------------------------------- @@ -64,6 +65,8 @@ void FEElasticMaterialPoint::Init() m_rt = m_r0; + m_p = 0; + // don't forget to initialize the base class FEMaterialPoint::Init(); } @@ -72,7 +75,7 @@ void FEElasticMaterialPoint::Init() void FEElasticMaterialPoint::Serialize(DumpStream& ar) { FEMaterialPoint::Serialize(ar); - ar & m_F & m_J & m_s & m_v & m_a & m_gradJ & m_L & m_Wt & m_Wp; + ar & m_F & m_J & m_s & m_v & m_a & m_gradJ & m_L & m_Wt & m_Wp & m_p; } //----------------------------------------------------------------------------- diff --git a/FEBioMech/FEElasticMaterialPoint.h b/FEBioMech/FEElasticMaterialPoint.h index 28f782aa6..bc25bf054 100644 --- a/FEBioMech/FEElasticMaterialPoint.h +++ b/FEBioMech/FEElasticMaterialPoint.h @@ -92,6 +92,9 @@ class FEBIOMECH_API FEElasticMaterialPoint : public FEMaterialPoint // solid material data mat3ds m_s; //!< Cauchy stress + // uncoupled pressure + double m_p; //!< only for uncoupled materials + // current time data double m_Wt; //!< strain energy density at current time diff --git a/FEBioMech/FEFacet2FacetSliding.cpp b/FEBioMech/FEFacet2FacetSliding.cpp index b2dfe8cc8..ef1f45350 100644 --- a/FEBioMech/FEFacet2FacetSliding.cpp +++ b/FEBioMech/FEFacet2FacetSliding.cpp @@ -71,12 +71,10 @@ FEFacetSlidingSurface::Data::Data() void FEFacetSlidingSurface::Data::Serialize(DumpStream& ar) { FEContactMaterialPoint::Serialize(ar); - ar & m_gap; - ar & m_nu; - ar & m_rs; ar & m_Lm; ar & m_eps; - ar & m_Ln; + ar & m_nu; + ar & m_rs; } //----------------------------------------------------------------------------- @@ -266,6 +264,10 @@ FEFacet2FacetSliding::FEFacet2FacetSliding(FEModel* pfem) : FEContactInterface(p m_mu = 0; m_epsf = 0; + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMech/FEFacet2FacetTied.cpp b/FEBioMech/FEFacet2FacetTied.cpp index b6fea8b26..02e7510d2 100644 --- a/FEBioMech/FEFacet2FacetTied.cpp +++ b/FEBioMech/FEFacet2FacetTied.cpp @@ -53,6 +53,12 @@ FEFacetTiedSurface::Data::Data() m_pme = (FESurfaceElement*) 0; } +void FEFacetTiedSurface::Data::Serialize(DumpStream& ar) +{ + FEContactMaterialPoint::Serialize(ar); + ar & m_vgap & m_Lm & m_rs; +} + //----------------------------------------------------------------------------- FEFacetTiedSurface::FEFacetTiedSurface(FEModel* pfem) : FEContactSurface(pfem) { @@ -154,6 +160,10 @@ FEFacet2FacetTied::FEFacet2FacetTied(FEModel* pfem) : FEContactInterface(pfem), static int count = 1; SetID(count++); + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + // define sibling relationships m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); diff --git a/FEBioMech/FEFacet2FacetTied.h b/FEBioMech/FEFacet2FacetTied.h index 5dd7bc762..ca165fa54 100644 --- a/FEBioMech/FEFacet2FacetTied.h +++ b/FEBioMech/FEFacet2FacetTied.h @@ -41,6 +41,8 @@ class FEFacetTiedSurface : public FEContactSurface public: Data(); + void Serialize(DumpStream& ar); + public: vec3d m_vgap; //!< gap function vec3d m_Lm; //!< Lagrange multiplier diff --git a/FEBioMech/FEFatigueMaterial.cpp b/FEBioMech/FEFatigueMaterial.cpp deleted file mode 100644 index 14b645275..000000000 --- a/FEBioMech/FEFatigueMaterial.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/*This file is part of the FEBio source code and is licensed under the MIT license -listed below. - -See Copyright-FEBio.txt for details. - -Copyright (c) 2021 University of Utah, The Trustees of Columbia University in -the City of New York, and others. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.*/ - - - -#include "stdafx.h" -#include "FEFatigueMaterial.h" -#include "FEDamageCriterion.h" -#include "FEDamageCDF.h" -#include "FEUncoupledMaterial.h" -#include "FECore/FECoreKernel.h" -#include -#include - -////////////////////// FATIGUE MATERIAL POINT ///////////////////////////////// -//----------------------------------------------------------------------------- -FEMaterialPoint* FEFatigueMaterialPoint::Copy() -{ - FEFatigueMaterialPoint* pt = new FEFatigueMaterialPoint(*this); - if (m_pNext) pt->m_pNext = m_pNext->Copy(); - return pt; -} - -//----------------------------------------------------------------------------- -void FEFatigueMaterialPoint::Init() -{ - FEMaterialPoint::Init(); - - // intialize data - m_D = 0; - - // initialize intact bond fraction to 1 - m_wi = m_wip = m_wit = 1.0; - m_awi = m_awip = m_awit = 0; - - // initialize fatigued bond fraction to 0 - m_wf = m_wfp = m_wft = 0; - m_awf = m_awfp = m_awft = 0; - - // initialize damage criterion - m_Xd = m_Xdp = m_Xdt = 0; - m_aXd = m_aXdp = m_aXdt = 0; - - // initialize fatigue criterion - m_Xf = m_Xfp = m_Xft = 0; - m_aXf = m_aXfp = m_aXft = 0; -} - -//----------------------------------------------------------------------------- -void FEFatigueMaterialPoint::Update(const FETimeInfo& timeInfo) -{ - FEMaterialPoint::Update(timeInfo); - - // update damage response - if (m_Xdt > m_Xdp) { - // intact bonds - m_wip = m_wit; - m_awip = m_awit; - // fatigued bonds - m_wfp = m_wft; - m_awfp = m_awft; - // damage criterion - m_Xdp = m_Xdt; - m_aXdp = m_aXdt; - } - - // update fatigue response - m_wfp = m_wft; - m_awfp = m_awft; - m_Xfp = m_Xft; - m_aXfp = m_aXft; -} - -//----------------------------------------------------------------------------- -void FEFatigueMaterialPoint::Serialize(DumpStream& ar) -{ - FEMaterialPoint::Serialize(ar); - ar & m_D; - ar & m_wi & m_wip & m_wit & m_awi & m_awip & m_awit; - ar & m_wf & m_wfp & m_wft & m_awf & m_awfp & m_awft; - ar & m_Xd & m_Xdp & m_Xdt & m_aXd & m_aXdp & m_aXdt; - ar & m_Xf & m_Xfp & m_Xft & m_aXf & m_aXfp & m_aXft; -} - -//////////////////////////// FATIGUE MATERIAL ///////////////////////////////// -//----------------------------------------------------------------------------- -// define the material parameters -BEGIN_FECORE_CLASS(FEFatigueMaterial, FEMaterial) - ADD_PARAMETER(m_k0 , FE_RANGE_GREATER_OR_EQUAL(0.0), "k0" ); - ADD_PARAMETER(m_beta , FE_RANGE_GREATER_OR_EQUAL(0.0), "beta"); - - // set material properties - ADD_PROPERTY(m_pBase, "elastic"); - ADD_PROPERTY(m_pIdmg, "intact_damage"); - ADD_PROPERTY(m_pFdmg, "fatigue_damage"); - ADD_PROPERTY(m_pDcrt, "damage_criterion"); - ADD_PROPERTY(m_pFcrt, "fatigue_criterion"); - -END_FECORE_CLASS(); - -//----------------------------------------------------------------------------- -//! Constructor. -FEFatigueMaterial::FEFatigueMaterial(FEModel* pfem) : FEElasticMaterial(pfem) -{ - m_pBase = 0; - m_pIdmg = 0; - m_pFdmg = 0; - m_pDcrt = 0; - m_pFcrt = 0; -} - -//----------------------------------------------------------------------------- -//! Initialization. -bool FEFatigueMaterial::Init() -{ - FEUncoupledMaterial* m_pMat = dynamic_cast((FEElasticMaterial*)m_pBase); - if (m_pMat != nullptr) - { - feLogError("Elastic material should not be of type uncoupled"); - return false; - } - - return FEElasticMaterial::Init(); -} - -//----------------------------------------------------------------------------- -//! calculate stress at material point -mat3ds FEFatigueMaterial::Stress(FEMaterialPoint& pt) -{ - // evaluate the damage - double d = Damage(pt); - - // evaluate the stress - mat3ds s = m_pBase->Stress(pt); - - // return damaged stress - return s*(1-d); -} - -//----------------------------------------------------------------------------- -//! calculate tangent stiffness at material point -tens4ds FEFatigueMaterial::Tangent(FEMaterialPoint& pt) -{ - // evaluate the damage - double d = Damage(pt); - - // evaluate the tangent - tens4ds c = m_pBase->Tangent(pt); - - // return damaged tangent - return c*(1-d); -} - -//----------------------------------------------------------------------------- -//! calculate strain energy density at material point -double FEFatigueMaterial::StrainEnergyDensity(FEMaterialPoint& pt) -{ - // evaluate the damage - double d = Damage(pt); - - // evaluate the strain energy density - double sed = m_pBase->StrainEnergyDensity(pt); - - // return damaged sed - return sed*(1-d); -} - -//----------------------------------------------------------------------------- -//! calculate damage at material point -double FEFatigueMaterial::Damage(FEMaterialPoint& pt) -{ - // get the damage material point data - FEFatigueMaterialPoint& pd = *pt.ExtractData(); - - pd.m_D = 1 - pd.m_wi - pd.m_wf; - - return pd.m_D; -} - -//----------------------------------------------------------------------------- -// update fatigue material point at each iteration -void FEFatigueMaterial::UpdateSpecializedMaterialPoints(FEMaterialPoint& pt, const FETimeInfo& tp) -{ - // get the fatigue material point data - FEFatigueMaterialPoint& pd = *pt.ExtractData(); - - // evaluate intermediate time point variables - pd.m_wi = (1-tp.alphaf)*pd.m_wip + tp.alphaf*pd.m_wit; - pd.m_awi = (1-tp.alpham)*pd.m_awip + tp.alpham*pd.m_awit; - pd.m_wf = (1-tp.alphaf)*pd.m_wfp + tp.alphaf*pd.m_wft; - pd.m_awf = (1-tp.alpham)*pd.m_awfp + tp.alpham*pd.m_awft; - - // get damage and fatigue criteria at intermediate time point - pd.m_Xd = m_pDcrt->DamageCriterion(pt); - pd.m_Xf = m_pFcrt->DamageCriterion(pt); - pd.m_Xdt = pd.m_Xdp + (pd.m_Xd - pd.m_Xdp)/tp.alphaf; - pd.m_Xft = pd.m_Xfp + (pd.m_Xf - pd.m_Xfp)/tp.alphaf; - pd.m_aXdt = (pd.m_Xd - pd.m_Xdp)/(tp.alphaf*tp.gamma*tp.timeIncrement) - (1.0/tp.gamma - 1.0)*pd.m_aXdp; - pd.m_aXft = (pd.m_Xf - pd.m_Xfp)/(tp.alphaf*tp.gamma*tp.timeIncrement) - (1.0/tp.gamma - 1.0)*pd.m_aXfp; - pd.m_aXd = (1-tp.alpham)*pd.m_aXdp + tp.alpham*pd.m_aXdt; - pd.m_aXf = (1-tp.alpham)*pd.m_aXfp + tp.alpham*pd.m_aXft; - - // evaluate mass supplies from damage - double fi = 0, ff = 0; - if (pd.m_Xd > pd.m_Xdp) { - fi = -m_pIdmg->pdf(pd.m_Xd)/(1-m_pIdmg->cdf(pd.m_Xd))*pd.m_aXd; - ff = -m_pFdmg->pdf(pd.m_Xd)/(1-m_pFdmg->cdf(pd.m_Xd))*pd.m_aXd; - } - - // evaluate mass supplies from fatigue - double f = m_k0*pow(fabs(pd.m_Xf), m_beta); - // deduct from intact bond fraction - fi -= f; - // add to fatigued bond fraction - ff += f; - - // update bond mass fractions based on mass supplies - double dwi = (fi*pd.m_wi - pd.m_awi)/(tp.alpham/tp.gamma/tp.timeIncrement - tp.alphaf*fi); - double dwf = (ff*pd.m_wf - pd.m_awf)/(tp.alpham/tp.gamma/tp.timeIncrement - tp.alphaf*ff); - pd.m_wit += dwi; - pd.m_wft += dwf; - pd.m_wi = (1-tp.alphaf)*pd.m_wip + tp.alphaf*pd.m_wit; - pd.m_wf = (1-tp.alphaf)*pd.m_wfp + tp.alphaf*pd.m_wft; - - // update time derivatives - pd.m_awit = (pd.m_wit - pd.m_wip)/(tp.gamma*tp.timeIncrement) + (1.0-1.0/tp.gamma)*pd.m_awip; - pd.m_awft = (pd.m_wft - pd.m_wfp)/(tp.gamma*tp.timeIncrement) + (1.0-1.0/tp.gamma)*pd.m_awfp; - pd.m_awi = (1-tp.alpham)*pd.m_awip + tp.alpham*pd.m_awit; - pd.m_awf = (1-tp.alpham)*pd.m_awfp + tp.alpham*pd.m_awft; -} diff --git a/FEBioMech/FEFatigueMaterial.h b/FEBioMech/FEFatigueMaterial.h deleted file mode 100644 index dc1b01d59..000000000 --- a/FEBioMech/FEFatigueMaterial.h +++ /dev/null @@ -1,134 +0,0 @@ -/*This file is part of the FEBio source code and is licensed under the MIT license -listed below. - -See Copyright-FEBio.txt for details. - -Copyright (c) 2021 University of Utah, The Trustees of Columbia University in -the City of New York, and others. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.*/ - - - -#pragma once -#include "FEElasticMaterial.h" -#include "FEDamageCriterion.h" -#include "FEDamageCDF.h" - -//----------------------------------------------------------------------------- -// Define a material point that stores the fatigue and damage variables. -class FEFatigueMaterialPoint : public FEMaterialPoint -{ -public: - FEFatigueMaterialPoint(FEMaterialPoint *pt) : FEMaterialPoint(pt) {} - - FEMaterialPoint* Copy(); - - void Init(); - void Update(const FETimeInfo& timeInfo); - - void Serialize(DumpStream& ar); - -public: - double m_D; //!< damage (0 = no damage, 1 = complete damage) - - double m_wi; //!< intact bond fraction at intermediate time - double m_wip; //!< intact bond fraction at previous time - double m_wit; //!< intact bond fraction at current time - - double m_awi; //!< time deriv of intact bond fraction at intermediate time - double m_awip; //!< time deriv of intact bond fraction at previous time - double m_awit; //!< time deriv of intact bond fraction at current time - - double m_wf; //!< fatigued bond fraction at intermediate time - double m_wfp; //!< fatigued bond fraction at previous time - double m_wft; //!< fatigued bond fraction at current time - - double m_awf; //!< time deriv of fatigued bond fraction at intermediate time - double m_awfp; //!< time deriv of fatigued bond fraction at previous time - double m_awft; //!< time deriv of fatigued bond fraction at current time - - double m_Xd; //!< damage criterion at intermediate time - double m_Xdp; //!< damage criterion at previous time - double m_Xdt; //!< damage criterion at current time - - double m_aXd; //!< time deriv of damage criterion at intermediate time - double m_aXdp; //!< time deriv of damage criterion at previous time - double m_aXdt; //!< time deriv of damage criterion at current time - - double m_Xf; //!< fatigue criterion at intermediate time - double m_Xfp; //!< fatigue criterion at previous time - double m_Xft; //!< fatigue criterion at current time - - double m_aXf; //!< time deriv of fatigue criterion at intermediate time - double m_aXfp; //!< time deriv of fatigue criterion at previous time - double m_aXft; //!< time deriv of fatigue criterion at current time - -}; - -//----------------------------------------------------------------------------- -// This material models fatigue and damage in any hyper-elastic materials. - -class FEFatigueMaterial : public FEElasticMaterial -{ -public: - FEFatigueMaterial(FEModel* pfem); - -public: - //! calculate stress at material point - mat3ds Stress(FEMaterialPoint& pt) override; - - //! calculate tangent stiffness at material point - tens4ds Tangent(FEMaterialPoint& pt) override; - - //! calculate strain energy density at material point - double StrainEnergyDensity(FEMaterialPoint& pt) override; - - //! damage - double Damage(FEMaterialPoint& pt); - - //! data initialization and checking - bool Init() override; - - // returns a pointer to a new material point object - FEMaterialPoint* CreateMaterialPointData() override - { - return new FEFatigueMaterialPoint(m_pBase->CreateMaterialPointData()); - } - - // get the elastic material - FEElasticMaterial* GetElasticMaterial() override { return m_pBase; } - - // update fatigue material point at each iteration - void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; - -public: - - FEElasticMaterial* m_pBase; // base elastic material - FEDamageCDF* m_pIdmg; // damage model for intact bonds - FEDamageCDF* m_pFdmg; // damage model for fatigued bonds - FEDamageCriterion* m_pDcrt; // damage criterion - FEDamageCriterion* m_pFcrt; // fatigue criterion - -public: - double m_k0; // reaction rate for fatigue reaction - double m_beta; // power exponent for fatigue reaction - - DECLARE_FECORE_CLASS(); -}; diff --git a/FEBioMech/FEFiberPowLinear.cpp b/FEBioMech/FEFiberPowLinear.cpp index bd72d2ab4..62ba0d455 100644 --- a/FEBioMech/FEFiberPowLinear.cpp +++ b/FEBioMech/FEFiberPowLinear.cpp @@ -173,41 +173,45 @@ double FEFiberPowLinear::FiberStrainEnergyDensity(FEMaterialPoint& mp, const vec } //----------------------------------------------------------------------------- -// FEFiberPowerLinear +// FEFiberExpPowLinear //----------------------------------------------------------------------------- // define the material parameters -BEGIN_FECORE_CLASS(FEFiberPowerLinear, FEElasticFiberMaterial) +BEGIN_FECORE_CLASS(FEFiberExpPowLinear, FEElasticFiberMaterial) ADD_PARAMETER(m_E , FE_RANGE_GREATER_OR_EQUAL(0.0), "E"); + ADD_PARAMETER(m_alpha, FE_RANGE_GREATER_OR_EQUAL(0.0), "alpha"); ADD_PARAMETER(m_beta, FE_RANGE_GREATER_OR_EQUAL(2.0), "beta"); ADD_PARAMETER(m_lam0, FE_RANGE_GREATER(1.0), "lam0"); ADD_PARAMETER(m_epsf, "epsilon_scale"); END_FECORE_CLASS(); //----------------------------------------------------------------------------- -FEFiberPowerLinear::FEFiberPowerLinear(FEModel* pfem) : FEElasticFiberMaterial(pfem) +FEFiberExpPowLinear::FEFiberExpPowLinear(FEModel* pfem) : FEElasticFiberMaterial(pfem) { m_E = 0; m_lam0 = 1; + m_alpha = 0; m_beta = 3; m_epsf = 0.0; } //----------------------------------------------------------------------------- -bool FEFiberPowerLinear::Validate() +bool FEFiberExpPowLinear::Validate() { if (FEElasticFiberMaterial::Validate() == false) return false; // initialize material constants m_I0 = m_lam0*m_lam0; - m_ksi = 0.25*m_E*pow(m_I0 - 1, 2 - m_beta) / (m_beta - 1)*pow(m_I0, -3. / 2.); - m_b = m_ksi*pow(m_I0 - 1, m_beta - 1) + m_E / 2 / sqrt(m_I0); + m_ksi = m_E*pow(m_I0-1,2-m_beta)*exp(-m_alpha*pow(m_I0-1,m_beta)) + /(4*pow(m_I0,1.5)*(m_beta-1+m_alpha*m_beta*pow(m_I0-1,m_beta))); + m_b = m_E*(2*m_I0*(m_beta-0.5+m_alpha*m_beta*pow(m_I0-1,m_beta))-1) + /(4*pow(m_I0,1.5)*(m_beta-1+m_alpha*m_beta*pow(m_I0-1,m_beta))); return true; } //----------------------------------------------------------------------------- -mat3ds FEFiberPowerLinear::FiberStress(FEMaterialPoint& mp, const vec3d& n0) +mat3ds FEFiberExpPowLinear::FiberStress(FEMaterialPoint& mp, const vec3d& n0) { FEElasticMaterialPoint& pt = *mp.ExtractData(); @@ -234,7 +238,7 @@ mat3ds FEFiberPowerLinear::FiberStress(FEMaterialPoint& mp, const vec3d& n0) // calculate the fiber stress magnitude double sn = (In < m_I0) ? - 2 * In*m_ksi*pow(In - 1, m_beta - 1) : + 2 * In*exp(m_alpha*pow(In-1,m_beta))*m_ksi*pow(In - 1, m_beta - 1) : 2 * m_b*In - m_E*sqrt(In); // calculate the fiber stress @@ -249,7 +253,7 @@ mat3ds FEFiberPowerLinear::FiberStress(FEMaterialPoint& mp, const vec3d& n0) } //----------------------------------------------------------------------------- -tens4ds FEFiberPowerLinear::FiberTangent(FEMaterialPoint& mp, const vec3d& n0) +tens4ds FEFiberExpPowLinear::FiberTangent(FEMaterialPoint& mp, const vec3d& n0) { FEElasticMaterialPoint& pt = *mp.ExtractData(); @@ -276,7 +280,7 @@ tens4ds FEFiberPowerLinear::FiberTangent(FEMaterialPoint& mp, const vec3d& n0) // calculate modulus double cn = (In < m_I0) ? - 4 * In*In*m_ksi*(m_beta - 1)*pow(In - 1, m_beta - 2) : + 4*m_ksi*In*In*exp(m_alpha*pow(In-1,m_beta))*pow(In-1,m_beta-2)*(m_beta-1+m_alpha*m_beta*pow(In-1,m_beta)) : m_E*sqrt(In); // calculate the fiber tangent @@ -292,7 +296,7 @@ tens4ds FEFiberPowerLinear::FiberTangent(FEMaterialPoint& mp, const vec3d& n0) //----------------------------------------------------------------------------- //! Strain energy density -double FEFiberPowerLinear::FiberStrainEnergyDensity(FEMaterialPoint& mp, const vec3d& n0) +double FEFiberExpPowLinear::FiberStrainEnergyDensity(FEMaterialPoint& mp, const vec3d& n0) { double sed = 0.0; @@ -309,9 +313,16 @@ double FEFiberPowerLinear::FiberStrainEnergyDensity(FEMaterialPoint& mp, const v if (In - 1 >= eps) { // calculate strain energy density + if (m_alpha == 0) { sed = (In < m_I0) ? m_ksi / m_beta*pow(In - 1, m_beta) : m_b*(In - m_I0) - m_E*(sqrt(In) - sqrt(m_I0)) + m_ksi / m_beta*pow(m_I0 - 1, m_beta); + } + else { + sed = (In < m_I0) ? + m_ksi / (m_alpha*m_beta)*(exp(m_alpha*pow(In - 1, m_beta))-1) : + m_b*(In - m_I0) - m_E*(sqrt(In) - sqrt(m_I0)) + m_ksi / (m_alpha*m_beta)*(exp(m_alpha*pow(m_I0 - 1, m_beta))-1); + } } return sed; diff --git a/FEBioMech/FEFiberPowLinear.h b/FEBioMech/FEFiberPowLinear.h index a0900bd81..4a36f8a28 100644 --- a/FEBioMech/FEFiberPowLinear.h +++ b/FEBioMech/FEFiberPowLinear.h @@ -58,12 +58,11 @@ class FEFiberPowLinear : public FEElasticFiberMaterial }; //----------------------------------------------------------------------------- -//! Power law toe region - linear -//! TODO: I want to delete one of these materials -class FEFiberPowerLinear : public FEElasticFiberMaterial +//! Exponential-Power law toe region - linear +class FEFiberExpPowLinear : public FEElasticFiberMaterial { public: - FEFiberPowerLinear(FEModel* pfem); + FEFiberExpPowLinear(FEModel* pfem); //! Initialization bool Validate() override; @@ -80,6 +79,7 @@ class FEFiberPowerLinear : public FEElasticFiberMaterial public: double m_E; // fiber modulus double m_lam0; // stretch ratio at end of toe region + double m_alpha; // exponential coefficient double m_beta; // power law exponent in toe region double m_epsf; diff --git a/FEBioMech/FEFiberPowLinearUncoupled.cpp b/FEBioMech/FEFiberPowLinearUncoupled.cpp index 16c4db05b..19803e95a 100644 --- a/FEBioMech/FEFiberPowLinearUncoupled.cpp +++ b/FEBioMech/FEFiberPowLinearUncoupled.cpp @@ -42,19 +42,6 @@ FEFiberPowLinearUncoupled::FEFiberPowLinearUncoupled(FEModel* pfem) : FEElasticF } -//----------------------------------------------------------------------------- -bool FEFiberPowLinearUncoupled::Validate() -{ - if (FEElasticFiberMaterialUC::Validate() == false) return false; - - // initialize material constants - m_I0 = m_lam0*m_lam0; - m_ksi = m_E / 4 / (m_beta - 1)*pow(m_I0, -3. / 2.)*pow(m_I0 - 1, 2 - m_beta); - m_b = m_ksi*pow(m_I0 - 1, m_beta - 1) + m_E / 2 / sqrt(m_I0); - - return true; -} - //----------------------------------------------------------------------------- mat3ds FEFiberPowLinearUncoupled::DevFiberStress(FEMaterialPoint& mp, const vec3d& n0) { @@ -71,6 +58,12 @@ mat3ds FEFiberPowLinearUncoupled::DevFiberStress(FEMaterialPoint& mp, const vec3 // Calculate In double In = n0*(C*n0); + // initialize material constants + double E = m_E(mp); + double I0 = m_lam0*m_lam0; + double ksi = m_E(mp) / 4.0 / (m_beta - 1)*pow(I0, -3.0 / 2.0)*pow(I0 - 1.0, 2.0 - m_beta); + double b = ksi*pow(I0 - 1.0, m_beta - 1.0) + E / 2.0 / sqrt(I0); + // only take fibers in tension into consideration const double eps = 0; if (In - 1 >= eps) @@ -82,9 +75,9 @@ mat3ds FEFiberPowLinearUncoupled::DevFiberStress(FEMaterialPoint& mp, const vec3 mat3ds N = dyad(nt); // calculate the fiber stress magnitude - double sn = (In < m_I0) ? - 2*In*m_ksi*pow(In-1, m_beta-1) : - 2*m_b*In - m_E*sqrt(In); + double sn = (In < I0) ? + 2*In*ksi*pow(In-1, m_beta-1) : + 2*b*In - m_E(mp)*sqrt(In); // calculate the fiber stress s = N*(sn/J); @@ -125,18 +118,22 @@ tens4ds FEFiberPowLinearUncoupled::DevFiberTangent(FEMaterialPoint& mp, const ve mat3ds N = dyad(nt); tens4ds NxN = dyad1s(N); + // initialize material constants + double E = m_E(mp); + double I0 = m_lam0 * m_lam0; + double ksi = m_E(mp) / 4.0 / (m_beta - 1) * pow(I0, -3.0 / 2.0) * pow(I0 - 1.0, 2.0 - m_beta); + double b = ksi * pow(I0 - 1.0, m_beta - 1.0) + E / 2.0 / sqrt(I0); + // calculate the fiber stress magnitude - double sn = (In < m_I0) ? - 2*In*m_ksi*pow(In-1, m_beta-1) : - 2*m_b*In - m_E*sqrt(In); + double sn = (In < I0) ? + 2*In*ksi*pow(In-1, m_beta-1) : + 2*b*In - E*sqrt(In); // calculate the fiber stress s = N*(sn/J); // calculate modulus - double cn = (In < m_I0) ? - 4*In*In*m_ksi*(m_beta-1)*pow(In-1, m_beta-2) : - m_E*sqrt(In); + double cn = (In < I0) ? 4*In*In*ksi*(m_beta-1)*pow(In-1, m_beta-2) : E*sqrt(In); // calculate the fiber tangent c = NxN*(cn/J); @@ -172,10 +169,16 @@ double FEFiberPowLinearUncoupled::DevFiberStrainEnergyDensity(FEMaterialPoint& m double sed = 0.0; if (In - 1 >= eps) { + // initialize material constants + double E = m_E(mp); + double I0 = m_lam0 * m_lam0; + double ksi = m_E(mp) / 4.0 / (m_beta - 1) * pow(I0, -3.0 / 2.0) * pow(I0 - 1.0, 2.0 - m_beta); + double b = ksi * pow(I0 - 1.0, m_beta - 1.0) + E / 2.0 / sqrt(I0); + // calculate strain energy density - sed = (In < m_I0) ? - m_ksi/m_beta*pow(In-1, m_beta) : - m_b*(In-m_I0) - m_E*(sqrt(In) - sqrt(m_I0)) + m_ksi/m_beta*pow(m_I0-1, m_beta); + sed = (In < I0) ? + ksi/m_beta*pow(In-1, m_beta) : + b*(In-I0) - E*(sqrt(In) - sqrt(I0)) + ksi/m_beta*pow(I0-1, m_beta); } return sed; diff --git a/FEBioMech/FEFiberPowLinearUncoupled.h b/FEBioMech/FEFiberPowLinearUncoupled.h index b0aaa8bca..b425d2f79 100644 --- a/FEBioMech/FEFiberPowLinearUncoupled.h +++ b/FEBioMech/FEFiberPowLinearUncoupled.h @@ -38,9 +38,7 @@ class FEFiberPowLinearUncoupled : public FEElasticFiberMaterialUC public: FEFiberPowLinearUncoupled(FEModel* pfem); - // validation - bool Validate() override; - + //! Cauchy stress virtual mat3ds DevFiberStress(FEMaterialPoint& mp, const vec3d& n0) override; @@ -51,15 +49,10 @@ class FEFiberPowLinearUncoupled : public FEElasticFiberMaterialUC virtual double DevFiberStrainEnergyDensity(FEMaterialPoint& mp, const vec3d& n0) override; public: - double m_E; // fiber modulus + FEParamDouble m_E; // fiber modulus double m_lam0; // stretch ratio at end of toe region double m_beta; // power law exponent in toe region -private: - double m_ksi; // power law coefficient in toe region - double m_I0; // m_lam0^2 - double m_b; // coefficient in linear region - // declare the parameter list DECLARE_FECORE_CLASS(); }; diff --git a/FEBioMech/FEFixedNormalDisplacement.cpp b/FEBioMech/FEFixedNormalDisplacement.cpp new file mode 100644 index 000000000..f617c5cd9 --- /dev/null +++ b/FEBioMech/FEFixedNormalDisplacement.cpp @@ -0,0 +1,145 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FEFixedNormalDisplacement.h" +#include "FECore/FECoreKernel.h" +#include + +//============================================================================= +BEGIN_FECORE_CLASS(FEFixedNormalDisplacement, FELinearConstraintSet) + ADD_PARAMETER(m_bshellb , "shell_bottom"); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +FEFixedNormalDisplacement::FEFixedNormalDisplacement(FEModel* pfem) : FELinearConstraintSet(pfem), m_surf(pfem) +{ + m_binit = false; + m_bshellb = false; +} + +//----------------------------------------------------------------------------- +//! Initializes data structures. +void FEFixedNormalDisplacement::Activate() +{ + // don't forget to call base class + FELinearConstraintSet::Activate(); + + FEModel& fem = *FELinearConstraintSet::GetFEModel(); + DOFS& dofs = fem.GetDOFS(); + + // evaluate the nodal normals + FENodeList nl = m_surf.GetNodeList(); + int N = nl.Size(); + vector nn(N,vec3d(0,0,0)); + vec3d nu(0,0,0); + + // loop over all elements to get nodal normals + for (int i=0; im_dof.push_back(dof); + } + // add the linear constraint to the system + add(pLC); + } + } + } + else { + for (int i=0; im_dof.push_back(dof); + } + // add the linear constraint to the system + add(pLC); + } + } + } +} + +//----------------------------------------------------------------------------- +bool FEFixedNormalDisplacement::Init() +{ + // initialize surface + return m_surf.Init(); +} diff --git a/FEBioMech/FEFixedNormalDisplacement.h b/FEBioMech/FEFixedNormalDisplacement.h new file mode 100644 index 000000000..ca9c7b317 --- /dev/null +++ b/FEBioMech/FEFixedNormalDisplacement.h @@ -0,0 +1,64 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#pragma once +#include "FEAugLagLinearConstraint.h" +#include +#include + +//----------------------------------------------------------------------------- +//! The FEFixedNormalDisplacement class implements a linear constraint for fixing the normal component +//! of the solid displacement. + +class FEFixedNormalDisplacement : public FELinearConstraintSet +{ +public: + //! constructor + FEFixedNormalDisplacement(FEModel* pfem); + + //! destructor + ~FEFixedNormalDisplacement() {} + + //! Activation + void Activate() override; + + //! initialization + bool Init() override; + + //! Get the surface + FESurface* GetSurface() override { return &m_surf; } + +protected: + FESurface m_surf; + bool m_binit; + +public: + bool m_bshellb; + + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FEForceVelocityContraction.cpp b/FEBioMech/FEForceVelocityContraction.cpp new file mode 100644 index 000000000..5fe4cf9d0 --- /dev/null +++ b/FEBioMech/FEForceVelocityContraction.cpp @@ -0,0 +1,298 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FEForceVelocityContraction.h" +#include "FEElasticMaterial.h" +#include + +////////////////////////////////////////////////////////////////////// +// FEForceVelocityMaterialPoint +////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +FEMaterialPoint* FEForceVelocityMaterialPoint::Copy() +{ + FEForceVelocityMaterialPoint* pt = new FEForceVelocityMaterialPoint(*this); + if (m_pNext) pt->m_pNext = m_pNext->Copy(); + return pt; +} + +//----------------------------------------------------------------------------- +void FEForceVelocityMaterialPoint::Init() +{ + FEMaterialPoint::Init(); + + m_lambdap = 1; + + for (int i=0; i> m_lambdap; + for (int i=0; i> m_H[i] >> m_Hp[i]; + } + + FEMaterialPoint::Serialize(ar); + +} + +////////////////////////////////////////////////////////////////////// +// FEForceVelocityContraction +////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +BEGIN_FECORE_CLASS(FEForceVelocityContraction, FEActiveContractionMaterial); + ADD_PARAMETER(m_ascl , "ascl"); + ADD_PARAMETER(m_Tmax , "Tmax"); + ADD_PARAMETER(m_ca0 , "ca0"); + ADD_PARAMETER(m_camax, "camax"); + ADD_PARAMETER(m_beta , "beta"); + ADD_PARAMETER(m_l0 , "l0"); + ADD_PARAMETER(m_refl , "refl"); + ADD_PARAMETER(m_alpha[0] , "alpha1"); + ADD_PARAMETER(m_alpha[1] , "alpha2"); + ADD_PARAMETER(m_alpha[2] , "alpha3"); + ADD_PARAMETER(m_A[0] , "A1"); + ADD_PARAMETER(m_A[1] , "A2"); + ADD_PARAMETER(m_A[2] , "A3"); + ADD_PARAMETER(m_at , "a_t"); + ADD_PARAMETER(m_bfvel, "force_velocity" ); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +FEForceVelocityContraction::FEForceVelocityContraction(FEModel* pfem) : FEActiveContractionMaterial(pfem) +{ + m_ascl = 0; + m_Tmax = 1.0; + m_ca0 = 1.0; + m_camax = 0.0; + m_l0 = m_refl = 0; + m_beta = 0; + m_A[0] = m_A[1] = m_A[2] = 0; + m_alpha[0] = m_alpha[1] = m_alpha[2] = 0; + m_at = 0; + m_bfvel = true; +} + +//----------------------------------------------------------------------------- +bool FEForceVelocityContraction::Init() +{ + if (FEMaterial::Init() == false) return false; + + // for backward compatibility we set m_camax to m_ca0 if it is not defined + if (m_camax == 0.0) m_camax = m_ca0; + if (m_camax <= 0.0) { feLogError("camax must be larger than zero"); return false; } + + return true; +} + +//----------------------------------------------------------------------------- +mat3ds FEForceVelocityContraction::ActiveStress(FEMaterialPoint& mp, const vec3d& a0) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // get the deformation gradient + mat3d F = pt.m_F; + double J = pt.m_J; + double Jm13 = pow(J, -1.0 / 3.0); + + // calculate the current material axis lam*a = F*a0; + vec3d a = F*a0; + + double lam, lamd; + lam = a.unit(); + lamd = lam*Jm13; // i.e. lambda tilde + + mat3ds AxA = dyad(a); + + // get the activation + double saf = 0.0; + double FVstress = 0.0; + double dt = GetFEModel()->GetTime().timeIncrement; + if (m_ascl > 0) + { + double ctenslm = m_ascl; + + // current sarcomere length + double strl = m_refl*lamd; + + // sarcomere length change + double dl = strl - m_l0; + + if (dl >= 0) + { + // calcium sensitivity + double eca50i = (exp(m_beta*dl) - 1); + + // ratio of Camax/Ca0 + double rca = m_camax/m_ca0; + + // active fiber stress + saf = m_Tmax*(eca50i / ( eca50i + rca*rca ))*ctenslm; + + if (m_bfvel) + { + FEForceVelocityMaterialPoint& vpt = *mp.ExtractData(); + + double lambdap = vpt.m_lambdap; + + double Qac = 0; + double Qac2 = 0; + + // double dt = GetFEModel()->GetTime().timeIncrement; + // double dt = 1; + double g; + double h; + // double Hnew; + // double Hnew = 10; + + for (int i=0; i 0) + { + vpt.m_H[i] = vpt.m_Hp[i]*g; // POSITIVE VELOCITY SET TO 0 + } + + Qac += vpt.m_H[i]*m_A[i]; + Qac2 = abs(Qac); + } + + // return the total Cauchy stress, + // which is the push-forward of sarcomere + + // FVstress = saf*(1 - m_at*Qac2)/(1+Qac2); //NEGATIVE ABSOLUTE VALUE OF Q + FVstress = saf*(1 + m_at*Qac)/(1-Qac); + } + else + { + FVstress = saf; + } + } + } + return AxA*FVstress; + +} + +//----------------------------------------------------------------------------- +tens4ds FEForceVelocityContraction::ActiveStiffness(FEMaterialPoint& mp, const vec3d& a0) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // get the deformation gradient + mat3d F = pt.m_F; + double J = pt.m_J; + double Jm13 = pow(J, -1.0 / 3.0); + + // calculate the current material axis lam*a = F*a0; + vec3d a = F*a0; + + // normalize material axis and store fiber stretch + double lam, lamd; + lam = a.unit(); + lamd = lam*Jm13; // i.e. lambda tilde + + // calculate dyad of a: AxA = (a x a) + mat3ds AxA = dyad(a); + tens4ds AxAxAxA = dyad1s(AxA); + + double c = 0; + if (m_ascl > 0) + { + // current sarcomere length + double strl = m_refl*lamd; + + // sarcomere length change + double dl = strl - m_l0; + + if (dl >= 0) + { + // calcium sensitivity + double eca50i = (exp(m_beta*dl) - 1); + + double decl = m_beta*m_refl*exp(m_beta*dl); + + // ratio of Camax/Ca0 + double rca = m_camax / m_ca0; + + double d = eca50i + rca*rca; + + // active fiber stress + double saf = m_Tmax*(eca50i / d)*m_ascl; + + double dsf = m_Tmax*m_ascl*decl*(1.0/ d - eca50i / (d*d)); + + c = (lamd*dsf - 2.0*saf); + } + } + + return AxAxAxA*c; +} + +//----------------------------------------------------------------------------- +// update force-velocity material point +void FEForceVelocityContraction::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp, const vec3d& a0) +{ + FEForceVelocityMaterialPoint& pt = *mp.ExtractData(); + FEElasticMaterialPoint& pe = *mp.ExtractData(); + double Jm13 = pow(pe.m_J, -1.0/3.0); + + vec3d a = pe.m_F*a0; + double lambda1 = a.unit(); + pt.m_lambdap = lambda1*Jm13; + + for (int i=0; i vars = { "I1", "I2", "J" }; @@ -88,7 +94,19 @@ bool FEGenericHyperelastic::Init() string sWJJ = o2s.Convert(m_WJJ); feLog("WJJ = %s\n", sWJJ.c_str()); #endif - return FEElasticMaterial::Init(); + return true; +} + + +// serialization +void FEGenericHyperelastic::Serialize(DumpStream& ar) +{ + FEElasticMaterial::Serialize(ar); + if ((ar.IsShallow() == false) && ar.IsLoading()) + { + bool b = BuildMathExpressions(); + assert(b); + } } mat3ds FEGenericHyperelastic::Stress(FEMaterialPoint& mp) diff --git a/FEBioMech/FEGenericHyperelastic.h b/FEBioMech/FEGenericHyperelastic.h index 0e638a8c2..b4b5a3a02 100644 --- a/FEBioMech/FEGenericHyperelastic.h +++ b/FEBioMech/FEGenericHyperelastic.h @@ -39,12 +39,18 @@ class FEGenericHyperelastic : public FEElasticMaterial bool Init() override; + // serialization + void Serialize(DumpStream& ar) override; + mat3ds Stress(FEMaterialPoint& mp) override; tens4ds Tangent(FEMaterialPoint& mp) override; double StrainEnergyDensity(FEMaterialPoint& mp) override; +private: + bool BuildMathExpressions(); + private: std::string m_exp; diff --git a/FEBioMech/FEGenericHyperelasticUC.cpp b/FEBioMech/FEGenericHyperelasticUC.cpp index e093edee9..1e5464fbe 100644 --- a/FEBioMech/FEGenericHyperelasticUC.cpp +++ b/FEBioMech/FEGenericHyperelasticUC.cpp @@ -41,6 +41,12 @@ FEGenericHyperelasticUC::FEGenericHyperelasticUC(FEModel* fem) : FEUncoupledMate // initialization bool FEGenericHyperelasticUC::Init() +{ + if (BuildMathExpressions() == false) return false; + return FEUncoupledMaterial::Init(); +} + +bool FEGenericHyperelasticUC::BuildMathExpressions() { vector vars = { "I1", "I2" }; @@ -85,7 +91,18 @@ bool FEGenericHyperelasticUC::Init() string sW22 = o2s.Convert(m_W22); feLog("W22 = %s\n", sW22.c_str()); } - return FEUncoupledMaterial::Init(); + return true; +} + +// serialization +void FEGenericHyperelasticUC::Serialize(DumpStream& ar) +{ + FEUncoupledMaterial::Serialize(ar); + if ((ar.IsShallow() == false) && ar.IsLoading()) + { + bool b = BuildMathExpressions(); + assert(b); + } } //! Deviatoric Cauchy stress diff --git a/FEBioMech/FEGenericHyperelasticUC.h b/FEBioMech/FEGenericHyperelasticUC.h index fd6004ccf..7a750bdc0 100644 --- a/FEBioMech/FEGenericHyperelasticUC.h +++ b/FEBioMech/FEGenericHyperelasticUC.h @@ -34,6 +34,9 @@ class FEGenericHyperelasticUC : public FEUncoupledMaterial // initialization bool Init() override; + // serialization + void Serialize(DumpStream& ar) override; + //! Deviatoric Cauchy stress mat3ds DevStress(FEMaterialPoint& mp) override; @@ -43,6 +46,9 @@ class FEGenericHyperelasticUC : public FEUncoupledMaterial //! Deviatoric strain energy density double DevStrainEnergyDensity(FEMaterialPoint& mp) override; +private: + bool BuildMathExpressions(); + private: std::string m_exp; // the string with the strain energy expression bool m_printDerivs; // option to print out derivatives diff --git a/FEBioMech/FEHGOCoronary.cpp b/FEBioMech/FEHGOCoronary.cpp new file mode 100644 index 000000000..b22a86207 --- /dev/null +++ b/FEBioMech/FEHGOCoronary.cpp @@ -0,0 +1,219 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#include "stdafx.h" +#include "FEHGOCoronary.h" + +// define the material parameters +BEGIN_FECORE_CLASS(FEHGOCoronary, FEUncoupledMaterial) + ADD_PARAMETER(m_rho, "rho"); + ADD_PARAMETER(m_k1 , "k1"); + ADD_PARAMETER(m_k2 , "k2"); + + ADD_PARAMETER(m_fiber, "fiber"); + +END_FECORE_CLASS(); + +////////////////////////////////////////////////////////////////////// +// FETransIsoMooneyRivlin +////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------------- +FEHGOCoronary::FEHGOCoronary(FEModel* pfem) : FEUncoupledMaterial(pfem) +{ + m_rho = 0.0; + m_k1 = 0.0; + m_k2 = 1.0; + m_fiber = vec3d(1,0,0); +} + +//----------------------------------------------------------------------------- +mat3ds FEHGOCoronary::DevStress(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // deformation gradient + mat3d F = pt.m_F; + double J = pt.m_J; + double Jm13 = pow(J, -1.0 / 3.0); + + // calculate deviatoric left Cauchy-Green tensor + mat3ds B = pt.DevLeftCauchyGreen(); + + // calculate square of B + mat3ds B2 = B.sqr(); + + // fiber vector + mat3d Q = GetLocalCS(mp); + vec3d a0 = Q*m_fiber(mp); a0.unit(); + vec3d a = F * a0; + double lam = Jm13 * a.unit(); + mat3ds m = dyad(a); + + // Invariants of B (= invariants of C) + // Note that these are the invariants of Btilde, not of B! + double I1 = B.tr(); + double I4 = lam * lam; + + // material parameters + double rho = m_rho; + double k1 = m_k1; + double k2 = m_k2; + + // --- TODO: put strain energy derivatives here --- + // Wi = dW/dIi + double w = k2 * ((1.0 - rho) * (I1 - 3.0) * (I1 - 3.0) + rho*(I4 - 1.0) * (I4 - 1.0)); + double w1 = 2.0 * k2 * (1.0 - rho) * (I1 - 3.0); + double w4 = 2.0 * k2 * rho * (I4 - 1.0); + double kew = k1*exp(w) / k2; + + double W1 = kew * w1; + double W4 = kew * w4; + // ------------------------------------------------ + + // calculate T = F*dW/dC*Ft + mat3ds T = B * W1 + m*(W4*I4); + + // calculate stress s = pI + 2/J * dev(T) + mat3ds s = T.dev() * (2.0 / J); + + return s; +} + +//----------------------------------------------------------------------------- +//! Calculate deviatoric tangent +tens4ds FEHGOCoronary::DevTangent(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // deformation gradient + mat3d F = pt.m_F; + double J = pt.m_J; + double Ji = 1.0 / pt.m_J; + double Jm13 = pow(J, -1.0 / 3.0); + + // calculate deviatoric left Cauchy-Green tensor: B = F*Ft + mat3ds B = pt.DevLeftCauchyGreen(); + + // calculate square of B + mat3ds B2 = B.sqr(); + + // fiber vector + mat3d Q = GetLocalCS(mp); + vec3d a0 = Q*m_fiber(mp); a0.unit(); + vec3d a = F * a0; + double lam = Jm13 * a.unit(); + mat3ds m = dyad(a); + + // Invariants of B (= invariants of C) + double J1 = B.tr(); + double J4 = lam * lam; + + // material parameters + double rho = m_rho; + double k1 = m_k1; + double k2 = m_k2; + + // --- TODO: put strain energy derivatives here --- + // Wi = dW/dIi + double w = k2 * ((1.0 - rho) * (J1 - 3.0) * (J1 - 3.0) + rho * (J4 - 1.0) * (J4 - 1.0)); + double w1 = 2.0 * k2 * (1.0 - rho) * (J1 - 3.0); + double w11 = 2.0 * k2 * (1.0 - rho); + double w4 = 2.0 * k2 * rho * (J4 - 1.0); + double w44 = 2.0 * k2 * rho; + double kew = k1 * exp(w) / k2; + + double W1 = kew * w1; + double W4 = kew * w4; + double W11 = kew * (w1*w1 + w11); + double W44 = kew * (w4*w4 + w44); + double W14 = kew * (w1*w4); + // ------------------------------------ + + // calculate T = F*dW/dC*Ft + mat3ds T = B * W1 + m * (W4 * J4); + + // calculate stress s = pI + 2/J * dev(T) + mat3ds devs = T.dev() * (2.0 / J); + + // calculate dWdC:C + double WC = W1 * J1 + W4 * J4; + + // calculate C:d2WdCdC:C + double CWWC = W11 * J1 * J1 + 2.0 * W14 * J1 * J4 + W44 * J4 * J4; + + mat3dd I(1); // Identity + tens4ds IxI = dyad1s(I); + tens4ds I4 = dyad4s(I); + tens4ds BxB = dyad1s(B); + tens4ds B4 = dyad4s(B); + tens4ds Bxm = dyad1s(B, m); + tens4ds mxm = dyad1s(m); + + // d2W/dCdC:C + mat3ds WCCxC = B * (W11 * J1) + B*(W14*J4) + m*(W14*J4*J1) + m*(W44*J4*J4); + + tens4ds Cw = BxB * W11 + Bxm * (W14 * J4) + mxm * (W44 * J4 * J4); + + tens4ds cw = Cw*(4.0 *Ji) - dyad1s(WCCxC, I) * (4.0 / 3.0 * Ji) + IxI * (4.0 / 9.0 * Ji * CWWC); + tens4ds c = dyad1s(devs, I) * (-2.0 / 3.0) + (I4 - IxI / 3.0) * (4.0 / 3.0 * Ji * WC) + cw; + + return c; +} + +//----------------------------------------------------------------------------- +double FEHGOCoronary::DevStrainEnergyDensity(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // deformation gradient + mat3d F = pt.m_F; + double J = pt.m_J; + double Jm13 = pow(J, -1.0 / 3.0); + + // calculate deviatoric left Cauchy-Green tensor + mat3ds B = pt.DevLeftCauchyGreen(); + + // fiber vector + mat3d Q = GetLocalCS(mp); + vec3d a0 = Q*m_fiber(mp); a0.unit(); + vec3d a = F * a0; + double lam = Jm13 * a.unit(); + + // Invariants of B (= invariants of C) + double J1 = B.tr(); + double J4 = lam * lam; + + // material parameters + double rho = m_rho; + double k1 = m_k1; + double k2 = m_k2; + + // calculate sed + double w = k2 * ((1.0 - rho) * (J1 - 3.0) * (J1 - 3.0) + rho * (J4 - 1.0) * (J4 - 1.0)); + double sed = (k1/k2)*(exp(w) - 1.0); + + return sed; +} diff --git a/FEBioMech/FEHGOCoronary.h b/FEBioMech/FEHGOCoronary.h new file mode 100644 index 000000000..e67d38ea7 --- /dev/null +++ b/FEBioMech/FEHGOCoronary.h @@ -0,0 +1,64 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + + + +#pragma once +#include "FEUncoupledMaterial.h" +#include "FEUncoupledFiberExpLinear.h" + +//----------------------------------------------------------------------------- +// Constitutive formulation from: +// Holzapfel, et.a., "Determination of layer-specific mechanical properties of human +// coronary arteries with nonatherosclerotic intimal thickening +// and related constitutive modeling", Am J Physiol Heart Circ Physiol 289 +class FEHGOCoronary : public FEUncoupledMaterial +{ +public: + FEHGOCoronary(FEModel* pfem); + +public: + double m_rho; + double m_k1; + double m_k2; + + FEParamVec3 m_fiber; + +public: + //! calculate deviatoric stress at material point + mat3ds DevStress(FEMaterialPoint& pt) override; + + //! calculate deviatoric tangent stiffness at material point + tens4ds DevTangent(FEMaterialPoint& pt) override; + + //! calculate deviatoric strain energy density at material point + double DevStrainEnergyDensity(FEMaterialPoint& pt) override; + +protected: + + // declare parameter list + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FEInSituStretchGradient.cpp b/FEBioMech/FEInSituStretchGradient.cpp index d99d1cbf6..52d522154 100644 --- a/FEBioMech/FEInSituStretchGradient.cpp +++ b/FEBioMech/FEInSituStretchGradient.cpp @@ -42,23 +42,41 @@ FEInSituStretchGradient::FEInSituStretchGradient(FEModel* pfem) : FEPrestrainGra //----------------------------------------------------------------------------- bool FEInSituStretchGradient::Init() +{ + m_fiber = GetFiberProperty(); + if (m_fiber == nullptr) return false; + return FEPrestrainGradient::Init(); +} + +//----------------------------------------------------------------------------- +FEParamVec3* FEInSituStretchGradient::GetFiberProperty() { // make sure the parent material is a prestrain material FEPrestrainMaterial* prestrainMat = dynamic_cast(GetParent()); - if (prestrainMat == nullptr) return false; + if (prestrainMat == nullptr) return nullptr; // get the elastic property FEElasticMaterial* elasticMat = prestrainMat->GetElasticMaterial(); // make sure it has a fiber property FEParam* fiberProp = elasticMat->FindParameter("fiber"); - if (fiberProp == nullptr) return false; + if (fiberProp == nullptr) return nullptr; // make sure it's a vector map - if (fiberProp->type() != FE_PARAM_VEC3D_MAPPED) return false; - m_fiber = &(fiberProp->value()); + if (fiberProp->type() != FE_PARAM_VEC3D_MAPPED) return nullptr; + + return &(fiberProp->value()); +} - return FEPrestrainGradient::Init(); +//----------------------------------------------------------------------------- +void FEInSituStretchGradient::Serialize(DumpStream& ar) +{ + FEPrestrainGradient::Serialize(ar); + if ((ar.IsShallow() == false) && ar.IsLoading()) + { + m_fiber = GetFiberProperty(); + assert(m_fiber); + } } //----------------------------------------------------------------------------- diff --git a/FEBioMech/FEInSituStretchGradient.h b/FEBioMech/FEInSituStretchGradient.h index f470bdca5..14b1692f3 100644 --- a/FEBioMech/FEInSituStretchGradient.h +++ b/FEBioMech/FEInSituStretchGradient.h @@ -39,6 +39,11 @@ class FEInSituStretchGradient : public FEPrestrainGradient void Initialize(const mat3d& F, FEMaterialPoint& mp) override; + void Serialize(DumpStream& ar) override; + +private: + FEParamVec3* GetFiberProperty(); + public: FEParamDouble m_lam; //!< in-situ stretch bool m_biso; //!< isochoric generator option diff --git a/FEBioMech/FEKamensky.cpp b/FEBioMech/FEIsotropicLeeSacks.cpp similarity index 91% rename from FEBioMech/FEKamensky.cpp rename to FEBioMech/FEIsotropicLeeSacks.cpp index a4dce0dbc..1723d01f8 100644 --- a/FEBioMech/FEKamensky.cpp +++ b/FEBioMech/FEIsotropicLeeSacks.cpp @@ -24,10 +24,10 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ #include "stdafx.h" -#include "FEKamensky.h" +#include "FEIsotropicLeeSacks.h" // define the material parameters -BEGIN_FECORE_CLASS(FEKamensky, FEElasticMaterial) +BEGIN_FECORE_CLASS(FEIsotropicLeeSacks, FEElasticMaterial) ADD_PARAMETER(m_c0, "c0"); ADD_PARAMETER(m_c1, "c1"); ADD_PARAMETER(m_c2, "c2"); @@ -36,7 +36,7 @@ BEGIN_FECORE_CLASS(FEKamensky, FEElasticMaterial) END_FECORE_CLASS(); //----------------------------------------------------------------------------- -FEKamensky::FEKamensky(FEModel* pfem) : FEElasticMaterial(pfem) +FEIsotropicLeeSacks::FEIsotropicLeeSacks(FEModel* pfem) : FEElasticMaterial(pfem) { m_c0 = 0.0; m_c1 = 0.0; @@ -47,7 +47,7 @@ FEKamensky::FEKamensky(FEModel* pfem) : FEElasticMaterial(pfem) //----------------------------------------------------------------------------- //! Calculates the strain energy density -double FEKamensky::StrainEnergyDensity(FEMaterialPoint& mp) +double FEIsotropicLeeSacks::StrainEnergyDensity(FEMaterialPoint& mp) { FEElasticMaterialPoint& pt = *mp.ExtractData(); @@ -72,7 +72,7 @@ double FEKamensky::StrainEnergyDensity(FEMaterialPoint& mp) //----------------------------------------------------------------------------- //! Calculates the deviatoric stress -mat3ds FEKamensky::Stress(FEMaterialPoint& mp) +mat3ds FEIsotropicLeeSacks::Stress(FEMaterialPoint& mp) { FEElasticMaterialPoint& pt = *mp.ExtractData(); @@ -96,7 +96,7 @@ mat3ds FEKamensky::Stress(FEMaterialPoint& mp) //----------------------------------------------------------------------------- //! Calculates the deviatoric tangent -tens4ds FEKamensky::Tangent(FEMaterialPoint& mp) +tens4ds FEIsotropicLeeSacks::Tangent(FEMaterialPoint& mp) { FEElasticMaterialPoint& pt = *mp.ExtractData(); diff --git a/FEBioMech/FEKamensky.h b/FEBioMech/FEIsotropicLeeSacks.h similarity index 95% rename from FEBioMech/FEKamensky.h rename to FEBioMech/FEIsotropicLeeSacks.h index 342cbbc89..7034a31c5 100644 --- a/FEBioMech/FEKamensky.h +++ b/FEBioMech/FEIsotropicLeeSacks.h @@ -26,10 +26,10 @@ SOFTWARE.*/ #pragma once #include "FEElasticMaterial.h" -class FEKamensky : public FEElasticMaterial +class FEIsotropicLeeSacks : public FEElasticMaterial { public: - FEKamensky(FEModel* pfem); + FEIsotropicLeeSacks(FEModel* pfem); //! calculate deviatoric stress at material point mat3ds Stress(FEMaterialPoint& pt) override; diff --git a/FEBioMech/FEKamenskyUncoupled.cpp b/FEBioMech/FEIsotropicLeeSacksUncoupled.cpp similarity index 89% rename from FEBioMech/FEKamenskyUncoupled.cpp rename to FEBioMech/FEIsotropicLeeSacksUncoupled.cpp index e54472d85..66d3dcf6c 100644 --- a/FEBioMech/FEKamenskyUncoupled.cpp +++ b/FEBioMech/FEIsotropicLeeSacksUncoupled.cpp @@ -24,10 +24,10 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ #include "stdafx.h" -#include "FEKamenskyUncoupled.h" +#include "FEIsotropicLeeSacksUncoupled.h" // define the material parameters -BEGIN_FECORE_CLASS(FEKamenskyUncoupled, FEUncoupledMaterial) +BEGIN_FECORE_CLASS(FEIsotropicLeeSacksUncoupled, FEUncoupledMaterial) ADD_PARAMETER(m_c0, "c0"); ADD_PARAMETER(m_c1, "c1"); ADD_PARAMETER(m_c2, "c2"); @@ -35,7 +35,7 @@ BEGIN_FECORE_CLASS(FEKamenskyUncoupled, FEUncoupledMaterial) END_FECORE_CLASS(); //----------------------------------------------------------------------------- -FEKamenskyUncoupled::FEKamenskyUncoupled(FEModel* pfem) : FEUncoupledMaterial(pfem) +FEIsotropicLeeSacksUncoupled::FEIsotropicLeeSacksUncoupled(FEModel* pfem) : FEUncoupledMaterial(pfem) { m_c0 = 0.0; m_c1 = 0.0; @@ -45,7 +45,7 @@ FEKamenskyUncoupled::FEKamenskyUncoupled(FEModel* pfem) : FEUncoupledMaterial(pf //----------------------------------------------------------------------------- //! Calculates the strain energy density -double FEKamenskyUncoupled::DevStrainEnergyDensity(FEMaterialPoint& mp) +double FEIsotropicLeeSacksUncoupled::DevStrainEnergyDensity(FEMaterialPoint& mp) { FEElasticMaterialPoint& pt = *mp.ExtractData(); @@ -65,7 +65,7 @@ double FEKamenskyUncoupled::DevStrainEnergyDensity(FEMaterialPoint& mp) //----------------------------------------------------------------------------- //! Calculates the deviatoric stress -mat3ds FEKamenskyUncoupled::DevStress(FEMaterialPoint& mp) +mat3ds FEIsotropicLeeSacksUncoupled::DevStress(FEMaterialPoint& mp) { FEElasticMaterialPoint& pt = *mp.ExtractData(); @@ -86,7 +86,7 @@ mat3ds FEKamenskyUncoupled::DevStress(FEMaterialPoint& mp) //----------------------------------------------------------------------------- //! Calculates the deviatoric tangent -tens4ds FEKamenskyUncoupled::DevTangent(FEMaterialPoint& mp) +tens4ds FEIsotropicLeeSacksUncoupled::DevTangent(FEMaterialPoint& mp) { FEElasticMaterialPoint& pt = *mp.ExtractData(); diff --git a/FEBioMech/FEKamenskyUncoupled.h b/FEBioMech/FEIsotropicLeeSacksUncoupled.h similarity index 94% rename from FEBioMech/FEKamenskyUncoupled.h rename to FEBioMech/FEIsotropicLeeSacksUncoupled.h index b5cd9bd6d..557008516 100644 --- a/FEBioMech/FEKamenskyUncoupled.h +++ b/FEBioMech/FEIsotropicLeeSacksUncoupled.h @@ -26,10 +26,10 @@ SOFTWARE.*/ #pragma once #include "FEUncoupledMaterial.h" -class FEKamenskyUncoupled : public FEUncoupledMaterial +class FEIsotropicLeeSacksUncoupled : public FEUncoupledMaterial { public: - FEKamenskyUncoupled(FEModel* pfem); + FEIsotropicLeeSacksUncoupled(FEModel* pfem); //! calculate deviatoric stress at material point mat3ds DevStress(FEMaterialPoint& pt) override; diff --git a/FEBioMech/FELungMaterial.cpp b/FEBioMech/FELungMaterial.cpp new file mode 100644 index 000000000..137bf2334 --- /dev/null +++ b/FEBioMech/FELungMaterial.cpp @@ -0,0 +1,121 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +#include "FELungMaterial.h" +#include + +BEGIN_FECORE_CLASS(FELungMaterial, FEElasticMaterial) + ADD_PARAMETER(m_E, FE_RANGE_GREATER(0.0), "E"); + ADD_PARAMETER(m_v, FE_RANGE_GREATER(0.0), "v"); + ADD_PARAMETER(m_c1, FE_RANGE_GREATER(0.0), "c1"); + ADD_PARAMETER(m_c3, FE_RANGE_GREATER(0.0), "c3"); + ADD_PARAMETER(m_d1, FE_RANGE_GREATER(0.0), "d1"); + ADD_PARAMETER(m_d3, FE_RANGE_GREATER(0.0), "d3"); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +FELungMaterial::FELungMaterial(FEModel* pfem) : FEElasticMaterial(pfem) +{ +} + +bool FELungMaterial::Init() +{ + if (FEElasticMaterial::Init() == false) return false; + + m_c = m_E/(4*(1+m_v)); + m_b = m_v/(1-2*m_v); + + return true; +} + +double FELungMaterial::StrainEnergyDensity(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + mat3ds B = pt.LeftCauchyGreen(); + + double I1 = B.tr(); + double I3 = B.det(); + + return m_c*(I1-3) + +m_c/m_b*(pow(I3, -m_b)-1) + +m_c1*pow((pow(I3, -1.0/3.0)*I1-3), m_d1) + +m_c3*pow((pow(I3, 1.0/3.0)-1), m_d3); +} + +mat3ds FELungMaterial::Stress(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + mat3ds B = pt.LeftCauchyGreen(); + + double I1 = B.tr(); + double I3 = B.det(); + + double J = pt.m_J; + + mat3dd I(1.0); + + mat3ds s = (2*m_c*B + - 2*m_c*pow(I3, -m_b)*I + + +2*m_c1*m_d1*pow(I3, -1.0/3.0)*pow(pow(I3, -1.0/3.0)*I1-3, m_d1-1)*(B-I1/3.0*I) + +2.0/3.0*m_c3*m_d3*pow(pow(I3, 1.0/3.0)-1, m_d3-1)*pow(I3,1.0/3.0)*I)/J; + + return s; +} + +tens4ds FELungMaterial::Tangent(FEMaterialPoint& mp) +{ + // As in the Stress function, we need the data from the FEElasticMaterialPoint + // class to calculate the tangent. + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // Get the deformation gradient and its determinant + double J = pt.m_J; + + mat3ds B = pt.LeftCauchyGreen(); + + double I1 = B.tr(); + double I3 = B.det(); + + // define identity tensor and some useful + // dyadic products of the identity tensor. + mat3dd I(1.0); + tens4ds IxI = dyad1s(I); + tens4ds I4 = dyad4s(I); + tens4ds bxI = dyad1s(B,I); + + + double term = m_c1*m_d1*pow(I3,-1.0/3.0)*pow(pow(I3,-1.0/3.0)*I1-3, m_d1-1); + + tens4ds c = (4*m_c*pow(I3, -m_b)*(m_b*IxI+I4) + -4.0/3.0*term*(bxI-I1/3.0*IxI) + +4*m_c1*m_d1*pow(I3,-2.0/3.0)*(m_d1-1)*pow(pow(I3,-1.0/3.0)*I1-3, m_d1-2)*(dyad1s(B)-I1/3.0*bxI+1.0/9.0*I1*I1*IxI) + +4.0/3.0*term*I1*I4 + +4.0/9.0*m_c3*m_d3*((m_d3-1)*pow(I3, 2.0/3.0)*pow(pow(I3,1.0/3.0)-1, m_d3-2)+pow(pow(I3,1.0/3.0)-1, m_d3-1)*pow(I3,1.0/3.0))*IxI + -4.0/3.0*m_c3*m_d3*pow(pow(I3,1.0/3.0)-1,m_d3-1)*pow(I3,1.0/3.0)*I4)/J; + + return c; +} diff --git a/FEBioMech/FELungMaterial.h b/FEBioMech/FELungMaterial.h new file mode 100644 index 000000000..4bab573bd --- /dev/null +++ b/FEBioMech/FELungMaterial.h @@ -0,0 +1,52 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +#include + +//---------------------------------------------------------------------------- +class FELungMaterial : public FEElasticMaterial +{ +public: + FELungMaterial(FEModel* pfem); + +private: + double m_c, m_c1, m_c3; + double m_d1, m_d3; + double m_b; + + double m_E, m_v; + +public: + virtual bool Init(); + + virtual double StrainEnergyDensity(FEMaterialPoint& pt); + + virtual mat3ds Stress(FEMaterialPoint& pt); + + virtual tens4ds Tangent(FEMaterialPoint& pt); + + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FEMassDamping.cpp b/FEBioMech/FEMassDamping.cpp index b7e54f877..b865f8f0c 100644 --- a/FEBioMech/FEMassDamping.cpp +++ b/FEBioMech/FEMassDamping.cpp @@ -40,7 +40,7 @@ FEMassDamping::FEMassDamping(FEModel* fem) : FEBodyForce(fem) //! calculate the body force at a material point vec3d FEMassDamping::force(FEMaterialPoint& mp) { - FEElasticMaterialPoint& ep = dynamic_cast(mp); + FEElasticMaterialPoint& ep = *mp.ExtractData(); return ep.m_v*m_C; } diff --git a/FEBioMech/FEMergedConstraint.cpp b/FEBioMech/FEMergedConstraint.cpp index 33a7b3d99..984f298a2 100644 --- a/FEBioMech/FEMergedConstraint.cpp +++ b/FEBioMech/FEMergedConstraint.cpp @@ -96,7 +96,7 @@ bool FEMergedConstraint::Merge(FEFacetSet* surf1, FEFacetSet* surf2, const vecto for (int j=0; jSetParentDof(dof, set1[i]); lc->AddChildDof(dof, set2[tag[i]], 1.0); diff --git a/FEBioMech/FENonlinearSpring.cpp b/FEBioMech/FENonlinearSpring.cpp new file mode 100644 index 000000000..031a997b4 --- /dev/null +++ b/FEBioMech/FENonlinearSpring.cpp @@ -0,0 +1,114 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#include "FENonlinearSpring.h" + +BEGIN_FECORE_CLASS(FENonlinearSpringMaterial, FEDiscreteElasticMaterial) + ADD_PARAMETER(m_scale, "scale"); + ADD_PARAMETER(m_measure, "measure", 0, "elongation\0strain\0stretch\0"); + ADD_PROPERTY(m_F, "force"); +END_FECORE_CLASS(); + + +FENonlinearSpringMaterial::FENonlinearSpringMaterial(FEModel* pfem) : FEDiscreteElasticMaterial(pfem) +{ + m_scale = 1.0; + m_measure = 0; + m_F = nullptr; +} + +vec3d FENonlinearSpringMaterial::Force(FEDiscreteMaterialPoint& mp) +{ + vec3d t = mp.m_drt; t.unit(); + + // calculate spring lenghts + double L0 = mp.m_dr0.norm(); + double Lt = mp.m_drt.norm(); + double DL = Lt - L0; + + // evaluate the deformation measure + double s = 0.0; + switch (m_measure) + { + case 0: s = DL; break; + case 1: s = DL / L0; break; + case 2: s = Lt / L0; break; + default: + break; + } + + // get the force + double F = m_scale * m_F->value(s); + + // evaluate the spring force + return t*F; +} + +mat3d FENonlinearSpringMaterial::Stiffness(FEDiscreteMaterialPoint& mp) +{ + vec3d e = mp.m_drt; e.unit(); + + // calculate spring lengths + double L0 = mp.m_dr0.norm(); + double Lt = mp.m_drt.norm(); + double DL = Lt - L0; + + // evaluate the deformation measure + double s = 0.0, ds = 1.0;; + switch (m_measure) + { + case 0: s = DL; break; + case 1: s = DL / L0; ds = 1.0 / L0; break; + case 2: s = Lt / L0; ds = 1.0 / L0; break; + default: + break; + } + + // get the force + double F = m_scale * m_F->value(s); + + // evaluate the stiffness + double E = m_scale * m_F->derive(s) * ds; + + if (Lt == 0) { F = 0; Lt = 1; e = vec3d(1, 1, 1); } + + mat3d A; A.zero(); + A[0][0] = ((E - F / Lt) * e.x * e.x + F / Lt); + A[1][1] = ((E - F / Lt) * e.y * e.y + F / Lt); + A[2][2] = ((E - F / Lt) * e.z * e.z + F / Lt); + + A[0][1] = A[1][0] = (E - F / Lt) * e.x * e.y; + A[1][2] = A[2][1] = (E - F / Lt) * e.y * e.z; + A[0][2] = A[2][0] = (E - F / Lt) * e.x * e.z; + + return A; +} + +double FENonlinearSpringMaterial::StrainEnergy(FEDiscreteMaterialPoint& mp) +{ + // TODO: implement this + assert(false); + return 0.0; +} diff --git a/FEBioMech/FENonlinearSpring.h b/FEBioMech/FENonlinearSpring.h new file mode 100644 index 000000000..e3110bee2 --- /dev/null +++ b/FEBioMech/FENonlinearSpring.h @@ -0,0 +1,50 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#pragma once +#include "FEDiscreteElasticMaterial.h" +#include +#include "febiomech_api.h" + +//----------------------------------------------------------------------------- +//! This class implements a non-linear spring where users can choose what +//! deformation measure to use in the force curve. +class FEBIOMECH_API FENonlinearSpringMaterial : public FEDiscreteElasticMaterial +{ +public: + FENonlinearSpringMaterial(FEModel* pfem); + + vec3d Force(FEDiscreteMaterialPoint& mp) override; + mat3d Stiffness(FEDiscreteMaterialPoint& mp) override; + double StrainEnergy(FEDiscreteMaterialPoint& mp) override; + +private: + FEFunction1D* m_F; //!< force-displacement function + double m_scale; //!< scale factor for force + int m_measure; //!< deformation measure + + // declare the parameter list + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FEPeriodicBoundary.cpp b/FEBioMech/FEPeriodicBoundary.cpp index 7325c71e7..9b8c22815 100644 --- a/FEBioMech/FEPeriodicBoundary.cpp +++ b/FEBioMech/FEPeriodicBoundary.cpp @@ -159,6 +159,10 @@ FEPeriodicBoundary::FEPeriodicBoundary(FEModel* pfem) : FEContactInterface(pfem) m_off = vec3d(0,0,0); m_naugmin = 0; + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMech/FEPeriodicLinearConstraint.cpp b/FEBioMech/FEPeriodicLinearConstraint.cpp index ddd66dd1d..78e30a337 100644 --- a/FEBioMech/FEPeriodicLinearConstraint.cpp +++ b/FEBioMech/FEPeriodicLinearConstraint.cpp @@ -272,7 +272,7 @@ void addLinearConstraint(FEModel& fem, int parent, int child, int nodeA, int nod // do one constraint for x, y, z for (int j = 0; j<3; ++j) { - FELinearConstraint* lc = new FELinearConstraint(&fem); + FELinearConstraint* lc = fecore_alloc(FELinearConstraint, &fem); lc->SetParentDof(j, parent); lc->AddChildDof(j, child, 1.0); diff --git a/FEBioMech/FEPeriodicSurfaceConstraint.cpp b/FEBioMech/FEPeriodicSurfaceConstraint.cpp index 355fe5291..34497b43a 100644 --- a/FEBioMech/FEPeriodicSurfaceConstraint.cpp +++ b/FEBioMech/FEPeriodicSurfaceConstraint.cpp @@ -133,6 +133,10 @@ FEPeriodicSurfaceConstraint::FEPeriodicSurfaceConstraint(FEModel* pfem) : FECont m_dofU.AddVariable(FEBioMech::GetVariableName(FEBioMech::DISPLACEMENT)); + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMech/FEPolynomalHyperElastic.cpp b/FEBioMech/FEPolynomalHyperElastic.cpp new file mode 100644 index 000000000..caeb9a15a --- /dev/null +++ b/FEBioMech/FEPolynomalHyperElastic.cpp @@ -0,0 +1,226 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#include "stdafx.h" +#include "FEPolynomialHyperElastic.h" + +//----------------------------------------------------------------------------- +// define the material parameters +BEGIN_FECORE_CLASS(FEPolynomialHyperElastic, FEElasticMaterial) +// ADD_PARAMETER(m_c[0][0], "c00"); // should always be zero + ADD_PARAMETER(m_c[0][1], "c01"); + ADD_PARAMETER(m_c[0][2], "c02"); + ADD_PARAMETER(m_c[1][0], "c10"); + ADD_PARAMETER(m_c[1][1], "c11"); + ADD_PARAMETER(m_c[1][2], "c12"); + ADD_PARAMETER(m_c[2][0], "c20"); + ADD_PARAMETER(m_c[2][1], "c21"); + ADD_PARAMETER(m_c[2][2], "c22"); + ADD_PARAMETER(m_D1, "D1"); + ADD_PARAMETER(m_D2, "D2"); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +FEPolynomialHyperElastic::FEPolynomialHyperElastic(FEModel* pfem) : FEElasticMaterial(pfem) +{ + m_D1 = m_D2 = 0.0; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) m_c[i][j] = 0.0; +} + +//----------------------------------------------------------------------------- +//! Calculate the deviatoric stress +mat3ds FEPolynomialHyperElastic::Stress(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // determinant of deformation gradient + double J = pt.m_J; + + // calculate deviatoric left Cauchy-Green tensor + mat3ds B = pt.DevLeftCauchyGreen(); + + // calculate square of B + mat3ds B2 = B.sqr(); + + // Invariants of B (= invariants of C) + // Note that these are the invariants of Btilde, not of B! + double I1 = B.tr(); + double I2 = 0.5 * (I1 * I1 - B2.tr()); + + // get material parameters + double c[3][3] = { 0 }; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + c[i][j] = m_c[i][j](mp); + c[0][0] = 0.0; + + // --- put strain energy derivatives here --- + // Wi = dW/dIi + double I1p1 = I1 - 3.0; + double I1p2 = I1p1 * I1p1; + double I2p1 = I2 - 3.0; + double I2p2 = I2p1 * I2p1; + + double W1 = c[1][0] + c[1][1] * I2p1 + c[1][2] * I2p2 + 2.0 * I1p1 * (c[2][0] + c[2][1] * I2p1 + c[2][2] * I2p2); + double W2 = c[0][1] + c[1][1] * I1p1 + c[2][1] * I1p2 + 2.0 * I2p1 * (c[0][2] + c[1][2] * I1p1 + c[2][2] * I1p2); + // --- + + // calculate T = F*dW/dC*Ft + // T = F*dW/dC*Ft + mat3ds T = B * (W1 + W2 * I1) - B2 * W2; + + mat3ds devs = T.dev() * (2.0 / J); + + pt.m_p = UJ(pt.m_J); + + return mat3dd(pt.m_p) + devs; +} + +//----------------------------------------------------------------------------- +//! Calculate the deviatoric tangent +tens4ds FEPolynomialHyperElastic::Tangent(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // determinant of deformation gradient + double J = pt.m_J; + double Ji = 1.0 / J; + + // calculate deviatoric left Cauchy-Green tensor: B = F*Ft + mat3ds B = pt.DevLeftCauchyGreen(); + + // calculate square of B + mat3ds B2 = B.sqr(); + + // Invariants of B (= invariants of C) + double I1 = B.tr(); + double I2 = 0.5 * (I1 * I1 - B2.tr()); + + // get material parameters + double c[3][3] = { 0 }; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + c[i][j] = m_c[i][j](mp); + c[0][0] = 0.0; + + // --- TODO: put strain energy derivatives here --- + // Wi = dW/dIi + double I1p1 = I1 - 3.0; + double I1p2 = I1p1 * I1p1; + double I2p1 = I2 - 3.0; + double I2p2 = I2p1 * I2p1; + + double W1 = c[1][0] + c[1][1] * I2p1 + c[1][2] * I2p2 + 2.0 * I1p1 * (c[2][0] + c[2][1] * I2p1 + c[2][2] * I2p2); + double W2 = c[0][1] + c[1][1] * I1p1 + c[2][1] * I1p2 + 2.0 * I2p1 * (c[0][2] + c[1][2] * I1p1 + c[2][2] * I1p2); + + double W11 = 2.0 * (c[2][0] + c[2][1] * I2p1 + c[2][2] * I2p2); + double W22 = 2.0 * (c[0][2] + c[1][2] * I1p1 + c[2][2] * I1p2); + + double W12 = c[1][1] + 2.0 * c[1][2] * I2p1 + 2.0 * c[2][1] * I1p1 + 4.0 * c[2][2]*I1p1 * I2p1; + double W21 = W12; + // --- + + // define some helper constants + double g1 = W11 + 2.0 * W12 * I1 + W22 * I1 * I1 + W2; + double g2 = W12 + I1 * W22; + double I2b = B2.tr(); + + // calculate dWdC:C + double WC = W1 * I1 + 2 * W2 * I2; + + // deviatoric cauchy-stress + mat3ds T = B * (W1 + W2 * I1) - B2 * W2; + mat3ds devs = T.dev() * (2.0 / J); + + // Identity tensor + mat3ds I(1, 1, 1, 0, 0, 0); + + tens4ds IxI = dyad1s(I); + tens4ds I4 = dyad4s(I); + tens4ds BxB = dyad1s(B); + tens4ds B2xB2 = dyad1s(B2); + tens4ds B4 = dyad4s(B); + + // calculate chat + tens4ds ch = BxB * g1 - dyad1s(B, B2) * g2 + B2xB2 * W22 - B4 * W2; + + // calculate I:ch:I + double IchI = W11*I1*I1 + 2.0*W12*I1*I2 + 2.0*W21*I1*I2 + 4.0*W22*I2*I2 + 2.0*W2*I2; + + // 1:ch + mat3ds Ich = B * (g1*I1-g2*I2b) + B2 * (W22*I2b - g2*I1 - W2); + + tens4ds cw = ch - dyad1s(Ich, I) * (1.0 / 3.0) + IxI * (1.0 / 9.0 * IchI); + + tens4ds cs = dyad1s(devs, I)* (-2.0 / 3.0) + (I4 - IxI / 3.0) * (4.0 / 3.0 * Ji * WC); + tens4ds ce = cs + cw*(4.0 * Ji); + + return ce + (IxI - I4 * 2) * pt.m_p + IxI * (UJJ(pt.m_J) * pt.m_J); +} + +//----------------------------------------------------------------------------- +//! calculate deviatoric strain energy density +double FEPolynomialHyperElastic::StrainEnergyDensity(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // get material parameters + double c[3][3] = { 0 }; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + c[i][j] = m_c[i][j](mp); + + // calculate deviatoric left Cauchy-Green tensor + mat3ds B = pt.DevLeftCauchyGreen(); + mat3ds B2 = B.sqr(); + + // Invariants of B (= invariants of C) + // Note that these are the invariants of Btilde, not of B! + double I1 = B.tr(); + double I2 = 0.5 * (I1 * I1 - B2.tr()); + + double W = 0.0; + for (int i = 0; i < 3; ++i) + for (int j = 0; j < 3; ++j) + W += c[i][j] * pow(I1 - 3, i) * pow(I2 - 3, j); + + return U(pt.m_J) + W; +} + +double FEPolynomialHyperElastic::U(double J) +{ + return m_D1 * pow(J - 1.0, 2.0) + m_D2 * pow(J - 1.0, 4.0); +} + +double FEPolynomialHyperElastic::UJ(double J) +{ + return 2.0*m_D1 * (J - 1.0) + 4.0*m_D2 * pow(J - 1.0, 3.0); +} + +double FEPolynomialHyperElastic::UJJ(double J) +{ + return 2.0*m_D1 + 12.0*m_D2 * pow(J - 1.0, 2.0); +} diff --git a/FEBioMech/FEPolynomialHyperElastic.h b/FEBioMech/FEPolynomialHyperElastic.h new file mode 100644 index 000000000..b90b1eefb --- /dev/null +++ b/FEBioMech/FEPolynomialHyperElastic.h @@ -0,0 +1,61 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + + + +#pragma once +#include "FEElasticMaterial.h" +#include + +//----------------------------------------------------------------------------- +//! Polynomial Hyperelastic +class FEPolynomialHyperElastic : public FEElasticMaterial +{ +public: + FEPolynomialHyperElastic(FEModel* pfem); + +public: + FEParamDouble m_c[3][3]; + double m_D1, m_D2; + +public: + //! calculate deviatoric stress at material point + mat3ds Stress(FEMaterialPoint& pt) override; + + //! calculate deviatoric tangent stiffness at material point + tens4ds Tangent(FEMaterialPoint& pt) override; + + //! calculate deviatoric strain energy density + double StrainEnergyDensity(FEMaterialPoint& mp) override; + +private: + double U(double J); + double UJ(double J); + double UJJ(double J); + + // declare the parameter list + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FEPreStrainElastic.cpp b/FEBioMech/FEPreStrainElastic.cpp index 9f3c2ab3f..0ea9ba998 100644 --- a/FEBioMech/FEPreStrainElastic.cpp +++ b/FEBioMech/FEPreStrainElastic.cpp @@ -64,6 +64,18 @@ FEPrestrainElastic::FEPrestrainElastic(FEModel* pfem) : FEElasticMaterial(pfem) m_Fp = nullptr; } +//----------------------------------------------------------------------------- +// evaluate density in (pre-strained) reference configuration +double FEPrestrainElastic::Density(FEMaterialPoint& mp) +{ + double d0 = FEElasticMaterial::Density(mp); + + mat3d Fp = PrestrainGradient(mp); + double Jp = Fp.det(); + + return d0 / Jp; +} + //----------------------------------------------------------------------------- //! Create material point data for this material FEMaterialPoint* FEPrestrainElastic::CreateMaterialPointData() diff --git a/FEBioMech/FEPreStrainElastic.h b/FEBioMech/FEPreStrainElastic.h index a211b6df5..865bf260d 100644 --- a/FEBioMech/FEPreStrainElastic.h +++ b/FEBioMech/FEPreStrainElastic.h @@ -111,6 +111,9 @@ class FEPrestrainElastic : public FEElasticMaterial, public FEPrestrainMaterial //! return the elastic material FEElasticMaterial* GetElasticMaterial() override { return m_mat; } + // evaluate density in (pre-strained) reference configuration + double Density(FEMaterialPoint& mp) override; + public: //! Cauchy stress mat3ds Stress(FEMaterialPoint& mp) override; diff --git a/FEBioMech/FEPreStrainUncoupledElastic.cpp b/FEBioMech/FEPreStrainUncoupledElastic.cpp index 2ee1d2553..a81ad9d80 100644 --- a/FEBioMech/FEPreStrainUncoupledElastic.cpp +++ b/FEBioMech/FEPreStrainUncoupledElastic.cpp @@ -56,6 +56,18 @@ FEMaterialPoint* FEPreStrainUncoupledElastic::CreateMaterialPointData() } } +//----------------------------------------------------------------------------- +//! calculate (pre-strained) density +double FEPreStrainUncoupledElastic::Density(FEMaterialPoint& mp) +{ + double d0 = FEElasticMaterial::Density(mp); + + mat3d Fp = PrestrainGradient(mp); + double Jp = Fp.det(); + + return d0 / Jp; +} + //----------------------------------------------------------------------------- mat3d FEPreStrainUncoupledElastic::PrestrainGradient(FEMaterialPoint& mp) { diff --git a/FEBioMech/FEPreStrainUncoupledElastic.h b/FEBioMech/FEPreStrainUncoupledElastic.h index 38714df26..caa2fba4c 100644 --- a/FEBioMech/FEPreStrainUncoupledElastic.h +++ b/FEBioMech/FEPreStrainUncoupledElastic.h @@ -45,6 +45,9 @@ class FEPreStrainUncoupledElastic : public FEUncoupledMaterial, public FEPrestra //! return the elastic material property FEElasticMaterial* GetElasticMaterial() override { return m_mat; } + //! calculate (pre-strained) density + double Density(FEMaterialPoint& mp) override; + public: //! Cauchy stress mat3ds DevStress(FEMaterialPoint& mp) override; diff --git a/FEBioMech/FERVEDamageMaterial.cpp b/FEBioMech/FERVEDamageMaterial.cpp index 26469bc37..b55fea06c 100644 --- a/FEBioMech/FERVEDamageMaterial.cpp +++ b/FEBioMech/FERVEDamageMaterial.cpp @@ -35,20 +35,20 @@ SOFTWARE.*/ //----------------------------------------------------------------------------- BEGIN_FECORE_CLASS(FERVEDamageMaterial, FEElasticMaterial) -// set material properties -ADD_PROPERTY(m_pRVE , "viscoelastic"); -ADD_PROPERTY(m_pDamg, "damage"); -ADD_PROPERTY(m_pCrit, "criterion"); + // set material properties + ADD_PROPERTY(m_pRVE , "viscoelastic"); + ADD_PROPERTY(m_pDamg, "damage"); + ADD_PROPERTY(m_pCrit, "criterion"); END_FECORE_CLASS(); //----------------------------------------------------------------------------- //! Constructor. FERVEDamageMaterial::FERVEDamageMaterial(FEModel* pfem) : FEElasticMaterial(pfem) { - m_pRVE = 0; - m_pBase = 0; - m_pDamg = 0; - m_pCrit = 0; + m_pRVE = nullptr; + m_pBase = nullptr; + m_pDamg = nullptr; + m_pCrit = nullptr; } //----------------------------------------------------------------------------- @@ -64,7 +64,22 @@ bool FERVEDamageMaterial::Init() m_pBase = m_pRVE->GetBaseMaterial(); - return FEElasticMaterial::Init(); + return m_pRVE->Init(); +} + +//----------------------------------------------------------------------------- +FEMaterialPoint* FERVEDamageMaterial::CreateMaterialPointData() +{ + FEReactiveViscoelasticMaterialPoint* pt = new FEReactiveViscoelasticMaterialPoint(); + // create damage materal point for strong bond (base) material + FEDamageMaterialPoint* pbase = new FEDamageMaterialPoint(m_pRVE->GetBaseMaterial()->CreateMaterialPointData()); + pt->AddMaterialPoint(pbase); + + // create materal point for weak bond material + FEReactiveVEMaterialPoint* pbond = new FEReactiveVEMaterialPoint(m_pRVE->GetBondMaterial()->CreateMaterialPointData()); + pt->AddMaterialPoint(pbond); + + return pt; } //----------------------------------------------------------------------------- @@ -109,19 +124,50 @@ double FERVEDamageMaterial::StrainEnergyDensity(FEMaterialPoint& pt) return sed*(1-d); } +//----------------------------------------------------------------------------- +//! calculate strong bond strain energy density at material point +double FERVEDamageMaterial::StrongBondSED(FEMaterialPoint& pt) +{ + // evaluate the damage + double d = Damage(pt); + + // evaluate the strain energy density + double sed = m_pRVE->StrongBondSED(pt); + + // return damaged sed + return sed*(1-d); +} + +//----------------------------------------------------------------------------- +//! calculate weak bond strain energy density at material point +double FERVEDamageMaterial::WeakBondSED(FEMaterialPoint& pt) +{ + // evaluate the damage + double d = Damage(pt); + + // evaluate the strain energy density + double sed = m_pRVE->WeakBondSED(pt); + + // return damaged sed + return sed*(1-d); +} + //----------------------------------------------------------------------------- //! calculate damage at material point double FERVEDamageMaterial::Damage(FEMaterialPoint& pt) { - // get the damage material point data - FEDamageMaterialPoint& pd = *pt.ExtractData(); + // get the reactive viscoelastic base material point + FEMaterialPoint* pb = m_pRVE->GetBaseMaterialPoint(pt); + + // get the damage material point data from its base material point + FEDamageMaterialPoint& pd = *pb->ExtractData(); // evaluate the trial value of the damage criterion // this must be done before evaluating the damage - pd.m_Etrial = m_pCrit->DamageCriterion(pt); + pd.m_Etrial = m_pCrit->DamageCriterion(*pb); // evaluate and set the damage - double d = m_pDamg->Damage(pt); + double d = m_pDamg->Damage(*pb); pd.m_D = d; return d; diff --git a/FEBioMech/FERVEDamageMaterial.h b/FEBioMech/FERVEDamageMaterial.h index a3173bc4b..fb783aff2 100644 --- a/FEBioMech/FERVEDamageMaterial.h +++ b/FEBioMech/FERVEDamageMaterial.h @@ -57,14 +57,21 @@ class FERVEDamageMaterial : public FEElasticMaterial bool Init() override; // returns a pointer to a new material point object - FEMaterialPoint* CreateMaterialPointData() override - { - return new FEDamageMaterialPoint(m_pRVE->CreateMaterialPointData()); - } + FEMaterialPoint* CreateMaterialPointData() override; // get the elastic material FEElasticMaterial* GetElasticMaterial() override { return m_pBase; } + //! specialized material points + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override + { + m_pRVE->UpdateSpecializedMaterialPoints(mp, tp); + } + +public: + double StrongBondSED(FEMaterialPoint& pt) override; + double WeakBondSED(FEMaterialPoint& pt) override; + public: FEReactiveViscoelasticMaterial* m_pRVE; // reactive viscoelastic material FEElasticMaterial* m_pBase; // base strong bond material diff --git a/FEBioMech/FEReactiveFatigue.cpp b/FEBioMech/FEReactiveFatigue.cpp new file mode 100644 index 000000000..7efe5fb7e --- /dev/null +++ b/FEBioMech/FEReactiveFatigue.cpp @@ -0,0 +1,206 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FEReactiveFatigue.h" +#include "FEDamageCriterion.h" +#include "FEDamageCDF.h" +#include "FEUncoupledMaterial.h" +#include +#include +#include +#include +#include + +//////////////////////////// FATIGUE MATERIAL ///////////////////////////////// +//----------------------------------------------------------------------------- +// define the material parameters +BEGIN_FECORE_CLASS(FEReactiveFatigue, FEElasticMaterial) + ADD_PARAMETER(m_k0 , FE_RANGE_GREATER_OR_EQUAL(0.0), "k0" ); + ADD_PARAMETER(m_beta , FE_RANGE_GREATER_OR_EQUAL(0.0), "beta"); + + // set material properties + ADD_PROPERTY(m_pBase, "elastic"); + ADD_PROPERTY(m_pIdmg, "elastic_damage"); + ADD_PROPERTY(m_pFdmg, "fatigue_damage"); + ADD_PROPERTY(m_pIcrt, "elastic_criterion"); + ADD_PROPERTY(m_pFcrt, "fatigue_criterion"); + +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +//! Constructor. +FEReactiveFatigue::FEReactiveFatigue(FEModel* pfem) : FEElasticMaterial(pfem) +{ + m_pBase = 0; + m_pIdmg = 0; + m_pFdmg = 0; + m_pIcrt = 0; + m_pFcrt = 0; +} + +//----------------------------------------------------------------------------- +//! Initialization. +bool FEReactiveFatigue::Init() +{ + FEUncoupledMaterial* m_pMat = dynamic_cast((FEElasticMaterial*)m_pBase); + if (m_pMat != nullptr) + { + feLogError("Elastic material should not be of type uncoupled"); + return false; + } + + return FEElasticMaterial::Init(); +} + +//----------------------------------------------------------------------------- +//! calculate stress at material point +mat3ds FEReactiveFatigue::Stress(FEMaterialPoint& pt) +{ + // evaluate the damage + double d = Damage(pt); + + // evaluate the stress + mat3ds s = m_pBase->Stress(pt); + + // return damaged stress + return s*(1-d); +} + +//----------------------------------------------------------------------------- +//! calculate tangent stiffness at material point +tens4ds FEReactiveFatigue::Tangent(FEMaterialPoint& pt) +{ + // evaluate the damage + double d = Damage(pt); + + // evaluate the tangent + tens4ds c = m_pBase->Tangent(pt); + + // return damaged tangent + return c*(1-d); +} + +//----------------------------------------------------------------------------- +//! calculate strain energy density at material point +double FEReactiveFatigue::StrainEnergyDensity(FEMaterialPoint& pt) +{ + // evaluate the damage + double d = Damage(pt); + + // evaluate the strain energy density + double sed = m_pBase->StrainEnergyDensity(pt); + + // return damaged sed + return sed*(1-d); +} + +//----------------------------------------------------------------------------- +//! calculate damage at material point +double FEReactiveFatigue::Damage(FEMaterialPoint& pt) +{ + // get the reactive fatigue material point data + FEReactiveFatigueMaterialPoint& pd = *pt.ExtractData(); + + return pd.m_D; +} + +//----------------------------------------------------------------------------- +// update fatigue material point at each iteration +void FEReactiveFatigue::UpdateSpecializedMaterialPoints(FEMaterialPoint& pt, const FETimeInfo& tp) +{ + double dt = tp.timeIncrement; + + // get the fatigue material point data + FEReactiveFatigueMaterialPoint& pd = *pt.ExtractData(); + + // get damage criterion for intact bonds at current time + pd.m_Xitrl = m_pIcrt->DamageCriterion(pt); + if (pd.m_Xitrl > pd.m_Ximax) + pd.m_Fit = m_pIdmg->cdf(pd.m_Xitrl); + else + pd.m_Fit = pd.m_Fip; + + // get damage criterion for fatigue bonds at current time + double Xftrl = m_pFcrt->DamageCriterion(pt); + for (int ig=0; ig < pd.m_fb.size(); ++ig) { + if (Xftrl > pd.m_fb[ig].m_Xfmax) { + pd.m_fb[ig].m_Xftrl = Xftrl; + pd.m_fb[ig].m_Fft = m_pFdmg->cdf(pd.m_fb[ig].m_Xftrl); + } + else + pd.m_fb[ig].m_Fft = pd.m_fb[ig].m_Ffp; + } + + // evaluate time derivative of intact bond criterion + pd.m_aXit = (pd.m_Xitrl - pd.m_Xip)/dt; + + // solve for bond mass fractions iteratively + double eps = 1e-6; + int maxit = 10; + double wbi = 0; + int iter = 0; + do { + wbi = pd.m_wbt; + // evaluate mass supply from fatigue of intact bonds + double dwf = m_k0*dt/2*(pow(fabs(pd.m_aXit)*pd.m_wbt,m_beta)*pd.m_wit+pow(fabs(pd.m_aXip)*pd.m_wbp,m_beta)*pd.m_wip); + double Fdwf = m_pFdmg->cdf(Xftrl); + + // kinetics of intact bonds + pd.m_wit = (pd.m_Fip < 1) ? pd.m_wip*(1-pd.m_Fit)/(1-pd.m_Fip) - dwf : pd.m_wip; + pd.m_wbt = (pd.m_Fip < 1) ? pd.m_wbp + pd.m_wip*(pd.m_Fit - pd.m_Fip)/(1-pd.m_Fip) : pd.m_wbp; + // add or update new generation + if ((pd.m_fb.size() == 0) || pd.m_fb.back().m_time < tp.currentTime) { + // add generation of fatigued bonds + FatigueBond fb; + fb.m_Fft = Fdwf; + fb.m_wfp = dwf; + fb.m_Xftrl = Xftrl; + fb.m_time = tp.currentTime; + pd.m_fb.push_back(fb); + } + else { + pd.m_fb.back().m_Fft = Fdwf; + pd.m_fb.back().m_wfp = dwf; + pd.m_fb.back().m_Xftrl = Xftrl; + } + // damage kinetics of fatigued bonds + for (int ig=0; ig < pd.m_fb.size(); ++ig) { + pd.m_fb[ig].m_wft = (pd.m_fb[ig].m_Ffp < 1) ? pd.m_fb[ig].m_wfp*(1-pd.m_fb[ig].m_Fft)/(1-pd.m_fb[ig].m_Ffp) : 0; + pd.m_wbt += (pd.m_fb[ig].m_Ffp < 1) ? pd.m_fb[ig].m_wfp*(pd.m_fb[ig].m_Fft-pd.m_fb[ig].m_Ffp)/(1-pd.m_fb[ig].m_Ffp) : pd.m_fb[ig].m_wfp; + } + // roundoff corrections + if (pd.m_wit < 0) pd.m_wit = 0; + if (pd.m_wbt > 1) pd.m_wbt = 1; + // evaluate fatigue bond fraction + pd.m_wft = 0; + for (int ig=0; ig < pd.m_fb.size(); ++ig) pd.m_wft += pd.m_fb[ig].m_wft; + } while ((pd.m_wbt > 0) && (pd.m_wbt < 1) && (fabs(wbi-pd.m_wbt) > eps*pd.m_wbt) && (++iterCreateMaterialPointData()); + } + + // get the elastic material + FEElasticMaterial* GetElasticMaterial() override { return m_pBase; } + + // update fatigue material point at each iteration + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; + +public: + + FEElasticMaterial* m_pBase; // base elastic material + FEDamageCDF* m_pIdmg; // damage model for intact bonds + FEDamageCDF* m_pFdmg; // damage model for fatigued bonds + FEDamageCriterion* m_pIcrt; // damage criterion + FEDamageCriterion* m_pFcrt; // fatigue criterion + +public: + double m_k0; // reaction rate for fatigue reaction + double m_beta; // power exponent for fatigue reaction + + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FEReactiveFatigueMaterialPoint.cpp b/FEBioMech/FEReactiveFatigueMaterialPoint.cpp new file mode 100644 index 000000000..759fe910f --- /dev/null +++ b/FEBioMech/FEReactiveFatigueMaterialPoint.cpp @@ -0,0 +1,247 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "FEReactiveFatigueMaterialPoint.h" +#include + +////////////////////// FATIGUE BOND ///////////////////////////////// +FatigueBond::FatigueBond() +{ + m_wft = m_wfp = m_Xfmax = m_Xftrl = m_Fft = m_Ffp = m_time = 0; + m_erase = false; +} + +FatigueBond::FatigueBond(const FatigueBond& fb) +{ + m_wft = fb.m_wft; + m_wfp = fb.m_wfp; + m_Xfmax = fb.m_Xfmax; + m_Xftrl = fb.m_Xftrl; + m_Fft = fb.m_Fft; + m_Ffp = fb.m_Ffp; + m_time = fb.m_time; + m_erase = fb.m_erase; +} + +FatigueBond::FatigueBond(FatigueBond& fb) +{ + m_wft = fb.m_wft; + m_wfp = fb.m_wfp; + m_Xfmax = fb.m_Xfmax; + m_Xftrl = fb.m_Xftrl; + m_Fft = fb.m_Fft; + m_Ffp = fb.m_Ffp; + m_time = fb.m_time; + m_erase = fb.m_erase; +} + +void FatigueBond::Update() +{ + m_wfp = m_wft; + m_Ffp = m_Fft; + if (m_Xftrl > m_Xfmax) m_Xfmax = m_Xftrl; +} + +////////////////////// FATIGUE MATERIAL POINT ///////////////////////////////// +//----------------------------------------------------------------------------- +// default constructor +FEReactiveFatigueMaterialPoint::FEReactiveFatigueMaterialPoint(FEMaterialPoint *pt) : FEMaterialPoint(pt) +{ + // get the reactive fatigue material point data + FEReactiveFatigueMaterialPoint& rfmp = *pt->ExtractData(); + + m_D = rfmp.m_D; + m_wit = rfmp.m_wit; + m_wip = rfmp.m_wip; + m_Ximax = rfmp.m_Ximax; + m_Xitrl = rfmp.m_Xitrl; + m_Xip = rfmp.m_Xip; + m_aXit = rfmp.m_aXit; + m_aXip = rfmp.m_aXip; + m_Fit = rfmp.m_Fit; + m_Fip = rfmp.m_Fip; + m_wbt = rfmp.m_wbt; + m_wbp = rfmp.m_wbp; + m_wft = rfmp.m_wft; + + m_fb.clear(); + for (int ig=0; igm_pNext = m_pNext->Copy(); + return pt; +} + +//----------------------------------------------------------------------------- +void FEReactiveFatigueMaterialPoint::Init() +{ + FEMaterialPoint::Init(); + + // intialize total damate + m_D = 0; + + // initialize intact bond fraction to 1 + m_wip = m_wit = 1.0; + + // initialize intact damage criterion + m_Ximax = m_Xitrl = m_Xip = 0; + m_Fip = m_Fit = 0; + + // initialize broken and fatigue bond fraction to 0 + m_wbp = m_wbt = m_wft = 0; + + // clear the fatigue bond structure + m_fb.clear(); +} + +//----------------------------------------------------------------------------- +void FEReactiveFatigueMaterialPoint::Update(const FETimeInfo& timeInfo) +{ + FEMaterialPoint::Update(timeInfo); + + // let's check overlapping generations of fatigued bonds + if (m_fb.size() > 1) { + for (int ig=0; ig < m_fb.size() - 1; ++ig) { + double Xfmax = max(m_fb[ig].m_Xftrl,m_fb[ig].m_Xfmax); + if (Xfmax <= m_fb.back().m_Xftrl) { + m_fb.back().m_wft += m_fb[ig].m_wft; + m_fb[ig].m_erase = true; + } + } + } + // cull generations that have been marked for erasure + std::deque::iterator it = m_fb.begin(); + while (it != m_fb.end()) { + if (it->m_erase) it = m_fb.erase(it); + else ++it; + } + + // update intact and damage bonds + m_wip = m_wit; + m_wbp = m_wbt; + + // update damage response for intact bonds + if (m_Xitrl > m_Ximax) m_Ximax = m_Xitrl; + m_Xip = m_Xitrl; + m_aXip = m_aXit; + m_Fip = m_Fit; + + // update damage response for fatigues bonds + for (int ig=0; ig 1) m_D = 1; +} + +//----------------------------------------------------------------------------- +void FEReactiveFatigueMaterialPoint::Serialize(DumpStream& ar) +{ + FEMaterialPoint::Serialize(ar); + ar & m_D; + ar & m_wit & m_wip & m_Ximax & m_Xitrl & m_Xip & m_aXit & m_aXip & m_Fit & m_Fip; + ar & m_wbt & m_wbp & m_wft; + + // handle deques and boolean + if (ar.IsSaving()) { + int n = (int)m_fb.size(); + ar << n; + for (int i=0; i> n; + m_fb.clear(); + for (int i=0; i> fb.m_wft >> fb.m_wfp; + ar >> fb.m_Xfmax >> fb.m_Xftrl; + ar >> fb.m_Fft >> fb.m_Ffp; + ar >> fb.m_time >> fb.m_erase; + m_fb.push_back(fb); + } + } +} diff --git a/FEBioMech/FEReactiveFatigueMaterialPoint.h b/FEBioMech/FEReactiveFatigueMaterialPoint.h new file mode 100644 index 000000000..acbfe0d64 --- /dev/null +++ b/FEBioMech/FEReactiveFatigueMaterialPoint.h @@ -0,0 +1,100 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#pragma once +#include +#include + +//----------------------------------------------------------------------------- +// structure for fatigue bonds +class FatigueBond +{ +public: + // constructor + FatigueBond(); + + // copy constructor + FatigueBond(const FatigueBond& fb); + FatigueBond(FatigueBond& fb); + // update + void Update(); + +public: + double m_wft; //!< fatigued bond fraction at current time + double m_wfp; //!< fatigued bond fraction at previous time + double m_Xfmax; //!< max damage criterion for fatigued bonds + double m_Xftrl; //!< trial value of Xfmax + double m_Fft; //!< fatigue bond damage CDF at current time + double m_Ffp; //!< fatigue bond damage CDF at previous time + double m_time; //!< fatigue bond generation time + bool m_erase; //!< flag for erasing a generation +}; + +//----------------------------------------------------------------------------- +// Define a material point that stores the fatigue and damage variables. +class FEReactiveFatigueMaterialPoint : public FEMaterialPoint +{ +public: + // default constructor + FEReactiveFatigueMaterialPoint(FEMaterialPoint *pt); + // copy constructors + FEReactiveFatigueMaterialPoint(const FEReactiveFatigueMaterialPoint& rfmp); + FEReactiveFatigueMaterialPoint(FEReactiveFatigueMaterialPoint& rfmp); + + FEMaterialPoint* Copy(); + + void Init(); + void Update(const FETimeInfo& timeInfo); + + void Serialize(DumpStream& ar); + +public: + double m_D; //!< damage (0 = no damage, 1 = complete damage) + + double m_wit; //!< intact bond mass fraction at current time + double m_wip; //!< intact bond mass fraction at previous time + + double m_Ximax; //!< max damage criterion for intact bonds + double m_Xitrl; //!< trial value of Ximax + double m_Xip; //!< Xi at previous time + + double m_aXit; //!< rate of change of Xi at current time + double m_aXip; //!< rate of change of Xi at previous time + + double m_Fit; //!< intact bond damage CDF at current time + double m_Fip; //!< intact bond damage CDF at previous time + + double m_wbt; //!< broken (damaged) bond fraction at current time + double m_wbp; //!< broken (damaged) bond fraction at previous time + + double m_wft; //!< fatigue bond fraction at current time + + + deque m_fb; //!< generations of fatigued bonds +}; + diff --git a/FEBioMech/FEReactivePlasticity.cpp b/FEBioMech/FEReactivePlasticity.cpp index abf0ceb71..6e7eed09b 100644 --- a/FEBioMech/FEReactivePlasticity.cpp +++ b/FEBioMech/FEReactivePlasticity.cpp @@ -73,6 +73,15 @@ bool FEReactivePlasticity::Init() return FEElasticMaterial::Init(); } +//----------------------------------------------------------------------------- +//! serialiation +void FEReactivePlasticity::Serialize(DumpStream& ar) +{ + FEElasticMaterial::Serialize(ar); + ar & m_n & m_isochrc & m_rtol; + ar & Ky & w; +} + //----------------------------------------------------------------------------- //! Create material point data for this material FEMaterialPoint* FEReactivePlasticity::CreateMaterialPointData() diff --git a/FEBioMech/FEReactivePlasticity.h b/FEBioMech/FEReactivePlasticity.h index 14f72d01a..fa5935df8 100644 --- a/FEBioMech/FEReactivePlasticity.h +++ b/FEBioMech/FEReactivePlasticity.h @@ -43,6 +43,9 @@ class FEReactivePlasticity : public FEElasticMaterial public: //! data initialization and checking bool Init() override; + + //! serialiation + void Serialize(DumpStream& ar) override; //! calculate stress at material point mat3ds Stress(FEMaterialPoint& pt) override; diff --git a/FEBioMech/FEReactiveVEMaterialPoint.cpp b/FEBioMech/FEReactiveVEMaterialPoint.cpp index 5833dc421..0afe33f74 100644 --- a/FEBioMech/FEReactiveVEMaterialPoint.cpp +++ b/FEBioMech/FEReactiveVEMaterialPoint.cpp @@ -83,10 +83,21 @@ void FEReactiveVEMaterialPoint::Init() m_v.clear(); m_f.clear(); + m_Et = 0; + m_Em = 0; + m_wv.clear(); + // don't forget to initialize the base class FEMaterialPoint::Init(); } +void FEReactiveVEMaterialPoint::Update(const FETimeInfo& timeInfo) +{ + FEMaterialPoint::Update(timeInfo); + + m_Em = max(m_Em, m_Et); +} + //----------------------------------------------------------------------------- //! Serialize data to the archive void FEReactiveVEMaterialPoint::Serialize(DumpStream& ar) diff --git a/FEBioMech/FEReactiveVEMaterialPoint.h b/FEBioMech/FEReactiveVEMaterialPoint.h index cc733787f..e40d3db39 100644 --- a/FEBioMech/FEReactiveVEMaterialPoint.h +++ b/FEBioMech/FEReactiveVEMaterialPoint.h @@ -67,6 +67,9 @@ class FEReactiveVEMaterialPoint : public FEMaterialPoint //! Initialize material point data void Init() override; + + //! Update material point data + void Update(const FETimeInfo& timeInfo) override; //! Serialize data to archive void Serialize(DumpStream& ar) override; @@ -77,4 +80,10 @@ class FEReactiveVEMaterialPoint : public FEMaterialPoint deque m_Jv; //!< determinant of Uv (store for efficiency) deque m_v; //!< time tv when generation starts breaking deque m_f; //!< mass fraction when generation starts breaking + +public: + // weak bond recruitment parameters + double m_Et; //!< trial strain value at time t + double m_Em; //!< max strain value up to time t + deque m_wv; //!< total mass fraction of weak bonds }; diff --git a/FEBioMech/FEReactiveViscoelastic.cpp b/FEBioMech/FEReactiveViscoelastic.cpp index 0cd059734..4bb5b97d0 100644 --- a/FEBioMech/FEReactiveViscoelastic.cpp +++ b/FEBioMech/FEReactiveViscoelastic.cpp @@ -53,6 +53,7 @@ BEGIN_FECORE_CLASS(FEReactiveViscoelasticMaterial, FEElasticMaterial) ADD_PROPERTY(m_pBase, "elastic"); ADD_PROPERTY(m_pBond, "bond"); ADD_PROPERTY(m_pRelx, "relaxation"); + ADD_PROPERTY(m_pWCDF, "recruitment", FEProperty::Optional); END_FECORE_CLASS(); @@ -70,7 +71,10 @@ FEReactiveViscoelasticMaterial::FEReactiveViscoelasticMaterial(FEModel* pfem) : m_pBase = nullptr; m_pBond = nullptr; m_pRelx = nullptr; + m_pWCDF = nullptr; + m_pDmg = nullptr; + m_pFtg = nullptr; } //----------------------------------------------------------------------------- @@ -92,6 +96,10 @@ bool FEReactiveViscoelasticMaterial::Init() if (!m_pBase->Init()) return false; if (!m_pBond->Init()) return false; if (!m_pRelx->Init()) return false; + if (m_pWCDF && !m_pWCDF->Init()) return false; + + m_pDmg = dynamic_cast(m_pBase); + m_pFtg = dynamic_cast(m_pBase); return FEElasticMaterial::Init(); } @@ -245,24 +253,24 @@ double FEReactiveViscoelasticMaterial::BreakingBondMassFraction(FEMaterialPoint& // current time double time = GetFEModel()->GetTime().currentTime; - double tv = time - pt.m_v[ig]; + double dtv = time - pt.m_v[ig]; switch (m_btype) { case 1: { - if (tv >= 0) - w = pt.m_f[ig]*m_pRelx->Relaxation(mp, tv, D); + if (dtv >= 0) + w = pt.m_f[ig]*m_pRelx->Relaxation(mp, dtv, D); } break; case 2: { if (ig == 0) { - w = m_pRelx->Relaxation(mp, tv, D); + w = m_pRelx->Relaxation(mp, dtv, D); } else { - double tu = time - pt.m_v[ig-1]; - w = m_pRelx->Relaxation(mp, tv, D) - m_pRelx->Relaxation(mp, tu, D); + double dtu = time - pt.m_v[ig-1]; + w = m_pRelx->Relaxation(mp, dtv, D) - m_pRelx->Relaxation(mp, dtu, D); } } break; @@ -271,7 +279,7 @@ double FEReactiveViscoelasticMaterial::BreakingBondMassFraction(FEMaterialPoint& break; } - assert((w >= 0) && (w <= 1)); + assert(w >= 0); return w; } @@ -295,7 +303,7 @@ double FEReactiveViscoelasticMaterial::ReformingBondMassFraction(FEMaterialPoint // get current number of generations int ng = (int)pt.m_Uv.size(); - double w = 1; + double f = (!pt.m_wv.empty()) ? pt.m_wv.back() : 1; for (int ig=0; ig= 0) && (w <= 1)); + assert(f >= 0); // return the bond mass fraction of the reforming generation - return w; + return f; } //----------------------------------------------------------------------------- @@ -402,7 +410,7 @@ mat3ds FEReactiveViscoelasticMaterial::StressWeakBonds(FEMaterialPoint& mp) mat3ds FEReactiveViscoelasticMaterial::Stress(FEMaterialPoint& mp) { mat3ds s = StressStrongBonds(mp); - s+= StressWeakBonds(mp); + s+= StressWeakBonds(mp)*(1-Damage(mp)); // return the total Cauchy stress return s; @@ -488,7 +496,7 @@ tens4ds FEReactiveViscoelasticMaterial::TangentWeakBonds(FEMaterialPoint& mp) tens4ds FEReactiveViscoelasticMaterial::Tangent(FEMaterialPoint& mp) { tens4ds c = TangentStrongBonds(mp); - c += TangentWeakBonds(mp); + c += TangentWeakBonds(mp)*(1-Damage(mp)); // return the total tangent return c; @@ -577,7 +585,7 @@ double FEReactiveViscoelasticMaterial::WeakBondSED(FEMaterialPoint& mp) double FEReactiveViscoelasticMaterial::StrainEnergyDensity(FEMaterialPoint& mp) { double sed = StrongBondSED(mp); - sed += WeakBondSED(mp); + sed += WeakBondSED(mp)*(1-Damage(mp)); // return the total strain energy density return sed; @@ -620,10 +628,12 @@ void FEReactiveViscoelasticMaterial::CullGenerations(FEMaterialPoint& mp) pt.m_Uv[1] = (pt.m_Uv[0]*w0 + pt.m_Uv[1]*w1)/(w0+w1); pt.m_Jv[1] = pt.m_Uv[1].det(); pt.m_f[1] = (w0*pt.m_f[0] + w1*pt.m_f[1])/(w0+w1); + pt.m_wv[1] = (w0*pt.m_wv[0] + w1*pt.m_wv[1])/(w0+w1); pt.m_Uv.pop_front(); pt.m_Jv.pop_front(); pt.m_v.pop_front(); pt.m_f.pop_front(); + pt.m_wv.pop_front(); } // restore safe copy of deformation gradient @@ -637,8 +647,13 @@ void FEReactiveViscoelasticMaterial::CullGenerations(FEMaterialPoint& mp) //! Update specialized material points void FEReactiveViscoelasticMaterial::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) { + FEMaterialPoint& sb = *GetBaseMaterialPoint(mp); FEMaterialPoint& wb = *GetBondMaterialPoint(mp); + // start by updating specialized material points of base and bond materials + m_pBase->UpdateSpecializedMaterialPoints(sb, tp); + m_pBond->UpdateSpecializedMaterialPoints(wb, tp); + // get the reactive viscoelastic point data FEReactiveVEMaterialPoint& pt = *wb.ExtractData(); @@ -656,6 +671,14 @@ void FEReactiveViscoelasticMaterial::UpdateSpecializedMaterialPoints(FEMaterialP pt.m_v.push_back(tp.currentTime); pt.m_Uv.push_back(Uv); pt.m_Jv.push_back(Jv); + if (m_pWCDF) { + pt.m_Et = ScalarStrain(pt); + if (pt.m_Et > pt.m_Em) + pt.m_wv.push_back(m_pWCDF->cdf(pt.m_Et)); + else + pt.m_wv.push_back(m_pWCDF->cdf(pt.m_Em)); + } + else pt.m_wv.push_back(1); double f = (!pt.m_v.empty()) ? ReformingBondMassFraction(wb) : 1; pt.m_f.push_back(f); CullGenerations(wb); @@ -665,6 +688,13 @@ void FEReactiveViscoelasticMaterial::UpdateSpecializedMaterialPoints(FEMaterialP else if (pt.m_v.back() == tp.currentTime) { pt.m_Uv.back() = Uv; pt.m_Jv.back() = Jv; + if (m_pWCDF) { + pt.m_Et = ScalarStrain(pt); + if (pt.m_Et > pt.m_Em) + pt.m_wv.back() = m_pWCDF->cdf(pt.m_Et); + else + pt.m_wv.back() = m_pWCDF->cdf(pt.m_Em); + } pt.m_f.back() = ReformingBondMassFraction(wb); } } @@ -681,3 +711,54 @@ int FEReactiveViscoelasticMaterial::RVEGenerations(FEMaterialPoint& mp) // return the bond mass fraction of the reforming generation return (int)pt.m_v.size(); } + +//----------------------------------------------------------------------------- +//! evaluate trigger strain +double FEReactiveViscoelasticMaterial::ScalarStrain(FEMaterialPoint& mp) +{ + double d; + // get the elastic point data + FEElasticMaterialPoint& ep = *mp.ExtractData(); + + switch (m_ttype) { + case 0: + { + // evaluate the Lagrangian strain + mat3ds E = ep.Strain(); + + d = E.norm(); + } + break; + case 1: + { + // distortional strain + // evaluate spatial Hencky (logarithmic) strain + mat3ds h = ep.LeftHencky(); + + // evaluate distortion magnitude (always positive) + d = (h.dev()).norm(); + } + break; + case 2: + { + // dilatational strain + d = fabs(log(ep.m_J)); + } + break; + + default: + d = 0; + break; + } + + return d; +} + +//----------------------------------------------------------------------------- +double FEReactiveViscoelasticMaterial::Damage(FEMaterialPoint& mp) +{ + double D = 0; + if (m_pDmg) D = m_pDmg->Damage(*GetBaseMaterialPoint(mp)); + else if (m_pFtg) D = m_pFtg->Damage(*GetBaseMaterialPoint(mp)); + return D; +} diff --git a/FEBioMech/FEReactiveViscoelastic.h b/FEBioMech/FEReactiveViscoelastic.h index 5bb85b8de..7b67f3f98 100644 --- a/FEBioMech/FEReactiveViscoelastic.h +++ b/FEBioMech/FEReactiveViscoelastic.h @@ -30,6 +30,8 @@ SOFTWARE.*/ #include "FEElasticMaterial.h" #include "FEBondRelaxation.h" #include "FEReactiveVEMaterialPoint.h" +#include "FEDamageMaterial.h" +#include "FEReactiveFatigue.h" #include //----------------------------------------------------------------------------- @@ -99,11 +101,20 @@ class FEReactiveViscoelasticMaterial : public FEElasticMaterial //! get bond material point FEMaterialPoint* GetBondMaterialPoint(FEMaterialPoint& mp); + //! evaluate scalar strain measure (same type as trigger strain for bond breaking) + double ScalarStrain(FEMaterialPoint& mp); + private: FEElasticMaterial* m_pBase; //!< pointer to elastic solid material for strong bonds FEElasticMaterial* m_pBond; //!< pointer to elastic solid material for reactive bonds FEBondRelaxation* m_pRelx; //!< pointer to bond relaxation material for reactive bonds - + FEDamageCDF* m_pWCDF; //!< pointer to weak bond recruitment CDF + +private: + FEDamageMaterial* m_pDmg; //!< pointer to base material if it is a FEDamageMaterial + FEReactiveFatigue* m_pFtg; //!< pointer to base material if it is a FEReactiveFatigue + double Damage(FEMaterialPoint& mp); //!< return damage in this material + public: double m_wmin; //!< minimum value of relaxation int m_btype; //!< bond kinetics type diff --git a/FEBioMech/FEShenoyMaterial.cpp b/FEBioMech/FEShenoyMaterial.cpp new file mode 100644 index 000000000..49b116908 --- /dev/null +++ b/FEBioMech/FEShenoyMaterial.cpp @@ -0,0 +1,165 @@ +// ShenoyMaterial.cpp : Defines the exported functions for the DLL application. +// + +#include "stdafx.h" +#include "FEShenoyMaterial.h" + +BEGIN_FECORE_CLASS(FEShenoyMaterial, FEElasticMaterial) + ADD_PARAMETER(m_mu, FE_RANGE_GREATER_OR_EQUAL(0.0), "mu"); + ADD_PARAMETER(m_k , FE_RANGE_GREATER_OR_EQUAL(0.0), "k"); + ADD_PARAMETER(m_Ef, FE_RANGE_GREATER_OR_EQUAL(0.0), "Ef"); + ADD_PARAMETER(m_lamc, FE_RANGE_GREATER_OR_EQUAL(1.0), "lam_c"); + ADD_PARAMETER(m_lamt, FE_RANGE_NOT_EQUAL(0.0), "lam_t"); + ADD_PARAMETER(m_n , FE_RANGE_GREATER_OR_EQUAL(1.0), "n"); + ADD_PARAMETER(m_m , FE_RANGE_GREATER_OR_EQUAL(1.0), "m"); +END_FECORE_CLASS(); + +FEShenoyMaterial::FEShenoyMaterial(FEModel* fem) : FEElasticMaterial(fem) +{ + m_mu = 0.0; + m_k = 0.0; + m_Ef = 0.0; + m_lamc = 1.0; + m_lamt = 0.0; + m_n = 5; + m_m = 1; +} + +double FEShenoyMaterial::fiberStress(double lam) +{ + double lam1 = m_lamc - m_lamt * 0.5; + double lam2 = m_lamc + m_lamt * 0.5; + + if (lam < lam1) return 0.0; + else if (lam > lam2) + { + return m_Ef*((lam2 - lam1) / (m_n + 1.0) + (pow(1.0 + lam - lam2, m_m + 1.0) - 1.0) / (m_m + 1.0)); + } + else + { + return m_Ef*(pow((lam - lam1)/(lam2 - lam1), m_n)*(lam - lam1)) / (m_n + 1); + } +} + +double FEShenoyMaterial::fiberTangent(double lam) +{ + double lam1 = m_lamc - m_lamt * 0.5; + double lam2 = m_lamc + m_lamt * 0.5; + + if (lam < lam1) return 0.0; + else if (lam > lam2) + { + return m_Ef*pow(1.0 + lam - lam2, m_m); + } + else + { + return m_Ef*pow((lam - lam1) / (lam2 - lam1), m_n); + } +} + +mat3ds FEShenoyMaterial::Stress(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + mat3ds B = pt.LeftCauchyGreen(); + double J = pt.m_J; + double Jm23 = pow(J, -2.0 / 3.0); + + mat3ds Bbar = B*Jm23; + mat3dd I(1.0); + + double lam[3] = {0}; + vec3d n[3]; + B.eigen(lam, n); + lam[0] = (lam[0] >= 0.0 ? sqrt(lam[0]) : 0.0); + lam[1] = (lam[1] >= 0.0 ? sqrt(lam[1]) : 0.0); + lam[2] = (lam[2] >= 0.0 ? sqrt(lam[2]) : 0.0); + + // isotropic component of the stress + mat3ds s_b = Bbar.dev()*(m_mu / J) + I*(m_k * (J - 1.0)); + + // anisotropic (fiber) contribution of the stress + double df[3] = {0}; + df[0] = fiberStress(lam[0]); + df[1] = fiberStress(lam[1]); + df[2] = fiberStress(lam[2]); + + mat3ds s_f = (dyad(n[0])*(df[0] * lam[0]) + dyad(n[1])*(df[1] * lam[1]) + dyad(n[2])*(df[2] * lam[2])) / J; + + // add them together + mat3ds s = s_b + s_f; + + // and done + return s; +} + +tens4ds FEShenoyMaterial::Tangent(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + mat3ds B = pt.LeftCauchyGreen(); + double J = pt.m_J; + double Jm23 = pow(J, -2.0 / 3.0); + + mat3ds Bbar = B*Jm23; + mat3dd I(1.0); + + double lam[3] = { 0 }; + vec3d n[3]; + B.eigen(lam, n); + lam[0] = (lam[0] >= 0.0 ? sqrt(lam[0]) : 0.0); + lam[1] = (lam[1] >= 0.0 ? sqrt(lam[1]) : 0.0); + lam[2] = (lam[2] >= 0.0 ? sqrt(lam[2]) : 0.0); + + double I1bar = Bbar.tr(); + + tens4ds IxI = dyad1s(I); + tens4ds I4 = dyad4s(I); + + tens4ds c_b = (I4*(2.0*I1bar / 3.0) - (dyad1s(Bbar, I))*(2.0 / 3.0) + IxI*(I1bar*2.0 / 9.0))*(m_mu / J) \ + + (IxI*(2.0*J - 1) - I4*(2.0*(J - 1.0)))*m_k; + + double df[3] = {0}, ddf[3] = {0}, sf[3] = {0}; + df[0] = fiberStress(lam[0]); + df[1] = fiberStress(lam[1]); + df[2] = fiberStress(lam[2]); + + ddf[0] = fiberTangent(lam[0]); + ddf[1] = fiberTangent(lam[1]); + ddf[2] = fiberTangent(lam[2]); + + sf[0] = lam[0] * df[0] / J; + sf[1] = lam[1] * df[1] / J; + sf[2] = lam[2] * df[2] / J; + + tens4ds c_f; c_f.zero(); + for (int a=0; a<3; ++a) + { + c_f += dyad1s(dyad(n[a]))*(lam[a]*(lam[a]*ddf[a] - df[a])/J); + } + + int p[][2] = {{0,1},{1,2},{0,2}}; + + for (int i=0; i < 3; ++i) + { + int a = p[i][0]; + int b = p[i][1]; + + double g = 0.0; + if (fabs(lam[a] - lam[b]) <= 1e-10) + { + g = 0.5*lam[a]*lam[a]*ddf[a] / J - sf[a]; + } + else + { + g = (sf[a]*lam[b]*lam[b] - sf[b]*lam[a]*lam[a])/(lam[a]*lam[a] - lam[b]*lam[b]); + } + + mat3ds Nab = dyads(n[a], n[b]); + c_f += dyad1s(Nab)*(g); + } + + tens4ds c = c_b + c_f; + + return c; +} diff --git a/FEBioMech/FEShenoyMaterial.h b/FEBioMech/FEShenoyMaterial.h new file mode 100644 index 000000000..93b04d734 --- /dev/null +++ b/FEBioMech/FEShenoyMaterial.h @@ -0,0 +1,31 @@ +#pragma once +#include + +// This plugin implements the constitutive model by +// Wang et al. (Biophysical Journal, 107, 2014, pp:2592 - 2603). +// This novel material proposes a mechanism for long-range force transmission in +// fibrous matrices enabled by tension-driven alignment of fibers. +class FEShenoyMaterial : public FEElasticMaterial +{ +public: + FEShenoyMaterial(FEModel* fem); + + mat3ds Stress(FEMaterialPoint& mp); + + tens4ds Tangent(FEMaterialPoint& mp); + +private: + double fiberStress(double lam); + double fiberTangent(double lam); + +private: + double m_mu; + double m_k; + double m_Ef; + double m_lamc; + double m_lamt; + double m_n; + double m_m; + + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FESlidingElasticInterface.cpp b/FEBioMech/FESlidingElasticInterface.cpp index 51a4bca64..61508e797 100644 --- a/FEBioMech/FESlidingElasticInterface.cpp +++ b/FEBioMech/FESlidingElasticInterface.cpp @@ -90,18 +90,16 @@ void FESlidingElasticSurface::Data::Init() void FESlidingElasticSurface::Data::Serialize(DumpStream& ar) { FEContactMaterialPoint::Serialize(ar); - ar & m_gap; ar & m_dg; - ar & m_nu; + ar & m_Lmd; + ar & m_epsn; + ar & m_Lmt; + ar & m_nu; ar & m_s1; + ar & m_tr; ar & m_rs; ar & m_rsp; - ar & m_Lmt; - ar & m_Lmd; - ar & m_epsn; - ar & m_Ln; ar & m_bstick; - ar & m_tr; } //----------------------------------------------------------------------------- @@ -314,6 +312,10 @@ FESlidingElasticInterface::FESlidingElasticInterface(FEModel* pfem) : FEContactI m_bflipm = m_bflips = false; m_bshellbm = m_bshellbs = false; + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMech/FESlidingInterface.cpp b/FEBioMech/FESlidingInterface.cpp index bd67c6e16..dbd9df071 100644 --- a/FEBioMech/FESlidingInterface.cpp +++ b/FEBioMech/FESlidingInterface.cpp @@ -54,12 +54,26 @@ void FESlidingSurface::FESlidingPoint::Serialize(DumpStream& ar) { FEContactMaterialPoint::Serialize(ar); - ar & m_gap & m_nu & m_eps & m_off; + ar & m_nu & m_eps & m_off; ar & m_rs & m_rsp; - ar & m_Lm & m_Lt & m_Ln; + ar & m_Lm & m_Lt; ar & m_M; } +void FESlidingSurface::FESlidingPoint::Init() +{ + FEContactMaterialPoint::Init(); + m_gap = 0.0; + m_nu = vec3d(0, 0, 0); + m_rs = vec2d(0, 0); + m_rsp = vec2d(0, 0); + m_Lm = 0.0; + m_M.zero(); + m_Lt = vec2d(0, 0); + m_off = 0.0; + m_eps = 1.0; +} + //----------------------------------------------------------------------------- // Define sliding interface parameters BEGIN_FECORE_CLASS(FESlidingInterface, FEContactInterface) @@ -81,6 +95,9 @@ BEGIN_FECORE_CLASS(FESlidingInterface, FEContactInterface) ADD_PARAMETER(m_bupdtpen , "update_penalty"); END_FECORE_CLASS(); +//----------------------------------------------------------------------------- +FESlidingSurface::FESlidingSurface(FEModel* pfem) : FEContactSurface(pfem) {} + //----------------------------------------------------------------------------- //! build the matrix profile for use in the stiffness matrix void FESlidingInterface::BuildMatrixProfile(FEGlobalMatrix& K) @@ -179,6 +196,11 @@ bool FESlidingSurface::Init() // allocate integration point data m_data.resize(nn); + for (int i = 0; i < nn; ++i) + { + FESlidingPoint& d = m_data[i]; + d.Init(); + } // we calculate the gap offset values // This value is used to take the shell thickness into account @@ -407,6 +429,10 @@ FESlidingInterface::FESlidingInterface(FEModel* pfem) : FEContactInterface(pfem) m_btwo_pass = false; // don't use two-pass m_sradius = 0; // no search radius limitation + // set parents + m_ms.SetContactInterface(this); + m_ss.SetContactInterface(this); + // set the siblings m_ms.SetSibling(&m_ss); m_ss.SetSibling(&m_ms); diff --git a/FEBioMech/FESlidingInterface.h b/FEBioMech/FESlidingInterface.h index 0bcd830f1..8238a9f60 100644 --- a/FEBioMech/FESlidingInterface.h +++ b/FEBioMech/FESlidingInterface.h @@ -42,6 +42,8 @@ class FEBIOMECH_API FESlidingSurface : public FEContactSurface void Serialize(DumpStream& ar) override; + void Init() override; + public: vec3d m_nu; //!< secondary surface normal at primary surface node vec2d m_rs; //!< natural coordinates of primary surface projection on secondary surface element @@ -55,7 +57,7 @@ class FEBIOMECH_API FESlidingSurface : public FEContactSurface public: //! constructor - FESlidingSurface(FEModel* pfem) : FEContactSurface(pfem) {} + FESlidingSurface(FEModel* pfem); //! Initializes data structures bool Init(); diff --git a/FEBioMech/FESpringMaterial.cpp b/FEBioMech/FESpringMaterial.cpp index 729a1c2ac..f63aa7122 100644 --- a/FEBioMech/FESpringMaterial.cpp +++ b/FEBioMech/FESpringMaterial.cpp @@ -126,35 +126,6 @@ double FETensionOnlyLinearSpring::strainEnergy(double dl) if(dl >= 0) return m_E*dl*dl/2; else return 0; } -//----------------------------------------------------------------------------- -// FENonLinearSpring -//----------------------------------------------------------------------------- - -// define the material parameters -BEGIN_FECORE_CLASS(FENonLinearSpring, FESpringMaterial) - ADD_PROPERTY(m_F, "force"); -END_FECORE_CLASS(); - -FENonLinearSpring::FENonLinearSpring(FEModel* pfem) : FESpringMaterial(pfem) -{ - m_F = nullptr; -} - -double FENonLinearSpring::force(double dl) -{ - return m_F->value(dl); -} - -double FENonLinearSpring::stiffness(double dl) -{ - return m_F->derive(dl); -} - -double FENonLinearSpring::strainEnergy(double dl) -{ - return m_F->integrate(0, dl); -} - //----------------------------------------------------------------------------- // FEExperimentalSpring //----------------------------------------------------------------------------- diff --git a/FEBioMech/FESpringMaterial.h b/FEBioMech/FESpringMaterial.h index 71ceec7f0..fafbd5c6e 100644 --- a/FEBioMech/FESpringMaterial.h +++ b/FEBioMech/FESpringMaterial.h @@ -81,24 +81,6 @@ class FEBIOMECH_API FETensionOnlyLinearSpring : public FESpringMaterial DECLARE_FECORE_CLASS(); }; -//----------------------------------------------------------------------------- -//! general purpose nonlinear spring -class FEBIOMECH_API FENonLinearSpring : public FESpringMaterial -{ -public: - FENonLinearSpring(FEModel* pfem); - - double force (double dl) override; - double stiffness(double dl) override; - double strainEnergy(double dl) override; - -public: - FEFunction1D* m_F; //!< force-displacement function - - // declare the parameter list - DECLARE_FECORE_CLASS(); -}; - //----------------------------------------------------------------------------- class FEBIOMECH_API FEExperimentalSpring : public FESpringMaterial { diff --git a/FEBioMech/FEStickyInterface.cpp b/FEBioMech/FEStickyInterface.cpp index d1b307863..951567ee6 100644 --- a/FEBioMech/FEStickyInterface.cpp +++ b/FEBioMech/FEStickyInterface.cpp @@ -125,6 +125,10 @@ FEStickyInterface::FEStickyInterface(FEModel* pfem) : FEContactInterface(pfem), static int count = 1; SetID(count++); + // set parents + ss.SetContactInterface(this); + ms.SetContactInterface(this); + // define sibling relationships ss.SetSibling(&ms); ms.SetSibling(&ss); diff --git a/FEBioMech/FESurfaceForceUniform.cpp b/FEBioMech/FESurfaceForceUniform.cpp new file mode 100644 index 000000000..b7c48bb12 --- /dev/null +++ b/FEBioMech/FESurfaceForceUniform.cpp @@ -0,0 +1,117 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FESurfaceForceUniform.h" +#include "FEBioMech.h" +#include + +//============================================================================= +BEGIN_FECORE_CLASS(FESurfaceForceUniform, FESurfaceLoad) + ADD_PARAMETER(m_scale , "scale"); + ADD_PARAMETER(m_force , "force"); + ADD_PARAMETER(m_bshellb , "shell_bottom"); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +//! constructor +FESurfaceForceUniform::FESurfaceForceUniform(FEModel* pfem) : FESurfaceLoad(pfem) +{ + m_scale = 1.0; + m_force = m_traction = vec3d(0, 0, 0); + m_bshellb = false; +} + +//----------------------------------------------------------------------------- +//! allocate storage +void FESurfaceForceUniform::SetSurface(FESurface* ps) +{ + FESurfaceLoad::SetSurface(ps); +} + +//----------------------------------------------------------------------------- +// initialization +bool FESurfaceForceUniform::Init() +{ + // get the degrees of freedom + m_dof.Clear(); + if (m_bshellb == false) + { + m_dof.AddVariable(FEBioMech::GetVariableName(FEBioMech::DISPLACEMENT)); + } + else + { + m_dof.AddVariable(FEBioMech::GetVariableName(FEBioMech::SHELL_DISPLACEMENT)); + } + if (m_dof.IsEmpty()) return false; + + if (FESurfaceLoad::Init() == false) return false; + + // evaluate uniform traction based on applied force + FESurface& surf = GetSurface(); + surf.SetShellBottom(m_bshellb); + double area = 0; + for (int i=0; i& val) { + + // evaluate traction at this material point + vec3d t = m_traction*m_scale; + if (load->m_bshellb) t = -t; + + double J = (pt.dxr ^ pt.dxs).norm(); + + double H_u = dof_a.shape; + + val[0] = H_u * t.x*J; + val[1] = H_u * t.y*J; + val[2] = H_u * t.z*J; + }); +} + +//----------------------------------------------------------------------------- +void FESurfaceForceUniform::StiffnessMatrix(FELinearSystem& LS, const FETimeInfo& tp) +{ + // Nothing to do here. + // TODO: I think if the linear flag is false, I do need to evaluate a stiffness. +} diff --git a/FEBioMech/FESurfaceForceUniform.h b/FEBioMech/FESurfaceForceUniform.h new file mode 100644 index 000000000..506792df9 --- /dev/null +++ b/FEBioMech/FESurfaceForceUniform.h @@ -0,0 +1,64 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#pragma once +#include +#include + +//----------------------------------------------------------------------------- +//! FESurfaceForceUniform is a surface that has a constant (deformation independant) +//! force on it, distributed as a uniform traction +//! +class FESurfaceForceUniform : public FESurfaceLoad +{ +public: + //! constructor + FESurfaceForceUniform(FEModel* pfem); + + //! Set the surface to apply the load to + void SetSurface(FESurface* ps) override; + + // initialization + bool Init() override; + +public: + //! calculate contact forces + void LoadVector(FEGlobalVector& R, const FETimeInfo& tp) override; + + //! calculate stiffness + void StiffnessMatrix(FELinearSystem& LS, const FETimeInfo& tp) override; + +protected: + double m_scale; //!< scale factor for traction + vec3d m_force; //!< vector force + bool m_bshellb; //!< flag to apply force on shell bottom +private: + vec3d m_traction; //!< calculated uniform traction + + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FESymmetryPlane.cpp b/FEBioMech/FESymmetryPlane.cpp index 841ccef94..cb0fd7768 100644 --- a/FEBioMech/FESymmetryPlane.cpp +++ b/FEBioMech/FESymmetryPlane.cpp @@ -63,14 +63,15 @@ void FESymmetryPlane::Activate() // create linear constraints // for a symmetry plane the constraint on (ux, uy, uz) is // nx*ux + ny*uy + nz*uz = 0 - for (int i=0; im_dof.push_back(dof); } - pLC->m_dof.push_back(dof); + // add the linear constraint to the system + add(pLC); } - // add the linear constraint to the system - add(pLC); } - } - - // for nodes that belong to shells, also constraint the shell bottom face displacements - for (int i=0; im_dof.push_back(dof); } - pLC->m_dof.push_back(dof); + // add the linear constraint to the system + add(pLC); } - // add the linear constraint to the system - add(pLC); } + + m_binit = true; } } diff --git a/FEBioMech/FETiedElasticInterface.cpp b/FEBioMech/FETiedElasticInterface.cpp index 67bc59af8..e0631f99c 100644 --- a/FEBioMech/FETiedElasticInterface.cpp +++ b/FEBioMech/FETiedElasticInterface.cpp @@ -76,6 +76,18 @@ void FETiedElasticSurface::Data::Serialize(DumpStream& ar) ar & m_tr; } +void FETiedElasticSurface::Data::Init() +{ + FEContactMaterialPoint::Init(); + m_Gap = vec3d(0, 0, 0); + m_dg = vec3d(0, 0, 0); + m_nu = vec3d(0, 0, 0); + m_rs = vec2d(0, 0); + m_Lmd = vec3d(0, 0, 0); + m_tr = vec3d(0, 0, 0); + m_epsn = 1.0; +} + //----------------------------------------------------------------------------- // FETiedElasticSurface //----------------------------------------------------------------------------- @@ -255,6 +267,10 @@ FETiedElasticInterface::FETiedElasticInterface(FEModel* pfem) : FEContactInterfa m_naugmin = 0; m_naugmax = 10; + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMech/FETiedElasticInterface.h b/FEBioMech/FETiedElasticInterface.h index 92dae5ef5..a888e5436 100644 --- a/FEBioMech/FETiedElasticInterface.h +++ b/FEBioMech/FETiedElasticInterface.h @@ -41,6 +41,8 @@ class FETiedElasticSurface : public FEContactSurface Data(); void Serialize(DumpStream& ar) override; + + void Init() override; public: vec3d m_Gap; //!< initial gap in reference configuration diff --git a/FEBioMech/FETiedInterface.cpp b/FEBioMech/FETiedInterface.cpp index cfb32cf5a..ab4670d44 100644 --- a/FEBioMech/FETiedInterface.cpp +++ b/FEBioMech/FETiedInterface.cpp @@ -68,6 +68,10 @@ FETiedInterface::FETiedInterface(FEModel* pfem) : FEContactInterface(pfem), ss(p m_Dmax = 0.0; m_bspecial = true; m_breloc = false; + + // set parents + ss.SetContactInterface(this); + ms.SetContactInterface(this); } //----------------------------------------------------------------------------- diff --git a/FEBioMech/FETraceFreeNeoHookean.cpp b/FEBioMech/FETraceFreeNeoHookean.cpp new file mode 100644 index 000000000..1ad94ade8 --- /dev/null +++ b/FEBioMech/FETraceFreeNeoHookean.cpp @@ -0,0 +1,128 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FETraceFreeNeoHookean.h" + +//----------------------------------------------------------------------------- +// define the material parameters +BEGIN_FECORE_CLASS(FETraceFreeNeoHookean, FEElasticMaterial) + ADD_PARAMETER(m_mu, FE_RANGE_GREATER(0.0), "mu"); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +mat3ds FETraceFreeNeoHookean::Stress(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + double J = pt.m_J; + + // get the material parameter + double mu = m_mu(mp); + + // calculate left Cauchy-Green tensor + mat3ds b = pt.LeftCauchyGreen(); + + double I1 = b.tr(); + + // Identity + mat3dd I(1); + + // calculate stress + mat3ds s = (b*(3/I1) - I)*(mu/J); + + return s; +} + +//----------------------------------------------------------------------------- +tens4ds FETraceFreeNeoHookean::Tangent(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + double J = pt.m_J; + + // get the material parameter + double mu = m_mu(mp); + + mat3dd I(1); + + return dyad4s(I)*(2*mu/J); +} + +//----------------------------------------------------------------------------- +double FETraceFreeNeoHookean::StrainEnergyDensity(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + double J = pt.m_J; + + // get the material parameter + double mu = m_mu(mp); + + // calculate left Cauchy-Green tensor + mat3ds b = pt.LeftCauchyGreen(); + double I1 = b.tr(); + + double sed = mu*log(pow(I1/3,1.5)/J); + + return sed; +} + +//----------------------------------------------------------------------------- +mat3ds FETraceFreeNeoHookean::PK2Stress(FEMaterialPoint& mp, const mat3ds ES) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // get the material parameter + double mu = m_mu(mp); + + mat3ds C = pt.RightCauchyGreen(); + double I1 = C.tr(); + + // Identity + mat3dd I(1); + + // calculate stress + mat3ds S = (I*(3/I1) - C.inverse())*mu; + + return S; +} + +//----------------------------------------------------------------------------- +tens4dmm FETraceFreeNeoHookean::MaterialTangent(FEMaterialPoint& mp, const mat3ds ES) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // get the material parameter + double mu = m_mu(mp); + + mat3ds C = pt.RightCauchyGreen(); + tens4dmm c = dyad4s(C.inverse())*(2*mu); + + return c; +} diff --git a/FEBioMech/FETraceFreeNeoHookean.h b/FEBioMech/FETraceFreeNeoHookean.h new file mode 100644 index 000000000..b6d279d1f --- /dev/null +++ b/FEBioMech/FETraceFreeNeoHookean.h @@ -0,0 +1,63 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#pragma once +#include "FEElasticMaterial.h" +#include + +//----------------------------------------------------------------------------- +//! Trace-Free Neo Hookean material + +//! Implementation of a trace-free neo-Hookean hyperelastic material. +class FEBIOMECH_API FETraceFreeNeoHookean : public FEElasticMaterial +{ +public: + FETraceFreeNeoHookean(FEModel* pfem) : FEElasticMaterial(pfem) {} + +public: + FEParamDouble m_mu; //!< shear modulus + +public: + //! calculate stress at material point + mat3ds Stress(FEMaterialPoint& pt) override; + + //! calculate tangent stiffness at material point + tens4ds Tangent(FEMaterialPoint& pt) override; + + //! calculate strain energy density at material point + double StrainEnergyDensity(FEMaterialPoint& pt) override; + + //! calculate the 2nd Piola-Kirchhoff stress at material point + mat3ds PK2Stress(FEMaterialPoint& pt, const mat3ds E) override; + + //! calculate material tangent stiffness at material point + tens4dmm MaterialTangent(FEMaterialPoint& pt, const mat3ds E) override; + + // declare the parameter list + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FETransIsoMREstrada.cpp b/FEBioMech/FETransIsoMREstrada.cpp new file mode 100644 index 000000000..8490e75c5 --- /dev/null +++ b/FEBioMech/FETransIsoMREstrada.cpp @@ -0,0 +1,199 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FETransIsoMREstrada.h" + +////////////////////////////////////////////////////////////////////// +// FETransIsoMREstrada +////////////////////////////////////////////////////////////////////// + +// define the material parameters +BEGIN_FECORE_CLASS(FETransIsoMREstrada, FEUncoupledMaterial) + ADD_PARAMETER(c1, "c1"); + ADD_PARAMETER(c2, "c2"); + ADD_PARAMETER(m_fib.m_c3, "c3"); + ADD_PARAMETER(m_fib.m_c4, "c4"); + ADD_PARAMETER(m_fib.m_c5, "c5"); + ADD_PARAMETER(m_fib.m_lam1, "lam_max"); + ADD_PARAMETER(m_fib.m_fiber, "fiber"); + + ADD_PROPERTY(m_ac, "active_contraction", FEProperty::Optional); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +FETransIsoMREstrada::FETransIsoMREstrada(FEModel* pfem) : FEUncoupledMaterial(pfem), m_fib(pfem) +{ + m_ac = nullptr; + m_fib.SetParent(this); +} + +//----------------------------------------------------------------------------- +//! create material point data +FEMaterialPoint* FETransIsoMREstrada::CreateMaterialPointData() { + // create the elastic solid material point + FEMaterialPoint* ep = new FEElasticMaterialPoint; + + // create the material point from the active contraction material + if (m_ac) { + FEMaterialPoint* pt = m_ac->CreateMaterialPointData(*ep); + if (pt != nullptr) return pt; + } + return ep; +} + +//----------------------------------------------------------------------------- +mat3ds FETransIsoMREstrada::DevStress(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // deformation gradient + double J = pt.m_J; + + // calculate deviatoric left Cauchy-Green tensor + mat3ds B = pt.DevLeftCauchyGreen(); + + // calculate square of B + mat3ds B2 = B.sqr(); + + // Invariants of B (= invariants of C) + // Note that these are the invariants of Btilde, not of B! + double I1 = B.tr(); + + // --- TODO: put strain energy derivatives here --- + // Wi = dW/dIi + double W1 = c1; + double W2 = c2; + // ------------------------------------------------ + + // calculate T = F*dW/dC*Ft + mat3ds T = B*(W1 + W2*I1) - B2*W2; + + // calculate stress s = pI + 2/J * dev(T) + mat3ds s = T.dev()*(2.0/J); + + // calculate the passive fiber stress + mat3ds fs = m_fib.DevFiberStress(mp,m_fib.FiberVector(mp)); + + // calculate the active fiber stress (if provided) + if (m_ac) fs += m_ac->ActiveStress(mp,m_fib.FiberVector(mp)); + + return s + fs; +} + +//----------------------------------------------------------------------------- +//! Calculate deviatoric tangent +tens4ds FETransIsoMREstrada::DevTangent(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // deformation gradient + double J = pt.m_J; + double Ji = 1.0/J; + + // calculate deviatoric left Cauchy-Green tensor: B = F*Ft + mat3ds B = pt.DevLeftCauchyGreen(); + + // calculate square of B + mat3ds B2 = B.sqr(); + + // Invariants of B (= invariants of C) + double I1 = B.tr(); + double I2 = 0.5*(I1*I1 - B2.tr()); + + // --- TODO: put strain energy derivatives here --- + // Wi = dW/dIi + double W1, W2; + W1 = c1; + W2 = c2; + // ------------------------------------ + + // calculate dWdC:C + double WC = W1*I1 + 2*W2*I2; + + // calculate C:d2WdCdC:C + double CWWC = 2*I2*W2; + + mat3dd I(1); // Identity + tens4ds IxI = dyad1s(I); + tens4ds I4 = dyad4s(I); + tens4ds BxB = dyad1s(B); + tens4ds B4 = dyad4s(B); + + // deviatoric cauchy-stress, trs = trace[s]/3 + mat3ds devs = pt.m_s.dev(); + + // d2W/dCdC:C + mat3ds WCCxC = B*(W2*I1) - B2*W2; + + tens4ds cw = (BxB - B4)*(W2*4.0*Ji) - dyad1s(WCCxC, I)*(4.0/3.0*Ji) + IxI*(4.0/9.0*Ji*CWWC); + tens4ds c = dyad1s(devs, I)*(-2.0/3.0) + (I4 - IxI/3.0)*(4.0/3.0*Ji*WC) + cw; + + // add the passive fiber stiffness + c += m_fib.DevFiberTangent(mp,m_fib.FiberVector(mp)); + + // add the active fiber stiffness + if (m_ac) c += m_ac->ActiveStiffness(mp, m_fib.FiberVector(mp)); + + return c; +} + +//----------------------------------------------------------------------------- +double FETransIsoMREstrada::DevStrainEnergyDensity(FEMaterialPoint& mp) +{ + FEElasticMaterialPoint& pt = *mp.ExtractData(); + + // calculate deviatoric left Cauchy-Green tensor + mat3ds B = pt.DevLeftCauchyGreen(); + + // calculate square of B + mat3ds B2 = B.sqr(); + + // Invariants of B (= invariants of C) + // Note that these are the invariants of Btilde, not of B! + double I1 = B.tr(); + double I2 = 0.5*(I1*I1 - B2.tr()); + + // calculate sed + double sed = c1*(I1-3) + c2*(I2-3); + + // add the fiber sed + sed += m_fib.DevFiberStrainEnergyDensity(mp,m_fib.FiberVector(mp)); + + return sed; +} + +//----------------------------------------------------------------------------- +// update force-velocity material point +void FETransIsoMREstrada::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& timeInfo) +{ + // get the material fiber axis + vec3d a0 = m_fib.m_fiber.unitVector(mp); + + if (m_ac) m_ac->UpdateSpecializedMaterialPoints(mp, timeInfo, a0); +} diff --git a/FEBioMech/FETransIsoMREstrada.h b/FEBioMech/FETransIsoMREstrada.h new file mode 100644 index 000000000..a567dffb9 --- /dev/null +++ b/FEBioMech/FETransIsoMREstrada.h @@ -0,0 +1,74 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#pragma once +#include "FEUncoupledMaterial.h" +#include "FEUncoupledFiberExpLinear.h" +#include "FEActiveContractionMaterial.h" + +//----------------------------------------------------------------------------- +//! Transversely Isotropic Mooney-Rivlin-Estrada material based on doi: 10.1115/1.4044030 + +//! This material has an isotopric Mooney-Rivlin basis and single preferred +//! fiber direction. + +class FETransIsoMREstrada: public FEUncoupledMaterial +{ +public: + enum { MAX_TERMS = 3 }; + +public: + FETransIsoMREstrada(FEModel* pfem); + +public: + double c1; //!< Mooney-Rivlin coefficient C1 + double c2; //!< Mooney-Rivlin coefficient C2 + +public: + //! calculate deviatoric stress at material point + mat3ds DevStress(FEMaterialPoint& pt) override; + + //! calculate deviatoric tangent stiffness at material point + tens4ds DevTangent(FEMaterialPoint& pt) override; + + //! calculate deviatoric strain energy density at material point + double DevStrainEnergyDensity(FEMaterialPoint& pt) override; + + //! create material point data + FEMaterialPoint* CreateMaterialPointData() override; + + // update force-velocity material point + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; + +protected: + FEUncoupledFiberExpLinear m_fib; + FEActiveContractionMaterial* m_ac; + + // declare parameter list + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FETransIsoMooneyRivlin.cpp b/FEBioMech/FETransIsoMooneyRivlin.cpp index b65a45a2e..e4548d313 100644 --- a/FEBioMech/FETransIsoMooneyRivlin.cpp +++ b/FEBioMech/FETransIsoMooneyRivlin.cpp @@ -49,10 +49,24 @@ END_FECORE_CLASS(); //----------------------------------------------------------------------------- FETransIsoMooneyRivlin::FETransIsoMooneyRivlin(FEModel* pfem) : FEUncoupledMaterial(pfem), m_fib(pfem) { - m_ac = 0; + m_ac = nullptr; m_fib.SetParent(this); } +//----------------------------------------------------------------------------- +//! create material point data +FEMaterialPoint* FETransIsoMooneyRivlin::CreateMaterialPointData() { + // create the elastic solid material point + FEMaterialPoint* ep = new FEElasticMaterialPoint; + + // create the material point from the active contraction material + if (m_ac) { + FEMaterialPoint* pt = m_ac->CreateMaterialPointData(*ep); + if (pt != nullptr) return pt; + } + return ep; +} + //----------------------------------------------------------------------------- mat3ds FETransIsoMooneyRivlin::DevStress(FEMaterialPoint& mp) { @@ -87,7 +101,7 @@ mat3ds FETransIsoMooneyRivlin::DevStress(FEMaterialPoint& mp) mat3ds fs = m_fib.DevFiberStress(mp,m_fib.FiberVector(mp)); // calculate the active fiber stress (if provided) - if (m_ac) fs += m_ac->FiberStress(m_fib.FiberVector(mp), pt); + if (m_ac) fs += m_ac->ActiveStress(mp, m_fib.FiberVector(mp)); return s + fs; } @@ -144,7 +158,7 @@ tens4ds FETransIsoMooneyRivlin::DevTangent(FEMaterialPoint& mp) c += m_fib.DevFiberTangent(mp,m_fib.FiberVector(mp)); // add the active fiber stiffness - if (m_ac) c += m_ac->FiberStiffness(m_fib.FiberVector(mp), mp); + if (m_ac) c += m_ac->ActiveStiffness(mp, m_fib.FiberVector(mp)); return c; } @@ -173,3 +187,14 @@ double FETransIsoMooneyRivlin::DevStrainEnergyDensity(FEMaterialPoint& mp) return sed; } + +//----------------------------------------------------------------------------- +// update force-velocity material point +void FETransIsoMooneyRivlin::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& timeInfo) +{ + // get the material fiber axis + vec3d a0 = m_fib.m_fiber.unitVector(mp); + + if (m_ac) m_ac->UpdateSpecializedMaterialPoints(mp, timeInfo, a0); +} + diff --git a/FEBioMech/FETransIsoMooneyRivlin.h b/FEBioMech/FETransIsoMooneyRivlin.h index b15b8451d..beaedf5b2 100644 --- a/FEBioMech/FETransIsoMooneyRivlin.h +++ b/FEBioMech/FETransIsoMooneyRivlin.h @@ -29,7 +29,7 @@ SOFTWARE.*/ #pragma once #include "FEUncoupledMaterial.h" #include "FEUncoupledFiberExpLinear.h" -#include "FEActiveFiberContraction.h" +#include "FEActiveContractionMaterial.h" //----------------------------------------------------------------------------- //! Transversely Isotropic Mooney-Rivlin material @@ -56,9 +56,15 @@ class FETransIsoMooneyRivlin: public FEUncoupledMaterial //! calculate deviatoric strain energy density at material point double DevStrainEnergyDensity(FEMaterialPoint& pt) override; + //! create material point data + FEMaterialPoint* CreateMaterialPointData() override; + + // update force-velocity material point + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; + protected: - FEUncoupledFiberExpLinear m_fib; - FEActiveFiberContraction* m_ac; + FEUncoupledFiberExpLinear m_fib; + FEActiveContractionMaterial* m_ac; // declare parameter list DECLARE_FECORE_CLASS(); diff --git a/FEBioMech/FETransIsoVerondaWestmann.cpp b/FEBioMech/FETransIsoVerondaWestmann.cpp index ccc29592c..8a72291c7 100644 --- a/FEBioMech/FETransIsoVerondaWestmann.cpp +++ b/FEBioMech/FETransIsoVerondaWestmann.cpp @@ -49,10 +49,24 @@ END_FECORE_CLASS(); //----------------------------------------------------------------------------- FETransIsoVerondaWestmann::FETransIsoVerondaWestmann(FEModel* pfem) : FEUncoupledMaterial(pfem), m_fib(pfem) { - m_ac = 0; + m_ac = nullptr; m_fib.SetParent(this); } +//----------------------------------------------------------------------------- +//! create material point data +FEMaterialPoint* FETransIsoVerondaWestmann::CreateMaterialPointData() { + // create the elastic solid material point + FEMaterialPoint* ep = new FEElasticMaterialPoint; + + // create the material point from the active contraction material + if (m_ac) { + FEMaterialPoint* pt = m_ac->CreateMaterialPointData(*ep); + if (pt != nullptr) return pt; + } + return ep; +} + //----------------------------------------------------------------------------- mat3ds FETransIsoVerondaWestmann::DevStress(FEMaterialPoint& mp) { @@ -87,9 +101,9 @@ mat3ds FETransIsoVerondaWestmann::DevStress(FEMaterialPoint& mp) // add the passive fiber stress s += m_fib.DevFiberStress(mp, m_fib.FiberVector(mp)); - // add the active fiber stress - if ((FEActiveFiberContraction*)m_ac) s += m_ac->FiberStress(m_fib.FiberVector(mp), mp); - + // calculate the active fiber stress (if provided) + if (m_ac) s += m_ac->ActiveStress(mp,m_fib.FiberVector(mp)); + return s; } @@ -143,6 +157,10 @@ tens4ds FETransIsoVerondaWestmann::DevTangent(FEMaterialPoint& mp) tens4ds cw = BxB*((W11 + W2)*4.0*Ji) - B4*(W2*4.0*Ji) - dyad1s(WCCxC, I)*(4.0/3.0*Ji) + IxI*(4.0/9.0*Ji*CWWC); tens4ds c = dyad1s(devs, I)*(-2.0/3.0) + (I4 - IxI/3.0)*(4.0/3.0*Ji*WC) + cw; + + // add the active fiber stiffness + if (m_ac) c += m_ac->ActiveStiffness(mp, m_fib.FiberVector(mp)); + return c + m_fib.DevFiberTangent(mp,m_fib.FiberVector(mp)); } @@ -170,3 +188,13 @@ double FETransIsoVerondaWestmann::DevStrainEnergyDensity(FEMaterialPoint& mp) return sed; } + +//----------------------------------------------------------------------------- +// update force-velocity material point +void FETransIsoVerondaWestmann::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& timeInfo) +{ + // get the material fiber axis + vec3d a0 = m_fib.m_fiber.unitVector(mp); + + if (m_ac) m_ac->UpdateSpecializedMaterialPoints(mp, timeInfo, a0); +} diff --git a/FEBioMech/FETransIsoVerondaWestmann.h b/FEBioMech/FETransIsoVerondaWestmann.h index e83ef65ef..ca190d0d3 100644 --- a/FEBioMech/FETransIsoVerondaWestmann.h +++ b/FEBioMech/FETransIsoVerondaWestmann.h @@ -29,8 +29,7 @@ SOFTWARE.*/ #pragma once #include "FEUncoupledMaterial.h" #include "FEUncoupledFiberExpLinear.h" -#include "FEActiveFiberContraction.h" -#include +#include "FEActiveContractionMaterial.h" //----------------------------------------------------------------------------- //! Transversely Isotropic Veronda-Westmann material @@ -49,17 +48,23 @@ class FETransIsoVerondaWestmann : public FEUncoupledMaterial public: //! calculate deviatoric stress at material point - virtual mat3ds DevStress(FEMaterialPoint& pt) override; + mat3ds DevStress(FEMaterialPoint& pt) override; //! calculate deviatoric tangent stiffness at material point - virtual tens4ds DevTangent(FEMaterialPoint& pt) override; + tens4ds DevTangent(FEMaterialPoint& pt) override; //! calculate deviatoric strain energy density at material point - virtual double DevStrainEnergyDensity(FEMaterialPoint& pt) override; + double DevStrainEnergyDensity(FEMaterialPoint& pt) override; + + //! create material point data + FEMaterialPoint* CreateMaterialPointData() override; + + // update force-velocity material point + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; protected: - FEUncoupledFiberExpLinear m_fib; - FEActiveFiberContraction* m_ac; + FEUncoupledFiberExpLinear m_fib; + FEActiveContractionMaterial* m_ac; // declare parameter list DECLARE_FECORE_CLASS(); diff --git a/FEBioMech/FEUT4Domain.cpp b/FEBioMech/FEUT4Domain.cpp index 593e56f0b..01daae4d8 100644 --- a/FEBioMech/FEUT4Domain.cpp +++ b/FEBioMech/FEUT4Domain.cpp @@ -244,7 +244,8 @@ void FEUT4Domain::SetUT4Parameters(double alpha, bool bdev) //! override Create so we can grab the ut4 parameters bool FEUT4Domain::Create(int nelems, FE_Element_Spec espec) { - if (espec.m_but4 == false) return false; + // NOTE: Commented this out, since during restart the espec is a dummy variable. +// if (espec.m_but4 == false) return false; m_alpha = espec.m_ut4_alpha; m_bdev = espec.m_ut4_bdev; diff --git a/FEBioMech/FEUncoupledElasticMixture.cpp b/FEBioMech/FEUncoupledElasticMixture.cpp index 8a34d17fc..9a33662fd 100644 --- a/FEBioMech/FEUncoupledElasticMixture.cpp +++ b/FEBioMech/FEUncoupledElasticMixture.cpp @@ -108,9 +108,9 @@ mat3ds FEUncoupledElasticMixture::DevStress(FEMaterialPoint& mp) FEUncoupledMaterial* uMat = dynamic_cast(m_pMat[i]); if (uMat) - s += epi.m_s = uMat->DevStress(*pt.GetPointData(i))*w[i]; + s += epi.m_s = uMat->DevStress(epi)*w[i]; else - s += epi.m_s = m_pMat[i]->Stress(*pt.GetPointData(i))*w[i]; + s += epi.m_s = m_pMat[i]->Stress(epi)*w[i]; } return s; @@ -144,9 +144,9 @@ tens4ds FEUncoupledElasticMixture::DevTangent(FEMaterialPoint& mp) FEUncoupledMaterial* uMat = dynamic_cast(m_pMat[i]); if (uMat) - c += uMat->DevTangent(*pt.GetPointData(i))*w[i]; + c += uMat->DevTangent(epi)*w[i]; else - c += m_pMat[i]->Tangent(*pt.GetPointData(i))*w[i]; + c += m_pMat[i]->Tangent(epi)*w[i]; } return c; @@ -180,9 +180,9 @@ double FEUncoupledElasticMixture::DevStrainEnergyDensity(FEMaterialPoint& mp) FEUncoupledMaterial* uMat = dynamic_cast(m_pMat[i]); if (uMat) - sed += uMat->DevStrainEnergyDensity(*pt.GetPointData(i))*w[i]; + sed += uMat->DevStrainEnergyDensity(epi)*w[i]; else - sed += m_pMat[i]->StrainEnergyDensity(*pt.GetPointData(i))*w[i]; + sed += m_pMat[i]->StrainEnergyDensity(epi)*w[i]; } return sed; @@ -216,9 +216,9 @@ double FEUncoupledElasticMixture::StrongBondDevSED(FEMaterialPoint& mp) FEUncoupledMaterial* uMat = dynamic_cast(m_pMat[i]); if (uMat) - sed += uMat->StrongBondDevSED(*pt.GetPointData(i))*w[i]; + sed += uMat->StrongBondDevSED(epi)*w[i]; else - sed += m_pMat[i]->StrongBondSED(*pt.GetPointData(i))*w[i]; + sed += m_pMat[i]->StrongBondSED(epi)*w[i]; } return sed; diff --git a/FEBioMech/FEUncoupledMaterial.cpp b/FEBioMech/FEUncoupledMaterial.cpp index a35d9d6f4..ac9a6087d 100644 --- a/FEBioMech/FEUncoupledMaterial.cpp +++ b/FEBioMech/FEUncoupledMaterial.cpp @@ -81,7 +81,8 @@ mat3ds FEUncoupledMaterial::Stress(FEMaterialPoint &mp) FEElasticMaterialPoint& pt = *mp.ExtractData(); // calculate the stress as a sum of deviatoric stress and pressure - return mat3dd(UJ(pt.m_J)) + DevStress(mp); + pt.m_p = UJ(pt.m_J); + return mat3dd(pt.m_p) + DevStress(mp); } //------------------------------------------------------------------------------ @@ -103,7 +104,7 @@ tens4ds FEUncoupledMaterial::Tangent(FEMaterialPoint &mp) tens4ds I4 = dyad4s(I); // pressure - double p = UJ(pt.m_J); + pt.m_p = UJ(pt.m_J); // tangent is sum of three terms // C = c_tilde + c_pressure + c_k @@ -116,7 +117,7 @@ tens4ds FEUncoupledMaterial::Tangent(FEMaterialPoint &mp) // but we do need to add it here. // // c_tilde c_pressure c_k - return DevTangent(mp) + (IxI - I4*2)*p + IxI*(UJJ(pt.m_J)*pt.m_J); + return DevTangent(mp) + (IxI - I4*2)*pt.m_p + IxI*(UJJ(pt.m_J)*pt.m_J); } //----------------------------------------------------------------------------- diff --git a/FEBioMech/FEUncoupledMaterial.h b/FEBioMech/FEUncoupledMaterial.h index a73782481..a93767cfa 100644 --- a/FEBioMech/FEUncoupledMaterial.h +++ b/FEBioMech/FEUncoupledMaterial.h @@ -77,6 +77,9 @@ class FEUncoupledMaterial : public FEElasticMaterial virtual double WeakBondDevSED(FEMaterialPoint& pt) { return 0; } public: + // TODO: removing virtual from the following 3 functions causes changes + // to the convergence criteria on macOS, despite these functions not + // being overridden anywhere. //! strain energy density U(J) virtual double U(double J) { switch (m_npmodel) { diff --git a/FEBioMech/FEUncoupledReactiveFatigue.cpp b/FEBioMech/FEUncoupledReactiveFatigue.cpp new file mode 100644 index 000000000..15aaf790b --- /dev/null +++ b/FEBioMech/FEUncoupledReactiveFatigue.cpp @@ -0,0 +1,198 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FEUncoupledReactiveFatigue.h" +#include "FEDamageCriterion.h" +#include "FEDamageCDF.h" +#include +#include +#include +#include +#include + +//////////////////////////// FATIGUE MATERIAL ///////////////////////////////// +//----------------------------------------------------------------------------- +// define the material parameters +BEGIN_FECORE_CLASS(FEUncoupledReactiveFatigue, FEUncoupledMaterial) +ADD_PARAMETER(m_k0 , FE_RANGE_GREATER_OR_EQUAL(0.0), "k0" ); +ADD_PARAMETER(m_beta , FE_RANGE_GREATER_OR_EQUAL(0.0), "beta"); + +// set material properties +ADD_PROPERTY(m_pBase, "elastic"); +ADD_PROPERTY(m_pIdmg, "elastic_damage"); +ADD_PROPERTY(m_pFdmg, "fatigue_damage"); +ADD_PROPERTY(m_pIcrt, "elastic_criterion"); +ADD_PROPERTY(m_pFcrt, "fatigue_criterion"); + +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +//! Constructor. +FEUncoupledReactiveFatigue::FEUncoupledReactiveFatigue(FEModel* pfem) : FEUncoupledMaterial(pfem) +{ + m_pBase = 0; + m_pIdmg = 0; + m_pFdmg = 0; + m_pIcrt = 0; + m_pFcrt = 0; +} + +//----------------------------------------------------------------------------- +//! Initialization. +bool FEUncoupledReactiveFatigue::Init() +{ + return FEUncoupledMaterial::Init(); +} + +//----------------------------------------------------------------------------- +//! calculate stress at material point +mat3ds FEUncoupledReactiveFatigue::DevStress(FEMaterialPoint& pt) +{ + // evaluate the damage + double d = Damage(pt); + + // evaluate the stress + mat3ds s = m_pBase->DevStress(pt); + + // return damaged stress + return s*(1-d); +} + +//----------------------------------------------------------------------------- +//! calculate tangent stiffness at material point +tens4ds FEUncoupledReactiveFatigue::DevTangent(FEMaterialPoint& pt) +{ + // evaluate the damage + double d = Damage(pt); + + // evaluate the tangent + tens4ds c = m_pBase->DevTangent(pt); + + // return damaged tangent + return c*(1-d); +} + +//----------------------------------------------------------------------------- +//! calculate strain energy density at material point +double FEUncoupledReactiveFatigue::DevStrainEnergyDensity(FEMaterialPoint& pt) +{ + // evaluate the damage + double d = Damage(pt); + + // evaluate the strain energy density + double sed = m_pBase->DevStrainEnergyDensity(pt); + + // return damaged sed + return sed*(1-d); +} + +//----------------------------------------------------------------------------- +//! calculate damage at material point +double FEUncoupledReactiveFatigue::Damage(FEMaterialPoint& pt) +{ + // get the reactive fatigue material point data + FEReactiveFatigueMaterialPoint& pd = *pt.ExtractData(); + + return pd.m_D; +} + +//----------------------------------------------------------------------------- +// update fatigue material point at each iteration +void FEUncoupledReactiveFatigue::UpdateSpecializedMaterialPoints(FEMaterialPoint& pt, const FETimeInfo& tp) +{ + double dt = tp.timeIncrement; + + // get the fatigue material point data + FEReactiveFatigueMaterialPoint& pd = *pt.ExtractData(); + + // get damage criterion for intact bonds at current time + pd.m_Xitrl = m_pIcrt->DamageCriterion(pt); + if (pd.m_Xitrl > pd.m_Ximax) + pd.m_Fit = m_pIdmg->cdf(pd.m_Xitrl); + else + pd.m_Fit = pd.m_Fip; + + // get damage criterion for fatigue bonds at current time + double Xftrl = m_pFcrt->DamageCriterion(pt); + for (int ig=0; ig < pd.m_fb.size(); ++ig) { + if (Xftrl > pd.m_fb[ig].m_Xfmax) { + pd.m_fb[ig].m_Xftrl = Xftrl; + pd.m_fb[ig].m_Fft = m_pFdmg->cdf(pd.m_fb[ig].m_Xftrl); + } + else + pd.m_fb[ig].m_Fft = pd.m_fb[ig].m_Ffp; + } + + // evaluate time derivative of intact bond criterion + pd.m_aXit = (pd.m_Xitrl - pd.m_Xip)/dt; + + // solve for bond mass fractions iteratively + double eps = 1e-6; + int maxit = 10; + double wbi = 0; + int iter = 0; + do { + wbi = pd.m_wbt; + // evaluate mass supply from fatigue of intact bonds + double dwf = m_k0*dt/2*(pow(fabs(pd.m_aXit)*pd.m_wbt,m_beta)*pd.m_wit+pow(fabs(pd.m_aXip)*pd.m_wbp,m_beta)*pd.m_wip); + double Fdwf = m_pFdmg->cdf(Xftrl); + + // kinetics of intact bonds + pd.m_wit = (pd.m_Fip < 1) ? pd.m_wip*(1-pd.m_Fit)/(1-pd.m_Fip) - dwf : 0; + pd.m_wbt = (pd.m_Fip < 1) ? pd.m_wbp + pd.m_wip*(pd.m_Fit - pd.m_Fip)/(1-pd.m_Fip) : pd.m_wbp; + // add or update new generation + if ((pd.m_fb.size() == 0) || pd.m_fb.back().m_time < tp.currentTime) { + // add generation of fatigued bonds + FatigueBond fb; + fb.m_Fft = Fdwf; + fb.m_wfp = dwf; + fb.m_Xftrl = Xftrl; + fb.m_time = tp.currentTime; + pd.m_fb.push_back(fb); + } + else { + pd.m_fb.back().m_Fft = Fdwf; + pd.m_fb.back().m_wfp = dwf; + pd.m_fb.back().m_Xftrl = Xftrl; + } + // damage kinetics of fatigued bonds + for (int ig=0; ig < pd.m_fb.size(); ++ig) { + pd.m_fb[ig].m_wft = (pd.m_fb[ig].m_Ffp < 1) ? pd.m_fb[ig].m_wfp*(1-pd.m_fb[ig].m_Fft)/(1-pd.m_fb[ig].m_Ffp) : 0; + pd.m_wbt += (pd.m_fb[ig].m_Ffp < 1) ? pd.m_fb[ig].m_wfp*(pd.m_fb[ig].m_Fft-pd.m_fb[ig].m_Ffp)/(1-pd.m_fb[ig].m_Ffp) : pd.m_fb[ig].m_wfp; + } + // roundoff corrections + if (pd.m_wit < 0) pd.m_wit = 0; + if (pd.m_wbt > 1) pd.m_wbt = 1; + // evaluate fatigue bond fraction + pd.m_wft = 0; + for (int ig=0; ig < pd.m_fb.size(); ++ig) pd.m_wft += pd.m_fb[ig].m_wft; + } while ((pd.m_wbt > 0) && (pd.m_wbt < 1) && (fabs(wbi-pd.m_wbt) > eps*pd.m_wbt) && (++iterCreateMaterialPointData()); + } + + // get the elastic material + FEElasticMaterial* GetElasticMaterial() override { return m_pBase; } + + // update fatigue material point at each iteration + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; + +public: + FEUncoupledMaterial* m_pBase; // base uncoupled material + FEDamageCDF* m_pIdmg; // damage model for intact bonds + FEDamageCDF* m_pFdmg; // damage model for fatigued bonds + FEDamageCriterion* m_pIcrt; // damage criterion + FEDamageCriterion* m_pFcrt; // fatigue criterion + +public: + double m_k0; // reaction rate for fatigue reaction + double m_beta; // power exponent for fatigue reaction + + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMech/FEUncoupledReactiveViscoelastic.cpp b/FEBioMech/FEUncoupledReactiveViscoelastic.cpp index 4597828ae..8f4bc80a4 100644 --- a/FEBioMech/FEUncoupledReactiveViscoelastic.cpp +++ b/FEBioMech/FEUncoupledReactiveViscoelastic.cpp @@ -53,6 +53,7 @@ BEGIN_FECORE_CLASS(FEUncoupledReactiveViscoelasticMaterial, FEUncoupledMaterial) ADD_PROPERTY(m_pBase, "elastic"); ADD_PROPERTY(m_pBond, "bond"); ADD_PROPERTY(m_pRelx, "relaxation"); + ADD_PROPERTY(m_pWCDF, "recruitment", FEProperty::Optional); END_FECORE_CLASS(); @@ -70,7 +71,12 @@ FEUncoupledReactiveViscoelasticMaterial::FEUncoupledReactiveViscoelasticMaterial m_pBase = nullptr; m_pBond = nullptr; m_pRelx = nullptr; + m_pWCDF = nullptr; + + m_pDmg = nullptr; + m_pFtg = nullptr; } + //----------------------------------------------------------------------------- //! data initialization bool FEUncoupledReactiveViscoelasticMaterial::Init() @@ -78,6 +84,10 @@ bool FEUncoupledReactiveViscoelasticMaterial::Init() if (!m_pBase->Init()) return false; if (!m_pBond->Init()) return false; if (!m_pRelx->Init()) return false; + if (m_pWCDF && !m_pWCDF->Init()) return false; + + m_pDmg = dynamic_cast(m_pBase); + m_pFtg = dynamic_cast(m_pBase); return FEUncoupledMaterial::Init(); } @@ -232,24 +242,24 @@ double FEUncoupledReactiveViscoelasticMaterial::BreakingBondMassFraction(FEMater // current time double time = GetFEModel()->GetTime().currentTime; - double tv = time - pt.m_v[ig]; + double dtv = time - pt.m_v[ig]; switch (m_btype) { case 1: { - if (tv >= 0) - w = pt.m_f[ig]*m_pRelx->Relaxation(mp, tv, D); + if (dtv >= 0) + w = pt.m_f[ig]*m_pRelx->Relaxation(mp, dtv, D); } break; case 2: { if (ig == 0) { - w = m_pRelx->Relaxation(mp, tv, D); + w = m_pRelx->Relaxation(mp, dtv, D); } else { - double tu = time - pt.m_v[ig-1]; - w = m_pRelx->Relaxation(mp, tv, D) - m_pRelx->Relaxation(mp, tu, D); + double dtu = time - pt.m_v[ig-1]; + w = m_pRelx->Relaxation(mp, dtv, D) - m_pRelx->Relaxation(mp, dtu, D); } } break; @@ -258,7 +268,7 @@ double FEUncoupledReactiveViscoelasticMaterial::BreakingBondMassFraction(FEMater break; } - assert((w >= 0) && (w <= 1)); + assert(w >= 0); return w; } @@ -282,7 +292,7 @@ double FEUncoupledReactiveViscoelasticMaterial::ReformingBondMassFraction(FEMate // get current number of generations int ng = (int)pt.m_Uv.size(); - double w = 1; + double f = (!pt.m_wv.empty()) ? pt.m_wv.back() : 1; for (int ig=0; ig= 0) && (w <= 1)); + assert(f >= 0); // return the bond mass fraction of the reforming generation - return w; + return f; } //----------------------------------------------------------------------------- @@ -389,7 +399,7 @@ mat3ds FEUncoupledReactiveViscoelasticMaterial::DevStress(FEMaterialPoint& mp) { // calculate the base material Cauchy stress mat3ds s = DevStressStrongBonds(mp); - s+= DevStressWeakBonds(mp); + s+= DevStressWeakBonds(mp)*(1-Damage(mp)); // return the total Cauchy stress return s; @@ -475,7 +485,7 @@ tens4ds FEUncoupledReactiveViscoelasticMaterial::DevTangentWeakBonds(FEMaterialP tens4ds FEUncoupledReactiveViscoelasticMaterial::DevTangent(FEMaterialPoint& mp) { tens4ds c = DevTangentStrongBonds(mp); - c+= DevTangentWeakBonds(mp); + c+= DevTangentWeakBonds(mp)*(1-Damage(mp)); // return the total tangent return c; @@ -545,9 +555,9 @@ double FEUncoupledReactiveViscoelasticMaterial::WeakBondDevSED(FEMaterialPoint& ep.m_J = J; if (fp) fp->ResetPreStretch(); } - // evaluate bond stress + // evaluate bond strain energy density sedb = m_pBond->DevStrainEnergyDensity(wb); - // add bond stress to total stress + // add bond stress to total strain energy density sed += sedb*w; } @@ -564,7 +574,7 @@ double FEUncoupledReactiveViscoelasticMaterial::WeakBondDevSED(FEMaterialPoint& double FEUncoupledReactiveViscoelasticMaterial::DevStrainEnergyDensity(FEMaterialPoint& mp) { double sed = StrongBondDevSED(mp); - sed += WeakBondDevSED(mp); + sed += WeakBondDevSED(mp)*(1-Damage(mp)); // return the total strain energy density return sed; @@ -607,10 +617,12 @@ void FEUncoupledReactiveViscoelasticMaterial::CullGenerations(FEMaterialPoint& m pt.m_Uv[1] = (pt.m_Uv[0]*w0 + pt.m_Uv[1]*w1)/(w0+w1); pt.m_Jv[1] = pt.m_Uv[1].det(); pt.m_f[1] = (w0*pt.m_f[0] + w1*pt.m_f[1])/(w0+w1); + pt.m_wv[1] = (w0*pt.m_wv[0] + w1*pt.m_wv[1])/(w0+w1); pt.m_Uv.pop_front(); pt.m_Jv.pop_front(); pt.m_v.pop_front(); pt.m_f.pop_front(); + pt.m_wv.pop_front(); } // restore safe copy of deformation gradient @@ -624,8 +636,13 @@ void FEUncoupledReactiveViscoelasticMaterial::CullGenerations(FEMaterialPoint& m //! Update specialized material points void FEUncoupledReactiveViscoelasticMaterial::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) { + FEMaterialPoint& sb = *GetBaseMaterialPoint(mp); FEMaterialPoint& wb = *GetBondMaterialPoint(mp); + // start by updating specialized material points of base and bond materials + m_pBase->UpdateSpecializedMaterialPoints(sb, tp); + m_pBond->UpdateSpecializedMaterialPoints(wb, tp); + // get the reactive viscoelastic point data FEReactiveVEMaterialPoint& pt = *wb.ExtractData(); @@ -645,6 +662,14 @@ void FEUncoupledReactiveViscoelasticMaterial::UpdateSpecializedMaterialPoints(FE pt.m_Jv.push_back(Jv); double f = (!pt.m_v.empty()) ? ReformingBondMassFraction(wb) : 1; pt.m_f.push_back(f); + if (m_pWCDF) { + pt.m_Et = ScalarStrain(pt); + if (pt.m_Et > pt.m_Em) + pt.m_wv.push_back(m_pWCDF->cdf(pt.m_Et)); + else + pt.m_wv.push_back(m_pWCDF->cdf(pt.m_Em)); + } + else pt.m_wv.push_back(1); CullGenerations(wb); } } @@ -652,6 +677,13 @@ void FEUncoupledReactiveViscoelasticMaterial::UpdateSpecializedMaterialPoints(FE else if (pt.m_v.back() == tp.currentTime) { pt.m_Uv.back() = Uv; pt.m_Jv.back() = Jv; + if (m_pWCDF) { + pt.m_Et = ScalarStrain(pt); + if (pt.m_Et > pt.m_Em) + pt.m_wv.back() = m_pWCDF->cdf(pt.m_Et); + else + pt.m_wv.back() = m_pWCDF->cdf(pt.m_Em); + } pt.m_f.back() = ReformingBondMassFraction(wb); } } @@ -668,3 +700,54 @@ int FEUncoupledReactiveViscoelasticMaterial::RVEGenerations(FEMaterialPoint& mp) // return the bond mass fraction of the reforming generation return (int)pt.m_v.size(); } + +//----------------------------------------------------------------------------- +//! evaluate trigger strain +double FEUncoupledReactiveViscoelasticMaterial::ScalarStrain(FEMaterialPoint& mp) +{ + double d; + // get the elastic point data + FEElasticMaterialPoint& ep = *mp.ExtractData(); + + switch (m_ttype) { + case 0: + { + // evaluate the Lagrangian strain + mat3ds E = ep.Strain(); + + d = E.norm(); + } + break; + case 1: + { + // distortional strain + // evaluate spatial Hencky (logarithmic) strain + mat3ds h = ep.LeftHencky(); + + // evaluate distortion magnitude (always positive) + d = (h.dev()).norm(); + } + break; + case 2: + { + // dilatational strain + d = fabs(log(ep.m_J)); + } + break; + + default: + d = 0; + break; + } + + return d; +} + +//----------------------------------------------------------------------------- +double FEUncoupledReactiveViscoelasticMaterial::Damage(FEMaterialPoint& mp) +{ + double D = 0; + if (m_pDmg) D = m_pDmg->Damage(*GetBaseMaterialPoint(mp)); + else if (m_pFtg) D = m_pFtg->Damage(*GetBaseMaterialPoint(mp)); + return D; +} diff --git a/FEBioMech/FEUncoupledReactiveViscoelastic.h b/FEBioMech/FEUncoupledReactiveViscoelastic.h index 0f1341b20..2b213b74e 100644 --- a/FEBioMech/FEUncoupledReactiveViscoelastic.h +++ b/FEBioMech/FEUncoupledReactiveViscoelastic.h @@ -30,6 +30,8 @@ SOFTWARE.*/ #include "FEUncoupledMaterial.h" #include "FEBondRelaxation.h" #include "FEReactiveVEMaterialPoint.h" +#include "FEDamageMaterialUC.h" +#include "FEUncoupledReactiveFatigue.h" #include //----------------------------------------------------------------------------- @@ -100,10 +102,19 @@ class FEUncoupledReactiveViscoelasticMaterial : public FEUncoupledMaterial //! get bond material point FEMaterialPoint* GetBondMaterialPoint(FEMaterialPoint& mp); + //! evaluate scalar strain measure (same type as trigger strain for bond breaking) + double ScalarStrain(FEMaterialPoint& mp); + private: FEUncoupledMaterial* m_pBase; //!< pointer to elastic solid material for strong bonds FEUncoupledMaterial* m_pBond; //!< pointer to elastic solid material for reactive bonds FEBondRelaxation* m_pRelx; //!< pointer to bond relaxation material for reactive bonds + FEDamageCDF* m_pWCDF; //!< pointer to weak bond recruitment CDF + +private: + FEDamageMaterialUC* m_pDmg; //!< pointer to base material if it is a FEDamageMaterialUC + FEUncoupledReactiveFatigue* m_pFtg; //!< pointer to base material if it is a FEUncoupledReactiveFatigue + double Damage(FEMaterialPoint& mp); //!< return damage in the base material public: double m_wmin; //!< minimum value of relaxation diff --git a/FEBioMix/FEBioMix.cpp b/FEBioMix/FEBioMix.cpp index 76a032469..f22f4d316 100644 --- a/FEBioMix/FEBioMix.cpp +++ b/FEBioMix/FEBioMix.cpp @@ -78,6 +78,7 @@ SOFTWARE.*/ #include "FEPoroTraction.h" #include "FEFluidFlux.h" #include "FESoluteFlux.h" +#include "FESoluteNaturalFlux.hpp" #include "FEPressureStabilization.h" #include "FEMatchingOsmoticCoefficientBC.h" @@ -201,6 +202,18 @@ void FEBioMix::InitModule() REGISTER_FECORE_CLASS(FELogElemFluidFluxY , "wy"); REGISTER_FECORE_CLASS(FELogElemFluidFluxZ , "wz"); REGISTER_FECORE_CLASS(FELogElemPorosity , "porosity"); + REGISTER_FECORE_CLASS_T(FELogElemPermeability_T, 0 , "Kpxx"); + REGISTER_FECORE_CLASS_T(FELogElemPermeability_T, 1 , "Kpyy"); + REGISTER_FECORE_CLASS_T(FELogElemPermeability_T, 2 , "Kpzz"); + REGISTER_FECORE_CLASS_T(FELogElemPermeability_T, 3 , "Kpxy"); + REGISTER_FECORE_CLASS_T(FELogElemPermeability_T, 4 , "Kpyz"); + REGISTER_FECORE_CLASS_T(FELogElemPermeability_T, 5 , "Kpxz"); + REGISTER_FECORE_CLASS_T(FELogElemSolidStress_T, 0, "esxx"); + REGISTER_FECORE_CLASS_T(FELogElemSolidStress_T, 1, "esyy"); + REGISTER_FECORE_CLASS_T(FELogElemSolidStress_T, 2, "eszz"); + REGISTER_FECORE_CLASS_T(FELogElemSolidStress_T, 3, "esxy"); + REGISTER_FECORE_CLASS_T(FELogElemSolidStress_T, 4, "esyz"); + REGISTER_FECORE_CLASS_T(FELogElemSolidStress_T, 5, "esxz"); //====================================================================== // setup the "solute" module (i.e. biphasic-solute) @@ -242,6 +255,7 @@ void FEBioMix::InitModule() //----------------------------------------------------------------------------- // Surface loads REGISTER_FECORE_CLASS(FESoluteFlux, "soluteflux"); + REGISTER_FECORE_CLASS(FESoluteNaturalFlux, "solute natural flux"); //----------------------------------------------------------------------------- // Contact interfaces @@ -384,6 +398,26 @@ void FEBioMix::InitModule() REGISTER_FECORE_CLASS_T(FELogElemSBMConcentration_T, 5, "sbm6"); REGISTER_FECORE_CLASS_T(FELogElemSBMConcentration_T, 6, "sbm7"); REGISTER_FECORE_CLASS_T(FELogElemSBMConcentration_T, 7, "sbm8"); - + + //----------------------------------------------------------------------------- + // domain log data + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSBMConcentration_T, 0, "sbm1_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSBMConcentration_T, 1, "sbm2_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSBMConcentration_T, 2, "sbm3_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSBMConcentration_T, 3, "sbm4_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSBMConcentration_T, 4, "sbm5_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSBMConcentration_T, 5, "sbm6_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSBMConcentration_T, 6, "sbm7_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSBMConcentration_T, 7, "sbm8_integral"); + + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSoluteConcentration_T, 0, "c1_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSoluteConcentration_T, 1, "c2_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSoluteConcentration_T, 2, "c3_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSoluteConcentration_T, 3, "c4_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSoluteConcentration_T, 4, "c5_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSoluteConcentration_T, 5, "c6_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSoluteConcentration_T, 6, "c7_integral"); + REGISTER_FECORE_CLASS_T(FELogDomainIntegralSoluteConcentration_T, 7, "c8_integral"); + febio.SetActiveModule(0); } diff --git a/FEBioMix/FEBioMixData.cpp b/FEBioMix/FEBioMixData.cpp index 00927c539..7856890f6 100644 --- a/FEBioMix/FEBioMixData.cpp +++ b/FEBioMix/FEBioMixData.cpp @@ -32,6 +32,7 @@ SOFTWARE.*/ #include "FETriphasic.h" #include "FEMultiphasic.h" #include "FECore/FEModel.h" +#include //----------------------------------------------------------------------------- double FENodeConcentration::value(int nnode) @@ -305,3 +306,130 @@ double FELogElemPorosity::value(FEElement& el) } return val / (double) nint; } + +//----------------------------------------------------------------------------- +double FELogElemPermeability::value(FEElement& el) +{ + FEDomain* dom = dynamic_cast(el.GetMeshPartition()); + if (dom == nullptr) return 0.0; + FEMaterial* mat = dom->GetMaterial(); + if (mat == nullptr) return 0.0; + + FEBiphasic* biphasic = mat->ExtractProperty(); + if (biphasic == nullptr) return 0.0; + + double val = 0.0; + int nint = el.GaussPoints(); + for (int i = 0; i < nint; ++i) + { + const FEMaterialPoint* mp = el.GetMaterialPoint(i); + mat3ds K = biphasic->Permeability(const_cast(*mp)); + + switch (m_comp) + { + case 0: val += K(0, 0); break; + case 1: val += K(1, 1); break; + case 2: val += K(2, 2); break; + case 3: val += K(0, 1); break; + case 4: val += K(1, 2); break; + case 5: val += K(0, 2); break; + } + } + return val / (double)nint; +} + +//----------------------------------------------------------------------------- +double FELogElemSolidStress::value(FEElement& el) +{ + double val = 0.0; + int nint = el.GaussPoints(); + for (int i = 0; i < nint; ++i) + { + const FEMaterialPoint* mp = el.GetMaterialPoint(i); + const FEBiphasicMaterialPoint* pt = (mp->ExtractData()); + if (pt) + { + mat3ds ss = pt->m_ss; + + switch (m_comp) + { + case 0: val += ss(0, 0); break; + case 1: val += ss(1, 1); break; + case 2: val += ss(2, 2); break; + case 3: val += ss(0, 1); break; + case 4: val += ss(1, 2); break; + case 5: val += ss(0, 2); break; + } + } + } + return val / (double)nint; +} + +//============================================================================= + +FELogDomainIntegralSBMConcentration::FELogDomainIntegralSBMConcentration(FEModel* fem, int sbm) : FELogDomainData(fem) +{ + m_sbm = sbm; +} + +double FELogDomainIntegralSBMConcentration::value(FEDomain& dom) +{ + double sum = 0.0; + if (dynamic_cast(&dom)) + { + FESolidDomain& solidDomain = dynamic_cast(dom); + for (int i = 0; i < solidDomain.Elements(); ++i) + { + FESolidElement& el = solidDomain.Element(i); + double val = 0.0; + int nint = el.GaussPoints(); + double* gw = el.GaussWeights(); + for (int n = 0; n < nint; ++n) + { + FESolutesMaterialPoint* ppt = el.GetMaterialPoint(n)->ExtractData(); + if (ppt) + { + double Jw = solidDomain.detJt(el, n) * gw[n]; + val += ppt->m_sbmr[m_sbm] * Jw; + } + } + + sum += val; + } + } + return sum; +} + +//============================================================================= +FELogDomainIntegralSoluteConcentration::FELogDomainIntegralSoluteConcentration(FEModel* fem, int sol) : FELogDomainData(fem) +{ + m_nsol = sol; +} + +double FELogDomainIntegralSoluteConcentration::value(FEDomain& dom) +{ + double sum = 0.0; + if (dynamic_cast(&dom)) + { + FESolidDomain& solidDomain = dynamic_cast(dom); + for (int i = 0; i < solidDomain.Elements(); ++i) + { + FESolidElement& el = solidDomain.Element(i); + double val = 0.0; + int nint = el.GaussPoints(); + double* gw = el.GaussWeights(); + for (int n = 0; n < nint; ++n) + { + FESolutesMaterialPoint* ppt = el.GetMaterialPoint(n)->ExtractData(); + if (ppt) + { + double Jw = solidDomain.detJt(el, n) * gw[n]; + val += ppt->m_ca[m_nsol] * Jw; + } + } + + sum += val; + } + } + return sum; +} diff --git a/FEBioMix/FEBioMixData.h b/FEBioMix/FEBioMixData.h index ce0ef0d64..d4505b2b8 100644 --- a/FEBioMix/FEBioMixData.h +++ b/FEBioMix/FEBioMixData.h @@ -29,6 +29,7 @@ SOFTWARE.*/ #pragma once #include "FECore/NodeDataRecord.h" #include "FECore/ElementDataRecord.h" +#include //============================================================================= // N O D E D A T A @@ -251,3 +252,72 @@ class FELogElemPorosity : public FELogElemData FELogElemPorosity(FEModel* fem) : FELogElemData(fem) {} double value(FEElement& el); }; + +//----------------------------------------------------------------------------- +class FELogElemPermeability : public FELogElemData +{ +public: + FELogElemPermeability(FEModel* fem, int n) : FELogElemData(fem) { m_comp = n; } + double value(FEElement& el); +protected: + int m_comp; +}; + +template +class FELogElemPermeability_T : public FELogElemPermeability +{ +public: FELogElemPermeability_T(FEModel* fem) : FELogElemPermeability(fem, n) {} +}; + +//----------------------------------------------------------------------------- +class FELogElemSolidStress : public FELogElemData +{ +public: + FELogElemSolidStress(FEModel* fem, int n) : FELogElemData(fem) { m_comp = n; } + double value(FEElement& el); +protected: + int m_comp; +}; + +template +class FELogElemSolidStress_T : public FELogElemSolidStress +{ +public: FELogElemSolidStress_T(FEModel* fem) : FELogElemSolidStress(fem, n) {} +}; + +//============================================================================= +// D O M A I N D A T A +//============================================================================= + +class FELogDomainIntegralSBMConcentration : public FELogDomainData +{ +public: + FELogDomainIntegralSBMConcentration(FEModel* fem, int sbm); + double value(FEDomain& dom) override; + +protected: + int m_sbm; +}; + +template class FELogDomainIntegralSBMConcentration_T : public FELogDomainIntegralSBMConcentration +{ +public: + FELogDomainIntegralSBMConcentration_T(FEModel* pfem) : FELogDomainIntegralSBMConcentration(pfem, N) {} +}; + +//------------------------------------------------------------------------------------------- +class FELogDomainIntegralSoluteConcentration : public FELogDomainData +{ +public: + FELogDomainIntegralSoluteConcentration(FEModel* fem, int sol); + double value(FEDomain& dom) override; + +protected: + int m_nsol; +}; + +template class FELogDomainIntegralSoluteConcentration_T : public FELogDomainIntegralSoluteConcentration +{ +public: + FELogDomainIntegralSoluteConcentration_T(FEModel* pfem) : FELogDomainIntegralSoluteConcentration(pfem, N) {} +}; diff --git a/FEBioMix/FEBioMixPlot.cpp b/FEBioMix/FEBioMixPlot.cpp index 0070b4172..db63d485a 100644 --- a/FEBioMix/FEBioMixPlot.cpp +++ b/FEBioMix/FEBioMixPlot.cpp @@ -96,9 +96,6 @@ bool FEPlotMixtureFluidFlowRate::Save(FESurface &surf, FEDataStream &a) FESurface* pcs = &surf; if (pcs == 0) return false; - // Evaluate this field only for a specific domain, by checking domain name - if (pcs->GetName() != GetDomainName()) return false; - int NF = pcs->Elements(); double fn = 0; // initialize diff --git a/FEBioMix/FEBiphasic.cpp b/FEBioMix/FEBiphasic.cpp index 02b933620..5a01266bc 100644 --- a/FEBioMix/FEBiphasic.cpp +++ b/FEBioMix/FEBiphasic.cpp @@ -100,28 +100,40 @@ FEBiphasic::FEBiphasic(FEModel* pfem) : FEMaterial(pfem) m_pAmom = 0; } +//----------------------------------------------------------------------------- +// initialize +bool FEBiphasic::Init() +{ + if (!m_pSolid->Init()) return false; + if (!m_pPerm->Init()) return false; + if (m_pSupp && !m_pSupp->Init()) return false; + if (m_pAmom && !m_pAmom->Init()) return false; + return true; +} + //----------------------------------------------------------------------------- // returns a pointer to a new material point object FEMaterialPoint* FEBiphasic::CreateMaterialPointData() { - // create biphasic material point - FEBiphasicMaterialPoint* pt = new FEBiphasicMaterialPoint(nullptr); - // create the solid material point FEMaterialPoint* ep = m_pSolid->CreateMaterialPointData(); - // create the permeability - FEMaterialPoint* pm = m_pPerm->CreateMaterialPointData(); - if (pm) - { - pm->SetNext(ep); - pt->SetNext(pm); - } - else pt->SetNext(ep); - + // create biphasic material point + FEBiphasicMaterialPoint* pt = new FEBiphasicMaterialPoint(ep); + return pt; } +//----------------------------------------------------------------------------- +// update specialized material points +void FEBiphasic::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) +{ + m_pSolid->UpdateSpecializedMaterialPoints(mp, tp); + m_pPerm->UpdateSpecializedMaterialPoints(mp, tp); + if (m_pSupp) m_pSupp->UpdateSpecializedMaterialPoints(mp, tp); + if (m_pAmom) m_pAmom->UpdateSpecializedMaterialPoints(mp, tp); +} + //----------------------------------------------------------------------------- //! Porosity in current configuration double FEBiphasic::Porosity(FEMaterialPoint& pt) diff --git a/FEBioMix/FEBiphasic.h b/FEBioMix/FEBiphasic.h index fc4bdea75..8a8a0de0a 100644 --- a/FEBioMix/FEBiphasic.h +++ b/FEBioMix/FEBiphasic.h @@ -86,6 +86,12 @@ class FEBIOMIX_API FEBiphasic : public FEMaterial FEElasticMaterial* GetElasticMaterial() { return m_pSolid; } public: + //! initialize + bool Init() override; + + //! specialized material points + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; + //! calculate stress at material point mat3ds Stress(FEMaterialPoint& pt); diff --git a/FEBioMix/FEBiphasicContactSurface.cpp b/FEBioMix/FEBiphasicContactSurface.cpp index f9e57cb80..fe477d86c 100644 --- a/FEBioMix/FEBiphasicContactSurface.cpp +++ b/FEBioMix/FEBiphasicContactSurface.cpp @@ -31,6 +31,12 @@ SOFTWARE.*/ #include "FEBiphasic.h" #include +void FEBiphasicContactPoint::Serialize(DumpStream& ar) +{ + FEContactMaterialPoint::Serialize(ar); + ar & m_Lmp & m_pg & m_mueff & m_fls; +} + //----------------------------------------------------------------------------- FEBiphasicContactSurface::FEBiphasicContactSurface(FEModel* pfem) : FEContactSurface(pfem) { diff --git a/FEBioMix/FEBiphasicContactSurface.h b/FEBioMix/FEBiphasicContactSurface.h index e264229bf..fd79644e8 100644 --- a/FEBioMix/FEBiphasicContactSurface.h +++ b/FEBioMix/FEBiphasicContactSurface.h @@ -38,6 +38,8 @@ class FEBIOMIX_API FEBiphasicContactPoint : public FEContactMaterialPoint double m_pg; //!< pressure "gap" for biphasic contact double m_mueff; //!< effective friction coefficient double m_fls; //!< local fluid load support + + void Serialize(DumpStream& ar) override; }; //----------------------------------------------------------------------------- diff --git a/FEBioMix/FEBiphasicSolidDomain.cpp b/FEBioMix/FEBiphasicSolidDomain.cpp index 0f866c5b2..0f9d75f2a 100644 --- a/FEBioMix/FEBiphasicSolidDomain.cpp +++ b/FEBioMix/FEBiphasicSolidDomain.cpp @@ -59,6 +59,17 @@ const FEDofList& FEBiphasicSolidDomain::GetDOFList() const return m_dof; } +//----------------------------------------------------------------------------- +void FEBiphasicSolidDomain::Serialize(DumpStream& ar) +{ + FESolidDomain::Serialize(ar); + + if (ar.IsShallow() == false) + { + ar & m_nodePressure; + } +} + //----------------------------------------------------------------------------- void FEBiphasicSolidDomain::SetMaterial(FEMaterial* pmat) { diff --git a/FEBioMix/FEBiphasicSolidDomain.h b/FEBioMix/FEBiphasicSolidDomain.h index a61852f65..59dfda19b 100644 --- a/FEBioMix/FEBiphasicSolidDomain.h +++ b/FEBioMix/FEBiphasicSolidDomain.h @@ -67,6 +67,9 @@ class FEBIOMIX_API FEBiphasicSolidDomain : public FESolidDomain, public FEBiphas //! get the total dof list const FEDofList& GetDOFList() const override; + //! serialization + void Serialize(DumpStream& ar) override; + public: // update domain data void Update(const FETimeInfo& tp) override; diff --git a/FEBioMix/FEBiphasicSolute.cpp b/FEBioMix/FEBiphasicSolute.cpp index 4b8d7f754..4c87e5afb 100644 --- a/FEBioMix/FEBiphasicSolute.cpp +++ b/FEBioMix/FEBiphasicSolute.cpp @@ -82,6 +82,11 @@ bool FEBiphasicSolute::Init() // because it is used in FESolute::Init() m_pSolute->SetSoluteLocalID(0); + if (!m_pSolid->Init()) return false; + if (!m_pPerm->Init()) return false; + if (!m_pOsmC->Init()) return false; + if (!m_pSolute->Init()) return false; + // Call base class which calls the Init member of all properties if (FEMaterial::Init() == false) return false; @@ -94,6 +99,16 @@ bool FEBiphasicSolute::Init() return true; } +//----------------------------------------------------------------------------- +// update specialized material points +void FEBiphasicSolute::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) +{ + m_pSolid->UpdateSpecializedMaterialPoints(mp, tp); + m_pPerm->UpdateSpecializedMaterialPoints(mp, tp); + m_pOsmC->UpdateSpecializedMaterialPoints(mp, tp); + m_pSolute->UpdateSpecializedMaterialPoints(mp, tp); +} + //----------------------------------------------------------------------------- void FEBiphasicSolute::Serialize(DumpStream& ar) { diff --git a/FEBioMix/FEBiphasicSolute.h b/FEBioMix/FEBiphasicSolute.h index 7cc8ab749..efab0d6b5 100644 --- a/FEBioMix/FEBiphasicSolute.h +++ b/FEBioMix/FEBiphasicSolute.h @@ -67,6 +67,9 @@ class FEBIOMIX_API FEBiphasicSolute : public FEMaterial, public FESoluteInterfac public: bool Init() override; + + //! specialized material points + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; //! serialization void Serialize(DumpStream& ar) override; diff --git a/FEBioMix/FEMultiphasic.cpp b/FEBioMix/FEMultiphasic.cpp index d1fe5a7b8..605d05268 100644 --- a/FEBioMix/FEMultiphasic.cpp +++ b/FEBioMix/FEMultiphasic.cpp @@ -336,6 +336,19 @@ bool FEMultiphasic::Init() m_pSolute[i]->SetSoluteLocalID(i); } + if (m_pSolid->Init() == false) return false; + if (m_pPerm->Init() == false) return false; + if (m_pOsmC->Init() == false) return false; + if (m_pSupp && (m_pSupp->Init() == false)) return false; + for (int i=0; iInit() == false) return false; + for (int i=0; iInit() == false) return false; + for (int i=0; iInit() == false) return false; + for (int i=0; iInit() == false) return false; + // call the base class. // This also initializes all properties if (FEMaterial::Init() == false) return false; @@ -365,6 +378,24 @@ bool FEMultiphasic::Init() return true; } +//----------------------------------------------------------------------------- +// update specialized material points +void FEMultiphasic::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) +{ + m_pSolid->UpdateSpecializedMaterialPoints(mp, tp); + m_pPerm->UpdateSpecializedMaterialPoints(mp, tp); + m_pOsmC->UpdateSpecializedMaterialPoints(mp, tp); + if (m_pSupp) m_pSupp->UpdateSpecializedMaterialPoints(mp, tp); + for (int i=0; iUpdateSpecializedMaterialPoints(mp, tp); + for (int i=0; iUpdateSpecializedMaterialPoints(mp, tp); + for (int i=0; iUpdateSpecializedMaterialPoints(mp, tp); + for (int i=0; iUpdateSpecializedMaterialPoints(mp, tp); +} + //----------------------------------------------------------------------------- void FEMultiphasic::Serialize(DumpStream& ar) { @@ -986,3 +1017,124 @@ vec3d FEMultiphasic::CurrentDensity(FEMaterialPoint& pt) return Ie; } + +//----------------------------------------------------------------------------- +//! Evaluate effective permeability +mat3ds FEMultiphasic::EffectivePermeability(FEMaterialPoint& pt) +{ + // evaluate the hydraulic permeability + mat3ds K = GetPermeability()->Permeability(pt); + + const int nsol = Solutes(); + + // if there are no solutes in this mixture, we're done + if (nsol == 0) return K; + + // initialize effective permeability + mat3ds Ke = K.inverse(); + + // fluid volume fraction (porosity) in current configuration + double phiw = Porosity(pt); + double tmp = m_Rgas*m_Tabs/phiw; + mat3dd I(1.0); + + FESolutesMaterialPoint& spt = *(pt.ExtractData()); + + // add solute contributions + for (int isol=0; isolm_pDiff->Diffusivity(pt); + // solute free diffusivity + double D0 = m_pSolute[isol]->m_pDiff->Free_Diffusivity(pt); + + Ke += (I - D/D0)*(tmp*ca/D0); + } + + return Ke.inverse(); +} + +//----------------------------------------------------------------------------- +//! Evaluate tangent of effective permeability w.r.t. strain +tens4dmm FEMultiphasic::TangentPermeabilityStrain(FEMaterialPoint& pt, const mat3ds& Ke) +{ + // get the hydraulic permeability strain tangent + tens4dmm dKdE = GetPermeability()->Tangent_Permeability_Strain(pt); + + const int nsol = Solutes(); + + // if there are no solutes in this mixture, we're done + if (nsol == 0) return dKdE; + + // evaluate the inverse of the hydraulic permeability + mat3ds Ki = GetPermeability()->Permeability(pt).inverse(); + + // fluid volume fraction (porosity) in current configuration + double phiw = Porosity(pt); + mat3dd I(1.0); + + FEElasticMaterialPoint& ept = *(pt.ExtractData()); + FESolutesMaterialPoint& spt = *(pt.ExtractData()); + + tens4dmm dKedE; + dKedE.zero(); + + // add solute contributions + for (int isol=0; isolm_pDiff->Free_Diffusivity(pt); + // solute diffusivity in mixture, normalized by D0 + mat3ds D = m_pSolute[isol]->m_pDiff->Diffusivity(pt)/D0; + // solute diffusiviety strain tangent, normalized by D0 + tens4dmm dDdE = m_pSolute[isol]->m_pDiff->Tangent_Diffusivity_Strain(pt)/D0; + + dKedE += (dDdE + (dyad4mm(I, D) + dyad4mm(D,I) - dyad4mm(I,I))*2 + - dyad1mm(D,I) + dyad1mm(I-D,I)*(1./phiw - ept.m_J*spt.m_dkdJ[isol]/spt.m_k[isol]))*ca/D0; + } + + dKedE = dKedE*(m_Rgas*m_Tabs/phiw) + ddot(dyad2mm(Ki,Ki), dKdE); + + return ddot(dyad2mm(Ke, Ke), dKedE); +} + +//----------------------------------------------------------------------------- +//! Evaluate tangent of effective permeability w.r.t. concentration +mat3ds FEMultiphasic::TangentPermeabilityConcentration(FEMaterialPoint& pt, const int sol, const mat3ds& Ke) +{ + mat3ds dKedc(0,0,0,0,0,0); + + const int nsol = Solutes(); + + if (nsol == 0) return dKedc; + + // fluid volume fraction (porosity) in current configuration + double phiw = Porosity(pt); + mat3dd I(1.0); + + FESolutesMaterialPoint& spt = *(pt.ExtractData()); + + // add solute contributions + for (int isol=0; isolm_pDiff->Free_Diffusivity(pt); + // solute diffusivity in mixture, normalized by D0 + mat3ds D = m_pSolute[isol]->m_pDiff->Diffusivity(pt)/D0; + // solute free diffusivity concentration tangent + double dD0dc = m_pSolute[isol]->m_pDiff->Tangent_Free_Diffusivity_Concentration(pt, sol); + // solute diffusivity concentration tangent + mat3ds dDdc = m_pSolute[isol]->m_pDiff->Tangent_Diffusivity_Concentration(pt,sol); + + double kd = (isol == sol) ? 1 : 0; + dKedc += (I-D)*((spt.m_dkdc[isol][sol]*spt.m_c[isol] + spt.m_k[isol]*kd - dD0dc*ca/D0)/D0) + - (dDdc - D*dD0dc)*(ca/D0/D0); + } + + dKedc *= m_Rgas*m_Tabs/phiw; + + return -(Ke*dKedc*Ke).sym(); +} diff --git a/FEBioMix/FEMultiphasic.h b/FEBioMix/FEMultiphasic.h index bc5e43fcb..9b4643933 100644 --- a/FEBioMix/FEMultiphasic.h +++ b/FEBioMix/FEMultiphasic.h @@ -47,6 +47,9 @@ class FEBIOMIX_API FEMultiphasic : public FEMaterial, public FESoluteInterface //! initialization bool Init() override; + + //! specialized material points + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; //! Serialization void Serialize(DumpStream& ar) override; @@ -130,13 +133,23 @@ class FEBIOMIX_API FEMultiphasic : public FEMaterial, public FESoluteInterface //! SBM charge number int SBMChargeNumber(const int sbm) { return m_pSBM[sbm]->ChargeNumber(); } - //! SBM actual concentration (molar concentration in current configuration) + //! SBM actual concentration (molar concentration per fluid volume in current configuration) double SBMConcentration(FEMaterialPoint& pt, const int sbm) { FEElasticMaterialPoint& ept = *pt.ExtractData(); FEBiphasicMaterialPoint& bpt = *pt.ExtractData(); FESolutesMaterialPoint& spt = *pt.ExtractData(); return spt.m_sbmr[sbm]/(ept.m_J-bpt.m_phi0)/SBMMolarMass(sbm); } + + //! SBM areal concentration (mole per shell area) -- should only be called from shell domains + double SBMArealConcentration(FEMaterialPoint& pt, const int sbm) { + FEShellElement* sel = dynamic_cast(pt.m_elem); + assert(sel); + double h = sel->Evaluate(sel->m_ht, pt.m_index); // shell thickness + FEElasticMaterialPoint& ept = *pt.ExtractData(); + FESolutesMaterialPoint& spt = *pt.ExtractData(); + return spt.m_sbmr[sbm]/SBMMolarMass(sbm)*h/ept.m_J; + } //! SBM referential volume fraction double SBMReferentialVolumeFraction(FEMaterialPoint& pt, const int sbm) { @@ -156,6 +169,12 @@ class FEBIOMIX_API FEMultiphasic : public FEMaterial, public FESoluteInterface //! Add a membrane reaction void AddMembraneReaction(FEMembraneReaction* pcr); +public: + //! Evaluate effective permeability + mat3ds EffectivePermeability(FEMaterialPoint& pt); + tens4dmm TangentPermeabilityStrain(FEMaterialPoint& pt, const mat3ds& Ke); + mat3ds TangentPermeabilityConcentration(FEMaterialPoint& pt, const int sol, const mat3ds& Ke); + // solute interface public: int Solutes() override { return (int)m_pSolute.size(); } diff --git a/FEBioMix/FESlidingInterface2.cpp b/FEBioMix/FESlidingInterface2.cpp index 231b44824..28e9f53bf 100644 --- a/FEBioMix/FESlidingInterface2.cpp +++ b/FEBioMix/FESlidingInterface2.cpp @@ -74,16 +74,12 @@ FESlidingSurface2::Data::Data() void FESlidingSurface2::Data::Serialize(DumpStream& ar) { FEBiphasicContactPoint::Serialize(ar); - ar & m_gap; - ar & m_nu; - ar & m_rs; ar & m_Lmd; - ar & m_Lmp; ar & m_epsn; ar & m_epsp; - ar & m_pg; ar & m_p1; - ar & m_Ln; + ar & m_nu; + ar & m_rs; } //----------------------------------------------------------------------------- @@ -494,6 +490,10 @@ FESlidingInterface2::FESlidingInterface2(FEModel* pfem) : FEContactInterface(pfe m_dofP = pfem->GetDOFIndex("p"); + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMix/FESlidingInterface3.cpp b/FEBioMix/FESlidingInterface3.cpp index 2b26d37f7..1f7a0b199 100644 --- a/FEBioMix/FESlidingInterface3.cpp +++ b/FEBioMix/FESlidingInterface3.cpp @@ -82,18 +82,14 @@ FESlidingSurface3::Data::Data() void FESlidingSurface3::Data::Serialize(DumpStream& ar) { FEBiphasicContactPoint::Serialize(ar); - ar & m_gap; - ar & m_nu; - ar & m_rs; ar & m_Lmd; - ar & m_Lmp; ar & m_Lmc; ar & m_epsn; ar & m_epsp; ar & m_epsc; - ar & m_pg; ar & m_cg; - ar & m_Ln; + ar & m_nu; + ar & m_rs; } //----------------------------------------------------------------------------- diff --git a/FEBioMix/FESlidingInterface3.h b/FEBioMix/FESlidingInterface3.h index fea509975..30a6db06b 100644 --- a/FEBioMix/FESlidingInterface3.h +++ b/FEBioMix/FESlidingInterface3.h @@ -43,7 +43,6 @@ class FEBIOMIX_API FESlidingSurface3 : public FEBiphasicContactSurface void Serialize(DumpStream& ar) override; public: - double m_gap; //!< gap function at integration points double m_Lmd; //!< Lagrange multipliers for displacements double m_Lmc; //!< Lagrange multipliers for solute concentrations double m_epsn; //!< displacement penalty factors diff --git a/FEBioMix/FESlidingInterfaceBiphasic.cpp b/FEBioMix/FESlidingInterfaceBiphasic.cpp index 1acb354d0..d06edbdf3 100644 --- a/FEBioMix/FESlidingInterfaceBiphasic.cpp +++ b/FEBioMix/FESlidingInterfaceBiphasic.cpp @@ -84,24 +84,18 @@ FESlidingSurfaceBiphasic::Data::Data() void FESlidingSurfaceBiphasic::Data::Serialize(DumpStream& ar) { FEBiphasicContactPoint::Serialize(ar); - ar & m_gap; ar & m_dg; - ar & m_nu; + ar & m_Lmd; + ar & m_Lmt; + ar & m_epsn; + ar & m_epsp; + ar & m_p1; + ar & m_nu; ar & m_s1; + ar & m_tr; ar & m_rs; ar & m_rsp; - ar & m_Lmd; - ar & m_Lmt; - ar & m_Lmp; - ar & m_epsn; - ar & m_epsp; - ar & m_pg; - ar & m_p1; - ar & m_Ln; - ar & m_bstick; - ar & m_tr; - ar & m_mueff; - ar & m_fls; + ar & m_bstick; } //----------------------------------------------------------------------------- @@ -555,6 +549,10 @@ FESlidingInterfaceBiphasic::FESlidingInterfaceBiphasic(FEModel* pfem) : FEContac m_dofP = pfem->GetDOFIndex("p"); + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMix/FESlidingInterfaceBiphasicMixed.cpp b/FEBioMix/FESlidingInterfaceBiphasicMixed.cpp index 202e71203..27d9492f7 100644 --- a/FEBioMix/FESlidingInterfaceBiphasicMixed.cpp +++ b/FEBioMix/FESlidingInterfaceBiphasicMixed.cpp @@ -85,23 +85,18 @@ FESlidingSurfaceBiphasicMixed::Data::Data() void FESlidingSurfaceBiphasicMixed::Data::Serialize(DumpStream& ar) { FEBiphasicContactPoint::Serialize(ar); - ar & m_gap; ar & m_dg; - ar & m_nu; + ar & m_Lmd; + ar & m_Lmt; + ar & m_epsn; + ar & m_epsp; + ar & m_p1; + ar & m_nu; ar & m_s1; + ar & m_tr; ar & m_rs; ar & m_rsp; - ar & m_Lmd; - ar & m_Lmt; - ar & m_Lmp; - ar & m_epsn; - ar & m_epsp; - ar & m_pg; - ar & m_p1; - ar & m_Ln; - ar & m_bstick; - ar & m_tr; - ar & m_mueff; + ar & m_bstick; } //----------------------------------------------------------------------------- @@ -600,6 +595,10 @@ FESlidingInterfaceBiphasicMixed::FESlidingInterfaceBiphasicMixed(FEModel* pfem) m_dofP = pfem->GetDOFIndex("p"); + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMix/FESlidingInterfaceMP.cpp b/FEBioMix/FESlidingInterfaceMP.cpp index f47c17865..f8758292a 100644 --- a/FEBioMix/FESlidingInterfaceMP.cpp +++ b/FEBioMix/FESlidingInterfaceMP.cpp @@ -80,18 +80,14 @@ FESlidingSurfaceMP::Data::Data() void FESlidingSurfaceMP::Data::Serialize(DumpStream& ar) { FEBiphasicContactPoint::Serialize(ar); - ar & m_gap; - ar & m_nu; - ar & m_rs; ar & m_Lmd; - ar & m_Lmp; - ar & m_Lmc; ar & m_epsn; ar & m_epsp; + ar & m_nu; + ar & m_rs; + ar & m_Lmc; ar & m_epsc; - ar & m_pg; ar & m_cg; - ar & m_Ln; } //----------------------------------------------------------------------------- diff --git a/FEBioMix/FESoluteNaturalFlux.cpp b/FEBioMix/FESoluteNaturalFlux.cpp new file mode 100644 index 000000000..de2f23659 --- /dev/null +++ b/FEBioMix/FESoluteNaturalFlux.cpp @@ -0,0 +1,210 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + + + +#include "stdafx.h" +#include "FESoluteNaturalFlux.hpp" +#include "FEMultiphasic.h" +#include +#include + +//----------------------------------------------------------------------------- +BEGIN_FECORE_CLASS(FESoluteNaturalFlux, FESurfaceLoad) + ADD_PARAMETER(m_bshellb, "shell_bottom"); + ADD_PARAMETER(m_isol , "solute_id"); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +//! constructor +FESoluteNaturalFlux::FESoluteNaturalFlux(FEModel* pfem) : FESurfaceLoad(pfem), m_dofC(pfem), m_dofU(pfem), m_dofP(pfem) +{ + m_bshellb = false; + m_isol = 0; +} + +//----------------------------------------------------------------------------- +//! allocate storage +void FESoluteNaturalFlux::SetSurface(FESurface* ps) +{ + FESurfaceLoad::SetSurface(ps); +} + +//----------------------------------------------------------------------------- +//! serialization +void FESoluteNaturalFlux::Serialize(DumpStream& ar) +{ + FESurfaceLoad::Serialize(ar); + + if (ar.IsShallow() == false) + { + ar & m_dofC & m_dofU & m_dofP; + } +} + +//----------------------------------------------------------------------------- +bool FESoluteNaturalFlux::Init() +{ + if (m_isol == -1) return false; + + // set up the dof lists + FEModel* fem = GetFEModel(); + m_dofC.Clear(); + m_dofU.Clear(); + m_dofP.Clear(); + if (m_bshellb == false) + { + m_dofC.AddDof(fem->GetDOFIndex("concentration", m_isol - 1)); + + m_dofU.AddDof(fem->GetDOFIndex("x")); + m_dofU.AddDof(fem->GetDOFIndex("y")); + m_dofU.AddDof(fem->GetDOFIndex("z")); + + m_dofP.AddDof(fem->GetDOFIndex("p")); + } + else + { + m_dofC.AddDof(fem->GetDOFIndex("shell concentration", m_isol - 1)); + + m_dofU.AddDof(fem->GetDOFIndex("sx")); + m_dofU.AddDof(fem->GetDOFIndex("sy")); + m_dofU.AddDof(fem->GetDOFIndex("sz")); + + m_dofP.AddDof(fem->GetDOFIndex("q")); + } + m_dof.AddDofs(m_dofU); + m_dof.AddDofs(m_dofP); + m_dof.AddDofs(m_dofC); + return FESurfaceLoad::Init(); +} + +//----------------------------------------------------------------------------- +void FESoluteNaturalFlux::LoadVector(FEGlobalVector& R, const FETimeInfo& tp) +{ + double dt = tp.timeIncrement; + + m_psurf->SetShellBottom(m_bshellb); + + FESoluteNaturalFlux* flux = this; + m_psurf->LoadVector(R, m_dofC, false, [=](FESurfaceMaterialPoint& mp, const FESurfaceDofShape& dof_a, std::vector& fa) { + + // get surface element + FESurfaceElement& el = *mp.SurfaceElement(); + // get underlying solid element + FEElement* pe = el.m_elem[0]; + FEMaterial* pm = GetFEModel()->GetMaterial(pe->GetMatID()); + // get the local solute id + FESoluteInterface* psi = dynamic_cast(pm); + if (psi == nullptr) { + fa[0] = 0; + return; + } + int sid = psi->FindLocalSoluteID(flux->m_isol); + + // get element-averaged fluid flux and actual solute concentration + vec3d w(0,0,0); + double c = 0; + int nint = pe->GaussPoints(); + for (int n=0; nGetMaterialPoint(n); + FEBiphasicMaterialPoint& pb = *(pt.ExtractData()); + FESolutesMaterialPoint& ps = *(pt.ExtractData()); + w += pb.m_w; + c += ps.m_ca[sid]; + } + w /= nint; + c /= nint; + + // evaluate desired natural solute flux + vec3d dxt = mp.dxr ^ mp.dxs; + double jn = c*(w*dxt); + if (flux->m_bshellb) jn = -jn; + + // molar flow rate + double f = jn* dt; + + double H_i = dof_a.shape; + fa[0] = H_i * f; + }); +} + +//----------------------------------------------------------------------------- +void FESoluteNaturalFlux::StiffnessMatrix(FELinearSystem& LS, const FETimeInfo& tp) +{ + // time increment + double dt = tp.timeIncrement; + + m_psurf->SetShellBottom(m_bshellb); + + // evaluate the stiffness contribution + FESoluteNaturalFlux* flux = this; + m_psurf->LoadStiffness(LS, m_dofC, m_dofU, [=](FESurfaceMaterialPoint& mp, const FESurfaceDofShape& dof_a, const FESurfaceDofShape& dof_b, matrix& Kab) { + + // get surface element + FESurfaceElement& el = *mp.SurfaceElement(); + // get underlying solid element + FEElement* pe = el.m_elem[0]; + FEMaterial* pm = GetFEModel()->GetMaterial(pe->GetMatID()); + // get the local solute id + FESoluteInterface* psi = dynamic_cast(pm); + if (psi == nullptr) return; + int sid = psi->FindLocalSoluteID(flux->m_isol); + + // get element-averaged fluid flux and actual solute concentration + vec3d w(0,0,0); + double c = 0; + int nint = pe->GaussPoints(); + for (int n=0; nGetMaterialPoint(n); + FEBiphasicMaterialPoint& pb = *(pt.ExtractData()); + FESolutesMaterialPoint& ps = *(pt.ExtractData()); + w += pb.m_w; + c += ps.m_ca[sid]; + } + w /= nint; + c /= nint; + + // shape functions and derivatives + double H_i = dof_a.shape; + double Gr_j = dof_b.shape_deriv_r; + double Gs_j = dof_b.shape_deriv_s; + + // calculate surface normal + vec3d dxt = mp.dxr ^ mp.dxs; + vec3d nu = dxt.normalized(); + double jn = c*(w*nu); + if (flux->m_bshellb) jn = -jn; + + // calculate stiffness component + vec3d t1 = nu*jn; + vec3d t2 = mp.dxs*Gr_j - mp.dxr*Gs_j; + vec3d kab = (t1 ^ t2)*(H_i)*dt; + + Kab[0][0] = kab.x; + Kab[0][1] = kab.y; + Kab[0][2] = kab.z; + }); +} diff --git a/FEBioMix/FESoluteNaturalFlux.hpp b/FEBioMix/FESoluteNaturalFlux.hpp new file mode 100644 index 000000000..3debb45f0 --- /dev/null +++ b/FEBioMix/FESoluteNaturalFlux.hpp @@ -0,0 +1,71 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2022 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + + + +#pragma once +#include +#include +#include "febiomix_api.h" + +//----------------------------------------------------------------------------- +//! The flux surface is a surface domain that sustains a solute natural flux boundary +//! condition +//! +class FEBIOMIX_API FESoluteNaturalFlux : public FESurfaceLoad +{ +public: + //! constructor + FESoluteNaturalFlux(FEModel* pfem); + + //! Initialization + bool Init() override; + + //! serialization + void Serialize(DumpStream& ar) override; + + //! Set the surface to apply the load to + void SetSurface(FESurface* ps) override; + + void SetSolute(int isol) { m_isol = isol; } + + //! calculate flux stiffness + void StiffnessMatrix(FELinearSystem& LS, const FETimeInfo& tp) override; + + //! calculate residual + void LoadVector(FEGlobalVector& R, const FETimeInfo& tp) override; + +protected: + bool m_bshellb; //!< flag for prescribing flux on shell bottom + int m_isol; //!< solute index + +protected: + FEDofList m_dofC; + FEDofList m_dofU; + FEDofList m_dofP; + + DECLARE_FECORE_CLASS(); +}; diff --git a/FEBioMix/FETiedBiphasicInterface.cpp b/FEBioMix/FETiedBiphasicInterface.cpp index 68fc83de3..bd1852282 100644 --- a/FEBioMix/FETiedBiphasicInterface.cpp +++ b/FEBioMix/FETiedBiphasicInterface.cpp @@ -78,11 +78,9 @@ void FETiedBiphasicSurface::Data::Serialize(DumpStream& ar) ar & m_nu; ar & m_rs; ar & m_Lmd; - ar & m_Lmp; + ar & m_tr; ar & m_epsn; ar & m_epsp; - ar & m_pg; - ar & m_tr; } //----------------------------------------------------------------------------- @@ -238,6 +236,10 @@ FETiedBiphasicInterface::FETiedBiphasicInterface(FEModel* pfem) : FEContactInter m_dofP = pfem->GetDOFIndex("p"); + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMix/FETiedMultiphasicInterface.cpp b/FEBioMix/FETiedMultiphasicInterface.cpp index 8a15e2661..bc3817c3e 100644 --- a/FEBioMix/FETiedMultiphasicInterface.cpp +++ b/FEBioMix/FETiedMultiphasicInterface.cpp @@ -81,11 +81,11 @@ void FETiedMultiphasicSurface::Data::Serialize(DumpStream& ar) ar & m_nu; ar & m_rs; ar & m_Lmd; - ar & m_Lmp; ar & m_epsn; ar & m_epsp; + ar & m_Lmc; ar & m_epsc; - ar & m_pg; + ar & m_cg; } //----------------------------------------------------------------------------- @@ -317,6 +317,10 @@ FETiedMultiphasicInterface::FETiedMultiphasicInterface(FEModel* pfem) : FEContac m_dofP = pfem->GetDOFIndex("p"); m_dofC = pfem->GetDOFIndex("concentration", 0); + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); } diff --git a/FEBioMix/FETriphasic.cpp b/FEBioMix/FETriphasic.cpp index 4a8bae313..9e36b5102 100644 --- a/FEBioMix/FETriphasic.cpp +++ b/FEBioMix/FETriphasic.cpp @@ -87,6 +87,12 @@ bool FETriphasic::Init() m_pSolute[0]->SetSoluteLocalID(0); m_pSolute[1]->SetSoluteLocalID(1); + if (m_pSolid->Init() == false) return false; + if (m_pPerm->Init() == false) return false; + if (m_pOsmC->Init() == false) return false; + for (int i=0; iInit() == false) return false; + // Call base class initialization. This will also initialize all properties. if (FEMaterial::Init() == false) return false; @@ -115,6 +121,17 @@ bool FETriphasic::Init() return true; } +//----------------------------------------------------------------------------- +// update specialized material points +void FETriphasic::UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) +{ + m_pSolid->UpdateSpecializedMaterialPoints(mp, tp); + m_pPerm->UpdateSpecializedMaterialPoints(mp, tp); + m_pOsmC->UpdateSpecializedMaterialPoints(mp, tp); + for (int i=0; iUpdateSpecializedMaterialPoints(mp, tp); +} + //----------------------------------------------------------------------------- void FETriphasic::Serialize(DumpStream& ar) { diff --git a/FEBioMix/FETriphasic.h b/FEBioMix/FETriphasic.h index 8400f58d3..5508ddf9e 100644 --- a/FEBioMix/FETriphasic.h +++ b/FEBioMix/FETriphasic.h @@ -40,6 +40,9 @@ class FEBIOMIX_API FETriphasic : public FEMaterial, public FESoluteInterface // initialization bool Init() override; + + //! specialized material points + void UpdateSpecializedMaterialPoints(FEMaterialPoint& mp, const FETimeInfo& tp) override; // serialization void Serialize(DumpStream& ar) override; diff --git a/FEBioOpt/FEConstrainedLMOptimizeMethod.cpp b/FEBioOpt/FEConstrainedLMOptimizeMethod.cpp index 57de27e48..2d2f6de87 100644 --- a/FEBioOpt/FEConstrainedLMOptimizeMethod.cpp +++ b/FEBioOpt/FEConstrainedLMOptimizeMethod.cpp @@ -42,34 +42,9 @@ BEGIN_FECORE_CLASS(FEConstrainedLMOptimizeMethod, FEOptimizeMethod) ADD_PARAMETER(m_tau , "tau" ); ADD_PARAMETER(m_fdiff , "f_diff_scale"); ADD_PARAMETER(m_nmax , "max_iter" ); + ADD_PARAMETER(m_scaleParams, "scale_parameters"); END_FECORE_CLASS(); -//----------------------------------------------------------------------------- -FEConstrainedLMOptimizeMethod* FEConstrainedLMOptimizeMethod::m_pThis = 0; - -//----------------------------------------------------------------------------- -void clevmar_cb(double *p, double *hx, int m, int n, void *adata) -{ - FEConstrainedLMOptimizeMethod* pLM = (FEConstrainedLMOptimizeMethod*) adata; - - // get the optimization data - FEOptimizeData& opt = *pLM->GetOptimizeData(); - FEObjectiveFunction& obj = opt.GetObjective(); - - // evaluate at a - vector a(m); - for (int i = 0; i y(n, 0.0); - opt.GetObjective().Evaluate(y); - for (int i=0; im_yopt = y; -} - //----------------------------------------------------------------------------- FEConstrainedLMOptimizeMethod::FEConstrainedLMOptimizeMethod() { @@ -77,6 +52,7 @@ FEConstrainedLMOptimizeMethod::FEConstrainedLMOptimizeMethod() m_objtol = 0.001; m_fdiff = 0.001; m_nmax = 100; + m_scaleParams = false; m_loglevel = LogLevel::LOG_NEVER; } @@ -86,32 +62,16 @@ bool FEConstrainedLMOptimizeMethod::Solve(FEOptimizeData *pOpt, vector& m_pOpt = pOpt; FEOptimizeData& opt = *pOpt; - // set the variables - int ma = opt.InputParameters(); - vector a(ma); - for (int i=0; i y(ndata, 0); obj.GetMeasurements(y); - // set the sigma's - // for now we set them all to 1 - vector sig(ndata); - for (int i=0; i& int niter = 1; + // if parameter scaling is not used, just set all scale factors to one + // to retain backward compatibility + if (m_scaleParams == false) + { + for (int i = 0; i < ma; ++i) + { + opt.GetInputParameter(i)->ScaleFactor() = 1.0; + } + } + try { - double* p = new double[ma]; - for (int i=0; i p(ma); + vector s(ma); + vector lb(ma); + vector ub(ma); + for (int i = 0; i < ma; ++i) + { + FEInputParameter& v = *opt.GetInputParameter(i); + double a = v.GetValue(); + double sf = v.ScaleFactor(); - double* lb = new double[ma]; - for (int i=0; iMinValue(); + s[i] = sf; + p[i] = a / sf; - double* ub = new double[ma]; - for (int i=0; iMaxValue(); + lb[i] = v.MinValue() / sf; + ub[i] = v.MaxValue() / sf; + } - double* q = new double[ndata]; + vector q(ndata); for (int i=0; i& if (opt.Constraints() > 0) { int NC = opt.Constraints(); - double* A = new double[NC*ma]; - double* b = new double[NC]; + vector A(NC * ma); + vector b(NC); for (int i=0; i& } // return optimal values - amin = a; ymin = m_yopt; if (minObj) *minObj = fret; - + return true; } //----------------------------------------------------------------------------- -void FEConstrainedLMOptimizeMethod::ObjFun(vector& x, vector& a, vector& y, matrix& dyda) +void FEConstrainedLMOptimizeMethod::ObjFun(double* p, double* hx, int m, int n) { // get the optimization data - FEOptimizeData& opt = *m_pOpt; + FEOptimizeData& opt = *GetOptimizeData(); + FEObjectiveFunction& obj = opt.GetObjective(); + + // evaluate at a + vector a(m); + for (int i = 0; i < m; ++i) + { + FEInputParameter& var = *opt.GetInputParameter(i); + a[i] = p[i]*var.ScaleFactor(); + } // poor man's box constraints - int ma = (int)a.size(); - vector dir(ma,1); // forward difference by default - for (int i=0; i= var.MaxValue()) { + } + else if (a[i] >= var.MaxValue()) { + feLogEx(opt.GetFEModel(), "Warning: clamping %s to max (was %lg)\n", var.GetName().c_str(), a[i]); a[i] = var.MaxValue(); - dir[i] = -1; // use backward difference } } - - // evaluate at a - if (opt.FESolve(a) == false) throw FEErrorTermination(); - opt.GetObjective().Evaluate(y); - m_yopt = y; - // now calculate the derivatives using forward differences - int ndata = (int)x.size(); - vector a1(a); - vector y1(ndata); - for (int i=0; iScaleFactor(); + // solve the problem + if (opt.FESolve(a) == false) throw FEErrorTermination(); - a1[i] = a1[i] + dir[i]*m_fdiff*(b + fabs(a[i])); + // store the measurement vector + vector y(n, 0.0); + opt.GetObjective().Evaluate(y); + for (int i = 0; i < n; ++i) hx[i] = y[i]; - if (opt.FESolve(a1) == false) throw FEErrorTermination(); - opt.GetObjective().Evaluate(y1); - for (int j=0; j& x, vector& a, vector& y, matrix& dyda); + void ObjFun(double* p, double* hx, int m, int n); - static FEConstrainedLMOptimizeMethod* m_pThis; - static void objfun(vector& x, vector& a, vector& y, matrix& dyda) { return m_pThis->ObjFun(x, a, y, dyda); } + static void objfun(double* p, double* hx, int m, int n, void* adata) + { + FEConstrainedLMOptimizeMethod* clm = (FEConstrainedLMOptimizeMethod*)adata; + return clm->ObjFun(p, hx, m , n); + } public: double m_tau; // scale factor for mu @@ -55,6 +58,7 @@ class FEConstrainedLMOptimizeMethod : public FEOptimizeMethod double m_fdiff; // forward difference step size int m_nmax; // maximum number of iterations int m_loglevel; // log file output level + bool m_scaleParams; // scale parameters flag public: vector m_yopt; // optimal y-values diff --git a/FEBioOpt/FEObjectiveFunction.cpp b/FEBioOpt/FEObjectiveFunction.cpp index a5fea208b..98859a720 100644 --- a/FEBioOpt/FEObjectiveFunction.cpp +++ b/FEBioOpt/FEObjectiveFunction.cpp @@ -73,6 +73,9 @@ double FEObjectiveFunction::Evaluate(vector& y) // get the measurement vector vector y0(ndata); GetMeasurements(y0); + + // evaluate regression coefficient R^2 + double rsq = RegressionCoefficient(y0, y); double chisq = 0.0; if (m_verbose) feLog(" CURRENT REQUIRED DIFFERENCE\n"); @@ -83,10 +86,29 @@ double FEObjectiveFunction::Evaluate(vector& y) if (m_verbose) feLog("%5d: %15.10lg %15.10lg %15lg\n", i + 1, y[i], y0[i], fabs(y[i] - y0[i])); } feLog("objective value: %lg\n", chisq); + feLog("regression coef: %lg\n", rsq); return chisq; } +double FEObjectiveFunction::RegressionCoefficient(const std::vector& y0, const std::vector& y) +{ + int ndata = (int)y0.size(); + double xb = 0, yb = 0, xyb = 0, x2b = 0, y2b = 0; + for (int i = 0; i < ndata; ++i) + { + xb += y0[i]; yb += y[i]; + xyb += y0[i] * y[i]; + x2b += pow(y0[i], 2); y2b += pow(y[i], 2); + } + xb /= ndata; yb /= ndata; + xyb /= ndata; + x2b /= ndata; y2b /= ndata; + + double rsq = pow(xyb - xb * yb, 2) / (x2b - xb * xb) / (y2b - yb * yb); + return rsq; +} + //============================================================================= //---------------------------------------------------------------------------- diff --git a/FEBioOpt/FEObjectiveFunction.h b/FEBioOpt/FEObjectiveFunction.h index 3523f7001..cd29159e5 100644 --- a/FEBioOpt/FEObjectiveFunction.h +++ b/FEBioOpt/FEObjectiveFunction.h @@ -65,7 +65,7 @@ class FEObjectiveFunction // evaluate objective function // also returns the function values in f - virtual double Evaluate(vector& f); + virtual double Evaluate(std::vector& f); // evaluate objective function double Evaluate(); @@ -76,6 +76,9 @@ class FEObjectiveFunction // return the FE model FEModel* GetFEModel() { return m_fem; } +public: + double RegressionCoefficient(const std::vector& y0, const std::vector& y); + public: // These functions need to be implemented by derived classes // return number of measurements (i.e. nr of terms in objective function) diff --git a/FEBioOpt/FEOptimizeData.cpp b/FEBioOpt/FEOptimizeData.cpp index c788cb06f..5b9e80428 100644 --- a/FEBioOpt/FEOptimizeData.cpp +++ b/FEBioOpt/FEOptimizeData.cpp @@ -57,30 +57,43 @@ bool FEModelParameter::Init() return false; } - // see if it's the correct type - if (val.type() == FE_PARAM_VEC2D) { - // make sure we have a valid data pointer - vec2d* vd = (vec2d*) val.data_ptr(); - // store the pointer to the parameter - m_pd = &vd->y(); - return true; + switch (val.type()) { + case FE_PARAM_DOUBLE: + { + // make sure we have a valid data pointer + double* pd = (double*) val.data_ptr(); + if (pd == 0) + { + feLogError("Invalid data pointer for parameter %s", name.c_str()); + return false; + } + + // store the pointer to the parameter + m_pd = pd; + } + break; + + case FE_PARAM_VEC2D: + { + // make sure we have a valid data pointer + vec2d* vd = (vec2d*) val.data_ptr(); + if (vd == 0) + { + feLogError("Invalid data pointer for parameter %s", name.c_str()); + return false; + } + // store the pointer to the parameter + m_pd = &vd->y(); + } + break; + + default: + { + feLogError("Invalid parameter type for parameter %s", name.c_str()); + return false; + } + break; } - else if (val.type() != FE_PARAM_DOUBLE) - { - feLogError("Invalid parameter type for parameter %s", name.c_str()); - return false; - } - - // make sure we have a valid data pointer - double* pd = (double*) val.data_ptr(); - if (pd == 0) - { - feLogError("Invalid data pointer for parameter %s", name.c_str()); - return false; - } - - // store the pointer to the parameter - m_pd = pd; return true; } @@ -174,8 +187,14 @@ bool FEOptimizeData::Solve() for (int i=0; i<(int) ymin.size(); ++i) feLog("\t\t%15lg\n", ymin[i]); + // evaluate final regression coefficient + vector y0; + m_obj->GetMeasurements(y0); + double minR2 = m_obj->RegressionCoefficient(y0, ymin); + feLog("\tTotal iterations ........ : %15d\n\n", m_niter); feLog("\tFinal objective value ... : %15lg\n\n", minObj); + feLog("\tFinal regression coef ... : %15lg\n\n", minR2); feLog("\tOptimal parameters:\n\n"); // report the parameters for the minimal value for (int i = 0; iGetDomainName(); + if (szdom) domName = szdom; + // loop over all surfaces FEMesh& m = fem.GetMesh(); int NS = m.Surfaces(); @@ -1592,62 +1597,65 @@ void FEBioPlotFile::WriteSurfaceDataField(FEModel& fem, FEPlotData* pd) { FESurface& S = m.Surface(i); - Surface& surf = m_Surf[i]; - assert(surf.surf == &S); - - // Determine data size. - // Note that for the FMT_MULT case we are - // assuming 9 data entries per facet - // regardless of the nr of nodes a facet really has - // this is because for surfaces, all elements are not - // necessarily of the same type - // TODO: Fix the assumption of the FMT_MULT - int datasize = pd->VarSize(pd->DataType()); - int nsize = datasize; - switch (pd->StorageFormat()) - { - case FMT_NODE: nsize *= S.Nodes(); break; - case FMT_ITEM: nsize *= S.Elements(); break; - case FMT_MULT: nsize *= surf.maxNodes * S.Elements(); break; - case FMT_REGION: - // one value per surface so nsize remains unchanged - break; - default: - assert(false); - } - - // save data - FEDataStream a; a.reserve(nsize); - if (pd->Save(S, a)) + if (domName.empty() || (domName == S.GetName())) { - // in FEBio 3.0, the data streams are assumed to have no padding, but for now we still need to pad - // the data stream before we write it to the file - if (a.size() == nsize) + Surface& surf = m_Surf[i]; + assert(surf.surf == &S); + + // Determine data size. + // Note that for the FMT_MULT case we are + // assuming 9 data entries per facet + // regardless of the nr of nodes a facet really has + // this is because for surfaces, all elements are not + // necessarily of the same type + // TODO: Fix the assumption of the FMT_MULT + int datasize = pd->VarSize(pd->DataType()); + int nsize = datasize; + switch (pd->StorageFormat()) { - // assumed padding is already there, or not needed - m_ar.WriteData(i + 1, a.data()); + case FMT_NODE: nsize *= S.Nodes(); break; + case FMT_ITEM: nsize *= S.Elements(); break; + case FMT_MULT: nsize *= surf.maxNodes * S.Elements(); break; + case FMT_REGION: + // one value per surface so nsize remains unchanged + break; + default: + assert(false); } - else + + // save data + FEDataStream a; a.reserve(nsize); + if (pd->Save(S, a)) { - // this is only needed for FMT_MULT storage - assert(pd->StorageFormat() == FMT_MULT); - - // add padding - const int M = surf.maxNodes; - int m = 0; - FEDataStream b; b.assign(nsize, 0.f); - for (int n = 0; n < S.Elements(); ++n) + // in FEBio 3.0, the data streams are assumed to have no padding, but for now we still need to pad + // the data stream before we write it to the file + if (a.size() == nsize) + { + // assumed padding is already there, or not needed + m_ar.WriteData(i + 1, a.data()); + } + else { - FESurfaceElement& el = S.Element(n); - int ne = el.Nodes(); - for (int j = 0; j < ne; ++j) + // this is only needed for FMT_MULT storage + assert(pd->StorageFormat() == FMT_MULT); + + // add padding + const int M = surf.maxNodes; + int m = 0; + FEDataStream b; b.assign(nsize, 0.f); + for (int n = 0; n < S.Elements(); ++n) { - for (int k = 0; k < datasize; ++k) b[n*M*datasize + j*datasize + k] = a[m++]; + FESurfaceElement& el = S.Element(n); + int ne = el.Nodes(); + for (int j = 0; j < ne; ++j) + { + for (int k = 0; k < datasize; ++k) b[n * M * datasize + j * datasize + k] = a[m++]; + } } - } - // write the padded data - m_ar.WriteData(i + 1, b.data()); + // write the padded data + m_ar.WriteData(i + 1, b.data()); + } } } } @@ -1673,44 +1681,51 @@ void FEBioPlotFile::WriteDomainDataField(FEModel &fem, FEPlotData* pd) return; } + // get the domain name (if any) + string domName; + const char* szdom = pd->GetDomainName(); + if (szdom) domName = szdom; + // loop over all domains in the item list - int N = (int)item.size(); for (int i = 0; iVarSize(pd->DataType()); - switch (pd->StorageFormat()) + if (domName.empty() || (D.GetName() == domName)) { - case FMT_NODE: nsize *= D.Nodes(); break; - case FMT_ITEM: nsize *= D.Elements(); break; - case FMT_MULT: - { - // since all elements have the same type within a domain - // we just grab the number of nodes of the first element - // to figure out how much storage we need - FEElement& e = D.ElementRef(0); - int n = e.Nodes(); - nsize *= n*D.Elements(); - } - break; - case FMT_REGION: - // one value for this domain so nsize remains unchanged + // calculate the size of the data vector + int nsize = pd->VarSize(pd->DataType()); + switch (pd->StorageFormat()) + { + case FMT_NODE: nsize *= D.Nodes(); break; + case FMT_ITEM: nsize *= D.Elements(); break; + case FMT_MULT: + { + // since all elements have the same type within a domain + // we just grab the number of nodes of the first element + // to figure out how much storage we need + FEElement& e = D.ElementRef(0); + int n = e.Nodes(); + nsize *= n * D.Elements(); + } break; - default: - assert(false); - } - assert(nsize > 0); + case FMT_REGION: + // one value for this domain so nsize remains unchanged + break; + default: + assert(false); + } + assert(nsize > 0); - // fill data vector and save - FEDataStream a; - a.reserve(nsize); - if (pd->Save(D, a)) - { - assert(a.size() == nsize); - m_ar.WriteData(item[i] + 1, a.data()); + // fill data vector and save + FEDataStream a; + a.reserve(nsize); + if (pd->Save(D, a)) + { + assert(a.size() == nsize); + m_ar.WriteData(item[i] + 1, a.data()); + } } } } diff --git a/FEBioRVE/FEPeriodicBoundary1O.cpp b/FEBioRVE/FEPeriodicBoundary1O.cpp index c4a89c9c9..0ae1437fa 100644 --- a/FEBioRVE/FEPeriodicBoundary1O.cpp +++ b/FEBioRVE/FEPeriodicBoundary1O.cpp @@ -61,6 +61,10 @@ FEPeriodicBoundary1O::FEPeriodicBoundary1O(FEModel* pfem) : FEContactInterface(p m_off = vec3d(0,0,0); m_naugmin = 0; + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); diff --git a/FEBioRVE/FEPeriodicBoundary2O.cpp b/FEBioRVE/FEPeriodicBoundary2O.cpp index 0efc216ba..4f0ab4560 100644 --- a/FEBioRVE/FEPeriodicBoundary2O.cpp +++ b/FEBioRVE/FEPeriodicBoundary2O.cpp @@ -61,6 +61,10 @@ FEPeriodicBoundary2O::FEPeriodicBoundary2O(FEModel* pfem) : FEContactInterface(p m_off = vec3d(0,0,0); m_naugmin = 0; + // set parents + m_ss.SetContactInterface(this); + m_ms.SetContactInterface(this); + m_ss.SetSibling(&m_ms); m_ms.SetSibling(&m_ss); diff --git a/FEBioRVE/FEPeriodicLinearConstraint2O.cpp b/FEBioRVE/FEPeriodicLinearConstraint2O.cpp index c9c52b4fa..d650bc9bb 100644 --- a/FEBioRVE/FEPeriodicLinearConstraint2O.cpp +++ b/FEBioRVE/FEPeriodicLinearConstraint2O.cpp @@ -92,7 +92,7 @@ void FEPeriodicLinearConstraint2O::addLinearConstraint(FEModel& fem, int parent, // do one constraint for x, y, z for (int j = 0; j<3; ++j) { - FELinearConstraint* lc = new FELinearConstraint(&fem); + FELinearConstraint* lc = fecore_alloc(FELinearConstraint, &fem); lc->SetParentDof(j, parent); lc->AddChildDof(j, child, 1.0); diff --git a/FEBioTest/FEResetTest.cpp b/FEBioTest/FEResetTest.cpp index 94014cc8c..6054cd7f0 100644 --- a/FEBioTest/FEResetTest.cpp +++ b/FEBioTest/FEResetTest.cpp @@ -30,6 +30,11 @@ SOFTWARE.*/ #include "FEResetTest.h" #include #include +#include +#include +#include +#include +using namespace std; //----------------------------------------------------------------------------- FEResetTest::FEResetTest(FEModel*pfem) : FECoreTask(pfem) @@ -42,6 +47,9 @@ bool FEResetTest::Init(const char* sz) { FEBioModel& fem = dynamic_cast(*GetFEModel()); + Logfile& log = fem.GetLogFile(); + log.SetMode(Logfile::MODE::LOG_FILE); + // do the FE initialization return fem.Init(); } @@ -52,14 +60,27 @@ bool FEResetTest::Run() { FEBioModel* fem = dynamic_cast(GetFEModel()); + FELogSolutionNorm sn(fem); + // try to run the model + cerr << "Running model for the first time.\n"; if (fem->Solve() == false) { feLogEx(fem, "Failed to run model."); return false; } + // collect results + ModelStats stats1 = fem->GetModelStats(); + double norm1 = sn.value(); + cerr << "time steps = " << stats1.ntimeSteps << endl; + cerr << "total iters = " << stats1.ntotalIters << endl; + cerr << "total reforms = " << stats1.ntotalReforms << endl; + cerr << "total rhs = " << stats1.ntotalRHS << endl; + cerr << "solution norm = " << std::setprecision(15) << norm1 << endl; + // reset the model + std::cerr << "Resetting model.\n"; if (fem->Reset() == false) { feLogEx(fem, "Failed to reset model."); @@ -67,11 +88,29 @@ bool FEResetTest::Run() } // try to run it again + std::cerr << "Running model for the second time.\n"; if (fem->Solve() == false) { feLogEx(fem, "Failed to run model second time."); return false; } - return true; + // get model stats + ModelStats stats2 = fem->GetModelStats(); + double norm2 = sn.value(); + cerr << "time steps = " << stats2.ntimeSteps << endl; + cerr << "total iters = " << stats2.ntotalIters << endl; + cerr << "total reforms = " << stats2.ntotalReforms << endl; + cerr << "total rhs = " << stats2.ntotalRHS << endl; + cerr << "solution norm = " << norm2 << endl; + + bool success = true; + if (stats1.ntimeSteps != stats2.ntimeSteps ) success = false; + if (stats1.ntotalIters != stats2.ntotalIters ) success = false; + if (stats1.ntotalReforms != stats2.ntotalReforms) success = false; + if (stats1.ntotalRHS != stats2.ntotalRHS ) success = false; + if (norm1 != norm2) success = false; + cerr << " --> Reset test " << (success ? "PASSED" : "FAILED") << endl; + + return success; } diff --git a/FEBioXML/FEBioBoundarySection.cpp b/FEBioXML/FEBioBoundarySection.cpp index 6ef5fdf17..9cfeb893b 100644 --- a/FEBioXML/FEBioBoundarySection.cpp +++ b/FEBioXML/FEBioBoundarySection.cpp @@ -287,7 +287,7 @@ void FEBioBoundarySection2::ParseBCFix(XMLTag &tag) int NN = mesh.Nodes(); // get the required bc attribute - char szbc[8]; + char szbc[32] = { 0 }; strcpy(szbc, tag.AttributeValue("bc")); // process the bc string @@ -867,7 +867,7 @@ void FEBioBoundarySection::ParseConstraints(XMLTag& tag) int dof = dofList[i]; if (dof < 0) throw XMLReader::InvalidAttributeValue(tag, "bc", szbc); - LC[i] = new FELinearConstraint(&fem); + LC[i] = fecore_alloc(FELinearConstraint, &fem); LC[i]->SetParentDof(dof, parentNode); } diff --git a/FEBioXML/FEBioBoundarySection3.cpp b/FEBioXML/FEBioBoundarySection3.cpp index 47b60d538..4dc296f72 100644 --- a/FEBioXML/FEBioBoundarySection3.cpp +++ b/FEBioXML/FEBioBoundarySection3.cpp @@ -162,7 +162,7 @@ void FEBioBoundarySection3::ParseLinearConstraint(XMLTag& tag) FEModelBuilder* feb = GetBuilder(); - FELinearConstraint* lc = new FELinearConstraint(&fem); + FELinearConstraint* lc = fecore_alloc(FELinearConstraint, &fem); ++tag; do diff --git a/FEBioXML/FEBioDiscreteSection.cpp b/FEBioXML/FEBioDiscreteSection.cpp index 11902a598..582a3116f 100644 --- a/FEBioXML/FEBioDiscreteSection.cpp +++ b/FEBioXML/FEBioDiscreteSection.cpp @@ -236,7 +236,7 @@ void FEBioDiscreteSection25::Parse(XMLTag& tag) ReadParameterList(tag, pl); // create an element set for this domain - FEElementSet* elset = new FEElementSet(&fem); + FEElementSet* elset = fecore_alloc(FEElementSet, &fem); elset->Create(pd); elset->SetName(pd->GetName()); mesh.AddElementSet(elset); diff --git a/FEBioXML/FEBioGlobalsSection.cpp b/FEBioXML/FEBioGlobalsSection.cpp index 88bd6bd5b..1afe62237 100644 --- a/FEBioXML/FEBioGlobalsSection.cpp +++ b/FEBioXML/FEBioGlobalsSection.cpp @@ -108,7 +108,7 @@ void FEBioGlobalsSection::ParseVariables(XMLTag& tag) { const char* szname = tag.AttributeValue("name"); double v = 0; tag.value(v); - fem.AddParameter(*(new double(v)), strdup(szname)); + fem.AddGlobalVariable(szname, v); } else throw XMLReader::InvalidTag(tag); ++tag; diff --git a/FEBioXML/FEBioOutputSection.cpp b/FEBioXML/FEBioOutputSection.cpp index 1c6a3f3d5..dafccd88b 100644 --- a/FEBioXML/FEBioOutputSection.cpp +++ b/FEBioXML/FEBioOutputSection.cpp @@ -35,6 +35,7 @@ SOFTWARE.*/ #include #include #include +#include #include #include #include @@ -350,6 +351,21 @@ void FEBioOutputSection::ParseLogfile(XMLTag &tag) GetFEBioImport()->AddDataRecord(prec); } + else if (tag == "model_data") + { + FEModelDataRecord* prec = new FEModelDataRecord(&fem, szfile); + + const char* szdata = tag.AttributeValue("data"); + prec->SetData(szdata); + + const char* szname = tag.AttributeValue("name", true); + if (szname != 0) prec->SetName(szname); else prec->SetName(szdata); + if (szdelim != 0) prec->SetDelim(szdelim); + if (szformat != 0) prec->SetFormat(szformat); + prec->SetComments(bcomment); + + GetFEBioImport()->AddDataRecord(prec); + } else throw XMLReader::InvalidTag(tag); ++tag; @@ -412,15 +428,16 @@ void FEBioOutputSection::ParsePlotfile(XMLTag &tag) if (tag.isempty() == false) tag.value(item); // see if a surface is referenced - const char* szset = tag.AttributeValue("surface", true); - if (szset) + const char* szsurf = tag.AttributeValue("surface", true); + const char* szeset = tag.AttributeValue("elem_set", true); + if (szsurf) { // make sure this tag does not have any children if (!tag.isleaf()) throw XMLReader::InvalidTag(tag); // see if we can find the facet set FEMesh& m = GetFEModel()->GetMesh(); - FEFacetSet* ps = m.FindFacetSet(szset); + FEFacetSet* ps = m.FindFacetSet(szsurf); // create a surface from the facet set if (ps) @@ -434,8 +451,25 @@ void FEBioOutputSection::ParsePlotfile(XMLTag &tag) const std::string& surfName = psurf->GetName(); plotData.AddPlotVariable(szt, item, surfName.c_str()); } - else throw XMLReader::InvalidAttributeValue(tag, "set", szset); + else throw XMLReader::InvalidAttributeValue(tag, "surface", szsurf); } + else if (szeset) + { + // make sure this tag does not have any children + if (!tag.isleaf()) throw XMLReader::InvalidTag(tag); + + // see if we can find the facet set + FEMesh& m = GetFEModel()->GetMesh(); + FEElementSet* ps = m.FindElementSet(szeset); + + // create a surface from the facet set + if (ps) + { + // Add the plot variable + plotData.AddPlotVariable(szt, item, szeset); + } + else throw XMLReader::InvalidAttributeValue(tag, "elem_set", szeset); + } else { // Add the plot variable diff --git a/FEBioXML/FEModelBuilder.cpp b/FEBioXML/FEModelBuilder.cpp index c17d20414..b1b073461 100644 --- a/FEBioXML/FEModelBuilder.cpp +++ b/FEBioXML/FEModelBuilder.cpp @@ -714,7 +714,7 @@ void FEModelBuilder::ApplyParameterMaps() if (p.type() == FE_PARAM_DOUBLE_MAPPED) { FEParamDouble& v = p.value(mp.index); - FEMappedValue* map = new FEMappedValue(&m_fem); + FEMappedValue* map = fecore_alloc(FEMappedValue, &m_fem); if (data->DataType() != FE_DOUBLE) { std::stringstream ss; @@ -729,7 +729,7 @@ void FEModelBuilder::ApplyParameterMaps() else if (p.type() == FE_PARAM_VEC3D_MAPPED) { FEParamVec3& v = p.value(); - FEMappedValueVec3* map = new FEMappedValueVec3(&m_fem); + FEMappedValueVec3* map = fecore_alloc(FEMappedValueVec3, &m_fem); if (data->DataType() != FE_VEC3D) { std::stringstream ss; diff --git a/FEBioXML/FERestartImport.cpp b/FEBioXML/FERestartImport.cpp index bfe9b3283..5877ec1f9 100644 --- a/FEBioXML/FERestartImport.cpp +++ b/FEBioXML/FERestartImport.cpp @@ -30,6 +30,7 @@ SOFTWARE.*/ #include "FERestartImport.h" #include "FECore/FESolver.h" #include "FECore/FEAnalysis.h" +#include "FECore/FESolver.h" #include "FECore/FEModel.h" #include "FECore/DumpFile.h" #include "FEBioLoadDataSection.h" @@ -76,6 +77,22 @@ void FERestartControlSection::Parse(XMLTag& tag) else if (strcmp(szval, "PLOT_AUGMENTATIONS") == 0) pstep->SetPlotLevel(FE_PLOT_AUGMENTATIONS); else throw XMLReader::InvalidValue(tag); } + else if (tag == "solver") + { + FEAnalysis* step = fem.GetCurrentStep(); + FESolver* solver = step->GetFESolver(); + if (solver == nullptr) throw XMLReader::InvalidTag(tag); + + ++tag; + do + { + if (ReadParameter(tag, solver) == false) + { + throw XMLReader::InvalidTag(tag); + } + ++tag; + } while (!tag.isend()); + } else throw XMLReader::InvalidTag(tag); ++tag; diff --git a/FECore/DataRecord.h b/FECore/DataRecord.h index 478498742..6ee7125f5 100644 --- a/FECore/DataRecord.h +++ b/FECore/DataRecord.h @@ -46,7 +46,8 @@ enum FEDataRecordType { FE_DATA_RB, FE_DATA_NLC, FE_DATA_SURFACE, - FE_DATA_DOMAIN + FE_DATA_DOMAIN, + FE_DATA_MODEL }; //----------------------------------------------------------------------------- diff --git a/FECore/FEClosestPointProjection.cpp b/FECore/FEClosestPointProjection.cpp index cd36e8a1a..c589c0481 100644 --- a/FECore/FEClosestPointProjection.cpp +++ b/FECore/FEClosestPointProjection.cpp @@ -542,6 +542,7 @@ FESurfaceElement* FEClosestPointProjection::ProjectSpecial(int closestPoint, con // make sure one of them is our closest point if (el.HasNode(m)) { + q = rm; return ⪙ } } diff --git a/FECore/FEConstValueVec3.cpp b/FECore/FEConstValueVec3.cpp index 796da3359..a86237dcd 100644 --- a/FECore/FEConstValueVec3.cpp +++ b/FECore/FEConstValueVec3.cpp @@ -125,7 +125,7 @@ vec3d FEMappedValueVec3::operator()(const FEMaterialPoint& pt) FEVec3dValuator* FEMappedValueVec3::copy() { - FEMappedValueVec3* map = new FEMappedValueVec3(GetFEModel()); + FEMappedValueVec3* map = fecore_alloc(FEMappedValueVec3, GetFEModel()); map->m_val = m_val; return map; } diff --git a/FECore/FECore.cpp b/FECore/FECore.cpp index 97fc339c8..e9009f151 100644 --- a/FECore/FECore.cpp +++ b/FECore/FECore.cpp @@ -55,6 +55,8 @@ SOFTWARE.*/ #include "FELogEnclosedVolume.h" #include "FELogElementVolume.h" #include "FELogDomainVolume.h" +#include "FELogSolutionNorm.h" +#include "FELinearConstraint.h" #define FECORE_VERSION 0 #define FECORE_SUBVERSION 1 @@ -115,7 +117,7 @@ REGISTER_FECORE_CLASS(FEParabolicMap , "parabolic map"); REGISTER_FECORE_CLASS(FEConstValue , "const"); REGISTER_FECORE_CLASS(FEMathValue , "math" ); REGISTER_FECORE_CLASS(FEMappedValue, "map" ); - +REGISTER_FECORE_CLASS_EXPLICIT(FELinearConstraint, FEBC_ID, "linear constraint"); // vector generators REGISTER_FECORE_CLASS(FELocalVectorGenerator , "local"); REGISTER_FECORE_CLASS(FEConstValueVec3 , "vector"); @@ -165,4 +167,5 @@ REGISTER_FECORE_CLASS(FELogElementVolume, "V"); REGISTER_FECORE_CLASS(FELogDomainVolume, "volume"); REGISTER_FECORE_CLASS(FELogAvgDomainData, "avg"); REGISTER_FECORE_CLASS(FELogPctDomainData, "pct"); +REGISTER_FECORE_CLASS(FELogSolutionNorm, "solution_norm"); } diff --git a/FECore/FECoreBase.cpp b/FECore/FECoreBase.cpp index 3c1ce6815..a270159ba 100644 --- a/FECore/FECoreBase.cpp +++ b/FECore/FECoreBase.cpp @@ -313,7 +313,7 @@ bool FECoreBase::Init() { if (pi->Init() == false) { - feLogError("The required property \"%s\" was not defined", pi->GetName()); + feLogError("The property \"%s\" failed to initialize or was not defined.", pi->GetName()); return false; } } diff --git a/FECore/FECorePlot.cpp b/FECore/FECorePlot.cpp index fdaf30793..6c888e2ea 100644 --- a/FECore/FECorePlot.cpp +++ b/FECore/FECorePlot.cpp @@ -37,6 +37,7 @@ SOFTWARE.*/ #include "FEMaterialPointProperty.h" #include "writeplot.h" #include "FESurfaceLoad.h" +#include "FEDomainMap.h" //----------------------------------------------------------------------------- FEPlotParameter::FEPlotParameter(FEModel* pfem) : FEPlotData(pfem) @@ -283,6 +284,34 @@ bool FEPlotParameter::Save(FEDomain& dom, FEDataStream& a) if (m_param.type() == FE_PARAM_DOUBLE_MAPPED) { FEParamDouble& mapDouble = dynamic_cast(map); + + FEMappedValue* val = dynamic_cast(mapDouble.valuator()); + if (val) + { + FEDomainMap* map = dynamic_cast(val->dataMap()); assert(map); + if (map->StorageFormat() == FMT_MULT) + { + // loop over all elements + int NE = dom.Elements(); + for (int i = 0; i < NE; ++i) + { + FEElement& e = dom.ElementRef(i); + int ne = e.Nodes(); + + vector sn(ne); + for (int j = 0; j < ne; ++j) + { + sn[j] = map->value(i, j); + } + + // push data to archive + for (int j = 0; j < ne; ++j) a << sn[j]; + } + + return true; + } + } + writeNodalProjectedElementValues(sd, a, mapDouble); } else if (m_param.type() == FE_PARAM_VEC3D_MAPPED) diff --git a/FECore/FEDiscreteDomain.cpp b/FECore/FEDiscreteDomain.cpp index 9d26e38dc..7f086e375 100644 --- a/FECore/FEDiscreteDomain.cpp +++ b/FECore/FEDiscreteDomain.cpp @@ -48,6 +48,12 @@ bool FEDiscreteDomain::Create(int nelems, FE_Element_Spec espec) return true; } +//----------------------------------------------------------------------------- +void FEDiscreteDomain::Reset() +{ + for (auto& el : m_Elem) el.setActive(); +} + //----------------------------------------------------------------------------- bool FEDiscreteDomain::Init() { @@ -59,6 +65,15 @@ bool FEDiscreteDomain::Init() return true; } +//----------------------------------------------------------------------------- +void FEDiscreteDomain::CopyFrom(FEMeshPartition* pd) +{ + FEDomain::CopyFrom(pd); + FEDiscreteDomain* psd = dynamic_cast(pd); + m_Elem = psd->m_Elem; + ForEachElement([=](FEElement& el) { el.SetMeshPartition(this); }); +} + //----------------------------------------------------------------------------- void FEDiscreteDomain::AddElement(int eid, int n[2]) { diff --git a/FECore/FEDiscreteDomain.h b/FECore/FEDiscreteDomain.h index 1d4056135..1d4d0d658 100644 --- a/FECore/FEDiscreteDomain.h +++ b/FECore/FEDiscreteDomain.h @@ -45,6 +45,11 @@ class FECORE_API FEDiscreteDomain : public FEDomain bool Init() override; + void Reset() override; + + //! copy data from another domain (overridden from FEDomain) + void CopyFrom(FEMeshPartition* pd) override; + public: void AddElement(int eid, int n[2]); diff --git a/FECore/FEElementTraits.cpp b/FECore/FEElementTraits.cpp index e10eb1419..6323601af 100644 --- a/FECore/FEElementTraits.cpp +++ b/FECore/FEElementTraits.cpp @@ -1691,7 +1691,10 @@ void FEQuad4_::init() m_shapeP[0] = 0; m_shapeP[1] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_QUAD4)); - // initialize base class + // centroid coordinates + cr = cs = 0; + + // initialize base class FESurfaceElementTraits::init(); } @@ -1756,6 +1759,9 @@ void FETri3_::init() m_shapeP[0] = 0; m_shapeP[1] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_TRI3)); + // centroid coordinates + cr = cs = 1.0/3.0; + // initialize base class FESurfaceElementTraits::init(); } @@ -1882,6 +1888,9 @@ void FETri6_::init() m_shapeP[1] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_TRI3)); m_shapeP[2] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_TRI6)); + // centroid coordinates + cr = cs = 1.0/3.0; + // initialize base class FESurfaceElementTraits::init(); } @@ -2255,6 +2264,9 @@ void FETri7_::init() m_shapeP[1] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_TRI3)); m_shapeP[2] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_TRI7)); + // centroid coordinates + cr = cs = 1.0/3.0; + // initialize base class FESurfaceElementTraits::init(); } @@ -2339,6 +2351,9 @@ void FETri10_::init() m_shapeP[2] = 0; // this element cannot be used for quadratic interpolation! m_shapeP[3] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_TRI10)); + // centroid coordinates + cr = cs = 1.0/3.0; + // initialize base class FESurfaceElementTraits::init(); } @@ -2418,6 +2433,9 @@ void FEQuad8_::init() m_shapeP[1] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_QUAD4)); m_shapeP[2] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_QUAD8)); + // centroid coordinates + cr = cs = 0; + // initialize base class FESurfaceElementTraits::init(); } @@ -2512,6 +2530,9 @@ void FEQuad9_::init() m_shapeP[1] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_QUAD4)); m_shapeP[2] = dynamic_cast(FEElementLibrary::GetElementShapeClass(ET_QUAD9)); + // centroid coordinates + cr = cs = 0; + // initialize base class FESurfaceElementTraits::init(); } diff --git a/FECore/FEElementTraits.h b/FECore/FEElementTraits.h index 2dc673f5a..f3bd846a2 100644 --- a/FECore/FEElementTraits.h +++ b/FECore/FEElementTraits.h @@ -811,6 +811,10 @@ class FESurfaceElementTraits : public FEElementTraits // local derivatives of shape functions at gauss points, for different interpolation order std::vector Gr_p; std::vector Gs_p; + + // parametric coordinates of element center + double cr; + double cs; }; //============================================================================= diff --git a/FECore/FEFunction1D.cpp b/FECore/FEFunction1D.cpp index 85daa077f..649d7d0f1 100644 --- a/FECore/FEFunction1D.cpp +++ b/FECore/FEFunction1D.cpp @@ -32,6 +32,7 @@ SOFTWARE.*/ #include "DumpStream.h" #include "MMath.h" #include "MObj2String.h" +#include "log.h" REGISTER_SUPER_CLASS(FEFunction1D, FEFUNCTION1D_ID); @@ -136,6 +137,12 @@ void FEMathFunction::SetMathString(const std::string& s) } bool FEMathFunction::Init() +{ + if (BuildMathExpressions() == false) return false; + return FEFunction1D::Init(); +} + +bool FEMathFunction::BuildMathExpressions() { // process the string m_exp.Clear(); @@ -194,7 +201,17 @@ bool FEMathFunction::Init() else m_d2exp.Create("0"); - return FEFunction1D::Init(); + return true; +} + +void FEMathFunction::Serialize(DumpStream& ar) +{ + FEFunction1D::Serialize(ar); + if ((ar.IsShallow() == false) && (ar.IsLoading())) + { + bool b = BuildMathExpressions(); + assert(b); + } } FEFunction1D* FEMathFunction::copy() diff --git a/FECore/FEFunction1D.h b/FECore/FEFunction1D.h index 736ba9a42..40859fc33 100644 --- a/FECore/FEFunction1D.h +++ b/FECore/FEFunction1D.h @@ -153,6 +153,8 @@ class FECORE_API FEMathFunction : public FEFunction1D bool Init() override; + void Serialize(DumpStream& ar) override; + FEFunction1D* copy() override; double value(double t) const override; @@ -166,6 +168,8 @@ class FECORE_API FEMathFunction : public FEFunction1D private: void evalParams(std::vector& val, double t) const; + bool BuildMathExpressions(); + private: std::string m_s; int m_ix; // index of independent variable diff --git a/FECore/FELinearConstraint.cpp b/FECore/FELinearConstraint.cpp index 359896ef2..d898382ca 100644 --- a/FECore/FELinearConstraint.cpp +++ b/FECore/FELinearConstraint.cpp @@ -41,6 +41,12 @@ FELinearConstraint::DOF::DOF() AddParameter(val, "value"); } +void FELinearConstraint::DOF::Serialize(DumpStream& ar) +{ + FEParamContainer::Serialize(ar); + ar & node & dof & val; +} + //----------------------------------------------------------------------------- FELinearConstraint::FELinearConstraint() : FEModelComponent(nullptr) { @@ -222,23 +228,23 @@ void FELinearConstraint::Serialize(DumpStream& ar) if (ar.IsSaving()) { - ar.write(m_parentDof, sizeof(DOF), 1); + m_parentDof->Serialize(ar); int n = (int)m_childDof.size(); ar << n; vector::iterator it = m_childDof.begin(); - for (int i=0; ival << (*it)->node << (*it)->dof; + for (int i = 0; i < n; ++i, ++it) (*it)->Serialize(ar); } else { m_childDof.clear(); if (m_parentDof == nullptr) m_parentDof = new DOF; - ar.read(m_parentDof, sizeof(DOF), 1); + m_parentDof->Serialize(ar); int n; ar >> n; for (int i=0; i> dof->val >> dof->node >> dof->dof; + dof->Serialize(ar); m_childDof.push_back(dof); } } diff --git a/FECore/FELinearConstraint.h b/FECore/FELinearConstraint.h index 048a9a475..92f414b4b 100644 --- a/FECore/FELinearConstraint.h +++ b/FECore/FELinearConstraint.h @@ -41,6 +41,8 @@ class FECORE_API FELinearConstraint : public FEModelComponent public: DOF(); + void Serialize(DumpStream& ar); + public: int node; // node number int dof; // degree of freedom diff --git a/FECore/FELinearConstraintManager.cpp b/FECore/FELinearConstraintManager.cpp index ba26ce6df..86e79361b 100644 --- a/FECore/FELinearConstraintManager.cpp +++ b/FECore/FELinearConstraintManager.cpp @@ -58,7 +58,7 @@ void FELinearConstraintManager::CopyFrom(const FELinearConstraintManager& lcm) Clear(); for (int i=0; iCopyFrom(lcm.LinearConstraint(i)); m_LinC.push_back(lc); } diff --git a/FECore/FELoadCurve.cpp b/FECore/FELoadCurve.cpp index e1d2be605..fa567faac 100644 --- a/FECore/FELoadCurve.cpp +++ b/FECore/FELoadCurve.cpp @@ -31,6 +31,7 @@ SOFTWARE.*/ #include "DumpStream.h" #include "FECoreKernel.h" #include "FEFunction1D.h" +#include "log.h" BEGIN_FECORE_CLASS(FELoadCurve, FELoadController) ADD_PARAMETER(m_fnc.m_points, "points"); @@ -87,6 +88,17 @@ void FELoadCurve::Clear() bool FELoadCurve::Init() { + // check points + if (m_fnc.Points() > 1) + { + for (int i = 1; i < m_fnc.Points(); ++i) + { + double t0 = m_fnc.LoadPoint(i-1).time; + double t1 = m_fnc.LoadPoint(i ).time; + if (t0 == t1) feLogWarning("Repeated time coordinate in load controller %d", GetID() + 1); + } + } + return m_fnc.Init(); } diff --git a/FECore/FELogSolutionNorm.cpp b/FECore/FELogSolutionNorm.cpp new file mode 100644 index 000000000..1fc589316 --- /dev/null +++ b/FECore/FELogSolutionNorm.cpp @@ -0,0 +1,49 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#include "stdafx.h" +#include "FELogSolutionNorm.h" +#include "FEModel.h" +#include "FEAnalysis.h" +#include "FESolver.h" + +//================================================================================ +FELogSolutionNorm::FELogSolutionNorm(FEModel* fem) : FEModelLogData(fem) {} +double FELogSolutionNorm::value() +{ + FEModel* fem = GetFEModel(); assert(fem); + if (fem == nullptr) return 0.0; + + FEAnalysis* step = fem->GetCurrentStep(); + if (step == nullptr) return 0.0; + + FESolver* solver = step->GetFESolver(); + if (solver == nullptr) return 0.0; + + std::vector u = solver->GetSolutionVector(); + double unorm = l2_norm(u); + + return unorm; +} diff --git a/FECore/FELogSolutionNorm.h b/FECore/FELogSolutionNorm.h new file mode 100644 index 000000000..e3da711fb --- /dev/null +++ b/FECore/FELogSolutionNorm.h @@ -0,0 +1,35 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#pragma once +#include "FEModelDataRecord.h" + +//----------------------------------------------------------------------------- +class FELogSolutionNorm : public FEModelLogData +{ +public: + FELogSolutionNorm(FEModel* fem); + double value() override; +}; diff --git a/FECore/FEMat3dValuator.cpp b/FECore/FEMat3dValuator.cpp index 204a994d2..450b313c9 100644 --- a/FECore/FEMat3dValuator.cpp +++ b/FECore/FEMat3dValuator.cpp @@ -491,7 +491,7 @@ mat3d FEMappedValueMat3d::operator()(const FEMaterialPoint& pt) FEMat3dValuator* FEMappedValueMat3d::copy() { - FEMappedValueMat3d* map = new FEMappedValueMat3d(GetFEModel()); + FEMappedValueMat3d* map = fecore_alloc(FEMappedValueMat3d, GetFEModel()); map->m_val = m_val; return map; } diff --git a/FECore/FEMat3dsValuator.cpp b/FECore/FEMat3dsValuator.cpp index 8ac125cf0..fa57ae049 100644 --- a/FECore/FEMat3dsValuator.cpp +++ b/FECore/FEMat3dsValuator.cpp @@ -76,7 +76,7 @@ mat3ds FEMappedValueMat3ds::operator()(const FEMaterialPoint& pt) FEMat3dsValuator* FEMappedValueMat3ds::copy() { - FEMappedValueMat3ds* map = new FEMappedValueMat3ds(GetFEModel()); + FEMappedValueMat3ds* map = fecore_alloc(FEMappedValueMat3ds, GetFEModel()); map->m_val = m_val; return map; } diff --git a/FECore/FEMesh.cpp b/FECore/FEMesh.cpp index 109f11e6e..c75fad59b 100644 --- a/FECore/FEMesh.cpp +++ b/FECore/FEMesh.cpp @@ -123,6 +123,17 @@ void FEMesh::Serialize(DumpStream& ar) // write facet sets ar << m_FaceSet; + // write surface pairs + int surfPairs = m_SurfPair.size(); + ar << surfPairs; + for (int i = 0; i < m_SurfPair.size(); ++i) + { + FESurfacePair& sp = *m_SurfPair[i]; + ar << sp.GetName(); + ar << sp.GetPrimarySurface()->GetName(); + ar << sp.GetSecondarySurface()->GetName(); + } + // write discrete sets int dsets = DiscreteSets(); ar << dsets; @@ -159,9 +170,30 @@ void FEMesh::Serialize(DumpStream& ar) // read element sets ar >> m_ElemSet; - // write facet sets + // read facet sets ar >> m_FaceSet; + // read surface pairs + int surfPairs = 0; + ar >> surfPairs; + for (int i = 0; i < surfPairs; ++i) + { + FESurfacePair* sp = new FESurfacePair(this); + std::string name; + ar >> name; + sp->SetName(name); + + ar >> name; + FEFacetSet* ps = FindFacetSet(name); + sp->SetPrimarySurface(ps); + + ar >> name; + ps = FindFacetSet(name); + sp->SetSecondarySurface(ps); + + AddSurfacePair(sp); + } + // read discrete sets int dsets = 0; ar >> dsets; diff --git a/FECore/FEModel.cpp b/FECore/FEModel.cpp index 8b7c3e86e..053bee4a1 100644 --- a/FECore/FEModel.cpp +++ b/FECore/FEModel.cpp @@ -203,6 +203,7 @@ class FEModel::Implementation public: // Global Data std::map m_Const; //!< Global model constants vector m_GD; //!< global data structures + std::vector m_Var; FEMODEL_MEMORY_STATS m_memstats; }; @@ -224,6 +225,7 @@ BEGIN_FECORE_CLASS(FEModel, FECoreBase) ADD_PROPERTY(m_imp->m_CI , "contact" ); ADD_PROPERTY(m_imp->m_NLC , "constraint" ); // ADD_PROPERTY(m_imp->m_ML , "model_load" ); + ADD_PROPERTY(m_imp->m_MA , "mesh_adaptor" ); ADD_PROPERTY(m_imp->m_LC , "load_controller"); ADD_PROPERTY(m_imp->m_Step, "step" ); ADD_PROPERTY(m_imp->m_Data, "data" ); @@ -298,6 +300,10 @@ void FEModel::Clear() for (size_t i = 0; im_GD.size(); ++i) delete m_imp->m_GD[i]; m_imp->m_GD.clear(); m_imp->m_Const.clear(); + // global variables (TODO: Should I delete the corresponding parameters?) + for (size_t i = 0; i < m_imp->m_Var.size(); ++i) delete m_imp->m_Var[i]; + m_imp->m_Var.clear(); + // clear the linear constraints if (m_imp->m_LCM) m_imp->m_LCM->Clear(); @@ -1657,7 +1663,7 @@ bool FEModel::EvaluateLoadParameters() case FE_PARAM_BOOL: { p->value() = (s > 0 ? true : false); if (m_imp->m_printParams) - feLog("Setting parameter \"%s\" to : %s\n", p->name(), (p->value() ? "false" : "true")); + feLog("Setting parameter \"%s\" to : %s\n", p->name(), (p->value() ? "true" : "false")); } break; case FE_PARAM_VEC3D: { @@ -1787,6 +1793,27 @@ double FEModel::GetGlobalConstant(const string& s) return (m_imp->m_Const.count(s) ? m_imp->m_Const.find(s)->second : 0); } +//----------------------------------------------------------------------------- +int FEModel::GlobalVariables() const +{ + return (int)m_imp->m_Var.size(); +} + +//----------------------------------------------------------------------------- +void FEModel::AddGlobalVariable(const string& s, double v) +{ + FEGlobalVariable* var = new FEGlobalVariable; + var->v = v; + var->name = s; + AddParameter(var->v, var->name.c_str()); + m_imp->m_Var.push_back(var); +} + +const FEGlobalVariable& FEModel::GetGlobalVariable(int n) +{ + return *m_imp->m_Var[n]; +} + //----------------------------------------------------------------------------- void FEModel::AddGlobalData(FEGlobalData* psd) { @@ -1834,32 +1861,32 @@ void FEModel::UpdateModelData() } //----------------------------------------------------------------------------- -FEMaterial* CopyMaterial(FEMaterial* pmat, FEModel* fem) +FECoreBase* CopyClass(FECoreBase* pc, FEModel* fem) { - const char* sztype = pmat->GetTypeStr(); + const char* sztype = pc->GetTypeStr(); // create a new material - FEMaterial* pnew = fecore_new(sztype, fem); - assert(pnew); + FECoreBase* pcnew = fecore_new(pc->GetSuperClassID(), sztype, fem); + assert(pcnew); - pnew->SetID(pmat->GetID()); + pcnew->SetID(pc->GetID()); // copy parameters - pnew->GetParameterList() = pmat->GetParameterList(); + pcnew->GetParameterList() = pc->GetParameterList(); // copy properties - for (int i = 0; i < pmat->Properties(); ++i) + for (int i = 0; i < pc->Properties(); ++i) { - FEProperty* prop = pmat->PropertyClass(i); - FEMaterial* mati = dynamic_cast(prop->get(0)); - if (mati) + FEProperty* prop = pc->PropertyClass(i); + FECoreBase* pci = prop->get(0); + if (pc) { - FEMaterial* newMati = CopyMaterial(mati, fem); - bool b = pnew->SetProperty(i, newMati); assert(b); + FECoreBase* pci_new = CopyClass(pci, fem); assert(pci_new); + bool b = pcnew->SetProperty(i, pci_new); assert(b); } } - return pnew; + return pcnew; } //----------------------------------------------------------------------------- @@ -1878,6 +1905,21 @@ void FEModel::CopyFrom(FEModel& fem) m_imp->m_ftime0 = fem.m_imp->m_ftime0; m_imp->m_pStep = 0; + // copy model variables + // we only copy the user created parameters, which presumably don't exist yet + // in this model. + int NS = fem.GlobalVariables(); + if (NS > 0) + { + assert(GlobalVariables() == 0); + FEParameterList& PL = GetParameterList(); + for (int i = 0; i < NS; ++i) + { + const FEGlobalVariable& var = fem.GetGlobalVariable(i); + AddGlobalVariable(var.name, var.v); + } + } + // --- Steps --- // copy the steps @@ -1920,7 +1962,8 @@ void FEModel::CopyFrom(FEModel& fem) FEMaterial* pmat = fem.GetMaterial(i); // copy the material - FEMaterial* pnew = CopyMaterial(pmat, this); + FEMaterial* pnew = dynamic_cast(CopyClass(pmat, this)); + assert(pnew); // copy the name pnew->SetName(pmat->GetName()); diff --git a/FECore/FEModel.h b/FECore/FEModel.h index 49eba93e6..7f9d9a877 100644 --- a/FECore/FEModel.h +++ b/FECore/FEModel.h @@ -80,6 +80,15 @@ enum TimerID { Timer_ModelSolve }; +//----------------------------------------------------------------------------- +// helper class for managing global (user-defined) variables. +class FEGlobalVariable +{ +public: + double v; + string name; +}; + //----------------------------------------------------------------------------- //! The FEModel class stores all the data for the finite element model, including //! geometry, analysis steps, boundary and loading conditions, contact interfaces @@ -406,6 +415,10 @@ class FECORE_API FEModel : public FECoreBase, public CallbackHandler void SetGlobalConstant(const string& s, double v); double GetGlobalConstant(const string& s); + int GlobalVariables() const; + void AddGlobalVariable(const string& s, double v); + const FEGlobalVariable& GetGlobalVariable(int n); + public: // model data void AddModelData(FEModelData* data); FEModelData* GetModelData(int i); diff --git a/FECore/FEModelDataRecord.cpp b/FECore/FEModelDataRecord.cpp new file mode 100644 index 000000000..dc78d3492 --- /dev/null +++ b/FECore/FEModelDataRecord.cpp @@ -0,0 +1,75 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#include "stdafx.h" +#include "FEModelDataRecord.h" + +REGISTER_SUPER_CLASS(FEModelLogData, FEMODELLOGDATA_ID); + +FEModelLogData::FEModelLogData(FEModel* fem) : FECoreBase(fem) {} +FEModelLogData::~FEModelLogData() {} + +FEModelDataRecord::FEModelDataRecord(FEModel* pfem, const char* szfile) : DataRecord(pfem, szfile, FE_DATA_MODEL) {} +double FEModelDataRecord::Evaluate(int item, int ndata) +{ + assert(item == 0); + return m_data[ndata]->value(); +} + +void FEModelDataRecord::ClearData() +{ + for (int i = 0; i < m_data.size(); ++i) delete m_data[i]; + m_data.clear(); +} + +void FEModelDataRecord::SetData(const char* szexpr) +{ + char szcopy[MAX_STRING] = { 0 }; + strcpy(szcopy, szexpr); + char* sz = szcopy, * ch; + ClearData(); + strcpy(m_szdata, szexpr); + do + { + ch = strchr(sz, ';'); + if (ch) *ch++ = 0; + FEModelLogData* pdata = fecore_new(sz, m_pfem); + if (pdata) m_data.push_back(pdata); + else throw UnknownDataField(sz); + sz = ch; + } while (ch); +} + +void FEModelDataRecord::SelectAllItems() +{ + std::vector items; + items.push_back(0); + SetItemList(items); +} + +int FEModelDataRecord::Size() const +{ + return 1; +} diff --git a/FECore/FEModelDataRecord.h b/FECore/FEModelDataRecord.h new file mode 100644 index 000000000..7882e48d8 --- /dev/null +++ b/FECore/FEModelDataRecord.h @@ -0,0 +1,56 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#pragma once +#include "FECoreBase.h" +#include "DataRecord.h" + +//----------------------------------------------------------------------------- +//! This is the base class for a model data +class FECORE_API FEModelLogData : public FECoreBase +{ + FECORE_SUPER_CLASS + +public: + FEModelLogData(FEModel* fem); + virtual ~FEModelLogData(); + virtual double value() = 0; +}; + +//----------------------------------------------------------------------------- +//! This class records model data +class FECORE_API FEModelDataRecord : public DataRecord +{ +public: + FEModelDataRecord(FEModel* pfem, const char* szfile); + double Evaluate(int item, int ndata); + void SetData(const char* sz); + void ClearData(); + void SelectAllItems(); + int Size() const; + +private: + std::vector m_data; +}; diff --git a/FECore/FEModelParam.cpp b/FECore/FEModelParam.cpp index 60db821a9..6ba01d4de 100644 --- a/FECore/FEModelParam.cpp +++ b/FECore/FEModelParam.cpp @@ -76,6 +76,14 @@ void FEParamDouble::operator = (double v) setValuator(val); } +void FEParamDouble::operator = (const FEParamDouble& p) +{ + if (m_val) delete m_val; + m_val = p.m_val->copy(); + m_scl = p.m_scl; +// m_dom = p.m_dom; +} + // set the valuator void FEParamDouble::setValuator(FEScalarValuator* val) { @@ -134,6 +142,13 @@ void FEParamVec3::operator = (const vec3d& v) setValuator(val); } +void FEParamVec3::operator = (const FEParamVec3& p) +{ + m_val = p.m_val->copy(); + m_scl = p.m_scl; +// m_dom = p.m_dom; +} + // set the valuator void FEParamVec3::setValuator(FEVec3dValuator* val) { @@ -175,6 +190,13 @@ void FEParamMat3d::operator = (const mat3d& v) setValuator(val); } +void FEParamMat3d::operator = (const FEParamMat3d& p) +{ + m_val = p.m_val->copy(); + m_scl = p.m_scl; +// m_dom = p.m_dom; +} + // set the valuator void FEParamMat3d::setValuator(FEMat3dValuator* val) { @@ -221,6 +243,13 @@ void FEParamMat3ds::operator = (const mat3ds& v) setValuator(val); } +void FEParamMat3ds::operator = (const FEParamMat3ds& p) +{ + m_val = p.m_val->copy(); + m_scl = p.m_scl; +// m_dom = p.m_dom; +} + // set the valuator void FEParamMat3ds::setValuator(FEMat3dsValuator* val) { diff --git a/FECore/FEModelParam.h b/FECore/FEModelParam.h index bca7f16e7..2cd7f2627 100644 --- a/FECore/FEModelParam.h +++ b/FECore/FEModelParam.h @@ -72,6 +72,7 @@ class FECORE_API FEParamDouble : public FEModelParam // set the value void operator = (double v); + void operator = (const FEParamDouble& p); // set the valuator void setValuator(FEScalarValuator* val); @@ -110,6 +111,7 @@ class FECORE_API FEParamVec3 : public FEModelParam // set the value void operator = (const vec3d& v); + void operator = (const FEParamVec3& p); // set the valuator void setValuator(FEVec3dValuator* val); @@ -145,6 +147,7 @@ class FECORE_API FEParamMat3d : public FEModelParam // set the value void operator = (const mat3d& v); + void operator = (const FEParamMat3d& v); // set the valuator void setValuator(FEMat3dValuator* val); @@ -179,6 +182,7 @@ class FECORE_API FEParamMat3ds : public FEModelParam // set the value void operator = (const mat3ds& v); + void operator = (const FEParamMat3ds& v); // set the valuator void setValuator(FEMat3dsValuator* val); diff --git a/FECore/FENewtonSolver.cpp b/FECore/FENewtonSolver.cpp index bcdc222e6..d085fb809 100644 --- a/FECore/FENewtonSolver.cpp +++ b/FECore/FENewtonSolver.cpp @@ -260,6 +260,13 @@ void FENewtonSolver::GetSolutionVector(std::vector& U) U = m_Ui + m_ui; } +//----------------------------------------------------------------------------- +//! Get the total solution vector +std::vector FENewtonSolver::GetSolutionVector() const +{ + return m_Ut; +} + //----------------------------------------------------------------------------- //! Creates the global stiffness matrix //! \todo Can we move this to the FEGlobalMatrix::Create function? @@ -487,9 +494,6 @@ void FENewtonSolver::Serialize(DumpStream& ar) m_R1.assign(m_neq, 0); m_ui.assign(m_neq, 0); m_Fd.assign(m_neq, 0); - - // reinitialize the linear system - if (AllocateLinearSystem() == false) throw DumpStream::ReadError(); } } } diff --git a/FECore/FENewtonSolver.h b/FECore/FENewtonSolver.h index 5806bb4d3..b7fda0b2f 100644 --- a/FECore/FENewtonSolver.h +++ b/FECore/FENewtonSolver.h @@ -152,6 +152,9 @@ class FECORE_API FENewtonSolver : public FESolver //! Get the total solution vector (for current Newton iteration) virtual void GetSolutionVector(std::vector& U); + //! Get the total solution vector + std::vector GetSolutionVector() const override; + public: //! do augmentations bool DoAugmentations(); diff --git a/FECore/FEParameterList.cpp b/FECore/FEParameterList.cpp index 6a4d0930f..e0108ff4b 100644 --- a/FECore/FEParameterList.cpp +++ b/FECore/FEParameterList.cpp @@ -63,6 +63,7 @@ void FEParameterList::operator = (FEParameterList& l) case FE_PARAM_MAT3D : d.value() = s.value(); break; case FE_PARAM_MAT3DS: d.value() = s.value(); break; case FE_PARAM_TENS3DRS: d.value() = s.value(); break; + case FE_PARAM_STD_STRING: d.value() = s.value(); break; case FE_PARAM_DOUBLE_MAPPED: { FEParamDouble& mat3d = d.value(); @@ -77,6 +78,11 @@ void FEParameterList::operator = (FEParameterList& l) mat3d.setValuator(src.valuator()->copy()); } break; + case FE_PARAM_STD_VECTOR_VEC2D: + { + d.value< std::vector >() = s.value< std::vector >(); + } + break; default: assert(false); } diff --git a/FECore/FEPlotData.cpp b/FECore/FEPlotData.cpp index 31bd0aea3..ec06ab84e 100644 --- a/FECore/FEPlotData.cpp +++ b/FECore/FEPlotData.cpp @@ -39,6 +39,7 @@ FEPlotData::FEPlotData(FEModel* fem) : FECoreBase(fem) m_nregion = FE_REGION_NODE; m_arraySize = 0; + m_szdom[0] = 0; } //----------------------------------------------------------------------------- @@ -49,6 +50,7 @@ FEPlotData::FEPlotData(FEModel* fem, Region_Type R, Var_Type t, Storage_Fmt s) : m_nregion = R; m_arraySize = 0; + m_szdom[0] = 0; } //----------------------------------------------------------------------------- diff --git a/FECore/FEPointFunction.cpp b/FECore/FEPointFunction.cpp index 3e9eef9b7..ea61d39a7 100644 --- a/FECore/FEPointFunction.cpp +++ b/FECore/FEPointFunction.cpp @@ -45,6 +45,39 @@ class FEPointFunction::Imp { public: BSpline* m_spline; //!< B-spline + +public: + bool InitSpline(FEPointFunction* pf) + { + const int N = pf->Points(); + // initialize B-spline + if (m_spline) delete m_spline; + m_spline = new BSpline(); + switch (pf->m_fnc) { + case CSPLINE: + { + int korder = min(N, 4); + if (!m_spline->init_interpolation(korder, pf->m_points)) return false; + } + break; + case CPOINTS: + { + int korder = min(N, 4); + if (!m_spline->init(korder, pf->m_points)) return false; + } + break; + case APPROX: + { + int korder = min(N / 2 + 1, 4); + if (!m_spline->init_approximation(korder, N / 2 + 1, pf->m_points)) return false; + } + break; + default: + break; + } + + return true; + } }; //----------------------------------------------------------------------------- @@ -65,34 +98,9 @@ FEPointFunction::~FEPointFunction() //! Clears the loadcurve data bool FEPointFunction::Init() { - if (m_fnc > SMOOTH) { - const int N = Points(); - // initialize B-spline - if (imp->m_spline) delete imp->m_spline; - imp->m_spline = new BSpline(); - switch (m_fnc) { - case CSPLINE: - { - int korder = min(N,4); - if (!imp->m_spline->init_interpolation(korder, m_points)) return false; - } - break; - case CPOINTS: - { - int korder = min(N,4); - if (!imp->m_spline->init(korder, m_points)) return false; - } - break; - case APPROX: - { - int korder = min(N/2+1,4); - if (!imp->m_spline->init_approximation(korder, N/2+1, m_points)) return false; - } - break; - - default: - break; - } + if (m_fnc > SMOOTH) + { + imp->InitSpline(this); } return FEFunction1D::Init(); } @@ -439,6 +447,12 @@ void FEPointFunction::Serialize(DumpStream& ar) ar >> n; m_fnc = (INTFUNC)n; ar >> n; m_ext = (EXTMODE)n; ar >> m_points; + + if (ar.IsShallow() == false) + { + bool b = imp->InitSpline(this); + assert(b); + } } } diff --git a/FECore/FEScalarValuator.cpp b/FECore/FEScalarValuator.cpp index 5d43c0e8c..c046493c0 100644 --- a/FECore/FEScalarValuator.cpp +++ b/FECore/FEScalarValuator.cpp @@ -209,6 +209,11 @@ void FEMappedValue::setDataMap(FEDataMap* val) m_val = val; } +FEDataMap* FEMappedValue::dataMap() +{ + return m_val; +} + double FEMappedValue::operator()(const FEMaterialPoint& pt) { return m_val->value(pt); @@ -216,7 +221,7 @@ double FEMappedValue::operator()(const FEMaterialPoint& pt) FEScalarValuator* FEMappedValue::copy() { - FEMappedValue* map = new FEMappedValue(GetFEModel()); + FEMappedValue* map = fecore_alloc(FEMappedValue, GetFEModel()); map->setDataMap(m_val); return map; } diff --git a/FECore/FEScalarValuator.h b/FECore/FEScalarValuator.h index e88a2c7b5..9d57834a4 100644 --- a/FECore/FEScalarValuator.h +++ b/FECore/FEScalarValuator.h @@ -114,6 +114,8 @@ class FECORE_API FEMappedValue : public FEScalarValuator FEMappedValue(FEModel* fem); void setDataMap(FEDataMap* val); + FEDataMap* dataMap(); + double operator()(const FEMaterialPoint& pt) override; FEScalarValuator* copy() override; diff --git a/FECore/FESolver.cpp b/FECore/FESolver.cpp index 0ba8bfce6..7d9129c31 100644 --- a/FECore/FESolver.cpp +++ b/FECore/FESolver.cpp @@ -164,6 +164,13 @@ double FESolver::ExtractSolutionNorm(const vector& v, const FEDofList& d return norm; } +//----------------------------------------------------------------------------- +// return the solution vector +std::vector FESolver::GetSolutionVector() const +{ + return std::vector(); +} + //----------------------------------------------------------------------------- // see if the dofs in the dof list are active in this solver bool FESolver::HasActiveDofs(const FEDofList& dof) diff --git a/FECore/FESolver.h b/FECore/FESolver.h index d6d63f8a3..4695b8bf7 100644 --- a/FECore/FESolver.h +++ b/FECore/FESolver.h @@ -181,6 +181,9 @@ class FECORE_API FESolver : public FECoreBase // extract the (square) norm of a solution vector double ExtractSolutionNorm(const vector& v, const FEDofList& dofs) const; + // return the solution vector + virtual std::vector GetSolutionVector() const; + public: //TODO Move these parameters elsewhere int m_bwopt; //!< bandwidth optimization flag int m_msymm; //!< matrix symmetry flag for linear solver allocation diff --git a/FECore/FESurface.cpp b/FECore/FESurface.cpp index 69c7d3630..20d2eae26 100644 --- a/FECore/FESurface.cpp +++ b/FECore/FESurface.cpp @@ -381,49 +381,47 @@ void FESurface::ForEachSurfaceElement(std::function for (size_t i = 0; i < m_el.size(); ++i) f(m_el[i]); } -// TODO: I should be able to speed this up void FESurface::FindElements(FESurfaceElement& el) { - // get the mesh to which this surface belongs - FEMesh* mesh = GetMesh(); - int ndom = mesh->Domains(); - // check all solid domains - for (int k = 0; kDomain(k); - - // check each solid element in this domain - int nselem = pdom.Elements(); -#pragma omp parallel for shared (nselem) - for (int l = 0; l& sf = el.m_node; + int node = el.m_node[0]; + int nval = NEL.Valence(node); + FEElement** ppe = NEL.ElementList(node); + for (int i = 0; i < nval; ++i) + { + FEElement& sel = *ppe[i]; - // check all faces of this solid element - int nfaces = sel.Faces(); - for (int j = 0; jgw[0]; } // weights of integration points double gr(int n) const { return ((FESurfaceElementTraits*)(m_pT))->gr[n]; } // integration point coordinate r double gs(int n) const { return ((FESurfaceElementTraits*)(m_pT))->gs[n]; } // integration point coordinate s + double cr() const { return ((FESurfaceElementTraits*)(m_pT))->cr; } // centroid point coordinate r + double cs() const { return ((FESurfaceElementTraits*)(m_pT))->cs; } // centroid point coordinate s double* Gr(int n) const { return ((FESurfaceElementTraits*)(m_pT))->Gr[n]; } // shape function derivative to r double* Gs(int n) const { return ((FESurfaceElementTraits*)(m_pT))->Gs[n]; } // shape function derivative to s diff --git a/FECore/FESurfaceLoad.h b/FECore/FESurfaceLoad.h index d55679a95..088e1c9b7 100644 --- a/FECore/FESurfaceLoad.h +++ b/FECore/FESurfaceLoad.h @@ -57,6 +57,10 @@ class FECORE_API FESurfaceLoad : public FEModelLoad void Serialize(DumpStream& ar) override; const FEDofList& GetDofList() const; + +public: + virtual double ScalarLoad(FESurfaceMaterialPoint& mp) { return 0; } + virtual vec3d VectorLoad(FESurfaceMaterialPoint& mp) { return vec3d(0,0,0); } protected: FESurface* m_psurf; diff --git a/FECore/FESurfacePair.cpp b/FECore/FESurfacePair.cpp index a98fe5e85..dccfa2163 100644 --- a/FECore/FESurfacePair.cpp +++ b/FECore/FESurfacePair.cpp @@ -68,3 +68,12 @@ void FESurfacePair::SetSecondarySurface(FEFacetSet* pf) { m_surface2 = pf; } + +void FESurfacePair::Serialize(DumpStream& ar) +{ + if (ar.IsShallow()) return; + + ar& m_surface1; + ar& m_surface2; + ar& m_mesh; +} diff --git a/FECore/FESurfacePair.h b/FECore/FESurfacePair.h index c930a4049..21a7fe85e 100644 --- a/FECore/FESurfacePair.h +++ b/FECore/FESurfacePair.h @@ -50,6 +50,8 @@ class FECORE_API FESurfacePair FEFacetSet* GetSecondarySurface(); void SetSecondarySurface(FEFacetSet* pf); + void Serialize(DumpStream& ar); + private: std::string m_name; FEFacetSet* m_surface1; // the primary surface diff --git a/FECore/FETimeStepController.cpp b/FECore/FETimeStepController.cpp index 5d4f127ff..c9760ccae 100644 --- a/FECore/FETimeStepController.cpp +++ b/FECore/FETimeStepController.cpp @@ -68,6 +68,8 @@ FETimeStepController::FETimeStepController(FEModel* fem) : FECoreBase(fem) m_ddt = 0; m_dtp = 0; + m_mp_repeat = false; + m_mp_toff = 0.0; m_dtforce = false; } @@ -113,6 +115,12 @@ bool FETimeStepController::Init() m_nmplc = plc->GetID(); fem->DetachLoadController(p); + // print a warning that dtmax is ignored + if (m_dtmax != 0) + { + feLogWarning("dtmax is ignored when specifying must points."); + } + // if a must-point curve is defined and the must-points are empty, // we copy the load curve points to the must-points if (m_must_points.empty()) @@ -121,11 +129,19 @@ bool FETimeStepController::Init() if (lc) { FEPointFunction& f = lc->GetFunction(); + + // make sure we have at least two points + if (f.Points() < 2) return false; + + // copy must points for (int i = 0; i < f.Points(); ++i) { double ti = f.LoadPoint(i).time; m_must_points.push_back(ti); } + + // check for repeat setting + if (f.m_ext == FEPointFunction::REPEAT) m_mp_repeat = true; } } } @@ -143,6 +159,7 @@ void FETimeStepController::Reset() m_dtp = m_step->m_dt0; m_nmust = -1; m_next_must = -1; + m_mp_toff = 0.0; } //----------------------------------------------------------------------------- @@ -221,24 +238,29 @@ void FETimeStepController::AutoTimeStep(int niter) // Adjust time step size if (scale >= 1) { - dtn = dtn + (dtmax - dtn)*MIN(.20, scale - 1); - dtn = MIN(dtn, 5.0*m_dtp); - dtn = MIN(dtn, dtmax); + dtn = dtn + (dtmax - dtn) * MIN(.20, scale - 1); + dtn = MIN(dtn, 5.0 * m_dtp); + if (dtmax > 0) dtn = MIN(dtn, dtmax); } else { - dtn = dtn - (dtn - m_dtmin)*(1 - scale); - dtn = MAX(dtn, m_dtmin); - dtn = MIN(dtn, dtmax); + dtn = dtn - (dtn - m_dtmin) * (1 - scale); + if (m_dtmin > 0) dtn = MAX(dtn, m_dtmin); + if (dtmax > 0) dtn = MIN(dtn, dtmax); } - - // Report new time step size - if (dtn > dt) - feLogEx(fem, "\nAUTO STEPPER: increasing time step, dt = %lg\n\n", dtn); - else if (dtn < dt) - feLogEx(fem, "\nAUTO STEPPER: decreasing time step, dt = %lg\n\n", dtn); + } + else if (niter == 0) + { + if (m_dtmin > 0) dtn = MAX(dtn, m_dtmin); + if (dtmax > 0) dtn = MIN(dtn, dtmax); } + // Report new time step size + if (dtn > dt) + feLogEx(fem, "\nAUTO STEPPER: increasing time step, dt = %lg\n\n", dtn); + else if (dtn < dt) + feLogEx(fem, "\nAUTO STEPPER: decreasing time step, dt = %lg\n\n", dtn); + // Store this time step value. This is the value that will be used to evaluate // the next time step increment. This will not include adjustments due to the must-point // controller since this could create really small time steps that may be difficult to @@ -256,6 +278,7 @@ void FETimeStepController::AutoTimeStep(int niter) } // store time step size + assert(dtn > 0); m_step->m_dt = dtn; } @@ -269,54 +292,53 @@ void FETimeStepController::AutoTimeStep(int niter) double FETimeStepController::CheckMustPoints(double t, double dt) { FEModel* fem = m_step->GetFEModel(); + const double eps = m_step->m_tend * 1e-12; - double tnew = t + dt; - double dtnew = dt; - const double eps = m_step->m_tend*1e-12; - double tmust = tnew + eps; m_nmust = -1; const int points = (int)m_must_points.size(); - if (m_next_must < points) + + if (m_next_must >= points) { - double lp; - if (m_next_must < 0) + if (m_mp_repeat) { - // find the first must-point that is on or past this time - m_next_must = 0; - bool bfound = false; - do - { - lp = m_must_points[m_next_must]; - if ((tmust > lp) && (fabs(tnew - lp) > 1e-12)) ++m_next_must; - else bfound = true; - } while ((bfound == false) && (m_next_must < points)); - - // make sure we did not pass all must points - if (m_next_must >= points) return dt; + m_mp_toff += m_must_points.back(); + m_next_must = -1; } - else lp = m_must_points[m_next_must]; + else return dt; + } - // TODO: what happens when dtnew < dtmin and the next time step fails?? - if (tmust > lp) - { - dtnew = lp - t; - feLogEx(fem, "MUST POINT CONTROLLER: adjusting time step. dt = %lg\n\n", dtnew); - m_nmust = m_next_must++; - } - else if (fabs(tnew - lp) < 1e-12) - { - m_nmust = m_next_must++; - tnew = lp; - dtnew = tnew - t; - feLogEx(fem, "MUST POINT CONTROLLER: adjusting time step. dt = %lg\n\n", dtnew); - } - else if (tnew > m_step->m_tend) + // set the first must-point if it has not been set + if (m_next_must < 0) + { + m_next_must = 0; + while ((m_next_must < points) && (m_must_points[m_next_must] + m_mp_toff < t + eps)) { - dtnew = m_step->m_tend - t; - feLogEx(fem, "MUST POINT CONTROLLER: adjusting time step. dt = %lg\n\n", dtnew); - m_nmust = m_next_must++; + m_next_must++; + if (m_next_must >= points) + { + if (m_mp_repeat) + { + m_next_must = 0; + m_mp_toff += m_must_points.back(); + } + else return dt; + } } } + + assert(m_next_must < points); + double tmust = m_must_points[m_next_must] + m_mp_toff; + assert(tmust + eps > t); + + double dtnew = dt; + double tnew = t + dt; + if (tmust < tnew + eps) + { + dtnew = tmust - t; + feLogEx(fem, "MUST POINT CONTROLLER: adjusting time step. dt = %lg\n\n", dtnew); + m_nmust = m_next_must++; + } + return dtnew; } @@ -329,6 +351,8 @@ void FETimeStepController::Serialize(DumpStream& ar) ar & m_nmplc; ar & m_nmust; ar & m_next_must; + ar & m_mp_toff; + ar & m_mp_repeat; ar & m_ddt & m_dtp; ar & m_step; ar & m_must_points; diff --git a/FECore/FETimeStepController.h b/FECore/FETimeStepController.h index 18a0b2d30..a6af2d7ae 100644 --- a/FECore/FETimeStepController.h +++ b/FECore/FETimeStepController.h @@ -80,6 +80,8 @@ class FECORE_API FETimeStepController : public FECoreBase double m_cutback; //!< cut back factor used in aggressive time stepping std::vector m_must_points; //!< the list of must-points + bool m_mp_repeat; //!< repeat must-points + double m_mp_toff; //!< offset for repeat must-points private: double m_ddt; //!< used by auto-time stepper diff --git a/FECore/MDerive.cpp b/FECore/MDerive.cpp index dd70d1bee..ef9de5a37 100644 --- a/FECore/MDerive.cpp +++ b/FECore/MDerive.cpp @@ -38,6 +38,9 @@ SOFTWARE.*/ MITEM MDerive(const MITEM& a, const MVariable& x) { MITEM e = MEvaluate(a); + + if (is_dependent(e, x) == false) return 0.0; + switch (e.Type()) { case MCONST: @@ -76,8 +79,8 @@ MITEM MDerive(const MITEM& a, const MVariable& x) { MITEM l = e.Left(); MITEM r = e.Right(); - if (isConst(r) || is_named(r) || is_frac(r)) return (r*(l^(r-1.0)))*MDerive(l, x); - else if (isConst(l) || is_named(l) || is_frac(l)) return (Log(l)*e)*MDerive(r, x); + if (is_dependent(r, x) == false) return (r*(l^(r-1.0)))*MDerive(l, x); + else if (is_dependent(l, x) == false) return (Log(l)*e)*MDerive(r, x); else { MITEM dl = MDerive(l, x); @@ -122,6 +125,10 @@ MITEM MDerive(const MITEM& a, const MVariable& x) MITEM Pi = new MNamedCt(PI, "pi"); return -(2/Sqrt(Pi))*Exp(-(p^2))*dp; } + if (s.compare("H") == 0) + { + return 0.0; + } assert(false); } break; diff --git a/FECore/MItem.h b/FECore/MItem.h index a87a64d84..536fb366d 100644 --- a/FECore/MItem.h +++ b/FECore/MItem.h @@ -593,6 +593,8 @@ bool is_dependent(const MItem* pi, const MVariable& x); // is i dependent on x bool is_dependent(const MItem* pi, const MItem* px); // is i dependent on x bool is_scalar(const MItem* pi); // is the expression scalar +inline bool is_rconst(const MITEM& i) { return is_rconst(i.ItemPtr()); } + bool is_pi(const MItem* pi); // is pi the constant pi? inline bool is_pi(const MITEM& i) { return is_pi(i.ItemPtr()); } diff --git a/FECore/Quadric.cpp b/FECore/Quadric.cpp new file mode 100644 index 000000000..e178c9725 --- /dev/null +++ b/FECore/Quadric.cpp @@ -0,0 +1,334 @@ +/*This file is part of the FEBio Studio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio-Studio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +#include "Quadric.h" +#include "matrix.h" +#include + +#ifndef M_PI +#define M_PI 3.141592653589793238462643 +#endif + +//------------------------------------------------------------------------------- +// constructor +Quadric::Quadric(Quadric* q) +{ + for (int i=0; i<10; ++i) m_c[i] = q->m_c[i]; + m_p = q->m_p; +} + +//------------------------------------------------------------------------------- +// copy constructor +Quadric::Quadric(const Quadric& q) +{ + for (int i=0; i<10; ++i) m_c[i] = q.m_c[i]; + m_p = q.m_p; +} + +//------------------------------------------------------------------------------- +// destructor +Quadric::~Quadric() +{ + for (int i=0; i<10; ++i) m_c[i] = 0; + m_p.clear(); +} + +//-------------------------------------------------------------------------------------- +bool Quadric::GetQuadricCoeficients() +{ + // get number of points in point cloud + int N = (int)m_p.size(); + + matrix A(10,10); + matrix d(1,10); + + //Populate D + A.zero(); + for (int j = 0; j < N; ++j) + { + vec3d p = m_p[j]; + d(0,0) = p.x*p.x; + d(0,1) = p.y*p.y; + d(0,2) = p.z*p.z; + d(0,3) = p.y*p.z; + d(0,4) = p.x*p.z; + d(0,5) = p.x*p.y; + d(0,6) = p.x; + d(0,7) = p.y; + d(0,8) = p.z; + d(0,9) = 1; + matrix D(10,10); + D = d.transpose()*d; + A += D; + } + + // find eigenvalues and eigenvectors of A + vector Aval; + matrix Avec(10,10); + bool good = A.eigen_vectors(Avec, Aval); + + if (good) { + // find smallest eigenvalue + int imin=0; + for (int i=1; i<10; ++i) + if (fabs(Aval[i]) < fabs(Aval[imin])) imin = i; + //if (Aval[i] < Aval[imin]) imin = i; + + // store the coefficients of the quadric surface + for (int j=0; j<10; ++j) + m_c[j] = Avec(j,imin); + + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------- +// Evaluate the surface normal at point p +vec3d Quadric::SurfaceNormal(const vec3d p) +{ + // extract quadric surface coefficients + // F(x,y,z) = a x^2 + b y^2 + c z^2 + e y z + f z x + g x y + l x + m y + n z + d = 0 + double a = m_c[0]; + double b = m_c[1]; + double c = m_c[2]; + double e = m_c[3]; + double f = m_c[4]; + double g = m_c[5]; + double l = m_c[6]; + double m = m_c[7]; + double n = m_c[8]; + + // evaluate first derivatives + double Fx = 2*a*p.x + f*p.z + g*p.y + l; + double Fy = 2*b*p.y + e*p.z + g*p.x + m; + double Fz = 2*c*p.z + e*p.y + f*p.x + n; + + vec3d xn(Fx,Fy,Fz); + xn.unit(); + + return xn; +} + +//-------------------------------------------------------------------------------------- +void Quadric::SurfaceCurvature(const vec3d p, const vec3d pn, vec2d& kappa, vec3d* v) +{ + double eps = 1e-9; + + // find magnitude of quadric gradient components + // to determine if we need to do permutation of axes + double f1 = fabs(2*m_c[0]*p.x + 2*m_c[4]*p.z + 2*m_c[5]*p.y + 2*m_c[6]); + double f2 = fabs(2*m_c[1]*p.y + 2*m_c[3]*p.z + 2*m_c[5]*p.x + 2*m_c[7]); + double f3 = fabs(2*m_c[2]*p.z + 2*m_c[3]*p.y + 2*m_c[4]*p.x + 2*m_c[8]); + + // pick direction with maximum gradient component magnitude + int e1 = 0, e2 = 1, e3 = 2; + double vmax = fmax(fmax(f1,f2),f3); + if (vmax == f1) { e3 = 0; e1 = 1; e2 = 2; } + else if (vmax == f2) { e3 = 1; e1 = 2; e2 = 0; } + + // extract quadric surface coefficients (and clean up roundoff errors) + // F(x,y,z) = a x^2 + b y^2 + c z^2 + e y z + f z x + g x y + l x + m y + n z + d = 0 + double a = (fabs(m_c[e1]) > eps) ? m_c[e1] : 0; + double b = (fabs(m_c[e2]) > eps) ? m_c[e2] : 0; + double c = (fabs(m_c[e3]) > eps) ? m_c[e3] : 0; + double e = (fabs(m_c[e1+3]) > eps) ? m_c[e1+3] : 0; + double f = (fabs(m_c[e2+3]) > eps) ? m_c[e2+3] : 0; + double g = (fabs(m_c[e3+3]) > eps) ? m_c[e3+3] : 0; + double l = (fabs(m_c[e1+6]) > eps) ? m_c[e1+6] : 0; + double m = (fabs(m_c[e2+6]) > eps) ? m_c[e2+6] : 0; + double n = (fabs(m_c[e3+6]) > eps) ? m_c[e3+6] : 0; + + // evaluate quadric surface derivatives and normal + double x = p(e1), y = p(e2), z = p(e3); + double den = n + f*x + e*y + 2*c*z; + double zx = -(l + 2*a*x + g*y + f*z)/den; + double zy = -(m + g*x + 2*b*y + e*z)/den; + double zxx = -2*(a + (f + c*zx)*zx)/den; + double zyy = -2*(b + (e + c*zy)*zy)/den; + double zxy = -(g + e*zx + f*zy + 2*c*zx*zy)/den; + vec3d xu, xv; + xu(e1) = 1; xu(e2) = 0; xu(e3) = zx; + xv(e1) = 0; xv(e2) = 1; xv(e3) = zy; + vec3d xuu, xvv, xuv; + xuu(e1) = 0; xuu(e2) = 0; xuu(e3) = zxx; + xvv(e1) = 0; xvv(e2) = 0; xvv(e3) = zyy; + xuv(e1) = 0; xuv(e2) = 0; xuv(e3) = zxy; + vec3d xn = (xu ^ xv).normalized(); + + // get coefficients of fundamental forms + double E = xu*xu, F = xu*xv, G = xv*xv; + double L = xuu*xn, M = xuv*xn, N = xvv*xn; + + // evaluate mean and gaussian curvatures + double tmp = E*G - F*F; + // gaussian + double kg = (L*N - M*M)/tmp; + // mean + double km = (2*F*M - E*N - G*L)/2./tmp; + // evaluate principal curvatures + double d1 = sqrt(km*km - kg); + // max curvature + double kmax = km + d1; + double kmin = km - d1; + + // evaluate principal directions of curvature + double a2 = F*N - G*M, b2 = E*N - G*L, c2 = E*M - F*L; + double d2 = b2*b2 - 4*a2*c2; if (fabs(d2) < 0) d2 = 0; + d2 = sqrt(d2); // d2=0 represents an umbilical point + double thmax = atan2(-b2 + d2, 2*a2); + double thmin = (d2 != 0) ? atan2(-b2 - d2, 2*a2) : thmax + M_PI/2; + vec3d xmax = xu*cos(thmax) + xv*sin(thmax); xmax.unit(); + vec3d xmin = xu*cos(thmin) + xv*sin(thmin); xmin.unit(); + + // check quadric normal versus face normal + if (xn*pn >= 0) { + kappa.x() = kmax; kappa.y() = kmin; + v[0] = xmax; v[1] = xmin; + } + else { + kappa.x() = kmin; kappa.y() = kmax; + v[0] = xmin; v[1] = xmax; + } + // fix handedness if neeeded + if ((v[0]^v[1])*pn < 0) v[0] = -v[0]; +} + +//-------------------------------------------------------------------------------------- +// Find ray-quadric surface intersections x: p is point on ray, n is normal along ray +// There are three possible solutions: 0 roots, 1 root, and 2 roots +// When 2 roots are found, sort results from closest to farthest +void Quadric::RayQuadricIntersection(const vec3d p, const vec3d n, vector* x, vector* t) +{ + double a = n.x*n.x*m_c[0]+n.y*n.y*m_c[1]+n.z*n.z*m_c[2]+n.y*n.z*m_c[3]+n.x*n.z*m_c[4]+n.x*n.y*m_c[5]; + double b = n.x*(2*p.x*m_c[0]+p.z*m_c[4]+p.y*m_c[5]+m_c[6]) + +n.y*(2*p.y*m_c[1]+p.z*m_c[3]+p.x*m_c[5]+m_c[7]) + +n.z*(2*p.z*m_c[2]+p.y*m_c[3]+p.x*m_c[4]+m_c[8]); + double c = p.x*p.x*m_c[0]+p.y*p.y*m_c[1]+p.z*p.z*m_c[2] + +p.x*(p.z*m_c[4]+p.y*m_c[5]+m_c[6]) + +p.y*(p.z*m_c[3]+m_c[7])+p.z*m_c[8]+m_c[9]; + + x->clear(); + t->clear(); + double d = b*b - 4*a*c; + if (d < 0) return; + else if ((a == 0) && (b != 0)) { + double t1 = -c/b; + t->push_back(t1); + x->push_back(p + n*t1); + return; + } + else if ((d == 0) && (a != 0)) { + double t1 = -b/(2*a); + t->push_back(t1); + x->push_back(p + n*t1); + return; + } + else if (a != 0) { + d = sqrt(d); + double t1 = (-b - d)/(2*a); + double t2 = (-b + d)/(2*a); + if (fabs(t1) < fabs(t2)) { + t->push_back(t1); + t->push_back(t2); + x->push_back(p + n*t1); + x->push_back(p + n*t2); + } + else { + t->push_back(t2); + t->push_back(t1); + x->push_back(p + n*t2); + x->push_back(p + n*t1); + } + } +} + +//-------------------------------------------------------------------------------------- +// This routine finds a closest point approximation (not the exact solution) +vec3d Quadric::ClosestPoint(const vec3d p) +{ + vector xsol; + vector tsol; + + vec3d n1 = vec3d(1,0,0); + vec3d n2 = vec3d(0,1,0); + vec3d n3 = vec3d(0,0,1); + vector x1, x2, x3; + vector t1, t2, t3; + RayQuadricIntersection(p, n1, &x1, &t1); + RayQuadricIntersection(p, n2, &x2, &t2); + RayQuadricIntersection(p, n3, &x3, &t3); + if (t1.size() > 0) { + xsol.push_back(x1[0]); + tsol.push_back(t1[0]); + } + if (t2.size() > 0) { + xsol.push_back(x2[0]); + tsol.push_back(t2[0]); + } + if (t3.size() > 0) { + xsol.push_back(x3[0]); + tsol.push_back(t3[0]); + } + + int N = (int)tsol.size(); + if (N > 0) { + int imin = 0; + double tmin = fabs(tsol[imin]); + for (int i = 1; i x; + vector t; + RayQuadricIntersection(p, norm, &x, &t); + + if (t.size() > 0) { + xsol = x[0]; + tsol = t[0]; + + return xsol; + } + else { + ClosestPoint(p); + } + return p; +} diff --git a/FECore/Quadric.h b/FECore/Quadric.h new file mode 100644 index 000000000..a07212aa6 --- /dev/null +++ b/FECore/Quadric.h @@ -0,0 +1,65 @@ +/*This file is part of the FEBio Studio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio-Studio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ + +#pragma once +#include +#include "vec3d.h" + +class Quadric +{ +public: + Quadric() {} + Quadric(std::vector& p) { m_p = p; } + Quadric(Quadric* q); + Quadric(const Quadric& q); + ~Quadric(); + +public: + // assign a point cloud to this bivariate spline object + void SetPoints(std::vector& p) { m_p = p; } + + // fit the point cloud to get quadric surface coefficients + bool GetQuadricCoeficients(); + + // Evaluate the surface normal at point p + vec3d SurfaceNormal(const vec3d p); + + // Evaluate the surface principal curvatures kappa and directions v at point p + void SurfaceCurvature(const vec3d p, const vec3d n, vec2d& kappa, vec3d* v); + + // Find ray-quadric surface intersections x: p is point on ray, n is normal along ray + void RayQuadricIntersection(const vec3d p, const vec3d n, std::vector* x, std::vector* t = nullptr); + + // Find the point on the quadric closest to the point p + vec3d ClosestPoint(const vec3d p); + + // Find the point on the quadric closest to the point p + vec3d ClosestPoint(const vec3d p, const vec3d norm); + +public: + double m_c[10]; // quadric surface coefficients + std::vector m_p; // point coordinates +}; diff --git a/FECore/QuadricFit.cpp b/FECore/QuadricFit.cpp new file mode 100644 index 000000000..bf9d8c4da --- /dev/null +++ b/FECore/QuadricFit.cpp @@ -0,0 +1,285 @@ +/*This file is part of the FEBio Studio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio-Studio.txt for details. + + Copyright (c) 2020 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + +// onchoidFit.cpp: implementation of the QuadricFit class. +// +////////////////////////////////////////////////////////////////////// +#include "stdafx.h" +#include "QuadricFit.h" +#include + +using std::swap; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +//------------------------------------------------------------------------------- +// constructor +QuadricFit::QuadricFit() +{ + m_rc = m_c2 = vec3d(0,0,0); + m_c = 0; + m_ax[0] = m_ax[1] = m_ax [2] = vec3d(0,0,0); + m_quad = new Quadric(); + m_eps = 1e-3; +} + +//------------------------------------------------------------------------------- +// copy constructor +QuadricFit::QuadricFit(const QuadricFit& qf) +{ + m_rc = qf.m_rc; + m_c2 = qf.m_c2; + m_c = qf.m_c; + m_ax[0] = qf.m_ax[0]; + m_ax[1] = qf.m_ax[1]; + m_ax[2] = qf.m_ax[2]; + m_quad = new Quadric(*qf.m_quad); + m_eps = qf.m_eps; +} + +//------------------------------------------------------------------------------- +// destructor +QuadricFit::~QuadricFit() +{ + +} + +//------------------------------------------------------------------------------- +void QuadricFit::GetOrientation() +{ + + mat3ds C(m_quad->m_c[0], m_quad->m_c[1], m_quad->m_c[2], + m_quad->m_c[5], m_quad->m_c[3], m_quad->m_c[4]); + vec3d v = vec3d(m_quad->m_c[6], m_quad->m_c[7], m_quad->m_c[8]); + double c = m_quad->m_c[9]; + + double eval[3]; + vec3d evec[3]; + C.eigen2(eval, evec); // eigenvalues sorted from smallest to largest + + // rectify sign of eigenvalues + double emag = sqrt(eval[0]*eval[0] + eval[1]*eval[1] + eval[2]*eval[2]); + if (eval[2] <= emag*m_eps) { + eval[0] = -eval[0]; + eval[1] = -eval[1]; + eval[2] = -eval[2]; + v = -v; + c = -c; + } + + // re-sort eigenvalues and eigenvectors from largest to smalles + if (eval[0] < eval[2]) { swap(eval[0],eval[2]); swap(evec[0], evec[2]); } + if (eval[0] < eval[1]) { swap(eval[0],eval[1]); swap(evec[0], evec[1]); } + if (eval[1] < eval[2]) { swap(eval[1],eval[2]); swap(evec[1], evec[2]); } + + // estimate the relative magnitudes of the eigenvalues + if (fabs(eval[0]) < m_eps*emag) eval[0] = 0; + if (fabs(eval[1]) < m_eps*emag) eval[1] = 0; + if (fabs(eval[2]) < m_eps*emag) eval[2] = 0; + + // normalize vectors + evec[0].unit(); evec[1].unit(); evec[2].unit(); + // clean up vector + if (fabs(evec[0].x) < m_eps) evec[0].x = 0; if (fabs(evec[0].y) < m_eps) evec[0].y = 0; if (fabs(evec[0].z) < m_eps) evec[0].z = 0; + if (fabs(evec[1].x) < m_eps) evec[1].x = 0; if (fabs(evec[1].y) < m_eps) evec[1].y = 0; if (fabs(evec[1].z) < m_eps) evec[1].z = 0; + if (fabs(evec[2].x) < m_eps) evec[2].x = 0; if (fabs(evec[2].y) < m_eps) evec[2].y = 0; if (fabs(evec[2].z) < m_eps) evec[2].z = 0; + evec[0].unit(); evec[1].unit(); evec[2].unit(); + // check if basis is right-handed or not + double rh = (evec[0] ^ evec[1])*evec[2]; + if (rh < 0) evec[1] = evec[2] ^ evec[0]; + + // estimate the relative magnitudes of the components of v + if (fabs(v.x) < m_eps*emag) v.x = 0; + if (fabs(v.y) < m_eps*emag) v.y = 0; + if (fabs(v.z) < m_eps*emag) v.z = 0; + + mat3d Q(evec[0].x, evec[1].x, evec[2].x, + evec[0].y, evec[1].y, evec[2].y, + evec[0].z, evec[1].z, evec[2].z); + + m_ax[0] = evec[0]; + m_ax[1] = evec[1]; + m_ax[2] = evec[2]; + + m_c2 = vec3d(eval[0], eval[1], eval[2]); + vec3d d = Q.transpose()*v; + m_v = v; + + vec3d X0; + if (m_c2.x*m_c2.y*m_c2.z != 0) { + X0.x = -d.x/(2*m_c2.x); + X0.y = -d.y/(2*m_c2.y); + X0.z = -d.z/(2*m_c2.z); + m_c = c - m_c2.x*pow(X0.x,2) - m_c2.y*pow(X0.y,2) - m_c2.z*pow(X0.z,2); + if (fabs(m_c) < m_eps) m_c = 0; + if (m_c != 0) { + m_c2 /= fabs(m_c); + m_c /= fabs(m_c); + } + } + else if (m_c2.x*m_c2.y != 0) { + X0.x = -d.x/(2*m_c2.x); + X0.y = -d.y/(2*m_c2.y); + X0.z = 0; + m_c = c - m_c2.x*pow(X0.x,2) - m_c2.y*pow(X0.y,2); + if (m_c != 0) { + m_c2 /= fabs(m_c); + m_c /= fabs(m_c); + } + } + else { + X0.x = -d.x/(2*m_c2.x); + X0.y = 0; + X0.z = 0; + m_c = c - m_c2.x*pow(X0.x,2); + if (m_c != 0) { + m_c2 /= fabs(m_c); + m_c /= fabs(m_c); + } + } + + m_rc = Q*X0; + // clean up + double rc = m_rc.norm(); + if (fabs(m_rc.x) < m_eps*rc) m_rc.x = 0; + if (fabs(m_rc.y) < m_eps*rc) m_rc.y = 0; + if (fabs(m_rc.z) < m_eps*rc) m_rc.z = 0; + +} + +//------------------------------------------------------------------------------- +// complete fit algorithm +//bool QuadricFit::Fit(PointCloud3d* pc) +bool QuadricFit::Fit(std::vector& pc) +{ +// m_quad->SetPointCloud3d(pc); + m_quad->m_p = pc; + if (m_quad->GetQuadricCoeficients()) + { + GetOrientation(); + return true; + } + else + return false; +} + +//------------------------------------------------------------------------------- +bool QuadricFit::isSame(const double& a, const double&b) +{ + if (fabs(b-a) < m_eps*fabs(a+b)/2) return true; + else return false; +} + +//------------------------------------------------------------------------------- +QuadricFit::Q_TYPE QuadricFit::GetType() +{ + // determine quadric type + Q_TYPE type = Q_UNKNOWN; + double A = m_c2.x, B = m_c2.y, C = m_c2.z; + + if ((A > 0) && (B > 0)) { + if ((C > 0) && isSame(m_c,-1)) { + type = Q_ELLIPSOID; + if (isSame(A,B)) { + type = Q_SPHEROID; + if (isSame(B,C)) type = Q_SPHERE; + } + } + else if (C == 0) { + if (isSame(m_v.z,-1) && (m_c == 0)) { + type = Q_ELLIPTIC_PARABOLOID; + if (isSame(A,B)) + type = Q_CIRCULAR_PARABOLOID; + } + else if ((m_v.z == 0) && isSame(m_c,-1)) { + type = Q_ELLIPTIC_CYLINDER; + if (isSame(A,B)) + type = Q_CIRCULAR_CYLINDER; + } + } + else if (C < 0) { + if (isSame(m_c,-1)) { + type = Q_ELLIPTIC_HYPERBOLOID_1; + if (isSame(A,B)) { + type = Q_CIRCULAR_HYPERBOLOID_1; + } + } + else if (isSame(m_c,1)) { + type = Q_ELLIPTIC_HYPERBOLOID_2; + if (isSame(A,B)) { + type = Q_CIRCULAR_HYPERBOLOID_2; + } + } + else if (m_c == 0) { + type = Q_ELLIPTIC_CONE; + if (isSame(A,B)) { + type = Q_CIRCULAR_CONE; + } + } + } + } + else if ((A > 0) && (B < 0)) { + if ((C == 0) && (m_c == 0) && isSame(m_v.z,-1)) { + type = Q_HYPERBOLIC_PARABOLOID; + } + else if ((C == 0) && isSame(m_c,-1) && (m_v.z == 0)) { + type = Q_HYPERBOLIC_CYLINDER; + } + } + else if ((A > 0) && (B == 0)) { + type = Q_PARABOLIC_CYLINDER; + } + + return type; +} + +//------------------------------------------------------------------------------- +std::string QuadricFit::GetStringType(Q_TYPE qtype) +{ + std::string quadric; + switch (qtype) { + case QuadricFit::Q_ELLIPSOID: quadric = std::string("Ellipsoid"); break; + case QuadricFit::Q_ELLIPTIC_PARABOLOID: quadric = std::string("Elliptic Paraboloid"); break; + case QuadricFit::Q_HYPERBOLIC_PARABOLOID: quadric = std::string("Hyperbolic Paraboloid"); break; + case QuadricFit::Q_ELLIPTIC_HYPERBOLOID_1: quadric = std::string("Elliptic Hyperboloid of One Sheet"); break; + case QuadricFit::Q_ELLIPTIC_HYPERBOLOID_2: quadric = std::string("Elliptic Hyperboloid of Two Sheets"); break; + case QuadricFit::Q_ELLIPTIC_CONE: quadric = std::string("Elliptic Cone"); break; + case QuadricFit::Q_ELLIPTIC_CYLINDER: quadric = std::string("Elliptic Cylinder"); break; + case QuadricFit::Q_PARABOLIC_CYLINDER: quadric = std::string("Parabolic Cylinder"); break; + case QuadricFit::Q_SPHEROID: quadric = std::string("Spheroid"); break; + case QuadricFit::Q_SPHERE: quadric = std::string("Sphere"); break; + case QuadricFit::Q_CIRCULAR_PARABOLOID: quadric = std::string("Circular Paraboloid"); break; + case QuadricFit::Q_CIRCULAR_HYPERBOLOID_1: quadric = std::string("Circular Hyperboloid of One Sheet"); break; + case QuadricFit::Q_CIRCULAR_HYPERBOLOID_2: quadric = std::string("Circular Hyperboloid of Two Sheets"); break; + case QuadricFit::Q_CIRCULAR_CONE: quadric = std::string("Circular Cone"); break; + case QuadricFit::Q_CIRCULAR_CYLINDER: quadric = std::string("Circular Cylinder"); break; + case QuadricFit::Q_UNKNOWN: quadric = std::string("Unknown"); break; + default: break; + } + return quadric; +} diff --git a/FECore/QuadricFit.h b/FECore/QuadricFit.h new file mode 100644 index 000000000..c34a140a0 --- /dev/null +++ b/FECore/QuadricFit.h @@ -0,0 +1,73 @@ +/*This file is part of the FEBio Studio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio-Studio.txt for details. + + Copyright (c) 2020 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + +#pragma once +#include +#include +#include "Quadric.h" +#include "quatd.h" + +class QuadricFit +{ +public: + enum Q_TYPE { Q_ELLIPSOID, Q_ELLIPTIC_PARABOLOID, Q_HYPERBOLIC_PARABOLOID, + Q_ELLIPTIC_HYPERBOLOID_1, Q_ELLIPTIC_HYPERBOLOID_2, Q_ELLIPTIC_CONE, + Q_ELLIPTIC_CYLINDER, Q_HYPERBOLIC_CYLINDER, Q_PARABOLIC_CYLINDER, + Q_SPHEROID, Q_SPHERE, Q_CIRCULAR_PARABOLOID, Q_CIRCULAR_HYPERBOLOID_1, + Q_CIRCULAR_HYPERBOLOID_2, Q_CIRCULAR_CONE, Q_CIRCULAR_CYLINDER, Q_UNKNOWN + }; + +public: + QuadricFit(); + QuadricFit(const QuadricFit& qf); + virtual ~QuadricFit(); + + bool Fit(std::vector& pc); + Q_TYPE GetType(); + std::string GetStringType(Q_TYPE qtype); + +protected: + vec3d Transform(vec3d& rc, quatd& q, const vec3d& p) + { + vec3d r = p - rc; + q.RotateVector(r); + return r; + } + + void GetOrientation(); + bool isSame(const double& a, const double&b); + + +public: + vec3d m_rc; // center of quadric + vec3d m_ax[3];// quadric axes + vec3d m_c2; // coefficients of square terms + vec3d m_v; // coefficients of linear terms + double m_c; // constant + double m_eps; // tolerance + + Quadric* m_quad; // quadric object +}; diff --git a/FECore/fecore_enum.h b/FECore/fecore_enum.h index eb635f0cc..9996427e3 100644 --- a/FECore/fecore_enum.h +++ b/FECore/fecore_enum.h @@ -241,6 +241,7 @@ enum SUPER_CLASS_ID { FEFACELOGDATA_ID, // derived from FEFaceLogData FEELEMLOGDATA_ID, // derived from FELogElemata FEOBJLOGDATA_ID, // derived from FELogObjectData + FEMODELLOGDATA_ID, // derived from FEModelLogData FEBC_ID, // derived from FEBoundaryCondition (TODO: This does not work yet) FEGLOBALDATA_ID, // derived from FEGlobalData FERIGIDOBJECT_ID, // derived from FECoreBase (TODO: work in progress) diff --git a/FECore/mat3d.h b/FECore/mat3d.h index 24c43b60b..c07017168 100644 --- a/FECore/mat3d.h +++ b/FECore/mat3d.h @@ -179,6 +179,11 @@ class mat3ds mat3d operator - (const mat3d& t) const; mat3d operator * (const mat3d& t) const; + // arithmetic operators for mat3da objects + mat3d operator + (const mat3da& t) const; + mat3d operator - (const mat3da& t) const; + mat3d operator * (const mat3da& t) const; + // unary operators mat3ds operator - () const; @@ -298,6 +303,10 @@ class mat3da vec3d operator * (const vec3d& a); + // arithmetic operators for mat3ds objects + mat3d operator + (const mat3ds& t) const; + mat3d operator - (const mat3ds& t) const; + protected: double d[3]; // stores xy, yz, xz diff --git a/FECore/mat3d.hpp b/FECore/mat3d.hpp index 33843edf1..5c939fd6f 100644 --- a/FECore/mat3d.hpp +++ b/FECore/mat3d.hpp @@ -302,6 +302,32 @@ inline mat3d mat3ds::operator * (const mat3d& d) const d.d[0][2]*m[XZ] + d.d[1][2]*m[YZ] + d.d[2][2]*m[ZZ]); } +// operator + for mat3da objects +inline mat3d mat3ds::operator + (const mat3da& d) const +{ + return mat3d(m[XX] , m[XY]+d.xy(), m[XZ]+d.xz(), + m[XY]-d.xy(), m[YY] , m[YZ]+d.yz(), + m[XZ]-d.xz(), m[YZ]-d.yz(), m[ZZ] ); +} + +// operator - for mat3da objects +inline mat3d mat3ds::operator - (const mat3da& d) const +{ + return mat3d(m[XX] , m[XY]-d.xy(), m[XZ]-d.xz(), + m[XY]+d.xy(), m[YY] , m[YZ]-d.yz(), + m[XZ]+d.xz(), m[YZ]+d.yz(), m[ZZ] ); +} + +// operator * for mat3d objects +inline mat3d mat3ds::operator * (const mat3da& d) const +{ + return mat3d( + -d.xy()*m[XY]-d.xz()*m[XZ],d.xy()*m[XX]-d.yz()*m[XZ],d.xz()*m[XX]+d.yz()*m[XY], + -d.xy()*m[YY]-d.xz()*m[YZ],d.xy()*m[XY]-d.yz()*m[YZ],d.xz()*m[XY]+d.yz()*m[YY], + -d.xy()*m[YZ]-d.xz()*m[ZZ],d.xy()*m[XZ]-d.yz()*m[ZZ],d.xz()*m[XZ]+d.yz()*m[YZ] + ); +} + // unary operator - inline mat3ds mat3ds::operator - () const @@ -555,6 +581,24 @@ inline mat3d mat3da::operator * (const mat3d& m) ); } +inline mat3d mat3da::operator + (const mat3ds& a) const +{ + return mat3d( + a.xx(),a.xy()+xy(),a.xz()+xz(), + a.xy()-xy(),a.yy(),a.yz()+yz(), + a.xz()-xz(),a.yz()-yz(),a.zz() + ); +} + +inline mat3d mat3da::operator - (const mat3ds& a) const +{ + return mat3d( + -a.xx(),-a.xy()+xy(),-a.xz()+xz(), + -a.xy()-xy(),-a.yy(),-a.yz()+yz(), + -a.xz()-xz(),-a.yz()-yz(),-a.zz() + ); +} + inline vec3d mat3da::operator * (const vec3d& a) { return vec3d( diff --git a/FECore/matrix.cpp b/FECore/matrix.cpp index f2b7e33e5..fe0e90287 100644 --- a/FECore/matrix.cpp +++ b/FECore/matrix.cpp @@ -460,3 +460,102 @@ matrix matrix::operator - (const matrix& m) const return s; } + +#define ROTATE(a, i, j, k, l) g=a[i][j]; h=a[k][l];a[i][j]=g-s*(h+g*tau); a[k][l] = h + s*(g - h*tau); + +//----------------------------------------------------------------------------- +bool matrix::eigen_vectors(matrix& Eigen, vector& eigen_values) +{ + matrix& A = *this; + int N = m_nc; + int R = m_nr; + const int NMAX = 50; + double sm, tresh, g, h, t, c, tau, s, th; + const double eps = 0;//1.0e-15; + int k ; + + //initialize Eigen to identity + for(int i = 0; i< R ; i++) + { + for(int j = 0;j b; + b.reserve(R); + vector z; + z.reserve(R); + + // initialize b and eigen_values to the diagonal of A + for(int i = 0; i 3) && ((fabs(eigen_values[i])+g) == fabs(eigen_values[i])) && ((fabs(eigen_values[j])+g) == fabs(eigen_values[j]))) + { + A[i][j] = 0.0; + } + else if (fabs(A[i][j]) > tresh){ + h = eigen_values[j] - eigen_values[i]; + if ((fabs(h)+g) == fabs(h)) + t = A[i][j]/h; + else + { + th = 0.5*h/A[i][j]; + t = 1.0/(fabs(th) + sqrt(1+th*th)); + if (th < 0.0) t = -t; + } + c = 1.0/sqrt(1.0 + t*t); + s = t*c; + tau = s/(1.0+c); + h = t*A[i][j]; + z[i] -= h; + z[j] += h; + eigen_values[i] -= h; + eigen_values[j] += h; + A[i][j] = 0; + for (k= 0; k<=i-1; ++k) { ROTATE(A, k, i, k, j) } + for (k=i+1; k<=j-1; ++k) { ROTATE(A, i, k, k, j) } + for (k=j+1; k& eigen_values); + public: void set(int i, int j, const mat3d& a); diff --git a/FECore/vec3d.h b/FECore/vec3d.h index 3527862eb..1aec35fe6 100644 --- a/FECore/vec3d.h +++ b/FECore/vec3d.h @@ -54,6 +54,28 @@ class vec3d vec3d operator - () const { return vec3d(-x, -y, -z); } + double& operator() (int i) + { + switch(i) + { + case 0: {return x; break;} + case 1: {return y; break;} + case 2: {return z; break;} + default: {return x; break;} + } + } + + double operator() (int i) const + { + switch(i) + { + case 0: {return x; break;} + case 1: {return y; break;} + case 2: {return z; break;} + default: {return x; break;} + } + } + // dot product double operator * (const vec3d& r) const { return (x*r.x + y*r.y + z*r.z); } diff --git a/FECore/version.h b/FECore/version.h index 704e2c251..48d27b01d 100644 --- a/FECore/version.h +++ b/FECore/version.h @@ -34,7 +34,7 @@ SOFTWARE.*/ // of FEBio. In that case, plugins need to be recompiled to be usable with the // newer version of FEBio. #define FE_SDK_MAJOR_VERSION 3 -#define FE_SDK_SUB_VERSION 6 +#define FE_SDK_SUB_VERSION 7 #define FE_SDK_SUBSUB_VERSION 0 //----------------------------------------------------------------------------- diff --git a/FindDependencies.cmake b/FindDependencies.cmake index 2d644005f..55556cc4a 100644 --- a/FindDependencies.cmake +++ b/FindDependencies.cmake @@ -47,7 +47,7 @@ if(MKLROOT) find_library(MKL_OMP_LIB NAMES iomp5 iomp5md libiomp5md.lib - PATHS ${MKLROOT}/../lib ${MKLROOT}/../compiler/lib + PATHS ${MKLROOT}/lib ${MKLROOT}/../lib ${MKLROOT}/../compiler/lib PATH_SUFFIXES "intel64" "intel32" NO_DEFAULT_PATH DOC "MKL OMP Library") diff --git a/NumCore/AccelerateSparseSolver.cpp b/NumCore/AccelerateSparseSolver.cpp new file mode 100644 index 000000000..abadb0b63 --- /dev/null +++ b/NumCore/AccelerateSparseSolver.cpp @@ -0,0 +1,296 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2021 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#include "stdafx.h" +#include +#include +#include "AccelerateSparseSolver.h" +#include "MatrixTools.h" +#include + +#ifdef __APPLE__ + +////////////////////////////////////////////////////////////// +// AccelerateSparseSolver +////////////////////////////////////////////////////////////// + +BEGIN_FECORE_CLASS(AccelerateSparseSolver, LinearSolver) + ADD_PARAMETER(m_print_cn, "print_condition_number"); + ADD_PARAMETER(m_iparm3 , "precondition"); +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +AccelerateSparseSolver::AccelerateSparseSolver(FEModel* fem) : LinearSolver(fem), m_pA(0) +{ + m_print_cn = false; + m_mtype = -2; + m_iparm3 = false; + m_isFactored = false; + +} + +//----------------------------------------------------------------------------- +AccelerateSparseSolver::~AccelerateSparseSolver() +{ + Destroy(); +} + +//----------------------------------------------------------------------------- +void AccelerateSparseSolver::PrintConditionNumber(bool b) +{ + m_print_cn = b; +} + +//----------------------------------------------------------------------------- +void AccelerateSparseSolver::UseIterativeFactorization(bool b) +{ + m_iparm3 = b; +} + +//----------------------------------------------------------------------------- +SparseMatrix* AccelerateSparseSolver::CreateSparseMatrix(Matrix_Type ntype) +{ + // allocate the correct matrix format depending on matrix symmetry type + switch (ntype) + { + case REAL_SYMMETRIC : m_mtype = -2; m_pA = new CompactSymmMatrix(0); break; + case REAL_UNSYMMETRIC : m_mtype = 11; m_pA = new CCSSparseMatrix(0); break; + case REAL_SYMM_STRUCTURE: m_mtype = 1; m_pA = new CCSSparseMatrix(0); break; + default: + assert(false); + m_pA = nullptr; + } + + return m_pA; +} + +//----------------------------------------------------------------------------- +bool AccelerateSparseSolver::SetSparseMatrix(SparseMatrix* pA) +{ + if (m_pA && m_isFactored) Destroy(); + m_pA = dynamic_cast(pA); + m_mtype = -2; + if (dynamic_cast(pA)) m_mtype = 11; + return (m_pA != nullptr); +} + +//----------------------------------------------------------------------------- +bool AccelerateSparseSolver::PreProcess() +{ + assert(m_isFactored == false); + + m_n = m_pA->Rows(); + m_nnz = m_pA->NonZeroes(); + m_nrhs = 1; + + pointers.resize(m_nnz); + for (int i=0; iPointers()[i]; + colS = &pointers[0]; + + if (__builtin_available(macOS 10.13, *)) { + SMS.columnCount = m_pA->Columns(); + SMS.rowCount = m_pA->Rows(); + SMS.rowIndices = m_pA->Indices(); + SMS.columnStarts = colS; + SMS.blockSize = 1; + if (m_mtype == 11) { + // Use QR factorization for non-symmetric matrix + SMS.attributes.kind = SparseOrdinary; + ASS = SparseFactor(SparseFactorizationQR, SMS); + } + else { + // Use LDLT factorization for symmetric matrix + // (Cholesky factorization does not work) + SMS.attributes.kind = SparseSymmetric; + ASS = SparseFactor(SparseFactorizationLDLTTPP, SMS); + } + } + else { + // Fallback on earlier versions + fprintf(stderr, "\nERROR during preprocessing: "); + fprintf(stderr, "\naccelerate solver not available for macOS earlier than 10.13!"); + return false; + } + + return LinearSolver::PreProcess(); +} + +//----------------------------------------------------------------------------- +bool AccelerateSparseSolver::Factor() +{ + // make sure we have work to do + if (m_pA->Rows() == 0) return true; + + // ------------------------------------------------------------------------------ + // This step does the factorization + // ------------------------------------------------------------------------------ + + if (__builtin_available(macOS 10.13, *)) { + // create the sparse matrix + A.structure = SMS; + A.data = m_pA->Values(); + + ASF = SparseFactor(ASS,A); + if (ASF.status != SparseStatusOK) { + fprintf(stderr, "\nERROR during factorization:"); + switch (ASF.status) { + case SparseFactorizationFailed: + fprintf(stderr, "\nFactorization failed!"); + break; + case SparseMatrixIsSingular: + fprintf(stderr, "\nSparse matrix is singular!"); + break; + case SparseInternalError: + fprintf(stderr, "\nSolver called internal error!"); + break; + case SparseParameterError: + fprintf(stderr, "\nSolver called parameter error!"); + break; + default: + fprintf(stderr, "\nUnknown error!"); + } + return false; + } + } + else { + // Fallback on earlier versions + fprintf(stderr, "\nERROR during factorization: "); + fprintf(stderr, "\nAccelerate solver not available for macOS earlier than 10.13!"); + return false; + } + + // calculate and print the condition number + if (m_print_cn) + { + double c = condition_number(); + feLog("\tcondition number (est.) ................... : %lg\n\n", c); + } + + m_isFactored = true; + + return true; +} + +//----------------------------------------------------------------------------- +bool AccelerateSparseSolver::BackSolve(double* x, double* b) +{ + // make sure we have work to do + if (m_pA->Rows() == 0) return true; + if (m_isFactored == false) return true; + + DenseVector_Double X, B; + X.count = B.count = m_n; + X.data = x; B.data = b; + + // solve the system + if (__builtin_available(macOS 10.13, *)) { + SparseSolve(ASF,B,X); + } else { + // Fallback on earlier versions + fprintf(stderr, "\nERROR during back solve: "); + fprintf(stderr, "\nAccelerate solver not available for macOS earlier than 10.13!"); + return false; + } + + // update stats + UpdateStats(1); + + return true; +} + +//----------------------------------------------------------------------------- +// This algorithm (naively) estimates the condition number. It is based on the observation that +// for a linear system of equations A.x = b, the following holds +// || A^-1 || >= ||x||.||b|| +// Thus the condition number can be estimated by +// c = ||A||.||A^-1|| >= ||A|| . ||x|| / ||b|| +// This algorithm tries for some random b vectors with norm ||b||=1 to maxize the ||x||. +// The returned value will be an underestimate of the condition number +double AccelerateSparseSolver::condition_number() +{ + // This assumes that the factorization is already done! + int N = m_pA->Rows(); + + // get the norm of the matrix + double normA = m_pA->infNorm(); + + // estimate the norm of the inverse of A + double normAi = 0.0; + + // choose max iterations + int iters = (N < 50 ? N : 50); + + vector b(N, 0), x(N, 0); + for (int i = 0; i < iters; ++i) + { + // create a random vector + NumCore::randomVector(b, -1.0, 1.0); + for (int j = 0; j < N; ++j) b[j] = (b[j] >= 0.0 ? 1.0 : -1.0); + + // calculate solution + BackSolve(&x[0], &b[0]); + + double normx = NumCore::infNorm(x); + if (normx > normAi) normAi = normx; + + int pct = (100 * i) / (iters - 1); + fprintf(stderr, "calculating condition number: %d%%\r", pct); + } + + double c = normA*normAi; + return c; +} + +//----------------------------------------------------------------------------- +void AccelerateSparseSolver::Destroy() +{ + if (m_pA && m_pA->Pointers() && m_isFactored) + { + SparseCleanup(ASS); + SparseCleanup(ASF); + } + m_isFactored = false; +} +#else +BEGIN_FECORE_CLASS(AccelerateSparseSolver, LinearSolver) +ADD_PARAMETER(m_print_cn, "print_condition_number"); +ADD_PARAMETER(m_iparm3, "precondition"); +END_FECORE_CLASS(); + +AccelerateSparseSolver::AccelerateSparseSolver(FEModel* fem) : LinearSolver(fem) {} +AccelerateSparseSolver::~AccelerateSparseSolver() {} +bool AccelerateSparseSolver::PreProcess() { return false; } +bool AccelerateSparseSolver::Factor() { return false; } +bool AccelerateSparseSolver::BackSolve(double* x, double* y) { return false; } +void AccelerateSparseSolver::Destroy() {} +SparseMatrix* AccelerateSparseSolver::CreateSparseMatrix(Matrix_Type ntype) { return nullptr; } +bool AccelerateSparseSolver::SetSparseMatrix(SparseMatrix* pA) { return false; } +void AccelerateSparseSolver::PrintConditionNumber(bool b) {} +double AccelerateSparseSolver::condition_number() { return 0; } +void AccelerateSparseSolver::UseIterativeFactorization(bool b) {} +#endif diff --git a/NumCore/AccelerateSparseSolver.h b/NumCore/AccelerateSparseSolver.h new file mode 100644 index 000000000..b575a3cdb --- /dev/null +++ b/NumCore/AccelerateSparseSolver.h @@ -0,0 +1,83 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license + listed below. + + See Copyright-FEBio.txt for details. + + Copyright (c) 2022 University of Utah, The Trustees of Columbia University in + the City of New York, and others. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE.*/ + + + +#pragma once +#include +#include "CompactUnSymmMatrix.h" +#include "CompactSymmMatrix.h" +#ifdef __APPLE__ +#include +#endif + +// This sparse linear solver uses the Accelerate framework on MAC. +class AccelerateSparseSolver : public LinearSolver +{ +public: + AccelerateSparseSolver(FEModel* fem); + ~AccelerateSparseSolver(); + bool PreProcess() override; + bool Factor() override; + bool BackSolve(double* x, double* y) override; + void Destroy() override; + + SparseMatrix* CreateSparseMatrix(Matrix_Type ntype) override; + bool SetSparseMatrix(SparseMatrix* pA) override; + + void PrintConditionNumber(bool b); + + double condition_number(); + + void UseIterativeFactorization(bool b); + +protected: + + CompactMatrix* m_pA; + int m_mtype; // matrix type + +#ifdef __APPLE__ + SparseMatrixStructure SMS; + SparseMatrix_Double A; + SparseOpaqueSymbolicFactorization ASS; + SparseOpaqueFactorization_Double ASF; + long* colS; + std::vector pointers; +#endif + + // solver control parameters + + bool m_iparm3; // use direct-iterative method + + // Matrix data + int m_n, m_nnz, m_nrhs; + + bool m_print_cn; // estimate and print the condition number + + bool m_isFactored; + + DECLARE_FECORE_CLASS(); +}; diff --git a/NumCore/CompactUnSymmMatrix.cpp b/NumCore/CompactUnSymmMatrix.cpp index 284f4f049..0a8a27af4 100644 --- a/NumCore/CompactUnSymmMatrix.cpp +++ b/NumCore/CompactUnSymmMatrix.cpp @@ -567,7 +567,7 @@ void CCSSparseMatrix::Create(SparseMatrixProfile& mp) int nc = mp.Columns(); int* pointers = new int[nc + 1]; - for (int i = 0; i <= nr; ++i) pointers[i] = 0; + for (int i = 0; i <= nc; ++i) pointers[i] = 0; int nsize = 0; for (int i = 0; i #include #include "FEASTEigenSolver.h" +#include "TestSolver.h" +#include "AccelerateSparseSolver.h" //============================================================================= // Call this to initialize the NumCore module @@ -64,6 +66,8 @@ void NumCore::InitModule() REGISTER_FECORE_CLASS(BIPNSolver , "bipn"); REGISTER_FECORE_CLASS(BiCGStabSolver , "bicgstab"); REGISTER_FECORE_CLASS(StrategySolver , "strategy"); + REGISTER_FECORE_CLASS(TestSolver , "test"); + REGISTER_FECORE_CLASS(AccelerateSparseSolver, "accelerate"); // register preconditioners REGISTER_FECORE_CLASS(ILU0_Preconditioner, "ilu0"); diff --git a/NumCore/TestSolver.cpp b/NumCore/TestSolver.cpp new file mode 100644 index 000000000..906d29315 --- /dev/null +++ b/NumCore/TestSolver.cpp @@ -0,0 +1,108 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#include "stdafx.h" +#include +#include +#include "TestSolver.h" +#include + + +BEGIN_FECORE_CLASS(TestSolver, LinearSolver) +END_FECORE_CLASS(); + +//----------------------------------------------------------------------------- +TestSolver::TestSolver(FEModel* fem) : LinearSolver(fem), m_pA(0) +{ + m_mtype = -2; +} + +//----------------------------------------------------------------------------- +TestSolver::~TestSolver() +{ + Destroy(); +} + +//----------------------------------------------------------------------------- +SparseMatrix* TestSolver::CreateSparseMatrix(Matrix_Type ntype) +{ + // allocate the correct matrix format depending on matrix symmetry type + switch (ntype) + { + case REAL_SYMMETRIC: m_mtype = -2; m_pA = new CompactSymmMatrix(1); break; + case REAL_UNSYMMETRIC: m_mtype = 11; m_pA = new CRSSparseMatrix(1); break; + case REAL_SYMM_STRUCTURE: m_mtype = 1; m_pA = new CRSSparseMatrix(1); break; + default: + assert(false); + m_pA = nullptr; + } + + return m_pA; +} + +//----------------------------------------------------------------------------- +bool TestSolver::SetSparseMatrix(SparseMatrix* pA) +{ + if (m_pA) Destroy(); + m_pA = dynamic_cast(pA); + m_mtype = -2; + if (dynamic_cast(pA)) m_mtype = 11; + return (m_pA != nullptr); +} + +//----------------------------------------------------------------------------- +bool TestSolver::PreProcess() +{ + m_n = m_pA->Rows(); + m_nnz = m_pA->NonZeroes(); + m_nrhs = 1; + return LinearSolver::PreProcess(); +} + +//----------------------------------------------------------------------------- +bool TestSolver::Factor() +{ + return true; +} + +//----------------------------------------------------------------------------- +bool TestSolver::BackSolve(double* x, double* b) +{ + // make sure we have work to do + if (m_pA->Rows() == 0) return true; + + for (int i = 0; i < m_n; ++i) x[i] = 0.0; + + // update stats + UpdateStats(1); + + return true; +} + +//----------------------------------------------------------------------------- +void TestSolver::Destroy() +{ + +} diff --git a/NumCore/TestSolver.h b/NumCore/TestSolver.h new file mode 100644 index 000000000..6e0eab3d1 --- /dev/null +++ b/NumCore/TestSolver.h @@ -0,0 +1,54 @@ +/*This file is part of the FEBio source code and is licensed under the MIT license +listed below. + +See Copyright-FEBio.txt for details. + +Copyright (c) 2021 University of Utah, The Trustees of Columbia University in +the City of New York, and others. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +#pragma once +#include +#include "CompactUnSymmMatrix.h" +#include "CompactSymmMatrix.h" + + +// Test solver. Doesn't actually solve anything. Just returns 0 as solution. +class TestSolver : public LinearSolver +{ +public: + TestSolver(FEModel* fem); + ~TestSolver(); + bool PreProcess() override; + bool Factor() override; + bool BackSolve(double* x, double* y) override; + void Destroy() override; + + SparseMatrix* CreateSparseMatrix(Matrix_Type ntype) override; + bool SetSparseMatrix(SparseMatrix* pA) override; + +protected: + CompactMatrix* m_pA; + int m_mtype; // matrix type + + // Matrix data + int m_n, m_nnz, m_nrhs; + + DECLARE_FECORE_CLASS(); +};