The base language#
Introduction#
zLanguage is an end-user and powerfull scripting language. Its main goal is to provide to the end-user an acess to all ZeBuLoN internal code without recompiling anything. Using l allows end-users to enrich specific parts of the code, mainly post-processing calculations and boundary conditions. It also allows to generate parametric meshes. It is difficult to explain how rich and powerfull this extension is : the reader is invited to read the following pages which contain a lot of different examples from very different areas. There is especially some very interessting sections named ”How to use a Zlanguage script to …“.
zLanguage consists in several packages devoted to specific parts of the code. Usually these packages are overlaped : the master package inherits from the base package.
The purpose of this chapter is to explain the base grammar and syntax of zLanguage. This chapter is not a programming course; the user is supposed to know the basis of structural programming.
General remark#
It is necessary to declare all the object at the begin of each block (void, function if etc ..
Script file format#
A script file is a regular plain text file as any other ZeBuLoN input file. All instructions must be ended by a semicolumn (except after a closing block brace); a line can contains multiple instructions. The two following zLanguage fragments are both legal and code the same algorithm piece :
void main()
{
double a,b;
a=2.;
b=-1.;
}
void main()
{
double a,b;
a=2.; b=-1.;
}
One can split its script into different files, using #include
directive to include one or more files into another. Suppose that file
named ’f1.h’ contains : void do_something() ...., one can
use function do_something in another script file using :
#include <f1.h>
void main()
{
.....
do_something();
.....
}
In order to avoid infinitely recursive include files, a file is included by another only if this file has never been included before : suppose that a file named ’f1.z7p’ includes ’f2.h’ and that ’f2.h’ includes ’f3.h’, if ’f3.h’ includes ’f1.z7p’ or ’f2.h’, a warning message is printed and the file is not included (to avoid infinite include recursion).
Include files are looked for first in Z-set directory
($Z7PATH/lib/Scripts) then in the current working directory.
Functions#
zLanguage can be seen as a subset of C++. It provides the main characteristics and mechanisms of all object oriented languages, with the exception of defining new types : l programs can not define new types and can only use predefined types.
A script consists in a given number of functions. The definition of a function respects C/C++ standard :
double do_something(double a, int b, string s)
{
}
defines a function named “do_something” taking three agruments : a floating point value (a), an integer value (b) and a string value (s). This function is also supposed to return a floating point value.
One special function must at least be defined : the main function. An execution of any script always start in the main function which must be defined (unless otherwise informed) as :
void main()
{
}
void is a special type used to informe zLanguage that this function do not return a value. The parameter list is empty because main is the script starting point.
It is now time to write the well known “Hello world !” program using zLanguage : put the following script in a file named “hello.z7p” and run the command ’Zrun -zp hello.z7p’. The ’-zp’ switch starts l interpreter with the only the base package activated.
void main()
{
("Hello world !"+endl).print();
}
it should write the words “Hello world !” on a single line. Some explanations about this first script :
“Hello world !” is a constant character string
endl is a predefined global object (i.e. you can acess this object everywhere in your scripts). It is just a string object containing a new line character.
operator + applied to strings is the concatenation operator
after it built the string to write, the script makes a calls to a method 1A method is a function attached to a precise type. The contens of this function is type dependant. named ’print’ which write the contens of the string on the terminal. All objects in zLanguage have a ’print()’ method to write their contens (sometimes this method is a default method doing nothing).
A somewhat more complex example (write the following script in a file named e.g. ’test_0.z7p’ and run the command ’Zrun -zp test_0.z7p’) :
void set_parameters(double p1, double p2)
{
p1=1.; p2=2.;
}
void main()
{
double a,b;
a=0.; b=0.;
("Before the call, a="+a+" and b="+b+endl).print();
set_parameters(a,b);
("After the call, a="+a+" and b="+b+endl).print();
}
this script should normally print the following lines (if not, please contact your ZeBuLoN hotline) :
Before the call, a=0.000000 and b=0.000000
After the call, a=1.000000 and b=2.000000
This script demonstrates :
it is possible to add a string and a floating point value. The result is the concatenation between the first string and the string representation of the floating point value
all function parameters are passed by reference : it means that modify a function parameter modifies, in fact, the calling object.
Each function can contain a declaration block and a statements block. The declaration block consists in a list of typed list.
zLanguage statements#
This section list all valid zLanguage statements, i.e. all basic instructions you can use in a script, with a trivial example for each statement (the left column contains the script; the right column contains execution result).
return(exp)Exits from the current function and return the given expression to the caller. Care must be taken to not return a parameter in a function returning void !double func() { return(3.); } void main() { ("Function returns : " +func()+endl).print(); }
Execution :Function returns : 3.000000if(exp) lstatementExecutes lstatement if exp if true (i.e. if exp is a positive integer).void func(double value) { if(value>=0.) ("pos"+endl).print(); if(value<0.) ("neg"+endl).print(); } void main() { double a; a=2.; "First call : ".print(); func(a); a=-1.; "Second call : ".print(); func(a); }
Execution :First call : posSecond call : negif(exp) lstatement1 else lstatement2Executes lstatement1 if exp is true, lstatements2 otherwise.void func(double value) { if(value>=0.) ("pos"+endl).print(); else ("neg"+endl).print(); } void main() { double a; a=2.; "First call : ".print(); func(a); a=-1.; "Second call : ".print(); func(a); }
Execution :First call : posSecond call : negwhile (exp) lstatementExecutes lstatement while exp is true.void main() { double a; a=0.; while(a<10.) { ("a="+a+endl).print(); a=a+1.; } }
Execution :a=0.000000a=1.000000a=2.000000a=3.000000a=4.000000a=5.000000a=6.000000a=7.000000a=8.000000a=9.000000do lstatement while(exp)Same as thewhilestatement except that lstatement is executed before the evaluation of exp (in other words, usingdostatement, lstatement is at least one time executed).void main() { double a; a=0.; do { ("a="+a+endl).print(); a=a+1.; } while(a<10.); }
Execution :a=0.000000a=1.000000a=2.000000a=3.000000a=4.000000a=5.000000a=6.000000a=7.000000a=8.000000a=9.000000for(init;test;next) lstatementThis statement executesinitandtest. Whiletestis true, it executes lstatement andnext.void main() { double a; for(a=0.;a<10.;a=a+1) { ("a="+a+endl).print(); a=a+1.; } }
Execution :a=0.000000a=2.000000a=4.000000a=6.000000a=8.000000
Debugger#
zLanguage implementation provides a simple debugger to help debugging scripts.
The debugger is launched every time ZSet wants to execute a script, as
soon as a specific global parameter is given on the command line. This
parameter is named Zlanguage.Debug. The user who wants to debug has
just to launch ZSet with the option [-s Zlanguage.Debug 1] whatever
the name of the command is (examples :
Zrun -s Zlanguage.Debug 1 -pp … or
Zmaster -s Zlanguage.Debug 1 -B …).
Each time the execution of a script is requested control is given to the
internal debugger which prints a prompt (zld ->) and waits for
commands. The main commands are summarized below (bracketed letters
design short cuts : the user may type break or just b) :
[b]reak <li>: inserts a breakpoint at line li[c]ont: continue a suspended execution[d]delete <id>: delete breakpoint \(\langle\)id\(\rangle\)[i]nfo: print breakpoints informations (usefull to get \(\langle\)id\(\rangle\) to be given to [d]elete)[n]ext: continue execution and break at next line code[p]rint <obj>: prints the contens of object named \(\langle\)obj\(\rangle\)[f]rame <id>: set active frame to \(\langle\)id\(\rangle\)[w]here: print call stack and frame ids[q]uit: quit and abort execution of the current script[h]elp: lists debugger commands
A classical debugging session usually consists in defining some breakpoints ([b]reak command) and in printing some objects.
Object#
Every accessible type in zLanguage is an object : it contains methods and members.
A method is a specific function attached to a particular type : two methods attached to two different types may have the same name and do completely different things.
A member is an object attached to a particular type.
Methods and members are accessed using ’.’ operator : alpha.print()
executes the print method of alpha (depending of alpha’s type);
beta.size=2; assigns 2 to member size of variable beta (assuming
that this assignement has a sense).
Templated types#
Some object type are “templatized” : they are associated to an underlying type and the behavior of such type depends on the sub-type. An array object is a very classical templated type : it is an object by itself, but on the other hand the user has to specify what the type of the contained sub-objects is.
Such templates classes are intoduced using \(\langle\) and \(\rangle\) brackets. The following piece of script declares an array of string and initializes it :
void main()
{
int i;
ARRAY<string> aos;
aos.resize(5);
for(i=0;i<!aos;i=i+1) aos[i]=("str "+i);
("Sub type of ARRAY<string> is : "
+aos.type+endl).print();
("Nb elements : "+!aos+endl).print();
for(i=0;i<!aos;i=i+1) (aos[i]+endl).print();
}
In the following sections templated types are explicitely signaled.
Base types#
This section describes base zLanguage types (these types are always
accessible, whatever package you are using). i denotes an integer
value, d a floating point value.
int: represents an integer.Operators :
+ - * /: classical arithmentic operators. With two integer operands, the result is always an integer (/represents the euclidian divide operator). When the second operand is a floting point value, the result is also a floting point value (/represents the floating point divide operator).%: the remainder of an euclidian division (7%4=3). Usefull to test if an integer value is odd or even.=: assignment operator (accept int or double).++: increase value by one (3++=4).–: decrease value by one (3–=2).> < >= <= == !=: classical comparison operators.! | &: boolean operation not, or and.
Methods :
print(): print current value.
double: represents a floating point value.Operators :
+ - * /: classical arithmentic operators.=: assignment operator (accept int or double).> < >= <= == !=: classical comparison operators.
Methods :
print(): print current value.
string: represents a character string.Operators :
+: concatenation operator. The second operand can be : a string, an integer or a floating point value.=: assignment operator.== !=: classical comparison operators.
Methods :
print(): print current value.
VECTOR: array of floating point values.Operators :
+ -: + and - operators. Both operands must be vectors with the same size./: Multiply or divide a vector by a floating point or an integer value.=: assignment operator. It is possible to assign a vector with another vector (component to component copy), with an integer or a floating point value (all component are set to this value), or with a TENSOR2 object.!: current size.|: dot product (v1|v2=sum(v1[i]*v2[i],i)).[i]: component access (v[i] denotes the ith component of vector v).
Methods :
set(...): initialize vector. This method takes a list of floating or integer values, resize and initialize vector.norm(): return the euclidian norm of the vector.resize(int): resize vector.print(): print current value.
TENSOR2: tensor of order 2.Operators :
+ -: + and - operators. Both operands must be tensors of order 2 with the same size.: Multiply a TENSOR2 by a floating point, an integer value, a TENSOR2 object or a TENSOR4 object.
/: Divide a TENSOR2 by a floating point or an integer value.=: assignment operator. It is possible to assign a TENSOR2 with another TENSOR2 (component to component copy), with an integer or a floating point value (all component are set to this value), or with a VECTOR object.!: current size.|: return the contracted prodcut of two tensors.[i]: component access (v[i] denotes the ith component of vector v).
Methods :
set(...): initialize TENSOR2. This method takes a list of floating or integer values. It resizes and initializes TENSOR2.mises(): return mises norm.trace(): return trace.deviator(): return deviatoric part.add_sqrt2(): add sqrt(2) terms 3,4 and 5 of the tensor.remove_sqrt2(): remove sqrt(2) terms 3,4 and 5 of the tensor.eigen(VECTOR, TENSOR2): return the ….eigen_vecs(VECTOR): return the principal values of the tensor.resize(int): resize TENSOR2.print(): print current value.
TENSOR4: tensor of order 4.Operators :
+ -: + and - operators. Both operands must be tensors of order 4 with the same size.: Multiply a TENSOR4 by a floating point, an integer value or a TENSOR2 object.
/: Divide a TENSOR4 by a floating point or an integer value.=: assignment operator. It is possible to assign a TENSOR4 with another TENSOR4 (component to component copy), with an integer or a floating point value (all component are set to this value).!: current size.
Methods :
resize(int): resize TENSOR4.
MATRIX: general matrix.Operators :
+ -: + and - operators. Both operands must be matrices with the same sizes.: Multiply a MATRIX. Right operand can be of type double, int, VECTOR or MATRIX.
=: assignment operator. It is possible to assign a MATRIX with another MATRIX (component to component copy), with an integer or a floating point value (all component are set to this value).(i,j): component access (m(i,j) denotes the component i,j of matrix m).
Methods :
set_rotation(double alpha): initialize matrix to be a 2D rotation operator with center (0.,0.) and angle alpha.resize(int n,int m): resize a MATRIX with n rows and m columns.print(): print current value.
Members :
int n(ro) : current number of rows.int m(ro) : current number of columns.
SMATRIX: general square matrix.Operators :
+ -: + and - operators. Both operands must be SMATRIX with the same sizes.: Multiply a SMATRIX. Right operand can be of type double, int, VECTOR, TENSOR2 or SMATRIX.
=: assignment operator. It is possible to assign a SMATRIX with another SMATRIX (component to component copy), with an integer or a floating point value (all component are set to this value), with a TENSOR4 or a MATRIX.(i,j): component access (m(i,j) denotes the component i,j of matrix m).
Methods :
resize(int n): resize a SMATRIX with n rows and n columns.inverse(): inverse a SMATRIX.transpose(): transpose a SMATRIX.print(): print current value.
Members :
int n(ro) : current number of rows.int m(ro) : current number of columns.
ARRAY<T>: general array of object. Templated typeOperators :
!: current size.[i]: component access (a[i] denotes the ith object of ARRAY a).
Methods :
resize(int): resize an ARRAY. This operation is safe regarding to stored components : previously stored components are preserved.print(): print current value.
Members :
string type(ro) : a string containing the sub-type of this templated object.
POINTER: generic pointer.Operators :
=: pointer assignement. Right operand may be any object.
Methods :
set_type(string): define the underlying type.
Members :
string type(ro) : current object type.OBJECT object(rw) : current object.
Note that this type is not a templated type (the reason is that this generic pointer can stores ”on the fly“ any object changing during the execution).
LIST: list of objects.Operators :
[i]: acess the ith object of the list.!: return current list size.
Methods :
add(OBJECT): add an object.reset(): reinitialize the list (i.e. set the list length to zero).suppress(int i): suppress the ith element of the list.print(): print all list objects.
Zfstream: general file object.Operators :
<<: to write in a file (see $Z7PATH/tests/Program_test/Base_test/INP for examples
Methods :
open(STRING name, int t): to open a file named “name”, t is open mode (ios::in to read, ios::out to write and ios::app to add something at the end of the file).close(): to close a file
Predefined objects#
This section lists all predefined objects to be used anywhere in a script.
Mathematical functions :
sin(double): sincos(double): costan(double): tanasin(double): asinacos(double): acosatan(double): atansinh(double): sinhcosh(double): coshtanh(double): tanhasinh(double): asinhacosh(double): acoshatanh(double): atanhfloor(double d): rounds d downwards to the nearest integerceil(double d): rounds d upwards to the nearest integersqrt(double d): square root of dabs(double d): absolute value of dln(double d): logarithm value of d, base eint(double d): converts double d to integerlog(double d): logarithm value of d, base 10exp(): exponentialrandom(): return a random floating point number in the interval [0..1]
Mathematical constants :
pi: \(\pi\)pi2: \(\pi/2\)pi3: \(\pi/3\)pi4: \(\pi/4\)e: \(e=exp(1)\)inve: \(1/e=exp(-1)\)
String constants :
endl: “\(\langle\)CRLF\(\rangle\)” (a string containing the single newline character)
General purpose objects :
cout: an object to handle streamed console outputs as C++ does. Usecout<<objectto print something on terminal. One can also nest such instructions :console<<"Hello world !"<<endlprints the string “Hello world !” followed by an carriage return.cin: an object to handle streamed console inputs as C++ does. Usecin>>objectto get something from terminal.cflush: used to flush output stream. The only method is(): the statement ’cflush();’ flushes output stream.ERROR: used to trigger a fatal error. The only method is(string): the statement ’ERROR("this is an error");’ prints the words “this is an error” on the output stream and exits the script.plot: an object used to draw a curve from vectors. See next section.runge: an object used to solve differential systems. See next section.data_file: an object used to load and save many things from a file. See next section.
Global objects plot, runge and data_file#
plot :plot(VECTOR vx, VECTOR vy): plot curve \(vy=f(vx)\) using gnuplot external program.
Members :
string labelx(rw) : label of x axis.string labely(rw) : label of y axis.string title(rw) : title of the curve.string style(rw) : style of the curve (see gnuplot online help for more info).
A test program about plot object, which plots the sinus function :
void main()
{
VECTOR vx,vy;
double x;
int i;
vx.resize(20); vy.resize(!vx);
for(i=0;i<!vx;i++) {
x=2*pi/!vx*i;
vx[i]=x; vy[i]=sin(vx[i]);
}
plot.labelx="x";
plot.labely="sin(x)";
plot.title="The sinus function";
plot.style="linespoints";
plot.plot(vx,vy);
}
runge :integrate(FUNCTION f, double xi, double xf, VECTOR chi, VECTOR dchi, int sample): solve the differential system \(\partial \chi/\partial x=f(\chi,x)\) using a Runge-Kutta method. The f FUNCTION must be a function with signature :void f(double t, VECTOR chi, VECTOR dchi). xi and xf are the lower and uppper bounds of the interval solution. sample is the number of samples across the interval solution. chi and dchi are two VECTORs.xintegrate(FUNCTION f, double xi, double xf, VECTOR chi, VECTOR dchi): solve the same differential system, but gives only the solution at the upper bound (ie no interval sampling).print(): print current Runge-Kutta parameters.
Members :
double eps_r(rw) : \(\varepsilon_r\) parameter.double ymax_r(rw) : \(ymax_r\) parameter.
A test program about runge object, which solves the differential
system
using integrate and xintegrate.
void main()
{
solve_cos();
x_solve_cos();
}
void derivative(double time, VECTOR chi, VECTOR dchi)
{
dchi.resize(1);
dchi[0]=sin(time);
}
void solve_cos()
{
VECTOR vy,vx;
double ti,tf;
runge.eps_r=.001;
runge.ymax_r=.001;
runge.print();
vy.resize(50);
vx.resize(vy.size());
ti=0.; tf=4*pi;
vy[0]=-1.;
runge.integrate(derivative,ti,tf,vx,vy,vx.size());
plot.labelx="x";
plot.labely="y";
plot.style="linespoints lw 2 ps 2";
plot.title="y=integrate(sin,0.,x)";
plot.plot(vx,vy);
}
void x_solve_cos()
{
VECTOR dchi,chi,vy,vx;
double t0,t1;
double ti,tf;
int i;
chi.resize(1);
dchi.resize(1);
runge.eps_r=.001;
runge.ymax_r=.001;
runge.print();
vy.resize(50);
vx.resize(vy.size());
ti=0.; tf=2*pi;
for(i=0;i<!vx;i=i+1) {
if(i==0) t0=ti; else t0=vx[i-1];
vx[i]=tf/vx.size()*i;
t1=vx[i];
if(i==0) chi[0]=0.; else chi[0]=vy[i-1];
runge.xintegrate(derivative,t0,t1,chi);
vy[i]=chi[0];
}
plot.labelx="x";
plot.labely="y";
plot.style="linespoints";
plot.title="y=integrate(sin,0.,x)";
plot.plot(vx,vy);
}
data_file :load_globals(string fname): try to open file namedfname. If suceeded, look on this file to define global double variables.load_vectors(string fname, VECTOR v1,...): try to open file namedfname. If suceeded, try to load column vectors onto VECTORs v1,…save_vectors(string fname, VECTOR v1,...): save VECTORs v1,… into a file namedfname.
To explain how load_globals works, suppose that a file named
’globals.dat’ contains :
A 1.
B 2.
then the two following functions f1 and f2 are strictly equivalent :
void f1()
{
data_file.load_globals("globals.dat");
}
void f2()
{
global double A,B;
A=1.; B=2.;
}
Mesher object#
It is also possible to acess some mesher objects inside zLanguage. This can be very usefull to make 3D extension, renumbering,…
UTILITY_MESH: an object representing a mesh (a .geof file).Methods :
load(string fmt): load the current mesh file name using format fmt.save(): save mesh using current file name and .geof format.print(): print some informations about the stored mesh.add(a): add an UTILITY_NODE, UTILITY_ELEMENT, UTILITY_NSET, UTILITY_ELSET or UTILITY_IPSET.int nb_node(): return number of nodesint nb_elem(): return number of elementsint nb_nset(): return number of node setsint nb_elset(): return number of element setsint nb_ipset(): return number of integration point setsUTILITY_NODE get_node(int n): return the nth nodeUTILITY_ELEMENT get_elem(int n): return the nth elementUTILITY_NSET get_nset(int n): return the nth node setUTILITY_ELSET get_elset(int n): return the nth element setUTILITY_IPSET get_ipset(int n): return the nth integration point set
Members :
string name(rw) : the mesh file name.
UTILITY_NODE: a mesh node object.Methods :
print(): print some informations about the current node.set_rank(int): set rank of node.set_id(int): set id of node.int nb_elem(): number of elements attached to node.UTILITY_ELEMENT get_elem(int n): return nth element attached to node.
Members :
int id(ro) : node id.int rank(ro) : node rank.VECTOR position(rw) : geometrical position of node.
UTILITY_ELEMENT: a mesh element object.Methods :
print(): print some informations about the current element.set_rank(int): set rank of element.set_id(int): set id of element.int nb_node(): number of nodes attached to element.UTILITY_NODE get_node(int n): return nth node attached to element.
Members :
int id(ro) : node id.int rank(ro) : node rank.string type(rw) : element type.
UTILITY_NSET: mesh node set object.Methods :
print(): print some informations about the current node set.suppress(UTILITY_NODE n): suppress node n from current node set.add(UTILITY_NODE n): add node n to current node set.reset(): reinitialize curent set (zero size).int nb_node(): return number of node in set.UTILITY_NODE get_node(int n): return nth node in set.
Members :
string name(rw) : node set name.
UTILITY_ELSET: mesh element set object.Methods :
print(): print some informations about the current element set.suppress(UTILITY_ELEMENT n): suppress element n from current node set.add(UTILITY_ELEMENT n): add element n to current node set.reset(): reinitialize curent set (zero size).int nb_elem(): return number of element in set.UTILITY_ELEMENT get_elem(int n): return nth element in set.
Members :
string name(rw) : node element name.
UTILITY_IPSET: mesh integration point set object.Methods :
print(): print some informations about the current set.suppress(n): suppress integration point from current set. n can be either an UTILITY_ELEMENT or an UTILITY_NODE.add(UTILITY_ELEMENT n, int i): add (element n, ip i) to current set.reset(): reinitialize curent set (zero size).int nb_elem(): return number of ip in set.UTILITY_ELEMENT get_elem(int n): return nth element in set.int get_ip(int n): return nth ip in set.
Members :
string name(rw) : set name.
MESHER_UNION: an object to make union between different meshes.Methods :
union(UTILITY_MESH m): make the union between all different meshes previously designated by methodadd(). The resulting mesh is stored into m.add(UTILITY_MESH m): add a mesh m for later union.reset(): reinitialize this object (forget all meshes previously designated by methodadd().
Members :
double tolerance(rw) : tolerance parameter (two nodes are considered to be the same node if the distance between them is lower than tolerance).string elset(rw) : elset name to be created with all elements added by this object.
MESHER_EXTENSION: an object to make a 3D extension on an utility_meshMethods :
apply(UTILITY_MESH m): make the extension using current parameters.
Members :
string elset(rw) : name of the elset to be extended.string elset2(rw) : name of the second optionnal elset to be extended (see zMesher manual for more informations).double progression(rw) : geometrical progression of the extension.double distance(rw) : distance of the extension along 3rd axis.int cuts(rw) : number of elements along 3rd axis.VECTOR direction(rw) : direction of the 3rd axis.
RENUMBERING: an object to renumber a mesh (to lower front or band width).Methods :
renumbering(UTILITY_MESH m): renumber given mesh m.
Members :
int type(rw) : front or band width optilisation (default=0, front optimization).int subdomain(rw) : equal 1 if domain renumbering (0 by default).double w1(rw) : parameter of the modified Sloan method.double w2(rw) : parameter of the modified Sloan method.