FreeFEM output and debugging

Setting FreeFEM verbosity

By default, PyFreeFEM hides the standard output of the FreeFEM process. It is possible to display it by specifying an integer value to the parameter verbosity when calling execute():

python ex_verbosity.py
from pyfreefem import FreeFemRunner

script = """
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);"""

runner = FreeFemRunner(script)
runner.execute(verbosity=2)
console
$ python ex_verbosity.py
-- FreeFem++ v4.12 (mer 25 jan 2023 14:14:39 CET - git v4.12)
   file : /tmp/pyfreefem_6vwrtwvg/run.edp  verbosity= 2
 Load: lg_fem lg_mesh lg_mesh3 eigenvalue
    1 :
    2 : mesh Th=square(30,30);
    3 : fespace Fh(Th,P1);
    4 : Fh u,v;
    5 :
    6 : solve laplace(u,v)=
    7 :     int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))
    8 :         -int2d(Th)(v)
    9 :         +on(1,2,3,4,u=0);  -- Problem type  ( complex : 0 )
 sizestack + 1024 =1576  ( 552 )

  -- Square mesh : nb vertices  =961 ,  nb triangles = 1800 ,  nb boundary edges 120
    Nb of Vertices 961 ,  Nb of Triangles 1800
    Nb of edge on user boundary  120 ,  Nb of edges on true boundary  120
   -- Change of Mesh 0  0x1ddc9e0
   -- size of Matrix 0 Bytes
  -- Solve :
          min 2.20333e-63  max 0.0736069
times: compile 0.002109s, execution 0.003763s,  mpirank:0
 CodeAlloc : nb ptr  3737,  size :504368 mpirank: 0
Ok: Normal End

When not specified, the method execute() assumes the default value verbosity=-1 (no standard output). Setting verbosity=n with a non-negative integer n displays the standard output of the command FreeFem++ with the verbosity option -v n.

Retrieving FreeFEM standard output

FreeFEM standard output can be retrieve after having called execute() by using the rets attribute:

python
print(runner.rets)
console
(0, '-- FreeFem++ v4.12 (mer 25 jan 2023 14:14:39 CET - git v4.12)\n   file : /tmp/pyfreefem_9xj1goi1/run.edp  verbosity= 2\n Load: lg_fem lg_mesh lg_mesh3 eigenvalue \n    1 : \n    2 : mesh Th=square(30,30);\n    3 : fespace Fh(Th,P1);\n    4 : Fh u,v;\n    5 : \n    6 : solve laplace(u,v)=\n    7 :     int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))\n    8 :         -int2d(Th)(v)\n    9 :         +on(1,2,3,4,u=0);  -- Problem type  ( complex : 0 )  \n sizestack + 1024 =1576  ( 552 )\n\n  -- Square mesh : nb vertices  =961 ,  nb triangles = 1800 ,  nb boundary edges 120\n    Nb of Vertices 961 ,  Nb of Triangles 1800\n    Nb of edge on user boundary  120 ,  Nb of edges on true boundary  120\n   -- Change of Mesh 0  0x23e79e0\n   -- size of Matrix 0 Bytes\n  -- Solve : \n          min 2.20333e-63  max 0.0736069\ntimes: compile 0.001899s, execution 0.003733s,  mpirank:0\n CodeAlloc : nb ptr  3737,  size :504368 mpirank: 0\nOk: Normal End\n', '', '-- FreeFem++ v4.12 (mer 25 jan 2023 14:14:39 CET - git v4.12)\n   file : /tmp/pyfreefem_9xj1goi1/run.edp  verbosity= 2\n Load: lg_fem lg_mesh lg_mesh3 eigenvalue \n    1 : \n    2 : mesh Th=square(30,30);\n    3 : fespace Fh(Th,P1);\n    4 : Fh u,v;\n    5 : \n    6 : solve laplace(u,v)=\n    7 :     int2d(Th)(dx(u)*dx(v)+dy(u)*dy(v))\n    8 :         -int2d(Th)(v)\n    9 :         +on(1,2,3,4,u=0);  -- Problem type  ( complex : 0 )  \n sizestack + 1024 =1576  ( 552 )\n\n  -- Square mesh : nb vertices  =961 ,  nb triangles = 1800 ,  nb boundary edges 120\n    Nb of Vertices 961 ,  Nb of Triangles 1800\n    Nb of edge on user boundary  120 ,  Nb of edges on true boundary  120\n   -- Change of Mesh 0  0x23e79e0\n   -- size of Matrix 0 Bytes\n  -- Solve : \n          min 2.20333e-63  max 0.0736069\ntimes: compile 0.001899s, execution 0.003733s,  mpirank:0\n CodeAlloc : nb ptr  3737,  size :504368 mpirank: 0\nOk: Normal End\n')

Retrieving the values of PyFreeFEM magic variables

The values of PyFreeFEM magic variables can be retrieved after calling the method pyfreefem.FreeFemRunner.execute() from the config attribute:

python
from pyfreefem import FreeFemRunner
script="""
DEFAULT (res,"high")
IFEQ (res,"high")
   DEFAULT (N,100)
ENDIF
IFEQ (res,"medium")
   DEFAULT (N,50)
ENDIF
IFEQ (res,"low")
   DEFAULT (N,10)
ENDIF
mesh Th=square(N,N);"""

runner = FreeFemRunner(script)
runner.execute({'res':'medium'})
print(runner.config)
console
$ python test.py
{'res': 'medium', 'DEBUG': 0, 'RUNDIR': '/tmp/pyfreefem_zoaqyf8k', 'FFEXPORTDIR': '/tmp/pyfreefem_zoaqyf8k/ffexport', 'FFIMPORTDIR': '/tmp/pyfreefem_zoaqyf8k/ffimport'}

Debugging

It is possible to have detailed information about parsing operation and code execution with a flexible level of verbosity by specifying a sufficiently large integer value to the debug argument in either the FreeFemRunner constructor or the execute() routine:

python script.py
 1from pyfreefem import FreeFemRunner
 2
 3script = """
 4DEFAULT (Re,10)
 5SET (Pe,30)
 6SET (ratioRePe,$Re/$Pe)
 7real Re=$Re;
 8real Pe=$Pe;
 9real ratio=$ratioRePe;"""
10
11FreeFemRunner(script,debug=10).execute()

Output:

console
$ python script.py
0 :
Interpreted :
1 : DEFAULT (Re,10)
Defined Re=10
2 : SET (Pe,30)
Defined Pe=30
3 : SET (ratioRePe,$Re/$Pe)
Defined ratioRePe=0.3333333333333333
4 : real Re=$Re;
Interpreted : real Re=10;
5 : real Pe=$Pe;
Interpreted : real Pe=30;
6 : real ratio=$ratioRePe;
Interpreted : real ratio=0.3333333333333333
Write /tmp/pyfreefem_0k3s9o5b/run.edp
Reset directory /tmp/pyfreefem_0k3s9o5b/ffexport
FreeFem++ /tmp/pyfreefem_0k3s9o5b/run.edp -v 0 -nw (0.01s)

Note

The debug argument of the method execute() has precedence over the one of the FreeFemRunner constructor.

python
runner = FreeFemRunner(script, debug=10)
runner.execute(debug=100) # Execution will follow with debug=100

Debugging syntax errors

If the .edp script is syntaxically incorrect, an exception will be raised. For instance, setting script in the above code to

python script.py
3script = """
4DEFAULT (Re,10)
5SET (Pe,30)
6SET (ratioRePe,$Re/$Pe)
7real Re=$Re
8real Pe=$Pe;
9real ratio=$ratioRePe;"""

and executing with debug=0 yields:

console
$ python test.py
Error : the process "FreeFem++ /tmp/pyfreefem_3kzp33g9/run.edp -v 0 -nw" failed with return code 1.

 Error line number 3, in file /tmp/pyfreefem_3kzp33g9/run.edp, before  token real
syntax error
  current line = 2
Compile error : syntax error
        line number :3, real
error Compile error : syntax error
        line number :3, real
 code = 1 mpirank: 0
Traceback (most recent call last):
  File "/home/florian/python/pyfreefem/pyfreefem/examples/test.py", line 11, in <module>
    FreeFemRunner(script,debug=0).execute()
  File "/home/florian/python/pyfreefem/pyfreefem/freefemrunner.py", line 307, in execute
    raise e
  File "/home/florian/python/pyfreefem/pyfreefem/freefemrunner.py", line 301, in execute
    exec2(self.cmd(target_file, **kwargs),
  File "/home/florian/python/pyfreefem/pyfreefem/io.py", line 253, in exec2
    raise ExecException('Error : the process "'
pyfreefem.io.ExecException

This output may not seem very explicit to understand the mistake. More information can be retrieved by showing FreeFEM standard output with verbosity=1:

freefem
FreeFemRunner(script).execute(verbosity=1)
console
$ python test.py
-- FreeFem++ v4.12 (mer 25 jan 2023 14:14:39 CET - git v4.12)
   file : /tmp/pyfreefem_dkem5s5z/run.edp
 Load: lg_fem lg_mesh lg_mesh3 eigenvalue
    1 :
    2 : real Re=10
    3 : real
 Error line number 3, in file /tmp/pyfreefem_dkem5s5z/run.edp, before  token real
syntax error
  current line = 2
Compile error : syntax error
        line number :3, real
error Compile error : syntax error
        line number :3, real
 code = 1 mpirank: 0
Error : the process "FreeFem++ /tmp/pyfreefem_dkem5s5z/run.edp -v 1 -nw" failed with return code 1.
-- FreeFem++ v4.12 (mer 25 jan 2023 14:14:39 CET - git v4.12)
   file : /tmp/pyfreefem_dkem5s5z/run.edp
 Load: lg_fem lg_mesh lg_mesh3 eigenvalue
    1 :
    2 : real Re=10
    3 : real
 Error line number 3, in file /tmp/pyfreefem_dkem5s5z/run.edp, before  token real
syntax error
  current line = 2
Compile error : syntax error
        line number :3, real
error Compile error : syntax error
        line number :3, real
 code = 1 mpirank: 0
Traceback (most recent call last):
  File "/home/florian/python/pyfreefem/pyfreefem/examples/test.py", line 11, in <module>
    FreeFemRunner(script).execute(verbosity=1)
  File "/home/florian/python/pyfreefem/pyfreefem/freefemrunner.py", line 307, in execute
    raise e
  File "/home/florian/python/pyfreefem/pyfreefem/freefemrunner.py", line 301, in execute
    exec2(self.cmd(target_file, **kwargs),
  File "/home/florian/python/pyfreefem/pyfreefem/io.py", line 253, in exec2
    raise ExecException('Error : the process "'
pyfreefem.io.ExecException

from where it is more clear to infer that the problem comes from the missing comma of line 7 in script.py (real Re=$N).

Note

If the standard output is still not readable enough for debugging, it can be useful to specify a running directory with

freefem
FreeFemRunner(script, run_dir="run").execute(verbosity=1)

and to check directly the file run/run.edp.