Using abaqus umat from shared library

I want to use abaqus umats from a shared library, but somehow it does not work. This is how I do it, according to the documentation:

Create the shared library
This includes several files, where some utility subroutines and the umats are included.
The Filename of the umat is for example umat_abaqus_lineartest.f90.
I compile it using gfortran to a file libLIBNAME.so.
The subroutine for the material behavior itself is only called lineartest, as this is how I understood it from the documentation.

Calculix executable
I am using the Calculix executable which can be downloaded here: FEA Cluster

Calling the shared library
This is done in the inp file with

*MATERIAL, NAME=@ABAQUS_LIBNAME_LINEARTEST
*USER MATERIAL, CONSTANTS=2
...

Have I missed something, or is it meant to be that for one umat routine you have one shared library? This I can’t find in the documentation anywhere.

After trying to run it, it creates a file named WarnNodeMussMultiStage.nam with this content:

 *NSET,NSET=WarnNodeMultiStage

Using an existing executable only makes sense if that was compiled with the compiler option -DCALCULIX_EXTERNAL_BEHAVIOURS_SUPPORT (see this thread on a similar recent discussion). Otherwise it won’t work. The mentioned thread further recommends to include the additional compiler option -DCALCULIX_EXTERNAL_BEHAVIOUR_DEBUG to better understand what is going on.

2 Likes

And since this option is only used in Makefile_MFront and not in the other Makefiles that come with CalculiX, most existing executables will probably not be built with external support.

Also keep in mind that this is a potential security vulnerability. Especially when running a pre-built library.

Thanks for the Replys.

I tried already to compile the executable with the compilerflag, but this gave me no result. Probably I added it not at the correct Makefile. I also tried using C for the umat, as this is mentioned as well in the documentation.

The Library is build by myself, so no malicious stuff will be in there.

If you write the umat in C, the name of the function in the object file will be different!

External functions written in Fortran have an underscore appended to the name, while those in C haven’t.

From the ccx source code:

In umat_abaqus.f:

      subroutine umat_abaqus(amat,iel,iint,kode,elconloc,emec,emec0,
     &        beta,xokl,voj,xkl,vj,ithermal,t1l,dtime,time,ttime,
     &        icmd,ielas,mi,nstate_,xstateini,xstate,stre,stiff,
     &        iorien,pgauss,orab,istep,kinc,pnewdt,nmethod,iperturb)

In pcgsolver.c:

ITG cgsolver (double *A, double *x, double *b, ITG neq, ITG len, ITG *ia, 
               ITG *iz,double *eps, ITG *niter, ITG precFlg);
void PCG (double *A, double *x, double *b, ITG neq, ITG len, ITG *ia, 
          ITG *iz,double *eps, ITG *niter, ITG precFlg,
          double *rho, double *r, double *g, double *C, double *z);
void CG (double *A, double *x, double *b, ITG neq, ITG len, ITG *ia, 
         ITG *iz,double *eps, ITG *niter,double *r, double *p, double *z);
void Scaling (double *A, double *b, ITG neq, ITG *ia, ITG *iz, double *d);
void MatVecProduct (double *A, double *p, ITG neq, ITG *ia, ITG *iz, 
                    double *z);
void PreConditioning (double *A, ITG neq, ITG len, ITG *ia, ITG *iz, 
                      double alpha, ITG precFlg,double *C, ITG *ier);
void Mrhor (double *C, ITG neq, ITG *ia, ITG *iz, double *r, double *rho);
void InnerProduct (double *a, double *b, ITG n, double *Sum);

Using nm to look at the object files:

> nm --extern-only --defined-only umat_abaqus.o pcgsolver.o

umat_abaqus.o:
0000000000000000 T umat_abaqus_

pcgsolver.o:
0000000000000950 T CG
0000000000000910 T InnerProduct
0000000000000170 T MatVecProduct
00000000000003a0 T Mrhor
00000000000004d0 T PCG
0000000000000220 T PreConditioning
0000000000000000 T Scaling
0000000000000c20 T cgsolver

If you look in the file external.c, you will see in the function calculix_registerExternalBehaviour that it is looking for a symbol called umat_ (so following the Fortran convention) in the shared library.

Thanks for the replies. I had to put it aside for a while for other projects, and got back to it the last days.
But I must still miss something, as I can’t manage it to work. It loads the test problem but exits without any visible error or computations.

I compiled ccx myself, adding the compiler flags as mentioned above.

-DCALCULIX_EXTERNAL_BEHAVIOURS_SUPPORT

Is it possible to find out if this step was successful at all? Adding the debug flag results in the same console output during compilation.

Next, I have the umat. I tried naming it different, but as said by @rsmith calculix_registerExternalBehaviour looks for umat_. I would assume naming the function simply subroutine umat(..) .. end subroutine umat is the way to go then? At least in the doc, it says the function is called with the third part of the material name. This would mean I have to name it subroutine linel(..)... for example, not umat. Both variants don’t seem to work for me.

The umat is written in free-format .f90 using the abaqus umat template. Could this cause the problem? In the doc, it is recommended to use 77 standard.

Next, I added the path variable

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/folder/with/.so

Double checked with echo $LD_LIBRARY_PATH. The library itself is stored in this case with libLINEARTEST.so. The lib is stripped by ccx, as I understood it in the source files.

Calling the external behaviour in the .inp looks as follows for a simple linear elastic test case:

*MATERIAL, NAME=@ABAQUSNL_LINEARTEST_LINEL
*USER MATERIAL,CONSTANTS=2
210000.0,0.3

However, trying different variations in the naming etc. has not resolved the problem. It feels like I am missing something obvious?

If you also add -DCALCULIX_EXTERNAL_BEHAVIOUR_DEBUG you should get extra messages when using external materials. See external.c.

If I read the documentation correctly, your subroutine should be named subroutine LINEL() (upper case).
To quote the documentation:

The base name of the library and the name of the function must be upper-cased.

Turned out I did miss the obvious. At least it wasn’t for me before.

The following two things have to be considered:

  • Add the compiler Flag to the C-flags, not the F-flags. Should be clear when the routines are written in C that are responsible for calling the library, I still missed it.
  • In case of an undefined reference error, make sure to rerun the whole process. Only recompiling partially does not work.

Now, it actually tells me that it can not find the external library, which means it’s looking for it.

Thanks y’all for the support.

1 Like

Maybe I will add some more information on how to do it, as it looks to me there is quite a bit information out there which diverges from each other.

This should help to include Abaqus umat as a shared Library.

  1. Create the umat in the Abaqus format. As a template, the file umat.f can be used. The documentation says at this point the following:

A further drawback of using
shared libraries is that the behavior must be written in C or C++ and the name
of the functions implementing the behavior must be upper-case due to CalculiX
internal conventions.

The template is given in Fortran, I did it in Fortran and it works. As mentioned by @rsmith, this seems to be due to the headers of the function in Fortran and C have an underscore / no underscore.

  1. Naming of the subroutine: Using Fortran, the name of the subroutine should be subroutine UMAT(..). In external.c, the call to the external library is handled. As far as my knowledge goes, it seems that it is looking for a function name as well as umat_ in the header of the shared library. Which points to the quote above, that C has to be used when the implementation goes with a different function name as above.
    Note that per library only one umat is possible, when the subroutine is named umat.

  2. Compiling the umat: I use gfortran. For each library, a individual makefile is needed. This should be straight forward, but I will share mine:

# Define the Fortran compiler
FC = gfortran

# Define the compiler flags
FFLAGS = -Wall -O2 -fPIC -ffree-form

# Default target
$(SRC)/%.o: $(SRC)/%.f90
	$(FC) $(FFLAGS) -c $< -o $@

# Define the source files and the output shared library
FSRC = $(wildcard *.f90)
FLIB = libLINEARTEST.so
FOBJ = $(FSRC:.f90=.o)

# Rule to create the Fortran shared library
make: $(FLIB)

$(FLIB): $(FSRC)
	$(FC) -shared -o $@ $^

# Clean up
clean:
	rm -f $(FLIB) $(CLIB) $(FOBJ) $(COBJ)
  1. Next, a ccx version with activated compiler flags is needed. Those have to be added to the C compiler, not fortran. This looks as follows. I think there are not mentioned in the documentation?
CFLAGS = -Wall -O2  -I ../../../SPOOLES.2.2 -DARCH="Linux" -DSPOOLES -DARPACK -DMATRIXSTORAGE -DNETWORKOUT -DCALCULIX_EXTERNAL_BEHAVIOURS_SUPPORT -DCALCULIX_EXTERNAL_BEHAVIOURS_DEBUG -fPIC -DPIC

Make sure to recompile clean when activating the flags, I missed it.

  1. Make the Library available to ccx. This can either be done by placing the *.so in the same folder as the ccx executable (works for me) or by editing LD_LIBRARY_PATH on unix, pointing to the library.
export $LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/folder/with/.so
  1. Calling the user material in the input file: When the subroutine is named umat, it should be called with @ABAQUSNL_LIBRARY. I have not tested to implement it in C, it should be an additional _FUNCTIONNAME, according to external.c. It also needs to be mentioned that a preceding lib is omitted by calculix.

  2. I used the source files from FEA Cluster and edited the Perl installation script a little to accomodate for a seperate umat compilation and some QoL features to save time when compiling/ installing several umats into shared librarys.