Difference between revisions of "Python"
(→String attributes) |
|||
(29 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
Any Python script can become a native ONELAB client by importing the '''onelab.py''' module. | Any Python script can become a native ONELAB client by importing the '''onelab.py''' module. | ||
− | = Getting started = | + | == Getting started == |
− | # Download and uncompress a recent version of Gmsh, or the | + | # Download and uncompress a recent version of Gmsh, or the ONELAB bundle for [http://onelab.info/files/onelab-Windows64.zip Windows] ([http://onelab.info/files/onelab-Windows32.zip 32 bit]), [http://onelab.info/files/onelab-Linux64.zip Linux] ([http://onelab.info/files/onelab-Linux32.zip 32 bit]), or [http://onelab.info/files/onelab-MacOSX.dmg MacOS]. |
# Double-click on the Gmsh executable ('''gmsh.exe''' [[File:GmshIcon.png|GmshIcon.png]] on Windows). | # Double-click on the Gmsh executable ('''gmsh.exe''' [[File:GmshIcon.png|GmshIcon.png]] on Windows). | ||
# Load the Python script ('''.py''' file) through the '''File/Open''' menu, e.g. load the [http://onelab.info/files/pendulum/pend.py pend.py] example given below. | # Load the Python script ('''.py''' file) through the '''File/Open''' menu, e.g. load the [http://onelab.info/files/pendulum/pend.py pend.py] example given below. | ||
Line 9: | Line 9: | ||
# ... that's it! | # ... that's it! | ||
− | = How does it work? = | + | == How does it work? == |
The Python ONELAB interface is implemented in a single Python module: '''onelab.py'''. This module comes pre-installed with Gmsh, in the same directory as the Gmsh executable. When you open a ONELAB-enabled Python solver with Gmsh, Gmsh automatically finds the '''onelab.py''' module. You can also install '''onelab.py''' in any directory of your choosing; in this case don't forget to update your '''PYTHONPATH''' environment variable. | The Python ONELAB interface is implemented in a single Python module: '''onelab.py'''. This module comes pre-installed with Gmsh, in the same directory as the Gmsh executable. When you open a ONELAB-enabled Python solver with Gmsh, Gmsh automatically finds the '''onelab.py''' module. You can also install '''onelab.py''' in any directory of your choosing; in this case don't forget to update your '''PYTHONPATH''' environment variable. | ||
− | |||
− | |||
The following example (a simple Python solver for the double pendulum problem) highlights the main features of the Python interface: | The following example (a simple Python solver for the double pendulum problem) highlights the main features of the Python interface: | ||
− | {{tutorial|pendulum/pend.py | + | {{tutorial|pendulum/pend.py|height=20em}} |
To interact with ONELAB, the script must first import the '''onelab.py''' module: | To interact with ONELAB, the script must first import the '''onelab.py''' module: | ||
− | < | + | <source lang="python"> |
import onelab | import onelab | ||
− | </ | + | </source> |
The script then creates a ONELAB client with: | The script then creates a ONELAB client with: | ||
− | < | + | <source lang="python"> |
− | c = onelab.client() | + | c = onelab.client(__file__) |
− | </ | + | </source> |
− | Creating the client connects the script to the onelab server, through a socket. New ONELAB variables can then be defined using '''defineNumber''', e.g.: | + | Creating the client connects the script to the onelab server, through a socket. |
− | < | + | The '''__file__''' argument is a python variable. It tells ONELAB in which directory the script being executed is located. |
+ | New ONELAB variables can then be defined using '''defineNumber''', e.g.: | ||
+ | <source lang="python"> | ||
l = c.defineNumber('Geom/arm length [m]', value=1.0) | l = c.defineNumber('Geom/arm length [m]', value=1.0) | ||
− | </ | + | </source> |
− | When the script is run, if the parameter '''Geom/arm length [m]''' has not been previously defined, it takes the value (1.0) provided in '''defineNumber''' and is sent to the ONELAB server. The "/" character in the variable name is interpreted as a path separator, and results in the creation of a sub-tree in the graphical user interface. If the script is re-run later, the value will be updated using the value from the server (unless it is labeled as '''readOnly''': see below). When Gmsh runs a ONELAB client, the client can be run in two modes: '''check''' | + | When the script is run, if the parameter '''Geom/arm length [m]''' has not been previously defined, it takes the value (1.0) provided in '''defineNumber''' and is sent to the ONELAB server. The "/" character in the variable name is interpreted as a path separator, and results in the creation of a sub-tree in the graphical user interface. If the script is re-run later, the value will be updated using the value from the server (unless it is labeled as '''readOnly''': see below). When Gmsh runs a ONELAB client, the client can be run in two modes: '''c.action=='check'''' to check the coherence of the ONELAB database and make adjustments if necessary, and '''c.action=='compute'''' to perform the actual computation. For instance, in ''''check'''' mode, the double pendulum client simply defines the ONELAB variables it wants to share with the server, then exits: |
− | < | + | <source lang="python"> |
if c.action == 'check' : | if c.action == 'check' : | ||
exit(0) | exit(0) | ||
− | </ | + | </source> |
− | In | + | In ''''compute'''' mode, the code enters a loop and performs the actual computation. During the computation the script can directly set a value in the ONELAB database with '''setNumber''', as is done in the example with: |
− | < | + | <source lang="python"> |
c.setNumber('Solu/phi', value=phi) | c.setNumber('Solu/phi', value=phi) | ||
− | </ | + | </source> |
It can also e.g. ask the server to read a file with '''mergeFile''': | It can also e.g. ask the server to read a file with '''mergeFile''': | ||
− | < | + | <source lang="python"> |
− | c.mergeFile( | + | c.mergeFile(c.checkPath('pend.msh')) |
− | </ | + | </source> |
+ | The '''check path''' function (c.checkPath) builds the pathname of a file named '''pend.msh''' located in the same directory as the script under execution, and then checks on whether the pathname exists on disk. If not, an error message is issued. Use the regular '''path''' function (c.getPath) to build a pathname without checking on the presence on disk of the file. | ||
== Common parameter attributes == | == Common parameter attributes == | ||
Line 59: | Line 60: | ||
: Alternative label used in the graphical user interface, replacing the part of "Name" located after the last "/" | : Alternative label used in the graphical user interface, replacing the part of "Name" located after the last "/" | ||
− | Other attributes can be specified using the generic '''attribute''' dictionary, e.g. '''attribute={'Highlight':string}'''. See [[ONELAB | + | Other attributes can be specified using the generic '''attribute''' dictionary, e.g. '''attribute={'Highlight':string}'''. See [[ONELAB syntax for Gmsh and GetDP]] for a list of all other attributes. |
== Number attributes == | == Number attributes == | ||
Line 82: | Line 83: | ||
;choices={''string'', ''string'', ...} | ;choices={''string'', ''string'', ...} | ||
: Possible choices for the parameter | : Possible choices for the parameter | ||
+ | |||
+ | == Access to runtime Gmsh front-end parameters == | ||
+ | |||
+ | Accessing a number of Gmsh runtime parameters can be useful to develop more involved on more user-friendly Python-ONELAB solvers. | ||
+ | |||
+ | ;c.action == 'check' | 'compute' | ||
+ | :Test on the string variable '''c.action''' can be done to branch on parts of the script to be executed or not according to the mode. See above. | ||
+ | |||
+ | ;c.loop == 0|1 | ||
+ | :Gmsh can loop on parameters to perform simple parametric analyses. The variable '''c.loop''' is 1 when Gmsh is engaged in such a loop, 0 otherwise. See [[Beam3D]] for an example. | ||
+ | |||
+ | ;c.batch == 0|1 | ||
+ | :The variable '''c.batch''' is 1 when a Python script '''script.py''' is called by Gmsh with no GUI, i.e. with '''gmsh script.py -'''. It is 0 otherwise. | ||
+ | |||
+ | ;c.getPath | c.checkPath | ||
+ | :The function '''c.getPath(subdir/filename)''' returns a pathname built by appending ‘subdir/filename’ to the pathname of the directory where the Python script under execution is located. The function '''c.checkPath''' is the same as '''c.getPpath''' but also checks whether the built pathname exists on disk. If the pathname does not exist, an error is issued. | ||
+ | |||
+ | == Saving/loading models and solutions == | ||
+ | |||
+ | If the '''Archive output files automatically''' checkbox is checked in the gear menu of Gmsh, the files declared in the python script by the statement | ||
+ | <source lang="python"> | ||
+ | c.outputFiles( [file1.ext1, file2.ext2, …] ) | ||
+ | </source> | ||
+ | as well as the database state, are copied at the end of each run of the model into the '''/archive''' subdirectory of the working directory with names | ||
+ | <source lang="python"> | ||
+ | file1_yyyy-mm-dd_hh-mm-ss_tag.ext1 | ||
+ | file2_yyyy-mm-dd_hh-mm-ss_tag.ext2 | ||
+ | ... | ||
+ | onelab_yyyy-mm-dd_hh-mm-ss_tag.db | ||
+ | </source> | ||
+ | The automatically appended stamp consists of a to the second accurate timestamp '''yyyy-mm-dd_hh-mm-ss''', | ||
+ | augmented with the user-defined ONELAB string parameter named '''Metamodel/Tag''' (which can be a null string). The purpose of automatic archiving is to keep track of all simulations done, which might be memory-space consuming. The declared output files should therefore not be too large in size, and contain in a concise form the main results of a simulation. The archived database, on the other hand, allows reproducing the simulation if needed. | ||
+ | |||
+ | When a metamodel involves heavy and time-consuming computations, it is also interesting, in addition to the output files, to also save the solution files. This allows making series of post-processing runs on the same simulation data. To do this, the '''Load Database''' and '''Save Database''' commands of the gear menu are used. If the script contains a statement | ||
+ | <source lang="python"> | ||
+ | c.solutionFiles( [file1.ext1, file2.ext2, …] ) | ||
+ | </source> | ||
+ | saving the database under the name '''onelab_tag.db''' into the directory '''dbdir''' with the '''Save Database''' widget will save the ONELAB database and additionally rename on disk the declared solution files into | ||
+ | <source lang="python"> | ||
+ | dbdir/archive/file1_tag.ext1 | ||
+ | dbdir/archive/file2_tag.ext2 | ||
+ | ... | ||
+ | </source> | ||
+ | It is a good practice to save the databases in the working directory, so that the saved solution files end up in the same directory as the automatically archived output files. | ||
+ | |||
+ | Be sure to clearly understand the difference between 'output files' and 'solution files'. The former are small-size files (order of a few kB) that summarize a simulation in a concise way, typically data for graphs. The latter are large-size files (order of MB) containing solutions at all nodes and all time steps of the finite element problem. The user is invited to clean up the '''/archive''' subdirectory regularly. | ||
+ | Practically, when a simulation is completed that you want to save, | ||
+ | * click on '''gear menu/Save database''', | ||
+ | * enter a filename of the form '''onelab_tag.db''' in the '''Save as''' box, with an explicit '''tag''' that characterizes the simulation at hand (e.g. '''onelab_case1.db''' or '''onelab_reference.db''') | ||
+ | * browse to the directory where the database should be saved (recommended: in the working directory) | ||
+ | * click on '''Save'''. | ||
+ | |||
+ | To reload a simulation, | ||
+ | * click on '''gear menu/Open database''' | ||
+ | * select the database to restore (e.g. onelab_case1.db) | ||
+ | * click on '''Open'''. | ||
+ | As long as the '''Use restored solution''' checkbox remains checked, model runs will use the restored solution files. |
Latest revision as of 18:07, 25 November 2017
Any Python script can become a native ONELAB client by importing the onelab.py module.
Contents
Getting started
- Download and uncompress a recent version of Gmsh, or the ONELAB bundle for Windows (32 bit), Linux (32 bit), or MacOS.
- Double-click on the Gmsh executable (gmsh.exe Error creating thumbnail: Unable to save thumbnail to destinationon Windows).
- Load the Python script (.py file) through the File/Open menu, e.g. load the pend.py example given below.
- Click on Run.
- ... that's it!
How does it work?
The Python ONELAB interface is implemented in a single Python module: onelab.py. This module comes pre-installed with Gmsh, in the same directory as the Gmsh executable. When you open a ONELAB-enabled Python solver with Gmsh, Gmsh automatically finds the onelab.py module. You can also install onelab.py in any directory of your choosing; in this case don't forget to update your PYTHONPATH environment variable.
The following example (a simple Python solver for the double pendulum problem) highlights the main features of the Python interface:#!/usr/bin/env python #coding=utf-8 # 1) launch "gmsh pend.py" # 2) there is no 2... :-) import onelab import math, os c = onelab.client(__file__) def exportMsh(le1,le2): mshFile = open(c.getPath("pend.msh"), 'w') mshFile.write('$MeshFormat\n2.2 0 8\n$EndMeshFormat\n') mshFile.write('$Nodes\n3\n1 0 0 0\n2 0 %s 0\n3 0 %s 0\n$EndNodes\n' %(-le1, -le1-le2)) mshFile.write('$Elements\n3\n1 1 2 0 1 1 2\n2 1 2 0 1 2 3\n3 15 2 0 2 3\n$EndElements\n') mshFile.close() def exportMshOpt(): optFile = open(c.getPath("pend.msh.opt"),'w') optFile.write('n = PostProcessing.NbViews - 1;\n') optFile.write('If(n >= 0)\nView[n].ShowScale = 0;\nView[n].VectorType = 5;\n') optFile.write('View[n].ExternalView = 0;\nView[n].DisplacementFactor = 1 ;\n') optFile.write('View[n].PointType = 1;\nView[n].PointSize = 5;\n') optFile.write('View[n].LineWidth = 2;\nEndIf\n') optFile.close() def exportIter(iter,t,x1,y1,x2,y2): mshFile = open(c.getPath("pend.msh"),'a') mshFile.write('$NodeData\n1\n"motion"\n1\n\t%f\n3\n\t%d\n3\n' % (t, iter)) mshFile.write('\t3\n\t1 0 0 0\n\t2 %f %f 0\n\t3 %f %f 0\n$EndNodeData\n' %(x1,y1,x2,y2)) mshFile.close() g = 9.8 # acceleration of gravity m = 0.3 # mass of pendulum balls l = c.defineNumber('Geom/arm length [m]', value=1.0) time = c.defineNumber('Dyna/time [s]', value=0.0) dt = c.defineNumber('Dyna/time step [s]', value=0.001) tmax = c.defineNumber('Dyna/max time [s]', value=20) refresh = c.defineNumber('Dyna/refresh interval [s]', value=0.1) theta0 = c.defineNumber('Init/initial theta angle [deg]', value=10, attributes={'Highlight':'Pink'}) phi0 = c.defineNumber('Init/initial phi angle [deg]', value=180, attributes={'Highlight':'Pink'}) # we're done if we are in the "check" phase if c.action == 'check' : exit(0) l1 = l; l2 = l; m1 = m; m2 = m; theta = theta0 / 180.*math.pi; phi = phi0 / 180.*math.pi; theta_dot = 0.0 phi_dot = 0.0 refr = 0.0 iter = 0 time = 0.0 while (time < tmax): delta = phi - theta sdelta = math.sin(delta) cdelta = math.cos(delta) theta_dot_dot = ( m2*l1*(theta_dot**2.0)*sdelta*cdelta + m2*g*math.sin(phi)*cdelta + m2*l2*(phi_dot**2.0)*sdelta - (m1+m2)*g*math.sin(theta) ) theta_dot_dot /= ( (m1+m2)*l1 - m2*l1*(cdelta)**2.0 ) phi_dot_dot = ( -m2*l2*(phi_dot**2.0)*sdelta*cdelta + (m1+m2)*(g*math.sin(theta)*cdelta - l1*(theta_dot**2.0)*sdelta - g*math.sin(phi)) ) phi_dot_dot /= ( (m1+m2)*l2 - m2*l2*(cdelta)**2.0 ) theta_dot = theta_dot + theta_dot_dot*dt phi_dot = phi_dot + phi_dot_dot*dt theta = theta + theta_dot*dt phi = phi + phi_dot*dt x1 = l1*math.sin(theta) y1 = -l1*math.cos(theta) x2 = l1*math.sin(theta) + l2*math.sin(phi) y2 = -l1*math.cos(theta) - l2*math.cos(phi) time += dt refr += dt exportMshOpt() if refr >= refresh: refr = 0 c.setNumber(c.name + '/Progress', value=time, min=0, max=tmax, visible=0) c.setNumber('Dyna/time [s]', value=time) c.setNumber('Solu/phi', value=phi) c.addNumberChoice('Solu/phi', phi) c.setNumber('Solu/theta', value=theta) c.addNumberChoice('Solu/theta', theta) c.setNumber('Solu/phi dot', value=phi_dot) c.addNumberChoice('Solu/phi dot', phi_dot) c.setNumber('Solu/theta dot', value=theta_dot) c.addNumberChoice('Solu/theta dot', theta_dot) # ask Gmsh to refresh c.setString('Gmsh/Action', value='refresh') # stop if we are asked to (by Gmsh) if(c.getString(c.name + '/Action') == 'stop'): break; exportMsh(l1, l2) exportIter(iter, time, x1, y1+l1, x2, y2+l1+l2) c.mergeFile(c.checkPath('pend.msh')) iter += 1 c.setNumber(c.name + '/Progress', value=0)
Direct link to file `pendulum/pend.py'
To interact with ONELAB, the script must first import the onelab.py module:
import onelab
The script then creates a ONELAB client with:
c = onelab.client(__file__)
Creating the client connects the script to the onelab server, through a socket. The __file__ argument is a python variable. It tells ONELAB in which directory the script being executed is located. New ONELAB variables can then be defined using defineNumber, e.g.:
l = c.defineNumber('Geom/arm length [m]', value=1.0)
When the script is run, if the parameter Geom/arm length [m] has not been previously defined, it takes the value (1.0) provided in defineNumber and is sent to the ONELAB server. The "/" character in the variable name is interpreted as a path separator, and results in the creation of a sub-tree in the graphical user interface. If the script is re-run later, the value will be updated using the value from the server (unless it is labeled as readOnly: see below). When Gmsh runs a ONELAB client, the client can be run in two modes: c.action=='check' to check the coherence of the ONELAB database and make adjustments if necessary, and c.action=='compute' to perform the actual computation. For instance, in 'check' mode, the double pendulum client simply defines the ONELAB variables it wants to share with the server, then exits:
if c.action == 'check' : exit(0)
In 'compute' mode, the code enters a loop and performs the actual computation. During the computation the script can directly set a value in the ONELAB database with setNumber, as is done in the example with:
c.setNumber('Solu/phi', value=phi)
It can also e.g. ask the server to read a file with mergeFile:
c.mergeFile(c.checkPath('pend.msh'))
The check path function (c.checkPath) builds the pathname of a file named pend.msh located in the same directory as the script under execution, and then checks on whether the pathname exists on disk. If not, an error message is issued. Use the regular path function (c.getPath) to build a pathname without checking on the presence on disk of the file.
Common parameter attributes
Here's the list of attributes available for all ONELAB parameters:
- name=string
- The name of the parameter in the ONELAB database, in the form of a "/"-separated path. The name attribute is mandatory to exchange the variable with the ONELAB server.
- readOnly=0|1
- If readOnly is set, the value cannot be changed server-side, and the value provided in the python script is always used
- visible=0|1
- Should the parameter be visible in the interface?
- help=string
- Help string for this parameter
- label=string
- Alternative label used in the graphical user interface, replacing the part of "Name" located after the last "/"
Other attributes can be specified using the generic attribute dictionary, e.g. attribute={'Highlight':string}. See ONELAB syntax for Gmsh and GetDP for a list of all other attributes.
Number attributes
In addition, numbers can take the following specific attributes:
- min=number
- Minimum value allowed when scrolling in the interface, and when looping on the parameter
- max=number
- Maximum value allowed when scrolling in the interface, and when looping on the parameter
- step=number
- Step value used when scrolling in the interface, and when looping on the parameter
- choices={number, number, ...}
- Possible choices for the parameter
- labels={number:string, number:string, ...}
- Possible choices for the parameter, with string labels for each choice
String attributes
Strings accept the following specific attributes:
- kind=string
- Mutable kind of the string (currently: "file")
- choices={string, string, ...}
- Possible choices for the parameter
Access to runtime Gmsh front-end parameters
Accessing a number of Gmsh runtime parameters can be useful to develop more involved on more user-friendly Python-ONELAB solvers.
- c.action == 'check' | 'compute'
- Test on the string variable c.action can be done to branch on parts of the script to be executed or not according to the mode. See above.
- c.loop == 0|1
- Gmsh can loop on parameters to perform simple parametric analyses. The variable c.loop is 1 when Gmsh is engaged in such a loop, 0 otherwise. See Beam3D for an example.
- c.batch == 0|1
- The variable c.batch is 1 when a Python script script.py is called by Gmsh with no GUI, i.e. with gmsh script.py -. It is 0 otherwise.
- c.getPath | c.checkPath
- The function c.getPath(subdir/filename) returns a pathname built by appending ‘subdir/filename’ to the pathname of the directory where the Python script under execution is located. The function c.checkPath is the same as c.getPpath but also checks whether the built pathname exists on disk. If the pathname does not exist, an error is issued.
Saving/loading models and solutions
If the Archive output files automatically checkbox is checked in the gear menu of Gmsh, the files declared in the python script by the statement
c.outputFiles( [file1.ext1, file2.ext2, …] )
as well as the database state, are copied at the end of each run of the model into the /archive subdirectory of the working directory with names
file1_yyyy-mm-dd_hh-mm-ss_tag.ext1 file2_yyyy-mm-dd_hh-mm-ss_tag.ext2 ... onelab_yyyy-mm-dd_hh-mm-ss_tag.db
The automatically appended stamp consists of a to the second accurate timestamp yyyy-mm-dd_hh-mm-ss, augmented with the user-defined ONELAB string parameter named Metamodel/Tag (which can be a null string). The purpose of automatic archiving is to keep track of all simulations done, which might be memory-space consuming. The declared output files should therefore not be too large in size, and contain in a concise form the main results of a simulation. The archived database, on the other hand, allows reproducing the simulation if needed.
When a metamodel involves heavy and time-consuming computations, it is also interesting, in addition to the output files, to also save the solution files. This allows making series of post-processing runs on the same simulation data. To do this, the Load Database and Save Database commands of the gear menu are used. If the script contains a statement
c.solutionFiles( [file1.ext1, file2.ext2, …] )
saving the database under the name onelab_tag.db into the directory dbdir with the Save Database widget will save the ONELAB database and additionally rename on disk the declared solution files into
dbdir/archive/file1_tag.ext1 dbdir/archive/file2_tag.ext2 ...
It is a good practice to save the databases in the working directory, so that the saved solution files end up in the same directory as the automatically archived output files.
Be sure to clearly understand the difference between 'output files' and 'solution files'. The former are small-size files (order of a few kB) that summarize a simulation in a concise way, typically data for graphs. The latter are large-size files (order of MB) containing solutions at all nodes and all time steps of the finite element problem. The user is invited to clean up the /archive subdirectory regularly. Practically, when a simulation is completed that you want to save,
- click on gear menu/Save database,
- enter a filename of the form onelab_tag.db in the Save as box, with an explicit tag that characterizes the simulation at hand (e.g. onelab_case1.db or onelab_reference.db)
- browse to the directory where the database should be saved (recommended: in the working directory)
- click on Save.
To reload a simulation,
- click on gear menu/Open database
- select the database to restore (e.g. onelab_case1.db)
- click on Open.
As long as the Use restored solution checkbox remains checked, model runs will use the restored solution files.