PyFreeFEM meta-language

PyFreeFEM supports special syntax elements that can be inserted in the .edp scripts to facilitate communication between the main python script and FreeFEM modules.

PyFreeFEM is using two types of syntax elements: magic variables and preprocessing directives. Magic variables are special variables that can be assigned from Python or in the .edp script. Preprocessing directives are instructions using special keywords (IMPORT, IF, ELSE, ENDIF, FOR, IFEQ) which allow to execute portions of .edp scripts conditionally to the values of the magic variables.

Magic variables

Magic variables are dollar prefixed variables (such as $x, $WITH_PETSC, $Re…) whose values are substituted textually in the .edp code generated and executed by execute(). Accolades can be used when it is necessary to concatenate a magic variable with with letters or digits.

Consider the following .edp script:

freefem script.edp
real Re=$Re;
real ${varname}0=100;
real x=$x;

Magic variable are assigned by using a dictionary when calling the method execute():

Python script

Interpreted .edp script

python
FreeFemRunner('script.edp').execute({'Re': 30,
                                     'varname':'Pe'
                                     'x': '3+5'})
freefem Interpreted script.edp
real Re=30;
real Pe0=100;
real x=3+5;

Note

The value of the magic variables are stored after calling execute() in the the config attribute. It is also possible to obtain them without actually executing the FreeFEM script by using the method parse() instead.

Automatic magic variables

A small number of magic variables are automatically assigned when calling the method execute():

Magic variable

Content

$DEBUG

Value of the debug parameter (see Debugging)

$RUNDIR

Running directory

$FFEXPORTDIR

Export directory used by PyFreeFEM for automatic exports (see Importing/Exporting data structures)

$FFIMPORTDIR

Import directory used by PyFreeFEM for automatic imports (see Importing/Exporting data structures)

$WITH_MPI

Defined if execute() is called with with_mpi=True or with ncpu defined.

DEFAULT

In practice, it can be convenient to assign default values directly in the .edp script in order to create default argument or to avoid non-assigned values. This is achieved with the DEFAULT keyword.

freefem script.edp
DEFAULT (Re,"10")
real Re=$Re;

The value of the magic variable $Re is assigned to 10 if not specified:

Python script

Interpreted .edp script

python
FreeFemRunner('script.edp').execute()
freefem Interpreted script.edp
real Re=10;
python
FreeFemRunner('script.edp').execute({'Re': 30})
freefem Interpreted script.edp
real Re=30;

SET

The keyword SET enables to assign a value of a magic variable in the .edp script. The instruction SET has precedence over assigning magic variables with the method execute() as illustrated with the following script:

freefem script.edp
SET (Re,"10")
real Re=$Re;

Python script

Interpreted .edp script

python
FreeFemRunner('script.edp').execute()
freefem Interpreted script.edp
real Re=10;
python
FreeFemRunner('script.edp').execute({'Re': 30})
freefem Interpreted script.edp
real Re=10;

SET_TEXTVAR

SET_TEXTVAR allows to define multiple lines magic variables from a FreeFEM script. The following example illustrates how to define the content of a Mmg parameter file params.mmg2d in FreeFEM and retrieving its value in Python.

freefem pyfreefem/examples/edp/ex2.edp
DEFAULT (hmin_loc,"0.001")
DEFAULT (hmin,0.1*$hmin_loc)
DEFAULT (hmax,"0.003")
DEFAULT (hgrad,"1.3")
DEFAULT (hausd,0.1*$hmin)

SET_TEXTVAR params.mmg2d
Parameters
1

10 Edges $hmin $hmin_loc $hausd
END_TEXTVAR
python pyfreefem/examples/ex02_set_textvar.py
from pyfreefem import FreeFemRunner
import os

runner = FreeFemRunner("pyfreefem/examples/edp/ex2.edp")
runner.parse()
print(runner.config['params.mmg2d'])

Output:

console
$ python pyfreefem/examples/ex02_set_textvar.py
Parameters
1

10 Edges 0.0001 0.001 1e-05

IF/IFDEF/IFEQ/ELSE/ENDIF

These instructions enable to conditionally include a portion of code in the final executable .edp depending on the values of the magic variables. Three conditional keywords can be used:

Keyword

Behavior

IF FOO

True if $FOO is defined and $FOO != "0"

IFEQ (FOO,"BAR")

True if $FOO == "BAR"

IFDEF FOO

True if $FOO is defined

An example of script illustrating this behavior is given in pyfreefem/examples/edp/ex3.edp

examples/edp/ex3.edp
DEFAULT (ORDER,"P1")

IFEQ (ORDER,"P1")
cout << "Solving with P1 finite elements." << endl;
SET (ORDER_OK,"1")
ENDIF

IFEQ (ORDER,"P2")
cout << "Solving with P2 finite elements." << endl;
SET (ORDER_OK,"1")
ENDIF

IF ORDER_OK
mesh Th=square(30,30);
fespace Fh(Th,$ORDER);
Fh u,v;
solve laplace(u,v)=
    int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
        -int2d(Th)(v)
        +on(1,2,3,4,u=0);
ELSE
cout << "The specified finite element order should be P1 or P2." << endl;
ENDIF

IFDEF ORDER_OK
cout << "ORDER_OK has been set." << endl;
ENDIF

The following table shows the interpreted code depending on the provided configuration:

python
runner = FreeFemRunner('pyfreefem/examples/edp/ex3.edp')

Python script

Interpreted .edp script

python
runner.parse()
freefem Interpreted script.edp
cout << "Solving with P1 finite elements." << endl;

mesh Th=square(30,30);
fespace Fh(Th,P1);
Fh u,v;
solve laplace(u,v)=
    int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
        -int2d(Th)(v)
        +on(1,2,3,4,u=0);

cout << "ORDER_OK has been set." << endl;
python
runner.parse({'ORDER':'P2'})
freefem Interpreted script.edp
cout << "Solving with P2 finite elements." << endl;

mesh Th=square(30,30);
fespace Fh(Th,P2);
Fh u,v;
solve laplace(u,v)=
    int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
        -int2d(Th)(v)
        +on(1,2,3,4,u=0);

cout << "ORDER_OK has been set." << endl;
python
runner.parse({'ORDER':'P1b'})
freefem Interpreted script.edp
cout << "The specified finite element order should be P1 or P2." << endl;

FOR

This instruction allows to include several times the same portion of code with an incremental magic variable.

FreeFEM script

Interpreted .edp script

freefem script.edp
DEFAULT (N,10)
FOR (I,1,N)
//Create a square mesh of size ${I}x${I}
mesh Th$I = square(10,10,[$I*x,$I*y]);
freefem Interpreted script.edp
//Create a square mesh of size 1x1
mesh Th1 = square(10,10,[1*x,1*y]);

//Create a square mesh of size 2x2
mesh Th2 = square(10,10,[2*x,2*y]);

//Create a square mesh of size 3x3
mesh Th3 = square(10,10,[3*x,3*y]);

//Create a square mesh of size 4x4
mesh Th4 = square(10,10,[4*x,4*y]);

//Create a square mesh of size 5x5
mesh Th5 = square(10,10,[5*x,5*y]);

//Create a square mesh of size 6x6
mesh Th6 = square(10,10,[6*x,6*y]);

//Create a square mesh of size 7x7
mesh Th7 = square(10,10,[7*x,7*y]);

//Create a square mesh of size 8x8
mesh Th8 = square(10,10,[8*x,8*y]);

//Create a square mesh of size 9x9
mesh Th9 = square(10,10,[9*x,9*y]);

INCLUDE

The instruction INCLUDE allows to include the content of another .edp file (accepting PyFreeFEM meta-language) textually in the current edp file.

freefem
//Include and parse the content of another .edp file
//Note  : the file won't be included twice if such instruction
//is written recursively in  the files
INCLUDE "file.edp"

Magic comments

Magic comments are comments starting by //**. These comments are removed in the final interpreted file. This is useful when one desires to insert comments referring to special PyFreeFEM instructions but to leave a clean interpreted .edp file.

FreeFEM script

Interpreted .edp script

freefem script.edp
//** Default values for the Reynolds number
//** This comment will NOT
//** be visible in the executable edp file.
DEFAULT (Re,"100")

// Display the Reynolds number
cout << "Re=$Re;" << endl;
freefem Interpreted script.edp
// Display the Reynolds number
cout << "Re=100;" << endl;

Double backslash \\

The double backslash character \\ enables to remove line breaks that come from preprocessing instructions, improving the readability of the generated executable .edp file.

FreeFEM script

Interpreted .edp script

freefem script.edp
solve laplace(u,v)=
    int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
        -int2d(Th)(v)
        IF BC
        +on(1,2,3,4,u=0)
        ENDIF
         \\;
        //This final semicolumn character will be put
        //at the end of the last previous line
freefem Interpreted script.edp
solve laplace(u,v)=
    int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
        -int2d(Th)(v);
        //This final semicolumn character will be put
        //at the end of the last previous line

IMPORT

The instruction IMPORT imports macro files that are in the folder pyfreefem/edp.

FreeFEM script

Interpreted .edp script

freefem script.edp
IMPORT "io.edp"

pyfreefemfolder/pyfreefem/edp/io.edp is copied to the running folder (for instance runfolder) containing the executable .edp script. The IMPORT instruction is replaced with:

freefem Interpreted script.edp
include "runfolder/io.edp"