diff --git a/.gitignore b/.gitignore index 9dd8f45c59a3fe637ce46978b967f1350f483877..cb98282bfb904d03ac706cc8740ee1ad922c8851 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,10 @@ GTAGS /doc/*.png /doc/*.gnu /doc/filename.txt +/doc/*pvd +/doc/*.geo +/doc/*.py +/doc/*.pvtu +/doc/lisp/.fltk/ +/doc/*.msh +/doc/*.vtu diff --git a/doc/userdoc.org b/doc/userdoc.org index 4b0123435640a6b9a430175a61f6356ad3f26249..db900f9b000b77a91b86e41899913e0cbcef3e36 100644 --- a/doc/userdoc.org +++ b/doc/userdoc.org @@ -30,15 +30,15 @@ #+LATEX_HEADER_EXTRA: \usepackage{mdframed} #+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{tabular}{\rowcolors[]{2}{orange!5}{orange!10}} -#+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{minted}{\begin{mdframed}[linecolor=blue,backgroundcolor=blue!5]} +#+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{minted}{\begin{mdframed}[linecolor=blue,backgroundcolor=blue!10]} #+LATEX_HEADER_EXTRA: \AfterEndEnvironment{minted}{\end{mdframed}} -#+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{verbatim}{\begin{mdframed}[linecolor=gray,backgroundcolor=green!5]} +#+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{verbatim}{\begin{mdframed}[linecolor=gray,backgroundcolor=gray!5]} #+LATEX_HEADER_EXTRA: \AfterEndEnvironment{verbatim}{\end{mdframed}} #+LATEX_HEADER_EXTRA: \newtheorem{note}{Note} -#+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{note}{\begin{mdframed}[linecolor=orange,backgroundcolor=orange!5]} +#+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{note}{\begin{mdframed}[linecolor=green,backgroundcolor=green!10]} #+LATEX_HEADER_EXTRA: \AfterEndEnvironment{note}{\end{mdframed}} #+LATEX_HEADER_EXTRA: \newtheorem{warning}{Warning} -#+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{warning}{\begin{mdframed}[linecolor=red,backgroundcolor=red!5]} +#+LATEX_HEADER_EXTRA: \BeforeBeginEnvironment{warning}{\begin{mdframed}[linecolor=red,backgroundcolor=red!10]} #+LATEX_HEADER_EXTRA: \AfterEndEnvironment{warning}{\end{mdframed}} #+LATEX_HEADER_EXTRA: \usepackage{mathpazo} @@ -77,7 +77,7 @@ mesh nodes according to a user-defined vector field $T: \mathbb{R}^2 let M:R^2 -> R^2x2, x -> [[cos(theta(x)), -sin(theta(x))], [sin(theta(x)), cos(theta(x))]]; let T: R^2 -> R^2, x -> x + M(x)*x; - let m:mesh, m = cartesian2dMesh([-1,-1], [1,1], (20,20)); + let m:mesh, m = cartesianMesh([-1,-1], [1,1], (20,20)); m = transform(m, T); @@ -150,7 +150,7 @@ already be discussed. section [[basic-types]] and [[high-level-types]] for details. - Also, there are two types of functions: *user-defined* functions and *builtin* functions. In this example, ~theta~, ~M~ and ~T~ are user-defined - functions. All other functions (~cos~, ~cartesian2dMesh~,...) are + functions. All other functions (~cos~, ~cartesianMesh~,...) are builtin functions and are generally defined when importing a module. These functions behave similarly, one should refer to [[functions]] for details. @@ -1632,9 +1632,9 @@ illustrate this, let us consider the following example. #+BEGIN_SRC pugs :exports both import mesh; - let m1:mesh, m1 = cartesian2dMesh(0, [1,1], (10,10)); + let m1:mesh, m1 = cartesianMesh(0, [1,1], (10,10)); let m2:mesh, m2 = m1; - let m3:mesh, m3 = cartesian2dMesh(0, [1,1], (10,10)); + let m3:mesh, m3 = cartesianMesh(0, [1,1], (10,10)); m3 = m1; #+END_SRC @@ -2490,7 +2490,7 @@ Running this example produces no output But a file is created (in the execution directory), with the name ~"filename.txt"~. Its content is #+NAME: cat-filename-txt -#+BEGIN_SRC bash :exports results :results output +#+BEGIN_SRC shell :exports results :results output cat filename.txt #+END_SRC #+RESULTS: cat-filename.txt @@ -2558,7 +2558,453 @@ rounding or truncation functions are ~ceil~, ~floor~, ~round~ and ~trunc~. See their ~C++~ man pages for details. #+END_note +#+BEGIN_note +Let us comment the use of the ~pow~ function. Actually one can wonder +why we did not use a syntax like ~x^y~? The reason is that if +mathematically ${x^y}^z = x^{(y^z)}$, many software treat it (by mistake) +as ${(x^y)}^z$. Thus, using the ~pow~ function avoids any confusion. +#+END_note + +*** The ~mesh~ module + +This is an important module. It provide mesh utilities tools. +#+NAME: get-module-info-mesh +#+BEGIN_SRC pugs :exports both :results output + cout << getModuleInfo("mesh") << "\n"; +#+END_SRC +#+RESULTS: get-module-info-mesh + +**** ~mesh~ provided types + +***** ~boundary~ + +The ~boundary~ type is a boundary descriptor: it refers to a boundary of +a ~mesh~ that is either designated by an integer or by a ~string~. + +A ~boundary~ can be used refer to an interface, it can designate a set +of nodes, edges or faces. The ~boundary~ (descriptor) itself is not +related to any ~mesh~, thus the nature of the ~boundary~ is precised when +it is used with a particular ~mesh~. + +***** ~zone~ + +Following the same idea, a ~zone~ is a descriptor of set of cells. It +can be either defined by an integer or by a ~string~. Its meaning is +precised when it is associated with a ~mesh~. + +***** ~mesh~ + +The type ~mesh~ is an *abstract* type that is used to store meshes. A +variable of that type can refer for instance unstructured meshes of +dimension 1, 2 or 3. + +The following binary operator is provided. +| ~ostream <<~ allowed expression type | +|------------------------------------| +| ~mesh~ | + +It enables to write mesh information to an ~ostream~, here is a simple +example. + +#+NAME: ostream-mesh-example +#+BEGIN_SRC pugs :exports both :results output + import mesh; + + let m:mesh, m = cartesianMesh(0,[1,1,2], (2,3,2)); + cout << m << "\n"; +#+END_SRC +Running this script generates the following output. +#+RESULTS: ostream-mesh-example +The information produced concerns +- the dimension of the connectivity, +- the number of cells and their references, +- the number of faces and their references, +- the number of edges and their references, +- and the number of nodes and their references. + +**** ~mesh~ provided functions + +***** ~boundaryName: string -> boundary~ + +Sets a boundary descriptor to a boundary name +#+BEGIN_SRC pugs :exports both :results none + import mesh; + + let b:boundary, b = boundaryName("boundary_name"); +#+END_SRC + +***** ~boundaryTag: Z -> boundary~ + +Creates a boundary descriptor to a boundary reference +#+BEGIN_SRC pugs :exports both :results none + import mesh; + + let b:boundary, b = boundaryTag(12); +#+END_SRC + +***** ~zoneName: string -> zone~ + +Creates a zone descriptor from a ~string~ name +#+BEGIN_SRC pugs :exports both :results none + import mesh; + + let z:zone, z = zoneName("zone_name"); +#+END_SRC + +***** ~zoneTag: Z -> zone~ + +Associates a zone descriptor from zone tag +#+BEGIN_SRC pugs :exports both :results none + import mesh; + + let z:zone, z = zoneTag(5); +#+END_SRC + +***** ~cartesianMesh: Rˆd*Rˆd*(N) -> mesh~ (with $d\in\{1, 2, 3\}$) + +Creates a cartesian mesh of dimension $d\in\{1, 2, 3\}$. The produced +cartesian grid is aligned with the axis and made of identical cells. + +The two first arguments are two opposite corners of the box (or +segment in 1d) and the list of natural integers (type ~(N)~) sets the +number of *cells* in each direction. Thus size of the list of ~N~ is $d$. + +For instance one can write: +#+BEGIN_SRC pugs :exports both :results none + import mesh; + + let m1d:mesh, m1d = cartesianMesh([0], [1], 10); + let m2d:mesh, m2d = cartesianMesh([0,0], [1,1], (3,6)); + let m3d:mesh, m3d = cartesianMesh([-1,-1,-1], [1,1,1], (3,2,4)); +#+END_SRC +- The ~m1d~ variable contains a uniform grid of $]0,1[$ made of 10 cells. +- The ~m2d~ variable refers to a uniform grid of $]0,1[^2$, made of 3 + cells in the $x$ direction, and of 6 cells along the $y$ axis. +- The ~m3d~ variable designates a mesh of $]-1,1[^3$ made of $3\times2\times4$ + cells. + + +***** ~readGmsh: string -> mesh~ + +Reads a ~mesh~ from a file. +#+BEGIN_warning +The file must conform to the mesh format ~msh2~. +#+END_warning + +#+BEGIN_SRC shell :exports results :results none +cat << EOF > hybrid-2d.geo +//+ +Point(1) = {0, 0, 0, 1.0}; +//+ +Point(2) = {1, 0, 0, 1.0}; +//+ +Point(3) = {1, 1, 0, 1.0}; +//+ +Point(4) = {0, 1, 0, 1.0}; +//+ +Point(5) = {2, 0, 0, 1.0}; +//+ +Point(6) = {2, 1, 0, 1.0}; +//+ +Line(1) = {4, 1}; +//+ +Line(2) = {2, 3}; +//+ +Line(3) = {5, 6}; +//+ +Line(4) = {3, 4}; +//+ +Line(5) = {6, 3}; +//+ +Line(6) = {1, 2}; +//+ +Line(7) = {2, 5}; +//+ +Curve Loop(1) = {1, 6, 2, 4}; +//+ +Surface(1) = {1}; +//+ +Curve Loop(2) = {-2, 7, 3, 5}; +//+ +Surface(2) = {2}; +//+ +Characteristic Length {4, 3, 6, 5, 2, 1} = 0.3; +//+ +Recombine Surface {1}; +//+ +Physical Curve("XMIN") = {1}; +//+ +Physical Curve("XMAX") = {3}; +//+ +Physical Curve("YMAX") = {4, 5}; +//+ +Physical Curve("YMIN") = {6, 7}; +//+ +Physical Curve("INTERFACE") = {2}; +//+ +Physical Surface("LEFT") = {1}; +//+ +Physical Surface("RIGHT") = {2}; +//+ +Physical Point("XMINYMIN") = {1}; +//+ +Physical Point("XMINYMAX") = {4}; +//+ +Physical Point("XMAXYMIN") = {5}; +//+ +Physical Point("XMAXYMAX") = {6}; +#+END_SRC + +#+BEGIN_SRC shell :exports results :results none +gmsh -2 hybrid-2d.geo -format msh2 +#+END_SRC + +#+BEGIN_SRC pugs :exports both :results none + import mesh; + import writer; + + let m:mesh, m = readGmsh("hybrid-2d.msh"); + write_mesh(gnuplot_writer("hybrid-2d", 0), m); +#+END_SRC + +The ~mesh~ is represented on Figure [[fig:gmsh-hybrid-2d]]. + +#+NAME: gmsh-hybrid-2d-img +#+BEGIN_SRC gnuplot :exports results :file (substitute-in-file-name "${PUGS_SOURCE_DIR}/doc/gmsh-hybrid-2d.png") + reset + unset grid + unset border + unset key + unset xtics + unset ytics + set terminal png truecolor enhanced size 960,480 + plot '<(sed "" $PUGS_SOURCE_DIR/doc/hybrid-2d.0000.gnu)' w l +#+END_SRC + +#+CAPTION: The mesh that was read from the file ~hydrid-2d.msh~ and then saved to the ~gnuplot~ format +#+NAME: fig:gmsh-hybrid-2d +#+ATTR_LATEX: :width 0.38\textwidth +#+ATTR_HTML: :width 300px; +#+RESULTS: gmsh-hybrid-2d-img + +***** ~diamondDual: mesh -> mesh~ + +This function creates the diamond dual ~mesh~ of a primal ~mesh~. +#+BEGIN_SRC pugs :exports both :results none + import mesh; + import writer; + + let primal_mesh:mesh, primal_mesh = readGmsh("hybrid-2d.msh"); + let dual_mesh:mesh, dual_mesh = diamondDual(primal_mesh); + write_mesh(gnuplot_writer("diamond", 0), dual_mesh); +#+END_SRC + +The diamond dual mesh is defined by joining the nodes of the faces to +the center of the adjacent cells of the primal mesh. + +The ~mesh~ is represented on Figure [[fig:gmsh-hybrid-2d]]. + +#+NAME: diamond-dual-img +#+BEGIN_SRC gnuplot :exports results :file (substitute-in-file-name "${PUGS_SOURCE_DIR}/doc/diamond-dual.png") + reset + unset grid + unset border + unset key + unset xtics + unset ytics + set terminal png truecolor enhanced size 960,480 + plot '<(sed "" $PUGS_SOURCE_DIR/doc/hybrid-2d.0000.gnu)' lt rgb "green" w l, '<(sed "" $PUGS_SOURCE_DIR/doc/diamond.0000.gnu)' lt rgb "black" w l +#+END_SRC + +#+CAPTION: The primal mesh in green and the diamond dual mesh in black +#+NAME: fig:diamond-dual +#+ATTR_LATEX: :width 0.38\textwidth +#+ATTR_HTML: :width 300px; +#+RESULTS: diamond-dual-img + +#+BEGIN_note +The mesh storage mechanisms in ~pugs~ is such that the diamond dual mesh +is built only once. This means that is one writes for instance +#+BEGIN_SRC pugs :exports both :results none + import mesh; + + let primal_mesh:mesh, primal_mesh = readGmsh("hybrid-2d.msh"); + let dual_mesh_1:mesh, dual_mesh_1 = diamondDual(primal_mesh); + let dual_mesh_2:mesh, dual_mesh_2 = diamondDual(primal_mesh); +#+END_SRC +then the meshes ~dual_mesh_1~ and ~dual_mesh_2~ will refer to the same +~mesh~ in memory. +#+END_note + +#+BEGIN_warning +The diamond dual mesh construction is not yet implemented in parallel +#+END_warning + +***** ~medianDual: mesh -> mesh~ + +This function creates the median dual ~mesh~ of a primal ~mesh~. +#+BEGIN_SRC pugs :exports both :results none + import mesh; + import writer; + + let primal_mesh:mesh, primal_mesh = readGmsh("hybrid-2d.msh"); + let dual_mesh:mesh, dual_mesh = medianDual(primal_mesh); + write_mesh(gnuplot_writer("median", 0), dual_mesh); +#+END_SRC + +The median dual mesh is defined by joining the centers of the faces to +the centers of the adjacent cells of the primal mesh. + +The ~mesh~ is represented on Figure [[fig:gmsh-hybrid-2d]]. + +#+NAME: median-dual-img +#+BEGIN_SRC gnuplot :exports results :file (substitute-in-file-name "${PUGS_SOURCE_DIR}/doc/median-dual.png") + reset + unset grid + unset border + unset key + unset xtics + unset ytics + set terminal png truecolor enhanced size 960,480 + plot '<(sed "" $PUGS_SOURCE_DIR/doc/hybrid-2d.0000.gnu)' lt rgb "green" w l, '<(sed "" $PUGS_SOURCE_DIR/doc/median.0000.gnu)' lt rgb "black" w l +#+END_SRC + +#+CAPTION: The primal mesh in green and the median dual mesh in black +#+NAME: fig:median-dual +#+ATTR_LATEX: :width 0.38\textwidth +#+ATTR_HTML: :width 300px; +#+RESULTS: median-dual-img + +#+BEGIN_note +In ~pugs~, the storage mechanisms of median dual meshes follows the same +rules as the diamond dual meshes. As long as the primary mesh lives +and as long as the median dual mesh is referred, it is kept in memory, +thus constructed only once. +#+END_note + +#+BEGIN_warning +The median dual mesh construction is not yet implemented in 3d and not +available in parallel +#+END_warning + +***** ~transform: mesh*function -> mesh~ + +This function allows to compute a new mesh as the transformation a +given mesh by displacing its nodes through a user defined function. + +For a mesh of dimension $d$, the mesh must be a function $\mathbb{R}^d +\to\mathbb{R}^d$. + +#+BEGIN_SRC pugs :exports both :results none +import mesh; +import math; +import writer; + +let m0:mesh, m0 = cartesianMesh([0,0], [1,1], (10,10)); + +let pi_over_3: R, pi_over_3 = acos(-1)/3; +let t: R^2 -> R^2, x -> [(0.2+0.8*x[0])*cos(pi_over_3*x[1]), (0.2+0.8*x[0])*sin(pi_over_3*x[1])]; + +let m1: mesh, m1 = transform(m0, t); +write_mesh(gnuplot_writer("transformed", 0), m1); +#+END_SRC + +#+BEGIN_note +One should keep in mind that the mesh produced the ~transform~ function +*shares* the same connectivity than the given mesh. This means that in +~pugs~ internals, there is only one connectivity object. +#+END_note + +The result of the previous script is given on Figure [[fig:transformed]]. + +#+NAME: transformed-img +#+BEGIN_SRC gnuplot :exports results :file (substitute-in-file-name "${PUGS_SOURCE_DIR}/doc/transformed.png") + reset + unset grid + unset border + unset key + unset xtics + unset ytics + set square + set terminal png truecolor enhanced size 640,640 + plot '<(sed "" $PUGS_SOURCE_DIR/doc/transformed.0000.gnu)' w l +#+END_SRC + +#+CAPTION: The transformed unit square +#+NAME: fig:transformed +#+ATTR_LATEX: :width 0.38\textwidth +#+ATTR_HTML: :width 300px; +#+RESULTS: transformed-img + +***** ~relax: mesh*mesh*R -> mesh~ + +This function is a simple utility that computes a ~mesh~ as the /mean/ of +two other mesh that share the same connectivity. The connectivity must +be the *same in memory*, this means that constructing two identical +meshes with /equivalent/ connectivity is not allowed. + +Thus for instance, the following code +#+NAME: relax-with-similar-connecticities +#+BEGIN_SRC pugs-error :exports both :results output + import mesh; + let m1:mesh, m1 = cartesianMesh(0, [1,1], (10,10)); + let m2:mesh, m2 = cartesianMesh(0, [1,1], (10,10)); + let m3:mesh, m3 = relax(m1,m2,0.3); +#+END_SRC +produces the runtime error +#+results: relax-with-similar-connecticities + +A proper use is +#+BEGIN_SRC pugs :exports both :results none +import mesh; +import math; +import writer; + +let m0:mesh, m0 = cartesianMesh([0,0], [1,1], (10,10)); +write_mesh(gnuplot_writer("relax_example_m0", 0), m0); + +let t: R^2 -> R^2, x -> [x[0]+0.25*x[1]*x[1], x[1]+0.3*sin(x[0])]; +let m1: mesh, m1 = transform(m0, t); +write_mesh(gnuplot_writer("relax_example_m1", 0), m1); + +let m2: mesh, m2 = relax(m0, m1, 0.3); +write_mesh(gnuplot_writer("relax_example_m2", 0), m2); +#+END_SRC + +In this example, the relaxation parameter is set to $\theta=0.3$, this +means that the coordinates of any vertex of the relaxed mesh +$\mathcal{M}_2$, are given by +\begin{equation*} +\forall r\in\mathcal{R},\quad\mathbf{x}_r^{\mathcal{M}_2} = (1-\theta) \mathbf{x}_r^{\mathcal{M}_0} + \theta \mathbf{x}_r^{\mathcal{M}_1} +\end{equation*} + +The different meshes produced in this example are displayed on Figure [[fig:relax]]. + +#+NAME: relax-img +#+BEGIN_SRC gnuplot :exports results :file (substitute-in-file-name "${PUGS_SOURCE_DIR}/doc/relax.png") + reset + unset grid + unset border + unset key + unset xtics + unset ytics + set square + set terminal png truecolor enhanced size 640,640 + plot '<(sed "" $PUGS_SOURCE_DIR/doc/relax_example_m0.0000.gnu)' lt rgb "green" w l, '<(sed "" $PUGS_SOURCE_DIR/doc/relax_example_m1.0000.gnu)' lt rgb "blue" w l, '<(sed "" $PUGS_SOURCE_DIR/doc/relax_example_m2.0000.gnu)' lt rgb "black" w l +#+END_SRC + +#+CAPTION: Example of meshes relaxation. The relaxed mesh $\mathcal{M}_2$ (black) and the original meshes in green ($\mathcal{M}_0$) and blue ($\mathcal{M}_1$). +#+NAME: fig:relax +#+ATTR_LATEX: :width 0.38\textwidth +#+ATTR_HTML: :width 300px; +#+RESULTS: relax-img + +This function is mainly useful to reduce the displacement of nodes +when using the ~randomizeMesh~ functions (see section [[scheme]]). + +**** The ~scheme~ module<<scheme>> + [fn:pugs-def] ~pugs~: Parallel Unstructured Grid Solvers [fn:MPI-def] ~MPI~: Message Passing Interface -[fn:DSL-def] ~DSL~: Domain Specific Language +[fn:DSL-def] ~DSL~: Domain Specific Language~