|
|
Keywords Explanations begin, { Begin a new block end, } End a block if, then, else, or, and,iter Conditionnals and Loops x,y,t,ib,iv,region,nx,ny Mesh variables log, exp, sqrt, abs, min, max sin, asin, tan, atan, cos, acos Mathematical Functions cosh, sinh, tanh I, Re, Im Complex Numbers complex Enter Complex Number Mode buildmesh, savemesh, loadmesh, adaptmesh Mesh related Functions build, save , load and mesh adaptation one, scal, dx, dy, dxx, dyy, dxy, dyx, convect Mathematical operators can be called wherever you want solve Enter Solver Mode pde, id, dnu laplace, div onbdy Solver Functions plot, plot3d graphical functions: plot isolines in 2D and Elevated Surface in 3D save, load, saveall Saving and Loading Functions Change the Wait State: if wait wait, nowait, changewait then the user must click in the window to continue precise, halt, include, evalfct, exec, user Miscellaneous Functions
Table 3.1: Gfem Keywords
buildmesh
Triangulate
(Macintosh only).
|
border
could be replaced by a line with polygon
|
f,g
are generic functions and the [...] denotes an optional addition.
The boundary is given in parametric form. The name of the parameter must
be t
and the two coordinates must be x
and y
. When the parameter
goes from t_min
to t_max
the boundary must be scanned so as to have W
on its left, meaning counter clockwise if it is the outer boundary and
clockwise if it is the boundary of a hole. Boundaries must be closed but
they may be entered by parts, each part with one instruction border
, and
have inner dividing curves; nb_t
points are put on the boundary with values
t = tmin + i * (tmax - tmin) / (nbt-1) where i
takes integer values
from 0
to nb_t-1
.nb_max
vertices at most. The size of the triangles is monitored by the size of
the nearest boundary edge. Therefore local refinement can be achieved by
adding inner artificial boundaries. ib
.ib=0
.if... then ... else
statement can be used with the compound
statement: begin...end
. This allows piecewise parametric definitions of
complicated or polygonal boundaries.ib
can be overwritten.For
example:
|
begin
and {
is the same and so is end
and }
.
Here one side of the unit square has ib=1. The 3 other sides have ib=2.polygon
causes a sequence of boundary points to be read
from the file file_name
which must be in the same directory as the
program. All points must be in sequential order and describing part of
the boundary counter clockwise; the last one should be equal to the first
one for a closed curve.
|
nb_t
is optional; it means that each segment will be divided into
nb_t
1+ equal segments (i.e. nb_t
points are added on each segments).
|
|
ì í î |
|
x,y
refers to the coordinates in the domain
ib
refers to the boundary identification number; it is zero inside
the domain.
nx
and ny
refer to the x-y components of the normal on the boundary
vertices; it is zero on all inner vertices.
region
refers to the domain identification number
which is itself based on an internal number, ngt, assigned to each
triangle by the triangulation constructor.
border
is called, an internal
number ngt
is incremented by 1. Then when the key word border
is
invoked the last edge of this portion of boundary assigns this number
to the triangle which lies on its left. Finally all triangles which are in
this subdomain are reassigned this number.ngt
. The number region is a piecewise linear continuous interpolation
at the vertices of ngt
. To be exact, the value of region at a
vertex (x0,y0) is the value of ngt at (x0,y0-10-6),
except if precise is set in which case region is equal to
ngt.f=x*y
really means that f(x,y)=x*yx
and y
. Here x
and y
refer
to the coordinates in the domain represented by the triangulation. g=sin(x*y); f=exp(g);
.x, y, iv, t
:
nx, ny, ib, region
.
|
one(x
y<0)+ for instance means 1
if x
y<0+ and 0
otherwise.
|
plot()
or plot3d()
is used ( here plot(f)
).dx()
and
dy()
. precise
is set, they are interpolated so the results is also
continuous piecewise linear (or discontinuous when precise is set).
Similarly the convection operator convect(f,u1,u2,dt)
defines a new
function which is approximately :=
is useful to create them, as in
|
f
is a function, a
is a scalar and pi
is a (predefined)
a scalar. a:=f(1,0)
Here the value of a
will be 1
because f(1,0)
means
f
at x=1
and y=0
.x,y,ib,region, nx, ny
.
x
is horizontal and y
is vertical.
0 inside W |
> 0 on ¶ W |
|
:=
tells the compiler not
to allocate a data array to this variable. Thus v=sin(a*pi*x);
generates an array for v
but no array is assigned to a
in the
statement a:=2
.f
has been defined earlier then it is possible to write a:=f(1.2,3.1);
Then a has the value of f
at x=1.2
and y=3.1
.
|
a
being a scalar, its value is appended to the
file a.dta.dx(f)
is the partial derivative of f
with respect to x
; the result
is piecewise constant when precise
is set and interpolated with
mass lumping as a the piecewise linear function when precise is not set.dx()
is a non local operator so statements like f=dx(f)
would give the wrong answer because the new value for f
is place before
the end of the use of the old one.convect
provides a tool for Lagrangian upwinding. By
g=convect(f,u,v,dt)
Gfem construct an approximation of
|
+ u |
|
+ v |
|
= limdt ® 0 |
|
|
+ u |
|
+ v |
|
-div(µ grad f) = g, |
dx(.)
and dy(.)
were use, the following scheme can be used:
|
convect
is
a nonlocal operator. The statement f = convect(f,u,v,dt) would give
an incorrect result because it modifies f
at some vertex where the
old value is still needed later. It is necessary to do
|
dx()
and a local operator
such as sin()
.dx(f)
at vertex q
we need f at all neighbors
of q
. Therefore evaluation of dx(2*f) require
the computation of 2*f
at all neighbor vertices of
q
before applying dx() ; but in which memory would the
result be stored? Therefore Gfem does not allow this
and forces the user to declare a function g =2*f
before evaluation of dx(g)
; Hence in
|
g
at all
vertices, then when the second equal signs forces the
evaluation of the expression on the right of h at
all vertices , everything is ready for it.
|
|
intt
returns a complex or real number, an integral with respect to x,y
int
returns a complex or real number, an integral on a curve
intt[f]
or intt(n1)[f]
or intt(n1,n2)[f]
or intt(n1,n2,n3)[f]
int(n1)[f]
or int(n1,n2)[f]
or int(n1,n2,n3)[f]
n1,n2,n3
are boundary or subdomain identification numbers and where
f
is an array function.
|
int
and intt
are global operators, so the values of the integrands are
needed at all vertices at once, therefore you can't put an expression
for the integrand, it must be a function.intt(n)[f]
.int(n)[g]
computes the integral of g
on all segments of the boundary (both ends
have id boundary number !=0) with one vertex boundary id number = n.
(Remember that you can control the boundary id number of the boundary ends
by the order in which you place the corresponding border
call or by an
extra argument in border
)
|
ib
's are boundary identification numbers, <expression>
is a generic
expression and g a generic function. id(u)
may be absent as in -dnu(u)=g
.
dnu(u)
represents the conormal of the PDE, i.e.
|
op
is one of the operator:
id()
dx()
dy()
laplace()
dxx()
dxy()
dyx()
dyy()
[*/]
means either a *
or a /
and similarly for ±.
Note that the expressions are necessarily AFTER the operator while in
practice they are between the 2 differentiations for laplace...dyy
.
Thus laplace(u)*(x+y) means
|
solve(u,v)
, see the section 2-Systems
.
It defines a PDE and its boundary conditions.
It will be solved by the Finite Element Method of degree 1 on triangles
and a Gauss factorization. solve
may be called again by
solve(u,-1)...;
then the matrix is not rebuilt nor factorized and
only a solution of the linear system is performed by an up and a down
sweep in the Gauss algorithm only. This saves a lot of CPU time whenever
possible. Several matrices can be stored and used simultaneously, in
which case the sequence is
|
i
is a scalar variable (not an array function).i=1
first
then i=2....
after they can be re-used in any order. One can also
re-use an old matrix with a new definition, as in
|
solve(u)
is equivalent to solve(u,1)
.
|
solve
is the same as for scalar PDEs; so
solve(u,v,1)
is ok for instance. The
equations above can be in any orders; several onbdy()
can be used in
case of multiple boundaries... onbdy
is the same as in the scalar case; either Dirichlet
or mixed-Neumann, but the later can have more than one id()
and
only one dnu()
.u,v
are allowed for mixed Neumann
only, such as id(u)+id(v)+dnu(v)=1. (As said later this is an
equation for v
).solve(u,v,i) begin .. end;
when i>0
the linear system is built
factorized and solved. When i<0
, it is only solved; this is useful when
only the right hand side in the boundary conditions or in the equations
have change. When i<0
, i
refers to a linear system i>0
of
SAME TYPE, so that scalar systems and 2-systems have their own count.saveall('filename',u,v)
works also.pde()
is the same as for the scalar case. Deciding which
equation is an equation for u
or v
is important in the resolution of the
linear system (which is done by Gauss block factorization) because some
block may not be definite matrices if the equations are not well chosen.
onbdy(...) ... dnu(u) ... = ...;
is a
boundary condition associated to u
, even if it contains id(v)
. onbdy(...) u...=...;
is also
associated with u
(the syntax forbids any v
-operator in this case).u
is the array function in a pde(u)
then what follows is the
PDE associated to u
.
|
1.0e12
and c
is multiplied by the same;
for Neumann a=0
. Thus Neumann condition is present even when there
is Dirichlet but the later overrules the former because of the large
penalty number. Functions a,b,c
are piecewise linear continuous, or
discontinuous if precise
is set.precise
can guarantee that
the integral on the edge near the corner on the Neumann side is properly taken
into account because then the corner has a Dirichlet value and a Neumann value
by the fact that functions are discontinuous.
|
<unknown function list>
and
<test function list>
are one or two function names separated by a comma.
<int>
is a positive or negative integer
<expression>
is an expression returning a real or
complex number
<< >>
whenever the entities
can be omitted.
Examples
|
varsolve
takes longer than solve
because derivatives like dx(u)
are evaluated 9 times
instead of once.plot(u)
will display u
.u
on
disk. If u
is a scalar variable then the (single) value of u
is
appended to the file (this is useful for time dependent problems or any
problem with iteration loop.).f
it is:
|
ns
is the number of vertices)f
is a constant, its single value is appended to the end of the file;
this is useful for time dependent problems or any problem with iteration
loop.precise
is set still the function stored by save
is interpolated on the vertices as the P1 continuous function given by mass lumping (see above).nt
= number of triangles):
|
me[][]
and
numbers the vertices starting from number 1 instead of 0 as in the
C-standard. Thus in C-programs one must use me[][]-1
..amdba
and .am_fmt
.
You can do the same if your format is not ours.
|
|
|
solve(,)
except that the
first parameter is the file name. The other parameters are used only
to indicate to the interpreter which is/are the unknown function.
|
|
|
|
N=2
. 0
are changed to value 1e-10
)
|
iter
with the adaptation
features of Gfem.complex
: to tell Gfem that complex number will be used.
When it is used it must be located at the beginning of the program
before any function declarations, otherwise the results will be incorrect.
It can appear more than once in the program but only the first occurrence
counts.complex
in the program implies all
computation will be done in real, even if I
is used. a:=scal(f,g);
doesa = | ó õ |
|
f(x,y) |
|
(x,y) dxdy |
plot
command, Gfem stops to let the user see
the result. By using nowait
no stop will be made;
plot
is displayed. It can
be visualized in several fashion, one of which being a one dimensional
plot along any segment defined by the mouse. Selection of this menu
brings causes Gfem to waits for the user input which should be the line
segment on which the function is to be displayed. Thus one should
press the mouse at the beginning point then drag the mouse and release
the button at the final point f
is
the last function displayed in the plot window. convect
and/or discontinuous nonlinear terms.exec('prog_name')
will launch the application prog_name
. It is
useful to execute an external PDE solver for instance especially under
Unix. It is not implemented for Macintosh because there is no simple way
to return to MacGfem after progname has ended.
The same can be achieved manually by a suitable combination of saveall
, wait
and
load
and simultaneous execution under multifinder.user(what,f)
calls the C++ function in a j-loop:
|
creal
is a scalar (float
) or a complex number if complex
has
been set; nquad=3*nt
if precise
is set and ns
otherwise. what
is intended for users who need several such functions.
Then all can be put in the super function user
and selection is by
an if statement on what
.gfemuser
access to all global variables are of course possible:
the triangulation (ns,nt, me, q, ng,ngt, area...
) ... refer to the file
fem.C
for more details.fem.C
; if you
wish to put your own you must compile and link it. Under Unix, it is
easy. Under the Macintosh system, either you use freefem, which is
Gfem's kernel, or you must ask us a library version of MacGfem.instruction
.The syntax analysis is
driven by the syntax rules because the language is LL(1). Thus there
is C-function for each non-terminal.
x * y
would generate a tree with root *
and two branches x
and y
. Trees are C-struct with four pointers
for the 4 branches (here two would point to NULL) and a symbol for the
operator. The C-function which builds trees is called plante
.
In the end the program is transformed into a full tree and
to execute the program there is only one thing to do: evaluate
the operator at the root of the tree.
eval
. It
looks at the root symbol and perform the corresponding operation. Here
it would do: return "value pointed by L1"*"value pointed by L2" if L1
and L2 where the addresses of the two branches.
x
is required, this is also done
by a tree which has the operator "oldvar" as root. The trickiest of all is
the compound instruction {...;....};
.
Here {
is considered as an operator with one branch on the current
instruction and one branch on the next one. Similarly for the
if...then... else
instruction.installe
. As there will be a
new Symbol, update the list of symbols (an enum structure). Add the
C-functions for the syntax analysis according to the diagrams. Modify
eval by adding to the switch
the new case.
|