diff --git a/doc/userdoc.org b/doc/userdoc.org
index e98a1115106575220569112fb80d52dc15394b31..5d189d77069459c6727645c9f08cd465da01c618 100644
--- a/doc/userdoc.org
+++ b/doc/userdoc.org
@@ -2309,7 +2309,228 @@ Running this example produces
 
 Builtin functions are defined when modules are imported, see [[modules]].
 
-** TODO modules<<modules>>
+** Modules<<modules>>
+
+Modules are sets of *builtin functions* and *high-level types* that are
+not provided by default by ~pugs~. To load a module, one has to use an
+~import~ instruction in the preamble of the script.
+
+For instance to load the ~math~ module which contains builtin
+mathematical functions, one writes in the preamble of the script
+#+BEGIN_SRC pugs :exports source
+  import math;
+#+END_SRC
+
+#+BEGIN_warning
+A work in progress
+- At the time of writing this documentation, one should note that
+  module inter-dependencies is still not implemented.
+- Also, (and especially with regard to the ~scheme~ module), module
+  contents are likely to change and to be reorganized.
+- Finally it is almost sure that modules will be equipped with a
+  /namespace/-like functionality to avoid conflicts. This actually
+  should make the scripts cleaner since, the naming of functions would
+  be more natural.
+#+END_warning
+
+One can access to the list of available modules inside the language.
+#+NAME: get-available-modules
+#+BEGIN_SRC pugs :exports both :results output
+  cout << getAvailableModules() << "\n";
+#+END_SRC
+The output lists all available modules
+#+RESULTS: get-available-modules
+Let us comment a bit this output. One notices that there are two kind
+of modules. Modules that are automatically imported (tagged with a ~*~)
+and the other ones.
+
+In this section we will not describe exhaustively the whole module
+contents but will give the basic information that should allow the
+user to find his way. To do so, it is important to examine carefully
+the content of the ~core~ module, since it contains some helper
+functions.
+
+*** The ~core~ module
+
+As already said, the ~core~ module cannot be imported manually since it
+is imported automatically.
+
+**** ~core~ provided types
+
+***** ~ostream~
+
+The ~core~ module provides an important type: ~ostream~. This type has
+already been encountered in this documentation. This is the type of
+some specific predefined objects: ~cout~, ~cerr~ and ~clog~. These objects
+are very similar to their ~C++~ counterparts, respectively ~std::cout~,
+~std::cerr~ and ~std::clog~.
+
+Objects of type ~ostream~ can be used as the left operand for the binary
+operator ~<<~ for basic types and their associated tuples.
+| ~ostream <<~ allowed expression type |
+|------------------------------------|
+| ~B~                                  |
+| ~N~                                  |
+| ~Z~                                  |
+| ~R~                                  |
+| ~R^1~                                |
+| ~R^2~                                |
+| ~R^3~                                |
+| ~R^1x1~                              |
+| ~R^2x2~                              |
+| ~R^3x3~                              |
+| ~string~                             |
+
+As one should have noticed, when the left operand of the binary
+operator ~<<~ is an ~ostream~, the result of the operation is also an
+~ostream~, which allows to chain output.
+
+One can overload the ~ostream <<~ construction for high-level types.
+
+Other variables of the type ~ostream~ can be created (in order to write
+to files for instance) as one should see below.
+
+**** ~core~ provided functions
+
+***** ~getAvailableModules: void -> string~
+
+This function that is used in the preamble of this section is a
+function that returns a ~string~ that contains the list of modules that
+are available in the current version of pugs.
+
+***** ~getModuleInfo: string -> string~
+
+This is a *very* helpful function. It lists *all* the available *builtin
+functions* of a module and *all* the provided *types*. It is important to
+remark that the name of the module is given as a ~string~ and not as is.
+
+#+BEGIN_note
+This function provides a very simple documentation of the
+modules. Hopefully in future developments it would be really useful to
+obtain a complete documentation of each function to offer a precise
+online documentation.
+#+END_note
+
+In the following of the documentation we will run this function on all
+modules.
+#+NAME: get-module-info-core
+#+BEGIN_SRC pugs :exports both :results output
+  cout << getModuleInfo("core") << "\n";
+#+END_SRC
+For the ~core~ module, it gives
+#+RESULTS: get-module-info-core
+This output is quite rustic, but it contains the main information: the
+name of the function and its input and output sets.
+
+#+BEGIN_warning
+Observe that this function does not provide the list of operators that
+are defined in the module (eventually associated to the defined
+types).
+#+END_warning
+
+***** ~getPugsBuildInfo: void -> string~
+
+Sets the building information of the executable into a ~string~.
+#+NAME: get-pugs-build-info
+#+BEGIN_SRC pugs :exports both :results output
+  cout << getPugsBuildInfo() << "\n";
+#+END_SRC
+It gives for instance
+#+RESULTS: get-pugs-build-info
+
+***** ~getPugsVersion: void -> string~
+
+Sets the ~pugs~ version of the executable into a ~string~.
+#+NAME: get-pugs-version
+#+BEGIN_SRC pugs :exports both :results output
+  cout << getPugsVersion() << "\n";
+#+END_SRC
+The output contains also ~git~ information
+#+RESULTS: get-pugs-version
+
+*****  ~resetRandomSeed: void -> void~
+
+At the start of ~pugs~, a *common* random seed is defined for all ~MPI~
+processes. The seed is written automatically written in the preamble
+of the listing (in the documentation the ~--no-preamble~ option is used
+this is why it is not displayed in examples).
+
+The ~resetRandomSeed~ creates a *new shared* random and displays its value.
+#+NAME: reset-random-seed
+#+BEGIN_SRC pugs :exports both :results output
+  resetRandomSeed();
+#+END_SRC
+The output is
+#+RESULTS: reset-random-seed
+
+***** ~setRandomSeed: Z -> void~
+
+In order to reproduce exactly the same results of a calculation, it
+can be interesting to set the random seed to some given value.
+#+NAME: set-random-seed
+#+BEGIN_SRC pugs :exports both :results output
+  setRandomSeed(123456789);
+#+END_SRC
+Running this example gives
+#+RESULTS: set-random-seed
+
+***** ~ofstream: string -> ostream~
+
+This function is used to create an ~ostream~ that actually write to the
+file which name is given by the ~string~ argument. One should notice
+that the file is *created* at the function call. If a file with the same
+name existed, it is *erased*.
+#+NAME: ofstream-example
+#+BEGIN_SRC pugs :exports both :results output
+  let fout:ostream, fout = ofstream("filename.txt");
+  fout << [1,2] << " is a vector of R^2\n";
+#+END_SRC
+Running this example produces no output
+#+RESULTS: ofstream-example
+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
+  cat filename.txt
+#+END_SRC
+#+RESULTS: cat-filename.txt
+Following ~C++~, the file is closed when the variable is destroyed.
+
+*** The ~math~ module
+
+The ~math~ module is a small utility module that provides a set of
+standard mathematical functions.
+
+#+NAME: get-module-info-math
+#+BEGIN_SRC pugs :exports both :results output
+  cout << getModuleInfo("math") << "\n";
+#+END_SRC
+For the ~math~ module, it gives
+#+RESULTS: get-module-info-math
+
+There is not much to say. One can see that this module does not
+provide new types of data. All the classical mathematical functions
+follow their ~C++~ counterparts. One can see that there are integer
+versions (type ~Z~) of ~abs~, ~min~ and ~max~ functions.
+
+The ~dot~ function family provides the dot product for vectors of
+$\mathbb{R}^1$, $\mathbb{R}^2$ and $\mathbb{R}^3$.
+#+NAME: dot-examples
+#+BEGIN_SRC pugs :exports both :results output
+  import math;
+  cout << "([1],[2])         = " << dot([1],[2]) << "\n";
+  cout << "([1,2],[3,4])     = " << dot([1,2],[3,4]) << "\n";
+  cout << "([1,2,3],[4,5,6]) = " << dot([1,2,3],[4,5,6]) << "\n";
+#+END_SRC
+The output is
+#+RESULTS: dot-examples
+
+#+BEGIN_note
+Observe that the use of a proper rounding or truncation function is
+the right way to convert a real value to an integer one. Available
+rounding or truncation functions are ~ceil~, ~floor~, ~round~ and ~trunc~. See
+their ~C++~ man pages for details.
+#+END_note
 
 
 [fn:pugs-def] ~pugs~: Parallel Unstructured Grid Solvers