Difference between revisions of "Python"

From ONELAB
Jump to: navigation, search
(Common parameter attributes)
(Common parameter attributes)
Line 47: Line 47:
 
: 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_Syntax_for_Gmsh_and_GetDP]] for a list of all other attributes.
+
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 ==

Revision as of 09:54, 8 December 2013

Any Python script can become a native ONELAB client by importing the onelab.py module.

Getting started

  1. Download and uncompress a recent version of Gmsh, or the Gmsh/GetDP bundle for Windows64, Windows32, Linux64, Linux32 or MacOSX.
  2. Double-click on the Gmsh executable (gmsh.exe
    Error creating thumbnail: Unable to save thumbnail to destination
    on Windows).
  3. Load the Python script (.py file) through the File/Open menu, e.g. load the pend.py example given below.
  4. Click on Run.
  5. ... 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.

Double pendulum example

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'


Let's examine the example step by step. To interact with ONELAB, the Python code must first import the onelab.py module: <syntaxhighlight lang="python"> import onelab </syntaxhighlight> After defining three functions that will export a mesh (with visualization options) and an associated time-dependent dataset, the script then creates a ONELAB client: <syntaxhighlight lang="python"> c = onelab.client() </syntaxhighlight> Creating the client connects the script to the onelab server, through a socket. New ONELAB variables are then defined using defineNumber, e.g.: <syntaxhighlight lang="python"> l = c.defineNumber('Geom/arm length [m]', value=1.0) </syntaxhighlight> When the script is run, if the parameter has not been previously defined, it takes the value 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).

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

String accepts the following specific attributes:

kind=string
Mutable kind of the string (currently: "file")
choices={string, string, ...}
Possible choices for the parameter