Contents

Introduction

Introduction to AceGen

Preface

The Mathematica package AceGen is used for the automatic derivation of formulae needed in numerical procedures. Symbolic derivation of the characteristic quantities (e.g. gradients, tangent operators, sensitivity vectors, … ) leads to exponential behavior of derived expressions, both in time and space. A new approach, implemented in AceGen, avoids this problem by combining several techniques: symbolic and algebraic capabilities of Mathematica, hybrid symbolic-automatic differentiation technique, automatic code generation, simultaneous optimization of expressions and theorem proving by a stochastic evaluation of the expressions. The multi-language capabilities of AceGen can be used for a rapid prototyping of numerical procedures in script languages of general problem solving environments like Mathematica or Matlab© as well as to generate highly optimized and efficient compiled language codes in FORTRAN or C. Through a unique user interface the derived formulae can be explored and analyzed.
The AceGen package also provides a collection of prearranged modules for the automatic creation of the interface between the automatically generated code and the numerical environment where the code would be executed. The AceGen package directly supports several numerical environments such as: MathLink connection to Mathematica, AceFEM is a research finite element environment based on Mathematica, FEAP© is a research finite element environment written in FORTRAN, ELFEN© and ABAQUS© are the commercial finite element environments written in FORTRAN etc.. The multi-language and multi-environment capabilities of AceGen package enable generation of numerical codes for various numerical environments from the same symbolic description. In combination with the finite element environment AceFEM the AceGen package represents ideal tool for a rapid development of new numerical models.

General

Symbolic and algebraic computer systems such as Mathematica are general and very powerful tools for the manipulation of formulae and for performing various mathematical operations by computer. However, in the case of complex numerical models, direct use of these systems is not possible. Two reasons are responsible for this fact: a) during the development stage the symbolic derivation of formulae leads to uncontrollable growth of expressions and consequently redundant operations and inefficient programs, b) for numerical implementation SAC systems can not keep up with the run-time efficiency of programming languages like FORTRAN and C and by no means with highly problem oriented and efficient numerical environments used for finite element analysis.
The following techniques which are results of rapid development in computer science in the last decades are particularly relevant when we want to describe a numerical method on a high abstract level, while preserving the numerical efficiency:

symbolic and algebraic computations (SAC) systems,

automatic differentiation (AD) tools,

problem Solving Environments (PSE),

theorem proving systems (TP),

numerical libraries,

specialized systems for FEM.

AceGen

The idea implemented in AceGen is not to try to combine different systems, but to combine different techniques inside one system in order to avoid the above mentioned problems. Thus, the main objective is to combine techniques in such a way that will lead to an optimal environment for the design and coding of numerical subroutines. Among the presented systems the most versatile are indeed the SAC systems. They normally contain, beside the algebraic manipulation, graphics and numeric capabilities, also powerful programming languages. It is therefore quite easy to simulate other techniques inside the SAC system. An approach to automatic code generation used in AceGen is called Simultaneous Stochastic Simplification of numerical code (Korelc 1997a). This approach combines the general computer algebra system Mathematica with an hybrid symbolic-automatic automatic differentiation technique and an automatic theorem proving by examples. To alleviate the problem of the growth of expressions and redundant calculations, simultaneous simplification of symbolic expressions is used. Stochastic evaluation of the formulae is used for determining the equivalence of algebraic expressions, instead of the conventional pattern matching technique. AceGen was designed to approach especially hard problems, where the general strategy to efficient  formulation of numerical procedures, such as analytical sensitivity analysis of complex multi-field problems, has not yet been established.

General characteristics of AceGen code generator:

simultaneous optimization of expressions  immediately after they have been derived (Expression Optimization),

hybrid symbolic-automatic automatic differentiation technique (Automatic Differentiation, Exceptions in Differentiation),

automatic selection of the appropriate intermediate variables,

the whole program structure can be generated (Mathematica Syntax - AceGen Syntax),

appropriate for large problems where also intermediate expressions can be subjected to the uncontrolled swell,

improved optimization procedures with stochastic evaluation of expressions,

differentiation with respect to indexed variables,

automatic interface to other numerical environments (by using Splice command of Mathematica),

multi-language code generation (Fortran/Fortran90, C/C++, Mathematica language, Matlab language),

advanced user interface,

advanced methods for exploring and debugging of generated formulae,

special procedures are needed for Local and Non-local Operations.

The AceGen system is written in the symbolic language of Mathematica. It consists of about 300 functions and 20000 lines of Mathematica's source code. Typical AceGen function takes the expression provided by the user, either interactively or in file, and returns an optimized version of the expression. Optimized version of the expression can result in a newly created auxiliary symbol ((Subscript[v, i])), or in an original expression in parts replaced by previously created auxiliary symbols. In the first case AceGen stores the new expression in an internal data base. The data base contains a global vector of all expressions, information about dependencies of the symbols, labels and names of the symbols, partial derivatives, etc. The data base is a global object which maintains information during the Mathematica session.
The classical way of optimizing expressions in computer algebra systems is searching for common sub-expressions at the end of the derivation, before the generation of the numerical code. In the numerical code common sub-expressions appear as auxiliary variables. An alternative approach is implemented in AceGen where formulae are optimized, simplified and replaced by the auxiliary variables simultaneously with the derivation of the problem. The optimized version is then used in further operations. If the optimization is performed simultaneously, the explicit form of the expression is obviously lost, since some parts are replaced by intermediate variables.

Simultaneous simplification procedure.

In real  problems it is almost impossible to recognize the identity of two expressions (for example the symmetry of the tangent stiffness matrix in nonlinear mechanical problems) automatically only by the pattern matching mechanisms. Normally our goal is to recognize the identity automatically without introducing additional knowledge into the derivation such as tensor algebra, matrix transformations, etc. Commands in Mathematica such as Simplify, Together, and Expand, are useless in the case of large expressions. Additionally, these commands are efficient only when the whole expression is considered. When optimization is performed simultaneously, the explicit form of the expression is lost. The only possible way at this stage of computer technology seems to be an algorithm which finds equivalence of expressions numerically. This relatively old idea (see for example Martin 1971 or Gonnet 1986) is rarely used, although it is essential for dealing with especially hard problems. However, numerical identity is not a mathematically rigorous proof for the identity of two expressions. Thus the correctness of the simplification can be determined only with a certain degree of probability. With regard to our experience this can be neglected in mechanical analysis when dealing with more or less ‘smooth’ functions.

Practice shows that at the research stage of the derivation of a new numerical software, different languages and different platforms are the best means for assessment of the specific performances and, of course, failures of the numerical model. Using the classical approach, re-coding of the source code in different languages would be extremely time consuming and is never done. With the symbolic concepts re-coding comes practically for free, since the code is automatically generated for several languages and for several platforms from the same basic symbolic description. The basic tests which are performed on a small numerical examples can be done most efficiently by using the general symbolic-numeric environments such as Mathematica, Maple, etc. It is well known that many design flaws such as instabilities or poor convergence characteristics of the numerical procedures can be easily identified if we are able to investigate the characteristic quantities (residual, tangent matrix, ... ) on a symbolic level. Unfortunately, symbolic-numeric environments become very inefficient if we have a larger examples or if we have to perform iterative numerical procedures. In order to assess performances of the numerical procedure under real conditions the easiest way is to perform tests on sequential machines with good debugging capabilities (typically personal computers and programs written in Fortran or C language). At the end, for real industrial simulations, large parallel machines have to be used. With the symbolic concepts implemented in AceGen, the code is automatically generated for several languages and for several platforms from the same basic symbolic description.
KORELC, Jože, Multi-language and Multi-environment Generation of Nonlinear Finite Element Codes,  Engineering with Computers, 2002, 18(4):312-327
KORELC, Jože. Automatic generation of finite-element code by simultaneous optimization of expressions. Theor. comput. sci.. , 1997, 187:231-248.

Mathematica and AceGen

Since AceGen runs in parallel with Mathematica we can use all the capabilities of Mathematica. The major algebraic computations which play crucial role in the development of any numerical code are:

analytical differentiation,

symbolic evaluation,

symbolic solution to the system of linear equations,

symbolic integration,

symbolic solution to the system of algebraic equations.

Each of these operations can be directly implemented also with the built-in Mathematica functions and the result optimized by AceGen. However, by using equivalent functions in AceGen with simultaneous optimization of expressions, much larger problems can be efficiently treated. Unfortunately, the equivalent AceGen functions exist only for the ‘local’ operations (see Local and Non-local Operations).

AceGen Palettes

Main AceGen palette.

Display generated program.

Debugger palette and display.

AceGen Overview

Installation instructions

(HyperlinkTemplate[Installation instructions, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, HyperlinkActionRecycled, HyperlinkActive, , ])

General AceGen Session

Standard AceGen Procedure

User Interface

SMSInitialize — start AceGen session

SMSModule — start new user subroutine

SMSWrite — end AceGen session and create source file

Assignments and expression manipulations

Auxiliary Variables

⊨ . ⊢ . ⫤ . ⊣ — assignment operators

SMSInt . SMSFreeze . SMSFictive  — special assignments

SMSSimplify . SMSReplaceAll . SMSSmartReduce . SMSSmartRestore . SMSRestore . SMSVariables — auxiliary variables manipulations

Arrays

SMSArray . SMSPart . SMSReplacePart . SMSDot . SMSSum — operations with arrays

Automatic Differentiation

SMSD . SMSDefineDerivative — automatic differentiation

Symbolic-numeric interface

Symbolic-Numeric Interface

SMSReal . SMSInteger . SMSLogical . SMSRealList .  — import from input parameters

SMSExport — export to output parameters

SMSCall — call external subroutines

Program Flow Control

Program Flow Control

SMSIf . SMSElse . SMSEndIf . SMSSwitch . SMSWhich —  conditionals

SMSDo . SMSEndDo —  loop construct

SMSReturn . SMSBreak . SMSContinue .

Special functions

User Defined Functions

SMSVerbatim —  include part of the code verbatim

SMSPrint . SMSPrintMessage —  print to output devices from the generated code

SMSAbs . SMSSign . SMSKroneckerDelta . SMSSqrt . SMSMin . SMSMax . SMSRandom . SMSNumberQ . SMSPower . SMSTime . SMSUnFreeze —  functions with random signature

SMSLinearSolve . SMSLUFactor . SMSLUSolve . SMSFactorSim . SMSInverse . SMSDet . SMSKrammer —  linear algebra functions

SMSCovariantBase . SMSCovariantMetric . SMSContravariantMetric . SMSChristoffell1 . SMSChristoffell2 . SMSTensorTransformation . SMSDCovariant — tensor algebra functions

SMSLameToHooke . SMSHookeToLame . SMSHookeToBulk . SMSBulkToHooke . SMSPlaneStressMatrix . SMSPlaneStrainMatrix . SMSEigenvalues . SMSMatrixExp . SMSInvariantsI . SMSInvariantsJ .  — mechanics of solids functions

Manipulating notebooks

SMSEvaluateCellsWithTag —  evaluate all notebook cells

SMSRecreateNotebook —  create new notebook that includes only evaluated cells

SMSTagIf . SMSTagSwitch . SMSTagReplace .  —  manipulate break points

Debugging

Verification and Debugging

SMSSetBreak —  insert break point

SMSLoadSession —  reload the data and definitions for debugging session

SMSClearBreak . SMSActivateBreak —  create new notebook that includes only evaluated parts

MathLink environment

SMSInstallMathLink . SMSLinkNoEvaluations . SMSSetLinkOptions . Solution to the System of Nonlinear Equations — create installable MathLink Program from generated C code

AceGen Examples

Standard AceGen Procedure . Solution to the System of Nonlinear Equations . Minimization of Free Energy

Finite element environments

Template Constants

Element Topology

Numerical Integration

Data Structures

Standard User Subroutines

AceGen Basics

Standard AceGen Procedure

Contents

Introductory Example

Description of Introductory Example

Description of AceGen Characteristic Steps

Step 1: Initialization

Step 2: Definition of Input and Output Parameters

Step 3: Definition of Numeric-Symbolic Interface Variables

Step 4: Description of the Problem

Step 5: Definition of Symbolic - Numeric Interface Variables

Step 6: Code Generation

Mathematica Syntax - AceGen Syntax

Example 1: Assignments

Example 2: Conditional statements (If construct)

Example 3: Loops (Do construct)

Example 4: Conditional statements (Which construct)

AceGen Session Functions

SMSInitialize

SMSModule

SMSWrite

SMSVerbatim

Examples of Multi-language Code Generation

Generation of C code

Generation of MathLink code

Generation of Matlab code

Introductory Example

Description of Introductory Example

Let us consider a simple example to illustrate the standard AceGen procedure for the generation of a typical numerical sub-program that returns gradient of a given function f with respect to the set of parameters. Let unknown function u be approximated by a linear combination  of unknown parameters (Subscript[u, 1]),(Subscript[u, 2]),(Subscript[u, 3]) and shape functions (Subscript[N, 1]),(Subscript[N, 2]),(Subscript[N, 3]).
u=(∑_(i=1)^3)(Subscript[N, i])(Subscript[u, i])
(Subscript[N, 1])=(x/L)
(Subscript[N, 2])=1-(x/L)
(Subscript[N, 3])=(x/L)(1-(x/L))
Let us suppose that our solution procedure needs gradient of function f=(u^2) with respect to the unknown parameters. AceGen can generate complete subprogram that returns the required quantity.

Description of AceGen Characteristic Steps

The syntax of the AceGen script language is the same as the syntax of the Mathematica script language with some additional functions. The input for AceGen can be divided into six characteristic steps.

Characteristic steps of the AceGen session

Due to the advantage of simultaneous optimization procedure we can execute each step separately and examine intermediate results. This is also the basic way how to trace the errors that might occur during the AceGen session.

Step 1: Initialization

This loads the AceGen package.

<<AceGen`

This initializes the AceGen session. FORTRAN is chosen as the final code language. See also SMSInitialize.

SMSInitialize["test","Language"->"Fortran"];

Step 2: Definition of Input and Output Parameters

This starts a new subroutine with the name "Test" and four real type parameters. The input parameters of the subroutine are u, x, and L, and parameter g is an output parameter of the subroutine. The input and output parameters of the subroutine are characterized by the double $ sign at the end of the name. See also Symbolic-Numeric Interface.

SMSModule["Test",Real[u$$[3],x$$,L$$,g$$[3]]];

Step 3: Definition of Numeric-Symbolic Interface Variables

Here the input parameters of the subroutine are assigned to the usual Mathematica variables. The standard Mathematica assignment operator = has been replaced by the special AceGen operator ⊨. Operator ⊨ performs stochastic simultaneous optimization of expressions. See also Auxiliary Variables, SMSReal.

x⊢SMSReal[x$$]

L⊢SMSReal[L$$]

Here the variables u[1], u[2], u[3] are introduced.

ui⊢SMSReal[Table[u$$[i]  ,{i,3}]]

Step 4: Description of the Problem

Here is the body of the subroutine.

Ni⊨{x/L, 1 - x/L, x/L*(1 - x/L)}

u⊨Ni . ui

f⊨u^2

g⊨SMSD[f, ui]

Step 5: Definition of Symbolic - Numeric Interface Variables

This assigns the results to the output parameters of the subroutine. See also SMSExport.

SMSExport[g, g$$];

Step 6: Code Generation

During the session AceGen generates pseudo-code which is stored into the AceGen database. At the end of the session AceGen translates the code from pseudo-code to the required script or compiled program language and prints out the code to the output file. See also SMSWrite.

SMSWrite[];

This displays the contents of the generated file.

FilePrint["test.f"]

Mathematica Syntax - AceGen Syntax

In principle we can get AceGen input simply by replacing the = operators in standard Mathematica input by an appropriate AceGen assignment operator ( ⊨,  ⊢ , ⫤ , ⊣ ), the standard Mathematica conditional statements If, Which and Switch by the AceGen SMSIf, SMSSwitch, SMSWhich statements and the standard Mathematica loop statement Do by the AceGen SMSDo statement. All other conditional and loop structures have to be manually replaced by the equivalent forms consisting only of SMSIf and SMSDo statements. It is important to notice that only the replaced conditionals and loops produce corresponding conditionals and loops in the generated code and are evaluated when the generated program is executed. The conditional and loops that are left unchanged are evaluated directly in Mathematica during the AceGen session.

Syntax of the basic AceGen commands.

The control structures in Mathematica have to be completely located inside one notebook cell (e.g. loop cannot start in once cell and end in another cell). AceGen extends the functionality of Mathematica with the cross-cell form of If and Do control structures as presented in Program Flow Control chapter.

Example 1: Assignments

Mathematica input

x=.;n=.;
y=((Sin[x])^n)

AceGen input

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["Test",Real[x$$,y$$],Integer[n$$]];
x⊢SMSReal[x$$];
n⊢SMSInteger[n$$];
y⊨((Sin[x])^n);

AceGen code profile

SMSExport[y,y$$];
SMSWrite[];

FilePrint["test.c"]

Example 2: Conditional statements (If construct)

y=(Piecewise[{{(Piecewise[{{7, x≥7}, {x, x<7}}]), x≥0}, {(x^2), x<0}}])
z=Sin(y)+1

Mathematica input

y=If[x≥ 0
,If[x≥7
,7
,x
]
,(x^2)
];
z=Sin[y]+1

AceGen input

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["Test",Real[x$$,z$$]];
x⊢SMSReal[x$$];
y⊨SMSIf[x≥ 0
,SMSIf[x≥7
,7
,x
]
,(x^2)
];
z⊨Sin[y]+1;

AceGen code profile

SMSExport[z,z$$];
SMSWrite[];
FilePrint["test.c"]

Example 3: Loops (Do construct)

z(i)=Sin((x^i))
y=(∑_(i=1)^n)(((z(i)+(i/(z(i)))))^i)

Mathematica input

NOTE: Upper limit n in Do can only have specific integer value!

Clear[x];n=5;
y=0;
Do[ 
z=Sin[(x^i)];
y=y+(((z+(i/z)))^i);
,{i,1,n,1}]
y

AceGen input

NOTE: Upper limit n in SMSDo can have arbitrary value! 
NOTE: Original list of arguments of Do construct {i, 1, n, 1} is in SMSDo extended by an additional argument {i, 1, n, 1, y} that provides information about variables that are imported into the loop and have values changed inside the loop and all variables that are defined inside the loop and  used outside the loop.

<<AceGen`;
SMSInitialize["test","Language"->"C#"];
SMSModule["Test",Real[x$$,y$$],Integer[n$$]];
x⊢SMSReal[x$$];
n⊢SMSInteger[n$$];
y⫤0;
SMSDo[ 
z⊨Sin[(x^i)];
y⊣y+(((z+(i/z)))^i);
,{i,1,n,1,y}];

AceGen code profile

SMSExport[y,y$$];
SMSWrite[];
FilePrint["test.cs"]

Example 4: Conditional statements (Which construct)

y={({{x≥0, {({{x≥7, 7}, {x<7, x}})}, {x<0, (x^2)}})
z=Sin[y]+1

Mathematica input

Clear[x];
y=Which[x≥ 0 && x≥7,7,x≥ 0 && x<7,x,x<0,(x^2)]
z=Sin[y]+1

AceGen input

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["Test",Real[x$$,z$$]];
x⊢SMSReal[x$$];
y⊨SMSWhich[x≥ 0 && x≥7,7,x≥ 0 && x<7,x,x<0,(x^2)];
z⊨Sin[y]+1;

AceGen code profile

SMSExport[z,z$$];
SMSWrite[];
FilePrint["test.f"]

AceGen Session Functions

SMSInitialize

In a "Debug" mode all the expressions are included into the final code and preceded by the explanatory comments. Derivation of the code in a "Optimal" mode usually takes 2-3 times longer than the derivation of the code in a "Prototype" mode.

This initializes the AceGen system and starts a new AceGen session with the name "test". At the end of the session, the FORTRAN code is generated.

SMSInitialize["test","Language"->"Fortran"];

SMSModule

The name of the module (method, subroutine, function, ...) name can be arbitrary string or Automatic. In the last case AceGen generates an unique name for the module composed of the session name and an unique number. All the parameters should follow special AceGen rules for the declaration of external variables as described in chapter Symbolic-Numeric Interface.  An arbitrary number of modules can be defined within a single AceGen session. An exception is Matlab language where the generation of only one module per AceGen session is allowed.

By default all the parameters are labeled as input/output parameters. The "Input" and the "Output" options are used in MathLink  (see Standard AceGen Procedure) and Matlab to specify the input and the output parameters.
The SMSModule command starts an arbitrary module. However, numerical environments usually require a standardized set of modules (traditionally called "user defined subroutines") that are used to perform specific task (e.g. to calculate tangent matrix) and with a strict set of I/O parameters. The SMSStandardModule command (see Standard User Subroutines) can be used instead of SMSModule for the definition of the standard user subroutines for supported finite element numerical environments.

Example 1

This creates a Fortran subroutine named "sub1" with real parameters x, z, real type array y(5), integer parameter i, and parameter m of the user defined type ‘mytype’ .

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"]; 
SMSModule["sub1",Real[x$$,y$$[5]],Integer[i$$],Real[z$$],"mytype"[m$$]
,"Verbatim"->"COMMON /xxx/a(5)\nwrite(*,*)'start'"
,"VerbatimEnd"->"write(*,*)'end'"];
SMSExport[π,x$$];
SMSWrite[];
FilePrint["test.f"]

Example 2

Create a C subroutine that calulactes series (Subscript[r, ij])=(∑_(s=1)^k) (Subscript[(x^s), ij]), i=1,...n;j=1,...m.

Solution 1: elements of the series are calculated and added to globaly defined (Subscript[r, ij]) directly. (Subscript[r, ij]) is alloocated on heap.

<<AceGen`;
SMSInitialize["test","Environment"->"MathLink"]; 
SMSModule["test",Real[x$$[n$$,m$$]],Integer[n$$,m$$,k$$],Real[r$$[n$$,m$$]],"Input"->{x$$,n$$,m$$,k$$},"Output"->r$$];
{n,m,k}⊨SMSInteger[{n$$,m$$,k$$}];
SMSDo[
SMSDo[
SMSDo[
SMSExport[SMSPower[SMSReal[x$$[i,j]],s],r$$[i,j],"AddIn"->True]
,{s,1,k}];
,{i,1,n}];
,{j,1,m}];
SMSWrite[];

SMSInstallMathLink[];

n=100;m=100;k=1000;
Total[test[Table[1./(i+j),{i,n},{j,m}],n,m,k],2]

SMSUninstallMathLink[];

Solution 2: elements of the series are calculated and added to locally defined (Subscript[r, ij]) allocated on stack. The result is then  exported to global (Subscript[r, ij]) allocated on heap. This can be numerically more efficient due to the local memory access, however stack memory is limited!

<<AceGen`;
SMSInitialize["test","Environment"->"MathLink"]; 
SMSModule["test",Real[x$$[n$$,m$$]],Integer[n$$,m$$,k$$],Real[r$$[n$$,m$$]],"Input"->{x$$,n$$,m$$,k$$},"Output"->r$$
,"Verbatim"->"double locr[*n][*m];\nint ii,jj;\nfor(ii=0;ii<(*n);ii++) for(jj=0;jj<(*m);jj++) locr[ii][jj]=0e0;"
,"VerbatimEnd"->"for(ii=0;ii<(*n);ii++) for(jj=0;jj<(*m);jj++) r[ii][jj]=locr[ii][jj];"
];
{n,m,k}⊨SMSInteger[{n$$,m$$,k$$}];
SMSDo[
SMSDo[
SMSDo[
SMSExport[SMSPower[SMSReal[x$$[i,j]],s],locr$$[i,j],"AddIn"->True]
,{s,1,k}];
,{i,1,n}];
,{j,1,m}];
SMSWrite[];

SMSInstallMathLink[];

n=100;m=100;k=1000;
Total[test[Table[1./(i+j),{i,n},{j,m}],n,m,k],2]

SMSUninstallMathLink[];

SMSWrite

The "splice-file" is arbitrary text file that is first interpreted by the Mathematica´s FileTemplate command and then prepended to the automatically generated source code file. Options "IncludeNames" and "IncludeAllFormulas" are useful during the ‘debugging’ period. They have effect only in the case that AceGen session was initiated in the "Debug" or "Prototype" mode. Option "OptimizingLoops" has effect only in the case that AceGen session was  initiated in the "Optimal" or a higher mode.
The default header files are located in $BaseDirectory/Applications/AceGen/Include/  directory together with the collection of utility routines (SMSUtility.c and SMSUtility.f). The header files and the utility subroutines should be available during the compilation of the generated source code. See also (HyperlinkTemplate[Installation instructions, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, HyperlinkActionRecycled, HyperlinkActive, , ]) for instructions how to compile and link the generated codes.

See also: Standard AceGen Procedure

This writes the generated code on the file "source.c" and prepends contents of the file "test.mc" interpreted by the Splice command.

<<AceGen`;

strm=OpenWrite["test.mc"];
WriteString[strm,"/*This is a \"splice\" file <*100+1*> */"];
Close[strm];

FilePrint["test.mc"]

SMSInitialize["test", "Language" -> "C"]; 
SMSModule["sub1", Real[x$$, y$$[2]]];
SMSExport[BesselJ[SMSReal[y$$[1]],SMSReal[y$$[2]]],x$$];
SMSWrite["source","Splice" -> "test.mc",
   "Substitutions"->{BesselJ[i_,j_]:>"mybessel"[i,j]}];

FilePrint["source.c"]

SMSVerbatim

Input parameters source, (Subscript[source, 1]),(Subscript[source, 2]),... have special form. They can be a single string, or a list of arbitrary expressions. Expressions can contain auxiliary variables as well. Since some of the characters (e.g. ") are not allowed in the string we have to use substitution instead accordingly to the table below.

Character substitution table.

The parameter "language" can be any of the languages supported by AceGen (''Mathematica'', ''Fortran'', "Fortan90", "C", ''C++'',...). It is sufficient to give a rule for the generic form of the language (''Mathematica'', ''Fortran'', "C") (e.g instead of the form for language "Fortran90" we can give the form for language "Fortran").
The source can contain arbitrary program sequences that are syntactically correct for the chosen program language, however the source is taken verbatim and is neglected during the differentiation procedure unless additional declarations are included as presented in User Defined Functions.

SMSInitialize["test","Language"->"C"];
SMSModule["test"];
SMSVerbatim[
	   "Fortran"->{"write(*,*) 'Hello'","\nstop"}
	   ,"Mathematica"->{"Print['Hello'];","\nAbort[];"} 
	   ,"C"->{"printf('Hello');","\nexit(0);"} 
];
SMSWrite["test"];

FilePrint["test.c"]

For more examples see User Defined Functions.

Examples of Multi-language Code Generation

Generation of C code

Instead of the step by step evaluation, we can run all the session at once. This time the C version of the code is generated.

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["Test",Real[u$$[3],x$$,L$$,g$$[3]]];
{x,L}⊢{SMSReal[x$$],SMSReal[L$$]};
ui⊢SMSReal[Table[u$$[i],{i,3}]]
Ni⊨{(x/L),1-(x/L),(x/L)(1-(x/L))};
u⊨Ni.ui;
f⊨(u^2);
g⊨SMSD[f,ui];
SMSExport[g,g$$];
SMSWrite[];

FilePrint["test.c"]

Generation of MathLink code

Here the MathLink (MathLink, Matlab Environments) version of the source code is generated. The generated code is automatically enhanced by an additional modules necessary for the proper MathLink connection.

<<AceGen`;
SMSInitialize["test","Environment"->"MathLink"];
SMSModule["Test",Real[u$$[3],x$$,L$$,g$$[3]],
"Input"->{u$$,x$$,L$$},"Output"->g$$];
{x,L}⊢{SMSReal[x$$],SMSReal[L$$]};
ui⊢SMSReal[Table[u$$[i],{i,3}]]
Ni⊨{(x/L),1-(x/L),(x/L)(1-(x/L))};
u⊨Ni.ui;
f⊨(u^2);
g⊨SMSD[f,ui];
SMSExport[g,g$$];
SMSWrite[];

FilePrint["test.c"]

Here the MathLink program Test.exe is build from the generated source code and installed so that functions defined in the source code can be called directly from Mathematica (see also SMSInstallMathLink).

SMSInstallMathLink[]

Here the generated executable is used to calculate gradient for the numerical test example.

Test[{0.,1.,7.},π//N,10.]

Generation of Matlab code

The AceGen generated M-file functions can be directly imported into Matlab. Here the Matlab version of the source code is generated.

<<AceGen`;
SMSInitialize["test","Language"->"Matlab"];
SMSModule["Test",Real[u$$[3],x$$,L$$,g$$[3]],
"Input"->{u$$,x$$,L$$},"Output"->g$$];
{x,L}⊢{SMSReal[x$$],SMSReal[L$$]};
ui⊢SMSReal[Table[u$$[i],{i,3}]]
Ni⊨{(x/L),1-(x/L),(x/L)(1-(x/L))};
u⊨Ni.ui;
f⊨(u^2);
g⊨SMSD[f,ui];
SMSExport[g,g$$];
SMSWrite[];

FilePrint["test.m"]

User Interface

Contents

General Description

Presentation of Formulas

Exploring the structure of the formula - Browser mode submenu

Output representations of the expressions

Polymorphism of the generated formulae - Variable tags submenu

Analyzing the structure of the program

Run time debugging

General Description

An important question arises: how to understand the automatically generated formulae? The automatically generated code should not act like a "black box". For example, after using the standard automatic differentiation tools we have no insight in the actual structure of the derivatives. While formulae are derived automatically with AceGen, AceGen tries to find the actual meaning of the auxiliary variables and assigns appropriate names. By asking Mathematica in an interactive dialog about certain symbols, we can retain this information and explore the structure of the generated expressions. In the following AceGen sessions various possibilities how to explore the structure of the program are presented.

Test Example

Let start with the subprogram that returns solution to the system of the following nonlinear equations
Φ={({{a x y+(x^3)=0}, {a−x (y^2)=0}})}

where x and y are unknowns and a is the parameter using the standard Newton-Raphson iterative procedure. The SMSSetBreak function inserts the breaks points with the identifications "X" and "A"  into the generated code.

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica","Mode"->"Debug"];
SMSModule["test",Real[x$$,y$$,a$$,tol$$],Integer[nmax$$]];
{x0,y0,a,ϵ}⊢SMSReal[{x$$,y$$,a$$,tol$$}];
nmax⊢SMSInteger[nmax$$];
{x,y}⫤{x0,y0};
SMSDo[
Φ⊨{a  x  y+(x^3),a - x (y^2)};
Kt⊨SMSD[Φ,{x,y}];
{Δx,Δy}⊨SMSLinearSolve[Kt,-Φ];
{x,y}⊣{x,y}+{Δx,Δy};
SMSIf[SMSSqrt[{Δx,Δy}.{Δx,Δy}]<ϵ
,SMSExport[{x,y},{x$$,y$$}];
SMSBreak[];
];
SMSIf[i==nmax
,SMSPrintMessage["no convergion"];
SMSReturn[];
];
,{i,1,nmax,1,{x,y}}
];
SMSWrite[];

Presentation of Formulas

Exploring the structure of the formula - Browser mode submenu

AceGen palette offers buttons that control how expressions are represented on a screen.

Palette for entering  AceGen  commands that control user-AceGen  interactions.

Auxiliary variables are represented as active areas (buttons) of the output form of the expressions in blue color. When we point with the mouse on one of the active areas, a new cell in the notebook is generated and the definition of the pointed variable will be displayed. Auxiliary variables are again represented as active areas and can be further explored. Definitions of the external variables are displayed in red color. The ";" character is used to indicate derivatives (e.g  (Subscript[Φ, 1;x])=((∂(Subscript[Φ, 1]))/(∂x ))).

Kt[[1,1]]

There are two possibilities how the new cell is generated. The first possibility is that the new cell contains only the definition of the pointed variable.
Button:

Kt

The new cell can also contain the whole expression from the original cell and only pointed variable replaced by its definition.
Button:

Kt

The new cell can also contain detailed information about selected variables.
Button:

Kt

Output representations of the expressions

Expressions can be displayed in several ways. The way how the expression is displayed does not affect the internal representation of the expression.

StandardForm

The most common is the representation of the expression where the automatically generated name represents particular auxiliary variable.
Button:

Kt

FullForm

The "true" or FullForm representation is when j-th instance of the i-th auxiliary variable is represented in a form $V[i,j]. In an automatically generated source code the i-th term of the global vector of auxiliary variables (v(i)) directly corresponds to the $V[i,j] auxiliary variable.
Button:

Kt

CondensedForm

If variables are in a FullForm they can not be further explored. Alternative representation where j-th instance of the i-th auxiliary variable is represented in a form (Subscript["", j])(Subscript["¥", i]) enables us to explore FullForm of the automatically generated expressions.
Button:

Kt

NumberForm

Auxiliary variables can also be represented by their signatures (assigned random numbers) during the AceGen session or by their current values during the execution of the automatically generated code. This type of representation is used for debugging. 
Button:

Kt

Polymorphism of the generated formulae - Variable tags submenu

Sometimes AceGen finds more that one meaning (tag) for the same auxiliary variable. By default it displays the shortest tag ( ).

Kt

By pressing button  the last found meaning (name) of the auxiliary variables will be displayed.

Kt

All meanings (names) of the auxiliary variables can also be explored ().

Kt

Analyzing the structure of the program

The   button can be used in order to produce separate window where the structure of the program is displayed together with the links to all generated formulae.

Run time debugging

The  code profile window is also used for the run-time debugging. See Run Time Debugging section for details.

Auxiliary Variables

Contents

Expression Optimization

Probability of incorrect simplifications

Functions with unique signatures

Expression optimization and automatic differentiation

Types of Auxiliary Variables

Example: real integer and logical variables

Example: multi-valued variables

Auxiliary Variables Functions

SMSR

SMSV

SMSM

SMSS

SMSSimplify

SMSVariables

SMSFreeze

SMSUnFreeze

SMSFictive

Local and Non-local Operations

SMSSmartReduce

SMSSmartRestore

SMSRestore

SMSReplaceAll

Expression Optimization

The basic approach to optimization of the automatically generated code is to search for the parts of the code that when evaluated yield the same result and substitute them with the new auxiliary variable. In the case of the pattern matching approach only sub-expressions that are syntactically equal are recognized as "common sub-expressions". 
KORELC, Jože, Multi-language and Multi-environment Generation of Nonlinear Finite Element Codes,  Engineering with Computers, 2002, 18(4):312-327
KORELC, Jože. Automatic generation of finite-element code by simultaneous optimization of expressions. Theor. comput. sci.. , 1997, 187:231-248. 
Signatures of the expressions are basis for the heuristic algorithm that can search also for complex relations among the expressions. The relations between expressions which are automatically recognized by the AceGen system are:

In the formulae above, (Subscript[e, i]),(Subscript[a, i]),(Subscript[b, i]),(Subscript[c, i]),(Subscript[d, i]) are arbitrary expressions or sub-expressions, and (Subscript[v, i]) are auxiliary variables. Formula  (Subscript[e, i])≡(Subscript[e, j]) means that the signature of the expression (Subscript[e, i]) is identical to the signature of the expression (Subscript[e, j]). Expressions do not need to be syntactically identical. Formula (Subscript[v, i]):=(Subscript[e, j]) means that a new auxiliary variable (Subscript[v, i ])with value (Subscript[e, j]) is generated, and formula (Subscript[e, i])⇒(Subscript[v, j]) means that expression (Subscript[e, i ])is substituted by auxiliary variable (Subscript[v, j]).

Sub-expressions in the above cases do not need to be syntactically identical, which means that higher relations are recognized also in cases where term rewriting and pattern matching algorithms in Mathematica fail. The disadvantage of the procedure is that the code is generated correctly only with certain probability.

Probability of incorrect simplifications

Let us first consider the two functions (Subscript[f, 1])=(x^3)-(x^2)+1 and (Subscript[f, 2])=Abs[x]+(x^2).

Plot[{(x^3)-(x^2)+1,Abs[x]+(x^2)},{x,-2,2}]

The value of (Subscript[f, 1]) is equal to the value of (Subscript[f, 2]) only for three discrete values of x. If we take random value for x∈[-4,4], then the probability of wrong simplification is for this case is negligible, although the event itself is not impossible. The second example are functions  (Subscript[f, 1])=x and (Subscript[f, 2])=Abs[x].

Plot[{x,Abs[x]},{x,-2,2}]

We can see that, for a random x from interval [-4,4], there is 50% probability to make incorrect simplification and consequently 50% probability that the resulting automatically generated numerical code will not be correct. The possibility of wrong simplifications can be eliminated by replacing the Abs function with a new function (e.g. SMSAbs[x]) that has unique high precision randomly generated number as a signature. Thus at the code derivation phase the SMSAbs function results in random number and at the code generation phase is translated into the correct form (Abs) accordingly to the chosen language. Some useful simplifications might be overlooked by this approach, but the incorrect simplifications are prevented.

A typical situation when probability to make incorrect simplification is always high is when a non-monotonic function and its inverse counterpart together appear as a part of the problem description.

Example: There exist a high probability that trigonometric (Sin, Cos, Tang) or hyperbolic functions (Cosh) combined with their inverse counterpart will be incorrectly simplified. However this is not true for monotonic functions such as Sinh, and Tanh.

GraphicsGrid[{{
Plot[{r,ArcSin[Sin[r]]},{r,-5,5},PlotLabel->ArcSin[Sin[r]]],Plot[{r,ArcTan[Tan[r]]},{r,-5,5},PlotLabel->ArcTan[Tan[r]]],Plot[{r,ArcCos[Cos[r]]},{r,-5,5},PlotLabel->ArcCos[Cos[r]]]},
{
Plot[{r,ArcCosh[Cosh[r]]},{r,-5,5},PlotLabel->ArcCosh[Cosh[r]]],
Plot[{r,ArcSinh[Sinh[r]]},{r,-5,5},PlotLabel->ArcSinh[Sinh[r]]],
Plot[{r,ArcTanh[Tanh[r]]},{r,-5,5},PlotLabel->ArcTanh[Tanh[r]]]
}}
]

Functions with unique signatures

When the result of the evaluation of the function is a randomly generated number then by definition the function has an unique signature. The AceGen package provides a set of "unique signature functions" that can be used as replacements for the most critical functions:

E.g. the SMSSqrt should be used instead of the Mathematica´s Sqrt function in order to reduce the possibility of incorrect simplification and to insure proper differentiation. For all other cases we can wrap critical function with the general unique signature function SMSFreeze[exp,"Code"->True]. Option "Code"->True is necessary in order to prevent incorrect simplifications throughout the session.

Example

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[r$$]];

Here is a unique signature from interval [0,1] assigned to r.

r⊢SMSReal[r$$];
r//SMSEvaluate

This input leads to incorrect simplification of Sqrt[x^2] expression.

ϕ⊨Sqrt[(r^2)];
SMSRestore[x]

This input prevents incorrect simplification.

ϕ⊨SMSSqrt[(r^2)];
SMSRestore[ϕ]

This input leads to incorrect simplification of ArcCos[Cos[r]] expression.

ϕ⊨ArcCos[Cos[r]];
SMSRestore[ϕ]

This is incorrect since the simplification of ArcCos[Cos[r]] is not prevented yet.

ϕ⊨SMSFreeze[ArcCos[Cos[r]],"Code"->True];
SMSRestore[ϕ]

This input represents correct formulation.

ϕ⊨ArcCos[SMSFreeze[Cos[r],"Code"->True]];
SMSRestore[ϕ]

Expression optimization and automatic differentiation

Differentiation (Automatic Differentiation) is an example where the problems involved in simultaneous simplification are obvious. The table below considers the simple example of the two expressions x, y and the differentiation of y with respect to x. L(a) is an arbitrary large expression and (Subscript[v, 1]) is an auxiliary variable. From the computational point of view, simplification A is the most efficient and it gives correct results for both values x and y. However, when used in a further operations, such as differentiation, it obviously leads to wrong results. On the other hand, simplification B has one more assignment and gives correct results also for the differentiation. To achieve maximal efficiency both types of simplification are used in the AceGen system. During the derivation of the formulae type B simplification is performed.

At the end of the session, before the code is generated, the formulae that are stored in global data base are reconsidered to achieve the maximum computational efficiency. At this stage type A simplification is used. All the independent variables (true independent or intermediate auxiliary) have to have an unique signature in order to prevent simplification A (e.g. one can define basic variables with the SMSFreeze function x⫤SMSFreeze[L(a)]).

Types of Auxiliary Variables

AceGen system can generate three types of auxiliary variables: real type, integer type, and logical type auxiliary variables. The way of how the auxiliary variables are labeled is crucial for the interaction between the AceGen and Mathematica. New auxiliary variables are labeled consecutively in the same order as they are created, and these labels remain fixed during the Mathematica session. This enables free manipulation with the expressions returned by the AceGen system. With Mathematica user can perform various algebraic transformations on the optimized expressions independently on AceGen. Although auxiliary variables are named consecutively, they are not always stored in the data base in the same order. Indeed, when two expressions contain a common sub-expression, AceGen immediately replaces the sub-expression with a new auxiliary variable which is stored in the data base in front of the considered expressions. The internal representation of the expressions in the data base can be continuously changed and optimized.
Auxiliary variables have standardized form $V[i, j], where i is an index of auxiliary variable and j is an instance of the i-th auxiliary variable. The new instance of the auxiliary variable is generated whenever specific variable appears on the left hand side of equation. Variables with more that one instance are "multi-valued variables".

The input for Mathematica  that generates new auxiliary variable is as follows:
  lhs  operator  rhs
The structure 'lhs operator rhs' first evaluates right-hand side expression rhs, creates new auxiliary variable, and assigns the new auxiliary variable to be the value of of the left-hand side symbol lhs. From then on, lhs is replaced by a new auxiliary variable whenever it appears. The rhs expression is then stored into the AceGen database.
In AceGen there are four operators ⊨,⊢, ⫤, and ⊣. Operators ⊨ and ⊢ are used for variables that will appear only once on the left-hand side of equation. For variables that will appear more that once on the left-hand side the operators  ⫤ and ⊣ have to be used. These operators are replacement for the simple assignment command in Mathematica (see Mathematica Syntax - AceGen Syntax).

Syntax of AceGen assignment  operators.

If x is a symbol with the value $V[i,j], then after the execution of the expression x⊣exp, x has a new value $V[i,j+1]. The value $V[i,j+1]  is a new instance of the i-th auxiliary variable.

Additionally to the basic operators there are functions that perform reduction in a special way. The SMSFreeze function imposes various restrictions in how expression is evaluated, simplified and differentiated. The SMSSmartReduce function does the optimization in a ‘smart’ way. ‘Smart’ optimization means that only those parts of the expression that are not important for the implementation of non-local operation are replaced by a new auxiliary variables.

The "signature" of the expression is a high precision real number assigned to the auxiliary variable that represents the expression. The signature is obtained by replacing all auxiliary variables in expression by corresponding signatures and then using the standard N function on the result (N[expr, SMSEvaluatePrecision]). The expression that does not yield a real number as the result of  N[expr, SMSEvaluatePrecision] will abort the execution. Thus, any function that yields a real number as the result of numerical evaluation can appear as a part of AceGen expression. However, there is no assurance that the generated code is compiled without errors if there exist no equivalent build in function in compiled language.
Two instances of the same auxiliary variable can appear in the separate branches of ‘If’ construct. At the code generation phase the active branch of the ‘If’ construct remains unknown. Consequently, the signature of the variable defined inside the "If" construct should not be used outside the "If" construct. Similar is valid also for "Do" construct, since we do not know how many times the "Do" loop will be actually executed. The scope of auxiliary variable is a part of the code where the signature associated with the particular instance of the auxiliary variable can be uniquely identified. The problem of how to use variables outside the "If"/"Do" constructs is solved by the introduction of fictive instances. Fictive instance is an instance of the existing auxiliary variable that has no effect on a generated source code. It has unique signature so that incorrect simplifications are prevented. Several examples are given in (SMSIf, SMSDo).
An unique signature is also required for all the basic independent variables for differentiation (see Automatic Differentiation) and is also automatically generated for parts of the expressions that when evaluated yield very high or very low signatures (e.g 10^100, 10^-100, see also Expression Optimization, Signatures of Expressions). The expression optimization procedure can recognize various relations between expressions, however that is no assurance that relations will be always recognized. Thus users input most not rely on expression optimization as such and it must produce the same result with or without expression optimization  (e.g. in "Plain" mode).

Example: real, integer and logical variables

This generates three auxiliary variables: real variable x with value π, integer variable i with value 1, and logical variable l with value True.

<<AceGen`;
SMSInitialize["test", "Language" -> "Fortran", "Mode" -> "Debug"];
SMSModule["Test"];
x ⊢ SMSReal[π];
i ⊢ SMSInteger[1];
l ⊢ SMSLogical[True];
SMSWrite[];

Intermediate variables are labeled consecutively regardless of the type of variable. This displays how internal variables really look like.

{x,i,l}//ToString

This displays the generated FORTRAN code. AceGen translates internal representation of auxiliary variables accordingly to the type of variable as follows:
({{x, :=, $V[1,1], =>, v(1)}, {i, :=, $V[2,1], =>, i2}, {l, :=, $V[3,1], =>, b3}})

FilePrint["test.f"]

Example: multi-valued variables

This generates two instances of the same variable x. The first instance has value π and the second instance has value (π^2).

<<AceGen`;
SMSInitialize["test", "Language" -> "Fortran", "Mode" -> "Debug"];
SMSModule["Test"];
x⫤SMSReal[π];
x⊣(π^2);
SMSWrite[];

This displays how the second instance of x looks like inside the expressions.

x//ToString

This displays the generated FORTRAN code. AceGen translates two instances of the first auxiliary variable into the same FORTRAN variable.
({{x, :=, $V[1,1], =>, v(1)}, {x, :=, $V[1,2], =>, v(1)}})

FilePrint["test.f"]

Auxiliary Variables Functions

SMSR

The SMSR function first evaluates exp. If the result of the evaluation is an elementary expression, then no auxiliary variables are created and the exp is assigned to be the value of symbol. If the result is not elementary expression, then AceGen creates a new auxiliary variable, and assigns the new auxiliary variable to be the value of symbol. From then on, symbol is replaced by the new auxiliary variable whenever it appears. Evaluated expression exp is then stored into the AceGen data base.
Precedence level of ⊨ operator is specified in precedence table below. It has higher precedence than arithmetical operators like +, -,*,/, but lower than postfix operators like // and /.,  /... .  In these cases the parentheses or the standard form of functions have to be used. 
For example, x ⊨ a+b/.a->3 statement will cause an error. There are several alternative ways how to enter this expression correctly.  Some of them are:
x ⊨(a+b/.a->3),
x ⊨ ReplaceAll[a+b,a->3],
SMSR[x,a+b/.a->3],
x=SMSSimplify[a+b/.a->3].

Precedence of AceGen operators.

Numbers are elementary expressions thus a new auxiliary is created only for expression Sin[5].

SMSInitialize["test","Language"->"Fortran"];
SMSModule["sub"];
x⊨1
y⊨Sin[5]

SMSV

The SMSV function first evaluates exp, then AceGen creates a new auxiliary variable, and assigns the new auxiliary variable to be the value of symbol. From then on, symbol is replaced by the new auxiliary variable whenever it appears. Evaluated expression exp is then stored into the AceGen database.
Precedence level of ⊢ operator is specified in Mathematica precedence table and described in SMSR.

The new auxiliary variables are created  for all expressions.

SMSInitialize["test","Language"->"Fortran"];
SMSModule["sub"];
x⊢1
y⊢Sin[5]

SMSM

The primal functionality of this form is to create a variable which will appear more than once on the left-hand side of equation (multi-valued variables). The SMSM function first evaluates exp, creates a new auxiliary variable, and assigns the new auxiliary variable to be the value of symbol. From then on, symbol is replaced by a new auxiliary variable whenever it appears. Evaluated expression exp is then stored into the AceGen database. The new auxiliary variable will not be created if exp matches one of the functions which create by default a new auxiliary variable. Those functions are SMSReal, SMSInteger, SMSLogical, SMSFreeze and SMSFictive. The result of those functions is assigned directly to the symbol.

Precedence level of ⫤ operator is described in SMSR.

SMSS

At the input the value of the symbol has to be a valid multi-valued auxiliary variable (created as a result of functions like SMSS, SMSM, SMSEndIf, SMSEndDo, etc.). At the output there is a new instance of the i-th auxiliary variable with the unique signature. SMSS function can be used in connection with the same auxiliary variable as many times as we wish.

Precedence level of ⊣ operator is described in SMSR.

Successive use of the ⫤ and ⊣ operators will produce several instances of the same variable x.

SMSInitialize["test","Language"->"Fortran","Mode"->"Prototype"];
SMSModule["sub",Real[x$$]];
x⫤1
x⊣x+2
x⊣5 x

SMSExport[x,x$$];
SMSWrite[];

FilePrint["test.f"]

SMSSimplify

The SMSSimplify function first evaluates exp. If the result of the evaluation is an elementary expression, then no auxiliary variables are created and the original exp is the result.  If the result is not an elementary expression, then AceGen creates and returns a new auxiliary variable. SMSSimplify function can appear also as a part of an arbitrary expression.

SMSVariables

Example

<<AceGen``;
SMSInitialize["test"];
SMSModule["Test",Real[a$$]];
a⊢SMSReal[a$$];
M⊨(({{a, (a^2)}, {(a^2), 0}}))

SMSVariables[M]

SMSFreeze, SMSUnFreeze

Imposing restrictions on an optimization procedure.

The SMSFreeze function creates SMSFreezeF data object that represents input expression. The numerical value of resulting SMSFreezeF data object (signature) is calculated by the random perturbation of the numerical value of input expression (unique signature). The SMSFreeze function can impose various additional restrictions on how expressions are evaluated, simplified and differentiated (see options). 
An unique signature is assigned to exp, thus optimization of exp as a whole is prevented, however AceGen can still simplify some parts of the expression. The "Contents"->True option prevents the search for common sub expressions inside the expression.
Original expression is recovered at the end of the session, when the program code is generated and all restrictions are removed. With the "Code"->True option the restrictions remain valid also in the code generation phase. An exception is the option "Dependency" which is always removed and true dependencies are restored before the code generation phase.  Similarly the effects of the SMSFreeze function are not inherited for the result of the differentiation. With the "Differentiation"->True option all restrictions remain valid for the result of the differentiation as well. 
With SMSFreeze[exp,"Dependency"->{{(Subscript[p, 1]),((∂exp)/(∂(Subscript[p, 1])))},{(Subscript[p, 2]),((∂exp)/(∂(Subscript[p, 2])))},...,{(Subscript[p, n]),((∂exp)/(∂(Subscript[p, n])))}}] the true dependencies of exp are ignored and it is assumed that exp depends on auxiliary variables (Subscript[p, 1]),… ,(Subscript[p, n]). Partial derivatives of exp with respect to auxiliary variables (Subscript[p, 1]),… ,(Subscript[p, n]) are taken to be ((∂exp)/(∂(Subscript[p, 1]))),((∂exp)/(∂(Subscript[p, 2]))),…,((∂exp)/(∂(Subscript[p, n]))) (see also SMSDefineDerivative where the definition of the total derivatives of the variables is described).
SMSFreeze[exp,"Verbatim"] stops all automatic simplification procedures.
SMSFreeze function is automatically threaded over the lists that appear as a part of exp.

Basic Examples

<<AceGen`;
SMSInitialize["test"];
SMSModule["sub",Real[x$$]];
x⊢SMSReal[x$$];

SMSFreeze creates data object (SMSFreezeF) that contains original expression Sin[x]. New auxiliary variable are not yet introduced!

SMSFreeze[Sin[x]]

However, its numerical evaluation yields an unique signature obtained by the random perturbation of the signature of original expression.

{Sin[x],SMSFreeze[Sin[x]]}//SMSEvaluate

New auxiliary variable that represents original expression can be introduced by

xf⊢SMSFreeze[Sin[x]];
xf

or by

SMSFreeze[xf,Sin[x]];
xf

Options

Options of the SMSFreeze functions are applied on matrix M=(({{x, 2 x, cos(x)}, {2 x, 2, 2 x}, {-cos(x), 0, (1/2)}}));

<<AceGen`;
SMSInitialize["test"];
SMSModule["sub",Real[x$$]];
x⊢SMSReal[x$$];
M=(({{x, 2 x, Cos[x]}, {2x, 2, 2x}, {-Cos[x], 0, 1/2}}));

The random signatures of elements of the original matrix are

M//SMSEvaluate//MatrixForm

The SMSFreeze function applied on the whole matrix will create a new auxiliary variable for each element of the matrix regardless on the structure of the matrix.

Mf⊢SMSFreeze[M];
Mf//MatrixForm

The random signatures of elements of the original matrix are obtained by perturbation of the random signatures of the elements of original matrix.

Mf//SMSEvaluate//MatrixForm

Here the new auxiliary variables with random signatures are generated only for the elements of the matrix for which NumberQ[x] yields true. 6 new auxiliary variables are generated.

SMSFreeze[Mf,M,"IgnoreNumbers"->True];
Mf//MatrixForm
Mf//SMSEvaluate//MatrixForm

Here the new auxiliary variables with random signatures are generated for all parts of the matrix that have random signatures (numbers do not have random signatures!) in a way that the number of new auxiliary variables is minimum. Only 3 new auxiliary variables are generated in this case. The properties of the matrix such as symmetry, antisymmetry etc. are preserved when detected. Note that the symmetry of the matrix is detected accordingly to the signature of the elements of the matrix, thus the detection of the symmetry is not absolutely guaranteed. When the symmetry or any other property of the matrix is essential for the correctness of derivation the property has to be enforced explicitly as presented below.

SMSFreeze[Mf,M,"KeepStructure"->True];
Mf//MatrixForm
Mf//SMSEvaluate//MatrixForm

Here the new auxiliary variables with random signatures are generated only for the elements of the matrix for which NumberQ[x] yields true. Additionally, symmetry of the resulting matrix is enforced.

SMSFreeze[Mf,M,"Symmetric"->True,"IgnoreNumbers"->True];
Mf//MatrixForm
Mf//SMSEvaluate//MatrixForm

Here all the auxiliary variables in original expression are replaced by new auxiliary variables with random signatures.

SMSFreeze[Mf,M,"Variables"->True];
Mf//MatrixForm
Mf//SMSEvaluate//MatrixForm

Option dependency

<<AceGen`;
SMSInitialize["test"];
SMSModule["sub",Real[p1$$,p2$$]];
{p1,p2}⊢SMSReal[{p1$$,p2$$}];
{e1,e2}⊨{ p1 p2,Sin[p1]Cos[p2]};

Here all partial derivatives of expression e1 are set to 0 except:
((∂e1)/(∂p1))=5.
The derivatives {((D Log(e1))/(D (Subscript[p, 1]))),((D Log(e1))/(D (Subscript[p, 2])))} are then evaluated assuming explicitly defined partial derivatives.

f1⊢SMSFreeze[e1,"Dependency"->{p1,5}];
SMSD[Log[f1],{p1,p2}]

Here all partial derivatives of expression e1 are set to 0 except:
((∂e1)/(∂p1))=5, ((∂e1)/(∂p2))=10.
The derivatives {((D Log(e1))/(D (Subscript[p, 1]))),((D Log(e1))/(D (Subscript[p, 2])))} are then evaluated assuming explicitly defined partial derivatives.

f1⊢SMSFreeze[e1,"Dependency"->{{p1,5},{p2,10}}];
SMSD[Log[f1],{p1,p2}]

Here all partial derivatives of expressions e1 and e2 are set to 0 except:
((∂e1)/(∂p1))=5, ((∂e1)/(∂p2))=10,
((∂e2)/(∂p1))=15, ((∂e2)/(∂p2))=20.
The derivatives (({{((D Log(e1))/(D (Subscript[p, 1]))), ((D Log(e1))/(D (Subscript[p, 2])))}, {((D Log(e2))/(D (Subscript[p, 1]))), ((D Log(e2))/(D (Subscript[p, 2])))}})) are then evaluated assuming explicitly defined gradients of expressions.

{f1,f2}⊢SMSFreeze[{e1,e2},"Dependency"->
{
{{p1,5},{p2,10}}    (*∇e1*)
,{{p1,15},{p2,20}}   (*∇e2*)
}];
SMSD[{Log[f1],Log[f2]},{p1,p2}]

The above result can be also obtained by defining a set of unknowns (Subscript[p, i]) and the Jacobian matrix (Subscript[J, i,j])=((∂(Subscript[e, i]))/(∂(Subscript[p, j]))).

{f1,f2}⊢SMSFreeze[{e1,e2},"Dependency"->
{{p1,p2}, (*(Subscript[p, i])*)
{{5,10},{15,20}}  (*Jacobian ((∂(Subscript[e, i]))/(∂(Subscript[p, j])))*)
}];
SMSD[{Log[f1],Log[f2]},{p1,p2}]

Troubleshooting

The use of SMSFreeze[exp,options] form of the SMSFreeze function with options Ignore, IgnoreNumbers, Symmetric, Variables and KeepStructure may lead to unexpected results! Please consider to use SMSFreeze[symbol,exp,options] form instead.

<<AceGen`;
SMSInitialize["test"];
SMSModule["sub",Real[x$$]];
x⊢SMSReal[x$$];

Here the option "IgnoreNumbers" is not accounted for in the final result.

vf⊢SMSFreeze[{Sin[x],0},"IgnoreNumbers"->True];
vf

Correct result is obtained if the SMSFreeze[symbol,exp,options] form is used.

SMSFreeze[vf,{Sin[x],0},"IgnoreNumbers"->True];
vf

SMSFictive

A fictive variable is used as a temporary variable to perform various algebraic operations symbolically on AceGen generated expression (e.g. integration, finding limits, solving algebraic equations symbolically, ...). For example, the integration variable x in a symbolically evaluated definite integral (∫_a^b)f(x)dx can be introduced as a fictive variable since it will not appear as a part of the result of integration.
The fictive variable is an auxiliary variable but it does not have assigned value, thus it must not appear anywhere in a final source code. The fictive variable that appears as a part of the final code is replaced by random value and a warning message appears.

See also:  Auxiliary Variables, Local and Non-local Operations.

Example

Here the pure fictive auxiliary variable is used for x in order to evaluate expression f(n)=(∑_(n=1)^m)((∂g(x))/(∂x))(Subscript[|, x=0]), where g(x) is arbitrary expression (can be large expression involving If and Do structures). Not that 0 cannot be assigned to x before the differentiation.

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["sub",Real[f$$,a$$,b$$],Integer[m$$]];
f⫤0;
SMSDo[n,1,SMSInteger[m$$],1,f];
x⊢SMSFictive[];
g⊨Sin[(x/n)]+Cos[(x/n)];
f⊣f+SMSReplaceAll[ SMSD[g,x],x->0];
SMSEndDo[f];
SMSExport[f,f$$];

SMSWrite[];

FilePrint["test.c"]

Local and Non-local Operations

General Description

Many high level operations in computer algebra can only be implemented when the whole expression to which they are applied is given in an explicit form. Integration and factorization are examples for such ‘non-local’ operations. On the other hand, some operations such as differentiation can be performed ‘locally’ without considering the entire expression. In general, we can divide algebraic computations into two groups:
Non-local operations have the following characteristics:
=>	symbolic integration, factorization, nonlinear equations,
=>	the entire expression has to be considered to get a solution,
=>	all the relevant variables have to be explicitly “visible”.
Local operations have the following characteristics:
=>	differentiation, evaluation, linear system of equations,
=>	operation can be performed on parts of the expression,
=>	relevant variables can be part of already optimized code.

Symbolic integration is rarely used in numerical analysis. It is possible only in limited cases.  Additionally, the integration is an operation of  ‘non-local’ type. Nevertheless, we can still use all the built-in capabilities of Mathematica and then optimize the results. 
Non-local operations are performed by corresponding Mathematica commands (Solve, Integrate, ...). The results of non-local operations is an general a regular Mathematica expression. However only those Mathematica expressions that are composed solely from elementary functions (+,-./,sin,Cos,...) that have C/FORTRAN/MATLAB equivalent are acceptable for AceGen automatic code generator. Thus one can define that the function is Integrable in a Mathematica/AceGen sense when the use of Mathematica command Integrate results in an expression that is solely composed from elementary functions (+,-./,sin,Cos,...) that have C/FORTRAN/MATLAB equivalent.

For 'non-local' operations, such as integration, the AceGen system provides a set of functions which perform optimization in a 'smart' way. 'Smart' optimization means that only those parts of the expression that are not important for the implementation of the 'non-local' operation are replaced by new auxiliary variables. Let us consider expression f which depends on variables x, y, and z.

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica"];
SMSModule["Test",Real[x$$,y$$,z$$]];
{x,y,z}⊢{SMSReal[x$$],SMSReal[y$$],SMSReal[z$$]};

f=(x^2)+2 x y+(y^2)+2 x y+ 2 y z+(z^2)

Since integration of f  with respect to x is to be performed, we perform 'smart' optimization of f by keeping the integration variable x unchanged which leads to the optimized expression fx. Additionally Normal converts expr to a normal expression, from a variety of AceGen special forms.

fx=SMSSmartReduce[f,x,Collect[#,x]&]//Normal

The following vector of auxiliary variables is created.

SMSShowVector[]

fint=∫fx\[DifferentialD]x

Note that the function Sin[fx] is not integrable in Mathematica/AceGen sens although the command Integrate produces an expression. It can become integrable if the user adds the definition of FresnelS and FresnelC as the user defined functions (see SMSCall).

∫Sin[fx]\[DifferentialD]x

After the integration, the resulting expression fint is used to obtain another expression fr. fr is identical to fint, however with an exposed variable y. New format is obtained by 'smart' restoring the expression fint with respect to variable y.

fr=SMSSmartRestore[fint,y,Collect[#,y]&]//Normal

At the end of the Mathematica session, the global vector of formulae contains the following auxiliary variables:

SMSShowVector[];

SMSSmartReduce

The default value for func is identity operator #&. Recommended value is Collect[#,v1|v2|...]&. The function func should perform only correctness preserving transformations, so that the value of expression exp remains the same.

SMSSmartRestore

At the output, all variables (Subscript[v, 1])|(Subscript[v, 2])|... become fully visible. The result can be used to perform non-local operations. The default values for func is identity operator #&. Recommended value is Collect[#,v1|v2|...]&. The function func should perform only correctness preserving transformations, so that the values of expression remain the same. 
The list of rules evaluation_rules can alter the value of exp. It can be used for a symbolic evaluation of expressions (see SMSReplaceAll).
The difference between the SMSSmartReduce function and the SMSSmartRestore function is that SMSSmartRestore function searches the entire database of formulae for the expressions which depend on the given list of auxiliary variables (Subscript[v, 1]),(Subscript[v, 2]),.... while SMSSmartReduce looks only at parts of the current expression.
The result of the SMSSmartRestore function is a single symbolic expression. If any of auxiliary variable involved has several definitions (multi-valued auxiliary variables), then the result can not be uniquely defined and the SMSSmartRestore function can not be used.

SMSRestore

At the output, all variables (Subscript[v, 1])|(Subscript[v, 2])|... become fully visible, the same as in the case of SMSSmartRestore function. However, while SMSSmartRestore simplifies the result by introducing new auxiliary variables, SMSRestore returns original expression. 
If any of auxiliary variable involved has several definitions (multi-valued auxiliary variables), then the result can not be uniquely defined and the SMSRestore function can not be used.

SMSReplaceAll

Symbolic evaluation means evaluation of expressions with the symbolic or numerical value for a particular parameter. The evaluation can be efficiently performed with the AceGen function SMSReplaceAll.

At the output the SMSReplaceAll function gives exp(Subscript[|, (Subscript[v, 1])=(Subscript[new, 1]),(Subscript[v, 2])=(Subscript[new, 2]),…]). The SMSReplaceAll function searches entire database for the auxiliary variables that influence evaluation of the given expression exp and at the same time depend on any of the auxiliary variables (Subscript[v, i]). The current program structure is then enhanced by the new auxiliary variables. Auxiliary variables involved can have several definitions (multi-valued auxiliary variables).

It is users responsibility that the new expressions are correct and consistent with the existing program structure. Each time the AceGen commands are used, the system tries to modified the entire subroutine in order to obtain optimal solution. As the result of this procedures some variables can be redefined or even deleted. Several situations when the use of SMSReplaceAll can lead to incorrect results are presented on examples.
However, even when all seems correctly the SMSReplaceAll can abort execution because it failed to make proper program structure. Please reconsider to perform replacements by evaluating expressions with the new values directly when SMSReplaceAll fails.

Example 1: Taylor series expansion

A typical example is a Taylor series expansion,

F(x)=F(x)(Subscript[|, x=(Subscript[x, 0])])+((∂F(x))/(∂x))(Subscript[|, x=(Subscript[x, 0])]) (x-(Subscript[x, 0])) ,

where the derivatives of F have to be evaluated at the specific point with respect to variable x. Since the optimized derivatives depend on x implicitly, simple replacement rules that are built-in Mathematica can not be applied.

This generates FORTRAN code that returns coefficients F(x)(Subscript[|, x=(Subscript[x, 0])]) and ((∂F(x))/(∂x))(Subscript[|, x=(Subscript[x, 0])]) of the Taylor expansion of the function 3 (x^2)+Sin[(x^2)]-Log[(x^2)-1].

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["Test",Real[x0$$,f0$$,fx0$$]];
x0⊢SMSReal[x0$$];
x⊨SMSFictive[];
f⊨3 (x^2)+Sin[(x^2)]-Log[(x^2)-1];
f0⊨SMSReplaceAll[f,x->x0];
fx⊨SMSD[f,x];
fx0⊨SMSReplaceAll[fx,x->x0];
SMSExport[{f0,fx0},{f0$$,fx0$$}];
SMSWrite[];
FilePrint["test.f"];

Example 2: the variable that should be replaced does not exist

The ⊨ command creates variables accordingly to the set of rules. Here the expression y⊨-x did not create a new variable y resulting in wrong replacement.

<<AceGen`;
SMSInitialize["test"];
SMSModule["sub",Real[x$$]];
x⊢SMSReal[x$$];
y⊨- x;
z⊨Sin[y];
SMSReplaceAll[z,y->π/3]

The ⊢ command always creates new variable and leads to the correct results.

<<AceGen`;
SMSInitialize["test"];
SMSModule["sub",Real[x$$]];
x⊢SMSReal[x$$];
y⊢- x;
z⊨Sin[y];
SMSReplaceAll[z,y->π/3]

Example 3: repeated use of SMSReplaceAll

Repeated use of SMSReplaceAll can produce large intermediate codes and should be avoided if possible.

<<AceGen`;
SMSInitialize["test"];
SMSModule["sub",Real[x$$]];
x⊢SMSReal[x$$];
y⊨Sin[x];
z⫤Cos[x];
y0⊨SMSReplaceAll[y,x->0];
z0⊨SMSReplaceAll[z,x->0];

Better formulation.

<<AceGen`;
SMSInitialize["test"];
SMSModule["sub",Real[x$$]];
x⊢SMSReal[x$$];
y⊨Sin[x];
z⫤Cos[x];
{y0,z0}⊨SMSReplaceAll[{y,z},x->0];

Program Flow Control

Contents

General Description

Conditionals

SMSIf

SMSElse

SMSEndIf

SMSSwitch

SMSWhich

Loops

SMSDo

SMSEndDo

SMSReturn

SMSBreak

SMSContinue

General Description

AceGen can automatically generate conditionals (SMSIf, SMSSwitch and SMSWhich constructs) and loops (SMSDo construct). The program structure specified by the conditionals and loops is created simultaneously during the AceGen session and it will appear as a part of automatically generated code in a specified language. All other conditional and loop structures have to be manually replaced by the equivalent forms consisting only of If and Do statements. It is important to notice that only the replaced conditionals and loops produce corresponding conditionals and loops in the generated code and are evaluated when the generated program is executed. The conditionals and loops that are left unchanged are evaluated directly in Mathematica during the AceGen session. Additionally, we can include parts of the final source code verbatim (SMSVerbatim statement).
The control structures in Mathematica have to be completely located inside one notebook cell (e.g. loop cannot start in once cell and end in another cell). Thus,  the following input is in Mathematica incorrect

Do[Print[i]

,{i,1,5}]

AceGen extends the functionality of Mathematica with the cross-cell form of If and Do control structures. Previous example can be written by using cross-cell form Do construct as follows

SMSDo[i,1,5]

SMSPrintMessage[i];

SMSEndDo[]

and using in-cell form as

SMSDo[Print[i],{i,1,5}]

Conditionals

SMSIf, SMSElse, SMSEndIf

The "in-cell" form of the SMSIf construct is a direct equivalent of the standard If statement. The condition of "If" construct is a logical statement. The in-cell form of the SMSIf command returns multi-valued auxiliary variable with random signature that represents both options. If t or f evaluates to Null then SMSIf returns Null. If t and f  evaluate to vectors of the same length then SMSIf returns a corresponding vector of multi-valued auxiliary variables.

Warning: The "==" operator has to be used for comparing expressions. In this case the actual comparison will be performed at the run time of the generated code. The "===" operator checks exact syntactical correspondence between expressions and is executed in Mathematica at the code derivation time and not at the code run time.

Formulae entered in between SMSIf and SMSElse will be evaluated if the logical expression condition evaluates to True. Formulae entered in between SMSElse and SMSEndIf will be evaluated if the logical expression evaluates to False. The SMSElse statement is not obligatory. New instances and new signatures are assigned to the out_var auxiliary variables. The out_var parameter can be a symbol or a list of symbols. The values of the symbols have to be multi-valued auxiliary variables. The cross-cell form of the SMSIf command returns the logical auxiliary variable where the condition is stored. The SMSElse command also returns the logical auxiliary variable where the condition is stored. The SMSEndIf command returns new instances of the out_var auxiliary variables or empty list. New instances have to be created for all auxiliary variables defined inside the "If" construct that are used also outside the "If" construct. 
Interaction between hybrid symbolic-automatic differentiation and an arbitrary program structure can result in redundant code. The user is strongly encouraged to keep "If" constructs as simple as possible to avoid redundant dependencies.

Example 1:  Generic example - in-cell form

Generation of the Fortran subroutine which evaluates the following function
 f(x)={({{x<=0, (x^2)}, {x>0, Sin[x]}}) .

This initializes the AceGen system and starts the description of the "test" subroutine.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];
f⊨SMSIf[x<=0,(x^2),Sin[x]];
SMSExport[f,f$$];
SMSWrite["test"];
FilePrint["test.f"]

Example 2:  Generic example - cross-cell form

Generation of the Fortran subroutine which evaluates the following function
 f(x)={({{x<=0, (x^2)}, {x>0, Sin[x]}}) .

This initializes the AceGen system and starts the description of the "test" subroutine.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];

Description of the cross-cell "If" construct.

SMSIf[x<=0]

f⫤(x^2);

SMSElse[]

f⊣Sin[x];

SMSEndIf[f]

SMSExport[f,f$$];
SMSWrite["test"];

This displays the contents of the generated file.

FilePrint["test.f"]

Example 3:  Generic example - using ternary operator

Generation of the Fortran subroutine which evaluates the following function
 f(x)={({{x<=0, (x^2)}, {x>0, Sin[x]}}) .

This initializes the AceGen system and starts the description of the "test" subroutine.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];
f⊨SMSIf[x<=0,(x^2),Sin[x],"Inline"->True];
SMSExport[f,f$$];
SMSWrite["test"];
FilePrint["test.f"]

Example 4:  Incorrect logical expression

The expression  x<=0 && i==="0"  in this example is evaluated already in Mathematica because the === operator always yields True or False. The correct form of the logical condition would be x<=0 && i=="0".

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,f$$],Integer[i$$]];
x⊢SMSReal[x$$];
f⊨SMSIf[x<=0 && i==="0",(x^2),Sin[x]];
SMSExport[f,f$$];
SMSWrite[];

FilePrint["test.f"]

Example 5:  Incorrect use of ternary operator

Generation of the C subroutine which evaluates the following function
 f(x)={({{x<=0, (x^2)}, {x>0, y=Cos[x];y+(y^2)}}) .

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];

Compound expression y⊨Cos[x];y+(y^2) will be incorrectly interpreted. Cos[x] will be evaluated also when x<=0 as seen from the generated code.

f⊨SMSIf[x<=0,(x^2),y⊨Cos[x];y+(y^2),"Inline"->True];
SMSExport[f,f$$];
SMSWrite["test"];
FilePrint["test.c"]

Example 6:  Redundant code

Generation of the C subroutine which evaluates derivative of f with respect to x.
f(x)={({{x≤0, (x^2)}, {x>0, Sin[x]}}) .
The first input given below leads to the construction of redundant code. The second differentiation involves f that is also defined in the first "if" construct, so the possibility that the first "if" was executed and that somehow effects the second one has to be considered. This redundant dependency is avoided in the second input by the use of temporary variable tmp and leading to much shorter code.

Input that results in inefficient code.

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,f$$,d$$]];
x⊢SMSReal[x$$];
SMSIf[x<=0];
f⫤(x^2);
d⫤SMSD[f,x];
SMSEndIf[f,d];
SMSIf[x>0];
f⊣Sin[x];
d⊣SMSD[f,x];
SMSEndIf[f,d];
SMSExport[{f,d},{f$$,d$$}];
SMSWrite[]

FilePrint["test.c"]

Corrected input.

SMSInitialize["test","Language"->"C","Mode"->"Optimal"];
SMSModule["test",Real[x$$,f$$,d$$]];
x⊢SMSReal[x$$];
SMSIf[x<=0];
    f⫤(x^2);
    d⫤SMSD[f,x];
SMSEndIf[f,d];
SMSIf[x>0];
     tmp=Sin[x];
     f⊣tmp;
     d⊣SMSD[tmp,x];
SMSEndIf[f,d];
SMSExport[{f,d},{f$$,d$$}];
SMSWrite[]

FilePrint["test.c"]

Example 7:  Variables out of scope 1

Generation of the Fortran subroutine which evaluates the following function
f(x)={({{x<=0, (x^2)}, {x>0, Sin[x]}}) .

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];
SMSIf[x<=0];
f⫤(x^2);
SMSElse[];
f⊣Sin[x];
SMSEndIf[];

Here symbol f appears outside the "If" construct.  Since f  is not specified in the SMSEndIf statement, we get "variable out of scope" error message.

SMSExport[f,f$$];

Example 8:  Variables out of scope 2

This is an example where a variable defined in one branch of "If" construct is used in another branch of "If" construct resulting in "Out of scope " message.

Input that results in "Out of scope" message.

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica","Mode"->"Debug"];
SMSModule["test",Integer[NN$$]];
NN⫤SMSInteger[nmax$$];
SMSIf[NN<10];
	NN⊣20;

last definition of nmax is here

SMSElse[];

nmax from the last definition can`t be used here because it is out of the scope (it is a part of another if branch)

SMSIf[NN<5]; 
		NN⊣0;
	SMSEndIf[];
SMSEndIf[NN];
SMSExport[NN,r$$];
SMSWrite[];

An additional variable NNaux is introduced at the point that is within the scope of the position where variable NN is used.

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica","Mode"->"Debug"];
SMSModule["test",Integer[NN$$]];
NN⫤SMSInteger[nmax$$];
NNaux⊢NN;
SMSIf[NN<10];
	NN⊣20;
SMSElse[];
	SMSIf[NNaux<5]; 
		NN⊣0;
	SMSEndIf[];
SMSEndIf[NN];
SMSExport[NN,r$$];
SMSWrite[];

SMSSwitch

The SMSSwitch construct is a direct equivalent of the standard Switch statement. The expr and the (Subscript[form, i]) are integer type expressions. The SMSSwitch command returns multi-valued auxiliary variable with random signature that represents all options. If all (Subscript[value, i]) evaluate to Null then SMSSwitch returns Null. If all (Subscript[value, i]) evaluate to vectors of the same length then SMSSwitch returns a corresponding vector of multi-valued auxiliary variables.

Warning: If none of the (Subscript[form, i]) match expr, the SMSSwitch returns arbitrary value.

SMSWhich

The SMSWhich construct is a direct equivalent of the standard Which statement. The (Subscript[test, i]) are logical expressions. The SMSWhich command returns multi-valued auxiliary variable with random signature that represents all options. If all (Subscript[value, i]) evaluate to Null then SMSWhich returns Null. If all (Subscript[value, i]) evaluate to vectors of the same length then SMSWhich returns a corresponding vector of multi-valued auxiliary variables.

Warning: If none of the (Subscript[test, i]) evaluates to True, the SMSWhich returns arbitrary value.

Warning: The "==" operator has to be used for comparing expressions. In this case the actual comparison will be performed at the run time of the generated code. The "===" operator checks exact syntactical correspondence between expressions and is executed in Mathematica at the code derivation time and not at the code run time.

Loops

SMSDo, SMSEndDo

Optimization procedures (see Expression Optimization) require that a new instance with the random signature have to be created for:
=>	all auxiliary variables that are imported into the loop and have values changed inside the loop (in_var and in_out _var),
=>	all variables that are defined inside the loop and used outside the loop (out_var and in_out _var).
New instances with random signature are assigned to the in_var and in_out _var variables at the start of the loop and to the out_var and in_out _var auxiliary variables at the end of the loop. The "in-cell" form of SMSDo command returns new instances of the in_out _var auxiliary variables or empty list. The "cross-cell" form of SMSDo command returns new instances of the in_var auxiliary variables or empty list. The SMSEndDo command returns new instances of the out_var variables or empty list.
The  in_var, out_var and in_out _var parameters can be a symbol or a list of symbols. The values of the symbols have to be multi-valued auxiliary variables. The iteration variable of the "Do" loop is an integer type auxiliary variable (i).

Example 1:  Generic example (in-cell)

Generation of the Fortran subroutine which evaluates the following sum f(x) = 1+(∑_(i=1)^n)(x^i).

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,f$$],Integer[n$$]];
x⊢SMSReal[x$$];n⊢SMSInteger[n$$];
f⫤1;
SMSDo[
   f⊣f+(x^i);
,{i,1,n,1,f}];
SMSExport[f,f$$];
SMSWrite["test"];
FilePrint["test.f"]

Example 2:  Generic example (cross-cell)

Generation of the Fortran subroutine which evaluates the following sum f(x) = 1+(∑_(i=1)^n)(x^i).

This initializes the AceGen system and starts the description of the "test" subroutine.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,f$$],Integer[n$$]];
x⊢SMSReal[x$$];n⊢SMSInteger[n$$];

Description of the loop.

f⫤1;
SMSDo[i,1,n,1,f];
	f⊣f+(x^i);
SMSEndDo[f];

This assigns the result to the output parameter of the subroutine and generates file "test.for".

SMSExport[f,f$$];
SMSWrite["test"];

This displays the contents of the generated file.

FilePrint["test.f"]

Example 3:  Incorrect and correct use of "Do" construct

Generation of Fortran subroutine which evaluates the n-th term of the following series (Subscript[S, 0])=0 , (Subscript[S, n]) = Cos (Subscript[S, n-1]).

Incorrect formulation

Since the signature of the S variable is not random at the beginning of the loop, AceGen makes wrong simplification and the resulting code is incorrect.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran","Mode"->"Optimal"];
SMSModule["test",Real[S$$],Integer[n$$]];
n⊢SMSInteger[n$$];
S⫤0;
SMSDo[i,1,n,1];
	S⊣Cos[S];
SMSEndDo[S];
SMSExport[S,S$$];
SMSWrite["test"];

FilePrint["test.f"]

Correct formulation

Assigning a random signature the S auxiliary variable prevents wrong simplification and leads to the correct code.

SMSInitialize["test","Language"->"Fortran","Mode"->"Optimal"];
SMSModule["test",Real[S$$],Integer[n$$]];
n⊢SMSInteger[n$$];
S⫤0;
SMSDo[i,1,n,1,S];
	S⊣Cos[S];
SMSEndDo[S];
SMSExport[S,S$$];
SMSWrite["test"];
FilePrint["test.f"]

The "in-cell" form by default assignes the random signature to S at the beginning and at the end of the loop, thus gives correct result.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[S$$],Integer[n$$]];
n⊢SMSInteger[n$$];
S⫤0;
SMSDo[
   S⊣Cos[S];
,{i,1,n,1,S}];
SMSExport[S,S$$];
SMSWrite["test"];
FilePrint["test.f"]

Example 4:  How to use variables defined inside the loop outside the loop?

Only the multi-valued variables (introduced by the ⫤ or ⊣ command) can be used outside the loop. The use of the single-valued variables (introduced by the  ⊨ or ⊢ command)  that are defined within loop outside the loop will result in Variables out of scope error.

Here the variable X is defined within the loop and used outside the loop.

Incorrect formulation

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[S$$],Integer[n$$]];
n⊢SMSInteger[n$$];
S⫤0;
SMSDo[
X⫤Cos[S];
S⊣S+X;
,{i,1,n,1,{S}}
];
Y⊨(X^2);

Correct formulation for "in-cell" form

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[S$$],Integer[n$$]];
n⊢SMSInteger[n$$];
S⫤0;
SMSDo[
X⫤Cos[S];
S⊣S+X;
,{i,1,n,1,{S},{S,X}}
];
Y⊨(X^2);

Correct formulation for "cross-cell" form

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[S$$],Integer[n$$]];
n⊢SMSInteger[n$$];
S⫤0;
SMSDo[i,1,n,1,S];
	X⫤Cos[S];
	S⊣S+X;
SMSEndDo[S,X];
Y⊨(X^2);

SMSReturn, SMSBreak, SMSContinue

Symbolic-Numeric Interface

Contents

General Description

Input Parameters

SMSReal

SMSInteger

SMSLogical

SMSRealList

Output Parameters

SMSExport

General Description

A general way of how to pass data from the main program into the automatically generated routine and how to get the results back to the main program is through external variables. External variables are used to establish the interface between the numerical environment and the automatically generated code.
External variables appear in a list of input/output parameters of the declaration of the subroutine, as a part of expression, and when the values are assigned to the output parameters of the subroutine.

Use of external variables.

The form of the external variables is prescribed and is characterized by the $ signs at the end of its name. The standard AceGen form is automatically transformed into the chosen language when the code is generated. The standard formats for external variables when they appear as part of subroutine declaration and their transformation into FORTRAN and C language declarations are as follows:

External variables in a subroutine declaration.

Arrays can have arbitrary number of dimensions. The dimension can be an integer constant, an integer external variable or a "*" character constant. The "*" character stands for the unknown dimension.
The standard format for external variables when they appear as part of expression and their transformation into FORTRAN and C language formats is then:

External variables as a part of expression.

A characteristic high precision real type number called "signature" is assigned to each external variable. This characteristic real number is then used throughout the AceGen session for the evaluation of the expressions. If the expression contains parts which cannot be evaluated with the given signatures of external variables, then AceGen reports an error and aborts the execution.
External variable is represented by the data object with the head SMSExternalF. This data object represents external expressions together with the information regarding signature and the type of variable.

Input Parameters

SMSReal

The SMSReal function does not create a new auxiliary variable. If an auxiliary variable is required, then we have to use one of the functions that introduces a new auxiliary variable (e.g. r⊢SMSReal[r$$]). The exte is, for the algebraic operations like differentiation, taken as independent on any auxiliary variable that might appear as part of exte. The parts of the exte which have proper form for the external variables are at the end of the session translated into FORTRAN or C format.

By default an unique signature (random high precision real number) is assigned to the SMSExternalF object. If the numerical evaluation of exte (obtained by N[exte,SMSEvaluatePrecision]) leads to the real type number then the default signature is calculated by it`s perturbation, else the default signature is taken as a real type random number form interval [0,1]. In some cases user has to provide it`s own signature in order to prevent situations where wrong simplification of expressions might occur (for mode details see Signatures of Expressions).

SMSInteger

The SMSInteger function does not create a new auxiliary variable. If an auxiliary variable is required, then we have to use one of the functions that introduces a new auxiliary variable (e.g. i⊢SMSInteger[i$$]). In order to avoid wrong simplifications an unique real type signature is assigned to the integer type variables.

SMSLogical

Logical expressions are ignored during the simultaneous simplification procedure. The SMSLogical function does not create a new auxiliary variable. If an auxiliary variable is required, then we have to use one of the functions that introduces a new auxiliary variable (e.g. b⊢SMSLogical[b$$]).

SMSRealList

The SMSRealList command remembers the number of array elements allocated. When called second time for the same array the consecutive elements of the array are taken starting from the last element from the first call. The array element identifications eID  is a string that represents the specific element of the array and can be used later on (through all the AceGen session) to retrieve the element of the array that was originally assigned to eID.
The parameter array is a pure function that returns the i-th element of the array. For the same array it should be always identical. The definitions x$$[#]& and x$$[#+1]&  are considered as different arrays.

Example

<<AceGen`
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[a$$[10],b$$[10],c$$[100]],Integer[L$$,i$$]];
SMSRealList[{"a1","a2"},a$$[#]&]

SMSRealList[{"a3","a4"},a$$[#]&]

SMSRealList["a3"]

SMSRealList[{"b1","b2"},b$$[#]&,"Length"->5,"Index"->2]

SMSRealList[{"b1","b2"},b$$[#]&,"Index"->3]

SMSRealList[{"b3","b4"},b$$[#]&,"Length"->20,"Index"->4]

The arguments "Length" is left unevaluated by the use of Hold function in order to be able to retrieve the same array elements through all the AceGen session. The actual auxiliary variable assigned to L  can be different in different subroutines!!

{L,i}⊨SMSInteger[{L$$,i$$}];
SMSRealList[{"c1","c2"},c$$[#]&,"Length"->Hold[2 L],"Index"->i+1]

SMSRealList[Array["β",2],c$$[#]&,"Length"->Hold[ L],"Index"->i]

TableForm[{SMSRealList["β"[_],"ID"],SMSRealList["β"[_]],SMSRealList["β"[_],"Plain"],SMSRealList["β"[_],"Export"]},TableHeadings->{{"ID","AceGen","Plain","Export"},None}]

SMSRealList["β"[_],"Length"]

Output Parameters

SMSExport

The expressions that are exported can be any regular expressions. The external variables have to be regular AceGen external variables. At the end of the session, the external variables are translated into the FORTRAN or C format.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,y$$,a$$[2],r$$[2,2]]];
x⊨SMSReal[x$$];
SMSExport[(x^2),y$$];
(* three equivalent forms how to export list of two values*)
SMSExport[{1,2},a$$];
SMSExport[{3,4},{a$$[1],a$$[2]}];
SMSExport[{5,6},Table[a$$[i],{i,1,2}]];
(* two equivalent forms how to export two-dimensional array*)
SMSExport[Table[Sin[i j],{i,2},{j,2}],r$$];
SMSExport[Table[Sin[i j],{i,2},{j,2}],Table[r$$[i, j],{i,2},{j,2}]];
SMSWrite["test"];

FilePrint["test.f"]

Automatic Differentiation

Contents

Theory of Automatic Differentiation

SMSD

Differentiation: Mathematica syntax versus AceGen syntax

Mathematica

AceGen

Automatic Differentiation Examples

Example 1: Simple C subroutine

Example 2: Differentiation of complex program structure

Example 3: Differentiation with respect to symmetric matrix

Example 4: Differentiation with respect to sparse matrix

Example 5: Differentiation with respect to intermediate variables

Characteristic Formulae

Example 1: characteristic formulae - one subset

Example 2: characteristic formulae - two subsets

Exceptions in Differentiation

SMSDefineDerivative

Exception Type A: Generic Example

Exception Type C: Implicit dependencies

Exception Type D: Alternative definition of partial derivatives

Limitations: Incorrect structure of the program

Theory of Automatic Differentiation

Differentiation is operation that plays crucial role in the development of new numerical procedures. We can easily recognize some areas of numerical analysis where the problem of analytical differentiation is emphasized:
=>	evaluation of consistent tangent matrices for non-standard physical models,
=>	sensitivity analysis according to arbitrary parameters,
=>	optimization problems,
=>	inverse analysis.
In all these cases, the general theoretical solution to obtain exact derivatives is still under consideration and numerical differentiation is often used instead. The automatic differentiation generates a program code for the derivative from a code for the basic function.

Throughout this section we consider function y = f(v) that is defined by a given sequence of formulae of the following form
For i = n+1,n+2,..,m
      (Subscript[v, i])=(Subscript[f, i])(Subscript[((Subscript[v, j])) , (Subscript[jϵA, i])     ])
y=(Subscript[v, m])
(Subscript[A, i])={1,2,...,i-1}

Here functions (Subscript[f, i]) depend on the already computed quantities (Subscript[v, j]). This is equivalent to the vector of formulae in AceGen where (Subscript[v, j]) are auxiliary variables. For functions composed from elementary operations, a gradient can be derived automatically by the use of symbolic derivation with Mathematica. Let (Subscript[v, i]) ,i=1...n be a set of independent variables and (Subscript[v, i]), i = n+1,n+2,...,m a set of auxiliary variables. The goal is to calculate the gradient of y with respect to the set of independent variables ∇y={((∂y)/(∂(Subscript[v, 1]))),((∂y)/(∂(Subscript[v, 2]))),...,((∂y)/(∂(Subscript[v, n])))}. To do this we must resolve dependencies due to the implicitly contained variables. Two approaches can be used for this, often recalled as forward and reverse mode of automatic differentiation.
The forward mode accumulates the derivatives of auxiliary variables with respect to the independent variables. Denoting by ∇(Subscript[v, i]) the gradient of (Subscript[v, i ]) with respect to the independent variables (Subscript[v, j]) ,j=1...n, we derive from the original sequence of formulae by the chain rule:

(Subscript[∇(Subscript[v, i])={(Subscript[δ, ij])}, j=1,2,...,n])  for i=1,2,...,n
For i=n+1,n+2,...,m
        ∇(Subscript[v, i])=(∑_(j=1)^(i-1))((∂(Subscript[f, i]))/(∂(Subscript[v, j])))∇(Subscript[v, j])
∇y=∇(Subscript[v, m])

In practical cases gradients ∇(Subscript[v, i]) are more or less sparse. This sparsity is considered automatically by the simultaneous simplification procedure.
In contrast to the forward mode, the reverse mode propagates adjoints, that is, the derivatives of the final values, with respect to auxiliary variables. First we associate the scalar derivative (OverBar[(Subscript[v, i])]) with each auxiliary variable (Subscript[v, i]).
(OverBar[(Subscript[v, i])])=((∂y)/(∂(Subscript[v, i])))              for i=m,m-1,...,n
∇y = {((∂y)/(∂(Subscript[v, i])))} = {(OverBar[(Subscript[v, i])])}   for i=1,2,...,n
As a consequence of the chain rule it can be shown that these adjoint quantities satisfy the relation
(OverBar[(Subscript[v, i])])=(∑_(j=i+1)^m)((∂(Subscript[f, j]))/(∂(Subscript[v, i])))(OverBar[(Subscript[v, j])])
To propagate adjoints, we have to reverse the flow of the program, starting with the last function first as follows
For i=m,m-1,...,n-1
      (OverBar[(Subscript[v, i])])=(∑_(j=i+1)^m)((∂(Subscript[f, j]))/(∂(Subscript[v, i])))(OverBar[(Subscript[v, j])])
∇y={(OverBar[(Subscript[v, 1])]),(OverBar[(Subscript[v, 2])]),...,(OverBar[(Subscript[v, n])])}
Again, simultaneous simplification improves the efficiency for the reverse mode by taking into account the actual dependency between variables.

The following simple example shows how the presented procedure actually works. Let us define three functions (Subscript[f, 1]),(Subscript[f, 2]),(Subscript[f, 3]), dependent on independent variables (Subscript[x, i]). The forward mode for the evaluation of gradient ∇(Subscript[v, 3])={((∂(Subscript[v, 3]))/(∂(Subscript[x, i])))} leads to

({{(Subscript[v, 1])=(Subscript[f, 1])((Subscript[x, i])), ((∂(Subscript[v, 1]))/(∂(Subscript[x, i])))=((∂(Subscript[f, 1]))/(∂(Subscript[x, i])))                                                            i=1,2,...,n}, {(Subscript[v, 2])=(Subscript[f, 2])((Subscript[x, i]),(Subscript[v, 1])), ((∂(Subscript[v, 2]))/(∂(Subscript[x, i])))=((∂(Subscript[f, 2]))/(∂(Subscript[x, i])))+((∂(Subscript[f, 2]))/(∂(Subscript[v, 1])))((∂(Subscript[v, 1]))/(∂(Subscript[x, i])))                                      i=1,2,...,n}, {(Subscript[v, 3])=(Subscript[f, 3])((Subscript[x, i]),(Subscript[v, 2]),(Subscript[v, 3])), ((∂(Subscript[v, 3]))/(∂(Subscript[x, i])))=((∂(Subscript[f, 3]))/(∂(Subscript[x, i])))+((∂(Subscript[f, 3]))/(∂(Subscript[v, 1])))((∂(Subscript[v, 1]))/(∂(Subscript[x, i])))+((∂(Subscript[f, 3]))/(∂(Subscript[v, 2])))((∂(Subscript[v, 2]))/(∂(Subscript[x, i])))               i=1,2,...,n.}})

The reverse mode is implemented as follows

({{(Subscript[v, 3])=(Subscript[f, 3])((Subscript[x, i]),(Subscript[v, 2]),(Subscript[v, 3])), (Subscript[(OverBar[v]), 3])=((∂(Subscript[v, 3]))/(∂(Subscript[v, 3])))=1                                               }, {(Subscript[v, 2])=(Subscript[f, 2])((Subscript[x, i]),(Subscript[v, 1])), (Subscript[(OverBar[v]), 2])=((∂(Subscript[v, 3]))/(∂(Subscript[v, 2])))=((∂(Subscript[f, 3]))/(∂(Subscript[v, 2]))) (Subscript[(OverBar[v]), 3])                         }, {(Subscript[v, 1])=(Subscript[f, 1])((Subscript[x, i])), (Subscript[(OverBar[v]), 1])=((∂(Subscript[v, 3]))/(∂(Subscript[v, 1])))=((∂(Subscript[f, 3]))/(∂(Subscript[v, 1]))) (Subscript[(OverBar[v]), 3])+((∂(Subscript[f, 2]))/(∂(Subscript[v, 1]))) (Subscript[(OverBar[v]), 2])}, {(Subscript[x, i]), ((∂(Subscript[v, 3]))/(∂(Subscript[x, i])))=((∂(Subscript[f, 3]))/(∂(Subscript[x, i])))(Subscript[(OverBar[v]), 3])+((∂(Subscript[f, 2]))/(∂(Subscript[x, i])))(Subscript[(OverBar[v]), 2])+((∂(Subscript[f, 1]))/(∂(Subscript[x, i])))(Subscript[(OverBar[v]), 1])         i=1,2,...,n.}})

By comparing both techniques, it is obvious that the reverse mode leads to a more efficient solution when the number of functions to differentiate is higher than the number of independent variables. The above formulae can be algorithmically implemented in two fundamentally different ways:
A) the standard automatic differentiation tools perform differentiation at program run time using operator overloading capabilities of modern computer languages,
B) in the case of code-to-code implementation derivatives are derived symbolically, program is written in standard computer language and compiled and link together with the rest of the program.
The code-to-code implementation does not require any additional data handling as operator overloading implementation. Consequently, it leads to faster codes. However, it is rarely used due to difficult implementation. The procedure implemented in the AceGen system represents a code-to-code transformation version of automatic differentiation technique combined with powerful simultaneous code optimisation. The resulting codes are much more numerically efficient than the codes based on the standard operator overloading automatic differentiation.
AceGen does automatic differentiation by using forward or backward mode of automatic differentiation. The vector of the new auxiliary variables, generated during the simultaneous simplification of the expressions, is a kind of pseudo code, which makes the automatic differentiation with AceGen possible. AceGen uses Mathematica's symbolic differentiation functions for the differentiation of explicit parts of the expression. The version of reverse or forward mode of 'automatic differentiation' technique is then employed for the collection of derivatives of  variables which implicitly dependent on differentiation variables. At both steps, additional optimization of expressions is performed simultaneously.
Higher order derivatives are difficult to be implemented by standard automatic differentiation tools. Most of the automatic differentiation tools offer only the first derivatives. When derivatives are derived by AceGen, the results and all the auxiliary formulae are stored on a global vector of formulae where they act as any other formula entered by the user. Thus, there is no limitation in AceGen concerning the number of derivatives which are to be derived.
There are several situations when the formulae and the program structure alone are not sufficient to make proper derivative code. These exceptions are described in chapter Exceptions in Differentiation. 
KORELC, Jože, Multi-language and Multi-environment Generation of Nonlinear Finite Element Codes,  Engineering with Computers, 2002, 18(4):312-327
Korelc  J. Automation of primal and sensitivity analysis of transient coupled problems.  Computational mechanics, 44(5):631-649 (2009).

SMSD Function

The argument index is an integer type auxiliary variable, array is an auxiliary variable that represents an array data object (the SMSArray function returns an array data object, not an auxiliary variable), and arrayindex is an auxiliary variable that represents index data object (see Arrays).
Sometimes differentiation with respect to intermediate auxiliary variables can lead to incorrect results due to the interaction of automatic differentiation and Expression Optimization. In order to prevent this, all the basic independent variables have to have an unique signature. Functions such as SMSFreeze, SMSReal, and SMSFictive return an auxiliary variable with the unique signature.

Differentiation: Mathematica syntax versus AceGen syntax

The standard Mathematica syntax is compared here with the equivalent AceGen Syntax.

Mathematica

Clear[x,y,z,k];
f=x+2 y+3 z+4 k

Partial derivative: ((∂f)/(∂x))

D[f,x]

Gradient: (Subscript[∇, x])=((∂f)/(∂(Subscript[x, j])))

D[f,{{x,y,z,k}}]

Jacobian: (Subscript[J, i,j])=((∂(Subscript[f, i]))/(∂(Subscript[x, j])))

D[{f,f^2},{{x,y}}]//MatrixForm

Derivatives of second order tensors: (Subscript[D, i,j,k,l])=((∂(Subscript[f, i,j]))/(∂(Subscript[x, k,l])))

D[{{f,f^2},{f^3,f^4}},{{{x,y},{z,k}}}]//MatrixForm

AceGen

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,y$$,z$$,k$$]];
{x,y,z,k}⊢SMSReal[{x$$,y$$,z$$,k$$}];
f⊨x+2 y+3 z+4 k;

Partial derivative: ((∂f)/(∂x))

dx⊨SMSD[f,x]

Gradient: (Subscript[∇, x])=((∂f)/(∂(Subscript[x, j])))

Note that in Mathematica the vector of independent variables has an extra bracket. This is due to the legacy problems with the Mathematica syntax.

∇x⊨SMSD[f,{x,y,z}]

Jacobian: (Subscript[J, i,j])=((∂(Subscript[f, i]))/(∂(Subscript[x, j])))

Jx⊨SMSD[{f,f^2},{x,y}]

SMSRestore[Jx,"Global"]//MatrixForm

Derivatives of second order tensors: (Subscript[D, i,j,k,l])=((∂(Subscript[f, i,j]))/(∂(Subscript[x, k,l])))

Dx⊨SMSD[{{f,f^2},{f^3,f^4}},{{x,y},{z,k}}]

SMSRestore[Dx,"Global"]//MatrixForm

See also SMSD for additional examples.

Automatic Differentiation Examples

Example 1: Simple C subroutine

Generation of the C subroutine which evaluates derivative of function z(x) with respect to x.
z(x)=3(x^2)+2y+Log[y].
y(x)=Sin[(x^2)].

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,r$$]];
x⊢SMSReal[x$$];
y⊨Sin[(x^2)];
z⫤3 (x^2)+2 y+Log[y];

Here the derivative of z with respect to x is calculated.

zx⊨SMSD[z,x];

SMSExport[zx,r$$];
SMSWrite[];

FilePrint["test.c"]

Example 2: Differentiation of complex program structure

Generation of the C function file which evaluates derivative of function f(x)=3 (z^2) with respect to x, where z is 
 z(x)={({{(x^2)+2y+Log[y], x>0}, {Cos[(x^3)], x≤0}}),
and y is y=Sin[(x^2)].

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,r$$]];
x⊢SMSReal[x$$];
z⊨SMSIf[x>0
,y⊨Sin[ (x^2)];
3 (x^2)+2 y+Log[y]
,Cos[(x^3)]
];
fx⊨SMSD[3 (z^2),x];
SMSExport[fx,r$$];
SMSWrite[];
FilePrint["test.c"]

Example 3: Differentiation with respect to symmetric matrix

The differentiation of a scalar value with respect to the matrix of differentiation variables can be nontrivial if the matrix has a special structure. 
If the scalar value exp(M) depends on a symmetric matrix of independent variables 
M⊨(({{(Subscript[v, 11]), (Subscript[v, 12]), …}, {(Subscript[v, 12]), (Subscript[v, 22]), …}, {…, …, …}})) 
then we have two possibilities to make proper differentiation:
A) the original matrix M can be replaced by the new matrix of unique variables
M𝔽⊨SMSFreeze[M];
δexp⊨SMSD[exp(M𝔽),M𝔽};
B) if the scalar value exp is an isotropic function of M then the "Symmetric"->True option also leads to proper derivative as follows
δexp⊨ SMSD[exp(M,M,"Symmetric"->True]  ≡ (({{1, (1/2), …}, {(1/2), 1, …}, {…, …, …}}))*(({{((∂exp )/(∂(Subscript[v, 11]))), ((∂exp )/(∂(Subscript[v, 12]))), …}, {((∂exp )/(∂(Subscript[v, 12]))), ((∂exp )/(∂(Subscript[v, 22]))), …}, {…, …, …}}))

Example:
Lets have matrix M=({{a, b}, {b, c}}) and functions (Subscript[f, iso])=det(M) and (Subscript[f, general])=((Subscript[M, 1,1])^2)+5 (Subscript[M, 1,2])-Sin((Subscript[M, 2,1]))-3(Subscript[M, 2,2]), thus
((∂(Subscript[f, iso]))/(∂M))=({{a, -b}, {-b, c}}) and ((∂(Subscript[f, general]))/(∂M))=({{2 a, 5}, {-Cos(b), -3}}).

<<AceGen`;
SMSInitialize["test"];
SMSModule["test",Real[a$$,b$$,c$$]];
{a,b,c}⊢SMSReal[{a$$,b$$,c$$}];

M⊨{{a,b},{b,c}};
fiso=Det[M];
fgeneral=M[[1,1]]^2+5M[[1,2]]-Sin[M[[2,1]]]-3 M[[2,2]];

The result of differentiation is incorrect under the assumption that M is a symmetric matrix of independent variables.

SMSD[fiso,M]//MatrixForm

With the "Symmetric"->True we obtain correct result for isotropic argument.

SMSD[fiso,M,"Symmetric"->True]//MatrixForm

The argument can be also an arbitrary structure composed of isotropic functions.

SMSD[{fiso,Sin[fiso]},M,"Symmetric"->True]//MatrixForm

With the "Symmetric"->True option wrong result is obtained for a general argument.

SMSD[fgeneral,M,"Symmetric"->True]//MatrixForm

SMSFreeze creates unique variables for all components of matrix. Note that the result is less optimized that the one with "Symmetric"->True option, however it creates correct results regardless on the type of the argument.

M⊨SMSFreeze[M];
fiso=Det[M];
fgeneral=M[[1,1]]^2+5M[[1,2]]-Sin[M[[2,1]]]-3 M[[2,2]];

SMSD[fiso,M]//MatrixForm

SMSD[fgeneral,M]//MatrixForm

Example 4: Differentiation with respect to sparse matrix

By default all differentiation variables have to be defined as auxiliary variables with unique random value. With the option "Ignore"->NumberQ the numbers are ignored and derivatives with respect to numbers are assumed to be 0.

 SMSD[exp,(({{(Subscript[v, 11]), (Subscript[v, 12]), …}, {(Subscript[v, 21]), 0, …}, {…, …, …}})),“Ignore”->NumberQ]  ≡ (({{((∂exp )/(∂(Subscript[v, 11]))), ((∂exp )/(∂(Subscript[v, 12]))), …}, {((∂exp )/(∂(Subscript[v, 12]))), 0, …}, {…, …, …}}))

<<AceGen`;
SMSInitialize["test"];
SMSModule["test",Real[a$$,b$$,c$$]];
{a,b,c}⊢SMSReal[{a$$,b$$,c$$}];

x⊨{a,b,c};
f=a+2 b+3 c;

SMSD[f,{a,b,5},"Ignore"->NumberQ]

Without the "Ignore"->NumberQ option the AceGen reports an error.

SMSD[f,{a,b,5}]

Example 5: Differentiation with respect to intermediate variables

Generation of the C subroutine which evaluates derivative of function Sin(w) with respect to w where w is intermediate auxiliary variable defined as w=(x^2)+1.
 w=(x^2)+1
((∂Sin(w))/(∂w))

The intermediate auxiliary variable is not truly independent variable and as such does not possess unique signature. Differentiation is in this case not possible.

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$]];
x⊢SMSReal[x$$];
w⊨(x^2)+1;
SMSD[Sin[w],w]

SMSFreeze creates unique signature for the intermediate auxiliary variable.

<<AceGen`;
SMSInitialize["test"];
SMSModule["test",Real[x$$]];
x⊢SMSReal[x$$];
w⊢SMSFreeze[(x^2)+1];
SMSD[Sin[w],w]

Characteristic Formulae

If the result would lead to large number of formulae, we can produce a characteristic formula. Characteristic formula is one general formula, that can be used for the evaluation of all other formulae. Characteristic formula can be produced by the use of AceGen functions that can work with the arrays and indices on a specific element of the array.
If (Subscript[N, d.o.f])  unknown parameters are used in our numerical procedure, then an explicit form of the gradient and the Hessian will have at least (Subscript[N, d.o.f])+((((Subscript[N, d.o.f])))^2) terms. Thus, explicit code for all terms can be generated only if the number of unknowns is small. If the number of parameters of the problem is large, then characteristic expressions for arbitrary term of gradient or Hessian have to be derived. The first step is to present a set of parameters as a union of disjoint subsets. The subset of unknown parameters, denoted by (Subscript[a, i]) , is defined by

(Subscript[a, i])⊂a
(Overscript[(⋃_(i=1)), L])(Subscript[a, i])=a
(Subscript[a, i])⋂(Subscript[a, j])=ϕ   ,i≠j.
Let f (a) be an arbitrary function, L the number of subsets of a, and ((∂f)/(∂a)) the gradient of f  with respect to a.
((∂f)/(∂a))=(Subscript[{((∂f)/(∂(Subscript[a, 1]))),((∂f)/(∂(Subscript[a, 2]))),...((∂f)/(∂(Subscript[a, L])))},  ])

Let (Subscript[(OverBar[a]), i]) be an arbitrary element of the i-th subset. At the evaluation time of the program, the actual index of an arbitrary element (Subscript[(OverBar[a]), i]) becomes known. Thus, (Subscript[(OverBar[a]), ij]) represents an element of the i-th subset with the index j.  Then we can calculate a characteristic formula for the gradient of f with respect to an arbitrary element of subset i as follows

((∂f)/(∂(Subscript[(OverBar[a]), ij])))=SMSD[f,(Subscript[a, i]),j].

Let (Subscript[a, kl]) represents an element of the k-th subset with the index l. Characteristic formula for the Hessian of f with respect to arbitrary element of subset k is then

(((∂^2)f)/(∂(Subscript[(OverBar[a]), ij])∂(Subscript[(OverBar[a]), kl])))=SMSD[((∂f)/(∂(Subscript[(OverBar[a]), ij]))),(Subscript[a, k]),l]

Example 1: characteristic formulae - one subset

Let us again consider the example presented at the beginning of the tutorial. A function which calculates gradient of function f=(u^2), with respect to unknown parameters (Subscript[u, i]) is required.
u=(∑_(i=1)^3)(Subscript[N, i])(Subscript[u, i])
(Subscript[N, 1])=(x/L),(Subscript[N, 2])=1-(x/L),(Subscript[N, 3])=(x/L)(1-(x/L))
The code presented here is generated without the generation of characteristic formulae. This time all unknown parameters are grouped together in one vector. AceGen can then generate a characteristic formula for the arbitrary element of the gradient.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"]
SMSModule["Test",Real[u$$[3],x$$,L$$,g$$[3]]];
{x,L}⊢{SMSReal[x$$],SMSReal[L$$]};
ui⊢SMSReal[Table[u$$[i],{i,3}]];
Ni⊨{(x/L),1-(x/L),(x/L) (1-(x/L))};
u⊨Ni.ui;
f⊨(u^2);
SMSDo[i,1,3];

Here the derivative of f with respect to i-th element of the set of unknown parameters ui is calculated.

fui⊨SMSD[f,ui,i];

SMSExport[fui,g$$[i]];
SMSEndDo[];
SMSWrite[];

FilePrint["test.f"]

Example 2: characteristic formulae - two subsets

Write function which calculates gradient ((∂f)/(∂(Subscript[a, i]))) and the Hessian (((∂^2)f)/(∂(Subscript[a, i]) ∂(Subscript[a, j]))) of the function,
 f=f((Subscript[u, 1]),(Subscript[v, 1,])(Subscript[u, 2]),(Subscript[v, 2]),(Subscript[u, 3]),(Subscript[v, 3]),(Subscript[u, 4]),(Subscript[v, 4]))=(u^2)+(v^2)+u v,
with respect to unknown parameters (Subscript[u, i]) and (Subscript[v, i]), where
u=(∑_(i=1)^4)(Subscript[N, i])(Subscript[u, i])
u=(∑_(i=1)^4)(Subscript[N, i]) (Subscript[v, i])
and
N={(1-X) (1-Y),(1+X) (1-Y),(1+X) (1+Y),(1-X) (1+Y)}.

We make two subsets (Subscript[u, i ])and  (Subscript[v, i])  of the set of independent variables (Subscript[a, i]).
(Subscript[a, i])={(Subscript[u, 1]),(Subscript[v, 1,])(Subscript[u, 2]),(Subscript[v, 2]),(Subscript[u, 3]),(Subscript[v, 3]),(Subscript[u, 4]),(Subscript[v, 4])}
(Subscript[u, i])={(Subscript[u, 1]),(Subscript[u, 2]),(Subscript[u, 3]),(Subscript[u, 4])},  (Subscript[v, i])={(Subscript[v, 1]),(Subscript[v, 2]),(Subscript[v, 3]),(Subscript[v, 4])}

<<AceGen`;
SMSInitialize["test","Language"->"C"]SMSModule["Test",Real[ul$$[4],vl$$[4],X$$,Y$$,g$$[8],H$$[8,8]]];{X,Y}⊢{SMSReal[X$$],SMSReal[Y$$]};
ui⊢SMSReal[Table[ul$$[i],{i,4}]];
vi⊢SMSReal[Table[vl$$[i],{i,4}]];
Ni⊨{(1-X) (1-Y),(1+X) (1-Y),(1+X) (1+Y),(1-X) (1+Y)};
u⊨Ni.ui;v⊨Ni.vi;
f⊨(u^2)+(v^2)+u v;
SMSDo[
(*Here the characteristic formulae for the sub-vector of the gradient vector are created.*){g1i,g2i}⊨{SMSD[f,ui,i],SMSD[f,vi,i]};(*Characteristic formulae have to be exported to the correct places in a gradient vector.*)
SMSExport[{g1i,g2i}, {g$$[2 i-1],g$$[2 i]}];
SMSDo[
(*Here the 2*2 characteristic sub-matrix of the Hessian is created.*)H⊨{{SMSD[g1i,ui,j],SMSD[g1i,vi,j]},
{SMSD[g2i,ui,j],SMSD[g2i,vi,j]}};
SMSExport[H,{{H$$[2 i-1,2 j-1],H$$[2 i-1,2 j]},
{H$$[2 i,2 j-1],H$$[2 i,2 j]}}];
,{j,1,4}
];
,{ i,1,4}
];
SMSWrite[];
FilePrint["test.c"]

Exceptions in Differentiation

The SMSDefineDerivative function should be used cautiously since derivatives are defined permanently and globally. The "Dependency" option of the SMSFreeze, SMSReal and SMSD function should be used instead whenever possible.

There are several situations when the formulae and the program structure alone are not sufficient to make proper derivative code. The basic situations that have to be considered are:

Type A
Basic case: The total derivatives of intermediate variables b(a) with respect to independent variables a are set to be equal to matrix M.

Type A
Basic case: The total derivatives of intermediate variables b(a) with respect to independent variables a are set to be equal to matrix M.

Type B
Special case of A: There exists explicit dependency between variables that has to be neglected for the differentiation.

Type C
Special case of A: There exists implicit dependency between variables (the dependency does not follows from the algorithm itself) that has to be considered for the differentiation.

Type D
Generalization of A: The total derivatives of intermediate variables b(c) with respect to intermediate variables c(a) are set to be equal to matrix M.

It was shown in the section Theory of Automatic Differentiation that with a simple chain rule we obtain derivatives with respect to the arbitrary variables by following the structure of the program (forward or backward). However this is no longer true when variables depend implicitly on each other. This is the case for nonlinear coordinate mapping, collocation variables at the collocation points etc. These implicit dependencies cannot be detected without introducing additional knowledge into the system.

The local definition of AD exception is defined as an option given to the SMSD command while the global definition of AD exception is introduced by SMSFreeze command. With the SMSFreeze[exp,"Dependency"] the true dependencies of exp with respect to auxiliary variables are neglected and all partial derivatives are taken to be 0. With the SMSFreeze[exp,"Dependency"->{{(Subscript[p, 1]),((∂exp)/(∂(Subscript[p, 1])))},{(Subscript[p, 2]),((∂exp)/(∂(Subscript[p, 2])))},...,{(Subscript[p, n]),((∂exp)/(∂(Subscript[p, n])))}}] the true dependencies of the exp are ignored and it is assumed that exp depends on auxiliary variables (Subscript[p, 1]),… ,(Subscript[p, n]). Partial derivatives of exp with respect to auxiliary variables (Subscript[p, 1]),… ,(Subscript[p, n]) are then taken to be ((∂exp)/(∂(Subscript[p, 1]))),((∂exp)/(∂(Subscript[p, 2]))),…,((∂exp)/(∂(Subscript[p, n]))) .

SMSDefineDerivative

Exception Type A: Generic Example

Lets take a function f=Sin(w) where w is intermediate auxiliary variable defined as w=a (x^2)+1 and evaluate the following derivative
 ((∂f)/(∂x))(Subscript[|, (Dw/Dx)=5])= 5 Cos(w)

Local definition of AD exception

<<AceGen`;
SMSInitialize["test"];
SMSModule["test",Real[x$$,a$$]];
x⊢SMSReal[x$$];a⊢SMSReal[a$$];
w⊢SMSFreeze[a (x^2)+1];
f⊢Sin[w];
SMSRestore[SMSD[f,x,"Dependency"->{w,x,5}],"Global"]

Global definition of AD exception with SMSFreeze

<<AceGen`;
SMSInitialize["test"];
SMSModule["test",Real[x$$,a$$]];
x⊢SMSReal[x$$];a⊢SMSReal[a$$];
w⊢SMSFreeze[a (x^2)+1,"Dependency"->{x,5}];
f⊢Sin[w];
SMSRestore[SMSD[f,x],"Global"]

Note that the "Dependency" option of the SMSFreeze command hides all other dependencies thus the derivative of f with respect to a  is 0.

SMSD[f,a]

Exception Type C: Implicit dependencies

The generation of the subroutine that calculates displacement gradient Dg defined by

({{ξ={ξ,η,ζ}, reference coordinates}, {X(ξ)=(∑_k)(Subscript[N(ξ), k])(Subscript[X, k])   , actual coordinates}, {u(ξ)=(∑_k)(Subscript[N(ξ), k])(Subscript[u, k])   , displacements}, {D=((∂u)/(∂X)), displacement gradient}})

where (Subscript[N, k]) =1/8 (1 + ξ (Subscript[ξ, k])) (1 + η (Subscript[η, k])) (1 + ζ (Subscript[ζ, k])) is the shape function for k-th node where {(Subscript[ξ, k]),(Subscript[η, k]),(Subscript[ζ, k])} are the coordinates of the k-th node.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["Test",Real[X$$[8,3],u$$[8,3],ksi$$,eta$$,ceta$$]];
Ξ={ξ,η,ζ}⊢Table[SMSReal[es$$["IntPoints",i,Ig]],{i,3}];
XI⊢Table[SMSReal[nd$$[i,"X",j]],{i,8},{j,3}];Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];

Coordinates X={(Subscript[X, g]),(Subscript[Y, g]),(Subscript[Z, g])}  are the basic independent variables. To prevent wrong simplifications, we have to define unique signatures for the definition of X.

X⊢SMSFreeze[NI.XI];

Here the Jacobian matrix of nonlinear coordinate transformation is calculated.

Jg⊨SMSD[X,Ξ]

Interpolation of displacements.

uI⊢SMSReal[Table[nd$$[i,"at",j],{i,8},{j,3}]];
u⊨NI.uI;

Simple use of SMSD leads to wrong results.

SMSD[u,X]

The implicit dependency of Ξ on X is now taken into account when the derivation of u is made with respect to X.

Local definition of type C AD exception.

SMSD[u,X,"Dependency"->{Ξ,X,Simplify[SMSInverse[Jg]]}]

Exception Type D: Alternative definition of partial derivatives

The generation of the FORTRAN subroutine calculates the derivative of function f=((Sin(2 (α^2)))/α) where α=Cos(x) with respect to x. Due to the numerical problems arising when α->0 we have to consider exceptions in the evaluation of the function as well as in the evaluation of its derivatives as follows:
f:={({{((Sin(2 (α^2)))/α)                 α≠0}, {(Underscript[Lim, α->0])((Sin(2 (α^2)))/α)       α=0}}),                 ((∂f)/(∂α)):={({{(∂/(∂α))(((Sin(2 (α^2)))/α))               α≠0}, {(Underscript[Lim, α->0])(∂/(∂α))(((Sin(2 (α^2)))/α) )     α=0}}).

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["Test",Real[x$$,f$$,dfdx$$]];
x⊢SMSReal[x$$];
α⊢SMSFreeze[Cos[x]];
f⊨SMSIf[SMSAbs[α]>(10^(-10))
,Sin[2 (α^2)]/α
,SMSFreeze[Limit[Sin[2 (α^2)]/α,α->0],
"Dependency"->{{α,Limit[D[Sin[2 (α^2)]/α,α]//Evaluate,α->0]}}]
];
dfdx⊨SMSD[f,x];
SMSExport[dfdx,dfdx$$];
SMSWrite[];

FilePrint["test.f"]

Limitations: Incorrect structure of the program

Differentiation cannot start inside the "If" construct if the variables involved have multiple instances defined on a separate branches of the same "If" construct. The limitation is due to the interaction of the simultaneous simplification procedure and the automatic differentiation procedure.

SMSIf[x>0];
  f⫤Sin[x];
  ...
SMSElse[];
  f⊣(x^2);
  fx⊨SMSD[f,x];
  ...
SMSEndIf[f];

The first instance of variable f can not be evaluated at the same time as the second instance of variable f. Thus, only the derivative code of the second expression have to be constructed.  However, if the construct appears inside the loop, then some indirect dependencies can appear and both branches have to be considered for differentiation. The problem is that AceGen can not detect this possibility at the point of construction of the derivative code. There are several possibilities how to resolve this problem.

With the introduction of an additional auxiliary variable we force the construction of the derivative code only for the second instance of f.

SMSIf[x>0];
  f⫤Sin[x];
SMSElse[];
  tmp⊨(x^2);
  fx⊨SMSD[tmp,x];
  f⊣tmp;
SMSEndIf[];

If the differentiation is placed outside the "If" construct, both instances of f are considered for the differentiation.

SMSIf[x>0];
  f⫤Sin[x];
SMSElse[];
  f⊣(x^2);
SMSEndIf[];
fx⊨SMSD[f,x];

If  f does not appear outside the "If" construct, then f should be defined as a single-valued variable (f⊨...) and not as multi-valued variable (f⫤...). In this case, there are no dependencies between the first and the second appearance of f. However in this case f can not be used outside the "If" construct. First definition of f is overwritten by the second definition of f.

SMSIf[x>0];
  f⊨Sin[x];
SMSElse[];
  f⊨(x^2);
  fx⊨SMSD[f,x];
SMSEndIf[];

Verification and Debugging

Contents

General Verification Procedures

Printing to Output Devices

SMSPrint

Example 1: printing from Mathematica code

Example 2: printing out to all output devices - C language

Example 3: printing out to all output devices - Fortran language

Example 4: printing from MathLink code

Example 5: printing out from numerical environment - AceFEM-MDriver

SMSPrintMessage

Run Time Debugging

Example of run-time debugging

SMSSetBreak

SMSLoadSession

SMSClearBreak

SMSActivateBreak

General Verification Procedures

We can verify the correctness of the generated code directly in Mathematica. To do this, we need to rerun the problem and to generate the code in a script language of Mathematica. The SMSSetBreak function inserts a break point into the generated code where the program stops and enters interactive debugger (see also User Interface).

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica","Mode"->"Debug"];
SMSModule["Test",Real[u$$[3],x$$,L$$,g$$[3]]];
{x,L}⊢{SMSReal[x$$],SMSReal[L$$]};
ui⊢Table[SMSReal[u$$[i]],{i,3}];
Ni⊨{(x/L),1-(x/L),(x/L)(1-(x/L))};
u⊨Ni.ui;
f⊨(u^2);
g⊨SMSD[f,ui];
SMSExport[g,g$$];
SMSWrite[];

We have several possibilities how to explore the derived formulae and generated code and how to verify the correctness of the model and of the generated code (see also User Interface).

The first possibility is to explore the generated formulae interactively with Mathematica in order to see whether their structure is logical.

u

In the case of more complex code, the code profile can be explored () where the structure of the program is displayed together with the links to all generated formulae  (see also User Interface).

The second possibility is to make some numerical tests and see whether the numerical results are logical.

This reads definition of the automatically generated "Test" function from the test.m file.

<<"test.m"

Here the numerical values of the input parameters are defined.
The context of the symbols used in the definition of the subroutine is global as well as the context of the input parameters. Consequently, the new definition would override the old ones. Thus the names of the arguments cannot be the same as the symbols used in the definition of the subroutine.

xv=π;Lv=10.;uv={0.,1.,7.};gv={Null,Null,Null};

Here the generated code is used to calculate gradient for the numerical test example.

Test[uv,xv,Lv,gv]

Here the numerical results are displayed.

gv

Partial evaluation, where part of expressions is numerically evaluated and part is left in a symbolic form, can also provide useful information.

Here the numerical values of u  and x input parameters are defined, while L is left in a symbolic form.

xv=π//N;Lv=.;uv={0.,1.,7.};gv={Null,Null,Null};

Here the generated code is used to calculate gradient for the given values of input parameters.

Test[uv,xv,Lv,gv]

Here the partially evaluated gradient is displayed.

gv//Expand

The third possibility is to compare the numerical results obtained by AceGen with the results obtained directly by Mathematica.

Here the gradient is calculated directly by Mathematica with essentially the same procedure as before. AceGen functions are removed and replaced with the equivalent functions in Mathematica.

Clear[x,L,up,g];
{x,L}={x,L};
ui=Array[up,3];
Ni={x/L,1-x/L,x/L(1-x/L)};
u=Ni.ui;
f=u^2;
g=Map[D[f,#]&,ui]//Simplify

Here the numerical results are calculated and displayed for the same numerical example as before. We can se that we get the same results.

x=π;L=10;up[1]=0;up[2]=1;up[3]=7.;
g

The last possibility is to look at the generated code directly.

Due to the option  "Mode"->"Debug" AceGen automatically generates comments that describe the actual meaning of the generated formulae. The code is also less optimized and it can be a bit more easily understood and explored.

FilePrint["test.m"]

Several modifications of the above procedures are possible.

Printing to Output Devices

SMSPrint

The SMSPrint function is active only in "Debug" and "Prototype" mode while the SMSPrintMessage function always creates source code and prints out to standard output device (see SMSPrintMessage).
Expression (Subscript[expr, i]) can be a string constant or an arbitrary AceGen expression. If the chosen language is Mathematica language or Fortran, then the expression can be of integer, real or string type.
Printing from finite elements might be problematic if the program is parallelized!! Please turn off parallelization with SMTInputData["Threads" -> 1].
The following restrictions exist for the C language:

=>	the integer type expression is allowed, but it will be cased into the real type expression;
=>	the string type constant is allowed and should be of the form "'text'";
=>	the string type expression is not allowed and will result in compiler error.

Additional AceFEM specific restrictions on printout

In order to prevent excessive printing to notebook or file AceFEM applies two additional conditions that limits the number of printouts.
Printing is executed accordingly to the value of the SMTIData["DebugElement"] environment variable:
	SMTIData["DebugElement",-1]  => printouts are active for all elements (default value)
	SMTIData["DebugElement",0]  => printouts are disabled
	SMTIData["DebugElement",i]  => printout is active for i-th  element
Printing is suspended if the actual number of printouts exceeds the maximum number allowed as defined by SMTIData["MaxMessages"] environment variable. Warning message is produced when the number of printouts reaches SMTIData["MaxMessages"].

Printing messages to console or terminal window

Windows

On Windows application can be started in a separate window with the option "Console"->True of the SMSInstallMathLink command (e.g. SMSInstallMathLink[“Console”->True]. Additional messages are then printed to  command window as shown below.

Mac OS

In order to direct printouts to terminal window on Mac Mathematica has to be started from the terminal as follows:

open Terminal (look under Applications-Utilities for Terminal.app),

start Mathematica form Terminal (e.g. /Applications/Mathematica.app/Contents/MacOS/Mathematica),

after SMTAnalysis[] set SMTIData[“ConsoleWindow”,1]

messages will now be printed to terminal window.

Linux

In order to direct printouts to terminal window  on Linux Mathematica has to be started from the terminal as follows:

open Terminal (e.g. search for Terminal),

start Mathematica form Terminal  (e.g.Mathematica &),

after SMTAnalysis[] set SMTIData[“ConsoleWindow”,1]

messages will now be printed to terminal window.

Example 1: printing from Mathematica code

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica","Mode"->"Prototype"];
SMSModule["test",Real[x$$,r$$],"Input"->{x$$},"Output"->{r$$}];
SMSPrint["pi=",π];
SMSExport[π,r$$];
SMSWrite[];

Get["test.m"]

FilePrint["test.m"]

r=0.;
test[1.,r]

Messages are printed to "console window" and to "test.out" file. Printing to notebook currently not supported!

FilePrint["test.out"]

Example 2: printing out to all output devices - C language

<<AceGen`;
SMSInitialize["test","Language"->"C","Mode"->"Prototype"]
SMSModule["test",Real[x$$]];
(*print to standard console*)
SMSPrint["pi=",π];
(*print to file test.out*)
SMSPrint["time=",SMSTime[],"Output"->{"File","test.out"}];
(*print to file test.out only when x>0 *)
SMSPrint["e=",E,"Output"->{"File","test.out"},"Condition"->SMSReal[x$$]>0];
SMSWrite[];

FilePrint["test.c"]

Example 3: printing out to all output devices - Fortran language

<<AceGen`;
SMSInitialize["test","Language"->"Fortran","Mode"->"Prototype"];
SMSModule["test",Real[x$$]];
(*print to standard console*)
SMSPrint["pi=",π];
(*print to file test.out*)
SMSPrint["time=",SMSTime[],"Output"->{"File","test.out"}];
(*print to Fortran I/O unit number 4 only when x>0 *)
SMSPrint["e=",E,"Output"->{"File",4},"Condition"->SMSReal[x$$]>0];
SMSWrite[];

FilePrint["test.f"]

Example 4: printing from MathLink code

<<AceGen`;
SMSInitialize["test","Environment"->"MathLink","Mode"->"Prototype"];
SMSModule["test",Real[x$$,r$$],"Input"->{x$$},"Output"->{r$$}];
(*print to standard console*)
SMSPrint["pi=",π];
(*print to file test.out*)
SMSPrint["time=",SMSTime[],"Output"->{"File","test.out"}];(*print to file test.out only when x>0 *)
SMSPrint["e=",E,"Output"->{"File","test.out"},"Condition"->SMSReal[x$$]>0];
SMSExport[π,r$$];
SMSWrite[];

SMSInstallMathLink["Console"->True]

test[1.]

Messages are printed to "console window" and to "test.out" file. Printing to notebook is currently not supported!

FilePrint["test.out"]

Example 5: printing out from numerical environment - AceFEM-MDriver

<<AceGen`;
SMSInitialize["test","Environment"->"AceFEM-MDriver","Mode"->"Prototype"];
SMSTemplate["SMSTopology"->"T1"];
SMSStandardModule["Tangent and residual"];
SMSPrint["'pi='",π];
SMSPrint["'load='",rdata$$["Multiplier"],"Output"->"File","Condition"->"DebugElement"];
SMSWrite[];

FilePrint["test.m"]

Run Time Debugging

Example of run-time debugging

Let start with the subprogram that returns solution to the system of the following nonlinear equations
Φ={({{a x y+(x^3)=0}, {a−x (y^2)=0}})}

where x and y are unknowns and a is the parameter using the standard Newton-Raphson iterative procedure. The SMSSetBreak function inserts the break points with the identifications "X" and "A"  into the generated code.

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica","Mode"->"Debug"];
SMSModule["test",Real[x$$,y$$,a$$,tol$$],Integer[nmax$$]];
{x0,y0,a,ϵ}⊢SMSReal[{x$$,y$$,a$$,tol$$}];
nmax⊢SMSInteger[nmax$$];
{x,y}⫤{x0,y0};
SMSDo[
Φ⊨{a  x  y+(x^3),a - x (y^2)};
Kt⊨SMSD[Φ,{x,y}];
{Δx,Δy}⊨SMSLinearSolve[Kt,-Φ];
{x,y}⊣{x,y}+{Δx,Δy};
SMSSetBreak["A","Active"->False];
SMSIf[SMSSqrt[{Δx,Δy}.{Δx,Δy}]<ϵ
,SMSExport[{x,y},{x$$,y$$}];
SMSBreak[];
];
SMSIf[i==nmax
,SMSPrintMessage["no convergion"];
SMSReturn[];
];
SMSSetBreak["X"];
,{i,1,nmax,1,{x,y}}
];
SMSWrite[];

Here the program is loaded and the generated subroutine is called.

<<AceGen`;
<<"test.m";
SMSLoadSession["test"];
x=1.9;y=-1.2;
test[x,y,3.,0.0001,10]

At the break point the structure of the program is displayed together with the links to all generated formulae and the actual values of the auxiliary variables.

The program stops and enters interactive debugger whenever selective SMSExecuteBreakPoint function is executed. The function also initiates special dialog mode supported by the Mathematica  (see also Dialog). The "dialog" is terminated by  button. Break points can be switched on (●) and off (○) by pressing the button at the position of the break point. The break points are automatically generated at the end of If.. else..endif and Do...enddo structures additional to the user defined break points. The current break point is displayed with the  sign.

Menu legend:
  => refresh the contents of the debug window
○  => disable all breaks points
●  => enable break point at the beginning of the subroutine
 => continue to the next break point

Here the break point "X" is inactivated and the break point "A" is activated. The break point "A" is given a pure function that is executed whenever the break point is called. Note that the SMSLoadSession also restores all definitions of the symbols that have been assigned value during the AceGen session (e.g. the definition of the Kt variable in the current example).

<<AceGen`;
<<"test.m";
SMSLoadSession["test"];
SMSClearBreak["X"];
SMSActivateBreak["A",Print["K=",Kt//MatrixForm]&];
x=1.9;y=-1.2;
test[x,y,3.,0.0001,10]

SMSSetBreak

The  code profile window is also used for the run-time debugging. The break points can be inserted into the source code by the SMSSetBreak command.

Break points are inserted only if the code is generated with the "Mode"->"Debug" option. In "Debug" mode the system also automatically generates file with the name "sessionname.dbg"  where all the information necessary for the run-time debugging is stored. The number of break points is not limited. All the user defined break points are by default active. With the option "Active"->False the break point becomes initially inactive. The break points are also automatically generated at the end of If.. else..endif and Do...enddo statements additionally to the user defined break points. All automatically defined break points are by default inactive. Using the break points is also one of the ways how the automatically generated code can be debugged.
The data has to be restored from the "sessionname.dbg" file by the SMSLoadSession command before the generated functions are executed.

SMSLoadSession

With an additional commands SMSClearBreak and SMSActivateBreak the breaks points can be activated and deactivated at the run time.

SMSClearBreak

SMSActivateBreak

The program can be stopped also when there are no user defined break points by activating the automatically generated break point at the beginning of the chosen module with the SMSActivateBreak[module_index] command.
If the debugging is used in combination with the finite element environment AceFEM, the element for which the break point is activated has to be specified first (SMTIData["DebugElement",elementnumber]).

General Utility Functions

Contents

Standard Functions With Unique Signature

Standard Functions Without Unique Signature

System Utility Functions

Utility Functions for Numerical Environments

Compressing Structures

Standard Functions With Unique Signature

Functions with unique signature and support for derivatives.

SMSSqrt (√x)

The square root function exhibits the singularity in derivatives around the origin. The SMSSqrt modifies the square root function on interval [0,x0] in a way that singularity in derivatives is avoided.

SMSPower ((x^y))

The (x^y) function exhibits the singularity in function or its derivatives around the origin for y<1. The SMSPower modifies the (x^y) function on interval [0,x0] in a way that singularities are avoided.

Standard Functions Without Unique Signature

Functions without unique signature and support for derivatives provided by Mathematica.

System Utility Functions

System functions with unique signature and no support for derivatives.

Compressing Structures

Example

<<AceGen`;
SMSInitialize["tmptest","Environment"->"MathLink","VectorLength"->50,"Mode"->"Optimal"];
SMSModule["Test",Real[u$$[3],x$$,L$$,k21$$[4],c$$[9]],"Input"->{u$$,x$$,L$$},"Output"->{k21$$,c$$}];
{x,L}⊨{SMSReal[x$$],SMSReal[L$$]};
ui⊨SMSReal[Array[u$$[#1] & ,3]];
Ni⊨{(x/L),1-(x/L),(x/L)(1-(x/L))};
u⊨Ni.ui;
f⊨(u^2);
g⊨SMSD[f,ui];
struct⊨SMSD[g,ui];

struct

analyze structure and find pattern inside the structure that can be used to compress the structure into vector. Function returns data that can be used to compress or uncompress structures.

structCompressed=SMSCompress[struct];

returns the length of vector into which the structure is compressed

structCompressed["Length"]

returns uncompress structure accordingly to the given signature

structUncompressed=SMSUncompress[structCompressed]

returns uncompressed compressedVector

compressedVector=Table[i,{i,6}]

SMSUncompress[structCompressed,compressedVector]

struct2 is original structure with symmetric element 2,1 set to zero.

otherStruct=ReplacePart[struct,{2,1}->0]

otherStruct is modified in such a way that otherStruct has the same pattern as struct, thus element 2,1 is set back to the original value

otherStructModified=SMSUncompress[structCompressed,otherStruct]

compress struct and export compressed vector into working vector c$$

structCompressed2=SMSCompress[struct,"Export"->Function[{i},c$$[i]]];

import compressed data from working vector c$$ and uncompress it

Table[Function[{i},c$$[i]][i],{i,6}]

structUncompressed2=SMSUncompress[structCompressed2,"Import"->True]

export element 2,1 obtained by various transformations

SMSExport[{struct[[2,1]],structUncompressed[[2,1]],otherStructModified[[2,1]],structUncompressed2[[2,1]]},k21$$];

SMSWrite[];

SMSInstallMathLink["Console"->False];

function returns element 2,1 obtained by various transformations and working vector c$$ used for compression. Note that only 6 elements of the working vector c$$ were used.

Test[{0.,1.,7.},π//N,10.]

Utility Functions for Numerical Environments

SMSIsDOFConstrained

SMSNoDummyNodes

SMSLastTrueNode

SMSLastTrueDOF

SMSIsDummyNode

SMSIsRealNode

Specialized Functions

Linear Algebra

Enormous growth of expressions typically appears when the SAC systems such as Mathematica are used directly for solving e.g. a system of linear algebraic equations analytically. It is caused mainly due to the redundant expressions, repeated several times. Although the operation is "local" by its nature, only systems with a small number of unknowns (up to 10) can be solved analytically.  When linear algebra operations are executed on numerical matrices, no expression growth appears, thus they can be applied on the matrices of  an arbitrary size.
With AceGen we can generate a code that evaluates linear algebra operations numerically or symbolically (closed form solution). Numerical solution is performed by calling the LAPACK linear algebra routines. If the code is generated for the AceFEM finite element environment, the necessary link is done automatically. For other cases the uses must provide the name of the routine and link the executable with an appropriate numerical library. 
In all closed form linear algebra routines it is assumed that the solution exist (det(A)≠0) and that no pivoting is needed. Pivoting is automatically done for the numerical  solution by LAPACK package.
The following routines are provided:

SMSLinearSolve

Parameter A is a square matrix. Parameter B can be a vector (one right-hand side) or a matrix (multiple right-hand sides). In the case of closed form solution, the Gauss elimination procedure is used without pivoting! Pivoting is automatically done for the numerical  solution by LAPACK package.

Example

This generates the FORTRAN code that returns the solution to the general linear system of equations:

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["Test",Real[a$$[4,4],b$$[4],x$$[4]]];
a⊢SMSReal[Table[a$$[i,j],{i,4},{j,4}]];
b⊢SMSReal[Table[b$$[i],{i,4}]];
x⊨SMSLinearSolve[a,b];
SMSExport[x,x$$];
SMSWrite[];

FilePrint["test.c"]

SMSEigensystem

Example

{σMain,σMainDirection}⊨SMSEigensystem[σ,"Solver"->"LAPACK","Symmetric"->True];

SMSLUFactor

The Gauss elimination procedure is used and simultaneous simplification is performed during the process. The SMSLUFactor performs the factorization of matrix A and returns a new matrix. The matrix generated by the SMSLUFactor is a compact way of storing the information contained in the upper and lower triangular matrices of the factorization.

SMSLUSolve

The Gauss elimination procedure is used and simultaneous simplification is performed during the process.  Parameter B can be a vector (one right-hand side) or a matrix (multiple right-hand sides).

SMSFactorSim

The Gauss elimination procedure is used and simultaneous simplification is performed during the process. The SMSFactorSim performs factorization of the matrix A and returns a new matrix. The matrix generated by the SMSFactorSim is a compact way of storing the information contained in the upper and lower triangular matrices of the factorization.

SMSInverse

Simultaneous simplification is performed during the process. The Krammer's rule is used and simultaneous simplification is performed during the process. For more than  6 equations is more efficient to use SMSLinearSolve[M,IdentityMatrix[M//Length]] instead.

SMSDet

Simultaneous simplification is performed during the process.

SMSKrammer

The Krammer's rule is used and simultaneous simplification is performed during the process.

SMSEigenvalues

All eigenvalues have to be real numbers. Solution is obtained by solving a general characteristic polynomial. Ill-conditioning around multiple zeros as well as wrong derivatives can occur!! In general, it is advisable to avoid the formulations that involve eigenvalues and use formulations based on matrix functions as described in Matrix Functions.

SMSInvariantsI

SMSInvariantsJ

SMSRotationMatrix

Tensor Algebra

Transformations (Subscript[ϕ, 1]),(Subscript[ϕ, 2]),(Subscript[ϕ, 3]) are arbitrary functions of independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]). Independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]) have to be proper auxiliary variables with unique signature (see also SMSD).

Example: Cylindrical coordinates

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica"];
SMSModule["test"];
{r,ϕ,z}⊨Array[SMSFictive[]&,{3}];
SMSCovariantBase[{r Cos[ϕ],r Sin[ϕ],z},{r,ϕ,z}]//MatrixForm

Transformations (Subscript[ϕ, 1]),(Subscript[ϕ, 2]),(Subscript[ϕ, 3]) are arbitrary functions of independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]). Independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]) have to be proper auxiliary variables with unique signature (see also SMSD).

Example: Cylindrical coordinates

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica"];
SMSModule["test"];
{r,ϕ,z}⊨Array[SMSFictive[]&,{3}];
SMSCovariantMetric[{r Cos[ϕ],r Sin[ϕ],z},{r,ϕ,z}]//MatrixForm

Transformations (Subscript[ϕ, 1]),(Subscript[ϕ, 2]),(Subscript[ϕ, 3]) are arbitrary functions of independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]). Independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]) have to be proper auxiliary variables with unique signature (see also SMSD).

Example: Cylindrical coordinates

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica"];
SMSModule["test"];
{r,ϕ,z}⊨Array[SMSFictive[]&,{3}];
SMSContravariantMetric[{r Cos[ϕ],r Sin[ϕ],z},{r,ϕ,z}]//MatrixForm

Transformations (Subscript[ϕ, 1]),(Subscript[ϕ, 2]),(Subscript[ϕ, 3]) are arbitrary functions of independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]). Independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]) have to be proper auxiliary variables with unique signature (see also SMSD).

Example: Cylindrical coordinates

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica"];
SMSModule["test"];
{r,ϕ,z}⊨Array[SMSFictive[]&,{3}];
SMSChristoffell1[{r Cos[ϕ],r Sin[ϕ],z},{r,ϕ,z}]//MatrixForm

Transformations (Subscript[ϕ, 1]),(Subscript[ϕ, 2]),(Subscript[ϕ, 3]) are arbitrary functions of independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]). Independent variables (Subscript[η, 1]),(Subscript[η, 2]),(Subscript[η, 3]) have to be proper auxiliary variables with unique signature (see also SMSD).

Example: Cylindrical coordinates

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica"];
SMSModule["test"];
{r,ϕ,z}⊨Array[SMSFictive[]&,{3}];
SMSChristoffell2[{r Cos[ϕ],r Sin[ϕ],z},{r,ϕ,z}]//MatrixForm

Transformations transf are arbitrary functions while coordinates coord have to be proper auxiliary variables with the unique signature (see also SMSD). The type of tensor indices is specified by the array index_types where True means covariant index and False contravariant index.

Example: Cylindrical coordinates

Transform contravariant tensor (u^i)={(r^2),r  Sin[ϕ],r z} defined in cylindrical coordinates {r,ϕ,z} into Cartesian coordinates.

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica"];
SMSModule["test"];
{r,ϕ,z}⊨Array[SMSFictive[]&,{3}];
SMSTensorTransformation[{(r^2),r Sin[ϕ],r z},{r Cos[ϕ],r Sin[ϕ],z},{r,ϕ,z},{False}]

Transformations transf are arbitrary functions while coordinates coord have to be proper auxiliary variables with unique signature (see also SMSD). The type of tensor indices is specified by the array index_types where True means covariant index and False contravariant index. 
The SMSDCovariant function accepts the same options as SMSD function.

Example: Cylindrical coordinates

Derive covariant derivatives (u^i)(Subscript[|, j]) of contravariant tensor (u^i)={(r^2),r  Sin[ϕ],r z} defined in cylindrical coordinates {r,ϕ,z}.

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica"];
SMSModule["test"];
{r,ϕ,z}⊨Array[SMSFictive[]&,{3}];
SMSDCovariant[{(r^2),r Sin[ϕ],r z},{r Cos[ϕ],r Sin[ϕ],z},{r,ϕ,z},{False}]//MatrixForm

Matrix Functions

Options for matrix functions.

Examples

A) Matrix exponential

Create MathLink program that calculates matrix exponential.

<<AceGen`;
SMSInitialize["ExpM","Environment"->"MathLink"];
SMSModule["ExpM",Real[M$$[3,3],EM$$[3,3]],"Input"->M$$,"Output"->EM$$];
M0⊢SMSReal[Array[M$$,{3,3}]];
EM⊨SMSMatrixExp[M0,0];
SMSExport[EM,EM$$];
SMSWrite[];
SMSInstallMathLink["ExpM","Console"->True];

Test: calculate (e^I).

M={{1,0,0},{0,1,0},{0,0,1}};
ExpM[M]//MatrixForm
MatrixExp[M]//MatrixForm

B) Matrix power and its first derivative

Create MathLink program that calculates (M^p) together with its first derivative.

<<AceGen`;
SMSInitialize["PowerM","Environment"->"MathLink"];
SMSModule["PowerM",Real[M$$[3,3],p$$,EM$$[3,3],DEM$$[3,3,3,3]],"Input"->{M$$,p$$},"Output"->{EM$$,DEM$$}];
M0⊢SMSReal[Array[M$$,{3,3}]];
p⊢SMSReal[p$$];
EM⊨SMSMatrixPower[M0,p,1];
SMSExport[EM,EM$$];
DEM⊨SMSD[EM,M0];
SMSExport[DEM,DEM$$];
SMSWrite[];
SMSInstallMathLink["PowerM","Console"->True];

Test: calculate (((2I))^3.5) and its first derivatives.

M=2{{1,0,0},{0,1,0},{0,0,1}};
{powerM,dpowerM}=PowerM[M,3.5];

powerM//MatrixForm

MatrixPower[M,3.5]//MatrixForm

dpowerM//MatrixForm

Numerical Root Finding

Contents

Numerical root finding of scalar function

Numerical root finding of a system of nonlinear equations

Numerical root finding of a system of nonlinear, path dependent, parameterized equations

Numerical root finding of scalar function

Function SMSFindRoot returns a vector:
{
x - calculated root,
True if convergence was obtained and False if not,
number of iteration for scalar function or  number of sub-steps for parameterized nonlinear system
}

The returned root x is an auxiliary variable. When implicit derivatives are required (option "Derivatives") differentiation exceptions are attached to the x  that define first and optionally second order derivatives of x with respect to given implicit variables (option  "ImplicitVariables").

General options.

Example

calculate root of equation a x^3+ b x+c together with its first and second derivative with respect to a, b, and c

<<AceGen`;

SMSInitialize["tmptest","Environment"->"MathLink"];
SMSModule["test",Real[a$$,b$$,c$$,x0$$,tol$$,x$$,dxdfi$$[3],d2xdfi2$$[3,3]],Integer[maxNR$$,NR$$],"Input"->{a$$,b$$,c$$,x0$$,tol$$,maxNR$$},"Output"->{x$$,dxdfi$$,d2xdfi2$$,NR$$}];
{a,b,c,tol}⊢SMSReal[{a$$,b$$,c$$,tol$$}];
x⫤SMSReal[x0$$];

ϕ={a,b,c};
maxNR⊢SMSInteger[maxNR$$];
{x,conv,NR}⊨SMSFindRoot[a x^3+ b x+c,{x,x},"Derivatives"->2,"MaxIterations"->maxNR,"Tolerance"->tol];
SMSExport[x,x$$];

Δx⊨SMSD[x,ϕ];
SMSExport[Δx,dxdfi$$];
ΔΔx⊨SMSD[Δx,ϕ];
SMSExport[ΔΔx,d2xdfi2$$];
SMSExport[NR,NR$$];
SMSWrite[];

SMSInstallMathLink["Console"->False]

test[1,1,1,-0.68,10.^-12,10]

verification

x=.;
rr=Solve[aa x^3+bb x+cc==0,x][[1,1,2]]

dd=D[rr,{{aa,bb,cc}}];

ddd=D[dd,{{aa,bb,cc}}];

{rr,dd,ddd}/.{aa->1.,bb->1,cc->1}

Numerical root finding of a system of nonlinear equations

Given pure function must return for the given input parameters {h,hn,λ} the following vector:
{
Q … vector of equations
,data - arbitrary data
}

Function  SMSFindRoot returns a vector:
{
h calculated root (Q(h)=0),
depending on reqired derivatives:
	Null =>if only root is required
	((∂h)/(∂r)) => first derivatives of the root with respect to given set of implicit variables
True if convergence was obtained and False if not,
number of iterations performed,
data - an arbitrary data returned by the given pure function
}

Options for the solution of system of equations.

Example:  Axisymmetric, finite strain elasto-plastic element .

Example

Generate and verify the MathLink program that returns solution to the system of nonlinear equations:
Φ=(({{a x y+(x^3)=0}, {a-x (y^2)=0}}))
where x and y are unknowns and a is parameter.

<<AceGen`;
SMSInitialize["test","Environment"->"MathLink"];
SMSModule["test",Real[x$$,y$$,a$$,tol$$,dx$$,dy$$],Integer[n$$],
"Input"->{x$$,y$$,a$$,tol$$,n$$},
"Output"->{x$$,y$$,dx$$,dy$$}];
{x0,y0,a,ϵ}⊢SMSReal[{x$$,y$$,a$$,tol$$}];
nmax⊢SMSInteger[n$$];
{{xc,yc},dx,conv,niter,data}=SMSFindRoot[
Function[{h},
{x,y}=h;
{{a x y+(x^3),a - x (y^2)},Null}
]
,{x0,y0}
,"MaxIterations"->nmax
,"Tolerance"->ϵ
,"Derivatives"->1
,"ImplicitVariables"->{a}
];
SMSIf[Not[conv],SMSPrintMessage["no convergence"];];
SMSExport[{xc,yc},{x$$,y$$}];
SMSExport[dx//Flatten,{dx$$,dy$$}];
SMSWrite[];

Here the MathLink program test.exe is build from the generated source code and installed so that functions defined in the source code can be called directly from Mathematica. (see also SMSInstallMathLink)

SMSInstallMathLink[]

For the verification of the generated code the solution calculated by the build in function is compared with the solution calculated by the generated code.

test[1.9,-1.2,3.,0.0001,10]

x=.;y=.;a=.;
sol=Solve[{a x y+(x^3)==0,a- x (y^2)==0},{x,y}]

{sol[[1]],D[sol[[1]],a]}/.a->3.

Numerical root finding of a system of nonlinear, path dependent, parameterized equations

Given pure function must return for the given input parameters (h,(Subscript[h, n]),λ) the following vector:
{Q(h,(Subscript[h, n]),λ) … vector of equations
,f(h,(Subscript[h, n]),λ)  ... if f(h,(Subscript[h, n]),λ)=True then Q(h,(Subscript[h, n]),λ)=0 else h=(Subscript[h, n])
,p(h,(Subscript[h, n]),λ)   ...  if p(h,(Subscript[h, n]),λ)=False then step cutting is performed regardless on convergence (solution is not acceptable from the physical point of view)
,an arbitrary data
}

Function  SMSFindRoot returns a vector:
{
h - calculated root,
∂h/∂r - derivatives of the root with respect to given set of implicit variables, 
expression that yields True if the problem was solved and False if not,
actual number of sub-steps performed,
the last arbitrary data returned by given user function
}

Options for the solution of parameterized system of equations.

Example: elasto - plastic problems

Let 𝕗(h,(Subscript[h, n])) be a yield function, (Subscript[ϵ, k]) and (Subscript[ϵ, k+1]) total strains at the last converged global step k and current step k+1, then for the last calculated local sub-step n and the current local sub-step n+1, a set of time discretized plastic evolution equations Q and corresponding state variables h is given by:
ϵ=λ (Subscript[ϵ, k+1])+(λ-1)(Subscript[ϵ, k]) ... parameterization of local plastic equations
σ=σ(ϵ-(ϵ^p));
 𝒵=(ϵ^p)-(Subscript[ϵ, n]^p)-((Subscript[λ, m])-(Subscript[λ, m,n])) (∂𝕗/∂σ)
Q={(Subscript[𝒵, 1,1]),(Subscript[𝒵, 2,2]),(Subscript[𝒵, 3,3]),(Subscript[𝒵, 1,2]),(Subscript[𝒵, 1,3]),(Subscript[𝒵, 2,3]), 𝕗}=0
h={(Subscript[ϵ, 1,1]^p),(Subscript[ϵ, 2,2]^p),(Subscript[ϵ, 3,3]^p),(Subscript[ϵ, 1,2]^p),(Subscript[ϵ, 1,3]^p),(Subscript[ϵ, 2,3]^p),(Subscript[λ, m])}

The sub-step is in elastic regime when 𝕗(h,(Subscript[h, n]))<0. In that case h=(Subscript[h, n])  leading to additional condition f(h,(Subscript[h, n]))=𝕗(h,(Subscript[h, n]))<0.

Plastic process is dissipative leading to additional condition on physical admissibility of the solution  p(h,(Subscript[h, n]))=(Subscript[λ, m])-(Subscript[λ, m,n])>0.

For the actual AceGen inputs look at the elasto-plastic elements available in AceShare.

Mechanics of Solids

Transformations of mechanical constants in mechanics of solids.

This transforms Lame's constants λ, G to Hooke's constants E, ν. No simplification is preformed!

SMSLameToHooke[λ,G]//Simplify

Find constitutive matrices for the linear elastic formulations in mechanics of solids.

This returns the plane stress constitutive matrix. No simplification is preformed!

SMSPlaneStressMatrix[e,ν]//MatrixForm

Advanced Features

User Defined Functions

Contents

General Description

SMSCall

Examples

Intrinsic user function 1: Scalar function exists but has different syntax in source code language

Intrinsic user function 2: Scalar function with closed form definition of the function and its derivatives

User AceGen module 1: Definition of the user subroutine and first derivatives

User AceGen module 2: Definition of the user subroutine and first and second derivatives

User external subroutines 1: Source code file added to the generated source code

User external subroutines 2: Header file added to the generated source code file

Embeded sequence with SMSVerbatim command: User defined source code is embedded into generated source code

MathLink program with modules

General Description

The user can define additional output formats for standard Mathematica functions or new functions. The advantage of properly defined function is that allows optimization of expressions and differentiation. In general there are several types of user defined functions supported in AceGen:

Intrinsic user function is scalar function of scalar input parameters with closed form definition of the function and its derivatives that can be expressed with the existing Mathematica functions. The definition of the intrinsic user function becomes an integral part of Mathematica and AceGen. Thus, a full optimization of the derived expressions and unlimited number of derivatives is provided.

User defined AceGen module is arbitrary subroutine with several input/output parameters of various types generated with AceGen within the same AceGen session as the main module. All AceGen modules generated within the same AceGen session are automatically written into the same source file and the proper definitions and declarations of input/output parameters are also included automatically. The user AceGen module can be called from the main module using the SMSCall command. Optimization of expressions is performed only within the module. Differentiation is not supported unless derivatives are also derived and exported to main module.

User defined external subroutines: External subroutines are arbitrary subroutines with several input/output parameters of various types written in source code language and provided by the user. The user defined external subroutines can be called from the main module using the SMSCall command in a same way as user AceGen module. The "System"->False option has to be included in order to signify that the subroutine has not been generated by AceGen. For the generation of the final executable we have two options:

The source code file can be incorporated into the generated source code file using the "Splice" option of the SMSWrite command. The original source code file of the user subroutine is not needed for the compilation.

Alternatively one can include only the header file containing the declaration of the function accordingly to the chosen source code language using the "IncludeHeaders" option of the SMSWrite command. The original source code of the external subroutine has to be compiled separately and linked together with the AceGen generated file.

Embedded sequences: User can embed the sequence of the code in chosen language with the use of SMSVerbatim command.

See also:  Elements that Call User External Subroutines.

SMSCall

The name of the subroutine can be arbitrary string. The SMSCall command inserts into the generated source code the call to the external subroutine "sub" with the given set of input and output parameters. The input parameters can be arbitrary expressions. The input and output arguments are always passed to functions by reference (pointers not values!). The input and output parameters are defined as local variables of the master subroutine unless they are I/O arguments of the master subroutine. No dynamic allocation is performed inside the subroutine, thus arrays must have known constant length. The only exceptions are I/O parameters that are at the same time also I/O parameters of the master subroutine.

Some examples of declarations of input parameters.

Some examples of declarations of output parameters.

Some examples of declarations of arbitrary type and form I/O parameters.

The use of output parameters later in the program and their declaration should follow AceGen rules for the declaration and use of external variables as described in chapter Symbolic-Numeric Interface (e.g. x⊨SMSReal[x$$,"Subordinate"->sc], ni⊨SMSInteger[i$$[5],"Subordinate"->sc], b⊨SMSLogical[b$$,"Subordinate"->sc]). The proper order of evaluation of expressions is assured by the "Subordinate"->sc option where the parameter sc is an auxiliary variable that represents the call of external subroutine. Additionally, the partial derivatives of output parameters with respect to input parameters can be defined by the option "Dependency"  as described in SMSFreeze.

Examples

Intrinsic user function 1: Scalar function exists but has different syntax in source code language

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];

This is an additional definition of output format for function tangent.

SMSAddFormat[
Tan[i_]:>Switch[SMSLanguage,"Mathematica","Tan"[i],"Fortran","dtan"[i],"C","tan"[i]]
];

SMSModule["sub1",Real[x$$,y$$[5]]];
x⊢SMSReal[x$$];
SMSExport[Tan[x],y$$[1]];
SMSWrite[];

The final code can also be formatted by the "Substitutions" option of the SMSWrite command.

FilePrint["test.f"]

IMPORTANT: Differentiation is not supported for the User AceGen module and User external subroutines unless derivatives are derived within the user subroutine explicitly and exported into the main module through the output parameters of the module (see example below). Consequently, if the first derivatives are not derived and exported to the main module, then the first  derivatives (and all higher derivatives as well) will be 0. If the first derivatives are defined and higher derivatives are not then in general the higher derivatives of the general function can be nonzero (see example below), however they are incorrect. NO WARNING is given about the possibility of incorrect derivatives.

Intrinsic user function 2: Scalar function with closed form definition of the function and its derivatives

This adds alternative definition of Power function MyPower[x,y]≡(x^y) that assumes that x>0 and
D[MyPower[x,y],x] = y ((MyPower[x,y])/x),
D[MyPower[x,y],y] =  MyPower[x,y]  Log[x].

<<AceGen`;
SMSInitialize["test","Language"->"C"];

This is an additional definition of output format for function MyPower.

SMSAddFormat[MyPower[i_,j_]:>Switch[SMSLanguage,"Mathematica",i^j,"Fortran",i^j,"C","Power"[i,j]]
];

Here the derivatives of MyPower with respect to all parameters are defined.

Unprotect[Derivative];
Derivative[1,0][MyPower][i_,j_]:=j MyPower[i,j]/i;
Derivative[0,1][MyPower][i_,j_]:=MyPower[i,j] Log[i];
Protect[Derivative];

Here is defined the numerical evaluation of MyPower with the p-digit precision.

N[MyPower[i_,j_],p_]:=i^j;

SMSModule["sub1",Real[x$$,y$$,z$$]];
x⊢SMSReal[x$$];
y⊢SMSReal[y$$];

SMSExport[SMSD[MyPower[x,y],x],z$$];

SMSWrite[];

FilePrint["test.c"]

User AceGen module 1: Definition of the user subroutine and first derivatives

<<AceGen`;
SMSInitialize["test","Language"->"C"];

This generates user AceGen module f=Sin((Subscript[a, 1])x+(Subscript[a, 2])x^2+(Subscript[a, 3])(x^3)) with an input parameter x and constants a[3] and the output parameters y=f(x) and first dy=((∂f)/(∂x)) derivatives.

SMSModule["f",Real[x$$,a$$[3],y$$,dy$$]];
x⊢SMSReal[x$$];
{a1,a2,a3}⊢SMSReal[Table[a$$[i],{i,3}]];
y⊨Sin[a1 x+a2 (x^2)+a3 (x^3)];
dy⊨SMSD[y,x];
SMSExport[y,y$$];
SMSExport[dy,dy$$];

This generates subroutine mf that calls subroutine f.

SMSModule["mf",Real[w$$,r$$]];
w⊢SMSReal[w$$];

This use of ⊢ operator here is obligatory to ensure that auxiliary variables is generated that can be used later for the definition of the partial derivatives.

z⊢w^2;

The SMSCall commands inserts into the generated source code the call of external subroutine with the given set of input and output parameters. All the arguments are passed to subroutine by reference (pointer). Input arguments are first assigned to an additional auxiliary variables before they are passed to subroutine. SMSCall returns auxiliary variable fo that represents the call of external subroutine f .

fo=SMSCall["f",z,{1/2,1/3,1/4},Real[y$$],Real[dy$$]];

The SMSReal is used here to import the output parameters of the subroutine to AceGen. The option "Subordinate" is necessary to ensure that the call to f is executed before the output parameters are imported.

dfdz⊢SMSReal[dy$$,"Subordinate"->fo];

The "Dependency"->{sin,{x,dy}} option defines that output parameter y depends on input parameter x and defines partial derivative of y with respect to input parameter x. By default all first partial derivatives of output parameters with respect to input parameters are set to 0.

f⊢SMSReal[y$$,"Subordinate"->fo,"Dependency"->{z,dfdz}];

First derivatives are derived and displayed here.

dw⊨SMSD[f,w];
SMSRestore[dw,"Global"]

Second derivatives are derived and displayed here. It is obvious that the second derivatives are incorrect, due to the lack of proper definition of the second derivative of f with respect to z.

ddw=SMSD[dw,w];
SMSRestore[ddw,"Global"]

SMSExport[dw,dy$$];
SMSWrite[];

FilePrint["test.c"]

User AceGen module 2: Definition of the user subroutine and first and second derivatives

This generates user AceGen module f=Sin((Subscript[a, 1])x+(Subscript[a, 2])x^2+(Subscript[a, 3])(x^3)) with an input parameter x and constants a[3] and the output parameters y=f(x) and first dy=((∂f)/(∂x)) and second ddy=(((∂^2)f)/(∂(x^2))) derivatives.

<<AceGen`;
SMSInitialize["test","Language"->"C"]; 

SMSModule["f",Real[x$$,a$$[3],y$$,dy$$,ddy$$]];
x⊢SMSReal[x$$];
{a1,a2,a3}⊢SMSReal[Table[a$$[i],{i,3}]];
y⊨Sin[a1 x+a2 (x^2)+a3 (x^3)];
dy⊨SMSD[y,x];
ddy⊨SMSD[y,x];
SMSExport[{y,dy,ddy},{y$$,dy$$,ddy$$}];

SMSModule["main",Real[w$$,r$$]];
w⊢SMSReal[w$$];
z⊢w^2;
fo=SMSCall["f",z,{1/2,1/3,1/4},Real[y$$],Real[dy$$],Real[ddy$$]];

dfdz2⊢SMSReal[ddy$$,"Subordinate"->fo];
dfdz⊢SMSReal[dy$$,"Subordinate"->fo,"Dependency"->{z,dfdz2}];
f⊢SMSReal[y$$,"Subordinate"->fo,"Dependency"->{z,dfdz}];
dw⊨SMSD[f,w];
ddw=SMSD[dw,w];

Both first and second derivatives are correct.

SMSRestore[{dw,ddw},"Global"]

SMSExport[{dw,ddw},{dy$$,ddy$$}];

SMSWrite[];

FilePrint["test.c"]

User external subroutines 1: Source code file added to the generated source code

Lets create the C source file "Energy.c" with the following contents

Export["Energy.c",
"void Energy (double *I1p, double *I3p, double *C1p, double *C2p,
  	double *C3p, double *pi, double dp[2], double ddp[2][2])
{
 	double I1, I3, C1, C2, C3;
  	I1 = *I1p; I3 = *I3p; C1 = *C1p; C2 = *C2p; C3 = *C3p;
  	*pi = (C2*(-3 + I1))/2. + (C1*(-1 + I3 - log (I3)))/4. - (C2*log (I3))/2.;
  	dp[0] = C2/2.;
  	dp[1] = (C1*(1 - 1/I3))/4. - C2/(2.*I3);
  	ddp[0][0] = 0;
  	ddp[0][1] = 0;
  	ddp[1][0] = 0;
  	ddp[1][1] = C1/(4.*I3*I3) + C2/(2.*I3*I3);
 }","Text"]

and the C header file "Energy.h" with the following contents

Export["Energy.h"," void Energy (double *I1p, double *I3p, double *C1p, double *C2p,
   double *C3p, double *pi, double dp[2], double ddp[2][2])","Text"];

Subroutine Energy calculates the strain energy Π(I1,I3) where I1 and I3 are first and third invariant of the right Cauchy-Green tensor and first and second derivative of the strain energy with respect to the input parameters I1 and I2.

This generates subroutine Stress with an input parameter right Cauchy-Green tensor C that returns Second Piola-Kirchoff stress tensor S. Stress tensor corresponds to the  arbitrary strain energy function given by source code file Energy.c. The user supplied source code is added to the generated source code file.

<<AceGen`;
SMSInitialize["test","Language"->"C"]; 
SMSModule["Stress",Real[C$$[3,3],S$$[3,3],C1$$,C2$$,C3$$]];
{C1,C2,C3}⊢SMSReal[{C1$$,C2$$,C3$$}];
ℂ⊢SMSReal[Table[C$$[i,j],{i,3},{j,3}]];
ℂ[[2,1]]=ℂ[[1,2]];ℂ[[3,1]]=ℂ[[1,3]];ℂ[[3,2]]=ℂ[[2,3]];
{I1,I3}⊢{Tr[ℂ],Det[ℂ]};
pcall=SMSCall["Energy",I1,I3,C1,C2,C3,Real[pi$$],Real[dp$$[2]],Real[ddp$$[2,2]],"System"->False];
ddp⊢SMSReal[Table[ddp$$[i,j],{i,2},{j,2}],"Subordinate"->pcall];
dp⊢SMSReal[Table[dp$$[i],{i,2}],"Subordinate"->pcall,"Dependency"->{{I1,I3},ddp}];
Π⊢SMSReal[pi$$,"Subordinate"->pcall,"Dependency"->{{I1,dp[[1]]},{I3,dp[[2]]}}];
S⊨2SMSD[Π,ℂ,"Symmetric"->True];
SMSExport[S,S$$];
SMSWrite["Splice"->{"Energy.c"}];

FilePrint["test.c"]

User external subroutines 2: Header file added to the generated source code file

Previous example is here modified in a way that only the header file "Energy.h" is added to the generated source code file.

<<AceGen`;
SMSInitialize["test","Language"->"C"]; 
SMSModule["main",Real[C$$[3,3],S$$[3,3],C1$$,C2$$,C3$$]];
{C1,C2,C3}⊢SMSReal[{C1$$,C2$$,C3$$}];
ℂ⊢SMSReal[Table[C$$[i,j],{i,3},{j,3}]];
ℂ[[2,1]]=ℂ[[1,2]];ℂ[[3,1]]=ℂ[[1,3]];ℂ[[3,2]]=ℂ[[2,3]];
{I1,I3}⊢{Tr[ℂ],Det[ℂ]};
pcall=SMSCall["Energy",I1,I3,C1,C2,C3,Real[pi$$],Real[dp$$[2]],Real[ddp$$[2,2]],"System"->False];
ddp⊢SMSReal[Table[ddp$$[i,j],{i,2},{j,2}],"Subordinate"->pcall];
dp⊢SMSReal[Table[dp$$[i],{i,2}],"Subordinate"->pcall,"Dependency"->{{I1,I3},ddp}];
Π⊢SMSReal[pi$$,"Subordinate"->pcall,"Dependency"->{{I1,dp[[1]]},{I3,dp[[2]]}}];
S⊨2SMSD[Π,ℂ,"Symmetric"->True];
SMSExport[S,S$$];
SMSWrite["IncludeHeaders"->{"Energy.h"}];

FilePrint["test.c"]

Embeded sequence with SMSVerbatim command: User defined source code is embedded into generated source code

Here is the part of the previously defined subroutine Energy.c embedded directly into the generated source code. The Verbatim command is used for that purpose where an additional option "DeclareSymbol" adds declarations of the local variables that are used within the code. The embedded part calculates the strain energy Π(I1,I3) and first derivative of the strain energy with respect to the invariants I1 and I2.

<<AceGen`;
SMSInitialize["test","Language"->"C"]; 
SMSModule["Stress",Real[C$$[3,3],S$$[3,3],C1$$,C2$$,C3$$]];
{C1,C2,C3}⊢SMSReal[{C1$$,C2$$,C3$$}];
ℂ⊢SMSReal[Table[C$$[i,j],{i,3},{j,3}]];
ℂ[[2,1]]=ℂ[[1,2]];ℂ[[3,1]]=ℂ[[1,3]];ℂ[[3,2]]=ℂ[[2,3]];
{I1,I3}⊢{Tr[ℂ],Det[ℂ]};

pcode=SMSVerbatim[
"I1c=",I1,";I3c=",I3,";\nC1c=",C1,";C2c=",C2,";C3c=",C3,";",
"\npi = (C2c*(-3 + I1))/2. + (C1c*(-1 + I3c - log(I3c)))/4. - (C2c*log(I3c))/2.;
dp[0] = C2c/2.;
dp[1] = (C1c*(1 - 1/I3c))/4. - C2c/(2.*I3c)"
,"DeclareSymbol"->{Real[C1c$$,C2c$$,C3c$$,I1c$$,I3c$$,pi$$,dp$$[2]]}];

dp⊢SMSReal[Table[dp$$[i],{i,2}],"Subordinate"->pcode];

Π⊢SMSReal[pi$$,"Subordinate"->pcode,"Dependency"->{{I1,dp[[1]]},{I3,dp[[2]]}}];

S⊨2SMSD[Π,ℂ,"Symmetric"->True];
SMSExport[S,S$$];
SMSWrite[];

FilePrint["test.c"]

MathLink program with modules

<<AceGen`;
SMSInitialize["test","Environment"->"MathLink"];

This generates the user AceGen module "f" that defines function f(x)=(∑_(i=1)^n)(Subscript[a, i])(x^(i-1)) with an input parameters x, n, and a vector of coefficients a and output parameters y=f(x), first derivative dy=((∂f)/(∂x)) and second derivative ddy=(((∂^2)f)/(∂(x^2))).

SMSModule["f",Real[x$$,a$$["*"]],Integer[n$$],Real[y$$,dy$$,ddy$$]];
x⊢SMSReal[x$$];
n⊢SMSInteger[n$$];
y⫤0;
SMSDo[
y⊣y+SMSReal[a$$[i]] (x^(i-1));
,{i,1,n,1,y}];
dy⊨SMSD[y,x];
ddy⊨SMSD[dy,x];
SMSExport[{y,dy,ddy},{y$$,dy$$,ddy$$}];

Definition of the MathLink module "mlinkA" that evaluates function y=f((e^w)) and returns second derivative ddw=(((∂^2)f((e^w)))/(∂(w^2))) for a constant set of coefficients a={1/2,1/3,1/4}.

SMSModule["mlinkA",Real[w$$,ddw$$],"Input"->w$$,"Output"->ddw$$];
w⊢SMSReal[w$$];
z⊢Exp[w];
fcall=SMSCall["f",z,{1/2,1/3,1/4},SMSInteger[3],Real[y$$],Real[dy$$],Real[ddy$$]];
dfdz2⊢SMSReal[ddy$$,"Subordinate"->fcall];
dfdz⊢SMSReal[dy$$,"Subordinate"->fcall,"Dependency"->{z,dfdz2}];
f⊢SMSReal[y$$,"Subordinate"->fcall,"Dependency"->{z,dfdz}];
dw⊨SMSD[f,w];
ddw=SMSD[dw,w];
SMSExport[ddw,ddw$$];

Definition of the MathLink module "mlinkB" that evaluates function y=f((e^w)) and returns second derivative ddw=(((∂^2)f((e^w)))/(∂(w^2))) for arbitrary set of coefficients given as an argument of "mlinkB" function.

SMSModule["mlinkB",Real[w$$,a$$["*"]],Integer[n$$],Real[ddw$$],"Input"->{w$$,a$$,n$$},"Output"->ddw$$];
w⊢SMSReal[w$$];
z⊢Exp[w];
n⊢SMSInteger[n$$];
fcall=SMSCall["f",z,Real[a$$["*"]],n,Real[y$$],Real[dy$$],Real[ddy$$]];
dfdz2⊢SMSReal[ddy$$,"Subordinate"->fcall];
dfdz⊢SMSReal[dy$$,"Subordinate"->fcall,"Dependency"->{z,dfdz2}];
f⊢SMSReal[y$$,"Subordinate"->fcall,"Dependency"->{z,dfdz}];
dw⊨SMSD[f,w];
ddw=SMSD[dw,w];
SMSExport[ddw,ddw$$];

SMSWrite[];

SMSInstallMathLink["test","Console"->True]

Test with MMA for w=2.5

w=.;x=Exp[w];D[{1/2,1/3,1/4}.{1,x,(x^2)},w,w]/.w->2.5

"mlinkA" and "mlinkB" give correct results.

mlinkA[2.5]

mlinkB[2.5,{1/2,1/3,1/4}//N,3]

Results is correct even when the length of a is more than 3, provided that only 3 coefficients are used.

mlinkB[2.5,{1/2,1/3,1/4,1/5,1/6}//N,3]

Arrays

Contents

General Description

SMSArray

Manipulating  Arrays

SMSPart

SMSReplacePart

SMSArrayLength

SMSDot

SMSSum

General Description

One can use all Mathematica built-in functions or any of the external Mathematica packages to perform those operations. Mathematica only supports integer indices (e.g. in expression M[[index]] index has to have integer value assigned at the time of evaluation) and the array M has to have explicit value assigned before the evaluation (e.g. M={1,2,3,4}). If either M has no value assigned yet or the index is not an integer number the matrix operations cannot be performed in Mathematica directly. The result of matrix operation in Mathematica is always a closed form solution for each component of the array. After the matrix operation is performed, one can optimize the result by using AceGen optimization capabilities. For each component of the array a new auxiliary variable is created (if necessary) that stores a closed form solution of the specific component (see e.g.  Introduction). For example:

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$[5]],Integer[i$$]];
x⊢SMSReal[x$$];
i⊢SMSInteger[i$$];

Here a standard Mathematica vector is defined and a vector of new auxiliary variables is created to store the result.

X⊢Table[SMSReal[x$$[i]],{i,5}]

Here the third component of the vector X is displayed.

X[[3]]

Note that an arbitrary symbol cannot be used as an index together with Mathematica arrays.

X[[i]]

The Mathematica arrays can be fully optimized and they result in a numerically efficient code. However, if the arrays are large then the resulting code might become to large to be compiled. In this case one can use AceGen defined arrays. With the AceGen arrays one can express an array of expressions with a single auxiliary variable and to make a reference to an arbitrary or representative element of the array of expressions (see also Characteristic Formulae). Using the representative elements of the arrays instead of a full arrays will result in a much smaller code, however some optimization of the code might be prevented. Thus, one should use AceGen arrays only if they are absolutely necessary. Only one dimensional arrays (vectors) are currently supported in AceGen and only a following small set of operations is provided:

SMSArray - create a new AceGen array

SMSPart - take an arbitrary element of the array

SMSReplacePart - replace an arbitrary element of the array.  (WARNING: The SMSReplacePart command should be used only if it is absolutely necessary.)

SMSDot - dot product of two vectors

SMSSum - sum of all elements of the vector

AceGen supports two types of arrays:

Constant arrays: a constant array is an array of arbitrary expressions (e.g. X⊢SMSArray[{1,2,3400+x}]). All elements of the array are set to have given values.

General arrays: The elements of the general array have no default values. Only a necessary memory space is allocated on the global vector of formulas at the time of introduction of a general array (e.g.  M⫤SMSArray[10] allocates memory for the real array M with length 10 and SMSArray[M,10,π&] would allocates memory and initialize all elements of M to π). General arrays are always introduced as a multi-valued auxiliary variables.

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$[5]],Integer[i$$,n$$]];
x⊢SMSReal[x$$];i⊢SMSInteger[i$$];

Here a constant AceGen array is created. Result is a single auxiliary variable.

X⊢SMSArray[Table[SMSReal[x$$[k]],{k,5}]]

In this case, the third component of Sin[X] cannot be accessed by Mathematica since X is a symbol not an array.

X[[3]]

The third component of Sin[X] can be accessed by AceGen using SMSPart command.

SMSPart[X,3]

However, with AceGen one can access the i-th component of X as well. During the AceGen sessions the actual value of the index i is not known, only later, at the evaluation time of the program, the value of the index i becomes known.

SMSPart[X,i]

Here a general array M of length n is created with the values set to Sin[i π/n],i=1,...,n.

n⊢SMSInteger[n$$];
SMSArray[M,n,Sin[π #/n]&]

The third component of M can be accessed by AceGen using SMSPart command.

SMSPart[M,3]

Here, the 3-th element is not actually the 3-th element but an SMSIndexF object that points to the 3-th element.

SMSPart[M,4]//ToString

General i-th component of M.

SMSPart[M,i]

Here, the 3-th element is changed to Cos[2 π/n].

M⊣SMSReplacePart[M,Cos[3 π/n],3]

Arrays are physically stored at the end of the global vector of formulae. The dimension of the global vector (specified in SMSInitialize) is automatically extended in order to accommodate additional arrays. In the case of array with the length that cannot be calculated at the code generation time, the user have to specify the length of global vector with the "WorkingVectorSize" option of the SMSWrite command.

SMSArray

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,r$$,s$$,t$$],Integer[n$$,m$$]];
x⊢SMSReal[x$$];
n⊢SMSInteger[n$$];

Constant arrays: A constant array is represented in the final source code as a sequence of auxiliary variables and formulae. The SMSArray[{(Subscript[exp, 1]),(Subscript[exp, 2]),...}] function returns the array data object (head SMSGroupF). All elements of the array are set to have given values. If an array is required as auxiliary variable then we have to use one of the functions that introduces a new auxiliary variable (e.g. r⊢SMSArray[{1,2,3,4}]).

This creates the AceGen array object with constant contents. If we look at the result of the SMSArray function we can see that a single object has been created (Array[...]) representing the whole array of 4 real values.

SMSArray[{x,x^2,0,π}]

General arrays: Definition of the general array only allocates space on the global vector. An array data object (head SMSArrayF) represents an array together with the information regarding random evaluation. Reference to the particular or an arbitrary element of the array is represented by the data object with the array index object (head SMSIndexF).

The SMSArray[length] function returns the SMSArrayF data object. The elements of the array have no default values. The SMSArrayF  object HAS TO BE introduced as a new multi-valued auxiliary variable (e.g. r⫤SMSArray[10]). The value of the i-th element of the array can be set or changed by the SMSReplacePart[array, new value, i] command.

This allocates space on the global vector of formulae and creates a general AceGen array object of length n.  The values of the vector are NOT INITIALIZED.

SMSArray[n]

The SMSArray[M, length, func] function assigns a multi-valued auxiliary variable that represent array of length length to symbol M. The elements of the array are set to the values returned by the function func. Function func has to return a representative formula valid for the arbitrary element of the array.

Here a general array M of length n is created with the values initialized to Sin[i π/n],i=1,...,n. Note that command returns an auxiliary variable assigned to  symbol M.

SMSArray[M,n,Sin[π #/n]&]

The above command is equivalent to:

M⫤SMSArray[n];
SMSDo[
M⊣SMSReplacePart[M,i->Sin[π i/n]];
,{i,1,n,1,M}];
M

The length of the array is obtained by SMSArrayLength

SMSArrayLength[M]

The SMSArray[M, {n,length},func] function assigns n multi-valued auxiliary variables that points at the nth SMSArrayF data objects to symbol M. The elements of the array are set to the values returned by the function func. Function func has to return n representative formulae valid for the arbitrary elements of the arrays.

Manipulating Arrays

SMSPart, SMSReplacePart, SMSArrayLength

The argument array is an array data object defined by SMSArray function or an auxiliary variable that represents an array data object. The argument index is an arbitrary integer type expression. During the AceGen sessions the actual value of the index is not known, only later, at the evaluation time of the program, the actual value of the index becomes known. Consequently, AceGen assigns a new signature to the index data object in order to prevent false simplifications. The values are calculated as perturbed mean values of the expressions that form the array.
The SMSPart function does not create a new auxiliary variable. If an arbitrary element of the array is required as an auxiliary variable, then we have to use one of the functions that introduces a new auxiliary variable (e.g. r⊢SMSPart[{1,2,3,4},i]).

Example: SMSPart

SMSInitialize["test"];
SMSModule["test",Real[x$$,r$$],Integer[i$$]];
x⊢SMSReal[x$$];
i⊢SMSInteger[i$$];
g⊨SMSArray[{x,x^2,0,π}];
gi⊨SMSPart[g,i];
SMSExport[gi,r$$];
SMSWrite["test"];

FilePrint["test.m"]

Example: SMSReplacePart

SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,r$$],Integer[n$$]];
x⊢SMSReal[x$$];
n⊢SMSInteger[n$$];
SMSArray[M,n,Function[{i},i^2]];
M⊣SMSReplacePart[M,0,2];
SMSExport[SMSPart[M,1],r$$];
SMSWrite["test","WorkingVectorSize"->200];

FilePrint["test.c"]

SMSDot

Example

The task is to create a function that returns a dot product of the two vectors of expressions and the i-th element of the second vector.

This initializes the AceGen system and starts the description of the "test" subroutine.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,r$$,s$$],Integer[n$$,m$$]];
x⊢SMSReal[x$$];
n⊢SMSInteger[n$$];m⊢SMSInteger[m$$];

If an array is required as auxiliary variable then we have to use one of the functions that introduces a new auxiliary variable. Note that a single auxiliary variable has been created representing arbitrary element of the array. The signature of the array is calculated as perturbed average signature of all array elements.

A⊨SMSArray[{x,x^2,0,π}]

This creates the second  AceGen array object with constant contents.

B⊨SMSArray[{3 x,1+x^2,Sin[x],Cos[x π]}]

This calculates a dot product of vectors A and B

dot=SMSDot[A,B]

This creates an index to the n-th element of the second vector.

Bn=SMSPart[B,n]

The same can be obtained  with command

SMSExport[{dot,Bn},{r$$,s$$}];
SMSWrite["test"];

FilePrint["test.f"]

SMSSum

The argument is an array data object that represents an array of expressions (see Arrays). The signature of the result is sum of the signatures of the array components.

Manipulating Notebooks

Cell tags are used in Mathematica  to find notebook cells or classes of cells in notebook. The Add/Remove Cell Tags menu item opens a dialog box that allows you to add or remove cell tags associated with the selected cell(s). Mathematica attaches the specified cell tag to each of the selected notebook cells. The cell tags are not visible unless Show Cell Tags in the Cell Tags menu is checked. To search for cells according to their cell tags, you can use the Cell Tags submenu command.

The Mathematica mechanism of tagging cells is in AceGen used to find parts of the current notebook that contain the actual AceGen input. Selected parts are then evaluated. An unevaluated form of the selected parts is also stored into internal AceGen database for later creation of a new notebook that is composed of the parts of the notebook that were actually used to generate numerical subroutines. Selected part can also be modified before they are included into data base.

SMSEvaluateCellsWithTag

The SMSEvaluateCellsWithTag command finds and evaluates all cells with the specified tag.

Example:

Print["this is cell with the tag CELLTAG"];

<<AceGen`;
SMSInitialize["test", "Language" -> "C"]; 
SMSModule["sub1"];
SMSEvaluateCellsWithTag["CELLTAG"];

SMSRecreateNotebook

The SMSRecreateNotebook command creates a new notebook that includes an unevaluated contents of all the notebook cells that were evaluated by the SMSEvaluateCellsWithTag commands during the AceGen session. The first SMSEvaluateCellsWithTag call has to have option "CollectInputStart"->True in order to start the process of collecting the cells.

Example:

Print["This is cell with the tag CELLTAG-1."];

Print["This is cell with the tag CELLTAG-2."];

<<AceGen`;
SMSInitialize["test", "Language" -> "C"]; 
SMSModule["sub1"];
SMSEvaluateCellsWithTag["CELLTAG-1","CollectInputStart"->True];
SMSEvaluateCellsWithTag["CELLTAG-2","RemoveTag"->True];

The SMSRecreateNotebook command creates a new notebook with the name "test.nb" that contains cells with the cell tag "CELLTAG-1" and the cell tag "CELLTAG-2". Note that the second cell has its cell tag removed due to the SMSEvaluateCellsWithTag option "RemoveTag"->True.

SMSRecreateNotebook[];

Manipulate the contents of the generated notebook

A series of commands can be used to change the appearance of the cells. First, based on the user input cell, two additional cells are generated:
a) evaluation cell,
a) recreated cell.
Evaluation cell is directly evaluated immediately after is created.  Recreated cell is included into data base for the generation of a special notebook that hold all the cells evaluated during the AceGen session. NOTE THAT ALL SMSTag... commands are evaluated before the evaluation cell is generated, thus arguments of the SMSTag... commands can not depend on anything that will be evaluated inside the cell.

This commands are executed after the cell has been read by the SMSEvaluateCellsWithTag command and before the cell is evaluated.

Example SMSRecreateNotebook:

SMSTagIf[condition
,Print["This is True branch of the SMSTagIf structure."];
,Print["This is False branch of the SMSTagIf structure."];
];

SMSTagSwitch[expr
,"A",Print["This is A branch of the SMSTagSwitch structure."];
,"B",Print["This is B branch of the SMSTagSwitch structure."];
,"C",Print["This is C branch of the SMSTagSwitch structure."];
];

SMSTagReplace[
Print["This branch of the SMSTagReplace structure is evaluated."];
,Print["This branch of the SMSTagReplace structure is included in new notebook."];
];

x=1+1;(*this is included in new notebook in an unevaluated form*)
x=SMSTagEvaluate[1+1];(*1+1 is evaluated before it is included in new notebook*)

<<AceGen`;
SMSInitialize["test", "Language" -> "C"]; 
SMSModule["sub1"];
condition=True;
expr="C";
SMSEvaluateCellsWithTag["CELLTAG-3","CollectInputStart"->True];

The SMSRecreateNotebook command creates a new notebook with the name "test.nb" that contains cell with the cell tag "CELLTAG-3".

SMSRecreateNotebook[];

The contents of the "CELLTAG-3" cell is modified due to the use of SMSTagIf, SMSTagSwitch and SMSTagEvaluate commands.

Example: create a function with SMSTagInclude

<<AceGen`;

Clear[func]

func[r_,t_]:=Module[{x,y},
SMSTagInclude["functionpart1C",part1];
SMSTagInclude["functionpart2C",part2];
x+y
]

x⊨5 r;
y⫤6 t;

y⊣y+Sin[t];

SMSInitialize["tmptest","Language"->"C","CollectInput"->True];

Here function func is created from the given set of cells. Function is defined, but not evaluated!

part1=True;
part2=True;
SMSEvaluateCellsWithTag["functionheadC"];

SMSModule["Include",Real[r$$,t$$,e$$]];
r⊢SMSReal[r$$];
t⊢SMSReal[t$$];

Here function func is symbolically evaluated for the given set of parameters.

e⊨func[r,t];

SMSExport[e,e$$];
SMSWrite[];

FilePrint["tmptest.c",-8]

The SMSRecreateNotebook command creates a new notebook with the name "tmptest.nb" that contains definition of the function.

nb=SMSRecreateNotebook[];

NotebookClose[nb];

Signatures of Expressions

The input parameters of the subroutine (independent variables) have assigned a randomly generated high precision real number or an unique signature. The signature of the dependent auxiliary variables is obtained by replacing all auxiliary variables in the definition of variable with corresponding signatures and is thus deterministic. The randomly generated high precision real numbers assigned to the input parameters of the subroutine can have in some cases effects on code optimization procedure or even results in wrong code. One reason for the incorrect optimization of the expressions is presented in section Expression Optimization. Two additional reasons for wrong simplification are round-off errors and hidden patterns inside the sets of random numbers. In AceGen we can use randomly generated numbers of arbitrary precision, so that we can exclude the possibility of wrong simplifications due to the round-off errors. AceGen also combines several different random number generators in order to minimize the risk of hidden patterns inside the sets of random numbers. 
KORELC, Jože. Automatic generation of finite-element code by simultaneous optimization of expressions. Theor. comput. sci.. , 1997, 187:231-248. 
The precision of the randomly generated real numbers assigned to the input parameters is specified by the "Precision" option of the  SMSInitialize function. Higher precision would slow down execution.
In rare cases user has to provide it`s own signature or increase default precision in order to prevent situations where wrong simplification of expressions might occur. This can be done by providing an additional argument to the symbolic-numeric interface functions SMSReal and SMSInteger, by the use of function that yields an unique signature (SMSFreeze, SMSFictive, Expression Optimization) or by increasing the general precision (SMSInitialize).

Example 1

The numerical constants with the Infinity precision (11, π, Sqrt[2], 2/3, etc.) can be used in AceGen input without changes. The fixed precision constants have to have at least SMSEvaluatePrecision precision in order to avoid wrong simplifications. If the precision of the numerical constant is less than default precision (SMSInitialize) then AceGen automatically increases precision with the SetPrecision[exp,SMSEvaluatePrecision] command.

<<AceGen`;
SMSInitialize["test","Language"->"Mathematica","Mode"->"Debug"];
SMSModule["test"];

x⊢π;

y⊢3.1415;

Example 2

This initializes the AceGen system, starts the description of the "test" subroutine and sets default precision of the signatures to 40.

<<AceGen`;
SMSInitialize["test","Language"->"Fortran","Precision"->40];
SMSModule["test",Real[x$$,y$$],Integer[n$$]];

Here variable x gets automatically generated real random value from interval [0,1], for variable y three interval is explicitly prescribed, and an integer external variable n also gets real random value.

x⊢SMSReal[x$$];
y⊢SMSReal[y$$,{-100,100}];
n⊢SMSInteger[n$$];

This displays the signatures of external variables x, y, and n .

{x,y,n}//SMSEvaluate//Print

AceGen Examples

Summary of AceGen Examples

The presented examples are meant to illustrate the general symbolic approach to automatic code generation and the use of AceGen in the process. They are NOT meant to represent the state of the art solution or formulation of particular numerical or physical problem.
More examples are available at www.fgg.uni-lj.si/symech/examples.htm.

Basic AceGen Examples

Standard AceGen Procedure

Solution to the System of Nonlinear Equations

Advanced AceGen Examples

User Defined Functions

Minimization of Free Energy

Implementation of Finite Elements in AceFEM

Examples related to the automation of the Finite Element Method using AceFEM are part of AceFEM documentation (see Summary of Examples).

Standard FE Procedure

Implementation of Finite Elements in Alternative Numerical Environments

FEAP - ELFEN - ABAQUS - ANSYS

User Defined Environment Interface

Solution to the System of Nonlinear Equations

Generate and verify the MathLink program that returns solution to the system of nonlinear equations:
Φ=(({{a x y+(x^3)=0}, {a-x (y^2)=0}}))
where x and y are unknowns and a is parameter.

Here the appropriate MathLink module is created.

<<AceGen`;
SMSInitialize["test","Environment"->"MathLink"];
SMSModule["test",Real[x$$,y$$,a$$,tol$$],Integer[n$$],
"Input"->{x$$,y$$,a$$,tol$$,n$$},
"Output"->{x$$,y$$}];
{x0,y0,a,ϵ}⊢SMSReal[{x$$,y$$,a$$,tol$$}];
nmax⊢SMSInteger[n$$];
{x,y}⫤{x0,y0};
SMSDo[
Φ⊨{a  x  y+(x^3),a - x (y^2)};
Kt⊨SMSD[Φ,{x,y}];
{Δx,Δy}⊨SMSLinearSolve[Kt,-Φ];
{x,y}⊣{x,y}+{Δx,Δy};
SMSIf[SMSSqrt[{Δx,Δy}.{Δx,Δy}]<ϵ
,SMSExport[{x,y},{x$$,y$$}];
SMSBreak[];
];
SMSIf[i==nmax
    ,SMSPrintMessage["no convergence"];
SMSReturn[];
];
,{i,1,nmax,1,{x,y}}
];
SMSWrite[];

Here the MathLink program test.exe is build from the generated source code and installed so that functions defined in the source code can be called directly from Mathematica. (see also SMSInstallMathLink)

SMSInstallMathLink[]

For the verification of the generated code the solution calculated by the build in function is compared with the solution calculated by the generated code.

test[1.9,-1.2,3.,0.0001,10]

x=.;y=.;a=3.;
Solve[{a x y+(x^3)==0,a- x (y^2)==0},{x,y}]

Minimization of Free Energy

Contents

Problem Description

A) Trial Lagrange polynomial interpolation

B) Finite difference interpolation

C) Finite element method

In the section Standard FE Procedure the description of the steady-state heat conduction on a three-dimensional domain was given. The solution of the same physical problem can be obtained also as a minimum of the free energy of the problem. Free energy of the heat conduction problem can be formulated as
Π=(∫_Ω)((1/2)k Δϕ.Δϕ-ϕ Q)dΩ  
where ϕ indicates temperature, k is the conductivity and Q is the heat generation per unit volume and Ω is the domain of the problem.

The domain of the example is a cube filled with water ([-.0.5m,0.5m]×[-0.5m,0.5m]×[0,1m]). On all sides, apart from the upper surface, the constant temperature ϕ=0 is maintained. The upper surface is isolated so that there is no heat flow over the boundary. There exists a constant heat source Q=500 W/(m^3) inside the cube. The thermal conductivity of water is 0.58 W/m K. The task is to calculate the temperature distribution inside the cube.
The problem is formulated using various approaches:
A. Trial polynomial interpolation
	M.G	Gradient method of optimization + Mathematica directly
	M.N	Newton method of optimization + Mathematica directly
	A.G	Gradient method of optimization + AceGen+MathLink
	A.N	Newton method of optimization + AceGen+MathLink
B. Finite difference interpolation 
	M.G	Gradient method of optimization + Mathematica directly
	M.N	Newton method of optimization + Mathematica directly
	A.G	Gradient method of optimization + AceGen+MathLink
	A.N	Newton method of optimization + AceGen+MathLink
C. AceFEM Finite element method

The following quantities are compared:
•	temperature at the central point of the cube (ϕ(0.,0.,0.5))
•	time for derivation of the equations
•	time for solution of the optimization problem
•	number of unknown parameters used to discretize the problem
•	peak memory allocated during the analysis
•	number of evaluations of function, gradient and hessian.

The case A with the trial polynomial interpolation represents the situation where the merit function is complicated and the number of parameters is small. The case B with the  finite difference interpolation represents the situation where the merit function is simple and the number of parameters is large. 
REMMARK: The presented example is meant to illustrate the general symbolic approach to minimization of complicated merit functions and is not the state of the art solution of thermal conduction problem.

A trial function for temperature ϕ is constructed as a fifth order Lagrange polynomial in x y and z direction. The chosen trial function is constructed in a way that  satisfies boundary conditions.

<<AceGen`;
Clear[x,y,z,α];
kcond=0.58;Q=500;
order=5;
nterm=(order-1)(order-1)(order)

Here the fifth order Lagrange polynomials are constructed in three dimensions.

toc=Table[{x,0},{x,-0.5,0.5,1/order}];xp=MapIndexed[ InterpolatingPolynomial[ReplacePart[toc,1,{#,2}],x]&,Range[2,order]];
yp=MapIndexed[ InterpolatingPolynomial[ReplacePart[toc,1,{#,2}],y]&,Range[2,order]];
toc=Table[{x,0},{x,0.,1.,1/order}];
zp=MapIndexed[ InterpolatingPolynomial[ReplacePart[toc,1,{#,2}],z]&,Range[2,order+1]];
ϕi=Array[α,nterm];
poly=Flatten[Outer[Times,xp,yp,zp]]//Chop;
ϕ=poly.ϕi;

poly[[28]]
Plot3D[poly[[28]]/.z->0.5,{x,-0.5,0.5},{y,-0.5,0.5},PlotRange->All]

Here the Gauss points and weights are calculated for ngp×ngp×ngp Gauss numerical integration of the free energy over the domain [-.0.5m,0.5m]×[-0.5m,0.5m]×[0,1m].

ngp=6;
<<NumericalDifferentialEquationAnalysis`;
g1=GaussianQuadratureWeights[ngp,-0.5,0.5];
g2=GaussianQuadratureWeights[ngp,-0.5,0.5];
g3=GaussianQuadratureWeights[ngp,0,1];
gp={g1[[#1[[1]],1]],g2[[#1[[2]],1]],g3[[#1[[3]],1]],g1[[#1[[1]],2]]*g2[[#1[[2]],2]]*g3[[#1[[3]],2]]}&/@Flatten[Array[{#3,#2,#1}&,{ngp,ngp,ngp}],2];

The subsection Definitions has to be executed before the current subsection.

start=SessionTime[];
Δϕ={D[ϕ,x],D[ϕ,y],D[ϕ,z]};
Π=1/2 kcond Δϕ.Δϕ-ϕ Q;
Πi=Total[Map[(#[[4]] Π/.{x->#[[1]],y->#[[2]],z->#[[3]]})&,gp]];
derivation=SessionTime[]-start

G. Gradient based optimization

start=SessionTime[];
ii=0;sol=FindMinimum[Πi,Array[{α[#] ,0.}&,nterm],Method->"Gradient",EvaluationMonitor:>(ii++;)];
{ii,ϕ/.sol[[2]]/.{x->0,y->0,z->0.5}}
SessionTime[]-start

N. Newton method based optimization

start=SessionTime[];
ii=0;sol=FindMinimum[Πi,Array[{α[#] ,0.}&,nterm],Method->"Newton",EvaluationMonitor:>(ii++;)];
{ii,ϕ/.sol[[2]]/.{x->0,y->0,z->0.5}}
SessionTime[]-start

The subsection Definitions has to be executed before the current subsection.

start=SessionTime[];
SMSInitialize["Thermal","Environment"->"MathLink"]

Πf[i_]:=(
ai⊢SMSReal[Array[a$$,nterm]];
ag⊨SMSArray[ai];
{xa,ya,za,wa}⊨Map[SMSArray,Transpose[gp]];
{xi,yi,zi}⊢SMSFreeze[{SMSPart[xa,i],SMSPart[ya,i],SMSPart[za,i]}];
{xpr,ypr,zpr}⊨{xp/.x->xi,yp/.y->yi,zp/.z->zi};
poly⊨SMSArray[Flatten[Outer[Times,xpr,ypr,zpr]]];
ϕt⊨SMSDot[poly,ag];
Δϕ⊨SMSD[ϕt,{xi,yi,zi}];
wi⊨SMSPart[wa,i];
wi(1/2 kcond Δϕ.Δϕ-ϕt Q)
)

SMSModule["FThermal",Real[a$$[nterm],f$$],"Input"->a$$,"Output"->f$$];
SMSExport[0,f$$];
SMSDo[i,1,gp//Length];
  Π⊨Πf[i];
  SMSExport[ Π,f$$,"AddIn"->True];
SMSEndDo[];

SMSModule["GThermal",Real[a$$[nterm],g$$[nterm]],"Input"->a$$,"Output"->g$$];
SMSExport[Table[0,{nterm}],g$$];
SMSDo[i,1,gp//Length];
  Π⊨Πf[i];
  SMSDo[j,1,nterm];
    δΠ⊨SMSD[Π,ag,j,"Mode"->"Forward"];
    SMSExport[δΠ,g$$[j],"AddIn"->True];
  SMSEndDo[];
SMSEndDo[];

derivation=SessionTime[]-start

SMSModule["HThermal",Real[a$$[nterm],h$$[nterm,nterm]],"Input"->a$$,"Output"->h$$];
SMSDo[i,1,nterm];
  SMSDo[j,1,nterm];
    SMSExport[0,h$$[i,j]];
  SMSEndDo[];
SMSEndDo[];
SMSDo[i,1,gp//Length];
  Π⊨Πf[i];
  SMSDo[j,1,nterm];
    δΠ⊨SMSD[Π,ag,j,"Mode"->"Forward"];
    SMSDo[k,1,nterm];
      hij⊨SMSD[δΠ,ag,k,"Mode"->"Forward"];
      SMSExport[hij,h$$[j,k],"AddIn"->True];
    SMSEndDo[];
  SMSEndDo[];
SMSEndDo[];

SMSWrite[];

SMSInstallMathLink[]
derivation=SessionTime[]-start

G. Gradient based optimization

start=SessionTime[];ii=0;
sol=FindMinimum[FThermal[ϕi],{ϕi,Table[0,{nterm}]},Method->"Gradient",Gradient->GThermal[ϕi],EvaluationMonitor:>(ii++;)];
{ii,ϕ/.MapThread[Rule,List@@sol[[2,1]]]/.{x->0,y->0,z->0.5},SessionTime[]-start}

N. Newton method based optimization

start=SessionTime[];ii=0;
sol=FindMinimum[FThermal[ϕi],{ϕi,Table[0,{nterm}]},
Method->{"Newton", Hessian->HThermal[ϕi]},
Gradient->GThermal[ϕi],EvaluationMonitor:>(ii++;)];
{ii,ϕ/.MapThread[Rule,List@@sol[[2,1]]]/.{x->0,y->0,z->0.5},SessionTime[]-start}

The central difference approximation of derivatives is used for the points inside the cube and backward or forward difference for the points on the boundary.

<<AceGen`;
Clear[α,i,j,k];
nx=ny=nz=11;
dlx=1./(nx-1);
dly=1./(ny-1);
dlz=1./(nz-1);
bound={0};
nboun=1;
kcond=0.58;Q=500;

nterm=0;dofs={};
index=Table[Which[
i≤2 || i ≥  nx+1  || j≤2 || j ≥  ny+1  || k≤ 2 ,b[1]
,k==nz+2,
If[FreeQ[dofs,α[i,j,k-1]]
,++nterm;AppendTo[dofs,α[i,j,k-1]->nterm];nterm
,α[i,j,k-1]/.dofs
]
,True,
If[FreeQ[dofs,α[i,j,k]]
,++nterm;AppendTo[dofs,α[i,j,k]->nterm];nterm
,α[i,j,k]/.dofs
]
],
{i,1,nx+2},{j,1,ny+2},{k,1,nz+2}]/.b[i_]:>nterm+i;
ϕi=Array[α,nterm];
nterm

The subsection Definitions have to be executed before the current subsection.

start=SessionTime[];
Πi=Sum[
dlxt=If[i==2 || i==nx+1 ,dlxt=dlx/2,dlx];
dlyt=If[j==2 || j==ny+1 ,dlyt=dly/2,dly];
dlzt=If[k==2 || k==nz+1 ,dlzt=dlz/2,dlz];
vol=dlxt dlyt dlzt;
aijk=Map[If[#>nterm,bound[[#-nterm]],α[#]]&,
Extract[index,{{i,j,k},{i-1,j,k},{i+1,j,k},{i,j-1,k},
{i,j+1,k},{i,j,k-1},{i,j,k+1}}]];
grad={((aijk[[3]]-aijk[[2]])/(2 dlxt)),((aijk[[5]]-aijk[[4]])/(2 dlyt)),((aijk[[7]]-aijk[[6]])/(2 dlzt))};

vol(1/2 kcond grad.grad-Q aijk[[1]])
,{i,2,nx+1},{j,2,ny+1},{k,2,nz+1}
];
derivation=SessionTime[]-start

G. Gradient based optimization

start=SessionTime[];ii=0;
sol=FindMinimum[Πi,Array[{α[#] ,0.}&,nterm],Method->"Gradient",EvaluationMonitor:>(ii++;)];
{ii,α[index[[(nx+3)/2,(ny+3)/2,(nz+3)/2]]]/.sol[[2]],SessionTime[]-start}

N. Newton method based optimization

start=SessionTime[];ii=0;
sol=FindMinimum[Πi,Array[{α[#] ,0.}&,nterm],Method->"Newton",EvaluationMonitor:>(ii++;)];
{ii,α[index[[(nx+3)/2,(ny+3)/2,(nz+3)/2]]]/.sol[[2]],SessionTime[]-start}

The subsection Definitions have to be executed before the current subsection.

start=SessionTime[];
SMSInitialize["Thermal","Environment"->"MathLink"]

Πf[i_,j_,k_]:=(
indexp⊢SMSInteger[Map[
index$$[(#[[1]]-1)*(nyp+2)(nzp+2)+(#[[2]]-1)*(nzp+2)+#[[3]]]&,
{{i,j,k},{i-1,j,k},{i+1,j,k},{i,j-1,k},
{i,j+1,k},{i,j,k-1},{i,j,k+1}}]];
aijk⊢SMSReal[Map[a$$[#]&,indexp]];
{dx,dy,dz,kc,Qt}⊢SMSReal[Array[mc$$,5]];
SMSIf[i==2 || i==nxp+1 ];
  dlxt⫤dx/2;
SMSElse[];
  dlxt⊣dx;
SMSEndIf[dlxt];
SMSIf[j==2 || j==nyp+1 ];
  dlyt⫤dy/2;
SMSElse[];
  dlyt⊣dy;
SMSEndIf[dlyt];
SMSIf[k==2 || k==nzp+1 ];
  dlzt⫤dz/2;
SMSElse[];
  dlzt⊣dz;
SMSEndIf[dlzt];
vol⊨dlxt dlyt dlzt;
grad={((aijk[[3]]-aijk[[2]])/(2 dlxt)),((aijk[[5]]-aijk[[4]])/(2 dlyt)),((aijk[[7]]-aijk[[6]])/(2 dlzt))};
vol (1/2 kc grad.grad-Qt aijk[[1]])
)

SMSModule["FThermal",Integer[ndof$$,nt$$[3],index$$["*"]],Real[a$$["*"],mc$$["*"],f$$],"Input"->{ndof$$,nt$$,index$$,a$$,mc$$},"Output"->f$$];
SMSExport[0,f$$];
{nxp,nyp,nzp}⊢SMSInteger[Array[nt$$,3]];
SMSDo[i,2,nxp+1];
  SMSDo[j,2,nyp+1];
    SMSDo[k,2,nzp+1];
      Π⊨Πf[i,j,k];
      SMSExport[Π,f$$,"AddIn"->True];
    SMSEndDo[];
  SMSEndDo[];
SMSEndDo[];

SMSModule["GThermal",Integer[ndof$$,nt$$[3],index$$["*"]],Real[a$$["*"],mc$$["*"],g$$[ndof$$]],"Input"->{ndof$$,nt$$,index$$,a$$,mc$$},"Output"->g$$];
ndof⊢SMSInteger[ndof$$];
{nxp,nyp,nzp}⊢SMSInteger[Array[nt$$,3]];
SMSDo[i,1,ndof];
  SMSExport[0,g$$[i]];
SMSEndDo[];

SMSDo[i,2,nxp+1];
  SMSDo[j,2,nyp+1];
    SMSDo[k,2,nzp+1];
      Π⊨Πf[i,j,k];
      SMSDo[i1,1,indexp//Length];
        dof⊨SMSPart[indexp,i1];
        SMSIf[dof<=ndof];
          gi⊨SMSD[Π,aijk,i1];
          SMSExport[gi,g$$[dof],"AddIn"->True];
        SMSEndIf[];
      SMSEndDo[];
    SMSEndDo[];
  SMSEndDo[];
SMSEndDo[];

derivation=SessionTime[]-start

SMSModule["HThermal",Integer[ndof$$,nt$$[3],index$$["*"]],Real[a$$["*"],mc$$["*"],h$$[ndof$$,ndof$$]],"Input"->{ndof$$,nt$$,index$$,a$$,mc$$},"Output"->h$$];
ndof⊢SMSInteger[ndof$$];
{nxp,nyp,nzp}⊢SMSInteger[Array[nt$$,3]];
SMSDo[i,1,ndof];
  SMSDo[j,1,ndof];
    SMSExport[0,h$$[i,j]];
  SMSEndDo[];
SMSEndDo[];

SMSDo[i,2,nxp+1];
  SMSDo[j,2,nyp+1];
    SMSDo[k,2,nzp+1];
      Π⊨Πf[i,j,k];
      SMSDo[i1,1,indexp//Length];
        dofi⊨SMSPart[indexp,i1];
        SMSIf[dofi<=ndof];
          gi⊨SMSD[Π,aijk,i1];
          SMSDo[j1,1,indexp//Length];
            dofj⊨SMSPart[indexp,j1];
            SMSIf[dofj<=ndof];
              hij⊨SMSD[gi,aijk,j1];
              SMSExport[hij,h$$[dofi,dofj],"AddIn"->True];
            SMSEndIf[];
          SMSEndDo[];
        SMSEndIf[];
      SMSEndDo[];
    SMSEndDo[];
  SMSEndDo[];
SMSEndDo[];

SMSWrite[];

SMSInstallMathLink[]
derivation=SessionTime[]-start

G. Gradient based optimization

start=SessionTime[];ii=0;
indexb=Flatten[index];
sol=FindMinimum[
FThermal[nterm,{nx,ny,nz},indexb,Join[ϕi,bound],{dlx,dly,dlz,kcond,Q}]
,{ϕi,Table[0,{nterm}]},
Method->"Gradient",
Gradient->GThermal[nterm,{nx,ny,nz},indexb,Join[ϕi,bound],{dlx,dly,dlz,kcond,Q}]
,EvaluationMonitor:>(ii++;)];{ii,α[index[[(nx+3)/2,(ny+3)/2,(nz+3)/2]]]/.MapThread[Rule,List@@sol[[2,1]]],SessionTime[]-start}

N. Newton method based optimization

start=SessionTime[];ii=0;
indexb=Flatten[index/.b[i_]:>nterm+i];
sol=FindMinimum[
FThermal[nterm,{nx,ny,nz},indexb,Join[ϕi,bound],{dlx,dly,dlz,kcond,Q}]
,{ϕi,Table[0,{nterm}]},
Method->{"Newton", Hessian->HThermal[nterm,{nx,ny,nz},indexb,Join[ϕi,bound],{dlx,dly,dlz,kcond,Q}]},
Gradient->GThermal[nterm,{nx,ny,nz},indexb,Join[ϕi,bound],{dlx,dly,dlz,kcond,Q}]
,EvaluationMonitor:>(ii++;)];{ii,α[index[[(nx+3)/2,(ny+3)/2,(nz+3)/2]]]/.MapThread[Rule,List@@sol[[2,1]]],SessionTime[]-start}

The tangent matrix is in the case of finite difference approximation extremely sparse.

MatrixPlot[HThermal[nterm,{nx,ny,nz},indexb,Join[0 ϕi,bound],{dlx,dly,dlz,kcond,Q}]]

First the finite element mesh 30×30×30 is used to obtain convergence solution at the central point of the cube. The procedure to generate heat-conduction element that is used in this example is explained in AceGen manual section Standard FE Procedure .

<<AceFEM`;
start=SessionTime[];
SMTInputData[];
k=0.58;Q=500;
nn=30;
SMTAddDomain["cube","ExamplesHeatConduction",{"k0 *"->k,"Q *"->Q}];
SMTAddEssentialBoundary[{"X"==-0.5|| "X"==0.5 || "Y"==-0.5 || "Y"==0.5 || "Z"==0.&,1->0}];
SMTMesh["cube","H1",{nn,nn,nn},{
{{{-0.5,-0.5,0},{0.5,-0.5,0}},{{-0.5,0.5,0},{0.5,0.5,0}}},{{{-0.5,-0.5,1},{0.5,-0.5,1}},{{-0.5,0.5,1},{0.5,0.5,1}}}
}];
SMTAnalysis[];

SMTNextStep[0,1];
SMTNewtonIteration[];

SMTPostData["T*",{0,0,0.5}]
SessionTime[]-start

SMTShowMesh["Mesh"->True,"FillElements"->True,"Field"->"T*"]

Numerical Environments

Finite Element Environments

Numerical simulations are well established in several engineering fields such as in automotive, aerospace, civil engineering, and material forming industries and are becoming more frequently applied in biophysics, food production, pharmaceutical and other sectors. Considerable improvements in these fields have already been achieved by using standard features of the currently available finite element (FE) packages. The mathematical models for these problems are described by a system of partial differential equations. Most of the existing numerical methods for solving partial differential equations can be classified into two classes: Finite Difference Method (FDM) and Finite Element Method (FEM). Unfortunately, the applicability of the present numerical methods is often limited and the search for methods which can provide a general tool for arbitrary problems in mechanics of solids has a long history. In order to develop a new finite element model quite a lot of time is spent in deriving characteristic quantities such as gradients, Jacobean, Hessian and coding of the program in a efficient compiled language. These quantities are required within the numerical solution procedure. A natural way to reduce this effort is to describe the mechanical problem on a high abstract level using only the basic formulas and leave the rest of the work to the computer.
The symbolic-numeric approach to FEM and FDM has been extensively studied in the last few years. Based on the studies various systems for automatic code generation have been developed. In many ways the present stage of the generation of finite difference code is more elaborated and more general than the generation of FEM code. Various transformations, differentiation, matrix operations, and a large number of degrees of freedom involved in the derivation of characteristic FEM quantities often lead to exponential growth of expressions in space and time. Therefore, additional structural knowledge about the problem is needed, which is not the case for FDM. 
Using the general finite element environment, such as FEAP (Taylor, 1990), ABAQUS, etc., for analyzing a variety of problems and for incorporating new elements is now already an everyday practice. The general finite element environments can handle, regardless of the type of elements, most of the required operations such as: pre-processing of the input data, manipulating and organizing of the data related to nodes and elements, material characteristics, displacements and stresses, construction of the global matrices by invoking different elements subroutines, solving the system of equations, post-processing and analysis of results. However large FE systems can be for the development and testing of new numerical procedures awkward. The basic tests which are performed on a single finite element or on a small patch of elements can be done most efficiently by using the general symbolic-numeric environments such as Mathematica, Maple, etc. It is well known that many design flaws such as element instabilities or poor convergence properties can be easily identified if we are able to investigate element quantities on a symbolic level. Unfortunately, symbolic-numeric environments become very inefficient if there is a larger number of elements or if we have to perform iterative numerical procedures. In order to assess element performances under real conditions the easiest way is to perform tests on sequential machines with good debugging capabilities (typically personal computers and programs written in Fortran or C/C++ language). In the end, for real industrial simulations, large parallel machines have to be used. By the classical approach, re-coding of the element in different languages would be extremely time consuming and is never done. With the symbolic concepts re-coding comes practically for free, since the code is automatically generated for several languages and for several platforms from the same basic symbolic description.
The AceGen package provides a collection of prearranged modules for the automatic creation of the interface between the finite element code and the finite element environment. AceGen enables multi-language and multi-environment generation of nonlinear finite element codes from the same symbolic description. The AceGen system currently supports the following FE environments:

=>	AceFem is a model FE environment written in a Mathematica's symbolic language and C (see AceFEM),
=>	FEAP is the research environment written in FORTRAN  (see FEAP - ELFEN - ABAQUS - ANSYS),
=>	ELFEN© is the commercial environment written in FORTRAN  (see FEAP - ELFEN - ABAQUS - ANSYS).
=>	ABAQUS© is the commercial environment written in FORTRAN  (see FEAP - ELFEN - ABAQUS - ANSYS).
The AceGen package is often used to generate user subroutines for various other environments. It is advisable for the user to use standardized interface as described in User Defined Environment Interface . 
There are several benefits of using the standardized interface:
	=>	automatic translation to other FE packages,
	=>	other researchers are able to repeat the results,
	=>	commercialization of the research is easier,
	=>	eventually, the users interface can be added to the list of  standard interfaces.

All FE environments are essentially treated in the same way. Additional interface code ensures proper data passing to and from automatically generated code for those systems. Interfacing the automatically generated code and FE environment is a two stage process. The purpose of the process is to generate element codes for various languages and environments from the same symbolic input. At the first stage user subroutine codes are generated. Each user subroutine performs specific task (see Standard User Subroutines). The  input/output arguments of the generated subroutines are environment and language dependent, however they should contain the same information. Due to the fundamental differences among FE environments, the required information is not readily available. Thus, at the second stage the contents of the "splice-file"  (see SMSWrite) that contains additional environment dependent interface and supplementary routines is added to the user subroutines codes. The "splice-file" code ensures proper data transfer from the environment to the user subroutine and back.

Automatic interface is already available for a collection of basic tasks required in the finite element analysis (see Standard User Subroutines). There are several possibilities in the case of need for an additional functionality. Standard User Subroutines can be used as templates by giving them a new name and, if necessary, additional arguments. The additional subroutines can be called directly from the environment or from the enhanced "splice-file". Source code of the "splice-files" for all supported environments are available at directory $BaseDirectory/Applications/AceGen/Splice/. The additional subroutines can be generated independently just by using the AceGen code generator and called directly from the environment or from the enhanced "splice-file". See also (HyperlinkTemplate[Installation instructions, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, HyperlinkActionRecycled, HyperlinkActive, , ]) for instructions how to compile and link the generated codes.
Since the complexity of the problem description mostly appears in a symbolic input, we can keep the number of data structures (see Data Structures) that appear as arguments of the user subroutines at minimum. The structure of the data is depicted below. If the "default form" of the arguments as external AceGen variables (see Symbolic-Numeric Interface) is used, then they are automatically transformed into the form that is correct for the selected FE environment. The basic data structures are as follows:

=> environment data defines a general information common to all nodes and elements (see Integer Type Environment Variables , Real Type Environment Variables ),
=> nodal data structure contains all the data that is associated with the node (see Node Data),
=> element specification data structure contains information common for all elements of particular type (see Domain Specification Data),
=> node specification data structure contains information common for all nodes of particular type (see Node Specification Data),
=> element data structure contains all the data that is associated with the specific element (see Element Data).
KORELC, Jože, Multi-language and Multi-environment Generation of Nonlinear Finite Element Codes,  Engineering with Computers, 2002, 18(4):312-327

Standard FE Procedure

Description of FE Characteristic Steps

The standard procedure to generate finite element source code is comprised of four major phases:
A) AceGen initialization
	- see SMSInitialize
B) Template initialization
	- see SMSTemplate
	- general characteristics of the element
	- rules for symbolic-numeric interface
C) Definition of user subroutines
	- see Standard User Subroutines
	- tangent matrix, residual, post-processing, …
D) Code generation
	- see SMSWrite
	- additional environment subroutines
	- compilation, dll, …

Due to the advantage of simultaneous optimization procedure we can execute each step separately and examine intermediate results. This is also the basic way how to trace the errors that might occur during the AceGen session.

Description of Introductory Example

Let us consider a simple example to illustrate the standard AceGen procedure for the generation and testing of a typical finite element. The problem considered is steady-state heat conduction on a three-dimensional domain, defined by:
(∂/(∂x))(k((∂ϕ)/(∂x)))+(∂/(∂y))(k((∂ϕ)/(∂y)))+(∂/(∂z))(k((∂ϕ)/(∂z))) +Q=0     on domain Ω,
ϕ-(OverBar[ϕ])= 0                                                                           essential boundary condition on  (Subscript[Γ, ϕ,])
k((∂ϕ)/(∂n))-(OverBar[q])=0                                                                     natural boundary condition on  (Subscript[Γ, q]),
where ϕ indicates temperature, k is conductivity, Q heat generation per unit volume, and (OverBar[ϕ]) and (OverBar[q]) are the prescribed values of temperature and heat flux on the boundaries. Thermal conductivity here is assumed to be a quadratic function of temperature:
k=(Subscript[k, 0])+(Subscript[k, 1]) ϕ+(Subscript[k, 2]) (ϕ^2).
Corresponding weak form is obtained directly by the standard Galerkin approach as
(∫_Ω^( ))[(▽^T)δϕ  k  ▽ϕ-δϕ Q ]dΩ-(∫_(Subscript[Γ, q])^( ))δϕ (OverBar[q])dΓ=0.
Only the generation of the element subroutine that is required for the direct, implicit analysis of the problem is presented here. Additional user subroutines may be required for other tasks such as sensitivity analysis, post-processing etc.. The problem considered is non-linear and it has unsymmetric Jacobian matrix.

Data interface

Interface to the input data of the element user subroutines can be created by using:

high level IO data management routines specifically designed for FEM interface  (see IO Data Management)

or low level direct specification of real and integer type variables with SMSReal and SMSInteger AceGen commands.

High level  IO Data Management routines are used first to build the interface. The input is repeated later by using low level interface.

AceGen input using high level I/O data management

Step 1: Initialization

This loads the AceGen code generator.

<<AceGen`;

This initializes the AceGen session. The AceFEM is chosen as the target numerical environment. See also SMSInitialize.

SMSInitialize["ExamplesHeatConduction","Environment"->"AceFEM"];

This initializes constants that are needed for proper symbolic-numeric interface (See Template Constants). Three-dimensional, eight node, hexahedron element with one degree of freedom per node is initialized.

SMSTemplate["SMSTopology"->"H1","SMSDOFGlobal"->1,
"SMSSymmetricTangent"->False,
"SMSDomainDataNames"->{"k0 -conductivity parameter","k1 -conductivity parameter",
"k2 -conductivity parameter","Q -heat source"},
"SMSDefaultData"->{1,0,0,0}];

Step 2: Element subroutine for the evaluation of tangent matrix and residual

Start of the definition of the user subroutine for the calculation of tangent matrix and residual vector and set up input/output parameters (see Standard User Subroutines).

SMSStandardModule["Tangent and residual"];

Step 3: Interface to the input data of the element subroutine

Here the coordinates of the element nodes and current values of the nodal temperatures are taken from the supplied arguments of the subroutine. The default values for "H1" topology are used to set the number of nodes and the type of nodes and SMSDOFGlobal is used to get the number of DOFs per node.

{XIO,ϕIO}⊨SMSIO["All coordinates and DOFs"];
ϕI=ϕIO[[All,1]];

The conductivity parameters (Subscript[k, 0]), (Subscript[k, 1]), (Subscript[k, 2]) and the internal heat source Q are assumed to be common for all elements in a particular domain (material or group data).  Thus they are placed into the element specification data field "Data" (see Element Data). In the case that material characteristic vary substantially over the domain it is better to use element data field "Data" instead of element specification data.

{k0,k1,k2,Q}⊨SMSIO["Domain data"];

Element is numerically integrated by one of the built-in standard numerical integration rules (see Numerical Integration). This starts the loop over the integration points, where ξ, η, ζ are coordinates of the current integration point and wGauss is integration point weight.

SMSDo[Ig,1,SMSIO["No. integration points"]];
Ξ={ξ,η,ζ}⊨SMSIO["Integration point"[Ig]];

Step 4: Definition of the trial functions

This defines the trilinear shape functions (Subscript[N, i]), i=1,2,…,8 and interpolation of the physical coordinates within the element. (Subscript[J, m]) is Jacobian matrix of the isoparametric mapping from actual coordinate system X, Y, Z to reference coordinates ξ, η, ζ.

Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];
X⊢SMSFreeze[NI.XIO];
Jg⊨SMSD[X,Ξ];Jgd⊨Det[Jg];

The trial function for the temperature distribution within the element is given as linear combination of the shape functions and the nodal temperatures ϕ = (Subscript[N, n]).(Subscript[ϕ, n]). The (Subscript[ϕ, n]) are unknown parameters of the variational problem.

ϕ⊨NI.ϕI;

Step 5: Definition of the governing equations

The implicit dependencies between the actual and the reference coordinates are given by ((∂(Subscript[ξ, j]))/(∂(Subscript[X, i])))=((Subscript[J, m])^(-1))((∂(Subscript[X, i]))/(∂(Subscript[ξ, j]))), where (Subscript[J, m]) is the Jacobean matrix of the nonlinear coordinate mapping.

Dϕ⊨SMSD[ϕ,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];
δϕ⊨SMSD[ϕ,ϕI];
Dδϕ⊨SMSD[δϕ,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];

Here is the definition of the weak form of the steady state heat conduction equations. The strength of the heat source is multiplied by the global variable rdata$$["Multiplier"] (see Real Type Environment Variables).

k⊨k0+k1 ϕ+k2 (ϕ^2);
λ⊨SMSIO["Multiplier"];

wgp⊨SMSIO["Integration weight"[Ig]];
Rg⊨Jgd wgp(k Dδϕ.Dϕ-δϕ λ Q);

Element contribution to global residual vector (Subscript[R, g]) is exported into the p$$ output parameter of the "Tangent and residual" subroutine (see Standard User Subroutines).

SMSIO[Rg,"Add to","Residual"];

Step 6: Definition of the Jacobian matrix

This evaluates the explicit form of the Jacobian (tangent) matrix and exports result into the s$$ output parameter of the user subroutine. Another possibility would be to generate a characteristic formula for the arbitrary element of the residual and the tangent matrix. This would substantially reduce the code size.

Kg⊨SMSD[Rg,ϕI];
SMSIO[Kg,"Add to","Tangent"];

This is the end of the integration loop.

SMSEndDo[];

Step 7: Post-processing subroutine

Start of the definition of the user subroutine for the definition and evaluation of post-processing quantities. The subroutine is not  obligatory, however it makes the post-processing much easier.

SMSStandardModule["Postprocessing"];

Here the nodal point post-processing quantity "Temperature" is introduced and exported to array of the nodal point quantities npost$$.

{XIO,ϕIO}⊨SMSIO["All coordinates and DOFs"];
ϕI=ϕIO[[All,1]];
SMSIO[{"Temperature"->ϕI},"Export to","Nodal point post"];

Here the integration point post-processing quantity "Conductivity" is introduced and exported to array of  the integration point quantities gpost$$.

{k0,k1,k2,Q}⊨SMSIO["Domain data"];
SMSDo[
Ξ={ξ,η,ζ}⊨SMSIO["Integration point"[Ig]];
Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];
ϕ⊨NI.ϕI;
k⊨k0+k1 ϕ+k2 (ϕ^2);
SMSIO[{"Conductivity"->k},"Export to","Integration point"[Ig]];
,{Ig,1,SMSIO["No. integration points"]}
];

Step 8: Code Generation

At the end of the session AceGen translates the code from pseudo-code to the required script or compiled program language and prepends the contest of the interface file to the generated code. See also SMSWrite. The result is ExamplesHeatConduction.c file with the element source code written in a C language.

SMSWrite[];

AceGen input using low level  I/O data management

Most of the AceGen code is the same as in the previous example, thus it will not be commented again.

Step 1: Initialization

<<AceGen`;
SMSInitialize["tmpExamplesHeatConduction","Environment"->"AceFEM"];
SMSTemplate["SMSTopology"->"H1","SMSDOFGlobal"->1,
"SMSSymmetricTangent"->False,
"SMSDomainDataNames"->{"k0 -conductivity parameter","k1 -conductivity parameter",
"k2 -conductivity parameter","Q -heat source"},
"SMSDefaultData"->{1,0,0,0}];

Step 2: Element subroutine for the evaluation of tangent matrix and residual

SMSStandardModule["Tangent and residual"];

Step 3: Interface to the input data of the element subroutine

Here the coordinates of the element nodes and current values of the nodal temperatures are taken from the supplied arguments of the subroutine nd$$[i,"X",j] and nd$$[i,"at",1] (see Node Data).

XI⊢Table[SMSReal[nd$$[i,"X",j]],{i,SMSNoNodes},{j,SMSNoDimensions}];ϕI⊢Table[SMSReal[nd$$[i,"at",1]],{i,8}];

The conductivity parameters (Subscript[k, 0]), (Subscript[k, 1]), (Subscript[k, 2]) and the internal heat source Q are assumed to be common for all elements in a particular domain (material or group data).  Thus they are placed into the element specification data field "Data" (see Element Data).

{k0,k1,k2,Q}⊢SMSReal[Table[es$$["Data",i],{i,4}]];

Element is numerically integrated by one of the built-in standard numerical integration rules (see Numerical Integration). This starts the loop over the integration points, where ξ, η, ζ are coordinates of the current integration point and wGauss is integration point weight.

SMSDo[Ig,1,SMSInteger[es$$["id","NoIntPoints"]]];
Ξ={ξ,η,ζ}⊢Table[SMSReal[es$$["IntPoints",i,Ig]],{i,3}];
wgp⊢SMSReal[es$$["IntPoints",4,Ig]];

Step 4: Definition of the trial functions

Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];
X⊢SMSFreeze[NI.XI];
Jg⊨SMSD[X,Ξ];Jgd⊨Det[Jg];
ϕ⊨NI.ϕI;

Step 5: Definition of the governing equations

Dϕ⊨SMSD[ϕ,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];
δϕ⊨SMSD[ϕ,ϕI];
Dδϕ⊨SMSD[δϕ,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];
k⊨k0+k1 ϕ+k2 (ϕ^2);

The strength of the heat source is multiplied by the global variable rdata$$["Multiplier"] (see Real Type Environment Variables).

λ⊢SMSReal[rdata$$["Multiplier"]];

Rg⊨Jgd wgp(k Dδϕ.Dϕ-δϕ λ Q);
SMSExport[Rg,p$$,"AddIn"->True];

Step 6: Definition of the Jacobian matrix

Kg⊨SMSD[Rg,ϕI];
SMSExport[Kg,s$$,"AddIn"->True];

SMSEndDo[];

Step 7: Post-processing subroutine

SMSStandardModule["Postprocessing"];
ϕI⊢Table[SMSReal[nd$$[i,"at",1]],{i,8}];
SMSNPostNames={"Temperature"};
SMSExport[ϕI,Table[npost$$[i,1],{i,8}]];
{k0,k1,k2,Q}⊢SMSReal[Table[es$$["Data",i],{i,Length[SMSDomainDataNames]}]];
SMSDo[
Ξ={ξ,η,ζ}⊢Table[SMSReal[es$$["IntPoints",i,Ig]],{i,3}];
Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];
ϕ⊨NI.ϕI;
k⊨k0+k1 ϕ+k2 (ϕ^2);
SMSGPostNames={"Conductivity"};
SMSExport[k,gpost$$[Ig,1]];
,{Ig,1,SMSInteger[es$$["id","NoIntPoints"]]}
];

Step 8: Code Generation

SMSWrite[];

Template Constants

Contents

General Description

SMSTemplate

Template Constants

Geometry

Degrees of Freedom; K and R

Data Management

Graphics and Postprocessing

Sensitivity Analysis

AceFEM Solution Procedure Specific

Description of the Element for AceShare

Environment Specific

General Description

The AceGen uses a set of global constants that at the code generation phase define the major characteristics of the finite element (called finite element template constants). In most cases the element topology and the number of nodal degrees of freedom are sufficient to generate a proper interface code. Some of the FE environments do not support all the possibilities given here. The AceGen tries to accommodate the differences and always generates the code. However, if the proper interface can not be done automatically, then it is left to the user. For some environments additional constants have to be declared (see e.g. ELFEN).
The template constants are initialized with the SMSTemplate function. Values of the constants can be also set or changed directly after SMSTemplate command.

SMSTemplate

The general characteristics of the element are specified by the set of options options. Options are of the form "Element_constant"->value (see also Template Constants for list of all constants). The SMSTemplate command must follow the SMSInitialize command.

See also Template Constants section for a list of all constants and the Data Structures section to see how template constants relate to the external variables in AceGen and the data manipulation routines in AceFEM.

This defines the 2D, quadrilateral element with 4 nodes and 5 degrees of freedom per node.

SMSTemplate["SMSTopology"->"Q1","SMSDOFGlobal"->5];

Template Constants

Geometry

Degrees of Freedom, K and R

Data Management

Graphics and Postprocessing

SMSAdditionalGraphics option defines a set of three pure functions {addGraphicsPrimitives, trueSegments, trueTriangulation}. Functions are called before the SMTShowMesh creates the post-processing mesh for each element. If the node coordinates or the element connectivity has been changed then the SMTUpdatePostData command has to be called first.
The results are used as follows:

addGraphicsPrimitives

addGraphicsPrimitives[
{element index, domain index,list of node indices}
,is True if node marks are required
, is True if boundary conditions are required
, {node coordinates for all element nodes}
]
must returns additional graphics primitives (Line, Point, etc.) that will be included into the final graphics verbatim.
 Global variable AceFEM`SMTSession[[60]] contains some of the SMTShowMesh options:
              AceFEM`SMTSession[[60]]=
                                    {1  - "DeformedMesh" True/False
                                     ,2  -  "Scale"
                                     ,3 -  "Mesh"
                                     ,4 -  "LineFieldScale"
                                    }
 In the case that  "DeformedMesh"===True the provided node coordinates are positions of the nodes of the deformed mesh.

Examples:

"SMSAdditionalGraphics"->{Function[{element,marks,bc,X},{Line[{X[[1]],X[[2]]}]}],Null,Null}
would produce a line connecting first and second element node)

"SMSAdditionalGraphics"->{Function[{element,marks,bc,X},{Red,Dashed,Line[{AceFEM`SMTNodeData[element[[3,1]],"X"],X[[1]]}]}],Null,Null}
would produce Red, Dashed, Line connecting the first element node  in undeformed mesh with corresponding node in deformed mesh.

trueSegments

trueSegments[element index, domain index,list of node indices]
must return all segments on the surface of the specific element as the sequence of the element node indices that define the edge of the segment (e.g. {{1,2,3,4}})

trueTriangulation

trueTriangulation[element index, domain index,list of node indices]
for all segments define a rule that splits the segments specified by  trueSegments into triangular or quadrilateral sub-segments (e.g. {{{1,2,3},{1,3,4}}})

This defines the post-processing for elements with variable number of nodes. It is assumed that given topological nodes form a polygon. Dummy nodes are neglected.

"SMSAdditionalGraphics"->{
Null,
Function[{ei,si,ni},{Range[Length[ni]-Count[ni,AceFEM`SMTDummyNodes]]}],
Function[{ei,si,ni},{{Range[Length[ni]-Count[ni,AceFEM`SMTDummyNodes]]}}]
}

Sensitivity Analysis

See also AceFEM manual sections Sensitivity Analysis.

AceFEM Solution Procedure Specific

Description of the Element for AceShare

Environment Specific (FEAP,ELFEN, user defiend environments, ...)

Data Structures

Contents

General Description

IO Data Management

General Input data

Nodal Input data

Element Input data

Output  data

Sensitivity analysis Input/Output data

Tasks Input/Output data

Example: IO data defined by SMSTemplate constants

Dynamically created IO data variables

IO data types

Example: dynamically created IO data variables

Example: dynamically created multi-field element IO

Example: low-level  IO data definitions

Utility IO data management commands

SMSIO

SMSIOInfo

SMSUndefineIO

Integer Type Environment Variables

General data

Mesh input related data

Iterative procedure related data

Debugging and errors related data

Linear solver related data

Sensitivity related data

Contact related data

Real Type Environment Variables

Node Specification Data

Node Data

Domain Specification Data

Memory allocation

General Data

Run Mathematica from code

Mesh generation

Domain input data

Numerical integration

Graphics postprocessing

Sensitivity analysis

Element Data

General Description

Environment data structure defines the general information common for all nodes and elements of the problem. If the "default form" of the data is used, then AceGen automatically transforms the input into the form that is correct for the selected FE environment. The scalar environment variables are stored into two vectors, one for the integer type variables and the other for the real type variables. All the environments do not provide all the data, thus automatic translation mechanism can sometimes fail. All data can be in general divided into 6 data structures:

Integer Type Environment Variables (in AceGen idata$$,in AceFEM SMTIData)

Real Type Environment Variables (in AceGen rdata$$, in AceFEM SMTRData)

Domain Specification Data (in AceGen es$$, in AceFEM SMTDomainData)

Element Data (in AceGen ed$$, in AceFEM SMTElementData)

Node Specification Data (in AceGen ns$$, in AceFEM SMTNodeSpecData)

Node Data (in AceGen nd$$, in AceFEM SMTNodeData)

Node Data Structures

Two types of the node specific data structures are defined. The structure (Node Specification Data, ns$$) defines the major characteristics of the nodes sharing the same node identification (NodeID, Node Identification). Nodal data structure (Node Data, nd$$) contains all the data that are associated with specific node. Nodal data structure can be set and accessed from the element code. For example, the command SMSReal[nd$$[i,"X",1]] returns x-coordinate of the i-th element node. At the analysis phase the data can be set and accessed interactively from the Mathematica by the user (see SMTNodeData, SMTElementData...). The data are always valid for the current element that has been processed by the FE environment. Index i is the index of the node accordingly to the definition of the particular element.

Element Data Structures

Two types of the element specific data structures are defined. The domain specification data structure (Domain Specification Data, es$$) defines the major characteristics of the element that is used to discretize particular sub-domain of the problem. It can also contain the data that are common for all elements of the domain (e.g. material constants). The element data structure (Element Data , ed$$) holds the data that are specific for each element in the mesh.
For a transient problems several sets of element dependent transient variables have to be stored. Typically there can be two sets: the current (ht) and  the previous (hp) values of the transient variables. The hp and ht data are switched at the beginning of a new step (see SMTNextStep).
All element data structures can be set and accessed from the element code. For example, the command SMSInteger[ed$$["nodes",1]] returns the index of the first element node. The data is always valid for the current element that has been processed by the FE environment.

IO Data management

IO data management routines provide higher level IO data management based on textual description of data required.

IO Data Management

IO data management routines provide keyword based interface between the input output parameters of user subroutine and AceGen session. Whenever several user subroutines are required, the allocated data structures have to be kept synchronized throughout the AceGen session.  AceGen enables three levels of IO data management depending on the complexity of the element.

Level 1:  IO data defined by SMSTemplate constants

For a simple elements all the information needed for the correct formulation of IO data variables is defined by SMSTemplate constants (SMSTopology, SMSAdditionalNodes, SMSNodeID, SMSDOFGlobal, SMSDomainDataNames, etc.). Specific data is identified by its name (dataName) defined in (IO Data Management, Sensitivity analysis Input/Output data, Tasks Input/Output data, AceFEM Code Generation Utility Functions) and it can be imported form or exported to IO parameters of corresponding user subroutine with the following commands:

Level 2:  dynamically allocated IO data variables (Dynamically created IO data variables)

In the case of complex multi-field numerical models the definition of IO variables becomes prone to errors. The primal purpose of the mechanism for the automatic IO Data Management is dynamic allocation of data of given type and association of the data with the keys. The allocated data is kept synchronized throughout the AceGen session based on the given keys. In this case the SMSTemplate constants (SMSTopology, SMSAdditionalNodes, SMSNodeID, SMSDOFGlobal, SMSDomainDataNames, etc.) are automatically updated and they don’t have to be defined with the SMSTemplate  command.

Level 3:  low-level definition of IO data definition (Example: low-level  IO data definitions)

Number of possible input/output data combinations is huge, thus only the most basic are supported by automatic IO Data management. IO data of complex finite elements have to be defined directly using SMSInteger, SMSReal and SMSExport commands.

General Input  data

A selected set of data can be access thought keywords (e.g. "Integration point") using the SMSIO command. IO data not covered by SMSIO command have to be defined directly using SMSInteger, SMSReal and SMSExport functions and actual appearance of the IO parameter as a part of user subroutine input/output parameters (e.g. es$$["IntPoints",coordinate,Ig]).

Nodal Input data

Element Input data

Examples: generic example

<<"AceGen`";
SMSInitialize["test","Environment"->"AceFEM"];
SMSTemplate["SMSTopology"->"Q1","SMSNoTimeStorage"->2];
SMSStandardModule["Tangent and residual"];

SMSIO["All coordinates and DOFs"]

SMSIO["Nodal coordinates"]

SMSIO["Nodal coordinates"[{1,3}]]

SMSIO["Nodal DOFs"[3]]

SMSIO[SMSInteger[2],"Export to","ErrorStatus"]

SMSIO["Element time dependent data"[{1,2}]]

SMSIO[{π,π^2},"Export to","Element time dependent data"[{1,2}]]

Examples: The new Input/Output mechanism makes formulating the elements with a variable number of nodes easy.

<<"AceGen`";
SMSInitialize["test","Environment"->"AceFEM"];
SMSTemplate["SMSTopology"->"Q1","SMSNoNodes"->100,"SMSAdditionalNodes"->Null,"SMSVariableNumberOfNodes"->True];
SMSStandardModule["Tangent and residual"];

when the true number of nodes is unknown, the SMSIO command returns an SMSArray array data object with the length equal to the maximum number of nodes

SMSIO["All coordinates and DOFs"]

components are then taken from the arrays

SMSIO["Nodal coordinates"[{1,3}]]

SMSLastTrueNode[] returns an index of the last element node that is not a dummy node (at AceFEM run time!, see also AceFEM Code Generation Utility Functions)

SMSDo[node,1,SMSLastTrueNode[]];

node index can be an arbitrary expression in the case of variable number of nodes “SMSVariableNumberOfNodes”->True

X⊨SMSIO["Nodal coordinates"[node]]

additional information about the node identification is required to get the number of DOFs at an arbitrary node

p⊨SMSIO["Nodal DOFs"[node,"D"]]

SMSEndDo[]

Output  data

Examples:

SMSIO[Rgi,"Add to","Residual"[i]];
SMSIO[Kgij,"Add to","Tangent"[i,j]];
SMSIO[{"DeformedMeshX"->u,...},"Export to","Nodal point post"[node]];
SMSIO[{"Sxx"->σ,...},"Export to","Integration point post"[Ig]];
SMSIO[{"DeformedMeshX"->{u1,u2,...},...},"Export to","Nodal point post"];

Sensitivity analysis Input/Output  data

For details see Forward Mode Implementation Notes,  Backward Mode Implementation Notes.

Tasks Input/Output  data

Example: IO data defined by SMSTemplate constants

<<"AceGen`";
SMSInitialize["tmpTest","Environment"->"AceFEM"];
SMSTemplate["SMSTopology"->"Q1","SMSSymmetricTangent"->True,"SMSDomainDataNames"->{"E -elastic modulus","ν -poisson ratio","t -thickness"},"SMSDefaultData"->{21000,0.3,1}];

SMSStandardModule["Tangent and residual"];
SMSDo[Ig,1,SMSIO["No. integration points"]];
SMSSaveAndEvaluate["Element definitions",
Ξ={ξ,η,ζ}⊨SMSIO["Integration point"[Ig]];
{XIO,uIO}⊨SMSIO["All coordinates and DOFs"];
Nh⊨(1/4) {(1-ξ) (1-η),(1+ξ) (1-η),(1+ξ) (1+η),(1-ξ) (1+η)};X⊢SMSFreeze[Append[Nh.XIO,ζ]];Je⊨SMSD[X,Ξ];Jed⊨Det[Je];u⊨Append[Nh.uIO,0];H⊨SMSD[u,X,"Dependency"->{Ξ,X,SMSInverse[Je]}];SMSFreeze[F,IdentityMatrix[3]+H,"Ignore"->PossibleZeroQ];JF⊨Det[F];Ct⊨Transpose[F].F;{Em,ν,tζ}⊨SMSIO["Domain data"];{λ,μ}⊨SMSHookeToLame[Em,ν];W⊨(1/2) λ (((JF-1))^2)+μ ((1/2) (Tr[Ct]-3)-Log[JF]);
wgp⊨SMSIO["Integration weight"[Ig]];
];
pe=Flatten[SMSIO["Nodal DOFs"]];
SMSDo[
Rgi⊨Jed tζ wgp SMSD[W,pe,i];
SMSIO[Rgi,"Add to","Residual"[i]];
SMSDo[
Kgij⊨SMSD[Rgi,pe,j];
SMSIO[Kgij,"Add to","Tangent"[i,j]];
,{j,i,8}];
,{i,1,8}];
SMSEndDo[];

SMSStandardModule["Postprocessing"];
{u,v}⊨Transpose[SMSIO["Nodal DOFs"]];
SMSIO[{"DeformedMeshX"->u,"DeformedMeshY"->v,"u"->u,"v"->v},"Export to","Nodal point post"];
SMSDo[Ig,1,SMSIO["No. integration points"]];
	SMSEvaluateSaved["Element definitions"];
	Eg⊨1/2(Ct-IdentityMatrix[3]);
	σ ⊨ (1/JF)*SMSD[W, F,"Ignore"->NumberQ] . Transpose[F];
	SMSIO[{
"Sxx"->σ[[1,1]],"Sxy"->σ[[1,2]],"Sxz"->σ[[1,3]],"Syx"->σ[[2,1]],"Syy"->σ[[2,2]],
"Syz"->σ[[2,3]],"Szx"->σ[[3,1]],"Szy"->σ[[3,2]],"Szz"->σ[[3,3]],
"Exx"->Eg[[1,1]],"Exy"->Eg[[1,2]],"Exz"->Eg[[1,3]],"Eyx"->Eg[[2,1]],"Eyy"->Eg[[2,2]]
,"Eyz"->Eg[[2,3]],"Ezx"->Eg[[3,1]],"Ezy"->Eg[[3,2]],"Ezz"->Eg[[3,3]]}
,"Export to","Integration point post"[Ig]];
SMSEndDo[];

SMSWrite[];

SMTInputData[];
SMTAddDomain["d","tmpTest",{}];
SMTAddMesh[Polygon[{{0,0},{48,44},{48,44+16},{0,44}}],"d","Q1",{3,3}];
SMTAddEssentialBoundary[Line[{{0,0},{0,44}}],1->0,2->0];
SMTAddNaturalBoundary[ Line[{{48,44},{48,44+16}}],2->Line[{-1000}]];
SMTAnalysis[];
nstep=10;Δλ=0.1;tolNR=10^-8;maxNR=15;
Do[
SMTNextStep["Δλ"->Δλ];
While[SMTConvergence[tolNR,maxNR],SMTNewtonIteration[];];
,{i,1,nstep}]
SMTShowMesh["DeformedMesh"->True,"BoundaryConditions"->True]

Dynamically created IO data variables

A simple IO interface presented in previous chapter uses template constants such as SMSTopology to create proper I/O interface. 
In the case that template constants are not known in advance there is an alternative mechanism available that allows dynamic allocation of data and creates template constants while creating the interface.  The dynamic SMSIO associates values with the keys in order to simplify the data management. The primal purpose of the mechanism for the automatic IO Data Management is dynamic allocation of data of given type and association of the data with the keys. The SMSIO command remembers the number of elements of specific type allocated. When called the second time with the same key the already defined value is returned. The key represents the specific value and can be used later on (through all the AceGen session!) to retrieve the value that was originally assigned to the key.

<<AceFEM`;

Examples:

SMSIO["Nodal coordinates",Table["X"[i],{i,SMSNoNodes}]];
SMSIO["Nodal DOFs",Table["u"[i]->{SMSNoDimensions,"D"},{i,SMSNoNodes}]];
SMSIO["Domain data","Em"-> {"E -elastic modulus",21000}];
SMSIO["Element time dependent data",Table["𝕙eIO"[i],{i,nhe}]];
SMSIO[Table[π,{nhe}],"Export to","Element time dependent data",Table["𝕙eIO"[i],{i,nhe}]];
SMSIO["Element time dependent data",Table["𝕙gIO"[i]->{Hold[NoIp],Ig},{i,nhg}]];
SMSIO["Element data","weighth"]; 
SMSIO["Integer type switch","N"->{10,"number of ..."}];SMSIO["Char type switch","contact"->"element is a contact finite element"];

key can also be a pattern, e.g. SMSIO["Nodal coordinates", "u"[_]] would return a set of nodal coordinates of all nodes with associated key that matches pattern "u"[_].

Example: dynamically created IO data variables

<<"AceGen`";
SMSInitialize["tmpTest","Environment"->"AceFEM"];
SMSTemplate["SMSTopology"->"Q1","SMSSymmetricTangent"->True];

SMSStandardModule["Tangent and residual"];
SMSDo[Ig,1,SMSIO["No. integration points"]];
SMSSaveAndEvaluate["Element definitions",
Ξ={ξ,η,ζ}⊨SMSIO["Integration point"[Ig]];
XIO⊨SMSIO["Nodal coordinates",Table["X"[i],{i,SMSNoNodes}]];
uIO⊨SMSIO["Nodal DOFs",Table["u"[i]->{SMSNoDimensions,"D"},{i,SMSNoNodes}]];Nh⊨1/4 {(1-ξ)(1-η),(1+ξ)(1-η),(1+ξ)(1+η),(1-ξ)(1+η)};
X⊢SMSFreeze[Append[Nh.XIO,ζ]];
Je⊨SMSD[X,Ξ];Jed⊨Det[Je];
u⊨Append[Nh.uIO,0];
H⊨SMSD[u,X,"Dependency"->{Ξ,X,SMSInverse[Je]}];
SMSFreeze[F,IdentityMatrix[3]+H,"Ignore"->PossibleZeroQ];
JF⊨Det[F];Ct⊨Transpose[F].F;
{Em,ν,tζ}⊨SMSIO["Domain data",{
"Em"-> {"E -elastic modulus",21000},
"ν"-> {"ν -poisson ratio",0.3},
"tζ"-> {"t -thickness",1}}];
{λ,μ}⊨SMSHookeToLame[Em,ν];
W⊨1/2 λ (JF-1)^2+μ (1/2 (Tr[Ct]-3)-Log[JF]);
];
wgp⊨SMSIO["Integration weight"[Ig]];
pe=Flatten[SMSIO["Nodal DOFs"]];
SMSDo[
Rgi⊨ Jed tζ wgp SMSD[W,pe,i];
SMSIO[Rgi,"Add to","Residual"[i]];
SMSDo[
Kgij⊨SMSD[Rgi,pe,j];
SMSIO[Kgij,"Add to","Tangent"[i,j]];
,{j,i,8}];
,{i,1,8}];
SMSEndDo[];

SMSStandardModule["Postprocessing"];
{u,v}⊨Transpose[SMSIO["Nodal DOFs","u"[_]]];
SMSIO[{"DeformedMeshX"->u,"DeformedMeshY"->v,"u"->u,"v"->v},"Export to","Nodal point post"];
SMSDo[Ig,1,SMSIO["No. integration points"]];
	SMSEvaluateSaved["Element definitions"];
	Eg⊨1/2(Ct-IdentityMatrix[3]);
	σ ⊨ (1/JF)*SMSD[W, F,"Ignore"->NumberQ] . Transpose[F];
	SMSIO[{
"Sxx"->σ[[1,1]],"Sxy"->σ[[1,2]],"Sxz"->σ[[1,3]],"Syx"->σ[[2,1]],"Syy"->σ[[2,2]],
"Syz"->σ[[2,3]],"Szx"->σ[[3,1]],"Szy"->σ[[3,2]],"Szz"->σ[[3,3]],
"Exx"->Eg[[1,1]],"Exy"->Eg[[1,2]],"Exz"->Eg[[1,3]],"Eyx"->Eg[[2,1]],"Eyy"->Eg[[2,2]]
,"Eyz"->Eg[[2,3]],"Ezx"->Eg[[3,1]],"Ezy"->Eg[[3,2]],"Ezz"->Eg[[3,3]]}
,"Export to","Integration point post"[Ig]];
SMSEndDo[];

SMSWrite[];

SMTInputData[];
SMTAddDomain["d","tmpTest",{}];
SMTAddMesh[Polygon[{{0,0},{48,44},{48,44+16},{0,44}}],"d","Q1",{3,3}];
SMTAddEssentialBoundary[Line[{{0,0},{0,44}}],1->0,2->0];
SMTAddNaturalBoundary[ Line[{{48,44},{48,44+16}}],2->Line[{-1000}]];
SMTAnalysis[];
nstep=10;Δλ=0.1;tolNR=10^-8;maxNR=15;
Do[
SMTNextStep["Δλ"->Δλ];
While[SMTConvergence[tolNR,maxNR],SMTNewtonIteration[];];
,{i,1,nstep}]
SMTShowMesh["DeformedMesh"->True,"BoundaryConditions"->True]

Example: dynamically created multi-field element IO

Create an element with the following nodes and nodal unknowns:

4 topological nodes with 2 unknowns for discretization of displacements

4 additional nodes with 1 unknown for discretization of temperature field

1 additional node with 1 unknown for local Lagrange type constrain equation

<<"AceGen`";
SMSInitialize["tmpTest","Environment"->"AceFEM"];
SMSTemplate["SMSTopology"->"Q1"];

Definition of  the first user subroutine.

SMSStandardModule["Tangent and residual"];

definition of topological nodes and nodal unknowns for discretization of displacements

X=SMSIO["Nodal coordinates",Table["X"[i],{i,SMSNoNodes}]]
p=SMSIO["Nodal DOFs",Table["u"[i]->{SMSNoDimensions,"D"},{i,SMSNoNodes}]]

{SMSNoNodes,SMSNodeID,SMSDOFGlobal,SMSAdditionalNodes}

SMSIO["Nodal coordinates"]

SMSIO["Nodal coordinates","X"[3]]

SMSIOInfo["Nodal coordinates","X"[3],"Export"]

SMSIOInfo["Nodal coordinates","Key"]

definition of additional nodes and nodal unknowns for discretization of temperature field

𝕏T=SMSIO["Nodal coordinates",Table["XT"[i]->i,{i,4}]]
𝕋IO=SMSIO["Nodal DOFs",Table["Te"[i]->{1,"T -M"},{i,4}]]

{SMSNoNodes,SMSNodeID,SMSDOFGlobal,SMSAdditionalNodes}

definition of additional node and nodal unknown for local Lagrange type constrain equation

SMSIO["Nodal coordinates","LC"->"Auxiliary"]

𝕃IO=SMSIO["Nodal DOFs","L"->{1,"LC -LP"}]

{SMSNoNodes,SMSNodeID,SMSDOFGlobal,SMSAdditionalNodes}

Definition of  the second user subroutine.

SMSStandardModule["Postprocessing"];

IO data structures are automatically updated based on previous definitions

SMSIO["Nodal coordinates","X"[3]]

𝕏IO=SMSIO["Nodal coordinates"]

𝕡eIO=SMSIO["Nodal DOFs"]

Example: low-level IO data definitions

<<"AceGen`";
SMSInitialize["tmpTest","Environment"->"AceFEM"];
SMSTemplate["SMSTopology"->"Q1","SMSSymmetricTangent"->True,"SMSDomainDataNames"->{"E -elastic modulus","ν -poisson ratio","t -thickness"},
"SMSDefaultData"->{21000,0.3,1}
];
SMSStandardModule["Tangent and residual"];
SMSDo[Ig,1,SMSInteger[es$$["id","NoIntPoints"]]];
Ξ={ξ,η,ζ}⊢Table[SMSReal[es$$["IntPoints",i,Ig]],{i,3}];
XIO⊢Table[SMSReal[nd$$[i,"X",j]],{i,SMSNoNodes},{j,SMSNoDimensions}];
uIO⊢SMSReal[Table[nd$$[i,"at",j],{i,SMSNoNodes},{j,SMSDOFGlobal[[i]]}]];
Nh⊨1/4 {(1-ξ)(1-η),(1+ξ)(1-η),(1+ξ)(1+η),(1-ξ)(1+η)};
X⊢SMSFreeze[Append[Nh.XIO,ζ]];
Je⊨SMSD[X,Ξ];Jed⊨Det[Je];
u⊨Append[Nh.uIO,0];
H⊨SMSD[u,X,"Dependency"->{Ξ,X,SMSInverse[Je]}];
SMSFreeze[F,IdentityMatrix[3]+H,"Ignore"->PossibleZeroQ];
JF⊨Det[F];Ct⊨Transpose[F].F;
{Em,ν,tζ}⊢SMSReal[Table[es$$["Data",i],{i,Length[SMSDomainDataNames]}]];
{λ,μ}⊨SMSHookeToLame[Em,ν];
W⊨1/2 λ (JF-1)^2+μ (1/2 (Tr[Ct]-3)-Log[JF]);
wgp⊢SMSReal[es$$["IntPoints",4,Ig]];
pe=Flatten[uIO];
SMSDo[
Rgi⊨ Jed tζ wgp SMSD[W,pe,i];
SMSExport[Rgi,p$$[i],"AddIn"->True];
SMSDo[
Kgij⊨SMSD[Rgi,pe,j];
SMSExport[Kgij,s$$[i,j],"AddIn"->True];
,{j,i,8}];
,{i,1,8}];
SMSEndDo[];
SMSWrite[];

SMTInputData[];
SMTAddDomain["d","tmpTest",{}];
SMTAddMesh[Polygon[{{0,0},{48,44},{48,44+16},{0,44}}],"d","Q1",{3,3}];
SMTAddEssentialBoundary[Line[{{0,0},{0,44}}],1->0,2->0];
SMTAddNaturalBoundary[ Line[{{48,44},{48,44+16}}],2->Line[{-1000}]];
SMTAnalysis[];
nstep=10;Δλ=0.1;tolNR=10^-8;maxNR=15;
Do[
SMTNextStep["Δλ"->Δλ];
While[SMTConvergence[tolNR,maxNR],SMTNewtonIteration[];];
,{i,1,nstep}]
SMTShowMesh["DeformedMesh"->True,"BoundaryConditions"->True]

Utility IO data management commands

Integer Type Environment Variables

General data

Mesh input related data

Iterative procedure related data

Debugging and errors related data

Linear solver related data

Sensitivity related data

Contact related data

The data is in  AceGen input created with SMSIO[idataCode] (see IO Data Management, General Input data, SMTIData).

General data

Mesh input related data

Iterative procedure related data

See: Iterative Solution Procedures, SMTConvergence, SMTStatusReport, SMTErrorCheck

Debugging and errors related data

See: Iterative Solution Procedures, SMTConvergence, SMTStatusReport, SMTErrorCheck

Linear solver related data

Sensitivity related data

The relevance of the specific data depends on the type of sensitivity analysis (forward or backward). See also  Sensitivity Analysis.

Contact related data

Real Type Environment Variables

Node Specification Data

One of the input parameters of the user subroutines is a list of pointers to the node specification of all nodes. The ns$$[ i , ...] construct represents the node specification data structure that belongs to the i-th local element node.

Node specification data structure.

Node Data

see Nodal Input data, SMTNodeData

Nodal data structures.

Nodal data related to sensitivity analysis.

For more details see AceFEM implementation of Sensitivity Analysis.

Domain Specification Data

General Data

Run Mathematica from code

Memory allocation

Domain input data

Mesh generation

Numerical integration

Graphics postprocessing

Sensitivity analysis

General Data

General Domain Specification Data

Relations between the template constants, AceGen and AceFEM

Run Mathematica from code

Memory allocation

Relations between the template constants, AceGen and AceFEM

Mesh generation

Numerical integration

Relations between the template constants, AceGen and AceFEM

Graphics post-processing

Relations between the template constants, AceGen and AceFEM

Sensitivity analysis

For more details see AceFEM implementation of Sensitivity Analysis.

Element Data

see Element Input data, SMTElementData

Element data structure.

Element Topology

Contents

Zero dimensional

One dimensional

Two dimensional

Three dimensional

SMCFEMTopologyData

Element topology type defines an outline of the element, dimensions, embedded spatial dimensions, number of nodes, default number of DOF per node, etc. The topology of the element can be defined in several basic ways:

When the element has one of the standard topologies with fixed number of nodes, then the proper interface for all supported environments is automatically generated. E.g. the SMSTemplate[“SMSTopology”-> “Q1”] command defines two dimensional, 4 node element.

Standard topology with fixed number of nodes can be enhanced by an arbitrary number of additional nodes (see Node Identification).

Element topology with arbitrary number of nodes and nonstandard numbering of nodes, but known general topology is defined with an “X” at the end. E.g. the SMSTemplate[“SMSTopology”->”TX”, SMSNoNodes ->5] command defines an element that has a triangular shape and 5 nodes, but the numbering of the nodes is arbitrary. All nodes have to be specified at the mesh generation phase.

If the element topology is completely unknown (“SMSTopology”->”XX”), then the number of dimensions and the number of nodes have to be specified explicitly and the proper interface is left to the user.

The coordinate systems in the figures below are only informative (e.g. X, Y can also stand for axisymmetric coordinate system X, Y, ϕ).

SMCFEMTopologyData

1 ... spatial dimensions

2 ... number of nodes

3 ... segments

4 ... element dimensions

5 ... description

"Q1"/. SMCFEMTopologyData

Undefined

Zero dimensional

One dimensional

Two dimensional

Three dimensional

Node Identification

Contents

Node Types and Switches

AceFEM Code Generation Utility Functions

SMSIsDOFConstrained

SMSNoDummyNodes

SMSLastTrueNode

SMSLastTrueDOF

SMSIsDummyNode

SMSIsRealNode

Self-transforming meshes

Node Identification Examples

Node Types and Switches

The node identification is a string that is used for identification of the nodes accordingly to the physical meaning of the nodal unknowns. Node identification is used by the SMTAnalysis command to construct the final FE mesh on a basis of the user defined topological mesh. Node identification can have additional switches (see table below). In order to have consistent set of elements one has to use the same names for the nodes with the same physical meaning. Standard node identification are: "D" - node with displacements for d.o.f.,  "DFi" - node with displacements and rotations for d.o.f.,  "T"-node with temperature d.o.f, "M"- node with magnetic potential d.o.f. etc.. 
Some node identification are reserved and can not be used. Reserved node identification are as follows:

"Multiplier"

"Time"

"X" "Y" "Z" "ID" 
This strings cannot be used because they are used to select nodes (see Selecting Nodes).

Accordingly to the node identification switches a node can be one of three basic types:

Topological node
Topological node belongs to a specific position in space. It can have associated unknowns.

Auxiliary node
Auxiliary node does not belong to a specific position in space and is created automatically. Auxiliary node can have associated unknowns. Instead of the nodal coordinates a Null sign must be given. Actual coordinates in a data base are set to zero. An auxiliary node can be a local auxiliary node, thus created for each element separately or a global auxiliary node, thus created at the level of the structure.
See also Self-transforming meshes, Mixed 3D Solid FE, Auxiliary Nodes

Dummy node
Dummy node does not belong to a specific position in space and have no associated unknowns.  Instead of the nodal coordinates a Null sign must be given. The actual coordinates of the node in a data base are set to zero. Only one nodal data structure is generated for all dummy nodes with particular node identification. Dummy nodes can only appear as automatically generated additional nodes. The dummy nodes can not be selected directly by SMTFindNodes command. An index of the dummy node associated with nodes with node identification NodeID can be accessed by SMTNodeSpecData[NodeID,"DummyNode"] command.

Basic node identifications switches.

During the final mesh generation two or more nodes with the same coordinates and the same node identification are automatically joined (tied) together into a single node. Tieing of the nodes can be suppressed by the - T switch. All the nodes that should be unique for each element (internal nodes) should have - T switch in order to prevent accidental tieing.

The dummy node mechanism can be used to generate elements with variable number of real nodes. For example the contact element has only slave nodes when there is no contact and slave and master segment nodes in the case of contact. Thus, the master segments nodes are dummy nodes if there is no contact and real nodes in the case of contact.

The string type identification is transformed into the integer type identification at run time. Transformation rules are stored in a SMSNodeIDIndex variable.

AceFEM Code Generation Utility Functions

Functions in this section are producing code sequences that are part of generated element code and executed at AceFEM run time.

Self-transforming meshes

The combination of various node types and SMSTemplate option SMSAdditionalNodes creates environment for self-transforming meshes. The basis for the self-transforming mesh is topological mesh given as user input with SMTAddMesh command. The transformation is performed by the SMTAnalysis function after the original mesh was given by the user.
Mesh transformation is defined by mesh transformation function given as an  SMSAdditionalNodes option of the SMSTemplate command. Input argument of the function are the coordinates of the topological nodes given as mesh input data.

The output argument of the function must be a list nodes. The node in the list can be defined by:

list of coordinates

A new topological node will be generated, added to the global list of nodes and the index of the global node becomes an element of the list of element nodes.

Null

If the node is defined as an auxiliary node (-LP or -GP) then a new auxiliary node will be generated, added to the global list of nodes and the index of the global node becomes an element of the list of element nodes. If the node is defined as dummy node (-D) the dummy node index becomes an element of the list of element nodes.

local node index

Local node index refers to the nodes given as mesh input data. Index of the global node that correspond to the local index becomes an element of the list of element nodes. No new nodes are generated.

The length of the list returned can be:

less than the number of element nodes (SMTNoNodes)

In this case a new list of nodes is added to the user supplied list of element nodes, thus the combined length of the user defined nodes and newly generated nodes must be exactly the number of element nodes. In this case the SMSAdditionalNodes defines a list of nodes that are added to the user supplied nodes.

exactly the number of nodes of the element

If the length returned is exactly the number of the nodes of the element, then the new list replaces the user supplied list of element nodes. In this case the SMSAdditionalNodes defines an arbitrary mesh transformation function.

Examples of self-transforming meshes can be found in Mixed 3D Solid FE, Auxiliary Nodes, Cubic triangle, Additional nodes, 2D slave node - line master segment element,.

Node Identification Examples

Examples: Non-standard elements

Element with single node. "simc -F -C -L" identifies the node with the identification "simc" that are not shown on a graphs, unknowns associated with the node are initially constrained and the resulting tangent matrix has zeros at the main diagonal.

SMSTemplate["SMSTopology"->"V3","SMSNodeID"->"simc -F -C -L",...];

Examples: Additional nodes generated from the element

This defines the 2D, triangular element with an additional node automatically generated at the center of triangle. Command defines an element with the basic outline as three node triangle and with an additional node at the center of the element. In that case, various subsystems (e.g. mesh generation and post-processing) assume that the first three nodes form the standard triangle. At the mesh generation phase only the 3 nodes of the underlying “T1” topology have to be given and the forth node is generated automatically.

SMSTemplate["SMSTopology"->"T1",
"SMSNoNodes"->4,
"SMSNodeID"->{"A","A","A","A"},"SMSAdditionalNodes"->Function[{x1,x2,x3},{(x1+x2+x3)/3}]];

This defines the 2D, triangular element with an additional local auxiliary node. An auxiliary node has no specific spatial position indicated by the Null constant. At the mesh generation phase only the 3 nodes of the underlying “T1” topology have to be given and the forth node is generated automatically.

SMSTemplate["SMSTopology"->"T1",
"SMSNoNodes"->4,
"SMSNodeID"->{"A","A","A","B -LP"},"SMSAdditionalNodes"->Function[{},{Null}],...];

The number of nodes provided as an input can be arbitrary. This will supplement missing nodes with auxiliary nodes. All nodes are by default dummy nodes, unless they are explicitly provided as an input.

maxNodes=15;
SMSTemplate["SMSTopology"->"T1",
"SMSNoNodes"->maxNodes,
"SMSNodeID"->Table["D -D",{maxNodes}],"SMSAdditionalNodes"->Null];

This changes constant triangle into quadratic one.

SMSTemplate["SMSTopology"->"T1",
"SMSNoNodes"->6,
"SMSNodeID"->{"D","D","D","D","D","D"},"SMSAdditionalNodes"->Function[{x1,x2,x3},{(x1+x2)/2,(x2+x3)/2,(x1+x3)/2}]];

Examples: An arbitrary transformation of the list of nodes

This changes the clockwise numeration of the nodes of triangle element into counter-clockwise numeration.

SMSTemplate["SMSTopology"->"T1",
"SMSNoNodes"->3,
"SMSNodeID"->{"D","D","D"},
"SMSAdditionalNodes"->Function[{x1,x2,x3},
If[Cross[{x2[[1]]-x1[[1]],x2[[2]]-x1[[2]],0},{x3[[1]]-x1[[1]],x3[[2]]-x1[[2]],0}][[3]]>0
,{1,2,3}
,{1,3,2}]
]];

This changes constant triangle into quadratic one with an alternative node ordering.

SMSTemplate["SMSTopology"->"T1",
"SMSNoNodes"->6,
"SMSNodeID"->{"D","D","D","D","D","D"},"SMSAdditionalNodes"->Function[{x1,x2,x3},{1,(x1+x2)/2,2,(x2+x3)/2,3,(x1+x3)/2}]];

This doubles the nodes of the triangle.

SMSTemplate["SMSTopology"->"T1",
"SMSNoNodes"->6,
"SMSNodeID"->{"D","T","D","T","D","T"},"SMSAdditionalNodes"->Function[{x1,x2,x3},{1,x1,2,x2,3,x3}]];

This doubles the nodes of an arbitrary polygon. The maximum number of nodes of the polygon has to specified in advance. All nodes are originally defined as dummy nodes and replaced later by the real nodes at the mesh generation phase. Note that the ## in the function definition represents the complete set of user defined nodes.

With[{maxNodes=15},
SMSTemplate["SMSTopology"->"T1"
,"SMSNoNodes"->2maxNodes
,"SMSNodeID"->Flatten[Table[{"D -D","T -D"},{maxNodes}]]
,"SMSAdditionalNodes"->Function[PadRight[Flatten[MapIndexed[{#2[[1]],#}&,{##}],1],2 maxNodes,Null]]
];
];

Numerical Integration

Contents

One dimensional

Quadrilateral

Triangle

Tetrahedra

Hexahedra

Implementation of Numerical Integration

Example 1: SMSIO Input/Output data management

Example 2: hard coded integration rules

Example 3: low-level definition of IO data

The coordinates and the weight factors for numerical integration for several standard element topologies are available. Specific numerical integration is defined by its code number.

One dimensional

Cartesian coordinates of the reference element: {ζ ,η, ζ} ∈ [-1,1] × [0,0] × [0,0]

Quadrilateral

Cartesian coordinates of the reference element: {ζ ,η, ζ} ∈ [-1,1] × [-1,1] × [0,0]

Triangle

AREA coordinates of the reference element: {ζ ,η, ζ} ∈ [0,1] × [0,1] × [0,0]

Tetrahedra

AREA coordinates of the reference element: {ζ ,η, ζ} ∈ [0,1] × [0,1] × [0,1]

Hexahedra

Cartesian coordinates of the reference element: {ζ ,η, ζ} ∈ [-1,1] × [-1,1] × [-1,1]

Implementation of Numerical Integration

Numerical integration is available under all supported environments as a part of supplementary routines. The coordinates and the weights of integration points are set automatically before the user subroutines are called. They can be obtained inside the user subroutines for the i-th integration point in a following way

(Subscript[ξ, i])⊢SMSReal[es$$["IntPoints",1,i]]
(Subscript[η, i])⊢SMSReal[es$$["IntPoints",2,i]]
(Subscript[ζ, i])⊢SMSReal[es$$["IntPoints",3,i]]
(Subscript[w, i])⊢SMSReal[es$$["IntPoints",4,i]]

where {(Subscript[ξ, i]) (Subscript[η, i]), (Subscript[ζ, i])} are the coordinates and (Subscript[w, i]) is the weight. The coordinates of the reference element are CARTESIAN for the one dimensional, quadrilateral and hexahedra topologies and AREA coordinates for the triangle and tetrahedra topologies. The integration points are constructed accordingly to the given integration code. Codes for the basic one two and three dimensional numerical integration rules are presented in tables below. Basic integration codes can be combined in order to get more complicated multi-dimensional integration rules. The combined code is given in the domain specification input data as a list of up to three basic codes as follows:
{codeA} ≡  codeA
{codeA,codeB}
{codeA,codeB,codeC}

where codeA, codeB and codeC are any of the basic integration codes. For example 2×2×5 Gauss integration can be represented with the code {2, 24} or equivalent code {21, 21, 24}. The integration code 7 stands for three dimensional 8 point (2×2×2) Gauss integration rule and integration code 21 for one dimensional 2 point Gauss integration. Thus the integration code 7 and the code {21,21,21} represent identical integration rule.

The numbering of the points is for the Cartesian coordinates depicted below.

Example 1: SMSIO Input/Output data management

This generates simple loop over all given integration points for 3D integration. Proper  data interface is created by IO Data Management. Integration points and weights are calculated at run time.

SMSDo[Ig,1,SMSIO["No. integration points"]];
	Ξ={ξ,η,ζ}⊨SMSIO["Integration point"[Ig]];
	wgp⊨SMSIO["Integration weight"[Ig]];
         …
SMSEndDo[];

This generates simple loop over all given integration points for 2D integration.

SMSDo[Ig,1,SMSIO["No. integration points"]];
	{ξ,η}⊨SMSIO["Integration point"[Ig]][[{1,2}]];
	wgp⊨SMSIO["Integration weight"[Ig]];
         …
SMSEndDo[];

This generates simple loop over all given integration points for 1D integration.

SMSDo[Ig,1,SMSIO["No. integration points"]];
	ξ⊨SMSIO["Integration point"[Ig]][[1]];
	wgp⊨SMSIO["Integration weight"[Ig]];
         …
SMSEndDo[];

Example 2: hard coded integration rules

Integration points and weights can be calculated in advance and hard coded into element code as well. This is useful if one needs several different integration rules within the same finite element.

This generates simple loop over all given integration points for 3×3×3 Gauss integration (code 27).

SMSDo[Ig,1,SMSIO["No. integration points"[27]]];
	Ξ={ξ,η,ζ}⊨SMSIO["Integration point"[Ig][27]];
	wgp⊨SMSIO["Integration weight"[Ig][27]];
         …
SMSEndDo[];

This generates simple loop over all given integration points for 10×2×2 Gauss integration (code {29,21,21}).

SMSDo[Ig,1,SMSIO["No. integration points"[{29,21,21}]]];
	Ξ={ξ,η,ζ}⊨SMSIO["Integration point"[Ig][{29,21,21}]];
	wgp⊨SMSIO["Integration weight"[Ig][{29,21,21}]];
         …
SMSEndDo[];

Example 3: low-level definition of IO data

In the case of the combined integration code, the integration can be also performed separately for each set of points. low-level definition of IO data has to be used in this case (see IO Data Management).

{nA,nB,nC}⊢SMSInteger[{es$$["id","NoIntPointsA"], es$$["id","NoIntPointsB"],es$$["id","NoIntPointsC"]}]
SMSDo[iξ,1,nA];
  ξ⊢SMSReal[es$$["IntPoints",1,iξ]];
  …
  SMSDo[iη,1,nB];
    η⊢SMSReal[es$$["IntPoints",2,(iη-1) nA+1]];
    …
    SMSDo[iζ,1,nC];
      ζ⊢SMSReal[es$$["IntPoints",3,(iζ-1) nA nB+1]];
      w⊢SMSReal[es$$["IntPoints",4,iξ+(iη-1)nA +(iζ-1) nA nB]];
      …
    SMSEndDo[];    …
         SMSEndDo[];
SMSEndDo[];

Elimination of Local Unknowns

Some elements have additional internal degrees of freedom that do not appear as part of formulation in any other element. Those degrees of freedom can be eliminated before the assembly of the global matrix, resulting in a reduced number of equations. The structure of the tangent matrix and the residual before the elimination should be as follows:

(({{(Subscript[K, uu]^n), (Subscript[K, uh]^n)}, {(Subscript[K, hu]^n), (Subscript[K, hh]^n)}})).(({{((Δu)^n)}, {((Δh)^n)}}))=(({{-(Subscript[R, u]^n)}, {-(Subscript[R, h]^n)}}))    ⟹  (Subscript[K, cond]) ((Δu)^n)=-(Subscript[R, cond])

where u is a global set of unknowns, 'n' is an iteration number and h is a set of unknowns that has to be eliminated. The built in mechanism ensures automatic condensation of the local tangent matrix before the assembly of the global tangent matrix as follows:

(Subscript[K, cond])=(Subscript[K, uu]^n) -(Subscript[K, uh]^n) (Subscript[H, a]^n)
(Subscript[R, cond])=(Subscript[R, u]^n) +(Subscript[K, uh]^n)(Subscript[H, b]^n)

where (Subscript[H, a]) is a matrix and (Subscript[H, b]) a vector defined as
(Subscript[H, a]^n)=((Subscript[K, hh]^n)^(-1))(Subscript[K, hu]^n)
(Subscript[H, b]^n)=-((Subscript[K, hh]^n)^(-1)) (Subscript[R, h]^n).
The actual values of the local unknowns are calculated first time when the element tangent and residual subroutine is called by:
(h^(n+1))=(h^n)+(Subscript[H, b])-(Subscript[H, a]) ((Δu)^n) .
Three quantities have to be stored at the element level for the presented scheme: the values of the local unknowns (h^n), the (Subscript[H, b]^n) matrix and the (Subscript[H, a]^n) matrix. The default values are available for all constants, however user should be careful that the default values do not interfere with his own data storage scheme. When default values are used, the system also increases the constants that specify the allocated memory per element (SMSNoTimeStorage and SMSNoElementData). 
The total storage per element required for the elimination of the local unknowns is:
SMSNoDOFCondense+SMSNoDOFCondense+SMSNoDOFCondense*SMSNoDOFGlobal

It is assumed that the sensitivity of the local unknowns (((δh)^n)) is stored as follows:
{((∂(Subscript[h, 1]))/(∂(Subscript[p, 1]))),((∂(Subscript[h, 1]))/(∂(Subscript[p, 2]))),...,((∂(Subscript[h, 1]))/(∂(Subscript[p, NoSensDerivatives]))),((∂(Subscript[h, 2]))/(∂(Subscript[p, 1]))),((∂(Subscript[h, 2]))/(∂(Subscript[p, 1]))),...,((∂(Subscript[h, SMSNoDOFCondense]))/(∂(Subscript[p, NoSensDerivatives])))}

The template constant SMSCondensationData stores pointers to the beginning of the corresponding data field as follows:

Storage scheme for the elimination of the local unknowns.

The the actual position is calculated accordingly to the data provided to the SMSTemplate command as follows:

All three inputs given below would yield the same default storage scheme if no time storage was previously prescribed. See also: Mixed 3D Solid FE, Elimination of Local Unknowns .

SMSTemplate["SMSTopology"->"H1","SMSNoDOFCondense"->9]

SMSTemplate["SMSTopology"->"H1","SMSNoDOFCondense"->9,"SMSCondensationData"->ed$$["ht",1],"SMSNoTimeStorage"->9]

SMSTemplate["SMSTopology"->"H1","SMSNoDOFCondense"->9,"SMSCondensationData"->{ed$$["ht",1],ed$$["ht",10],ed$$["ht",19],ed$$["ht",235]},"SMSNoTimeStorage"->234+9 idata$$["NoSensDerivatives"]]

Example

Let assume that SMSNoTimeStorage constant has value le before the SMSWrite command is executed and that the local unknowns were allocated by the "SMSNoDOFCondense" -> nhe template constant. The true allocation of the storage is then done automatically by the SMSWrite command. The proper AceGen input and the position of the data within the "ht" history field that corresponds to the input is as follows:

SMSInitialize["test", "Environment" -> "AceFEM"];
SMSTemplate["SMSTopology" -> "Q1", "SMSNoTimeStorage"->le,"SMSNoDOFCondense" -> nhe]

hi⊢SMSReal[Array[ed$$["ht",le+ #] &, nhe]];
j⊢SMSInteger[idata$$["SensIndex"]];
δhi⊢SMSReal[Array[ed$$["ht",le + 2 nhe + nhe*SMSNoDOFGlobal + (j - 1)*nhe + #] &, nhe]];
....
SMSWrite[]

See also: Mixed 3D Solid FE, Elimination of Local Unknowns

Standard User Subroutines

Contents

SMSStandardModule

Standard User Subroutines

Subroutine: Tangent and residual

Subroutine: Postprocessing

Subroutine: sensitivity analysis related subroutines

Subroutine: Tasks

SMSStandardModule

There is a standard set of input/output arguments passed to all user subroutines as shown in the table below. The arguments are in all supported source code languages are passed "by address", so that they can be either input or output arguments. The element data structures can be set and accessed from the element code as the AceGen external variables. For example, the command SMSReal[nd$$[i,"X",1]] returns the  first coordinate of the i-th element node. The data returned are always valid for the current element that has been processed by the FE environment.

Some additional I/O arguments are needed for specific tasks as follows:

The user defined subroutines described here are connected with a particular element. For the specific tasks such as shape sensitivity analysis additional element independent user subroutines my be required (e.g. see Standard User Subroutines ).

All the environments do not support all user subroutines. In the table below the accessibility of the user subroutine according to the environment is presented. The subroutine without the mark should be avoided when the code is generated for a certain environment.

This creates the element source with the environment dependent supplementary routines and the user defined subroutine "Tangent and residual". The code is created for the 2D, quadrilateral element with 4 nodes, 5 degrees of freedom per node and two material constants. Just to illustrate the procedure the X coordinate of the first element node is exported as the first element of the element residual vector p$$. The element is generated for AceFEM and FEAP environments. The AceGen input and the generated codes are presented.

<<AceGen`;
SMSInitialize["test","Environment"->"AceFEM"];
SMSTemplate["SMSTopology"->"Q1","SMSDOFGlobal"->5,
"SMSDomainDataNames"->{"Constant 1","Constant 2"}];
SMSStandardModule["Tangent and residual"];
SMSExport[SMSReal[nd$$[1,"X",1]],p$$[1]];
SMSWrite[];

FilePrint["test.c"]

<<AceGen`;
SMSInitialize["test","Environment"->"FEAP"];
SMSTemplate["SMSTopology"->"Q1","SMSDOFGlobal"->5,"SMSDomainDataNames"->{"Constant 1","Constant 2"}];
SMSStandardModule["Tangent and residual"];
SMSExport[SMSReal[nd$$[1,"X",1]],p$$[1]];
SMSWrite[];

Standard User Subroutines

Subroutine: "Tangent and residual"

The "Tangent and residual" standard user subroutine returns the tangent matrix and residual for the current values of nodal and element data.
See Standard FE Procedure  and

Example: IO data defined by SMSTemplate constants

Example: dynamically created IO data variables

Example: low-level of IO data definitions

Subroutine: "Postprocessing"

The "Postprocessing" user subroutine returns two arrays with arbitrary number of post-processing quantities as follows:
=>	gpost$$ array of  the integration point quantities with the dimension "number of integration points"×"number of integration point quantities",
=>	npost$$ array of the nodal point quantities with the dimension "number of nodes"×"number of nodal point quantities".
The dimension and the contents of the arrays are defined by the two vectors of strings SMSGPostNames and SMSNPostNames. They contain the keywords of post-processing quantities. Those names are also used in the analysis to identify specific quantity (see SMTPostData).
The keywords can be arbitrary. It is the responsibility of the user to keep the keywords of the post-processing quantities consistent for all used elements. Some keywords are reserved and have predefined meaning as follows:

See also:

Example: IO data defined by SMSTemplate constants

Example: dynamically created IO data variables

Example: low-level of IO data definitions

This outlines the major parts of the "Postprocessing" user subroutine using IO data interface.

(* template constants related to the post-processing*)
SMSTemplate[
"SMSSegments"->…,"SMSReferenceNodes"->…,"SMSPostNodeWeights"->…,"SMSAdditionalGraphics"->…
]

SMSStandardModule["Postprocessing"];
(* nodal post-processing *)
{u,v}⊨Transpose[SMSIO["Nodal DOFs"]];
SMSIO[{"DeformedMeshX"->u,"DeformedMeshY"->v,"u"->u,"v"->v},"Export to","Nodal point post"];
(* integration point post-processing *)
SMSDo[Ig,1,SMSIO["No. integration points"]];
	…
	SMSIO[{"Sxx"->σ[[1,1]],"Sxy"->σ[[1,2]],…},"Export to","Integration point post"[Ig]];
SMSEndDo[];

This outlines the major parts of the "Postprocessing" user subroutine with low-level I/O interface.

(* template constants related to the post-processing*)
SMSTemplate[
"SMSSegments"->…,"SMSReferenceNodes"->…,"SMSPostNodeWeights"->…,"SMSAdditionalGraphics"->…
]

SMSStandardModule["Postprocessing"];

(* integration point post-processing *)
SMSGPostNames={"Sxx","Syy","Sxy",...};
SMSDo[Ig,1,SMSInteger[es$$["id","NoIntPoints"]]];
  (* export integration point post-processing values to Ig-th integration point*)
   SMSExport[{Sxx,Syy,Sxy,...},gpost$$[Ig,#1]&];
SMSEndDo[];

(* nodal post-processing *)
SMSNPostNames={"DeformedMeshX","DeformedMeshY","DeformedMeshZ","a","b",...};
(* Example: export nodal point post-processing values for all nodes*)
SMSExport[Table[{ui[[i]],vi[[i]],w[[i]],a[[i]],b[[i]],…},{i,1,SMSNoNodes}],npost$$];

(* Example: export nodal point post-processing values to i-th nodes*)
SMSDo[node,1,SMSNoNodes]
uNode=…;…
SMSExport[{uNode,vNode,wNode,aNode,bNode,…},npost$$[node,#]&];
SMSEndDo[]

Integration point quantities are mapped to nodes accordingly to the type of extrapolation as follows:
Type 0: Least square extrapolation from integration points to nodal points is used. 
Type 1:  The integration point value is multiplied by the weight factor. Weight factor can be e.g the value of the shape functions at the integration point and have to be supplied by the user. By default the last NoNodes integration point quantities are taken for the weight factors (see SMTPostData).
The type of extrapolation is defined by the value of idata$$["ExtrapolationType"]. The nodal value is additionally multiplied by the user defined nodal wight factor that is stored in element specification data structure for each node (es$$["PostNodeWeights",nodenumber]). Default value of the nodal weight factor is 1 for all nodes. It can be changed by setting the SMSPostNodeWeights template constant.

Subroutine: sensitivity analysis related subroutines

See AceFEM manual sections Sensitivity Analysis.

Subroutine: "Tasks"

See AceFEM manual sections User Defined Tasks.

User Defined Environment Interface

Regenerate the heat conduction element from chapter Standard FE Procedure for arbitrary user defined C based finite element environment in a way that element description remains consistent for all environments.

Here the SMSStandardModule["Tangent and residual"] user subroutine is redefined for user environment. Mathematica has to be restarted in order to get old definitions back!!!

<<AceGen`;
SMSStandardModule["Tangent and residual"]:=
   SMSModule["RKt",Real[D$$[2],X$$[2,2],U$$[2,2],load$$,K$$[4,4],S$$[2]]];

Here the replacement rules are defined that transform standard input/output parameters to user defined input/output parameters.

datarules={nd$$[i_,"X",j_]:>X$$[i,j],
nd$$[i_,"at",j_]:>U$$[i,j],
es$$["Data",i_]:>D$$[i],
s$$[i_,j_]:>K$$[i,j],
p$$[i_]:>S$$[i],
rdata$$["Multiplier"]->load$$};

The element description remains essentially unchanged.
Additional subroutines (for initialization, dispatching of messages, etc..) can be added to the source code using the "Splice" option of SMSWrite command. The "splice-file" is arbitrary text file that is first interpreted by the Mathematica´s Splice command and then prepended to the automatically generated source code file.

SMSInitialize["UserEnvironment","Environment"->"User","Language"->"C"];
SMSTemplate["SMSTopology"->"H1","SMSDOFGlobal"->1,"SMSSymmetricTangent"->False,"SMSDomainDataNames"->{"Conductivity parameter k0","Conductivity parameter k1",
"Conductivity parameter k2","Heat source"}
,"SMSUserDataRules"->datarules];
SMSStandardModule["Tangent and residual"];
SMSDo[Ig,1,SMSInteger[es$$["id","NoIntPoints"]]];
Ξ={ξ,η,ζ}⊢Table[SMSReal[es$$["IntPoints",i,Ig]],{i,3}];
XI⊢Table[SMSReal[nd$$[i,"X",j]],{i,SMSNoNodes},{j,SMSNoDimensions}];Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];
X⊢SMSFreeze[NI.XI];Jg⊨SMSD[X,Ξ];Jgd⊨Det[Jg];
ϕI⊢SMSReal[Table[nd$$[i,"at",1],{i,SMSNoNodes}]];
ϕ⊨NI.ϕI;
{k0,k1,k2,Q}⊢SMSReal[Table[es$$["Data",i],{i,Length[SMSDomainDataNames]}]];
k⊨k0+k1 ϕ+k2 (ϕ^2);
SMSSetBreak["k"];
λ⊢SMSReal[rdata$$["Multiplier"]];
wgp⊢SMSReal[es$$["IntPoints",4,Ig]];
SMSDo[
Dϕ⊨SMSD[ϕ,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];
δϕ⊨SMSD[ϕ,ϕI,i];
Dδϕ⊨SMSD[δϕ,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];
Rg⊨Jgd wgp(k Dδϕ.Dϕ-δϕ λ Q);
SMSExport[SMSResidualSign Rg,p$$[i],"AddIn"->True];
SMSDo[
Kg⊨SMSD[Rg,ϕI,j];
SMSExport[Kg,s$$[i,j],"AddIn"->True];
,{j,1,8}
];
,{i,1,8}
];
SMSEndDo[];
SMSWrite[];

Quit[];

AceFEM

About AceFEM

The AceFEM package is a general finite element environment designed for solving multi-physics and multi-field problems. (see also AceFEM Overview)

Examples related to the automation of the Finite Element Method using AceFEM are part of AceFEM documentation (see  Summary of Examples ).

FEAP - ELFEN - ABAQUS - ANSYS

Contents

Running the generated code with the target numerical environment

SMSFEEnvironment

ABAQUS

FEAP

ELFEN

ANSYS

Running the generated code with the target numerical environment

AceGen can automatically compile and link the generated codes into the target numerical environment, if the proper script files are written by the user. Script files are located at the  FileNameJoin[{$BaseDirectory,"Applications","AceGen","Include", environment}] directory.
User must adjust the script files accordingly to his specific operating system, FORTRAN compiler and  environment version.

The following script template files are needed depending on the task executed:

The environmentCompile.bat file is a script template file used to compile the element source code into object file. The environmentRun.bat file is a script template file used to link the compiled source code into environment and run the simulation using the given simulation input data file. The script template files are using the Wolfram Language symbolic template framework (see Working with Templates). The script template file is first interpreted by the Wolfram Language  Symbolic Templating framework and then written to the working directory. The following special form can be used in the template script file:

`slotname` is literary replaced by the value of the slotname

<*expr*>is replaced by the evaluated expr. expr  is an arbitrary expression where template slots appear as  #slotname (e.g. <*#SourceCodeFileName<>”.for”*> would produce a name of the file together with its extension)

The following slot names are provided:

In order to compile and link a new element or user subroutine with environment we need:

header file sms.h (available at FileNameJoin[{$BaseDirectory,"Applications","AceGen","Include", environment}])

utility library "libaceutilityWinIntelF.lib"/"libaceutilityMacF.lib"/"libaceutilityLinuxF.lib" ( available at FileNameJoin[{$BaseDirectory,"Applications","AceGen","Include","Fortran"}])

user element or other user subroutines source code file.

SMSFEEnvironment

ABAQUS

(ABAQUS^©) is a commercial FE environment developed by ABAQUS, Inc.
The generated code is linked with the (ABAQUS^©) through the user element subroutines (UEL) and user material subroutines (UMAT). Currently the interface for (ABAQUS^©)  support direct, static implicit analysis. The interface does not support elements with the internal degrees of freedom. Supplementary files are available at FileNameJoin[{$BaseDirectory,"Applications","AceGen","Include", "ABAQUS"}] directory. See also (HyperlinkTemplate[Installation instructions, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, HyperlinkActionRecycled, HyperlinkActive, , ]) for instructions how to compile and link the generated codes.

User material subroutine for ABAQUS

AceGen provides an automatic interface for the generation of the user material subroutine for ABAQUS. Input/Output parameters of the UMAT subroutine are different from the I/O parameters of the UEL subroutine. In general UMAT receives the deformation tensors and returns the stress tensor together with the material constitutive matrix. The automatic interface ensures maximal compatibility between the standardized user element interface and user material interface, however only the constants and variables that have meaning at material point are actually available in UMAT subroutine.

The traditional FEM environments are more oriented towards mechanics of solids and require definition of an additional template constants for the construction of proper interface code. Additional numerical environment dependent constants are defined automatically and can be used within the code generation process. Default values are based on the number of spatial dimensions and are not correct for some special cases such as plane stress condition.

Stress tensor and constitutive matrix must be vectorized accordingly to ABAQUS manual. Stress tensor is vectorized as:

TensorComponents=Switch[ContinuumModel
,"PS",
{{1,1},{2,2},{1,2}}
,"PE"|"AX",
{{1,1},{2,2},{3,3},{1,2}}
,"D3",
{{1,1},{2,2},{3,3},{1,2},{1,3},{2,3}}
]
Extract[σ,TensorComponents]

Constitutive tensor is vectorized by:

Table[Extract[DσD𝔼,Join[i1, i2]],{i1,TensorComponents},{i2,TensorComponents}]

Example of 3D hyper-elastic user material subroutine for ABAQUS

<<"AceGen`";
SMSInitialize["test","Environment"->"ABAQUS"];
SMSTemplate["SMSUserSubroutine"->"UMAT"
,"SMSTopology"->"XX","SMSNoDimensions"->3,"SMSNoNodes"->0,"SMSNoTensorComponents"->6
,"SMSDomainDataNames"->{"E -elastic modulus","ν -poisson ratio","β -volumetric strain exponent"}
,"SMSDefaultData"->{21000,0.3,-2}];
SMSStandardModule["ABAQUS UMAT"];
{Em,ν,β}⊢SMSReal[Table[es$$["Data",i],{i,Length[SMSDomainDataNames]}]];

deformation gradient: needs NLGEOM=YES set in ABAQUS input

F⊢SMSReal[Array[F$$,{3,3}]];
JF⊨Det[F];
SMSFreeze[be,F.F\[Transpose],"Symmetric"-> True];
Jbe=Det[be];
{μ,Κ}⊨SMSHookeToBulk[Em,ν];
W⊨ (μ/2)((Jbe^(-1/3))Tr[be]-3)+(Κ/(β^2))((Jbe^(-β/2))-1+(β/2) Log[Jbe]);
τ⊨Simplify[2 be.SMSD[W,be,"Ignore"-> NumberQ,"Symmetric"->True]];
σ⊨τ/JF;
DτDF⊨SMSD[τ,F];
(*material constitutive matrix for isotropic materials*)
DσDE⊨Table[Sum[
F[[l,m]]DτDF[[i,j,k,m]]+F[[k,m]]DτDF[[i,j,l,m]],{m,3}],
{l,3},{k,3},{j,3},{i,3}]/JF/2;
SMSExport[W,W$$];

stress tensor and constitutive matrix is vectorized accordingly to ABAQUS manual

TensorComponents={{1,1},{2,2},{3,3},{1,2},{1,3},{2,3}};
SMSExport[Extract[σ,TensorComponents],S$$];
SMSExport[Table[Extract[DσDE,Join[i1, i2]],{i1,TensorComponents},{i2,TensorComponents}],DSDE$$];

SMSWrite[];

Here is the generated UMAT code compiled and linked into the ABAQUS. The SMSFEEnvironment compiles the source code file, links the resulting object file into ABAQUS and starts ABAQUS.

SMSFEEnvironment["ABAQUS","SourceCode"->"test","SimulationInputFile"->"test.dat","SimulationOutputFile"->"test.res"]

User element subroutine for ABAQUS

Regenerate the three-dimensional, eight node finite element described in AceFEM documentation (see Mixed 3D Solid FE, Elimination of Local Unknowns) for ABAQUS environment. The AceGen input presented in previous examples can be used again with the "Environment"->"ABAQUS" option to produce ABAQUS's source code file. The current ABAQUS interface does not support internal degrees of freedom. Consequently, the mixed deformation modes are skipped. The generated code is then incorporated into ABAQUS.

Example of 3D hyper-elastic user element subroutine for ABAQUS

<<"AceGen`";
SMSInitialize["test","Environment"->"ABAQUS"];
SMSTemplate["SMSTopology"->"H1","SMSSymmetricTangent"->True
,"SMSDomainDataNames"->{"E -elastic modulus","ν -poisson ratio","Qx -volume load X","Qy -volume load Y","Qz -volume load Z"}
,"SMSDefaultData"->{21000,0.3,0,0,0}];
SMSStandardModule["Tangent and residual"];
SMSDo[Ig,1,SMSInteger[es$$["id","NoIntPoints"]]];
Ξ={ξ,η,ζ}⊢Table[SMSReal[es$$["IntPoints",i,Ig]],{i,3}];
XI⊢Table[SMSReal[nd$$[i,"X",j]],{i,SMSNoNodes},{j,SMSNoDimensions}];Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];
X⊢SMSFreeze[NI.XI];Jg⊨SMSD[X,Ξ];Jgd⊨Det[Jg];
uI⊢SMSReal[Table[nd$$[i,"at",j],{i,SMSNoNodes},{j,SMSNoDimensions}]];
pe=Flatten[uI];u⊨NI.uI;
Dg⊨SMSD[u,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];
F⊨IdentityMatrix[3]+Dg;JF⊨Det[F];Cg⊨Transpose[F].F;{Em,ν,Qx,Qy,Qz}⊢SMSReal[Table[es$$["Data",i],{i,Length[SMSDomainDataNames]}]];
{λ,μ}⊨SMSHookeToLame[Em,ν];
W⊨1/2 λ (JF-1)^2+μ (1/2 (Tr[Cg]-3)-Log[JF])-{Qx,Qy,Qz}.u;
wgp⊢SMSReal[es$$["IntPoints",4,Ig]];
SMSDo[Rg⊨ Jgd  wgp SMSD[W,pe,i];
SMSExport[SMSResidualSign Rg,p$$[i],"AddIn"->True];
SMSDo[Kg⊨SMSD[Rg,pe,j];
SMSExport[Kg,s$$[i,j],"AddIn"->True];
,{j,i,24}];
,{i,1,24}];
SMSEndDo[];
SMSWrite[];

Here is the generated element compiled and linked into the ABAQUS. The SMSFEEnvironment compiles the source code file, links the resulting object file into ABAQUS and starts ABAQUS with a ABAQUSExample.dat file as a input file and tmp.res as output file. The ABAQUS input data file for the one element test example is available at the
$BaseDirectory/Applications/AceGen/Include/ABAQUS directory.

SMSFEEnvironment["ABAQUS","SourceCode"->"test","SimulationInputFile"->"ABAQUSExample.dat","SimulationOutputFile"->"tmp.res"]

ABAQUS input data file and simulation

In the input file of ABAQUS we have to specify that material will be user defined:

"*Material, NAME=user1
*USER MATERIAL, CONSTANTS=7
1000, 0.2, -2.0, 100, 0, 0, 1"

deformation gradient: needs NLGEOM=YES set in ABAQUS input

The compiled object file must be provided when calling the ABAQUS analysis (ifort must be called first):

call abaqus job = `SimulationInputFile` user=" SourceCodeFileName.obj" interactive

We can supply the code directly to ABAQUS and it will compile and link it itself (ifort must be called first):

call abaqus job = `SimulationInputFile` user=" SourceCodeFileName.for" interactive

If we use include or external object we have to specify the folders in which the files or libraries are located in the file  “abaqus_v6.env” (we can add additional options at ‘ifort’ and ‘LINK’) . This applies to both cases, when we provide .obj file or .for file.

An examples of ABAQUS script templates

Version: 
Intel Parallel Studio XE 2016 (intel fortran compiler)
ABAQUS version 6.14 - 1

FEAP

FEAP is an FE environment developed by R. L. Taylor, Department of Civil Engineering, University of California at Berkeley, Berkeley, California 94720.
(refer to http://www.ce.berkeley.edu/~rlt/feap/).
FEAP is the research type FE environment with open architecture, but only basic pre/post-processing capabilities. The generated user subroutines are connected with the FEAP through its standard user subroutine interface (see Standard User Subroutines). By default, the element with the number 10 is generated. Supplementary files are available at FileNameJoin[{$BaseDirectory,"Applications","AceGen","Include", "FEAP"}] directory. See also (HyperlinkTemplate[Installation instructions, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, HyperlinkActionRecycled, HyperlinkActive, , ]) for instructions how to compile and link the generated codes.

Specific FEAP Interface Data

Additional template constants (see Template Constants ) have to be specified in order to process the FEAP's  "splice-file" correctly.

Example: Mixed 3D Solid FE for FEAP

Regenerate the three-dimensional, eight node finite element described in AceFEM documentation (see Mixed 3D Solid FE, Elimination of Local Unknowns) for FEAP environment.

<<"AceGen`";
SMSInitialize["test","Environment"->"FEAP"];
SMSTemplate["SMSTopology"->"H1","SMSSymmetricTangent"->True,"SMSNoDOFCondense"->9
,"SMSDomainDataNames"->{"E -elastic modulus","ν -poisson ratio","Qx -volume load X","Qy -volume load Y","Qz -volume load Z"}
,"SMSDefaultData"->{21000,0.3,0,0,0}];
SMSStandardModule["Tangent and residual"];
SMSDo[Ig,1,SMSInteger[es$$["id","NoIntPoints"]]];
Ξ={ξ,η,ζ}⊢Table[SMSReal[es$$["IntPoints",i,Ig]],{i,3}];
XI⊢Table[SMSReal[nd$$[i,"X",j]],{i,SMSNoNodes},{j,SMSNoDimensions}];Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];
X⊢SMSFreeze[NI.XI];Jg⊨SMSD[X,Ξ];Jgd⊨Det[Jg];
uI⊢SMSReal[Table[nd$$[i,"at",j],{i,SMSNoNodes},{j,SMSNoDimensions}]];
pe=Flatten[uI];u⊨NI.uI;
Dg⊨SMSD[u,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];
J0⊨SMSReplaceAll[Jg,{ξ->0,η->0,ζ->0}];J0d⊨Det[J0];
αe ⊢ Table[SMSReal[ed$$["ht", i]],{i, SMSNoDOFCondense}];
ph=Join[pe,αe];
HbΞ=(({{ξ αe[[1]], η αe[[2]], ζ αe[[3]]}, {ξ αe[[4]], η αe[[5]], ζ αe[[6]]}, {ξ αe[[7]], η αe[[8]], ζ αe[[9]]}}));Hb⊨((J0d )/Jgd)HbΞ.SMSInverse[J0];
F⊨IdentityMatrix[3]+Dg+Hb;JF⊨Det[F];Cg⊨Transpose[F].F;{Em,ν,Qx,Qy,Qz}⊢SMSReal[Table[es$$["Data",i],{i,Length[SMSDomainDataNames]}]];
{λ,μ}⊨SMSHookeToLame[Em,ν];
W⊨1/2 λ (JF-1)^2+μ (1/2 (Tr[Cg]-3)-Log[JF])-{Qx,Qy,Qz}.u;
wgp⊢SMSReal[es$$["IntPoints",4,Ig]];
SMSDo[Rg⊨ Jgd  wgp SMSD[W,ph,i];
SMSExport[SMSResidualSign Rg,p$$[i],"AddIn"->True];
SMSDo[Kg⊨SMSD[Rg,ph,j];
SMSExport[Kg,s$$[i,j],"AddIn"->True];
,{j,i,SMSNoAllDOF}];
,{i,1,SMSNoAllDOF}];
SMSEndDo[];
SMSWrite[];

Test example: FEAP

Here is the FEAP input data file for the test example from the chapter Mixed 3D Solid FE, Elimination of Local Unknowns. You need to install FEAP environment in order to run the example.

feap
0,0,0,3,3,8

block
cart,6,15,6,1,1,1,10
1,10.,0.,0.
2,10.,2.,0.
3,0.,2.,0.
4,0.,0.,0.
5,10.,0.,2.
6,10.,2.,2.
7,0.,2.,3.
8,0.,0.,3.

ebou
1,0,1,1,1
1,10.,,,1

edisp,add
1,10.,,,-1.

mate,1
user,10
1000,0.3

end

macr
tol,,1e-9
prop,,1
dt,,1
loop,,5
time
loop,,10
tang,,1
next
disp,,340
next
end

stop

Here is the generated element compiled and linked into the FEAP. The SMSFEEnvironment compiles the source code file, links the resulting object file into FEAP and starts FEAP with a feap.inp file as a input file and tmp.res as output file. The FEAP input data file for the one element test example is available at the
$BaseDirectory/Applications/AceGen/Include/FEAP/directory.

SMSFEEnvironment["ELFEN","SourceCode"->"test","SimulationInputFile"->"feap.inp","SimulationOutputFile"->"tmp.res"]

ELFEN

(ELFEN^©) is commercial FE environment developed by Rockfield Software, The Innovation Centre, University of Wales College Swansea, Singleton Park, Swansea, SA2 8PP, U.K. 
ELFEN is a general FE environment with the advanced pre and post-processing capabilities. The generated code is linked with the (ELFEN^©) through the user defined subroutines. By default the element with the number 2999 is generated. Interface for (ELFEN^©) does not support elements with the internal degrees of freedom.

Due to the non-standard way how the Newton-Raphson procedure is implemented in ELFEN, the ELFEN source codes of the elements presented in the examples section can not be obtained directly. Instead of one "Tangent and residual" user subroutine we have to generate two separate routines for the evaluation of the tangent matrix and the residual .

The traditional FEM environments are more oriented towards mechanics of solids and require definition of an additional template constants for the construction of proper interface code. Additional numerical environment dependent constants are defined automatically and can be used within the code generation process. Default values are based on the number of spatial dimensions and are not correct for some special cases such as plane stress condition. 
Supplementary files are available at FileNameJoin[{$BaseDirectory,"Applications","AceGen","Include", "ELFEN"}] directory. See also (HyperlinkTemplate[Installation instructions, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, HyperlinkActionRecycled, HyperlinkActive, , ]) for instructions how to compile and link the generated codes.

Specific ELFEN Interface Data

Additional template constants (see Template Constants ) have to be specified in order to process the ELFEN's "splice-file" correctly. Default values for the constants are chosen accordingly to the element topology.

Here the additional constants for the 2D, plane strain element are defined.

Example: 3D Solid FE for ELFEN

Regenerate the three-dimensional, eight node finite element described in AceFEM documentation (see Mixed 3D Solid FE, Elimination of Local Unknowns) for ELFEN environment.

The AceGen input presented in previous example can be used again with the "Environment"->"ELFEN" option to produce Elfen's source code file. The procedure is controlled by the values of  environment constants "SkipTangent", "SkipResidual" and "SubIterationMode". 
When the tangent matrix is required the variables are set to

idata$$["SkipTangent"] = 0,
idata$$["SkipResidual"] = 1,
idata$$["SubIterationMode"] = 1

and when the residual is required the variables are set to

idata$$["SkipTangent"] = 1,
idata$$["SkipResidual"] = 0,
idata$$["SubIterationMode"] = 0.

<<"AceGen`";
SMSInitialize["test","Environment"->"ELFEN"];
SMSTemplate["SMSTopology"->"H1","SMSSymmetricTangent"->True
,"SMSDomainDataNames"->{"E -elastic modulus","ν -poisson ratio","Qx -volume load X","Qy -volume load Y","Qz -volume load Z"}
,"SMSDefaultData"->{21000,0.3,0,0,0}];
SMSStandardModule["Tangent and residual"];
SMSDo[Ig,1,SMSInteger[es$$["id","NoIntPoints"]]];
Ξ={ξ,η,ζ}⊢Table[SMSReal[es$$["IntPoints",i,Ig]],{i,3}];
XI⊢Table[SMSReal[nd$$[i,"X",j]],{i,SMSNoNodes},{j,SMSNoDimensions}];Ξn={{-1,-1,-1},{1,-1,-1},{1,1,-1},{-1,1,-1},
{-1,-1,1},{1,-1,1},{1,1,1},{-1,1,1}};
NI⊨Table[1/8(1+ξ Ξn[[i,1]])(1+η Ξn[[i,2]])(1+ζ Ξn[[i,3]]),{i,1,8}];
X⊢SMSFreeze[NI.XI];Jg⊨SMSD[X,Ξ];Jgd⊨Det[Jg];
uI⊢SMSReal[Table[nd$$[i,"at",j],{i,SMSNoNodes},{j,SMSNoDimensions}]];
pe=Flatten[uI];u⊨NI.uI;
Dg⊨SMSD[u,X,"Dependency"->{Ξ,X,SMSInverse[Jg]}];
F⊨IdentityMatrix[3]+Dg;JF⊨Det[F];Cg⊨Transpose[F].F;{Em,ν,Qx,Qy,Qz}⊢SMSReal[Table[es$$["Data",i],{i,Length[SMSDomainDataNames]}]];
{λ,μ}⊨SMSHookeToLame[Em,ν];
W⊨1/2 λ (JF-1)^2+μ (1/2 (Tr[Cg]-3)-Log[JF])-{Qx,Qy,Qz}.u;
wgp⊢SMSReal[es$$["IntPoints",4,Ig]];
SMSDo[Rg⊨ Jgd  wgp SMSD[W,pe,i];
SMSExport[SMSResidualSign Rg,p$$[i],"AddIn"->True];
SMSDo[Kg⊨SMSD[Rg,pe,j];
SMSExport[Kg,s$$[i,j],"AddIn"->True];
,{j,i,24}];
,{i,1,24}];
SMSEndDo[];
SMSWrite[];

Here is the generated element compiled and linked into the ELFEN. The SMSFEEnvironment compiles the source code file, links the resulting object file into ELFEN and starts ELFEN with a ELFENExample.dat file as a input file and tmp.res as output file. The ELFEN input data file for the one element test example is available at the
$BaseDirectory/Applications/AceGen/Include/ELFEN/ directory.

SMSFEEnvironment["ELFEN","SourceCode"->"test","SimulationInputFile"->"ELFENExample.dat","SimulationOutputFile"->"tmp.res"]

ANSYS

(ANSYS^©) is a commercial FE environment developed by ANSYS, Inc.
The generated code is linked with the (ANSYS^©) through the user material subroutines (USERMAT). The interface does not support elements with the internal degrees of freedom. If we specify user material in ANSYS, it will call the function USERMAT and from USERMAT the AceGen functions. Supplementary files are available at FileNameJoin[{$BaseDirectory,"Applications","AceGen","Include", "ANSYS"}] directory. See also (HyperlinkTemplate[Installation instructions, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, http://symech.fgg.uni-lj.si/User/AceInstallation.htm, HyperlinkActionRecycled, HyperlinkActive, , ]) for instructions how to compile and link the generated codes.

ANSYS interface has been contributed by asist. dr. Blaž Hudobivnik, Institute of Continuum Mechanics, Leibniz University of Hannover (blaz.hudobivnik@fgg.uni-lj.si).

User material subroutine for ANSYS

AceGen provides an automatic interface for the generation of the user material subroutine for ANSYS. In general USERMAT receives the deformation tensors and returns the stress tensor together with the material constitutive matrix. The automatic interface ensures maximal compatibility between the standardized user element interface and user material interface, however only the constants and variables that have meaning at material point are actually available in USERMAT subroutine.

The traditional FEM environments are more oriented towards mechanics of solids and require definition of an additional template constants for the construction of proper interface code. Additional numerical environment dependent constants are defined automatically and can be used within the code generation process. Default values are based on the number of spatial dimensions and are not correct for some special cases such as plane stress condition.

Stress tensor and constitutive matrix must be vectorized accordingly to ANSYS manual. Stress tensor is vectorized as:

TensorComponents=Switch[ContinuumModel
,"PS",
{{1,1},{2,2},{1,2}}
,"PE"|"AX",
{{1,1},{2,2},{3,3},{1,2}}
,"D3",
{{1,1},{2,2},{3,3},{1,2},{2,3},{1,3}}
]
Extract[σ,TensorComponents]

Constitutive tensor is vectorized by:

Table[Extract[DσD𝔼,Join[i1, i2]],{i1,TensorComponents},{i2,TensorComponents}]

Example Neo-Hooke user material for ANSYS

<<AceGen`;

SMSInitialize["ANSYS_USERMAT_NH","Environment"->"ANSYS"];
SMSTemplate[
"SMSUserSubroutine"->"USERMAT"
,"SMSTopology"->"XX","SMSNoDimensions"->3,"SMSNoNodes"->0,"SMSNoTensorComponents"->6
,"SMSDomainDataNames"->{"E -elastic modulus","ν -poisson ratio","β -volumetric strain exponent"}
,"SMSDefaultData"->{1000,0.2,-2}
];

SMSStandardModule["ANSYS USERMAT"];

{Em,ν,β}⊢SMSReal[Table[es$$["Data",i],{i,Length[SMSDomainDataNames]}]];

𝔽n⊢SMSReal[Array[Fn$$,{3,3}]];
𝔽⊢SMSReal[Array[F$$,{3,3}]];
JF⊨Det[𝔽];

SMSFreeze[𝕓e,𝔽.𝔽\[Transpose],"Symmetric"-> True];
Jbe=Det[𝕓e];

{λ,μ}⊨SMSHookeToLame[Em,ν];
{μ,Κ}⊨SMSHookeToBulk[Em,ν];
W⊨ (μ/2)((Jbe^(-1/3))Tr[𝕓e]-3)+(Κ/(β^2))((Jbe^(-β/2))-1+(β/2) Log[Jbe]);
τ⊨Simplify[2 𝕓e.SMSD[W,𝕓e,"Ignore"-> NumberQ,"Symmetric"->True]];
σ⊨τ/JF;
DτD𝔽⊨SMSD[τ,𝔽];
DσD𝔼⊨(Table[Sum[
𝔽[[l,m]]DτD𝔽[[i,j,k,m]]+𝔽[[k,m]]DτD𝔽[[i,j,l,m]],{m,3}],
{l,3},{k,3},{j,3},{i,3}])/JF/2;
SMSExport[W,W$$];

TensorComponents={{1,1},{2,2},{3,3},{1,2},{2,3},{1,3}};
SMSExport[Extract[σ,TensorComponents],S$$];
SMSExport[Table[Extract[DσD𝔼,Join[i1, i2]],{i1,TensorComponents},{i2,TensorComponents}],DSDE$$];

SMSWrite[];

Compiling the ANSYS user materials

ANSYS provides a file ANSUSERSHARED which links and compiles all the code in the chosen folder and creates a library file, which can then be used by ANSYS.

The file ANSUSERSHARED (in Windows ANSUSERSHARED.bat) is located at: 
...\ANSYS Inc\v170\ansys\custom\user\winx64 or ...\ANSYS Inc\v170\ansys\customise\user\ 
The file needs to be copied in the folder where the Fortran code is present (workpath represents the absolute path to the file).

In Windows or Linux we have change the active directory to the workpath (in CMD or Console) and then running the file ANSUSERSHARED or ANSUSERSHARED.bat. This scripts searches for *.F files (Linux is case sensitive) and calls ifort compiler, (in Windows ifort should be initialized first, same way as for ABAQUS). We can copy all the required libraries and include files to the folder, and they will be compiled and linked in single file “userlib.a” (in Linux).

To use the generated library (Dll or a), the system environment variable must be set globally: ANS_USER _PATH = workpath
OpenSuse: 
We must save the .bashrc to our home directory, with the content:
“export ANS_USER_PATH=’workpath’”
In Windows we must set the path: 
by set command:
“setx ANS_USER_PATH workpath #must be run as administrator”
or
“set ANS_USER_PATH=workpath ”
check with command:
“echo %ANS_USER_PATH%”

Using the ANSYS user materials

ANSYS to use the user library file we must first make sure, that ANS_USER_PATH points to the correct folder. This can be checked with simple Python script in workbench. (open File/Scripting/Open Command Window):

print os.environ.get('ANS_USER_PATH')

Path can also be set (is to be tested if it works properly) :

os.environ['ANS_USER_PATH']= "workpath "

ANSYS should have now user defined code. To use it we must call it first:  We can define user elements or user gauss point model. To use e.g. User material, we have to attach a script file to the model in benchmark with the following content (or write it in input file):

"tb,user,matid,2,4 
 tbtemp,1.0 
 tbdata,1,19e5, 0.3, 1e3,100 
 tbtemp,2.0 
 tbdata,1,21e5, 0.3, 2e3,100"

If we want to add state variables (ANSYS does not care about the content, it just provides the interface. FOr physical meaning we must export the variables to physical vector, e.g. if it stores plastic variables, we can put them into plastic strain tensor, available for us):

"TB,state,matid,,8"

Note the “user” means we are calling the User material function. We can also specify other functions as described.

ANSYS Mechanical APDL Programmer' s Reference :
2.4 .1. Subroutine UserMat (Creating Your Own Material Model)
2.4 .2. Subroutine UserMatTh (Creating Your Own Thermal Material Model)
2.4 .3. Subroutine UserHyper (Writing Your Own Hyperelasticity Laws)
2.4 .4. Subroutine UserCreep (Defining Creep Material Behavior)
2.4 .5. Subroutine user_tbelastic (Defining Material Linear Elastic Properties)
2.4 .6. Subroutine userfc (Defining Your Own Failure Criteria)
2.4 .7. Subroutine userCZM (Defining Your Own Cohesive Zone Material)
2.4 .8. Subroutine userswstrain (Defining Your Own Swelling Laws)
2.4 .9. Subroutine userck (Checking User - Defined Material Data)
2.4 .10. Supporting Function egen
2.4 .11. Subroutine UserFld (Update User - Defined Field Variables)

An examples of ANSYS script template for Linux

MathLink, Matlab Environments

The AceGen can build, compile and install C functions so that functions defined in the source code can be called directly from Mathematica using the MathLink protocol. The SMSInstallMathLink command builds the executable program, starts the program and installs Mathematica definitions to call functions in it.

The SMSInstallMathLink command executes the standard C compiler and linker. For unsupported C compilers, the user should write his own SMSInstallMathLink function that creates MathLink executable on a basis of the element source file, the sms.h header file and the SMSUtility.c file.  Files can be found at the directory $BaseDirectory/Applications/AceGen/Include/MathLink/ ).

At run time one can effect the way how the functions are executed with an additional function SMSSetLinkOptions.

Options for SMSSetLinkOptions.

For more examples see  Standard AceGen Procedure, Minimization of Free Energy, Solution to the System of Nonlinear Equations.

The AceGen generated M-file functions can be directly imported into Matlab. See also Standard AceGen Procedure .

<<AceGen`;
SMSInitialize["test","Environment"->"MathLink"];
SMSModule["Test",Real[u$$[3],x$$,L$$,g$$[3]],
"Input"->{u$$,x$$,L$$},"Output"->g$$];
{x,L}⊢{SMSReal[x$$],SMSReal[L$$]};
ui⊢SMSReal[Table[u$$[i],{i,3}]]
Ni⊨{(x/L),1-(x/L),(x/L)(1-(x/L))};
u⊨Ni.ui;
f⊨(u^2);
g⊨SMSD[f,ui];
SMSExport[g,g$$];
SMSWrite[];

SMSInstallMathLink[]

Here the generated executable is used to calculate gradient for the numerical test example.

Test[{0.,1.,7.},π//N,10.]

Appendix

Bibliography

AceGen

KORELC, J. Automation of primal and sensitivity analysis of transient coupled problems.  Computational mechanics, 44(5):631-649 (2009).
KORELC, Jože, Multi-language and Multi-environment Generation of Nonlinear Finite Element Codes,  Engineering with Computers, 2002, 18(4):312-327
KORELC, Jože. Automatic generation of finite-element code by simultaneous optimization of expressions. Theor. comput. sci.. , 1997, 187:231-248. 
HUDOBIVNIK, Blaž, KORELC, Jože. Closed-form representation of matrix functions in the formulation of nonlinear material models. Finite Elements in Analysis and Design, 2016, 111:19-32
KORELC, J. Semi-analytical solution of path-independent nonlinear finite element models. Finite elem. anal. des., 2011, 47:281-287.
KORELC, J. Automation of the finite element method. V: WRIGGERS, Peter. Nonlinear finite element methods. Springer,  483-508 (2008).

Applications

ZUPAN, Nina, KORELC, Jože. Sensitivity analysis based multi-scale methods of coupled path-dependent problems, Computational Mechanics, 2019, DOI 10.1007/s00466-019-01762-8
ŠOLINC, Urša, KORELC, Jože. A simple way to improved formulation of FE2 analysis. Computational mechanics,  2015,  56:905-915, doi: 10.1007/s00466-015-1208-4. 
MELINK, Teja, KORELC, Jože. Stability of Karhunen- Loève expansion for the simulation of Gaussian stochastic fields using Galerkin scheme. Probabilistic Engineering Mechanics, 2014, 37:7-15, doi: 10.1016/j.probengmech.2014.03.006. 
KORELC, Jože, STUPKIEWICZ, Stanislaw. Closed-form matrix exponential and its application in finite-strain plasticity. International journal for numerical methods in engineering, ISSN 0029-5981, 2014, 98(13):960-987, ilustr., doi: 10.1002/nme.4653. 
CLASEN, Heiko, HIRSCHBERGER, C. Britta, KORELC, Jože, WRIGGERS, Peter, FE2-homogenization of micromorphic elasto-plastic materials,  XII International Conference on Computational Plasticity. Fundamentals and Applications, COMPLAS XII, 2013 
LENGIEWICZ, Jakub, KORELC, Joze, STUPKIEWICZ, Stanislaw., Automation of finite element formulations for large deformation contact problems. Int. j. numer. methods eng., 2011, 85: 1252-1279.
KORELC, J. Direct computation of critical points based on Crout`s elimination and diagonal subset test function, Computers and Structures, 88:189-197 (2010).
WRIGGERS, Peter, KRSTULOVIC-OPARA, Lovre, KORELC, Jože.(2001),  Smooth C1-interpolations for two-dimensional frictional contact problems. Int. j. numer. methods eng., 2001, vol. 51, issue 12, str. 1469-1495
KRSTULOVIC-OPARA, Lovre, WRIGGERS, Peter, KORELC, Jože. (2002), A C1-continuous formulation for 3D finite deformation frictional contact. Comput. mech., vol. 29, issue 1, 27-42
STUPKIEWICZ, Stanislaw, KORELC, Jože, DUTKO, Martin, RODIC, Tomaž. (2002), Shape sensitivity analysis of large deformation frictional contact problems. Comput. methods appl. mech. eng., 2002, vol. 191, issue 33, 3555-3581
BRANK, Boštjan, KORELC, Jože, IBRAHIMBEGOVIC, Adnan. (2002), Nonlinear shell problem formulation accounting for through-the-tickness stretching and its finite element implementation. Comput. struct.. vol. 80, n. 9/10,  699-717
BRANK, Boštjan, KORELC, Jože, IBRAHIMBEGOVIC, Adnan. (2003),Dynamic and time-stepping schemes for elastic shells undergoing finite rotations. Comput. struct., vol. 81, issue 12, 1193-1210
STADLER, Michael, HOLZAPFEL, Gerhard A., KORELC, Jože. (2003) Cn continuous modelling of smooth contact surfaces using NURBS and application to 2D problems. Int. j. numer. methods eng.,  2177-2203
KUNC, Robert, PREBIL, Ivan, RODIC, Tomaž, KORELC, Jože.  (2002),Low cycle elastoplastic properties of normalised and tempered 42CrMo4 steel. Mater. sci. technol.,  Vol. 18, 1363-1368.
Bialas M, Majerus P, Herzog R, Mroz Z, Numerical simulation of segmentation cracking in thermal barrier coatings by means of cohesive zone elements, MATERIALS SCIENCE AND ENGINEERING A-STRUCTURAL MATERIALS PROPERTIES MICROSTRUCTURE AND PROCESSING 412 (1-2): 241-251 Sp. Iss. SI, DEC 5 2005
Maciejewski G, Kret S, Ruterana P, Piezoelectric field around threading dislocation in GaN determined on the basis of high-resolution transmission electron microscopy image , JOURNAL OF MICROSCOPY-OXFORD 223: 212-215 Part 3 SEP 2006 
Wisniewski K, Turska E, Enhanced Allman quadrilateral for finite drilling rotations, COMPUTER METHODS IN APPLIED MECHANICS AND ENGINEERING 195 (44-47): 6086-6109 2006 
Maciejewski G, Stupkiewicz S, Petryk H, Elastic micro-strain energy at the austenite-twinned martensite interface, ARCHIVES OF MECHANICS 57 (4): 277-297 2005 
Stupkiewicz S, The effect of stacking fault energy on the formation of stress-induced internally faulted martensite plates, EUROPEAN JOURNAL OF MECHANICS A-SOLIDS 23 (1): 107-126 JAN-FEB 2004

Symbolic methods

Korelc J. (1997b), A symbolic system for cooperative problem solving in computational mechanics, Computational Plasticity Fundamentals and Applications, (Owen D.R.J., Oñate E. and Hinton E., editors), CIMNE, Barcelona, 447-451.
Korelc J., and Wriggers P. (1997c), Symbolic approach in computational mechanics, Computational Plasticity Fundamentals and Applications, (Owen D.R.J., Oñate E. and Hinton E., editors), CIMNE, Barcelona, 286-304.
Korelc J., (2001), Hybrid system for multi-language and multi-environment generation of numerical codes, Proceedings of the ISSAC'2001 Symposium on Symbolic and Algebraic Computation, New York, ACM:Press, 209-216
Korelc, J. (2003) Automatic Generation of Numerical Code.  MITIC, Peter. Challenging the boundaries of symbolic computation : proceedings of the 5th International Mathematica Symposium. London: Imperial College Press,  9-16.
Gonnet G. (1986), New results for random determination of equivalence of expression, Proc. of 1986 ACM Symp. on Symbolic and Algebraic Comp, (Char B.W., editor), Waterloo, July 1986, 127-131.
Griewank A. (1989), On Automatic Differentiation, Mathematical Programming: Recent Developments and Applications, Kluwer Academic Publisher, Amsterdam, 83-108.
Hulzen J.A. (1983), Code optimization of multivariate polynomial schemes: A pragmatic approach. Proc. of IEUROCAL'83, (Hulzen J.A., editor), Springer-Verlag LNCS Series Nr. 162.
Kant E. (1993), Synthesis of Mathematical Modeling Software, IEEE Software, May 1993.
Leff L. and Yun D.Y.Y. (1991), The symbolic finite element analysis system. Computers & Structures, 41, 227-231.
Noor A.K. (1994), Computerized Symbolic Manipulation in Structural Mechanics, Computerized symbolic manipulation in mechanics, (Kreuzer E., editor), Springer-Verlag, New York, 149-200.
Schwartz J.T. (1980), Fast probabilistic algorithms for verification of polynomial identities. Journal of the ACM, 27(4), 701-717.
Sofroniou M. (1993), An efficient symbolic-numeric environment by extending mathematica's format rules. Proceedings of Workshop on Symbolic and Numerical Computation, (Apiola H., editor), University of Helsinki, Technical Report Series, 69-83.
Wang P.S. (1986),  Finger: A symbolic system for automatic generation of numerical programs in finite element analysis,  J. Symb. Comput, 2, 305-316.
Wang P.S. (1991), Symbolic computation and parallel software, Technical Report ICM-9109-12, Department of Mathematics and Computer Science, Kent State University, USA.

AceGen Troubleshooting

General

Rerun the input in debug mode (SMSInitialize[..."Mode"->"Debug)].

Divide the input statements into the separate cells (Shift+Ctrl+D), remove the ; character at the end of the statement and check the result of each statement separately.

Check the precedence of the special AceGen operators ⊨,⊢,⫤,⊣. They have lower precedence than e.g // operator. (see also SMSR)

Check the input parameters of the SMSVerbatim, SMSReal, SMSInteger, SMSLogical commands. They are passed into the source code verbatim, without checking the syntax, thus the resulting code may not compile correctly.

Check that all used functions have equivalent function in the chosen compiled language. No additional libraries are included automatically by AceGen.

Try to minimize the number of calls to automatic differentiation procedure. Remember that in backward mode of automatic differentiation the expression SMSD[a,c]+SMSD[b,c] can result in code that is twice as large and twice slower than the code produced by the equivalent expression SMSD[a+b,c].

The situation when the new AceGen version gives different results than the old version does not necessary mean that there is a bug in AceGen. Even when the two versions produce mathematically equivalent expressions, the results can be different when evaluated within the finite precision arithmetics due to the different structure of the formulas. It is not only the different AceGen version but also the different Mathematica version that can produce formulae that are equivalent but not the same (e.q. formulas ((Sin[x])^2)+((Cos[x])^2) and 1 are equivalent, but not the same).

The expression optimization procedure can recognize various relations between expressions, however that is no assurance that relations will be in fact recognized. Thus, the users input must not rely on expression optimization as such and it must produce the same result with or without expression optimization  (see Automatic Differentiation).

Check the argument of the SMSIf command for incorrect comparitions. The expressions  a===b or a=!=b are executed in Mathematica and not later in a source code!!! Use the a==b and a !=b form instead of the a===b or a=!=b form.

Check the information given at www.fgg.uni-lj.si/symech/FAQ/.

Message: Variables out of scope

See extensive documentation and examples  in Auxiliary Variables, SMSIf, SMSDo, SMSFictive and additional examples below.

Symbol appears outside the "If" or "Do" construct

Erroneous input

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];
SMSIf[x<=0];
  f⫤(x^2);
SMSElse[];
  f⊣Sin[x];
SMSEndIf[];
SMSExport[f,f$$];

Corrected input

<<AceGen`;
SMSInitialize["test","Language"->"Fortran"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];
SMSIf[x<=0];
  f⫤(x^2);
SMSElse[];
  f⊣Sin[x];
SMSEndIf[f];
SMSExport[f,f$$];

Symbol is defined in other branch of "If" construct

Erroneous input

<<AceGen`;
SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];
f⫤x;
SMSIf[x<=0];
  f⊣(x^2);
SMSElse[];
  y⊨2 f;

Corrected input

SMSInitialize["test","Language"->"C"];
SMSModule["test",Real[x$$,f$$]];
x⊢SMSReal[x$$];
f⫤x;
tmp⊢f;
SMSIf[x<=0];
  f⊣(x^2);
SMSElse[];
  y⊨2 tmp;

Generated code does not compile correctly

The actual source code of a single formula is produced directly by Mathematica using CForm or FortranForm commands and not by AceGen. However, Mathematica will produce compiled language equivalent code only in the case that there exist equivalent command in compiled language. The standard form of Mathematica expressions can hide some special functions. Please use FullForm to see all used functions. Mathematica has several hundred functions and number of possible combinations that have no equivalent compiled language form. There are to ways how to get compiled language code out of symbolic input:

one can include special libraries or write compiled language code for functions without compiled language equivalent

make sure that symbolic input contains only functions with the compiled language equivalent or define additional transformations as in example below

Examples of erroneus and corrected input:

Erroneous input

a<b<c

FullForm[a<b<c]

CForm[a<b<c]

There exist no standard C equivalent for Less so it is left in original form and the resulting code would probably failed to compile correctly.

Corrected input

Unprotect[CForm];
CForm[Less[a_,b_,c_]]:=a<b && b<c;
Protect[CForm];

CForm[a<b<c]

MathLink

if the compilation is to slow restrict compiler optimization with SMSInstallMathLink["Optimize"->False]

in the case of sudden crash of the MathLink program use SMSInstallMathLink["PauseOnExit"->True] to see the printouts generated by SMSPrint