Git Product home page Git Product logo

ttb's Introduction

Tensor Toolbox for Modern Fortran.

GitHub release (latest by date) Fortran License Documentation DOI

Commercial FEM software packages offer interfaces (user subroutines written in Fortran) for custom defined user materials like UMAT in Abaqus or HYPELA2 in MSC.Marc. In comparison to other scientific programming languages like MATLAB or Python Fortran is not as comfortable to use when dealing with high level programming features of tensor manipulation. On the other hand it's super fast - so why not combine the handy features from MATLAB or Python's NumPy/Scipy with the speed of Fortran? That's the reason why I started working on a simple but effective module called Tensor Toolbox for Modern Fortran. I adopted the idea to my needs from Naumann, C. (2016).

The full documentation is available at https://adtzlr.github.io/ttb. This project is licensed under the terms of the MIT license.

Overview

deformation

This tensor toolbox provides the following basic operations for tensor calculus (all written in double precision real(kind=8)):

  • Dot Product C(i,j) = A(i,k) B(k,j) written as C = A*B
  • Double Dot Product C = A(i,j) B(i,j) written as C = A**B
  • Dyadic Product C(i,j,k,l) = A(i,j) B(k,l) written as C = A.dya.B
  • Crossed Dyadic Product C(i,j,k,l) = (A(i,k) B(j,l) + A(i,l) B(j,k) + B(i,k) A(j,l) + B(i,l) A(j,k))/4 written as C = A.cdya.B
  • Addition C(i,j) = A(i,j) + B(i,j) written as C = A+B
  • Subtraction C(i,j) = A(i,j) - B(i,j) written as C = A-B
  • Multiplication and Division by a Scalar
  • Deviatoric Part of Tensor dev(C) = C - tr(C)/3 * Eye written as dev(C)
  • Transpose and Permutation of indices written as B = permute(A,1,3,2,4)
  • Rank 2 Identity tensor of input type Eye = identity2(Eye) with C = Eye*C
  • Rank 4 Identity tensor (symmetric variant) of input type I4 = identity4(Eye) or I4 = Eye.cdya.Eye with C = I4**C or inv(C) = identity4(inv(C))**C
  • Square Root of a positive definite rank 2 tensor U = sqrt(C)
  • Assigment of a real-valued Scalar to all components of a Tensor A = 0.0 or A = 0.d0
  • Assigment of a real-valued Array to a Tensor with matching dimensions A = B where B is an Array and A a Tensor
  • Assigment of a Tensor in Voigt notation to a Tensor in tensorial notation and vice versa

The idea is to create derived data types for rank 1, rank 2 and rank 4 tensors (and it's symmetric variants). In a next step the operators are defined in a way that Fortran calls different functions based on the input types of the operator: performing a dot product between a vector and a rank 2 tensor or a rank 2 and a rank 2 tensor is a different function. Best of it: you don't have to take care of that.

Basic Usage

The most basic example on how to use this module is to download the module, put the 'ttb'-Folder in your working directory and add two lines of code:

       include 'ttb/ttb_library.f'

       program script101_ttb
       use Tensor
       implicit none

       ! user code

       end program script101_ttb

The include 'ttb/ttb_library.f' statement replaces the line with the content of the ttb-module. The first line in a program or subroutine is now a use Tensor statement. That's it - now you're ready to go.

Tensor or Voigt Notation

It depends on your preferences: either you store all tensors in full tensor dimension(3,3) or in voigt dimension(6) notation. The equations remain (nearly) the same. Dot Product, Double Dot Product - every function is implemented in both full tensor and voigt notation. Look for the voigt-comments in an example of a user subroutine for MSC.Marc.

Access Tensor components by Array

Tensor components may be accessed by a conventional array with the name of the tensor variable T followed by a percent operator % and a type-specific keyword as follows:

  • Tensor of rank 1 components as array: T%a. i-th component of T: T%a(i)

  • Tensor of rank 2 components as array: T%ab. i,j component of T: T%ab(i,j)

  • Tensor of rank 4 components as array: T%abcd. i,j,k,l component of T: T%abcd(i,j,k,l)

  • Symmetric Tensor of rank 2 (Voigt) components as array: T%a6. i-th component of T: T%a6(i)

  • Symmetric Tensor of rank 4 (Voigt) components as array: T%a6b6. i,j component of T: T%a6b6(i,j) (at least minor symmetric)

Warning: Output as array

It is not possible to access tensor components of a tensor valued function in a direct way s = symstore(S1)%a6 - unfortunately this is a limitation of Fortran. To avoid the creation of an extra variable it is possible to use the asarray(T,i_max[,j_max,k_max,l_max]) function to access tensor components. i_max,j_max,k_max,l_max is not the single component, instead a slice T%abcd(1:i_max,1:j_max,1:k_max,1:l_max) is returned. This can be useful when dealing with mixed formulation or variation principles where the last entry/entries of stress and strain voigt vectors are used for the pressure boundary. To export a full stress tensor S1 to voigt notation use:

       s(1:ndim)        = asarray( voigt(S1), ndim )
       d(1:ndim,1:ndim) = asarray( voigt(C4), ndim, ndim )

Abaqus Users: Output as abqarray

To export a stress tensor to Abaqus Voigt notation use asabqarray which reorders the storage indices to 11,22,33,12,13,23. This function is available for Tensor2s and Tensor4s data types.

       s(1:ndim) = asabqarray( symstore(S1), ndim )
       ddsdde(1:ndim,1:ndim) = asabqarray( symstore(C4), ndim, ndim )

A note on the Permutation of Indices

The permutation function reorders indices in the given order for a fourth order tensor of data type Tensor4. Example: (i,j,k,l) --> (i,k,j,l) with permute(C4,1,3,2,4).

Neo-Hookean Material

With the help of the Tensor module the Second Piola-Kirchhoff stress tensor S of a nearly-incompressible Neo-Hookean material model is basically a one-liner:

Second Piola Kirchhoff Stress Tensor

       S = mu*det(C)**(-1./3.)*dev(C)*inv(C)+p*det(C)**(1./2.)*inv(C)

While this is of course not the fastest way of calculating the stress tensor it is extremely short and readable. Also the second order tensor variables S, C and scalar quantities mu, p have to be created at the beginning of the program. A minimal working example for a very simple umat user subroutine can be found in script_umat.f. The program is just an example where a subroutine umat is called and an output information is printed. It is shown that the tensor toolbox is only used inside the material user subroutine umat.

Material Elasticity Tensor

The isochoric part of the material elasticity tensor C4_iso of a nearly-incompressible Neo-Hookean material model is defined and coded as:

       C4_iso = det(F)**(-2./3.) * 2./3.* (
     *       tr(C) * identity4(inv(C))
     *     - (Eye.dya.inv(C)) - (inv(C).dya.Eye)
     *     + tr(C)/3. * (inv(C).dya.inv(C)) )

Example of Marc HYPELA2

Here you can find an example of a nearly-incompressible version of a Neo-Hookean material for Marc. Updated Lagrange is implemented by a push forward operator of both the stress and the fourth-order elasticity tensor. Herrmann Elements are automatically detected. As HYPELA2 is called twice per iteration the stiffness calculation is only active during stage lovl == 4. One of the best things is the super-simple switch from tensor to voigt notation: Change data types of all symmetric tensors and save the right Cauchy-Green deformation tensor in voigt notation. See commented lines for details.

Download HYPELA2: Neo-Hooke, Marc, Total Lagrange, Tensor Toolbox

Credits

Naumann, C.: Chemisch-mechanisch gekoppelte Modellierung und Simulation oxidativer Alterungsvorgänge in Gummibauteilen (German). PhD thesis. Fakultät für Maschinenbau der Technischen Universität Chemnitz, 2016.

Changelog

All notable changes to this project will be documented in this file. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

ttb's People

Contributors

adtzlr avatar dependabot[bot] avatar jamal-dev avatar jfriedlein avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ttb's Issues

Add sqrt(T)

Perform a polar decomposition of a positive definite 3x3 matrix to obtain the stretch tensor which satisfies C = U^2

Wrong orientation of the Rotation Matrix

depending on the axis of rotation.

See https://en.wikipedia.org/wiki/Rotation_matrix and

ttb/ttb/librotation.f

Lines 9 to 23 in f41cfdc

R = reshape( (/cos(phi), sin(phi),
* -sin(phi), cos(phi)/), (/2,2/) )
rotation_2 = identity2(rotation_2)
if (i == 1) then
rotation_2%ab(2:3,2:3) = R
else if (i == 3) then
rotation_2%ab(1:2,1:2) = R
else !i == 2
rotation_2%ab(1,1) = R(1,1)
rotation_2%ab(3,3) = R(2,2)
rotation_2%ab(1,3) = R(1,2)
rotation_2%ab(3,1) = R(2,1)
end if

Cmake/Makefile for ttb

Hi @adtzlr,
Thanks for this, it is going to be very useful!

In order to make your library easier to interface with existing codes, would you consider to do a CMakeLists.txt or a Makefile?

Enhance `libpower.f`

Add an assertion to both functions in libpower.f that throws an error if the exponent is neither 0, -1, nor a positive integer. This should catch "pow_2(tensor,-2)". If somebody tries to be smart and calls pow_2 with exponent 1/2 to get the square root, we still might get some problems. Even though pow_2(tensor,0.5) is caught by the compiler, pow_2(stress,1/2) is regarded as zero exponent. It is already explained what Power does in the documentation https://adtzlr.github.io/ttb/functions/power.html, but maybe we can add some further notes (iis integer) and protection (i>=-1).

Originally posted by @jfriedlein in #35 (comment) (slightly modified by @adtzlr)

Assign a scalar multiplies the scalar with the array items

in libassignscalar.f,

       subroutine assignscalar_4(T,w)
        implicit none
        
        type(Tensor4), intent(inout) :: T
        real(kind=8), intent(in) :: w
        
        T%abcd = T%abcd*w
        
       end subroutine assignscalar_4

the assignment must be replaced by

        T%abcd = w

for all assignments.

Tensor to Voigt Contraction

What is the best way to perform Tensor (3,3,3,3) to Voigt (6,6) contraction?

A symmetric fourth order identity tensor:
Eye4(i,j,k,l) = 1/2 * (Eye(i,k)*Eye(j,l)+Eye(i,l)*Eye(j,k))

is written as Eye4 = identity4(Eye) or Eye = Eye.cdya.Eye - but both methods result in different tensors!
A "true" fourth order identity tensor should be a zero matrix with diagonal elements equal to 1.0:
Eye4 = 0.0 and Eye4(i,i) = 1.0
but only the hardcoded identity4 matrix is true. I think I have to include a sum over the first dual shear indices (4) = (1,2)+(2,1), (5) = (2,3) + (3,1), ...

Questions about unfixed bugs

Hello, I am very interested in your fortran tensor calculation! Are there any known unfixed bugs in your code? Thank you for your generous answer!

umat_nh_ttb_simple.f does not work in Abaqus

First error it gives at the line 'implicit none'. If I comment this line the code does not pop any error in Abaqus, but it gives NaN stress which should not be the case.

It also gives this error in Log file.
"Begin Linking Abaqus/Standard User Subroutines
Creating library standardU.lib and object standardU.exp
libirc.lib(fast_mem_ops.c.obj) : warning LNK4210: .CRT section exists; there may be unhandled static initializers or terminators
End Linking Abaqus/Standard User Subroutines"

What could be the problem?

Einstein summation

Thank you for the valuable tensor library. Is Einstein summation included in it?

Implement Polar decomposition

Discussed in #53

Originally posted by Cyan2077 December 22, 2023
This toolbox is really nice. I have small suggestion that you can add the ' Polar decomposition' function into this toolbox. Because when we edit UMAT in abaqus, if we use keyword 'orientation', the deformation tensor F will be passed in UMAT in local coordinate. We always need 'Polar decomposition' to get the rotation part of the F, so that we can rotate the F back to the global coordinate.

@Cyan2077 to be sure: you mean you have a deformation gradient $\boldsymbol{F}$ at hand and you would like to perform $\boldsymbol{F} = \boldsymbol{R} \boldsymbol{U}$, where $\boldsymbol{R}$ is the rotation matrix and $\boldsymbol{U}$ is the right stretch tensor? Are you interested in the left-polar decomposition $\boldsymbol{F} = \boldsymbol{V} \boldsymbol{R}$ too?

Priority of overloaded operators

According to the priority of operators in Fortran it is necessary to use brackets for Tensor operators. For example the power operator ** which is overridden by the double dot product .ddot.has the highest priority. This is wrong, especially for a double contraction where one tensor is a result of a crossed dyadic product: A**B.cdya.C - the crossdyadic product has to be evaluated first. So the correct way of defining the equation is: A**(B.cdya.C)

Improve this behaviour...

Request toolbox compatibility LS-Dyna

@adtzlr
I currently implement user material models in LS-Dyna with Fortran. Luckily, I found your tensor toolbox to be able to implement our tensor-based models.
Firstly, thank you so much for giving us such a well-written toolbox with, most importantly, a great documentation.
I found some minor issues when trying to use your toolbox in the Fortran version of LS-Dyna, as described below. Nevertheless, I use it now successfully. I also added some additional functions (volumetric part, deviatoric fourth order tensor, ...).
I was wondering whether I could contribute to your repository, so we get a toolbox for Abaqus, Marc and LS-Dyna.

ttb in LS-Dyna:
LS-Dyna probably uses an older Fortran version than Abaqus and Marc. When I include the toolbox, the following error results

.\ttb/libdiv.f(57): error #5286: Ambiguous generic interface OPERATOR(/): previously declared specific procedure DIV_10 is not distinguishable from this declaration. [DIV_10_R4] function div_10_r4(T, w)
... (for all functions ending with r4)

By simply deleting all the module procedure *r4 in ttb_library.f all errors disappear and we can use the toolbox (of course without the r4 variants). Is this because this fortran version cannot yet distinguish between data type-"templated" functions?

proposols:
Maybe we use a new ttb_library.f with the above modification or can incorporate this into a single file. The additional functions (vol, I_dev, ...) could be added to existing and new files.

If you can make time and give me an answer, I would appreciate it.

ttb compatibility with default r8

Finally it became clear what the problem in Issue #10 was, where in LS-Dyna the toolbox gave compiler errors .\ttb/libdiv.f(57): error #5286: Ambiguous generic interface OPERATOR(/): previously declared specific procedure DIV_10 is not distinguishable from this declaration. [DIV_10_R4] function div_10_r4(T, w) ... for all functions ending with r4.

LS-Dyna settings:
In the LS-Dyna makefile, the settings for Windows are:
"SMPD = -DOPENMP -Qopenmp -DAUTODOUBLE -4R8 -4I8"
and similarly in the Linux Makefile
"FF= ... -r8 ..."
"R8"/"r8" imply that by default double precision is used. This means that for instance whenever we write "real, ..." it is interpreted as "real(kind=8), ...". In Abaqus the default seems to be single precision, so "real, ..." is read as "real(kind=4), ...". I only noticed these compilation flags, when moving to Linux, so sorry for not mentioning this in the initial Issue #10.

Consequences for ttb:
In the toolbox all functions ending with "r4" use "real, ...", whereas in the remaining functions "real(kind=8), ..." is specified. If the default precision is r4, then there is a difference between "real, ...", which is read as "real(kind=4)" in the r4-functions, and "real(kind=8), ..." in the other functions. However, when the default precision is r8, then the compiler cannot distinguish between a function with "real, ..." (read as "real(kind=8), ...") and the actual "real(kind=8), ..." functions, thus throwing the above error.

Easy fix:
The above errors can be resolved by simply always specifying what precision shall be used and never relying on the default value. Hence, I added "(kind=4)" to all unspecified "real, ..." (as done in the appended four files based on current release v1.0.2, replaced all "real," by "real(kind=4),"), which eliminated the error. If this also works under Abaqus etc., we could directly return to the old framework (no precompilation flags, classical "include", lower case "ttb.f", ...).

libassignarray.f.txt
libassignscalar.f.txt
libdiv.f.txt
libdot.f.txt

Initialisation of tensor components to zero

While trying the new branch, I again noticed a change I did a while ago to my local implementation.

When defining the tensor types, I initialised all tensor components to zero, so that an uninitialised tensor is zero and its components are not undefined (numerically chaotic values). I was used to this from deal.ii and it might also protect other naive and innocent people like me. To initialise the components to zero, simply add "= 0." as shown below in the file ttb_library.f:

    type Tensor1
    ! tensor of rank 1
    real(kind=8), dimension(3) :: a = 0.
   end type Tensor1
   
   type Tensor2
    ! tensor of rank 2
    real(kind=8), dimension(3,3) :: ab = 0.
   end type Tensor2
   
   type Tensor2S
    ! symmetric tensor of rank 2 stored as vector
    real(kind=8), dimension(6) :: a6 = 0.
   end type Tensor2S
   
   type Tensor4
    ! tensor of rank 4
    real(kind=8), dimension(3,3,3,3) :: abcd = 0.
   end type Tensor4
   
   type Tensor4S
    ! symmetric tensor of rank 4 stored as 6x6 matrix
    real(kind=8), dimension(6, 6) :: a6b6 = 0.
   end type Tensor4S

This might be something to add, in case there is no reason against it?

cannot compile script_umat.f

Hi,
I am a new user of fortran trying to use the toolbox to help writing a umat in abaqus. I was trying to start running the example script_umat.f but it couldn't compile in gfortran 6.3.0. I got many errors saying "Derived type 'Tensor1' is being used before it is defined." I wonder if you can give some suggestions on how to fix these errors.
Thank you!

Crossed-dyadic product is wrong

as already pointed out in #37 ,

the result of the crossed-dyadic product of two symmetric tensors $\boldsymbol{A}$ and $\boldsymbol{B}$

$$C_{ijkl} = \frac{1}{2} \left(A_{ik} \cdot B_{jl} +A_{il} \cdot B_{jk} \right) $$

is not symmetric and hence, can't be stored as a 6x6 tensor.

The implementation is wrong. The current implementation is only valid if $\boldsymbol{A} = \boldsymbol{B}$!

Cannot read uppercase extensions .F in Ubuntu

Hi,

I know that the library has not been tested in ubuntu but I would like to ask if anyone knows how to read .F extensions in Abaqus in Ubuntu.
The library is not working because the pre-processor is not called.

abaqus14 job=rectangle_fibers user=hgo_crimpingCopy.F
Abaqus Error: The following file(s) could not be located: hgo_crimpingCopy.F.f, hgo_crimpingCopy.F.for, hgo_crimpingCopy.F.c, hgo_crimpingCopy.F.cpp, hgo_crimpingCopy.F.C, hgo_crimpingCopy.F.c++, hgo_crimpingCopy.F.o
Abaqus/Analysis exited with error(s).

If I rename the file with a .f, there is a pre-processor violation and *Use tensor does not work.

Thanks in advance,

Iulen,

Voigt notation component ordering

Voigt Notation is in ordering (11,22,33,12,23,31). Abaqus uses different ordering. Add option to allow both orderings in the future.

access component in Tensor is incorrect in Abaqus

Hi @adtzlr ,
When I use the toolbox to write Abaqus subroutine, T%ab(i,j) gives me T(j,i) instead of T(i,j). This doesn't not happen when I test the subroutine outside of the Abaqus framework, (e.g. in Intel Fortran). And I couldn't debug what is the cause of this issue. Have you experienced similar issue or could you give some suggests how I could fix this?
Thank you,
Yiling

Experimental: Voigt Notation

Voigt notation is possible but marked as 'experimental' because some functions could be wrong and some are still missing.

toolbox logo and citation

Hi Andreas @adtzlr ,
I don't want to hold you up, so the following is absolutely not a priority (just nice to have). However, would you mind giving me a Go/Nogo answer soon?

For an upcoming presentation I would like to refer to the ttb (and advertise it). Just for the fun I played around with a logo some time ago, because I think we're still missing one for the toolbox (always nicer than showing a written URL).
This is what I came up with (editable .svg file appended):
ttb logo
I just wanted to check in with you, whether I may use this logo for the time being. Of course, it's your toolbox, you decide and we can alter the logo to your liking.

Another question that arises in this context, is how the toolbox could be cited (others for instance: https://www.tensortoolbox.org/, https://sites.google.com/site/aenader/umat-workshop). But that does not need to be elaborated in the near future.

Thanks and once again, lots of appreciation for the work you've put into the toolbox, it facilitates and improves my work majorly,
Johannes

PNG and SVG:
ttb logo.zip

Enhance Piola operation in Voigt notation

The implementation of function piola4s is very slow (even slower than full tensor version piola4) because first the fourth order tensor is converted to tensor storage, then the piola operation is performed and lastly it is converted back to Voigt notation.

Is it easy to call this library by .f file instead of .F

Hi, many thanks for your efforts as I was trying to heavily use your library in the development of UMAT. However, due to software limitation, only the .f file is compatible with my current settings. I am wondering if it is easy to integrate your library by calling a .f file instead of .F file?

Thanks!

dot product of two vectors

Hi @adtzlr ,
I got unexpected results when I tried to use dot_11 to calculate dot product of two vectors.
I think it should be
dot_11 = dot_11 + T1%a(i)*T2%a(i)
instead of
dot_11 = dot_11 + T1%a(i)*T2%a(j)

Please correct me if I am wrong.
image

Add unit tests

ideally within a CI/CD pipeline using Github Actions.

Question of Example umat_nh_ttb_simple.F

Hi, Andreas:

I have a couple questions for this umat example using ttb.

First, have you tested running of this umat file on Abaqus? I am assuming not, because apparently the updated stress (STRESS) and constitutive tangent (DDSDDE) is not defined, despite they were assigned by s and d in your code.

Secondly, since I was running the umat developed on my own but it always have convergent issues. I noticed you have an additional step to push forward to Jaumann tangent rate of Cauchy stress for Abaqus. In the past, I always understand the DDSDDE required by Abaqus can be approximated by dSdE, where S is the 2nd PK stress. However, it seems that should be dsigma/dD, where sigma is Cauchy stress and D is the displacement, Would you mind expand a little bit about how did you get the equation on line 60 of your example code.

Best,

Docs are broken

due to a recent switch of the Jekyll theme and a switch to GitHub Actions.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.