]> SALOME platform Git repositories - tools/configuration.git/commitdiff
Salome HOME
ParaView-5.8.0 build options and patches
authorrnv <rnv@opencascade.com>
Wed, 1 Apr 2020 10:39:31 +0000 (13:39 +0300)
committerrnv <rnv@opencascade.com>
Tue, 14 Apr 2020 13:50:22 +0000 (16:50 +0300)
config/build_options/occ/options_compilation_salome_master.txt
config/patches/paraview.0001-LATA-reader.patch [new file with mode: 0644]
config/patches/paraview.0002-vtkUnstructuredGridRelevantPointsFilter-fix-for-poly.patch [new file with mode: 0644]
config/patches/paraview.0003-ParaViewClient.patch [new file with mode: 0644]
config/patches/paraview.0004-ParaView_hdf5.patch [new file with mode: 0644]
config/patches/paraview.0005-ParaView_find_cgns.patch [new file with mode: 0644]
config/patches/paraview.0006-ParaView_find_libxml2.patch [new file with mode: 0644]
config/patches/paraview.0007-ParaView_find_freetype.patch [new file with mode: 0644]
config/patches/paraview.001_against_multiple_py_sv_thr.patch [deleted file]
config/patches/paraview.002_statestorage_bug.patch [deleted file]
config/patches/paraview.004_forwarding.patch [deleted file]

index 2e53e1a902ca1de236624150a07face3fa527983..f0378cd94bf4e75813b81b07800b9d2c271ec73f 100644 (file)
@@ -152,7 +152,7 @@ CAS
 > cmake -DINSTALL_DIR:STRING=${CAS_ROOT_DIR} -D3RDPARTY_TCL_DIR:PATH=${TCLTK_ROOT_DIR} -DUSE_TBB:BOOL=ON -D3RDPARTY_TBB_DIR:PATH=${TBB_ROOT_DIR} -D3RDPARTY_FREETYPE_DIR:PATH=${FREETYPE_ROOT_DIR} -DUSE_FREEIMAGE:BOOL=ON -D3RDPARTY_FREEIMAGE_DIR:PATH=${FREEIMAGE_ROOT_DIR} -DUSE_GL2PS:BOOL=ON -D3RDPARTY_GL2PS_DIR:PATH=${GL2PS_ROOT_DIR} -DCMAKE_BUILD_TYPE:STRING=Release ${CAS_SRC_DIR}
 
 Paraview
-cmake -DCMAKE_INSTALL_PREFIX:STRING=${PARAVIEW_ROOT_DIR} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=Release -DBUILD_SHARED_LIBS:BOOL=ON -DBUILD_TESTING:BOOL=OFF -DCMAKE_CXX_FLAGS:STRING=-m64 -DCMAKE_C_FLAGS:STRING=-m64 -DPARAVIEW_INSTALL_DEVELOPMENT_FILES:BOOL=ON -DVTK_PYTHON_FULL_THREADSAFE:BOOL=ON -DVTK_NO_PYTHON_THREADS:BOOL=OFF -DVTK_PYTHON_VERSION:STRING=3 -DOpenGL_GL_PREFERENCE:STRING=LEGACY -DPARAVIEW_USE_OSPRAY:BOOL=ON -DOSPRAY_INSTALL_DIR:PATH=${OSPRAY_ROOT_DIR} -Dembree_DIR:PATH=${EMBREE_ROOT_DIR}/lib64/cmake/embree-3.5.2 -DVTK_USE_64BIT_IDS:BOOL=OFF -DVTK_REPORT_OPENGL_ERRORS:BOOL=OFF -DVTK_RENDERING_BACKEND:STRING=OpenGL2 -DPARAVIEW_BUILD_QT_GUI:BOOL=ON -DQT_HELP_GENERATOR:STRING=${QT5_ROOT_DIR}/bin/qhelpgenerator -DPARAVIEW_QT_VERSION:STRING=5 -DVTK_BUILD_QT_DESIGNER_PLUGIN:BOOL=OFF -DPARAVIEW_ENABLE_PYTHON:BOOL=ON -DVTK_WRAP_PYTHON:BOOL=ON -DPYTHON_EXECUTABLE:STRING=${PYTHON_ROOT_DIR}/bin/python3.6 -DPYTHON_INCLUDE_DIR:STRING=${PYTHON_ROOT_DIR}/include/python3.6 -DPYTHON_LIBRARY:STRING=${PYTHON_ROOT_DIR}/lib/libpython3.6.so -DVTK_NO_PYTHON_THREADS:BOOL=OFF -DVTK_USE_SYSTEM_PYGMENTS:BOOL=ON -DVTK_WRAP_JAVA:BOOL=OFF -DPARAVIEW_USE_MPI:BOOL=OFF -DVTK_USE_SYSTEM_HDF5:BOOL=ON -DHDF5_USE_STATIC_LIBRARIES:BOOL=OFF -DHDF5_ROOT:PATH=${HDF5_ROOT_DIR} -DHDF5_INCLUDE_DIRS:STRING=${HDF5_ROOT_DIR}/include -DHDF5_LIBRARIES:FILEPATH=${HDF5_ROOT_DIR}/lib/libhdf5.so;${HDF5_ROOT_DIR}/lib/libhdf5_hl.so -DHDF5_INCLUDE_DIR:PATH=${HDF5_ROOT_DIR}/include -DPARAVIEW_USE_VISITBRIDGE:BOOL=ON -DBOOST_ROOT:PATH=${BOOST_ROOT_DIR} -DVTK_USE_SYSTEM_GL2PS:BOOL=ON -DGL2PS_INCLUDE_DIR:STRING=${GL2PS_ROOT_DIR}/include -DGL2PS_LIBRARY:STRING=${GL2PS_ROOT_DIR}/lib/libgl2ps.so -DVTK_USE_SYSTEM_LIBXML2:BOOL=ON -DLIBXML2_INCLUDE_DIR:STRING=${LIBXML2_ROOT_DIR}/include/libxml2 -DLIBXML2_LIBRARIES:STRING=${LIBXML2_ROOT_DIR}/lib/libxml2.so -DVTK_USE_SYSTEM_FREETYPE:BOOL=ON -DPARAVIEW_BUILD_PLUGIN_Moments:BOOL=OFF -DPARAVIEW_BUILD_PLUGIN_SLACTools:BOOL=OFF -DPARAVIEW_BUILD_PLUGIN_SierraPlotTools:BOOL=OFF -DPARAVIEW_BUILD_PLUGIN_PacMan:BOOL=OFF -DPARAVIEW_ENABLE_COPROCESSING:BOOL=OFF -DPARAVIEW_BUILD_PLUGIN_EyeDomeLighting:BOOL=ON -DPARAVIEW_BUILD_PLUGIN_PointSprite:BOOL=ON -DPARAVIEW_BUILD_PLUGIN_SurfaceLIC:BOOL=ON -DPARAVIEW_ENABLE_MATPLOTLIB:BOOL=ON ${PARAVIEW_SRC_DIR}
+cmake -DCMAKE_INSTALL_PREFIX:STRING=${PARAVIEW_ROOT_DIR} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_CXX_FLAGS:STRING=-m64 -DCMAKE_C_FLAGS:STRING=-m64 -DPARAVIEW_BUILD_SHARED_LIBS:BOOL=ON -DPARAVIEW_BUILD_TESTING:BOOL=OFF -DPARAVIEW_INSTALL_DEVELOPMENT_FILES:BOOL=ON -DOpenGL_GL_PREFERENCE:STRING=LEGACY -DPARAVIEW_ENABLE_RAYTRACING:BOOL=ON -DVTK_ENABLE_OSPRAY:BOOL=ON -Dembree_DIR:PATH=${EMBREE_ROOT_DIR}/lib64/cmake/embree-3.3.0 -DTBB_ROOT:PATH=${TBB_ROOT_DIR} -DVTK_USE_64BIT_IDS:BOOL=OFF -DVTK_REPORT_OPENGL_ERRORS:BOOL=OFF -DVTK_MODULE_ENABLE_VTK_RenderingLOD:INTERNAL=YES -DVTK_MODULE_ENABLE_VTK_FiltersCore:INTERNAL=YES -DVTK_MODULE_ENABLE_VTK_CommonCore:INTERNAL=YES -DVTK_MODULE_ENABLE_VTK_IOCore:INTERNAL=YES -DVTK_MODULE_ENABLE_VTK_IOEnSight:INTERNAL=YES -DVTK_MODULE_ENABLE_VTK_IOInfovis:INTERNAL=YES -DPARAVIEW_USE_QT:BOOL=ON -DVTK_BUILD_QT_DESIGNER_PLUGIN:BOOL=OFF -DPARAVIEW_USE_PYTHON:BOOL=ON -DVTK_WRAP_PYTHON:BOOL=ON -DPython3_INCLUDE_DIR:STRING=${PYTHON_ROOT_DIR}/include/python3.6 -DPython3_LIBRARY:STRING=${PYTHON_ROOT_DIR}/lib/libpython3.6.so -DVTK_PYTHON_FULL_THREADSAFE:BOOL=ON -DVTK_NO_PYTHON_THREADS:BOOL=OFF -DVTK_PYTHON_VERSION:STRING=3 -DVTK_WRAP_JAVA:BOOL=OFF -DPARAVIEW_USE_MPI:BOOL=OFF -DVTK_MODULE_USE_EXTERNAL_VTK_hdf5:BOOL=ON -DHDF5_DIR:PATH=${HDF5_ROOT_DIR}/share/cmake/hdf5 -DHDF5_USE_STATIC_LIBRARIES:BOOL=OFF -DPARAVIEW_ENABLE_VISITBRIDGE:BOOL=ON -DBOOST_ROOT:PATH=${BOOST_ROOT_DIR} -DBoost_NO_BOOST_CMAKE:BOOL=ON -DBoost_NO_SYSTEM_PATHS:BOOL=ON -DVTK_MODULE_USE_EXTERNAL_VTK_gl2ps:BOOL=OFF -DVTK_MODULE_USE_EXTERNAL_VTK_libxml2:BOOL=ON -DLIBXML2_INCLUDE_DIR:STRING=${LIBXML2_ROOT_DIR}/include/libxml2 -DLIBXML2_LIBRARIES:STRING=${LIBXML2_ROOT_DIR}/lib/libxml2.so -DVTK_MODULE_USE_EXTERNAL_VTK_freetype:BOOL=ON -DVTK_MODULE_USE_EXTERNAL_ParaView_cgns:BOOL=ON -DCGNS_INCLUDE_DIR:PATH=${CGNS_ROOT_DIR}/include -DCGNS_LIBRARY:PATH=${CGNS_ROOT_DIR}/lib/libcgns.so -DVTK_MODULE_ENABLE_ParaView_cgns:INTERNAL=YES -DVTK_MODULE_ENABLE_ParaView_VTKExtensionsCGNSReader:INTERNAL=YES -DVTK_MODULE_ENABLE_ParaView_VTKExtensionsCGNSWriter:INTERNAL=YES -DPARAVIEW_PLUGINS_DEFAULT:BOOL=ON -DPARAVIEW_PLUGIN_ENABLE_Moments:BOOL=OFF -DPARAVIEW_PLUGIN_ENABLE_SLACTools:BOOL=OFF -DPARAVIEW_PLUGIN_ENABLE_SierraPlotTools:BOOL=OFF -DPARAVIEW_PLUGIN_ENABLE_PacMan:BOOL=OFF -DPARAVIEW_PLUGIN_ENABLE_pvblot:BOOL=OFF ${PARAVIEW_SRC_DIR}
 
 PyQt
 > python3 ./configure.py -b ${PYQT5_ROOT_DIR}/bin -d ${PYQT5_ROOT_DIR} -v ${PYQT5_ROOT_DIR}/sip  --confirm-license --designer-plugindir=${PYQT5_ROOT_DIR}/plugins/designer --qml-plugindir=${PYQT5_ROOT_DIR}/plugins/qml --no-qsci-api --sip-incdir=${SIP_ROOT_DIR}/include/python3.6
diff --git a/config/patches/paraview.0001-LATA-reader.patch b/config/patches/paraview.0001-LATA-reader.patch
new file mode 100644 (file)
index 0000000..873c94d
--- /dev/null
@@ -0,0 +1,20242 @@
+From 8b92e13269c76f0c4b3422cd2774412bb24368b7 Mon Sep 17 00:00:00 2001
+From: Antoine Gerschenfeld <antoine.gerschenfeld@cea.fr>
+Date: Sun, 19 May 2019 20:24:42 +0200
+Subject: [PATCH 1/3] LATA reader
+
+---
+ databases/CMakeLists.txt                      |    1 +
+ databases/readers/Lata/ArrOfBit.C             |  179 ++
+ databases/readers/Lata/ArrOfBit.h             |  110 +
+ databases/readers/Lata/ArrOfDouble.C          | 1185 +++++++++
+ databases/readers/Lata/ArrOfDouble.h          |  353 +++
+ databases/readers/Lata/ArrOfFloat.C           | 1185 +++++++++
+ databases/readers/Lata/ArrOfFloat.h           |  353 +++
+ databases/readers/Lata/ArrOfInt.C             | 1110 ++++++++
+ databases/readers/Lata/ArrOfInt.h             |  343 +++
+ .../readers/Lata/ArrOf_Scalar_Prototype.cpp.h | 1168 +++++++++
+ .../readers/Lata/ArrOf_Scalar_Prototype.h     |  357 +++
+ databases/readers/Lata/CMakeLists.txt         |   35 +
+ .../readers/Lata/Connectivite_som_elem.C      |  189 ++
+ .../readers/Lata/Connectivite_som_elem.h      |   44 +
+ databases/readers/Lata/DoubleTab.h            |   30 +
+ databases/readers/Lata/EFichier.h             |   60 +
+ databases/readers/Lata/Entree.h               |   77 +
+ databases/readers/Lata/FloatTab.h             |   30 +
+ databases/readers/Lata/IntTab.h               |   31 +
+ databases/readers/Lata/LataDB.C               | 2313 +++++++++++++++++
+ databases/readers/Lata/LataDB.h               |  303 +++
+ databases/readers/Lata/LataDBmed.h            |  586 +++++
+ databases/readers/Lata/LataFilter.C           | 1106 ++++++++
+ databases/readers/Lata/LataFilter.h           |  261 ++
+ databases/readers/Lata/LataJournal.h          |   36 +
+ databases/readers/Lata/LataStructures.C       |  743 ++++++
+ databases/readers/Lata/LataStructures.h       |  332 +++
+ .../readers/Lata/LataV1_field_definitions.C   |   84 +
+ .../readers/Lata/LataV1_field_definitions.h   |   35 +
+ databases/readers/Lata/LataVector.h           |   64 +
+ databases/readers/Lata/LataWriter.C           |  331 +++
+ databases/readers/Lata/LataWriter.h           |   61 +
+ databases/readers/Lata/Lata_tools.C           |  128 +
+ databases/readers/Lata/Lata_tools.h           |  194 ++
+ databases/readers/Lata/LmlReader.C            |  435 ++++
+ databases/readers/Lata/LmlReader.h            |   38 +
+ databases/readers/Lata/Motcle.C               |  142 +
+ databases/readers/Lata/Motcle.h               |  150 ++
+ databases/readers/Lata/Noms.h                 |   29 +
+ databases/readers/Lata/Objet_U.h              |   41 +
+ databases/readers/Lata/Octree_Double.C        |  395 +++
+ databases/readers/Lata/Octree_Double.h        |   89 +
+ databases/readers/Lata/Octree_Int.C           |  485 ++++
+ databases/readers/Lata/Octree_Int.h           |  103 +
+ databases/readers/Lata/OpenDXWriter.C         |  335 +++
+ databases/readers/Lata/OpenDXWriter.h         |   83 +
+ databases/readers/Lata/Operator.h             |  224 ++
+ databases/readers/Lata/OperatorBoundary.C     |  227 ++
+ databases/readers/Lata/OperatorDualMesh.C     |  222 ++
+ databases/readers/Lata/OperatorFacesMesh.C    |  130 +
+ databases/readers/Lata/OperatorReconnect.C    |  125 +
+ databases/readers/Lata/OperatorRegularize.C   |  296 +++
+ .../readers/Lata/Rebuild_virtual_layer.C      |  141 +
+ .../readers/Lata/Rebuild_virtual_layer.h      |   35 +
+ databases/readers/Lata/Sortie.h               |   44 +
+ databases/readers/Lata/Static_Int_Lists.C     |  128 +
+ databases/readers/Lata/Static_Int_Lists.h     |  110 +
+ databases/readers/Lata/UserFields.C           | 1038 ++++++++
+ databases/readers/Lata/UserFields.h           |  108 +
+ databases/readers/Lata/Vect.h                 |   34 +
+ databases/readers/Lata/VectArrOfInt.h         |   34 +
+ databases/readers/Lata/arch.h                 |   34 +
+ databases/readers/Lata/avtlataFileFormat.C    |  865 ++++++
+ databases/readers/Lata/avtlataFileFormat.h    |  114 +
+ databases/readers/Lata/simd_interface.h       |   31 +
+ databases/visit_readers.xml                   |   13 +
+ 66 files changed, 19695 insertions(+)
+ create mode 100644 databases/readers/Lata/ArrOfBit.C
+ create mode 100644 databases/readers/Lata/ArrOfBit.h
+ create mode 100644 databases/readers/Lata/ArrOfDouble.C
+ create mode 100644 databases/readers/Lata/ArrOfDouble.h
+ create mode 100644 databases/readers/Lata/ArrOfFloat.C
+ create mode 100644 databases/readers/Lata/ArrOfFloat.h
+ create mode 100644 databases/readers/Lata/ArrOfInt.C
+ create mode 100644 databases/readers/Lata/ArrOfInt.h
+ create mode 100644 databases/readers/Lata/ArrOf_Scalar_Prototype.cpp.h
+ create mode 100644 databases/readers/Lata/ArrOf_Scalar_Prototype.h
+ create mode 100644 databases/readers/Lata/CMakeLists.txt
+ create mode 100644 databases/readers/Lata/Connectivite_som_elem.C
+ create mode 100644 databases/readers/Lata/Connectivite_som_elem.h
+ create mode 100644 databases/readers/Lata/DoubleTab.h
+ create mode 100644 databases/readers/Lata/EFichier.h
+ create mode 100644 databases/readers/Lata/Entree.h
+ create mode 100644 databases/readers/Lata/FloatTab.h
+ create mode 100644 databases/readers/Lata/IntTab.h
+ create mode 100644 databases/readers/Lata/LataDB.C
+ create mode 100644 databases/readers/Lata/LataDB.h
+ create mode 100644 databases/readers/Lata/LataDBmed.h
+ create mode 100644 databases/readers/Lata/LataFilter.C
+ create mode 100644 databases/readers/Lata/LataFilter.h
+ create mode 100644 databases/readers/Lata/LataJournal.h
+ create mode 100644 databases/readers/Lata/LataStructures.C
+ create mode 100644 databases/readers/Lata/LataStructures.h
+ create mode 100644 databases/readers/Lata/LataV1_field_definitions.C
+ create mode 100644 databases/readers/Lata/LataV1_field_definitions.h
+ create mode 100644 databases/readers/Lata/LataVector.h
+ create mode 100644 databases/readers/Lata/LataWriter.C
+ create mode 100644 databases/readers/Lata/LataWriter.h
+ create mode 100644 databases/readers/Lata/Lata_tools.C
+ create mode 100644 databases/readers/Lata/Lata_tools.h
+ create mode 100644 databases/readers/Lata/LmlReader.C
+ create mode 100644 databases/readers/Lata/LmlReader.h
+ create mode 100644 databases/readers/Lata/Motcle.C
+ create mode 100644 databases/readers/Lata/Motcle.h
+ create mode 100644 databases/readers/Lata/Noms.h
+ create mode 100644 databases/readers/Lata/Objet_U.h
+ create mode 100644 databases/readers/Lata/Octree_Double.C
+ create mode 100644 databases/readers/Lata/Octree_Double.h
+ create mode 100644 databases/readers/Lata/Octree_Int.C
+ create mode 100644 databases/readers/Lata/Octree_Int.h
+ create mode 100644 databases/readers/Lata/OpenDXWriter.C
+ create mode 100644 databases/readers/Lata/OpenDXWriter.h
+ create mode 100644 databases/readers/Lata/Operator.h
+ create mode 100644 databases/readers/Lata/OperatorBoundary.C
+ create mode 100644 databases/readers/Lata/OperatorDualMesh.C
+ create mode 100644 databases/readers/Lata/OperatorFacesMesh.C
+ create mode 100644 databases/readers/Lata/OperatorReconnect.C
+ create mode 100644 databases/readers/Lata/OperatorRegularize.C
+ create mode 100644 databases/readers/Lata/Rebuild_virtual_layer.C
+ create mode 100644 databases/readers/Lata/Rebuild_virtual_layer.h
+ create mode 100644 databases/readers/Lata/Sortie.h
+ create mode 100644 databases/readers/Lata/Static_Int_Lists.C
+ create mode 100644 databases/readers/Lata/Static_Int_Lists.h
+ create mode 100644 databases/readers/Lata/UserFields.C
+ create mode 100644 databases/readers/Lata/UserFields.h
+ create mode 100644 databases/readers/Lata/Vect.h
+ create mode 100644 databases/readers/Lata/VectArrOfInt.h
+ create mode 100644 databases/readers/Lata/arch.h
+ create mode 100644 databases/readers/Lata/avtlataFileFormat.C
+ create mode 100644 databases/readers/Lata/avtlataFileFormat.h
+ create mode 100644 databases/readers/Lata/simd_interface.h
+
+diff --git a/databases/CMakeLists.txt b/databases/CMakeLists.txt
+index a3d1b03..7b4bd48 100644
+--- a/databases/CMakeLists.txt
++++ b/databases/CMakeLists.txt
+@@ -35,6 +35,7 @@ set(DEFAULT_BRIDGE_READERS
+   H5Nimrod
+   Image
+   LAMMPS
++  Lata
+   Lines
+   M3D
+   M3DC1
+diff --git a/databases/readers/Lata/ArrOfBit.C b/databases/readers/Lata/ArrOfBit.C
+new file mode 100644
+index 0000000..c1b4b45
+--- /dev/null
++++ b/databases/readers/Lata/ArrOfBit.C
+@@ -0,0 +1,179 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <ArrOfBit.h>
++#include <string.h>
++//Implemente_instanciable_sans_constructeur_ni_destructeur(ArrOfBit,"ArrOfBit",Objet_U);
++
++const unsigned int ArrOfBit::SIZE_OF_INT_BITS = 5;
++const unsigned int ArrOfBit::DRAPEAUX_INT = 31;
++
++// Description: Constructeur d'un tableau de taille n, non initialise
++ArrOfBit::ArrOfBit(entier n)
++{
++  taille = 0;
++  data = 0;
++  resize_array(n);
++}
++
++// Description: Destructeur.
++ArrOfBit::~ArrOfBit()
++{
++  if (data)
++    delete[] data;
++  data = 0;
++}
++
++// Description: Constructeur par copie (deep copy)
++ArrOfBit::ArrOfBit(const ArrOfBit& array)
++{
++  taille = 0;
++  data = 0;
++  operator=(array);
++}
++
++// Description:
++// Taille en "int" du tableau requis pour stocker un tableau de bits
++// de taille donnees.
++entier ArrOfBit::calculer_int_size(entier taille) const
++{
++  assert(taille >= 0);
++  entier siz = taille >> SIZE_OF_INT_BITS;
++  if (taille & DRAPEAUX_INT)
++    siz++;
++  return siz;
++}
++
++// Description: Change la taille du tableau et copie les donnees
++// existantes. Si la taille est plus petite, les donnees sont
++// tronquees, et si la taille est plus grande, les nouveaux elements
++// ne sont pas initialises.
++ArrOfBit& ArrOfBit::resize_array(entier n)
++{
++  if (taille == n)
++    return *this;
++  assert(n >= 0);
++  if (n > 0)
++    {
++      entier oldsize = calculer_int_size(taille);
++      entier newsize = calculer_int_size(n);
++      unsigned int * newdata = new unsigned int[newsize];
++      entier size_copy = (newsize > oldsize) ? oldsize : newsize;
++      if (size_copy)
++        {
++          memcpy(newdata, data, size_copy);
++          delete[] data;
++        }
++      data = newdata;
++      taille = n;
++    }
++  else
++    {
++      delete[] data; // data!=0 sinon taille==n et on ne serait pas ici
++      data = 0;
++      taille = 0;
++    }
++  return *this;
++}
++
++// Description: Operateur copie (deep copy).
++ArrOfBit& ArrOfBit::operator=(const ArrOfBit& array)
++{
++  entier newsize = calculer_int_size(array.taille);
++  if (taille != array.taille)
++    {
++      if (data)
++        {
++          delete[] data;
++          data = 0;
++        }
++      if (newsize > 0)
++        data = new unsigned int[newsize];
++    }
++  taille = array.taille;
++  if (taille)
++    memcpy(data, array.data, newsize * sizeof(unsigned int));
++  return *this;
++}
++
++// Description: Si la valeur est non nulle, met la valeur 1 dans
++// tous les elements du tableau, sinon met la valeur 0.
++
++ArrOfBit& ArrOfBit::operator=(entier val)
++{
++  unsigned int valeur = val ? (~((unsigned int) 0)) : 0;
++  entier size = calculer_int_size(taille);
++  entier i;
++  for (i = 0; i < size; i++)
++    data[i] = valeur;
++  return *this;
++}
++
++// Description: Ecriture du tableau. Format:
++// n
++// 0 1 0 0 1 0 ... (n valeurs)
++Sortie& ArrOfBit::printOn(Sortie& os) const
++{
++  os << taille << finl;
++  entier i;
++  // Un retour a la ligne tous les 32 bits,
++  // Une espace tous les 8 bits
++  for (i = 0; i < taille; i++)
++    {
++      os << operator[](i);
++      if ((i & 7) == 7)
++        os << " ";
++      if ((i & 31) == 31)
++        os << finl;
++    }
++  // Un retour a la ligne si la derniere ligne n'etait pas terminee
++  if (i & 31)
++    os << finl;
++  return os;
++}
++
++// Description: Lecture du tableau. Format:
++// n
++// 0 1 0 0 1 0 ... (n valeurs)
++Entree& ArrOfBit::readOn(Entree& is)
++{
++  entier newsize;
++  is >> newsize;
++  resize_array(newsize);
++  operator=(0);
++
++  entier i;
++  for (i = 0; i < taille; i++)
++    {
++      entier bit;
++      is >> bit;
++      if (bit) setbit(i);
++    }
++  return is;
++}
+diff --git a/databases/readers/Lata/ArrOfBit.h b/databases/readers/Lata/ArrOfBit.h
+new file mode 100644
+index 0000000..ed21f48
+--- /dev/null
++++ b/databases/readers/Lata/ArrOfBit.h
+@@ -0,0 +1,110 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++
++#ifndef ARROFBIT_H
++#define ARROFBIT_H
++
++#include <assert.h>
++#include <Objet_U.h>
++
++class ArrOfBit // : public Objet_U
++{
++// Declare_instanciable_sans_constructeur_ni_destructeur(ArrOfBit);
++protected:
++  Entree& readOn(Entree& is);
++  Sortie& printOn(Sortie& os) const;
++public:
++  ArrOfBit(entier n=0);
++  ArrOfBit(const ArrOfBit& array);              // Constructeur par copie
++  ~ArrOfBit();                                  // Destructeur
++  ArrOfBit& operator=(const ArrOfBit& array);   // Operateur copie
++  ArrOfBit& operator=(entier i);
++  inline entier operator[](entier i) const;
++  inline void setbit(entier i) const;
++  inline entier testsetbit(entier i) const;
++  inline void clearbit(entier i) const;
++  inline entier size_array() const;
++  ArrOfBit& resize_array(entier n);
++  entier calculer_int_size(entier taille) const;
++protected:
++  entier taille;
++  unsigned int *data;
++  static const unsigned int SIZE_OF_INT_BITS;
++  static const unsigned int DRAPEAUX_INT;
++};
++
++// Description: Renvoie 1 si le bit e est mis, 0 sinon.
++inline entier ArrOfBit::operator[](entier e) const
++{
++  assert(e >= 0 && e < taille);
++  unsigned int i = (unsigned int) e;
++  unsigned int x = data[i >> SIZE_OF_INT_BITS];
++  unsigned int flag = 1 << (i & DRAPEAUX_INT);
++  entier resultat = ((x & flag) != 0) ? 1 : 0;
++  return resultat;
++}
++
++// Description: Met le bit e a 1.
++inline void ArrOfBit::setbit(entier e) const
++{
++  assert(e >= 0 && e < taille);
++  unsigned int i = (unsigned int) e;
++  unsigned int flag = 1 << (i & DRAPEAUX_INT);
++  data[i >> SIZE_OF_INT_BITS] |= flag;
++}
++
++// Description: Renvoie la valeur du bit e, puis met le bit e a 1.
++inline entier ArrOfBit::testsetbit(entier e) const
++{
++  assert(e >= 0 && e < taille);
++  unsigned int i = (unsigned int) e;
++  unsigned int flag = 1 << (i & DRAPEAUX_INT);
++  entier index = i >> SIZE_OF_INT_BITS;
++  unsigned int old = data[index];
++  data[index] = old | flag;
++  return ((old & flag) != 0) ? 1 : 0;
++}
++
++// Description: Met le bit e a 0.
++inline void ArrOfBit::clearbit(entier e) const
++{
++  assert(e >= 0 && e < taille);
++  unsigned int i = (unsigned int) e;
++  unsigned int flag = 1 << (i & DRAPEAUX_INT);
++  data[i >> SIZE_OF_INT_BITS] &= ~flag;
++}
++
++// Description: Renvoie la taille du tableau en bits
++inline entier ArrOfBit::size_array() const
++{
++  return taille;
++}
++
++#endif
+diff --git a/databases/readers/Lata/ArrOfDouble.C b/databases/readers/Lata/ArrOfDouble.C
+new file mode 100644
+index 0000000..5605a0d
+--- /dev/null
++++ b/databases/readers/Lata/ArrOfDouble.C
+@@ -0,0 +1,1185 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++////////////////////////////////////////////////////////////
++//
++// Warning : DO NOT EDIT !
++//         Please update ArrOf_Scalar_Prototype.cpp.h
++//         and this file will be generated automatically
++//           by the script file check.sh
++////////////////////////////////////////////////////////////
++
++#include <ArrOfDouble.h>
++#include <math.h>
++#include <stdlib.h>
++#include <Objet_U.h>
++#include <iostream>
++#include <stdlib.h>
++#include <string.h>
++#include "simd_interface.h"
++
++using namespace std;
++
++// ******************************************************************
++//
++//             Implementation des methodes de VDoubledata
++//
++// ******************************************************************
++////////////////////////////////////////////////////////////////////
++// .NOM        ArrOfDouble
++// .ENTETE     TRUST Math
++// .LIBRAIRIE  libtmath
++// .FILE       ArrOfDouble.h
++// .FILE       ArrOfDouble.cpp
++//
++// .DESCRIPTION
++// VDoubledata alloue une zone de memoire de la taille specifiee au
++// constructeur, et libere la zone de memoire a la destruction.
++//
++// "ref_count" compte le nombre de pointeurs qui font reference a "this".
++// (permet au dernier utilisateur de l'objet de le detruire), voir
++// ArrOfDouble.
++//
++// .SECTION voir aussi
++// .CONTRAINTES
++// .INVARIANTS
++// .HTML
++// .EPS
++///////////////////////////////////////////////////////////////////
++
++class VDoubledata
++{
++public:
++  VDoubledata(entier size, ArrOfDouble::Storage storage);
++  ~VDoubledata();
++  entier          add_one_ref();
++  entier          suppr_one_ref();
++  double *        get_data();
++  const double *  get_data() const;
++  inline entier   ref_count() const;
++  inline entier   get_size() const;
++private:
++  // Le constructeur par copie et l'operateur= sont interdits.
++  VDoubledata(const VDoubledata& v);
++  VDoubledata& operator=(const VDoubledata& v);
++
++  // "data" est un pointeur sur une zone de memoire de taille
++  // sz * sizeof(double), allouee par le
++  // constructeur et liberee par le destructeur.
++  // Ce pointeur n'est jamais nul meme si size_==0
++  double * data_;
++  // Compteur incremente par add_one_ref et decremente par suppr_one_ref.
++  // Contient le nombre d'objets ArrOfDouble dont le membre "p" pointe
++  // vers "this". On a ref_count_ >= 0.
++  entier ref_count_;
++  // "sz" est la taille du tableau "data_" alloue
++  // On a sz >= 0.
++  entier size_;
++  ArrOfDouble::Storage storage_;
++};
++
++
++// Description:
++//    Construit un VDoubledata de taille size >= 0
++// Parametre: entier s
++//    Signification: taille du VDoubledata, il faut size >= 0
++// Parametre: Storage storage
++//    Signification: indique si la memoire doit etre allouee
++//                   avec "new" ou avec "simd_malloc"
++//    Valeurs par defaut: STANDARD (allocation avec "new")
++// Postcondition:
++//    data_ n'est jamais nul, meme si size==0
++VDoubledata::VDoubledata(entier size, ArrOfDouble::Storage storage)
++{
++  if (size == 0)
++    storage = ArrOfDouble::STANDARD;
++
++  switch (storage)
++    {
++    case ArrOfDouble::STANDARD:
++      {
++#ifdef _EXCEPTION_
++        // Allocation de la memoire sur le tas
++        try
++          {
++            data_ = new double[size];
++          }
++        catch(...)
++          {
++            Cerr << "impossible d'allouer " << size << " double " << finl;
++            throw;
++          }
++#else
++        data_ = new double[size];
++        if(!data_)
++          {
++            Cerr << "impossible d'allouer " << size << "double " << finl;
++            throw ;
++          }
++#endif
++        break;
++      }
++    case ArrOfDouble::SIMD_ALIGNED:
++      {
++#ifdef SIMD_TOOLS_H
++        data_ = (double*) simd_malloc (sizeof(double) * size);
++#else
++        Cerr<<"unable to allocate simd_aligned, version compiled without simd "<<finl;
++        throw;
++#endif
++        break;
++      }
++    default:
++      throw;
++    }
++  ref_count_ = 1;
++  size_ = size;
++  storage_ = storage;
++  assert(data_ != 0);
++}
++
++// Description:
++//  Detruit la zone de memoire allouee.
++// Precondition:
++//  ref_count == 0 (la zone de memoire ne doit etre referencee nulle part)
++VDoubledata::~VDoubledata()
++{
++  assert(ref_count_ == 0);
++
++  // Stockage STANDARD
++  switch(storage_)
++    {
++    case ArrOfDouble::STANDARD:
++      delete[] data_;
++      break;
++    case ArrOfDouble::SIMD_ALIGNED:
++#ifdef SIMD_TOOLS_H
++      simd_free(data_);
++#else
++      Cerr<<"unable to allocate simd_aligned, version compiled without simd "<<finl;
++      throw;
++#endif
++      break;
++    default:
++      throw;
++    }
++
++  data_ = 0;  // paranoia: si size_==-1 c'est qu'on pointe sur un zombie
++  size_ = -1; //  (pointeur vers un objet qui a ete detruit)
++  storage_ = ArrOfDouble::STANDARD;
++}
++
++// Description: renvoie ref_count_
++inline entier VDoubledata::ref_count() const
++{
++  return ref_count_;
++}
++
++// Description: renvoie size_
++inline entier VDoubledata::get_size() const
++{
++  return size_;
++}
++
++// Description:
++//     Un nouveau tableau utilise cette zone memoire :
++//     incremente ref_count
++// Retour: int
++//    Signification: ref_count
++inline entier VDoubledata::add_one_ref()
++{
++  return ++ref_count_;
++}
++
++// Description:
++//     Un tableau de moins utilise cette zone memoire
++//     decremente ref_count
++// Precondition:
++//     ref_count_ > 0
++// Retour: int
++//    Signification: ref_count
++inline entier VDoubledata::suppr_one_ref()
++{
++  assert(ref_count_ > 0);
++  return (--ref_count_);
++}
++
++// Description: renvoie data_
++inline double * VDoubledata::get_data()
++{
++  return data_;
++}
++
++// Description: renvoie data_
++inline const double * VDoubledata::get_data() const
++{
++  return data_;
++}
++
++// Description: Constructeur par copie. Interdit : genere une erreur !
++VDoubledata::VDoubledata(const VDoubledata& v)
++{
++  Cerr << "Erreur dans VDoubledata::VDoubledata(const VDoubledata & v)" << finl;
++  throw;
++}
++
++// Description: Operateur= interdit. Genere une erreur !
++VDoubledata& VDoubledata::operator=(const VDoubledata& v)
++{
++  Cerr << "Erreur dans VDoubledata::operator=(const VDoubledata & v)" << finl;
++  throw;
++  return *this;
++}
++
++// ******************************************************************
++//
++//             Implementation des methodes de ArrOfDouble
++//
++// ******************************************************************
++
++
++// Definition des constantes pour les options de memory_resize
++const entier ArrOfDouble::COPY_OLD = 1;
++const entier ArrOfDouble::INITIALIZE_NEW = 2;
++
++// Description:
++//  Destructeur : appelle detach_array()
++ArrOfDouble::~ArrOfDouble()
++{
++  detach_array();
++  size_array_ = -1; // Paranoia: si size_array_==-1, c'est un zombie
++}
++
++// Description:
++//  Constructeur par defaut: cree un tableau "detache",
++//  soit p_==0, data_==0, size_array_==0, smart_resize_==0
++ArrOfDouble::ArrOfDouble() :
++  p_(0),
++  data_(0),
++  size_array_(0),
++  memory_size_(0),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++}
++
++// Description:
++//     Cree un tableau de taille n avec allocation standard
++//     (voir set_mem_storage).
++//     Valeur de remplissage par defaut: voir fill_default_value
++// Precondition:
++// Parametre: entier n
++//    Signification: taille du tableau
++ArrOfDouble::ArrOfDouble(entier n) :
++  p_(new VDoubledata(n, STANDARD)),
++  data_(p_->get_data()),
++  size_array_(n),
++  memory_size_(n),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++  if (n > 0)
++    fill_default_value(0, n);
++}
++
++// Description:
++//     Cree un tableau de taille n
++//     toutes les cases sont initialisees a x
++// Precondition:
++// Parametre: entier n
++//    Signification: taille du tableau
++// Parametre: double x
++//    Signification: valeur pour initialiser le tableau
++ArrOfDouble::ArrOfDouble(entier n, double x) :
++  p_(new VDoubledata(n, STANDARD)),
++  data_(p_->get_data()),
++  size_array_(n),
++  memory_size_(n),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++  *this = x;
++}
++
++// Description:
++//     Constructeur par copie. On alloue une nouvelle zone de memoire
++//     et on copie le contenu du tableau. L'attribut smart_resize_ est
++//     copie aussi.
++//     Si le tableau A est de taille nulle, on cree un tableau "detache",
++//     sinon on cree un tableau "normal".
++// Parametre: const ArrOfDouble& A
++//    Signification: le tableau a copier
++ArrOfDouble::ArrOfDouble(const ArrOfDouble& A)
++{
++  const entier size = A.size_array();
++  if (size > 0)
++    {
++      // Creation d'un tableau "normal"
++      storage_type_ = STANDARD;
++      p_ = new VDoubledata(size, STANDARD);
++      data_ = p_->get_data();
++      size_array_ = size;
++      memory_size_ = size;
++      smart_resize_ = A.smart_resize_;
++      inject_array(A);
++    }
++  else
++    {
++      // Creation d'un tableau "detache"
++      p_ = 0;
++      data_ = 0;
++      size_array_ = 0;
++      memory_size_ = 0;
++      smart_resize_ = 0;
++      storage_type_ = STANDARD;
++    }
++}
++
++// Description:
++//   Change le mode d'allocation memoire lors des resize
++//   (voir VDoubledata et Double_ptr_trav)
++//   Exemple pour creer un tableau avec allocation temporaire:
++//    DoubleTab tab; // Creation d'un tableau vide
++//    tab.set_mem_storage(TEMP_STORAGE); // Changement de mode d'allocation
++//    tab.resize(n); // Allocation memoire
++void ArrOfDouble::set_mem_storage(const Storage storage)
++{
++  storage_type_ = storage;
++}
++
++// Description:
++//   Renvoie le mode d'allocation du tableau (qui sera utilise
++//   lors du prochain resize si changement de taille).
++//   (voir VDoubledata et Double_ptr_trav)
++enum ArrOfDouble::Storage ArrOfDouble::get_mem_storage() const
++{
++  return storage_type_;
++}
++
++// Description:
++//   Change le mode l'allocation memoire: reallocation d'un tableau
++//   a chaque changement de taille (flag = 0) ou reallocation
++//   uniquement si la taille augmente et par doublement de la taille
++//   du tableau (flag = 1).
++void ArrOfDouble::set_smart_resize(entier flag)
++{
++  assert(flag == 0 || flag == 1);
++  smart_resize_ = flag;
++}
++
++// Description:
++//    Remet le tableau dans l'etat obtenu avec le constructeur par defaut
++//    (libere la memoire mais conserve le mode d'allocation memoire actuel)
++void ArrOfDouble::reset()
++{
++  detach_array();
++}
++
++// Description:
++//    Copie les donnees du tableau m.
++//    Si "m" n'a pas la meme taille que "*this", on fait un resize_array.
++//    Ensuite, on copie les valeurs de "m" dans "*this".
++//    Le type de tableau (methode d'allocation) n'est pas copie.
++// Precondition:
++//    Si le tableau n'a pas la meme taille que "m", alors *this doit
++//    etre "resizable" (ne pas etre de type "ref_data" et "ref_count == 1")
++// Parametre: const ArrOfDouble& m
++//    Signification: la tableau a copier
++// Retour:  ArrOfDouble&
++//    Signification: *this
++ArrOfDouble& ArrOfDouble::operator=(const ArrOfDouble& m)
++{
++  if (&m != this)
++    {
++      const entier new_size = m.size_array();
++      // Le code suivant est quasiment une copie de ArrOfDouble::resize()
++      // SAUF: memory_resize est appele avec NO_INITIALIZE (la zone de memoire
++      //  n'est pas initialisee)
++      if (new_size != size_array())
++        {
++          if ((smart_resize_ == 0) || (new_size > memory_size_))
++            memory_resize(new_size, 0); // Pas d'initialisation
++          size_array_ = new_size;
++        }
++      inject_array(m);
++    }
++  return *this;
++}
++
++
++// Description:
++//     x est affecte a toutes les cases
++// Precondition:
++// Parametre: double x
++//    Signification: la valeur a affecter a toutes les cases du tableau
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfDouble&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfDouble& ArrOfDouble::operator=(double x)
++{
++  const entier n = size_array();
++  double *data = addr();
++  for (entier i = 0; i < n; i++)
++    {
++      data[i] = x;
++    }
++  return *this;
++}
++
++// Description: appelle operator=(a)
++ArrOfDouble& ArrOfDouble::copy_array(const ArrOfDouble& a)
++{
++  operator=(a);
++  return *this;
++}
++
++// Description:
++//  Si besoin, alloue une nouvelle zone de memoire,
++//  copie les donnees et efface l'ancienne zone de memoire.
++//  Attention, on suppose que cette methode est appelee par
++//  resize_array().
++//  Attention: si ref_count_>1, l'appel a resize_array() est
++//  autorise uniquement si la nouvelle taille est identique
++//  a la precedente.
++// Precondition:
++//  Le tableau doit etre de type "detache" ou "normal" avec
++//  ref_count==1, et il faut new_size >= 0
++//  On suppose que size_array contient encore le nombre d'elements
++//  valides avant changement de taille.
++// Parametre: new_size
++//  Signification: nouvelle taille demandee pour le tableau.
++// Parametre: options
++//  Signification: COPY_OLD => on recopie les anciennes donnees dans le nouveau
++//                  tableau (jusqu'au max de l'ancienne et de la nouvelle taille).
++//                 INITIALIZE_NEW => initialisation des cases non copiees
++// Postcondition:
++//  p_ et data_ sont mis a jour, mais pas size_array_ !!!
++//  (on suppose que c'est fait dans resize_array()).
++//  Si la nouvelle taille est nulle, on detache le tableau.
++void  ArrOfDouble::memory_resize(entier new_size, entier options)
++{
++  assert(new_size >= 0);
++
++  // Occupation memoire de l'ancien tableau:
++  entier old_mem_size = 0;
++  if (p_)
++    old_mem_size = p_->get_size();
++
++  // Occupation memoire du nouveau tableau :
++  // Si smart_resize, on prend au moins deux fois la taille
++  // precedente, ou new_size
++  entier new_mem_size = new_size;
++  if (smart_resize_ && (old_mem_size * 2 > new_size))
++    new_mem_size = old_mem_size * 2;
++
++  if (new_mem_size != old_mem_size)
++    {
++      // detach_array() efface le contenu de size_array_. On le met de cote:
++      const entier old_size_array = size_array_;
++      // On va reellement changer l'adresse du tableau.
++      // Il ne faut pas qu'il existe d'autre reference a ce tableau.
++      assert(data_ == 0 || (p_ != 0 && ref_count() == 1));
++      if (new_mem_size == 0)
++        {
++          // La nouvelle taille est nulle, on cree un tableau "detache"
++          detach_array();
++        }
++      else
++        {
++          // Allocation d'une nouvelle zone
++          VDoubledata * new_p = new VDoubledata(new_mem_size, storage_type_);
++          double * new_data = new_p->get_data();
++          // Raccourci si le tableau etait "detache", inutile de copier
++          // les anciennes donnees. On copie si COPY_OLD est demande
++          entier copy_size = 0;
++          if (data_ != 0)
++            {
++              // Calcul du nombre d'elements a copier vers la nouvelle
++              // zone de memoire : c'est le min de l'ancienne et de
++              // la nouvelle taille.
++              if (options & COPY_OLD)
++                {
++                  copy_size = size_array_;
++                  if (new_size < copy_size)
++                    copy_size = new_size;
++                  // Copie des valeurs dans le nouveau tableau
++                  for (entier i = 0; i < copy_size; i++)
++                    new_data[i] = data_[i];
++                }
++              // Destruction de l'ancienne zone (si plus aucune reference)
++              detach_array();
++            }
++          // On attache la nouvelle zone de memoire
++          p_ = new_p;
++          data_ = new_data;
++          memory_size_ = new_mem_size;
++          // Initialisation des cases supplementaires avec une valeur par defaut
++          if (options & INITIALIZE_NEW)
++            fill_default_value(copy_size, new_mem_size - copy_size);
++          // Restaure l'ancienne valeur de size_array_
++          size_array_ = old_size_array;
++        }
++    }
++}
++
++// Description:
++//  Remplit "nb" cases consecutives du tableau a partir de la case "first"
++//  avec une valeur par defaut.
++//  Cette fonction est appelee lors d'un resize pour initialiser les
++//  cases nouvellement creees.
++//  Le comportement depend actuellement du type de tableau :
++//  * Tableau de type "smart_resize":
++//    * en mode debug (macro NDEBUG non definie) le tableau est initialise
++//      avec une valeur invalide.
++//    * en optimise, le tableau n'est pas initialise
++//  * Tableau normal :
++//    Le tableau est initialise avec la valeur 0. Ce comportement est choisi
++//    pour des raisons de compatibilite avec l'implementation precedente.
++//    Cette specification pourrait etre modifiee prochainement pour des raisons
++//    de performances (pour ne pas avoir a initialiser inutilement les tableaux).
++//    DONC: il faut supposer desormais que les nouvelles cases ne sont pas
++//    initialisees lors d'un resize.
++// Parametre: first
++//  Signification: premiere case a initialiser.
++//  Contrainte:    (nb==0) ou (0 <= first < memory_size_)
++// Parametre: nb
++//  Signification: nombre de cases a initialiser.
++//  Contrainte:    (nb==0) ou (0 < nb <= memory_size_ - first)
++void  ArrOfDouble::fill_default_value(entier first, entier nb)
++{
++  assert((nb == 0) || (first >= 0 && first < memory_size_));
++  assert((nb == 0) || (nb > 0 && nb <= memory_size_ - first));
++  double * data = addr();
++  assert(data!=0 || nb==0);
++  data += first;
++  if (smart_resize_)
++    {
++      /*
++          // On initialise uniquement en mode debug
++      #ifndef NDEBUG
++          // Ceci represente un NAN. N'importe quelle operation avec ca fait encore un NAN.
++          // Si c'est pas portable, on peut remplacer par DMAX_FLOAT sur les autres machines.
++          static const unsigned long long  VALEUR_INVALIDE =
++            0x7ff7ffffffffffffULL;
++
++          // On utilise "memcpy" et non "=" car "=" peut provoquer une exception
++          // si la copie passe par le fpu.
++          for (entier i = 0; i < nb; i++)
++            memcpy(data + i, & VALEUR_INVALIDE, sizeof(double));
++      #endif
++      */
++    }
++  else
++    {
++      // Comportement pour les tableaux normaux : compatibilite avec la
++      // version precedente : on initialise avec 0.
++      for (entier i = 0; i < nb; i++)
++        data[i] = (double) 0;
++    }
++}
++
++// ****************************************************************
++//
++//         Fonctions non membres de la classe ArrOfDouble
++//
++// ****************************************************************
++
++// Description:
++//  Renvoie 1 si les tableaux "v" et "a" sont de la meme taille
++//  et contiennent les memes valeurs au sens strict, sinon renvoie 0.
++//  Le test est !(v[i]!=a[i])
++entier operator==(const ArrOfDouble& v, const ArrOfDouble& a)
++{
++  const entier n = v.size_array();
++  const entier na = a.size_array();
++  entier resu = 1;
++  if (n != na)
++    {
++      resu = 0;
++    }
++  else
++    {
++      const double* vv = v.addr();
++      const double* av = a.addr();
++      entier i;
++      for (i = 0; i < n; i++)
++        {
++          if (av[i] != vv[i])
++            {
++              resu = 0;
++              break;
++            }
++        }
++    }
++  return resu;
++}
++
++// Description:
++//    Retourne l'indice du min ou -1 si le tableau est vide
++// Precondition:
++// Parametre: const ArrOfDouble& dx
++//    Signification: tableau a utiliser
++// Retour: int
++//    Signification: indice du min
++entier imin_array(const ArrOfDouble& dx)
++{
++  entier indice_min = -1;
++  const entier size = dx.size_array();
++  if (size > 0)
++    {
++      indice_min = 0;
++      double valeur_min = dx[0];
++      for(entier i = 1; i < size; i++)
++        {
++          const double val = dx[i];
++          if(val < valeur_min)
++            {
++              indice_min = i;
++              valeur_min = val;
++            }
++        }
++    }
++  return indice_min;
++}
++
++// Description:
++//    Retourne l'indice du max ou -1 si le tableau est vide
++// Precondition:
++// Parametre: const ArrOfDouble& dx
++//    Signification: tableau a utiliser
++// Retour: int
++//    Signification: indice du max
++entier imax_array(const ArrOfDouble& dx)
++{
++  entier indice_max = -1;
++  const entier size = dx.size_array();
++  if (size > 0)
++    {
++      indice_max = 0;
++      double valeur_max = dx[0];
++      for(entier i = 1; i < size; i++)
++        {
++          const double val = dx[i];
++          if(val > valeur_max)
++            {
++              indice_max = i;
++              valeur_max = val;
++            }
++        }
++    }
++  return indice_max;
++}
++
++// Description:
++//    Retourne la valeur minimale
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOfDouble& dx
++//    Signification: tableau a utiliser
++// Retour: double
++//    Signification: valeur du min
++double min_array(const ArrOfDouble& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  double valeur_min = dx[0];
++  for(entier i = 1; i < size; i++)
++    {
++      const double val = dx[i];
++      if (val < valeur_min)
++        valeur_min = val;
++    }
++  return valeur_min;
++}
++
++// Description:
++//    Retourne la valeur maximale
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOfDouble& dx
++//    Signification: tableau a utiliser
++// Retour: double
++//    Signification: valeur du max
++double max_array(const ArrOfDouble& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  double valeur_max = dx[0];
++  for(entier i = 1; i < size; i++)
++    {
++      const double val = dx[i];
++      if (val > valeur_max)
++        valeur_max = val;
++    }
++  return valeur_max;
++}
++
++// Description:
++//   Fonction de comparaison utilisee pour trier le tableau
++//   dans ArrOfDouble::trier(). Voir man qsort
++static int fonction_compare_arrofdouble_ordonner(const void * data1, const void * data2)
++{
++  const double x = *(const double*)data1;
++  const double y = *(const double*)data2;
++  if (x < y)
++    return -1;
++  else if (x > y)
++    return 1;
++  else
++    return 0;
++}
++
++// Description:
++//   Tri des valeurs du tableau dans l'ordre croissant.
++//   La fonction utilisee est qsort de stdlib (elle est en n*log(n)).
++void ArrOfDouble::ordonne_array()
++{
++  const entier size = size_array();
++  if (size > 1)
++    {
++      double * data = addr();
++      qsort(data, size, sizeof(double),
++            fonction_compare_arrofdouble_ordonner);
++    }
++}
++
++// Description:
++//    Fait pointer le tableau vers les memes donnees qu'un tableau
++//    existant. Le tableau sera du meme type que le tableau m ("detache",
++//    "normal"). Le tableau m ne doit pas etre de type "ref_data"
++//    Les donnes existantes sont perdues si elles
++//    ne sont pas referencees ailleurs.
++// Precondition:
++// Parametre: const ArrOfDouble& m
++//    Signification: le tableau a referencer (pas de type "ref_data"
++//                   et different de *this !!!)
++// Retour: ArrOfDouble&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfDouble& ArrOfDouble::ref_array(const ArrOfDouble& m)
++{
++  assert(&m != this);
++  // La condition 'm n'est pas de type "ref_data"' est necessaire pour
++  // attach_array().
++  detach_array();
++  attach_array(m);
++  return *this;
++}
++
++// Description:
++//    Fait pointer le tableau vers la zone de memoire "data_".
++//    On detache la zone de memoire existante. Le tableau devient
++//    de type "ref_data". Attention : ptr doit etre non nul.
++//    La taille est initialisee avec size.
++//    Cette methode est appelee notamment par DoubleVect::adopter.
++// Parametre: double*
++//    Signification: le tableau a recuperer. Si pointeur nul alors size
++//                   doit etre nulle aussi et le tableau reste detache
++// Parametre: entier size
++//    Signification: le nombre d'elements du tableau.
++// Retour: ArrOfDouble&
++//    Signification: *this
++ArrOfDouble& ArrOfDouble::ref_data(double* ptr, entier size)
++{
++  assert(ptr != 0 || size == 0);
++  assert(size >= 0);
++  detach_array();
++  data_ = ptr;
++  size_array_ = size;
++  return *this;
++}
++
++// Description:
++//  Amene le tableau dans l'etat "detache". C'est a dire:
++//  Si le tableau est "detache" :
++//   * ne rien faire
++//  Si le tableau est "normal" :
++//   * decremente le nombre de references a *p
++//   * detruit *p si p->ref_count==0
++//   * annule p_, data_ et size_array_
++//  Si le tableau est "ref_data" :
++//   * annule data_ et size_array_
++// Retour: int
++//    Signification: 1 si les donnees du tableau ont ete supprimees
++// Precondition:
++// Postcondition:
++//  On a p_==0, data_==0 et size_array_==0, memory_size_ = 0
++//  L'attribut smart_resize_ est conserve.
++entier ArrOfDouble::detach_array()
++{
++  entier retour = 0;
++  if (p_)
++    {
++      // Le tableau est de type "normal"
++      // Si la zone de memoire n'est plus utilisee par personne,
++      // on la detruit.
++      if ((p_->suppr_one_ref()) == 0)
++        {
++          delete p_;
++          retour = 1;
++        }
++      p_ = 0;
++    }
++  data_ = 0;
++  size_array_ = 0;
++  memory_size_ = 0;
++  return retour;
++}
++
++// Description:
++//    Amene le tableau dans l'etat "normal", "detache" ou "ref_array"
++//    en associant la meme zone de memoire que le tableau m.
++// Precondition:
++//    Le tableau doit etre "detache"
++// Parametre: const ArrOfDouble& m
++//    Signification: tableau a utiliser
++//                   le tableau doit etre different de *this !!!
++// Retour:
++//    Signification:
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++//    Si m est detache, le tableau reste detache,
++//    si m est "ref_array", le tableau devient "ref_array",
++//    sinon le tableau est "normal", avec ref_count > 1
++//    Si m est de taille nulle, le tableau reste detache + Warning dans fichier .log
++void ArrOfDouble::attach_array(const ArrOfDouble& m)
++{
++  // Le tableau doit etre detache
++  assert(data_ == 0 && p_ == 0);
++  // Le tableau doit etre different de *this
++  assert(&m != this);
++
++  if (m.size_array() > 0)
++    {
++      p_ = m.p_;
++      if (p_)
++        p_->add_one_ref();
++      data_ = m.data_;
++      size_array_ = m.size_array_;
++      memory_size_ = m.memory_size_;
++      smart_resize_ = m.smart_resize_;
++    }
++  else
++    {
++      // Cas particulier ou on attache un tableau de taille nulle:
++      //  en theorie, c'est pareil qu'un tableau de taille non nulle, MAIS
++      //  dans les operateurs (ex:Op_Dift_VDF_Face_Axi), une ref est construite
++      //  avant que le tableau ne prenne sa taille definitive. Donc, pour ne pas
++      //  empecher le resize, il ne faut pas attacher le tableau s'il n'a pas
++      //  encore la bonne taille. Solution propre: reecrire les operateurs pour
++      //  qu'ils ne prennent pas une ref avant que le tableau ne soit valide
++      //  et faire p_ = m.p_ dans tous les cas.
++    }
++}
++
++// Description:
++//    Copie les elements source[first_element_source + i]
++//    dans les elements  (*this)[first_element_dest + i] pour 0 <= i < nb_elements
++//    Les autres elements de (*this) sont inchanges.
++// Precondition:
++// Parametre:       const ArrOfDouble& m
++//  Signification:   le tableau a utiliser, doit etre different de *this !
++// Parametre:       entier nb_elements
++//  Signification:   nombre d'elements a copier, nb_elements >= -1.
++//                   Si nb_elements==-1, on copie tout le tableau m.
++//  Valeurs par defaut: -1
++// Parametre:       entier first_element_dest
++//  Valeurs par defaut: 0
++// Parametre:       entier first_element_source
++//  Valeurs par defaut: 0
++// Retour: ArrOfDouble&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++//    Sort en erreur si la taille du tableau m est plus grande que la
++//    taille de tableau this.
++// Effets de bord:
++// Postcondition:
++ArrOfDouble& ArrOfDouble::inject_array(const ArrOfDouble& source,
++                                       entier nb_elements,
++                                       entier first_element_dest,
++                                       entier first_element_source)
++{
++  assert(&source != this);
++  assert(nb_elements >= -1);
++  assert(first_element_dest >= 0);
++  assert(first_element_source >= 0);
++
++  if (nb_elements < 0)
++    nb_elements = source.size_array();
++
++  assert(first_element_source + nb_elements <= source.size_array());
++  assert(first_element_dest + nb_elements <= size_array());
++
++  if (nb_elements > 0)
++    {
++      double * addr_dest = addr() + first_element_dest;
++      const double * addr_source = source.addr() + first_element_source;
++      // memcpy(addr_dest , addr_source, nb_elements * sizeof(double));
++      entier i;
++      for (i = 0; i < nb_elements; i++)
++        {
++          addr_dest[i] = addr_source[i];
++        }
++    }
++  return *this;
++}
++
++// Description:
++//    Retourne le nombre de references des donnees du tableau
++//    si le tableau est "normal", -1 s'il est "detache" ou "ref_data"
++// Retour: int
++//    Signification: ref_count_
++entier ArrOfDouble::ref_count() const
++{
++  if (p_)
++    return p_->ref_count();
++  else
++    return -1;
++}
++
++// Description:
++//    Addition case a case sur toutes les cases du tableau
++// Precondition:
++//    la taille de y doit etre au moins egale a la taille de this
++// Parametre: const ArrOfDouble& y
++//    Signification: tableau a ajouter
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfDouble&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfDouble& ArrOfDouble::operator+=(const ArrOfDouble& y)
++{
++  assert(size_array()==y.size_array());
++  double* dx = addr();
++  const double* dy = y.addr();
++  const entier n = size_array();
++  for (entier i=0; i<n; i++)
++    dx[i] += dy[i];
++  return *this;
++}
++
++// Description:
++//     ajoute la meme valeur a toutes les cases du tableau
++// Precondition:
++// Parametre: const double dy
++//    Signification: valeur a ajouter
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfDouble
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfDouble& ArrOfDouble::operator+=(const double dy)
++{
++  double * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] += dy;
++  return *this;
++}
++// Description:
++//    Soustraction case a case sur toutes les cases du tableau
++// Parametre: const ArrOfDouble& y
++//    Signification: tableau de meme taille que *this
++// Retour: ArrOfDouble&
++//    Signification: *this
++ArrOfDouble& ArrOfDouble::operator-=(const ArrOfDouble& y)
++{
++  const entier size = size_array();
++  assert(size == y.size_array());
++  double * data = addr();
++  const double * data_y = y.addr();
++  for (entier i=0; i < size; i++)
++    data[i] -= data_y[i];
++  return *this;
++}
++
++
++// Description:
++//     soustrait la meme valeur a toutes les cases
++// Retour: ArrOfDouble &
++//    Signification: *this
++ArrOfDouble& ArrOfDouble::operator-=(const double dy)
++{
++  double * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] -= dy;
++  return *this;
++}
++
++// Description:
++//   Renvoie un pointeur sur le premier element du tableau.
++//   Le pointeur est nul si le tableau est "detache".
++//   Attention, l'adresse peut changer apres un appel
++//   a resize_array(), ref_data, ref_array, ...
++// Precondition:
++// Retour: const double*
++//   Signification: pointeur sur le premier element du tableau
++const double* ArrOfDouble::addr() const
++{
++  return data_;
++}
++
++// Description:
++//   Renvoie un pointeur sur le premier element du tableau.
++//   Le pointeur est nul si le tableau est "detache".
++// Precondition:
++// Retour: const double*
++//    Signification: la zone memoire du tableau
++double* ArrOfDouble::addr()
++{
++  return data_;
++}
++
++
++// Description:
++//    Retourne le max des abs(i)
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOfDouble& dx
++//    Signification: tableau a utiliser
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: double
++//    Signification: valeur du max des valeurs absolues
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++double max_abs_array(const ArrOfDouble& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  double valeur_max = fabs(dx[0]);
++  for(entier i = 1; i < size; i++)
++    {
++      const double val = fabs(dx[i]);
++      if (val > valeur_max)
++        valeur_max = val;
++    }
++  return valeur_max;
++}
++
++// Description:
++//     muliplie toutes les cases par dy
++// Retour: ArrOfDouble &
++//    Signification: *this
++ArrOfDouble& ArrOfDouble::operator*= (const double dy)
++{
++  double * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] *= dy;
++  return *this;
++}
++
++
++// Description:
++//     divise toutes les cases par dy
++// Retour: ArrOfDouble &
++//    Signification: *this
++ArrOfDouble& ArrOfDouble::operator/= (const double dy)
++{
++  // En theorie: les deux lignes suivantes sont plus efficaces, mais
++  //  cela produit des differences sur certains cas tests
++  //  (Hyd_C_VEF_Smago et Lambda_var_VEF_turb). Ca veut dire qu'il y
++  //  a un probleme autre part mais pour l'instant on laisse l'ancien
++  //  codage.
++  // const double i_dy = 1. / dy;
++  // operator*=(i_dy);
++
++  double * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] /= dy;
++
++  return *this;
++}
++
++DoubleTab::DoubleTab()
++{
++  // nb_dim_ = 2;
++  dimensions_[0] = 0;
++  dimensions_[1] = 0;
++}
++
++DoubleTab::DoubleTab(const DoubleTab& tab) :
++  ArrOfDouble(tab)
++{
++  // nb_dim_ = tab.nb_dim_;
++  dimensions_[0] = tab.dimensions_[0];
++  dimensions_[1] = tab.dimensions_[1];
++}
++DoubleTab::DoubleTab(const entier i, const entier j) :
++  ArrOfDouble(i*j)
++{
++  // nb_dim_ = 2;
++  dimensions_[0] = i;
++  dimensions_[1] = j;
++}
++
++DoubleTab& DoubleTab::operator=(const DoubleTab& tab)
++{
++  ArrOfDouble::operator=(tab);
++  // nb_dim_ = tab.nb_dim_;
++  dimensions_[0] = tab.dimensions_[0];
++  dimensions_[1] = tab.dimensions_[1];
++  return *this;
++}
++
++void DoubleTab::reset()
++{
++  ArrOfDouble::reset();
++  // nb_dim_ = 2;
++  dimensions_[0] = 0;
++  dimensions_[1] = 0;
++}
++
+diff --git a/databases/readers/Lata/ArrOfDouble.h b/databases/readers/Lata/ArrOfDouble.h
+new file mode 100644
+index 0000000..fcc08f1
+--- /dev/null
++++ b/databases/readers/Lata/ArrOfDouble.h
+@@ -0,0 +1,353 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++////////////////////////////////////////////////////////////
++//
++// Warning : DO NOT EDIT !
++//         Please update ArrOf_Scalar_Prototype.h.P
++//         and this file will be generated automatically
++//           by the script file check.sh
++////////////////////////////////////////////////////////////
++
++#ifndef ArrOfDouble_H
++#define ArrOfDouble_H
++
++#include <assert.h>
++#include <arch.h>
++#include <Objet_U.h>
++
++#if ! defined(DMAXFLOAT)
++#define DMAXFLOAT 1e40
++#endif
++
++class VDoubledata;
++
++class ArrOfDouble
++{
++public:
++  //
++  // Destructeur
++  //
++  virtual ~ArrOfDouble();
++  //
++  // Constructeurs
++  //
++  ArrOfDouble();
++  ArrOfDouble(entier size);
++  ArrOfDouble(entier size, double initial_value);
++  // Constructeur par copie : deep copy (on duplique les donnees)
++  ArrOfDouble(const ArrOfDouble& );
++  //
++  // Methodes de construction tardive (on cree un tableau vide avec ArrOfDouble()
++  // puis on appelle ces methodes pour modifier les caracteristiques du tableau :
++  //
++  // Change le nombre d'elements du tableau
++  inline ArrOfDouble& resize_array(entier new_size);
++
++  // Methodes de gestion de l'allocation memoire:
++  // Assigne une valeur au drapeau "smart_resize"
++  // (reallocation uniquement si la taille augmente)
++  void    set_smart_resize(entier flag);
++  // Gestion du type de memoire alouee (standard ou pool de memoire Trio-U)
++  enum    Storage { STANDARD, TEMP_STORAGE, SIMD_ALIGNED };
++  void    set_mem_storage(const Storage storage);
++  Storage get_mem_storage() const;
++
++  // Construction de tableaux qui pointent vers des donnees existantes
++  // !!! Utiliser ref_data avec precaution (attention a size_array_)
++  ArrOfDouble& ref_data(double* ptr, entier size);
++  ArrOfDouble& ref_array(const ArrOfDouble&);
++  // Operateur copie
++  ArrOfDouble& operator=(const ArrOfDouble&);
++  // Remise du tableau dans l'etat initial (obtenu par le constructeur par defaut)
++  virtual void reset();
++
++  //
++  // Methodes d'acces aux donnees et aux caracteristiques du tableau
++  //
++  // Remplit le tableau avec la valeur en parametre
++  ArrOfDouble& operator=(double valeur);
++
++  inline       double& operator[](entier i);
++  inline const double& operator[](entier i) const;
++
++  // Ces methodes renvoient un pointeur vers le premier element du tableau.
++  const double * addr() const;
++  double * addr();
++  // Renvoie le nombre d'elements du tableau (et non la taille allouee)
++  inline entier size_array() const;
++  // Renvoie le nombre de tableaux qui pointent vers la stucture "*p_"
++  entier ref_count() const;
++  // Ajoute une case en fin de tableau et y stocke la "valeur"
++  inline void   append_array(double valeur);
++
++  //
++  // Operateurs divers
++  //
++  ArrOfDouble& operator+=(const ArrOfDouble&);
++  ArrOfDouble& operator+=(const double);
++  ArrOfDouble& operator-=(const ArrOfDouble&);
++  ArrOfDouble& operator-=(const double);
++  ArrOfDouble& inject_array(const ArrOfDouble& source,
++                            entier nb_elements = -1,
++                            entier first_element_dest = 0,
++                            entier first_element_source = 0);
++  ArrOfDouble& copy_array(const ArrOfDouble&);
++
++  ArrOfDouble& operator*= (const double) ;
++  ArrOfDouble& operator/= (const double) ;
++
++  void             ordonne_array();
++
++protected:
++  //
++  // Methodes accessibles depuis les descendants de ArrOfDouble
++  //
++  void   attach_array(const ArrOfDouble&);
++  entier detach_array();
++  void   fill_default_value(entier first, entier nb);
++private:
++  // B. Mathieu 22/06/2004 : je mets ces membres "private" pour forcer
++  // le passage par les accesseurs dans les classes derivees, au cas ou
++  // on voudrait modifier l'implementation.
++
++  // Zone de memoire contenant les valeurs du tableau.
++  // Pointeur nul => le tableau est "detache" ou "ref_data"
++  // Pointeur non nul => le tableau est "normal"
++  VDoubledata* p_;
++
++  // Pointeur vers le premier element du tableau (egal a p_->data si p_!=0)
++  // Pointeur nul => le tableau est "detache".
++  // Pointeur non nul => le tableau est "normal" ou "ref_data"
++  double*   data_;
++
++  // Nombre d'elements du tableau (inferieur ou egal a memory_size_).
++  // Si le tableau est "detache", alors size_array_=0
++  entier    size_array_;
++  // Taille memoire reellement allouee pour le tableau
++  // (pour le mecanisme smart_resize_). memory_size_ est nul
++  // si le tableau est de type "ref_data". Sinon memory_size_
++  // est egal a p_->size_.
++  entier    memory_size_;
++
++  // Drapeau indiquant si on applique une strategie d'allocation
++  // preventive (la memoire alouee augmente d'un facteur constant
++  // si la taille devient insuffisante).
++  // Si smart_resize_ == 0, alors on a toujours p_->size_ == size
++  entier    smart_resize_;
++
++  // Drapeau indiquant si l'allocation memoire a lieu avec un new classique
++  // ou dans le pool de memoire temporaire de Trio
++  Storage   storage_type_;
++
++  // Partie non inline de resize_array():
++  // Declaration des constantes pour les options de memory_resize
++  static const entier COPY_OLD;
++  static const entier INITIALIZE_NEW;
++  void memory_resize(entier new_size, entier options);
++};
++
++#define MAXDIMDoubleTab 2
++
++class DoubleTab : public ArrOfDouble
++{
++public:
++  DoubleTab();
++  DoubleTab(const DoubleTab&);
++  DoubleTab(const entier i, const entier j);
++  DoubleTab&    operator=(const DoubleTab&);
++  void              reset();
++
++  inline double& operator()(entier i, entier j);
++  inline double   operator()(entier i, entier j) const;
++
++  inline entier resize(entier i, entier j);
++  inline entier dimension(entier i) const;
++  inline entier dimension_tot(entier i) const;
++
++protected:
++  // In order to mimic TRUST behavior, operator[] is forbidden
++  // for 2 dimensionnal matrices, you must cast to ArrOf to use it..
++  double&        operator[](entier i);
++  const double& operator[](entier i) const;
++
++private:
++  //  entier nb_dim_;
++  entier dimensions_[MAXDIMDoubleTab];
++};
++
++inline double& DoubleTab::operator()(entier i, entier j)
++{
++  // assert(nb_dim_ == 2);
++  assert(i >= 0 && i < dimensions_[0] && j >= 0 && j < dimensions_[1]);
++  const entier n = i * dimensions_[1] + j;
++  double& x = ArrOfDouble::operator[] (n);
++  return x;
++}
++
++inline double   DoubleTab::operator()(entier i, entier j) const
++{
++  // assert(nb_dim_ == 2);
++  assert(i >= 0 && i < dimensions_[0] && j >= 0 && j < dimensions_[1]);
++  const entier n = i * dimensions_[1] + j;
++  double x = ArrOfDouble::operator[] (n);
++  return x;
++}
++
++inline entier DoubleTab::resize(entier i, entier j)
++{
++  assert(i >= 0 && j >= 0);
++  // nb_dim_ = 2;
++  dimensions_[0] = i;
++  dimensions_[1] = j;
++  ArrOfDouble::resize_array(i * j);
++  return i*j;
++}
++
++inline entier DoubleTab::dimension(entier i) const
++{
++  assert(i >= 0 && i < 2);
++  return dimensions_[i];
++}
++
++// Description: renvoie la meme valeur que dimension.
++inline entier DoubleTab::dimension_tot(entier i) const
++{
++  return dimension(i);
++}
++
++//
++// Declarations des fonctions non membres de la classe ArrOfDouble
++//
++entier operator==(const ArrOfDouble& x, const ArrOfDouble& y) ;
++entier imin_array(const ArrOfDouble&) ;
++entier imax_array(const ArrOfDouble&) ;
++double min_array(const ArrOfDouble&) ;
++double max_array(const ArrOfDouble&) ;
++
++double max_abs_array(const ArrOfDouble&) ;
++
++// ******************************************************************
++//                   FONCTIONS MEMBRES DE ArrOfDouble
++// ******************************************************************
++
++// Description :
++//  Change le nombre d'elements du tableau. Cette fonction est inline
++//  car elle doit etre tres rapide dans le cas ou smart_resize_==1
++//  (utilisation frequente de resize_array())
++//  Si smart_resize est non nul :
++//   Si la nouvelle taille est inferieure ou egale a la taille
++//   alouee (p->get_size()) on ne realloue pas de memoire
++//   sinon, on realloue et on copie les donnees existantes.
++//  Astuce pour ne pas copier les anciennes donnees:
++//   resize(0); resize(n);
++//  Si smart_resize est nul, on realloue une nouvelle zone memoire
++//   uniquement si la nouvelle taille est differente de l'ancienne.
++// Precondition :
++//  Si "new_size" est egal a la taille du tableau, aucune condition.
++//  Sinon, le tableau doit etre soit detache, soit normal (pas de type "ref_data")
++//  et ref_count doit etre egal a 1 (pas d'autre reference au tableau).
++//
++inline ArrOfDouble& ArrOfDouble::resize_array(entier new_size)
++{
++  assert(new_size >= 0);
++  // Soit le tableau est detache (data_==0), soit il est normal (p_!=0)
++  // S'il est normal, il ne faut pas qu'il y ait d'autre reference au tableau,
++  // ou alors la taille ne doit pas changer.
++  assert(new_size == size_array_ || data_ == 0 || (p_ != 0 && ref_count() == 1));
++
++  if ((smart_resize_ == 0) || (new_size > memory_size_))
++    memory_resize(new_size, COPY_OLD + INITIALIZE_NEW);
++  size_array_ = new_size;
++  return *this;
++}
++
++// Description:
++//     operateur [] retourne le ieme element du tableau
++// Precondition:
++// Parametre: entier i
++//    Signification: indice dans l'intervalle 0 <= i < size_array()
++// Exception:
++//    assert si la valeur sort de l'intervalle : [ -DMAXFLOAT,DMAXFLOAT ]
++//    assert si i n'est pas dans l'intervalle
++inline double& ArrOfDouble::operator[](entier i)
++{
++  assert(i >= 0 && i < size_array_);
++  assert((smart_resize_==1)|| (data_[i] > -DMAXFLOAT && data_[i] < DMAXFLOAT));
++  return data_[i];
++}
++
++// Description:
++//     operateur [] retourne le ieme element du tableau
++// Precondition:
++// Parametre: entier i
++//    Signification: indice dans l'intervalle 0 <= i < size_array()
++// Exception:
++//    assert si la valeur sort de l'intervalle : [ -DMAXFLOAT,DMAXFLOAT ]
++//    assert si i n'est pas dans l'intervalle
++inline const double& ArrOfDouble::operator[](entier i) const
++{
++  assert(i >= 0 && i < size_array_);
++  assert(data_[i] > -DMAXFLOAT && data_[i] < DMAXFLOAT);
++  return data_[i];
++}
++
++// Description:
++//    Renvoie la taille du tableau (nombre d'elements declares
++//    a la construction ou a resize_array()).
++//    C'est le nombre d'elements accessibles a operator[]
++// Retour: entier
++inline entier  ArrOfDouble::size_array() const
++{
++  return size_array_;
++}
++
++// Description:
++//  Ajoute une case en fin de tableau et y stocke la "valeur"
++// Precondition:
++//  Tableau doit etre de type "smart_resize" (sinon, ecroulement
++//  des performances). De plus, le tableau ne doit pas etre "ref_data",
++//  et il ne doit pas y avoir plus d'une reference a la zone de
++//  memoire pointee (meme precondition que resize_array())
++inline void   ArrOfDouble::append_array(double valeur)
++{
++  assert(smart_resize_);
++  // Soit le tableau est detache (data_==0), soit il est normal (p_!=0)
++  // S'il est normal, il ne faut pas qu'il y ait d'autre reference au tableau.
++  assert(data_ == 0 || (p_ != 0 && ref_count() == 1));
++
++  if (size_array_+1 > memory_size_)
++    memory_resize(size_array_+1, COPY_OLD);
++  data_[size_array_] = valeur;
++  size_array_++;
++}
++
++// ArrOfDouble_H
++#endif
++
+diff --git a/databases/readers/Lata/ArrOfFloat.C b/databases/readers/Lata/ArrOfFloat.C
+new file mode 100644
+index 0000000..dd59a24
+--- /dev/null
++++ b/databases/readers/Lata/ArrOfFloat.C
+@@ -0,0 +1,1185 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++////////////////////////////////////////////////////////////
++//
++// Warning : DO NOT EDIT !
++//         Please update ArrOf_Scalar_Prototype.cpp.h
++//         and this file will be generated automatically
++//           by the script file check.sh
++////////////////////////////////////////////////////////////
++
++#include <ArrOfFloat.h>
++#include <math.h>
++#include <stdlib.h>
++#include <Objet_U.h>
++#include <iostream>
++#include <stdlib.h>
++#include <string.h>
++#include "simd_interface.h"
++
++using namespace std;
++
++// ******************************************************************
++//
++//             Implementation des methodes de VFloatdata
++//
++// ******************************************************************
++////////////////////////////////////////////////////////////////////
++// .NOM        ArrOfFloat
++// .ENTETE     TRUST Math
++// .LIBRAIRIE  libtmath
++// .FILE       ArrOfFloat.h
++// .FILE       ArrOfFloat.cpp
++//
++// .DESCRIPTION
++// VFloatdata alloue une zone de memoire de la taille specifiee au
++// constructeur, et libere la zone de memoire a la destruction.
++//
++// "ref_count" compte le nombre de pointeurs qui font reference a "this".
++// (permet au dernier utilisateur de l'objet de le detruire), voir
++// ArrOfFloat.
++//
++// .SECTION voir aussi
++// .CONTRAINTES
++// .INVARIANTS
++// .HTML
++// .EPS
++///////////////////////////////////////////////////////////////////
++
++class VFloatdata
++{
++public:
++  VFloatdata(entier size, ArrOfFloat::Storage storage);
++  ~VFloatdata();
++  entier          add_one_ref();
++  entier          suppr_one_ref();
++  float *        get_data();
++  const float *  get_data() const;
++  inline entier   ref_count() const;
++  inline entier   get_size() const;
++private:
++  // Le constructeur par copie et l'operateur= sont interdits.
++  VFloatdata(const VFloatdata& v);
++  VFloatdata& operator=(const VFloatdata& v);
++
++  // "data" est un pointeur sur une zone de memoire de taille
++  // sz * sizeof(float), allouee par le
++  // constructeur et liberee par le destructeur.
++  // Ce pointeur n'est jamais nul meme si size_==0
++  float * data_;
++  // Compteur incremente par add_one_ref et decremente par suppr_one_ref.
++  // Contient le nombre d'objets ArrOfFloat dont le membre "p" pointe
++  // vers "this". On a ref_count_ >= 0.
++  entier ref_count_;
++  // "sz" est la taille du tableau "data_" alloue
++  // On a sz >= 0.
++  entier size_;
++  ArrOfFloat::Storage storage_;
++};
++
++
++// Description:
++//    Construit un VFloatdata de taille size >= 0
++// Parametre: entier s
++//    Signification: taille du VFloatdata, il faut size >= 0
++// Parametre: Storage storage
++//    Signification: indique si la memoire doit etre allouee
++//                   avec "new" ou avec "simd_malloc"
++//    Valeurs par defaut: STANDARD (allocation avec "new")
++// Postcondition:
++//    data_ n'est jamais nul, meme si size==0
++VFloatdata::VFloatdata(entier size, ArrOfFloat::Storage storage)
++{
++  if (size == 0)
++    storage = ArrOfFloat::STANDARD;
++
++  switch (storage)
++    {
++    case ArrOfFloat::STANDARD:
++      {
++#ifdef _EXCEPTION_
++        // Allocation de la memoire sur le tas
++        try
++          {
++            data_ = new float[size];
++          }
++        catch(...)
++          {
++            Cerr << "impossible d'allouer " << size << " float " << finl;
++            throw;
++          }
++#else
++        data_ = new float[size];
++        if(!data_)
++          {
++            Cerr << "impossible d'allouer " << size << "float " << finl;
++            throw ;
++          }
++#endif
++        break;
++      }
++    case ArrOfFloat::SIMD_ALIGNED:
++      {
++#ifdef SIMD_TOOLS_H
++        data_ = (float*) simd_malloc (sizeof(float) * size);
++#else
++        Cerr<<"unable to allocate simd_aligned, version compiled without simd "<<finl;
++        throw;
++#endif
++        break;
++      }
++    default:
++      throw;
++    }
++  ref_count_ = 1;
++  size_ = size;
++  storage_ = storage;
++  assert(data_ != 0);
++}
++
++// Description:
++//  Detruit la zone de memoire allouee.
++// Precondition:
++//  ref_count == 0 (la zone de memoire ne doit etre referencee nulle part)
++VFloatdata::~VFloatdata()
++{
++  assert(ref_count_ == 0);
++
++  // Stockage STANDARD
++  switch(storage_)
++    {
++    case ArrOfFloat::STANDARD:
++      delete[] data_;
++      break;
++    case ArrOfFloat::SIMD_ALIGNED:
++#ifdef SIMD_TOOLS_H
++      simd_free(data_);
++#else
++      Cerr<<"unable to allocate simd_aligned, version compiled without simd "<<finl;
++      throw;
++#endif
++      break;
++    default:
++      throw;
++    }
++
++  data_ = 0;  // paranoia: si size_==-1 c'est qu'on pointe sur un zombie
++  size_ = -1; //  (pointeur vers un objet qui a ete detruit)
++  storage_ = ArrOfFloat::STANDARD;
++}
++
++// Description: renvoie ref_count_
++inline entier VFloatdata::ref_count() const
++{
++  return ref_count_;
++}
++
++// Description: renvoie size_
++inline entier VFloatdata::get_size() const
++{
++  return size_;
++}
++
++// Description:
++//     Un nouveau tableau utilise cette zone memoire :
++//     incremente ref_count
++// Retour: int
++//    Signification: ref_count
++inline entier VFloatdata::add_one_ref()
++{
++  return ++ref_count_;
++}
++
++// Description:
++//     Un tableau de moins utilise cette zone memoire
++//     decremente ref_count
++// Precondition:
++//     ref_count_ > 0
++// Retour: int
++//    Signification: ref_count
++inline entier VFloatdata::suppr_one_ref()
++{
++  assert(ref_count_ > 0);
++  return (--ref_count_);
++}
++
++// Description: renvoie data_
++inline float * VFloatdata::get_data()
++{
++  return data_;
++}
++
++// Description: renvoie data_
++inline const float * VFloatdata::get_data() const
++{
++  return data_;
++}
++
++// Description: Constructeur par copie. Interdit : genere une erreur !
++VFloatdata::VFloatdata(const VFloatdata& v)
++{
++  Cerr << "Erreur dans VFloatdata::VFloatdata(const VFloatdata & v)" << finl;
++  throw;
++}
++
++// Description: Operateur= interdit. Genere une erreur !
++VFloatdata& VFloatdata::operator=(const VFloatdata& v)
++{
++  Cerr << "Erreur dans VFloatdata::operator=(const VFloatdata & v)" << finl;
++  throw;
++  return *this;
++}
++
++// ******************************************************************
++//
++//             Implementation des methodes de ArrOfFloat
++//
++// ******************************************************************
++
++
++// Definition des constantes pour les options de memory_resize
++const entier ArrOfFloat::COPY_OLD = 1;
++const entier ArrOfFloat::INITIALIZE_NEW = 2;
++
++// Description:
++//  Destructeur : appelle detach_array()
++ArrOfFloat::~ArrOfFloat()
++{
++  detach_array();
++  size_array_ = -1; // Paranoia: si size_array_==-1, c'est un zombie
++}
++
++// Description:
++//  Constructeur par defaut: cree un tableau "detache",
++//  soit p_==0, data_==0, size_array_==0, smart_resize_==0
++ArrOfFloat::ArrOfFloat() :
++  p_(0),
++  data_(0),
++  size_array_(0),
++  memory_size_(0),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++}
++
++// Description:
++//     Cree un tableau de taille n avec allocation standard
++//     (voir set_mem_storage).
++//     Valeur de remplissage par defaut: voir fill_default_value
++// Precondition:
++// Parametre: entier n
++//    Signification: taille du tableau
++ArrOfFloat::ArrOfFloat(entier n) :
++  p_(new VFloatdata(n, STANDARD)),
++  data_(p_->get_data()),
++  size_array_(n),
++  memory_size_(n),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++  if (n > 0)
++    fill_default_value(0, n);
++}
++
++// Description:
++//     Cree un tableau de taille n
++//     toutes les cases sont initialisees a x
++// Precondition:
++// Parametre: entier n
++//    Signification: taille du tableau
++// Parametre: float x
++//    Signification: valeur pour initialiser le tableau
++ArrOfFloat::ArrOfFloat(entier n, float x) :
++  p_(new VFloatdata(n, STANDARD)),
++  data_(p_->get_data()),
++  size_array_(n),
++  memory_size_(n),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++  *this = x;
++}
++
++// Description:
++//     Constructeur par copie. On alloue une nouvelle zone de memoire
++//     et on copie le contenu du tableau. L'attribut smart_resize_ est
++//     copie aussi.
++//     Si le tableau A est de taille nulle, on cree un tableau "detache",
++//     sinon on cree un tableau "normal".
++// Parametre: const ArrOfFloat& A
++//    Signification: le tableau a copier
++ArrOfFloat::ArrOfFloat(const ArrOfFloat& A)
++{
++  const entier size = A.size_array();
++  if (size > 0)
++    {
++      // Creation d'un tableau "normal"
++      storage_type_ = STANDARD;
++      p_ = new VFloatdata(size, STANDARD);
++      data_ = p_->get_data();
++      size_array_ = size;
++      memory_size_ = size;
++      smart_resize_ = A.smart_resize_;
++      inject_array(A);
++    }
++  else
++    {
++      // Creation d'un tableau "detache"
++      p_ = 0;
++      data_ = 0;
++      size_array_ = 0;
++      memory_size_ = 0;
++      smart_resize_ = 0;
++      storage_type_ = STANDARD;
++    }
++}
++
++// Description:
++//   Change le mode d'allocation memoire lors des resize
++//   (voir VFloatdata et Float_ptr_trav)
++//   Exemple pour creer un tableau avec allocation temporaire:
++//    DoubleTab tab; // Creation d'un tableau vide
++//    tab.set_mem_storage(TEMP_STORAGE); // Changement de mode d'allocation
++//    tab.resize(n); // Allocation memoire
++void ArrOfFloat::set_mem_storage(const Storage storage)
++{
++  storage_type_ = storage;
++}
++
++// Description:
++//   Renvoie le mode d'allocation du tableau (qui sera utilise
++//   lors du prochain resize si changement de taille).
++//   (voir VFloatdata et Float_ptr_trav)
++enum ArrOfFloat::Storage ArrOfFloat::get_mem_storage() const
++{
++  return storage_type_;
++}
++
++// Description:
++//   Change le mode l'allocation memoire: reallocation d'un tableau
++//   a chaque changement de taille (flag = 0) ou reallocation
++//   uniquement si la taille augmente et par doublement de la taille
++//   du tableau (flag = 1).
++void ArrOfFloat::set_smart_resize(entier flag)
++{
++  assert(flag == 0 || flag == 1);
++  smart_resize_ = flag;
++}
++
++// Description:
++//    Remet le tableau dans l'etat obtenu avec le constructeur par defaut
++//    (libere la memoire mais conserve le mode d'allocation memoire actuel)
++void ArrOfFloat::reset()
++{
++  detach_array();
++}
++
++// Description:
++//    Copie les donnees du tableau m.
++//    Si "m" n'a pas la meme taille que "*this", on fait un resize_array.
++//    Ensuite, on copie les valeurs de "m" dans "*this".
++//    Le type de tableau (methode d'allocation) n'est pas copie.
++// Precondition:
++//    Si le tableau n'a pas la meme taille que "m", alors *this doit
++//    etre "resizable" (ne pas etre de type "ref_data" et "ref_count == 1")
++// Parametre: const ArrOfFloat& m
++//    Signification: la tableau a copier
++// Retour:  ArrOfFloat&
++//    Signification: *this
++ArrOfFloat& ArrOfFloat::operator=(const ArrOfFloat& m)
++{
++  if (&m != this)
++    {
++      const entier new_size = m.size_array();
++      // Le code suivant est quasiment une copie de ArrOfFloat::resize()
++      // SAUF: memory_resize est appele avec NO_INITIALIZE (la zone de memoire
++      //  n'est pas initialisee)
++      if (new_size != size_array())
++        {
++          if ((smart_resize_ == 0) || (new_size > memory_size_))
++            memory_resize(new_size, 0); // Pas d'initialisation
++          size_array_ = new_size;
++        }
++      inject_array(m);
++    }
++  return *this;
++}
++
++
++// Description:
++//     x est affecte a toutes les cases
++// Precondition:
++// Parametre: float x
++//    Signification: la valeur a affecter a toutes les cases du tableau
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfFloat&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfFloat& ArrOfFloat::operator=(float x)
++{
++  const entier n = size_array();
++  float *data = addr();
++  for (entier i = 0; i < n; i++)
++    {
++      data[i] = x;
++    }
++  return *this;
++}
++
++// Description: appelle operator=(a)
++ArrOfFloat& ArrOfFloat::copy_array(const ArrOfFloat& a)
++{
++  operator=(a);
++  return *this;
++}
++
++// Description:
++//  Si besoin, alloue une nouvelle zone de memoire,
++//  copie les donnees et efface l'ancienne zone de memoire.
++//  Attention, on suppose que cette methode est appelee par
++//  resize_array().
++//  Attention: si ref_count_>1, l'appel a resize_array() est
++//  autorise uniquement si la nouvelle taille est identique
++//  a la precedente.
++// Precondition:
++//  Le tableau doit etre de type "detache" ou "normal" avec
++//  ref_count==1, et il faut new_size >= 0
++//  On suppose que size_array contient encore le nombre d'elements
++//  valides avant changement de taille.
++// Parametre: new_size
++//  Signification: nouvelle taille demandee pour le tableau.
++// Parametre: options
++//  Signification: COPY_OLD => on recopie les anciennes donnees dans le nouveau
++//                  tableau (jusqu'au max de l'ancienne et de la nouvelle taille).
++//                 INITIALIZE_NEW => initialisation des cases non copiees
++// Postcondition:
++//  p_ et data_ sont mis a jour, mais pas size_array_ !!!
++//  (on suppose que c'est fait dans resize_array()).
++//  Si la nouvelle taille est nulle, on detache le tableau.
++void  ArrOfFloat::memory_resize(entier new_size, entier options)
++{
++  assert(new_size >= 0);
++
++  // Occupation memoire de l'ancien tableau:
++  entier old_mem_size = 0;
++  if (p_)
++    old_mem_size = p_->get_size();
++
++  // Occupation memoire du nouveau tableau :
++  // Si smart_resize, on prend au moins deux fois la taille
++  // precedente, ou new_size
++  entier new_mem_size = new_size;
++  if (smart_resize_ && (old_mem_size * 2 > new_size))
++    new_mem_size = old_mem_size * 2;
++
++  if (new_mem_size != old_mem_size)
++    {
++      // detach_array() efface le contenu de size_array_. On le met de cote:
++      const entier old_size_array = size_array_;
++      // On va reellement changer l'adresse du tableau.
++      // Il ne faut pas qu'il existe d'autre reference a ce tableau.
++      assert(data_ == 0 || (p_ != 0 && ref_count() == 1));
++      if (new_mem_size == 0)
++        {
++          // La nouvelle taille est nulle, on cree un tableau "detache"
++          detach_array();
++        }
++      else
++        {
++          // Allocation d'une nouvelle zone
++          VFloatdata * new_p = new VFloatdata(new_mem_size, storage_type_);
++          float * new_data = new_p->get_data();
++          // Raccourci si le tableau etait "detache", inutile de copier
++          // les anciennes donnees. On copie si COPY_OLD est demande
++          entier copy_size = 0;
++          if (data_ != 0)
++            {
++              // Calcul du nombre d'elements a copier vers la nouvelle
++              // zone de memoire : c'est le min de l'ancienne et de
++              // la nouvelle taille.
++              if (options & COPY_OLD)
++                {
++                  copy_size = size_array_;
++                  if (new_size < copy_size)
++                    copy_size = new_size;
++                  // Copie des valeurs dans le nouveau tableau
++                  for (entier i = 0; i < copy_size; i++)
++                    new_data[i] = data_[i];
++                }
++              // Destruction de l'ancienne zone (si plus aucune reference)
++              detach_array();
++            }
++          // On attache la nouvelle zone de memoire
++          p_ = new_p;
++          data_ = new_data;
++          memory_size_ = new_mem_size;
++          // Initialisation des cases supplementaires avec une valeur par defaut
++          if (options & INITIALIZE_NEW)
++            fill_default_value(copy_size, new_mem_size - copy_size);
++          // Restaure l'ancienne valeur de size_array_
++          size_array_ = old_size_array;
++        }
++    }
++}
++
++// Description:
++//  Remplit "nb" cases consecutives du tableau a partir de la case "first"
++//  avec une valeur par defaut.
++//  Cette fonction est appelee lors d'un resize pour initialiser les
++//  cases nouvellement creees.
++//  Le comportement depend actuellement du type de tableau :
++//  * Tableau de type "smart_resize":
++//    * en mode debug (macro NDEBUG non definie) le tableau est initialise
++//      avec une valeur invalide.
++//    * en optimise, le tableau n'est pas initialise
++//  * Tableau normal :
++//    Le tableau est initialise avec la valeur 0. Ce comportement est choisi
++//    pour des raisons de compatibilite avec l'implementation precedente.
++//    Cette specification pourrait etre modifiee prochainement pour des raisons
++//    de performances (pour ne pas avoir a initialiser inutilement les tableaux).
++//    DONC: il faut supposer desormais que les nouvelles cases ne sont pas
++//    initialisees lors d'un resize.
++// Parametre: first
++//  Signification: premiere case a initialiser.
++//  Contrainte:    (nb==0) ou (0 <= first < memory_size_)
++// Parametre: nb
++//  Signification: nombre de cases a initialiser.
++//  Contrainte:    (nb==0) ou (0 < nb <= memory_size_ - first)
++void  ArrOfFloat::fill_default_value(entier first, entier nb)
++{
++  assert((nb == 0) || (first >= 0 && first < memory_size_));
++  assert((nb == 0) || (nb > 0 && nb <= memory_size_ - first));
++  float * data = addr();
++  assert(data!=0 || nb==0);
++  data += first;
++  if (smart_resize_)
++    {
++      /*
++          // On initialise uniquement en mode debug
++      #ifndef NDEBUG
++          // Ceci represente un NAN. N'importe quelle operation avec ca fait encore un NAN.
++          // Si c'est pas portable, on peut remplacer par DMAX_FLOAT sur les autres machines.
++          static const unsigned long long  VALEUR_INVALIDE =
++            0x7ff7ffffffffffffULL;
++
++          // On utilise "memcpy" et non "=" car "=" peut provoquer une exception
++          // si la copie passe par le fpu.
++          for (entier i = 0; i < nb; i++)
++            memcpy(data + i, & VALEUR_INVALIDE, sizeof(float));
++      #endif
++      */
++    }
++  else
++    {
++      // Comportement pour les tableaux normaux : compatibilite avec la
++      // version precedente : on initialise avec 0.
++      for (entier i = 0; i < nb; i++)
++        data[i] = (float) 0;
++    }
++}
++
++// ****************************************************************
++//
++//         Fonctions non membres de la classe ArrOfFloat
++//
++// ****************************************************************
++
++// Description:
++//  Renvoie 1 si les tableaux "v" et "a" sont de la meme taille
++//  et contiennent les memes valeurs au sens strict, sinon renvoie 0.
++//  Le test est !(v[i]!=a[i])
++entier operator==(const ArrOfFloat& v, const ArrOfFloat& a)
++{
++  const entier n = v.size_array();
++  const entier na = a.size_array();
++  entier resu = 1;
++  if (n != na)
++    {
++      resu = 0;
++    }
++  else
++    {
++      const float* vv = v.addr();
++      const float* av = a.addr();
++      entier i;
++      for (i = 0; i < n; i++)
++        {
++          if (av[i] != vv[i])
++            {
++              resu = 0;
++              break;
++            }
++        }
++    }
++  return resu;
++}
++
++// Description:
++//    Retourne l'indice du min ou -1 si le tableau est vide
++// Precondition:
++// Parametre: const ArrOfFloat& dx
++//    Signification: tableau a utiliser
++// Retour: int
++//    Signification: indice du min
++entier imin_array(const ArrOfFloat& dx)
++{
++  entier indice_min = -1;
++  const entier size = dx.size_array();
++  if (size > 0)
++    {
++      indice_min = 0;
++      float valeur_min = dx[0];
++      for(entier i = 1; i < size; i++)
++        {
++          const float val = dx[i];
++          if(val < valeur_min)
++            {
++              indice_min = i;
++              valeur_min = val;
++            }
++        }
++    }
++  return indice_min;
++}
++
++// Description:
++//    Retourne l'indice du max ou -1 si le tableau est vide
++// Precondition:
++// Parametre: const ArrOfFloat& dx
++//    Signification: tableau a utiliser
++// Retour: int
++//    Signification: indice du max
++entier imax_array(const ArrOfFloat& dx)
++{
++  entier indice_max = -1;
++  const entier size = dx.size_array();
++  if (size > 0)
++    {
++      indice_max = 0;
++      float valeur_max = dx[0];
++      for(entier i = 1; i < size; i++)
++        {
++          const float val = dx[i];
++          if(val > valeur_max)
++            {
++              indice_max = i;
++              valeur_max = val;
++            }
++        }
++    }
++  return indice_max;
++}
++
++// Description:
++//    Retourne la valeur minimale
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOfFloat& dx
++//    Signification: tableau a utiliser
++// Retour: float
++//    Signification: valeur du min
++float min_array(const ArrOfFloat& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  float valeur_min = dx[0];
++  for(entier i = 1; i < size; i++)
++    {
++      const float val = dx[i];
++      if (val < valeur_min)
++        valeur_min = val;
++    }
++  return valeur_min;
++}
++
++// Description:
++//    Retourne la valeur maximale
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOfFloat& dx
++//    Signification: tableau a utiliser
++// Retour: float
++//    Signification: valeur du max
++float max_array(const ArrOfFloat& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  float valeur_max = dx[0];
++  for(entier i = 1; i < size; i++)
++    {
++      const float val = dx[i];
++      if (val > valeur_max)
++        valeur_max = val;
++    }
++  return valeur_max;
++}
++
++// Description:
++//   Fonction de comparaison utilisee pour trier le tableau
++//   dans ArrOfFloat::trier(). Voir man qsort
++static int fonction_compare_arroffloat_ordonner(const void * data1, const void * data2)
++{
++  const float x = *(const float*)data1;
++  const float y = *(const float*)data2;
++  if (x < y)
++    return -1;
++  else if (x > y)
++    return 1;
++  else
++    return 0;
++}
++
++// Description:
++//   Tri des valeurs du tableau dans l'ordre croissant.
++//   La fonction utilisee est qsort de stdlib (elle est en n*log(n)).
++void ArrOfFloat::ordonne_array()
++{
++  const entier size = size_array();
++  if (size > 1)
++    {
++      float * data = addr();
++      qsort(data, size, sizeof(float),
++            fonction_compare_arroffloat_ordonner);
++    }
++}
++
++// Description:
++//    Fait pointer le tableau vers les memes donnees qu'un tableau
++//    existant. Le tableau sera du meme type que le tableau m ("detache",
++//    "normal"). Le tableau m ne doit pas etre de type "ref_data"
++//    Les donnes existantes sont perdues si elles
++//    ne sont pas referencees ailleurs.
++// Precondition:
++// Parametre: const ArrOfFloat& m
++//    Signification: le tableau a referencer (pas de type "ref_data"
++//                   et different de *this !!!)
++// Retour: ArrOfFloat&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfFloat& ArrOfFloat::ref_array(const ArrOfFloat& m)
++{
++  assert(&m != this);
++  // La condition 'm n'est pas de type "ref_data"' est necessaire pour
++  // attach_array().
++  detach_array();
++  attach_array(m);
++  return *this;
++}
++
++// Description:
++//    Fait pointer le tableau vers la zone de memoire "data_".
++//    On detache la zone de memoire existante. Le tableau devient
++//    de type "ref_data". Attention : ptr doit etre non nul.
++//    La taille est initialisee avec size.
++//    Cette methode est appelee notamment par FloatVect::adopter.
++// Parametre: float*
++//    Signification: le tableau a recuperer. Si pointeur nul alors size
++//                   doit etre nulle aussi et le tableau reste detache
++// Parametre: entier size
++//    Signification: le nombre d'elements du tableau.
++// Retour: ArrOfFloat&
++//    Signification: *this
++ArrOfFloat& ArrOfFloat::ref_data(float* ptr, entier size)
++{
++  assert(ptr != 0 || size == 0);
++  assert(size >= 0);
++  detach_array();
++  data_ = ptr;
++  size_array_ = size;
++  return *this;
++}
++
++// Description:
++//  Amene le tableau dans l'etat "detache". C'est a dire:
++//  Si le tableau est "detache" :
++//   * ne rien faire
++//  Si le tableau est "normal" :
++//   * decremente le nombre de references a *p
++//   * detruit *p si p->ref_count==0
++//   * annule p_, data_ et size_array_
++//  Si le tableau est "ref_data" :
++//   * annule data_ et size_array_
++// Retour: int
++//    Signification: 1 si les donnees du tableau ont ete supprimees
++// Precondition:
++// Postcondition:
++//  On a p_==0, data_==0 et size_array_==0, memory_size_ = 0
++//  L'attribut smart_resize_ est conserve.
++entier ArrOfFloat::detach_array()
++{
++  entier retour = 0;
++  if (p_)
++    {
++      // Le tableau est de type "normal"
++      // Si la zone de memoire n'est plus utilisee par personne,
++      // on la detruit.
++      if ((p_->suppr_one_ref()) == 0)
++        {
++          delete p_;
++          retour = 1;
++        }
++      p_ = 0;
++    }
++  data_ = 0;
++  size_array_ = 0;
++  memory_size_ = 0;
++  return retour;
++}
++
++// Description:
++//    Amene le tableau dans l'etat "normal", "detache" ou "ref_array"
++//    en associant la meme zone de memoire que le tableau m.
++// Precondition:
++//    Le tableau doit etre "detache"
++// Parametre: const ArrOfFloat& m
++//    Signification: tableau a utiliser
++//                   le tableau doit etre different de *this !!!
++// Retour:
++//    Signification:
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++//    Si m est detache, le tableau reste detache,
++//    si m est "ref_array", le tableau devient "ref_array",
++//    sinon le tableau est "normal", avec ref_count > 1
++//    Si m est de taille nulle, le tableau reste detache + Warning dans fichier .log
++void ArrOfFloat::attach_array(const ArrOfFloat& m)
++{
++  // Le tableau doit etre detache
++  assert(data_ == 0 && p_ == 0);
++  // Le tableau doit etre different de *this
++  assert(&m != this);
++
++  if (m.size_array() > 0)
++    {
++      p_ = m.p_;
++      if (p_)
++        p_->add_one_ref();
++      data_ = m.data_;
++      size_array_ = m.size_array_;
++      memory_size_ = m.memory_size_;
++      smart_resize_ = m.smart_resize_;
++    }
++  else
++    {
++      // Cas particulier ou on attache un tableau de taille nulle:
++      //  en theorie, c'est pareil qu'un tableau de taille non nulle, MAIS
++      //  dans les operateurs (ex:Op_Dift_VDF_Face_Axi), une ref est construite
++      //  avant que le tableau ne prenne sa taille definitive. Donc, pour ne pas
++      //  empecher le resize, il ne faut pas attacher le tableau s'il n'a pas
++      //  encore la bonne taille. Solution propre: reecrire les operateurs pour
++      //  qu'ils ne prennent pas une ref avant que le tableau ne soit valide
++      //  et faire p_ = m.p_ dans tous les cas.
++    }
++}
++
++// Description:
++//    Copie les elements source[first_element_source + i]
++//    dans les elements  (*this)[first_element_dest + i] pour 0 <= i < nb_elements
++//    Les autres elements de (*this) sont inchanges.
++// Precondition:
++// Parametre:       const ArrOfFloat& m
++//  Signification:   le tableau a utiliser, doit etre different de *this !
++// Parametre:       entier nb_elements
++//  Signification:   nombre d'elements a copier, nb_elements >= -1.
++//                   Si nb_elements==-1, on copie tout le tableau m.
++//  Valeurs par defaut: -1
++// Parametre:       entier first_element_dest
++//  Valeurs par defaut: 0
++// Parametre:       entier first_element_source
++//  Valeurs par defaut: 0
++// Retour: ArrOfFloat&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++//    Sort en erreur si la taille du tableau m est plus grande que la
++//    taille de tableau this.
++// Effets de bord:
++// Postcondition:
++ArrOfFloat& ArrOfFloat::inject_array(const ArrOfFloat& source,
++                                     entier nb_elements,
++                                     entier first_element_dest,
++                                     entier first_element_source)
++{
++  assert(&source != this);
++  assert(nb_elements >= -1);
++  assert(first_element_dest >= 0);
++  assert(first_element_source >= 0);
++
++  if (nb_elements < 0)
++    nb_elements = source.size_array();
++
++  assert(first_element_source + nb_elements <= source.size_array());
++  assert(first_element_dest + nb_elements <= size_array());
++
++  if (nb_elements > 0)
++    {
++      float * addr_dest = addr() + first_element_dest;
++      const float * addr_source = source.addr() + first_element_source;
++      // memcpy(addr_dest , addr_source, nb_elements * sizeof(float));
++      entier i;
++      for (i = 0; i < nb_elements; i++)
++        {
++          addr_dest[i] = addr_source[i];
++        }
++    }
++  return *this;
++}
++
++// Description:
++//    Retourne le nombre de references des donnees du tableau
++//    si le tableau est "normal", -1 s'il est "detache" ou "ref_data"
++// Retour: int
++//    Signification: ref_count_
++entier ArrOfFloat::ref_count() const
++{
++  if (p_)
++    return p_->ref_count();
++  else
++    return -1;
++}
++
++// Description:
++//    Addition case a case sur toutes les cases du tableau
++// Precondition:
++//    la taille de y doit etre au moins egale a la taille de this
++// Parametre: const ArrOfFloat& y
++//    Signification: tableau a ajouter
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfFloat&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfFloat& ArrOfFloat::operator+=(const ArrOfFloat& y)
++{
++  assert(size_array()==y.size_array());
++  float* dx = addr();
++  const float* dy = y.addr();
++  const entier n = size_array();
++  for (entier i=0; i<n; i++)
++    dx[i] += dy[i];
++  return *this;
++}
++
++// Description:
++//     ajoute la meme valeur a toutes les cases du tableau
++// Precondition:
++// Parametre: const float dy
++//    Signification: valeur a ajouter
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfFloat
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfFloat& ArrOfFloat::operator+=(const float dy)
++{
++  float * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] += dy;
++  return *this;
++}
++// Description:
++//    Soustraction case a case sur toutes les cases du tableau
++// Parametre: const ArrOfFloat& y
++//    Signification: tableau de meme taille que *this
++// Retour: ArrOfFloat&
++//    Signification: *this
++ArrOfFloat& ArrOfFloat::operator-=(const ArrOfFloat& y)
++{
++  const entier size = size_array();
++  assert(size == y.size_array());
++  float * data = addr();
++  const float * data_y = y.addr();
++  for (entier i=0; i < size; i++)
++    data[i] -= data_y[i];
++  return *this;
++}
++
++
++// Description:
++//     soustrait la meme valeur a toutes les cases
++// Retour: ArrOfFloat &
++//    Signification: *this
++ArrOfFloat& ArrOfFloat::operator-=(const float dy)
++{
++  float * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] -= dy;
++  return *this;
++}
++
++// Description:
++//   Renvoie un pointeur sur le premier element du tableau.
++//   Le pointeur est nul si le tableau est "detache".
++//   Attention, l'adresse peut changer apres un appel
++//   a resize_array(), ref_data, ref_array, ...
++// Precondition:
++// Retour: const float*
++//   Signification: pointeur sur le premier element du tableau
++const float* ArrOfFloat::addr() const
++{
++  return data_;
++}
++
++// Description:
++//   Renvoie un pointeur sur le premier element du tableau.
++//   Le pointeur est nul si le tableau est "detache".
++// Precondition:
++// Retour: const float*
++//    Signification: la zone memoire du tableau
++float* ArrOfFloat::addr()
++{
++  return data_;
++}
++
++
++// Description:
++//    Retourne le max des abs(i)
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOfFloat& dx
++//    Signification: tableau a utiliser
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: float
++//    Signification: valeur du max des valeurs absolues
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++float max_abs_array(const ArrOfFloat& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  float valeur_max = fabs(dx[0]);
++  for(entier i = 1; i < size; i++)
++    {
++      const float val = fabs(dx[i]);
++      if (val > valeur_max)
++        valeur_max = val;
++    }
++  return valeur_max;
++}
++
++// Description:
++//     muliplie toutes les cases par dy
++// Retour: ArrOfFloat &
++//    Signification: *this
++ArrOfFloat& ArrOfFloat::operator*= (const float dy)
++{
++  float * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] *= dy;
++  return *this;
++}
++
++
++// Description:
++//     divise toutes les cases par dy
++// Retour: ArrOfFloat &
++//    Signification: *this
++ArrOfFloat& ArrOfFloat::operator/= (const float dy)
++{
++  // En theorie: les deux lignes suivantes sont plus efficaces, mais
++  //  cela produit des differences sur certains cas tests
++  //  (Hyd_C_VEF_Smago et Lambda_var_VEF_turb). Ca veut dire qu'il y
++  //  a un probleme autre part mais pour l'instant on laisse l'ancien
++  //  codage.
++  // const float i_dy = 1. / dy;
++  // operator*=(i_dy);
++
++  float * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] /= dy;
++
++  return *this;
++}
++
++FloatTab::FloatTab()
++{
++  // nb_dim_ = 2;
++  dimensions_[0] = 0;
++  dimensions_[1] = 0;
++}
++
++FloatTab::FloatTab(const FloatTab& tab) :
++  ArrOfFloat(tab)
++{
++  // nb_dim_ = tab.nb_dim_;
++  dimensions_[0] = tab.dimensions_[0];
++  dimensions_[1] = tab.dimensions_[1];
++}
++FloatTab::FloatTab(const entier i, const entier j) :
++  ArrOfFloat(i*j)
++{
++  // nb_dim_ = 2;
++  dimensions_[0] = i;
++  dimensions_[1] = j;
++}
++
++FloatTab& FloatTab::operator=(const FloatTab& tab)
++{
++  ArrOfFloat::operator=(tab);
++  // nb_dim_ = tab.nb_dim_;
++  dimensions_[0] = tab.dimensions_[0];
++  dimensions_[1] = tab.dimensions_[1];
++  return *this;
++}
++
++void FloatTab::reset()
++{
++  ArrOfFloat::reset();
++  // nb_dim_ = 2;
++  dimensions_[0] = 0;
++  dimensions_[1] = 0;
++}
++
+diff --git a/databases/readers/Lata/ArrOfFloat.h b/databases/readers/Lata/ArrOfFloat.h
+new file mode 100644
+index 0000000..f80d4ee
+--- /dev/null
++++ b/databases/readers/Lata/ArrOfFloat.h
+@@ -0,0 +1,353 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++////////////////////////////////////////////////////////////
++//
++// Warning : DO NOT EDIT !
++//         Please update ArrOf_Scalar_Prototype.h.P
++//         and this file will be generated automatically
++//           by the script file check.sh
++////////////////////////////////////////////////////////////
++
++#ifndef ArrOfFloat_H
++#define ArrOfFloat_H
++
++#include <assert.h>
++#include <arch.h>
++#include <Objet_U.h>
++
++#if ! defined(DMAXFLOAT)
++#define DMAXFLOAT 1e40
++#endif
++
++class VFloatdata;
++
++class ArrOfFloat
++{
++public:
++  //
++  // Destructeur
++  //
++  virtual ~ArrOfFloat();
++  //
++  // Constructeurs
++  //
++  ArrOfFloat();
++  ArrOfFloat(entier size);
++  ArrOfFloat(entier size, float initial_value);
++  // Constructeur par copie : deep copy (on duplique les donnees)
++  ArrOfFloat(const ArrOfFloat& );
++  //
++  // Methodes de construction tardive (on cree un tableau vide avec ArrOfFloat()
++  // puis on appelle ces methodes pour modifier les caracteristiques du tableau :
++  //
++  // Change le nombre d'elements du tableau
++  inline ArrOfFloat& resize_array(entier new_size);
++
++  // Methodes de gestion de l'allocation memoire:
++  // Assigne une valeur au drapeau "smart_resize"
++  // (reallocation uniquement si la taille augmente)
++  void    set_smart_resize(entier flag);
++  // Gestion du type de memoire alouee (standard ou pool de memoire Trio-U)
++  enum    Storage { STANDARD, TEMP_STORAGE, SIMD_ALIGNED };
++  void    set_mem_storage(const Storage storage);
++  Storage get_mem_storage() const;
++
++  // Construction de tableaux qui pointent vers des donnees existantes
++  // !!! Utiliser ref_data avec precaution (attention a size_array_)
++  ArrOfFloat& ref_data(float* ptr, entier size);
++  ArrOfFloat& ref_array(const ArrOfFloat&);
++  // Operateur copie
++  ArrOfFloat& operator=(const ArrOfFloat&);
++  // Remise du tableau dans l'etat initial (obtenu par le constructeur par defaut)
++  virtual void reset();
++
++  //
++  // Methodes d'acces aux donnees et aux caracteristiques du tableau
++  //
++  // Remplit le tableau avec la valeur en parametre
++  ArrOfFloat& operator=(float valeur);
++
++  inline       float& operator[](entier i);
++  inline const float& operator[](entier i) const;
++
++  // Ces methodes renvoient un pointeur vers le premier element du tableau.
++  const float * addr() const;
++  float * addr();
++  // Renvoie le nombre d'elements du tableau (et non la taille allouee)
++  inline entier size_array() const;
++  // Renvoie le nombre de tableaux qui pointent vers la stucture "*p_"
++  entier ref_count() const;
++  // Ajoute une case en fin de tableau et y stocke la "valeur"
++  inline void   append_array(float valeur);
++
++  //
++  // Operateurs divers
++  //
++  ArrOfFloat& operator+=(const ArrOfFloat&);
++  ArrOfFloat& operator+=(const float);
++  ArrOfFloat& operator-=(const ArrOfFloat&);
++  ArrOfFloat& operator-=(const float);
++  ArrOfFloat& inject_array(const ArrOfFloat& source,
++                           entier nb_elements = -1,
++                           entier first_element_dest = 0,
++                           entier first_element_source = 0);
++  ArrOfFloat& copy_array(const ArrOfFloat&);
++
++  ArrOfFloat& operator*= (const float) ;
++  ArrOfFloat& operator/= (const float) ;
++
++  void             ordonne_array();
++
++protected:
++  //
++  // Methodes accessibles depuis les descendants de ArrOfFloat
++  //
++  void   attach_array(const ArrOfFloat&);
++  entier detach_array();
++  void   fill_default_value(entier first, entier nb);
++private:
++  // B. Mathieu 22/06/2004 : je mets ces membres "private" pour forcer
++  // le passage par les accesseurs dans les classes derivees, au cas ou
++  // on voudrait modifier l'implementation.
++
++  // Zone de memoire contenant les valeurs du tableau.
++  // Pointeur nul => le tableau est "detache" ou "ref_data"
++  // Pointeur non nul => le tableau est "normal"
++  VFloatdata* p_;
++
++  // Pointeur vers le premier element du tableau (egal a p_->data si p_!=0)
++  // Pointeur nul => le tableau est "detache".
++  // Pointeur non nul => le tableau est "normal" ou "ref_data"
++  float*   data_;
++
++  // Nombre d'elements du tableau (inferieur ou egal a memory_size_).
++  // Si le tableau est "detache", alors size_array_=0
++  entier    size_array_;
++  // Taille memoire reellement allouee pour le tableau
++  // (pour le mecanisme smart_resize_). memory_size_ est nul
++  // si le tableau est de type "ref_data". Sinon memory_size_
++  // est egal a p_->size_.
++  entier    memory_size_;
++
++  // Drapeau indiquant si on applique une strategie d'allocation
++  // preventive (la memoire alouee augmente d'un facteur constant
++  // si la taille devient insuffisante).
++  // Si smart_resize_ == 0, alors on a toujours p_->size_ == size
++  entier    smart_resize_;
++
++  // Drapeau indiquant si l'allocation memoire a lieu avec un new classique
++  // ou dans le pool de memoire temporaire de Trio
++  Storage   storage_type_;
++
++  // Partie non inline de resize_array():
++  // Declaration des constantes pour les options de memory_resize
++  static const entier COPY_OLD;
++  static const entier INITIALIZE_NEW;
++  void memory_resize(entier new_size, entier options);
++};
++
++#define MAXDIMFloatTab 2
++
++class FloatTab : public ArrOfFloat
++{
++public:
++  FloatTab();
++  FloatTab(const FloatTab&);
++  FloatTab(const entier i, const entier j);
++  FloatTab&    operator=(const FloatTab&);
++  void              reset();
++
++  inline float& operator()(entier i, entier j);
++  inline float   operator()(entier i, entier j) const;
++
++  inline entier resize(entier i, entier j);
++  inline entier dimension(entier i) const;
++  inline entier dimension_tot(entier i) const;
++
++protected:
++  // In order to mimic TRUST behavior, operator[] is forbidden
++  // for 2 dimensionnal matrices, you must cast to ArrOf to use it..
++  double&        operator[](entier i);
++  const double& operator[](entier i) const;
++
++private:
++  //  entier nb_dim_;
++  entier dimensions_[MAXDIMFloatTab];
++};
++
++inline float& FloatTab::operator()(entier i, entier j)
++{
++  // assert(nb_dim_ == 2);
++  assert(i >= 0 && i < dimensions_[0] && j >= 0 && j < dimensions_[1]);
++  const entier n = i * dimensions_[1] + j;
++  float& x = ArrOfFloat::operator[] (n);
++  return x;
++}
++
++inline float   FloatTab::operator()(entier i, entier j) const
++{
++  // assert(nb_dim_ == 2);
++  assert(i >= 0 && i < dimensions_[0] && j >= 0 && j < dimensions_[1]);
++  const entier n = i * dimensions_[1] + j;
++  float x = ArrOfFloat::operator[] (n);
++  return x;
++}
++
++inline entier FloatTab::resize(entier i, entier j)
++{
++  assert(i >= 0 && j >= 0);
++  // nb_dim_ = 2;
++  dimensions_[0] = i;
++  dimensions_[1] = j;
++  ArrOfFloat::resize_array(i * j);
++  return i*j;
++}
++
++inline entier FloatTab::dimension(entier i) const
++{
++  assert(i >= 0 && i < 2);
++  return dimensions_[i];
++}
++
++// Description: renvoie la meme valeur que dimension.
++inline entier FloatTab::dimension_tot(entier i) const
++{
++  return dimension(i);
++}
++
++//
++// Declarations des fonctions non membres de la classe ArrOfFloat
++//
++entier operator==(const ArrOfFloat& x, const ArrOfFloat& y) ;
++entier imin_array(const ArrOfFloat&) ;
++entier imax_array(const ArrOfFloat&) ;
++float min_array(const ArrOfFloat&) ;
++float max_array(const ArrOfFloat&) ;
++
++float max_abs_array(const ArrOfFloat&) ;
++
++// ******************************************************************
++//                   FONCTIONS MEMBRES DE ArrOfFloat
++// ******************************************************************
++
++// Description :
++//  Change le nombre d'elements du tableau. Cette fonction est inline
++//  car elle doit etre tres rapide dans le cas ou smart_resize_==1
++//  (utilisation frequente de resize_array())
++//  Si smart_resize est non nul :
++//   Si la nouvelle taille est inferieure ou egale a la taille
++//   alouee (p->get_size()) on ne realloue pas de memoire
++//   sinon, on realloue et on copie les donnees existantes.
++//  Astuce pour ne pas copier les anciennes donnees:
++//   resize(0); resize(n);
++//  Si smart_resize est nul, on realloue une nouvelle zone memoire
++//   uniquement si la nouvelle taille est differente de l'ancienne.
++// Precondition :
++//  Si "new_size" est egal a la taille du tableau, aucune condition.
++//  Sinon, le tableau doit etre soit detache, soit normal (pas de type "ref_data")
++//  et ref_count doit etre egal a 1 (pas d'autre reference au tableau).
++//
++inline ArrOfFloat& ArrOfFloat::resize_array(entier new_size)
++{
++  assert(new_size >= 0);
++  // Soit le tableau est detache (data_==0), soit il est normal (p_!=0)
++  // S'il est normal, il ne faut pas qu'il y ait d'autre reference au tableau,
++  // ou alors la taille ne doit pas changer.
++  assert(new_size == size_array_ || data_ == 0 || (p_ != 0 && ref_count() == 1));
++
++  if ((smart_resize_ == 0) || (new_size > memory_size_))
++    memory_resize(new_size, COPY_OLD + INITIALIZE_NEW);
++  size_array_ = new_size;
++  return *this;
++}
++
++// Description:
++//     operateur [] retourne le ieme element du tableau
++// Precondition:
++// Parametre: entier i
++//    Signification: indice dans l'intervalle 0 <= i < size_array()
++// Exception:
++//    assert si la valeur sort de l'intervalle : [ -DMAXFLOAT,DMAXFLOAT ]
++//    assert si i n'est pas dans l'intervalle
++inline float& ArrOfFloat::operator[](entier i)
++{
++  assert(i >= 0 && i < size_array_);
++  assert((smart_resize_==1)|| (data_[i] > -DMAXFLOAT && data_[i] < DMAXFLOAT));
++  return data_[i];
++}
++
++// Description:
++//     operateur [] retourne le ieme element du tableau
++// Precondition:
++// Parametre: entier i
++//    Signification: indice dans l'intervalle 0 <= i < size_array()
++// Exception:
++//    assert si la valeur sort de l'intervalle : [ -DMAXFLOAT,DMAXFLOAT ]
++//    assert si i n'est pas dans l'intervalle
++inline const float& ArrOfFloat::operator[](entier i) const
++{
++  assert(i >= 0 && i < size_array_);
++  assert(data_[i] > -DMAXFLOAT && data_[i] < DMAXFLOAT);
++  return data_[i];
++}
++
++// Description:
++//    Renvoie la taille du tableau (nombre d'elements declares
++//    a la construction ou a resize_array()).
++//    C'est le nombre d'elements accessibles a operator[]
++// Retour: entier
++inline entier  ArrOfFloat::size_array() const
++{
++  return size_array_;
++}
++
++// Description:
++//  Ajoute une case en fin de tableau et y stocke la "valeur"
++// Precondition:
++//  Tableau doit etre de type "smart_resize" (sinon, ecroulement
++//  des performances). De plus, le tableau ne doit pas etre "ref_data",
++//  et il ne doit pas y avoir plus d'une reference a la zone de
++//  memoire pointee (meme precondition que resize_array())
++inline void   ArrOfFloat::append_array(float valeur)
++{
++  assert(smart_resize_);
++  // Soit le tableau est detache (data_==0), soit il est normal (p_!=0)
++  // S'il est normal, il ne faut pas qu'il y ait d'autre reference au tableau.
++  assert(data_ == 0 || (p_ != 0 && ref_count() == 1));
++
++  if (size_array_+1 > memory_size_)
++    memory_resize(size_array_+1, COPY_OLD);
++  data_[size_array_] = valeur;
++  size_array_++;
++}
++
++// ArrOfFloat_H
++#endif
++
+diff --git a/databases/readers/Lata/ArrOfInt.C b/databases/readers/Lata/ArrOfInt.C
+new file mode 100644
+index 0000000..a4a150b
+--- /dev/null
++++ b/databases/readers/Lata/ArrOfInt.C
+@@ -0,0 +1,1110 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++////////////////////////////////////////////////////////////
++//
++// Warning : DO NOT EDIT !
++//         Please update ArrOf_Scalar_Prototype.cpp.h
++//         and this file will be generated automatically
++//           by the script file check.sh
++////////////////////////////////////////////////////////////
++
++#include <ArrOfInt.h>
++// limits.h definit INT_MIN, SHRT_MIN, ...
++#include <limits.h>
++#include <stdlib.h>
++#include <Objet_U.h>
++#include <iostream>
++#include <stdlib.h>
++#include <string.h>
++#include "simd_interface.h"
++
++using namespace std;
++
++// ******************************************************************
++//
++//             Implementation des methodes de VIntdata
++//
++// ******************************************************************
++////////////////////////////////////////////////////////////////////
++// .NOM        ArrOfInt
++// .ENTETE     TRUST Math
++// .LIBRAIRIE  libtmath
++// .FILE       ArrOfInt.h
++// .FILE       ArrOfInt.cpp
++//
++// .DESCRIPTION
++// VIntdata alloue une zone de memoire de la taille specifiee au
++// constructeur, et libere la zone de memoire a la destruction.
++//
++// "ref_count" compte le nombre de pointeurs qui font reference a "this".
++// (permet au dernier utilisateur de l'objet de le detruire), voir
++// ArrOfInt.
++//
++// .SECTION voir aussi
++// .CONTRAINTES
++// .INVARIANTS
++// .HTML
++// .EPS
++///////////////////////////////////////////////////////////////////
++
++class VIntdata
++{
++public:
++  VIntdata(entier size, ArrOfInt::Storage storage);
++  ~VIntdata();
++  entier          add_one_ref();
++  entier          suppr_one_ref();
++  entier *        get_data();
++  const entier *  get_data() const;
++  inline entier   ref_count() const;
++  inline entier   get_size() const;
++private:
++  // Le constructeur par copie et l'operateur= sont interdits.
++  VIntdata(const VIntdata& v);
++  VIntdata& operator=(const VIntdata& v);
++
++  // "data" est un pointeur sur une zone de memoire de taille
++  // sz * sizeof(entier), allouee par le
++  // constructeur et liberee par le destructeur.
++  // Ce pointeur n'est jamais nul meme si size_==0
++  entier * data_;
++  // Compteur incremente par add_one_ref et decremente par suppr_one_ref.
++  // Contient le nombre d'objets ArrOfInt dont le membre "p" pointe
++  // vers "this". On a ref_count_ >= 0.
++  entier ref_count_;
++  // "sz" est la taille du tableau "data_" alloue
++  // On a sz >= 0.
++  entier size_;
++  ArrOfInt::Storage storage_;
++};
++
++
++// Description:
++//    Construit un VIntdata de taille size >= 0
++// Parametre: entier s
++//    Signification: taille du VIntdata, il faut size >= 0
++// Parametre: Storage storage
++//    Signification: indique si la memoire doit etre allouee
++//                   avec "new" ou avec "simd_malloc"
++//    Valeurs par defaut: STANDARD (allocation avec "new")
++// Postcondition:
++//    data_ n'est jamais nul, meme si size==0
++VIntdata::VIntdata(entier size, ArrOfInt::Storage storage)
++{
++  if (size == 0)
++    storage = ArrOfInt::STANDARD;
++
++  switch (storage)
++    {
++    case ArrOfInt::STANDARD:
++      {
++#ifdef _EXCEPTION_
++        // Allocation de la memoire sur le tas
++        try
++          {
++            data_ = new entier[size];
++          }
++        catch(...)
++          {
++            Cerr << "impossible d'allouer " << size << " entier " << finl;
++            throw;
++          }
++#else
++        data_ = new entier[size];
++        if(!data_)
++          {
++            Cerr << "impossible d'allouer " << size << "entier " << finl;
++            throw ;
++          }
++#endif
++        break;
++      }
++    case ArrOfInt::SIMD_ALIGNED:
++      {
++#ifdef SIMD_TOOLS_H
++        data_ = (entier*) simd_malloc (sizeof(entier) * size);
++#else
++        Cerr<<"unable to allocate simd_aligned, version compiled without simd "<<finl;
++        throw;
++#endif
++        break;
++      }
++    default:
++      throw;
++    }
++  ref_count_ = 1;
++  size_ = size;
++  storage_ = storage;
++  assert(data_ != 0);
++}
++
++// Description:
++//  Detruit la zone de memoire allouee.
++// Precondition:
++//  ref_count == 0 (la zone de memoire ne doit etre referencee nulle part)
++VIntdata::~VIntdata()
++{
++  assert(ref_count_ == 0);
++
++  // Stockage STANDARD
++  switch(storage_)
++    {
++    case ArrOfInt::STANDARD:
++      delete[] data_;
++      break;
++    case ArrOfInt::SIMD_ALIGNED:
++#ifdef SIMD_TOOLS_H
++      simd_free(data_);
++#else
++      Cerr<<"unable to allocate simd_aligned, version compiled without simd "<<finl;
++      throw;
++#endif
++      break;
++    default:
++      throw;
++    }
++
++  data_ = 0;  // paranoia: si size_==-1 c'est qu'on pointe sur un zombie
++  size_ = -1; //  (pointeur vers un objet qui a ete detruit)
++  storage_ = ArrOfInt::STANDARD;
++}
++
++// Description: renvoie ref_count_
++inline entier VIntdata::ref_count() const
++{
++  return ref_count_;
++}
++
++// Description: renvoie size_
++inline entier VIntdata::get_size() const
++{
++  return size_;
++}
++
++// Description:
++//     Un nouveau tableau utilise cette zone memoire :
++//     incremente ref_count
++// Retour: int
++//    Signification: ref_count
++inline entier VIntdata::add_one_ref()
++{
++  return ++ref_count_;
++}
++
++// Description:
++//     Un tableau de moins utilise cette zone memoire
++//     decremente ref_count
++// Precondition:
++//     ref_count_ > 0
++// Retour: int
++//    Signification: ref_count
++inline entier VIntdata::suppr_one_ref()
++{
++  assert(ref_count_ > 0);
++  return (--ref_count_);
++}
++
++// Description: renvoie data_
++inline entier * VIntdata::get_data()
++{
++  return data_;
++}
++
++// Description: renvoie data_
++inline const entier * VIntdata::get_data() const
++{
++  return data_;
++}
++
++// Description: Constructeur par copie. Interdit : genere une erreur !
++VIntdata::VIntdata(const VIntdata& v)
++{
++  Cerr << "Erreur dans VIntdata::VIntdata(const VIntdata & v)" << finl;
++  throw;
++}
++
++// Description: Operateur= interdit. Genere une erreur !
++VIntdata& VIntdata::operator=(const VIntdata& v)
++{
++  Cerr << "Erreur dans VIntdata::operator=(const VIntdata & v)" << finl;
++  throw;
++  return *this;
++}
++
++// ******************************************************************
++//
++//             Implementation des methodes de ArrOfInt
++//
++// ******************************************************************
++
++
++// Definition des constantes pour les options de memory_resize
++const entier ArrOfInt::COPY_OLD = 1;
++const entier ArrOfInt::INITIALIZE_NEW = 2;
++
++// Description:
++//  Destructeur : appelle detach_array()
++ArrOfInt::~ArrOfInt()
++{
++  detach_array();
++  size_array_ = -1; // Paranoia: si size_array_==-1, c'est un zombie
++}
++
++// Description:
++//  Constructeur par defaut: cree un tableau "detache",
++//  soit p_==0, data_==0, size_array_==0, smart_resize_==0
++ArrOfInt::ArrOfInt() :
++  p_(0),
++  data_(0),
++  size_array_(0),
++  memory_size_(0),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++}
++
++// Description:
++//     Cree un tableau de taille n avec allocation standard
++//     (voir set_mem_storage).
++//     Valeur de remplissage par defaut: voir fill_default_value
++// Precondition:
++// Parametre: entier n
++//    Signification: taille du tableau
++ArrOfInt::ArrOfInt(entier n) :
++  p_(new VIntdata(n, STANDARD)),
++  data_(p_->get_data()),
++  size_array_(n),
++  memory_size_(n),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++  if (n > 0)
++    fill_default_value(0, n);
++}
++
++// Description:
++//     Cree un tableau de taille n
++//     toutes les cases sont initialisees a x
++// Precondition:
++// Parametre: entier n
++//    Signification: taille du tableau
++// Parametre: entier x
++//    Signification: valeur pour initialiser le tableau
++ArrOfInt::ArrOfInt(entier n, entier x) :
++  p_(new VIntdata(n, STANDARD)),
++  data_(p_->get_data()),
++  size_array_(n),
++  memory_size_(n),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++  *this = x;
++}
++
++// Description:
++//     Constructeur par copie. On alloue une nouvelle zone de memoire
++//     et on copie le contenu du tableau. L'attribut smart_resize_ est
++//     copie aussi.
++//     Si le tableau A est de taille nulle, on cree un tableau "detache",
++//     sinon on cree un tableau "normal".
++// Parametre: const ArrOfInt& A
++//    Signification: le tableau a copier
++ArrOfInt::ArrOfInt(const ArrOfInt& A)
++{
++  const entier size = A.size_array();
++  if (size > 0)
++    {
++      // Creation d'un tableau "normal"
++      storage_type_ = STANDARD;
++      p_ = new VIntdata(size, STANDARD);
++      data_ = p_->get_data();
++      size_array_ = size;
++      memory_size_ = size;
++      smart_resize_ = A.smart_resize_;
++      inject_array(A);
++    }
++  else
++    {
++      // Creation d'un tableau "detache"
++      p_ = 0;
++      data_ = 0;
++      size_array_ = 0;
++      memory_size_ = 0;
++      smart_resize_ = 0;
++      storage_type_ = STANDARD;
++    }
++}
++
++// Description:
++//   Change le mode d'allocation memoire lors des resize
++//   (voir VIntdata et Int_ptr_trav)
++//   Exemple pour creer un tableau avec allocation temporaire:
++//    DoubleTab tab; // Creation d'un tableau vide
++//    tab.set_mem_storage(TEMP_STORAGE); // Changement de mode d'allocation
++//    tab.resize(n); // Allocation memoire
++void ArrOfInt::set_mem_storage(const Storage storage)
++{
++  storage_type_ = storage;
++}
++
++// Description:
++//   Renvoie le mode d'allocation du tableau (qui sera utilise
++//   lors du prochain resize si changement de taille).
++//   (voir VIntdata et Int_ptr_trav)
++enum ArrOfInt::Storage ArrOfInt::get_mem_storage() const
++{
++  return storage_type_;
++}
++
++// Description:
++//   Change le mode l'allocation memoire: reallocation d'un tableau
++//   a chaque changement de taille (flag = 0) ou reallocation
++//   uniquement si la taille augmente et par doublement de la taille
++//   du tableau (flag = 1).
++void ArrOfInt::set_smart_resize(entier flag)
++{
++  assert(flag == 0 || flag == 1);
++  smart_resize_ = flag;
++}
++
++// Description:
++//    Remet le tableau dans l'etat obtenu avec le constructeur par defaut
++//    (libere la memoire mais conserve le mode d'allocation memoire actuel)
++void ArrOfInt::reset()
++{
++  detach_array();
++}
++
++// Description:
++//    Copie les donnees du tableau m.
++//    Si "m" n'a pas la meme taille que "*this", on fait un resize_array.
++//    Ensuite, on copie les valeurs de "m" dans "*this".
++//    Le type de tableau (methode d'allocation) n'est pas copie.
++// Precondition:
++//    Si le tableau n'a pas la meme taille que "m", alors *this doit
++//    etre "resizable" (ne pas etre de type "ref_data" et "ref_count == 1")
++// Parametre: const ArrOfInt& m
++//    Signification: la tableau a copier
++// Retour:  ArrOfInt&
++//    Signification: *this
++ArrOfInt& ArrOfInt::operator=(const ArrOfInt& m)
++{
++  if (&m != this)
++    {
++      const entier new_size = m.size_array();
++      // Le code suivant est quasiment une copie de ArrOfInt::resize()
++      // SAUF: memory_resize est appele avec NO_INITIALIZE (la zone de memoire
++      //  n'est pas initialisee)
++      if (new_size != size_array())
++        {
++          if ((smart_resize_ == 0) || (new_size > memory_size_))
++            memory_resize(new_size, 0); // Pas d'initialisation
++          size_array_ = new_size;
++        }
++      inject_array(m);
++    }
++  return *this;
++}
++
++
++// Description:
++//     x est affecte a toutes les cases
++// Precondition:
++// Parametre: entier x
++//    Signification: la valeur a affecter a toutes les cases du tableau
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfInt&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfInt& ArrOfInt::operator=(entier x)
++{
++  const entier n = size_array();
++  entier *data = addr();
++  for (entier i = 0; i < n; i++)
++    {
++      data[i] = x;
++    }
++  return *this;
++}
++
++// Description: appelle operator=(a)
++ArrOfInt& ArrOfInt::copy_array(const ArrOfInt& a)
++{
++  operator=(a);
++  return *this;
++}
++
++// Description:
++//  Si besoin, alloue une nouvelle zone de memoire,
++//  copie les donnees et efface l'ancienne zone de memoire.
++//  Attention, on suppose que cette methode est appelee par
++//  resize_array().
++//  Attention: si ref_count_>1, l'appel a resize_array() est
++//  autorise uniquement si la nouvelle taille est identique
++//  a la precedente.
++// Precondition:
++//  Le tableau doit etre de type "detache" ou "normal" avec
++//  ref_count==1, et il faut new_size >= 0
++//  On suppose que size_array contient encore le nombre d'elements
++//  valides avant changement de taille.
++// Parametre: new_size
++//  Signification: nouvelle taille demandee pour le tableau.
++// Parametre: options
++//  Signification: COPY_OLD => on recopie les anciennes donnees dans le nouveau
++//                  tableau (jusqu'au max de l'ancienne et de la nouvelle taille).
++//                 INITIALIZE_NEW => initialisation des cases non copiees
++// Postcondition:
++//  p_ et data_ sont mis a jour, mais pas size_array_ !!!
++//  (on suppose que c'est fait dans resize_array()).
++//  Si la nouvelle taille est nulle, on detache le tableau.
++void  ArrOfInt::memory_resize(entier new_size, entier options)
++{
++  assert(new_size >= 0);
++
++  // Occupation memoire de l'ancien tableau:
++  entier old_mem_size = 0;
++  if (p_)
++    old_mem_size = p_->get_size();
++
++  // Occupation memoire du nouveau tableau :
++  // Si smart_resize, on prend au moins deux fois la taille
++  // precedente, ou new_size
++  entier new_mem_size = new_size;
++  if (smart_resize_ && (old_mem_size * 2 > new_size))
++    new_mem_size = old_mem_size * 2;
++
++  if (new_mem_size != old_mem_size)
++    {
++      // detach_array() efface le contenu de size_array_. On le met de cote:
++      const entier old_size_array = size_array_;
++      // On va reellement changer l'adresse du tableau.
++      // Il ne faut pas qu'il existe d'autre reference a ce tableau.
++      assert(data_ == 0 || (p_ != 0 && ref_count() == 1));
++      if (new_mem_size == 0)
++        {
++          // La nouvelle taille est nulle, on cree un tableau "detache"
++          detach_array();
++        }
++      else
++        {
++          // Allocation d'une nouvelle zone
++          VIntdata * new_p = new VIntdata(new_mem_size, storage_type_);
++          entier * new_data = new_p->get_data();
++          // Raccourci si le tableau etait "detache", inutile de copier
++          // les anciennes donnees. On copie si COPY_OLD est demande
++          entier copy_size = 0;
++          if (data_ != 0)
++            {
++              // Calcul du nombre d'elements a copier vers la nouvelle
++              // zone de memoire : c'est le min de l'ancienne et de
++              // la nouvelle taille.
++              if (options & COPY_OLD)
++                {
++                  copy_size = size_array_;
++                  if (new_size < copy_size)
++                    copy_size = new_size;
++                  // Copie des valeurs dans le nouveau tableau
++                  for (entier i = 0; i < copy_size; i++)
++                    new_data[i] = data_[i];
++                }
++              // Destruction de l'ancienne zone (si plus aucune reference)
++              detach_array();
++            }
++          // On attache la nouvelle zone de memoire
++          p_ = new_p;
++          data_ = new_data;
++          memory_size_ = new_mem_size;
++          // Initialisation des cases supplementaires avec une valeur par defaut
++          if (options & INITIALIZE_NEW)
++            fill_default_value(copy_size, new_mem_size - copy_size);
++          // Restaure l'ancienne valeur de size_array_
++          size_array_ = old_size_array;
++        }
++    }
++}
++
++// Description:
++//  Remplit "nb" cases consecutives du tableau a partir de la case "first"
++//  avec une valeur par defaut.
++//  Cette fonction est appelee lors d'un resize pour initialiser les
++//  cases nouvellement creees.
++//  Le comportement depend actuellement du type de tableau :
++//  * Tableau de type "smart_resize":
++//    * en mode debug (macro NDEBUG non definie) le tableau est initialise
++//      avec une valeur invalide.
++//    * en optimise, le tableau n'est pas initialise
++//  * Tableau normal :
++//    Le tableau est initialise avec la valeur 0. Ce comportement est choisi
++//    pour des raisons de compatibilite avec l'implementation precedente.
++//    Cette specification pourrait etre modifiee prochainement pour des raisons
++//    de performances (pour ne pas avoir a initialiser inutilement les tableaux).
++//    DONC: il faut supposer desormais que les nouvelles cases ne sont pas
++//    initialisees lors d'un resize.
++// Parametre: first
++//  Signification: premiere case a initialiser.
++//  Contrainte:    (nb==0) ou (0 <= first < memory_size_)
++// Parametre: nb
++//  Signification: nombre de cases a initialiser.
++//  Contrainte:    (nb==0) ou (0 < nb <= memory_size_ - first)
++void  ArrOfInt::fill_default_value(entier first, entier nb)
++{
++  assert((nb == 0) || (first >= 0 && first < memory_size_));
++  assert((nb == 0) || (nb > 0 && nb <= memory_size_ - first));
++  entier * data = addr();
++  assert(data!=0 || nb==0);
++  data += first;
++  if (smart_resize_)
++    {
++      /*
++          // On initialise uniquement en mode debug
++      #ifndef NDEBUG
++          static const entier ENTIER_INVALIDE = INT_MIN;
++          for (entier i = 0; i < nb; i++)
++            data[i] = ENTIER_INVALIDE;
++      #endif
++      */
++    }
++  else
++    {
++      // Comportement pour les tableaux normaux : compatibilite avec la
++      // version precedente : on initialise avec 0.
++      for (entier i = 0; i < nb; i++)
++        data[i] = (entier) 0;
++    }
++}
++
++// ****************************************************************
++//
++//         Fonctions non membres de la classe ArrOfInt
++//
++// ****************************************************************
++
++// Description:
++//  Renvoie 1 si les tableaux "v" et "a" sont de la meme taille
++//  et contiennent les memes valeurs au sens strict, sinon renvoie 0.
++//  Le test est !(v[i]!=a[i])
++entier operator==(const ArrOfInt& v, const ArrOfInt& a)
++{
++  const entier n = v.size_array();
++  const entier na = a.size_array();
++  entier resu = 1;
++  if (n != na)
++    {
++      resu = 0;
++    }
++  else
++    {
++      const entier* vv = v.addr();
++      const entier* av = a.addr();
++      entier i;
++      for (i = 0; i < n; i++)
++        {
++          if (av[i] != vv[i])
++            {
++              resu = 0;
++              break;
++            }
++        }
++    }
++  return resu;
++}
++
++// Description:
++//    Retourne l'indice du min ou -1 si le tableau est vide
++// Precondition:
++// Parametre: const ArrOfInt& dx
++//    Signification: tableau a utiliser
++// Retour: int
++//    Signification: indice du min
++entier imin_array(const ArrOfInt& dx)
++{
++  entier indice_min = -1;
++  const entier size = dx.size_array();
++  if (size > 0)
++    {
++      indice_min = 0;
++      entier valeur_min = dx[0];
++      for(entier i = 1; i < size; i++)
++        {
++          const entier val = dx[i];
++          if(val < valeur_min)
++            {
++              indice_min = i;
++              valeur_min = val;
++            }
++        }
++    }
++  return indice_min;
++}
++
++// Description:
++//    Retourne l'indice du max ou -1 si le tableau est vide
++// Precondition:
++// Parametre: const ArrOfInt& dx
++//    Signification: tableau a utiliser
++// Retour: int
++//    Signification: indice du max
++entier imax_array(const ArrOfInt& dx)
++{
++  entier indice_max = -1;
++  const entier size = dx.size_array();
++  if (size > 0)
++    {
++      indice_max = 0;
++      entier valeur_max = dx[0];
++      for(entier i = 1; i < size; i++)
++        {
++          const entier val = dx[i];
++          if(val > valeur_max)
++            {
++              indice_max = i;
++              valeur_max = val;
++            }
++        }
++    }
++  return indice_max;
++}
++
++// Description:
++//    Retourne la valeur minimale
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOfInt& dx
++//    Signification: tableau a utiliser
++// Retour: entier
++//    Signification: valeur du min
++entier min_array(const ArrOfInt& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  entier valeur_min = dx[0];
++  for(entier i = 1; i < size; i++)
++    {
++      const entier val = dx[i];
++      if (val < valeur_min)
++        valeur_min = val;
++    }
++  return valeur_min;
++}
++
++// Description:
++//    Retourne la valeur maximale
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOfInt& dx
++//    Signification: tableau a utiliser
++// Retour: entier
++//    Signification: valeur du max
++entier max_array(const ArrOfInt& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  entier valeur_max = dx[0];
++  for(entier i = 1; i < size; i++)
++    {
++      const entier val = dx[i];
++      if (val > valeur_max)
++        valeur_max = val;
++    }
++  return valeur_max;
++}
++
++// Description:
++//   Fonction de comparaison utilisee pour trier le tableau
++//   dans ArrOfInt::trier(). Voir man qsort
++static int fonction_compare_arrofentier_ordonner(const void * data1, const void * data2)
++{
++  const entier x = *(const entier*)data1;
++  const entier y = *(const entier*)data2;
++  return x - y;
++}
++
++// Description:
++//   Tri des valeurs du tableau dans l'ordre croissant.
++//   La fonction utilisee est qsort de stdlib (elle est en n*log(n)).
++void ArrOfInt::ordonne_array()
++{
++  const entier size = size_array();
++  if (size > 1)
++    {
++      entier * data = addr();
++      qsort(data, size, sizeof(entier),
++            fonction_compare_arrofentier_ordonner);
++    }
++}
++
++// Description:
++//    Fait pointer le tableau vers les memes donnees qu'un tableau
++//    existant. Le tableau sera du meme type que le tableau m ("detache",
++//    "normal"). Le tableau m ne doit pas etre de type "ref_data"
++//    Les donnes existantes sont perdues si elles
++//    ne sont pas referencees ailleurs.
++// Precondition:
++// Parametre: const ArrOfInt& m
++//    Signification: le tableau a referencer (pas de type "ref_data"
++//                   et different de *this !!!)
++// Retour: ArrOfInt&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfInt& ArrOfInt::ref_array(const ArrOfInt& m)
++{
++  assert(&m != this);
++  // La condition 'm n'est pas de type "ref_data"' est necessaire pour
++  // attach_array().
++  detach_array();
++  attach_array(m);
++  return *this;
++}
++
++// Description:
++//    Fait pointer le tableau vers la zone de memoire "data_".
++//    On detache la zone de memoire existante. Le tableau devient
++//    de type "ref_data". Attention : ptr doit etre non nul.
++//    La taille est initialisee avec size.
++//    Cette methode est appelee notamment par IntVect::adopter.
++// Parametre: entier*
++//    Signification: le tableau a recuperer. Si pointeur nul alors size
++//                   doit etre nulle aussi et le tableau reste detache
++// Parametre: entier size
++//    Signification: le nombre d'elements du tableau.
++// Retour: ArrOfInt&
++//    Signification: *this
++ArrOfInt& ArrOfInt::ref_data(entier* ptr, entier size)
++{
++  assert(ptr != 0 || size == 0);
++  assert(size >= 0);
++  detach_array();
++  data_ = ptr;
++  size_array_ = size;
++  return *this;
++}
++
++// Description:
++//  Amene le tableau dans l'etat "detache". C'est a dire:
++//  Si le tableau est "detache" :
++//   * ne rien faire
++//  Si le tableau est "normal" :
++//   * decremente le nombre de references a *p
++//   * detruit *p si p->ref_count==0
++//   * annule p_, data_ et size_array_
++//  Si le tableau est "ref_data" :
++//   * annule data_ et size_array_
++// Retour: int
++//    Signification: 1 si les donnees du tableau ont ete supprimees
++// Precondition:
++// Postcondition:
++//  On a p_==0, data_==0 et size_array_==0, memory_size_ = 0
++//  L'attribut smart_resize_ est conserve.
++entier ArrOfInt::detach_array()
++{
++  entier retour = 0;
++  if (p_)
++    {
++      // Le tableau est de type "normal"
++      // Si la zone de memoire n'est plus utilisee par personne,
++      // on la detruit.
++      if ((p_->suppr_one_ref()) == 0)
++        {
++          delete p_;
++          retour = 1;
++        }
++      p_ = 0;
++    }
++  data_ = 0;
++  size_array_ = 0;
++  memory_size_ = 0;
++  return retour;
++}
++
++// Description:
++//    Amene le tableau dans l'etat "normal", "detache" ou "ref_array"
++//    en associant la meme zone de memoire que le tableau m.
++// Precondition:
++//    Le tableau doit etre "detache"
++// Parametre: const ArrOfInt& m
++//    Signification: tableau a utiliser
++//                   le tableau doit etre different de *this !!!
++// Retour:
++//    Signification:
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++//    Si m est detache, le tableau reste detache,
++//    si m est "ref_array", le tableau devient "ref_array",
++//    sinon le tableau est "normal", avec ref_count > 1
++//    Si m est de taille nulle, le tableau reste detache + Warning dans fichier .log
++void ArrOfInt::attach_array(const ArrOfInt& m)
++{
++  // Le tableau doit etre detache
++  assert(data_ == 0 && p_ == 0);
++  // Le tableau doit etre different de *this
++  assert(&m != this);
++
++  if (m.size_array() > 0)
++    {
++      p_ = m.p_;
++      if (p_)
++        p_->add_one_ref();
++      data_ = m.data_;
++      size_array_ = m.size_array_;
++      memory_size_ = m.memory_size_;
++      smart_resize_ = m.smart_resize_;
++    }
++  else
++    {
++      // Cas particulier ou on attache un tableau de taille nulle:
++      //  en theorie, c'est pareil qu'un tableau de taille non nulle, MAIS
++      //  dans les operateurs (ex:Op_Dift_VDF_Face_Axi), une ref est construite
++      //  avant que le tableau ne prenne sa taille definitive. Donc, pour ne pas
++      //  empecher le resize, il ne faut pas attacher le tableau s'il n'a pas
++      //  encore la bonne taille. Solution propre: reecrire les operateurs pour
++      //  qu'ils ne prennent pas une ref avant que le tableau ne soit valide
++      //  et faire p_ = m.p_ dans tous les cas.
++    }
++}
++
++// Description:
++//    Copie les elements source[first_element_source + i]
++//    dans les elements  (*this)[first_element_dest + i] pour 0 <= i < nb_elements
++//    Les autres elements de (*this) sont inchanges.
++// Precondition:
++// Parametre:       const ArrOfInt& m
++//  Signification:   le tableau a utiliser, doit etre different de *this !
++// Parametre:       entier nb_elements
++//  Signification:   nombre d'elements a copier, nb_elements >= -1.
++//                   Si nb_elements==-1, on copie tout le tableau m.
++//  Valeurs par defaut: -1
++// Parametre:       entier first_element_dest
++//  Valeurs par defaut: 0
++// Parametre:       entier first_element_source
++//  Valeurs par defaut: 0
++// Retour: ArrOfInt&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++//    Sort en erreur si la taille du tableau m est plus grande que la
++//    taille de tableau this.
++// Effets de bord:
++// Postcondition:
++ArrOfInt& ArrOfInt::inject_array(const ArrOfInt& source,
++                                 entier nb_elements,
++                                 entier first_element_dest,
++                                 entier first_element_source)
++{
++  assert(&source != this);
++  assert(nb_elements >= -1);
++  assert(first_element_dest >= 0);
++  assert(first_element_source >= 0);
++
++  if (nb_elements < 0)
++    nb_elements = source.size_array();
++
++  assert(first_element_source + nb_elements <= source.size_array());
++  assert(first_element_dest + nb_elements <= size_array());
++
++  if (nb_elements > 0)
++    {
++      entier * addr_dest = addr() + first_element_dest;
++      const entier * addr_source = source.addr() + first_element_source;
++      // memcpy(addr_dest , addr_source, nb_elements * sizeof(entier));
++      entier i;
++      for (i = 0; i < nb_elements; i++)
++        {
++          addr_dest[i] = addr_source[i];
++        }
++    }
++  return *this;
++}
++
++// Description:
++//    Retourne le nombre de references des donnees du tableau
++//    si le tableau est "normal", -1 s'il est "detache" ou "ref_data"
++// Retour: int
++//    Signification: ref_count_
++entier ArrOfInt::ref_count() const
++{
++  if (p_)
++    return p_->ref_count();
++  else
++    return -1;
++}
++
++// Description:
++//    Addition case a case sur toutes les cases du tableau
++// Precondition:
++//    la taille de y doit etre au moins egale a la taille de this
++// Parametre: const ArrOfInt& y
++//    Signification: tableau a ajouter
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfInt&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfInt& ArrOfInt::operator+=(const ArrOfInt& y)
++{
++  assert(size_array()==y.size_array());
++  entier* dx = addr();
++  const entier* dy = y.addr();
++  const entier n = size_array();
++  for (entier i=0; i<n; i++)
++    dx[i] += dy[i];
++  return *this;
++}
++
++// Description:
++//     ajoute la meme valeur a toutes les cases du tableau
++// Precondition:
++// Parametre: const entier dy
++//    Signification: valeur a ajouter
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOfInt
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOfInt& ArrOfInt::operator+=(const entier dy)
++{
++  entier * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] += dy;
++  return *this;
++}
++// Description:
++//    Soustraction case a case sur toutes les cases du tableau
++// Parametre: const ArrOfInt& y
++//    Signification: tableau de meme taille que *this
++// Retour: ArrOfInt&
++//    Signification: *this
++ArrOfInt& ArrOfInt::operator-=(const ArrOfInt& y)
++{
++  const entier size = size_array();
++  assert(size == y.size_array());
++  entier * data = addr();
++  const entier * data_y = y.addr();
++  for (entier i=0; i < size; i++)
++    data[i] -= data_y[i];
++  return *this;
++}
++
++
++// Description:
++//     soustrait la meme valeur a toutes les cases
++// Retour: ArrOfInt &
++//    Signification: *this
++ArrOfInt& ArrOfInt::operator-=(const entier dy)
++{
++  entier * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] -= dy;
++  return *this;
++}
++
++// Description:
++//   Renvoie un pointeur sur le premier element du tableau.
++//   Le pointeur est nul si le tableau est "detache".
++//   Attention, l'adresse peut changer apres un appel
++//   a resize_array(), ref_data, ref_array, ...
++// Precondition:
++// Retour: const entier*
++//   Signification: pointeur sur le premier element du tableau
++const entier* ArrOfInt::addr() const
++{
++  return data_;
++}
++
++// Description:
++//   Renvoie un pointeur sur le premier element du tableau.
++//   Le pointeur est nul si le tableau est "detache".
++// Precondition:
++// Retour: const entier*
++//    Signification: la zone memoire du tableau
++entier* ArrOfInt::addr()
++{
++  return data_;
++}
++
++
++IntTab::IntTab()
++{
++  // nb_dim_ = 2;
++  dimensions_[0] = 0;
++  dimensions_[1] = 0;
++}
++
++IntTab::IntTab(const IntTab& tab) :
++  ArrOfInt(tab)
++{
++  // nb_dim_ = tab.nb_dim_;
++  dimensions_[0] = tab.dimensions_[0];
++  dimensions_[1] = tab.dimensions_[1];
++}
++IntTab::IntTab(const entier i, const entier j) :
++  ArrOfInt(i*j)
++{
++  // nb_dim_ = 2;
++  dimensions_[0] = i;
++  dimensions_[1] = j;
++}
++
++IntTab& IntTab::operator=(const IntTab& tab)
++{
++  ArrOfInt::operator=(tab);
++  // nb_dim_ = tab.nb_dim_;
++  dimensions_[0] = tab.dimensions_[0];
++  dimensions_[1] = tab.dimensions_[1];
++  return *this;
++}
++
++void IntTab::reset()
++{
++  ArrOfInt::reset();
++  // nb_dim_ = 2;
++  dimensions_[0] = 0;
++  dimensions_[1] = 0;
++}
++
+diff --git a/databases/readers/Lata/ArrOfInt.h b/databases/readers/Lata/ArrOfInt.h
+new file mode 100644
+index 0000000..9d9a542
+--- /dev/null
++++ b/databases/readers/Lata/ArrOfInt.h
+@@ -0,0 +1,343 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++////////////////////////////////////////////////////////////
++//
++// Warning : DO NOT EDIT !
++//         Please update ArrOf_Scalar_Prototype.h.P
++//         and this file will be generated automatically
++//           by the script file check.sh
++////////////////////////////////////////////////////////////
++
++#ifndef ArrOfInt_H
++#define ArrOfInt_H
++
++#include <assert.h>
++#include <arch.h>
++#include <Objet_U.h>
++
++
++class VIntdata;
++
++class ArrOfInt
++{
++public:
++  //
++  // Destructeur
++  //
++  virtual ~ArrOfInt();
++  //
++  // Constructeurs
++  //
++  ArrOfInt();
++  ArrOfInt(entier size);
++  ArrOfInt(entier size, entier initial_value);
++  // Constructeur par copie : deep copy (on duplique les donnees)
++  ArrOfInt(const ArrOfInt& );
++  //
++  // Methodes de construction tardive (on cree un tableau vide avec ArrOfInt()
++  // puis on appelle ces methodes pour modifier les caracteristiques du tableau :
++  //
++  // Change le nombre d'elements du tableau
++  inline ArrOfInt& resize_array(entier new_size);
++
++  // Methodes de gestion de l'allocation memoire:
++  // Assigne une valeur au drapeau "smart_resize"
++  // (reallocation uniquement si la taille augmente)
++  void    set_smart_resize(entier flag);
++  // Gestion du type de memoire alouee (standard ou pool de memoire Trio-U)
++  enum    Storage { STANDARD, TEMP_STORAGE, SIMD_ALIGNED };
++  void    set_mem_storage(const Storage storage);
++  Storage get_mem_storage() const;
++
++  // Construction de tableaux qui pointent vers des donnees existantes
++  // !!! Utiliser ref_data avec precaution (attention a size_array_)
++  ArrOfInt& ref_data(entier* ptr, entier size);
++  ArrOfInt& ref_array(const ArrOfInt&);
++  // Operateur copie
++  ArrOfInt& operator=(const ArrOfInt&);
++  // Remise du tableau dans l'etat initial (obtenu par le constructeur par defaut)
++  virtual void reset();
++
++  //
++  // Methodes d'acces aux donnees et aux caracteristiques du tableau
++  //
++  // Remplit le tableau avec la valeur en parametre
++  ArrOfInt& operator=(entier valeur);
++
++  inline       entier& operator[](entier i);
++  inline const entier& operator[](entier i) const;
++
++  // Ces methodes renvoient un pointeur vers le premier element du tableau.
++  const entier * addr() const;
++  entier * addr();
++  // Renvoie le nombre d'elements du tableau (et non la taille allouee)
++  inline entier size_array() const;
++  // Renvoie le nombre de tableaux qui pointent vers la stucture "*p_"
++  entier ref_count() const;
++  // Ajoute une case en fin de tableau et y stocke la "valeur"
++  inline void   append_array(entier valeur);
++
++  //
++  // Operateurs divers
++  //
++  ArrOfInt& operator+=(const ArrOfInt&);
++  ArrOfInt& operator+=(const entier);
++  ArrOfInt& operator-=(const ArrOfInt&);
++  ArrOfInt& operator-=(const entier);
++  ArrOfInt& inject_array(const ArrOfInt& source,
++                         entier nb_elements = -1,
++                         entier first_element_dest = 0,
++                         entier first_element_source = 0);
++  ArrOfInt& copy_array(const ArrOfInt&);
++
++
++  void             ordonne_array();
++
++protected:
++  //
++  // Methodes accessibles depuis les descendants de ArrOfInt
++  //
++  void   attach_array(const ArrOfInt&);
++  entier detach_array();
++  void   fill_default_value(entier first, entier nb);
++private:
++  // B. Mathieu 22/06/2004 : je mets ces membres "private" pour forcer
++  // le passage par les accesseurs dans les classes derivees, au cas ou
++  // on voudrait modifier l'implementation.
++
++  // Zone de memoire contenant les valeurs du tableau.
++  // Pointeur nul => le tableau est "detache" ou "ref_data"
++  // Pointeur non nul => le tableau est "normal"
++  VIntdata* p_;
++
++  // Pointeur vers le premier element du tableau (egal a p_->data si p_!=0)
++  // Pointeur nul => le tableau est "detache".
++  // Pointeur non nul => le tableau est "normal" ou "ref_data"
++  entier*   data_;
++
++  // Nombre d'elements du tableau (inferieur ou egal a memory_size_).
++  // Si le tableau est "detache", alors size_array_=0
++  entier    size_array_;
++  // Taille memoire reellement allouee pour le tableau
++  // (pour le mecanisme smart_resize_). memory_size_ est nul
++  // si le tableau est de type "ref_data". Sinon memory_size_
++  // est egal a p_->size_.
++  entier    memory_size_;
++
++  // Drapeau indiquant si on applique une strategie d'allocation
++  // preventive (la memoire alouee augmente d'un facteur constant
++  // si la taille devient insuffisante).
++  // Si smart_resize_ == 0, alors on a toujours p_->size_ == size
++  entier    smart_resize_;
++
++  // Drapeau indiquant si l'allocation memoire a lieu avec un new classique
++  // ou dans le pool de memoire temporaire de Trio
++  Storage   storage_type_;
++
++  // Partie non inline de resize_array():
++  // Declaration des constantes pour les options de memory_resize
++  static const entier COPY_OLD;
++  static const entier INITIALIZE_NEW;
++  void memory_resize(entier new_size, entier options);
++};
++
++#define MAXDIMIntTab 2
++
++class IntTab : public ArrOfInt
++{
++public:
++  IntTab();
++  IntTab(const IntTab&);
++  IntTab(const entier i, const entier j);
++  IntTab&    operator=(const IntTab&);
++  void              reset();
++
++  inline entier& operator()(entier i, entier j);
++  inline entier   operator()(entier i, entier j) const;
++
++  inline entier resize(entier i, entier j);
++  inline entier dimension(entier i) const;
++  inline entier dimension_tot(entier i) const;
++
++protected:
++  // In order to mimic TRUST behavior, operator[] is forbidden
++  // for 2 dimensionnal matrices, you must cast to ArrOf to use it..
++  double&        operator[](entier i);
++  const double& operator[](entier i) const;
++
++private:
++  //  entier nb_dim_;
++  entier dimensions_[MAXDIMIntTab];
++};
++
++inline entier& IntTab::operator()(entier i, entier j)
++{
++  // assert(nb_dim_ == 2);
++  assert(i >= 0 && i < dimensions_[0] && j >= 0 && j < dimensions_[1]);
++  const entier n = i * dimensions_[1] + j;
++  entier& x = ArrOfInt::operator[] (n);
++  return x;
++}
++
++inline entier   IntTab::operator()(entier i, entier j) const
++{
++  // assert(nb_dim_ == 2);
++  assert(i >= 0 && i < dimensions_[0] && j >= 0 && j < dimensions_[1]);
++  const entier n = i * dimensions_[1] + j;
++  entier x = ArrOfInt::operator[] (n);
++  return x;
++}
++
++inline entier IntTab::resize(entier i, entier j)
++{
++  assert(i >= 0 && j >= 0);
++  // nb_dim_ = 2;
++  dimensions_[0] = i;
++  dimensions_[1] = j;
++  ArrOfInt::resize_array(i * j);
++  return i*j;
++}
++
++inline entier IntTab::dimension(entier i) const
++{
++  assert(i >= 0 && i < 2);
++  return dimensions_[i];
++}
++
++// Description: renvoie la meme valeur que dimension.
++inline entier IntTab::dimension_tot(entier i) const
++{
++  return dimension(i);
++}
++
++//
++// Declarations des fonctions non membres de la classe ArrOfInt
++//
++entier operator==(const ArrOfInt& x, const ArrOfInt& y) ;
++entier imin_array(const ArrOfInt&) ;
++entier imax_array(const ArrOfInt&) ;
++entier min_array(const ArrOfInt&) ;
++entier max_array(const ArrOfInt&) ;
++
++
++// ******************************************************************
++//                   FONCTIONS MEMBRES DE ArrOfInt
++// ******************************************************************
++
++// Description :
++//  Change le nombre d'elements du tableau. Cette fonction est inline
++//  car elle doit etre tres rapide dans le cas ou smart_resize_==1
++//  (utilisation frequente de resize_array())
++//  Si smart_resize est non nul :
++//   Si la nouvelle taille est inferieure ou egale a la taille
++//   alouee (p->get_size()) on ne realloue pas de memoire
++//   sinon, on realloue et on copie les donnees existantes.
++//  Astuce pour ne pas copier les anciennes donnees:
++//   resize(0); resize(n);
++//  Si smart_resize est nul, on realloue une nouvelle zone memoire
++//   uniquement si la nouvelle taille est differente de l'ancienne.
++// Precondition :
++//  Si "new_size" est egal a la taille du tableau, aucune condition.
++//  Sinon, le tableau doit etre soit detache, soit normal (pas de type "ref_data")
++//  et ref_count doit etre egal a 1 (pas d'autre reference au tableau).
++//
++inline ArrOfInt& ArrOfInt::resize_array(entier new_size)
++{
++  assert(new_size >= 0);
++  // Soit le tableau est detache (data_==0), soit il est normal (p_!=0)
++  // S'il est normal, il ne faut pas qu'il y ait d'autre reference au tableau,
++  // ou alors la taille ne doit pas changer.
++  assert(new_size == size_array_ || data_ == 0 || (p_ != 0 && ref_count() == 1));
++
++  if ((smart_resize_ == 0) || (new_size > memory_size_))
++    memory_resize(new_size, COPY_OLD + INITIALIZE_NEW);
++  size_array_ = new_size;
++  return *this;
++}
++
++// Description:
++//     operateur [] retourne le ieme element du tableau
++// Precondition:
++// Parametre: entier i
++//    Signification: indice dans l'intervalle 0 <= i < size_array()
++// Exception:
++//    assert si i n'est pas dans l'intervalle
++inline entier& ArrOfInt::operator[](entier i)
++{
++  assert(i >= 0 && i < size_array_);
++  return data_[i];
++}
++
++// Description:
++//     operateur [] retourne le ieme element du tableau
++// Precondition:
++// Parametre: entier i
++//    Signification: indice dans l'intervalle 0 <= i < size_array()
++// Exception:
++//    assert si i n'est pas dans l'intervalle
++inline const entier& ArrOfInt::operator[](entier i) const
++{
++  assert(i >= 0 && i < size_array_);
++  return data_[i];
++}
++
++// Description:
++//    Renvoie la taille du tableau (nombre d'elements declares
++//    a la construction ou a resize_array()).
++//    C'est le nombre d'elements accessibles a operator[]
++// Retour: entier
++inline entier  ArrOfInt::size_array() const
++{
++  return size_array_;
++}
++
++// Description:
++//  Ajoute une case en fin de tableau et y stocke la "valeur"
++// Precondition:
++//  Tableau doit etre de type "smart_resize" (sinon, ecroulement
++//  des performances). De plus, le tableau ne doit pas etre "ref_data",
++//  et il ne doit pas y avoir plus d'une reference a la zone de
++//  memoire pointee (meme precondition que resize_array())
++inline void   ArrOfInt::append_array(entier valeur)
++{
++  assert(smart_resize_);
++  // Soit le tableau est detache (data_==0), soit il est normal (p_!=0)
++  // S'il est normal, il ne faut pas qu'il y ait d'autre reference au tableau.
++  assert(data_ == 0 || (p_ != 0 && ref_count() == 1));
++
++  if (size_array_+1 > memory_size_)
++    memory_resize(size_array_+1, COPY_OLD);
++  data_[size_array_] = valeur;
++  size_array_++;
++}
++
++// ArrOfInt_H
++#endif
++
+diff --git a/databases/readers/Lata/ArrOf_Scalar_Prototype.cpp.h b/databases/readers/Lata/ArrOf_Scalar_Prototype.cpp.h
+new file mode 100644
+index 0000000..b881750
+--- /dev/null
++++ b/databases/readers/Lata/ArrOf_Scalar_Prototype.cpp.h
+@@ -0,0 +1,1168 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <ArrOf__Scalar__.h>
++__DoubleOnlyBegin__
++#include <math.h>
++__DoubleOnlyEnd__
++__IntOnlyBegin__
++// limits.h definit INT_MIN, SHRT_MIN, ...
++#include <limits.h>
++__IntOnlyEnd__
++#include <stdlib.h>
++#include <Objet_U.h>
++#include <iostream>
++#include <stdlib.h>
++
++// ******************************************************************
++//
++//             Implementation des methodes de V__Scalar__data
++//
++// ******************************************************************
++////////////////////////////////////////////////////////////////////
++// .NOM        ArrOf__Scalar__
++// .ENTETE     TRUST Math
++// .LIBRAIRIE  libtmath
++// .FILE       ArrOf__Scalar__.h
++// .FILE       ArrOf__Scalar__.cpp
++//
++// .DESCRIPTION
++// V__Scalar__data alloue une zone de memoire de la taille specifiee au
++// constructeur, et libere la zone de memoire a la destruction.
++// La memoire peut etre allouee sur le tas (avec new) ou par le
++// mecanisme Memoire::add_trav___scalar__.
++//
++// "ref_count" compte le nombre de pointeurs qui font reference a "this".
++// (permet au dernier utilisateur de l'objet de le detruire), voir
++// ArrOf__Scalar__.
++//
++// .SECTION voir aussi
++// .CONTRAINTES
++// .INVARIANTS
++// .HTML
++// .EPS
++///////////////////////////////////////////////////////////////////
++
++class V__Scalar__data
++{
++public:
++  V__Scalar__data(entier size, ArrOf__Scalar__::Storage storage);
++  ~V__Scalar__data();
++  entier          add_one_ref();
++  entier          suppr_one_ref();
++  __scalar__ *        get_data();
++  const __scalar__ *  get_data() const;
++  inline entier   ref_count() const;
++  inline entier   get_size() const;
++private:
++  // Le constructeur par copie et l'operateur= sont interdits.
++  V__Scalar__data(const V__Scalar__data& v);
++  V__Scalar__data& operator=(const V__Scalar__data& v);
++
++  // "data" est un pointeur sur une zone de memoire de taille
++  // sz * sizeof(__scalar__), allouee par le
++  // constructeur et liberee par le destructeur.
++  // Ce pointeur n'est jamais nul meme si size_==0
++  __scalar__ * data_;
++  // Compteur incremente par add_one_ref et decremente par suppr_one_ref.
++  // Contient le nombre d'objets ArrOf__Scalar__ dont le membre "p" pointe
++  // vers "this". On a ref_count_ >= 0.
++  entier ref_count_;
++  // "sz" est la taille du tableau "data_" alloue
++  // On a sz >= 0.
++  entier size_;
++  // Si storage est de type TEMP_STORAGE, d_ptr_trav porte la reference
++  // a la zone allouee, sinon le pointeur est nul.
++  //__Scalar___ptr_trav * d_ptr_trav_;
++};
++
++
++// Description:
++//    Construit un V__Scalar__data de taille size >= 0
++// Parametre: entier s
++//    Signification: taille du V__Scalar__data, il faut size >= 0
++// Parametre: Storage storage
++//    Signification: indique si la memoire doit etre allouee
++//                   avec "new" ou avec "memoire.add_trav___scalar__()"
++//    Valeurs par defaut: STANDARD (allocation avec "new")
++// Postcondition:
++//    data_ n'est jamais nul, meme si size==0
++V__Scalar__data::V__Scalar__data(entier size, ArrOf__Scalar__::Storage storage)
++{
++  if (size == 0)
++    storage = ArrOf__Scalar__::STANDARD;
++
++  switch (storage)
++    {
++    case ArrOf__Scalar__::STANDARD:
++      {
++#ifdef _EXCEPTION_
++        // Allocation de la memoire sur le tas
++        try
++          {
++            data_ = new __scalar__[size];
++          }
++        catch(...)
++          {
++            Cerr << "impossible d'allouer " << size << " __scalar__ " << finl;
++            throw;
++          }
++#else
++        data_ = new __scalar__[size];
++        if(!data_)
++          {
++            Cerr << "impossible d'allouer " << size << "__scalar__ " << finl;
++            throw ;
++          }
++#endif
++        break;
++      }
++    default:
++      throw;
++    }
++  ref_count_ = 1;
++  size_ = size;
++
++  assert(data_ != 0);
++}
++
++// Description:
++//  Detruit la zone de memoire allouee.
++// Precondition:
++//  ref_count == 0 (la zone de memoire ne doit etre referencee nulle part)
++V__Scalar__data::~V__Scalar__data()
++{
++  assert(ref_count_ == 0);
++
++  // Stockage STANDARD
++  delete[] data_;
++
++  data_ = 0;  // paranoia: si size_==-1 c'est qu'on pointe sur un zombie
++  size_ = -1; //  (pointeur vers un objet qui a ete detruit)
++}
++
++// Description: renvoie ref_count_
++inline entier V__Scalar__data::ref_count() const
++{
++  return ref_count_;
++}
++
++// Description: renvoie size_
++inline entier V__Scalar__data::get_size() const
++{
++  return size_;
++}
++
++// Description:
++//     Un nouveau tableau utilise cette zone memoire :
++//     incremente ref_count
++// Retour: int
++//    Signification: ref_count
++inline entier V__Scalar__data::add_one_ref()
++{
++  return ++ref_count_;
++}
++
++// Description:
++//     Un tableau de moins utilise cette zone memoire
++//     decremente ref_count
++// Precondition:
++//     ref_count_ > 0
++// Retour: int
++//    Signification: ref_count
++inline entier V__Scalar__data::suppr_one_ref()
++{
++  assert(ref_count_ > 0);
++  return (--ref_count_);
++}
++
++// Description: renvoie data_
++inline __scalar__ * V__Scalar__data::get_data()
++{
++  return data_;
++}
++
++// Description: renvoie data_
++inline const __scalar__ * V__Scalar__data::get_data() const
++{
++  return data_;
++}
++
++// Description: Constructeur par copie. Interdit : genere une erreur !
++V__Scalar__data::V__Scalar__data(const V__Scalar__data& v)
++{
++  Cerr << "Erreur dans V__Scalar__data::V__Scalar__data(const V__Scalar__data & v)" << finl;
++  throw;
++}
++
++// Description: Operateur= interdit. Genere une erreur !
++V__Scalar__data& V__Scalar__data::operator=(const V__Scalar__data& v)
++{
++  Cerr << "Erreur dans V__Scalar__data::operator=(const V__Scalar__data & v)" << finl;
++  throw;
++  return *this;
++}
++
++// ******************************************************************
++//
++//             Implementation des methodes de ArrOf__Scalar__
++//
++// ******************************************************************
++
++
++// Definition des constantes pour les options de memory_resize
++const entier ArrOf__Scalar__::COPY_OLD = 1;
++const entier ArrOf__Scalar__::INITIALIZE_NEW = 2;
++
++// Description:
++//  Destructeur : appelle detach_array()
++ArrOf__Scalar__::~ArrOf__Scalar__()
++{
++  detach_array();
++  size_array_ = -1; // Paranoia: si size_array_==-1, c'est un zombie
++}
++
++// Description:
++//  Constructeur par defaut: cree un tableau "detache",
++//  soit p_==0, data_==0, size_array_==0, smart_resize_==0
++ArrOf__Scalar__::ArrOf__Scalar__() :
++  p_(0),
++  data_(0),
++  size_array_(0),
++  memory_size_(0),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++}
++
++// Description:
++//     Cree un tableau de taille n avec allocation standard
++//     (voir set_mem_storage).
++//     Valeur de remplissage par defaut: voir fill_default_value
++// Precondition:
++// Parametre: entier n
++//    Signification: taille du tableau
++ArrOf__Scalar__::ArrOf__Scalar__(entier n) :
++  p_(new V__Scalar__data(n, STANDARD)),
++  data_(p_->get_data()),
++  size_array_(n),
++  memory_size_(n),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++  if (n > 0)
++    fill_default_value(0, n);
++}
++
++// Description:
++//     Cree un tableau de taille n
++//     toutes les cases sont initialisees a x
++// Precondition:
++// Parametre: entier n
++//    Signification: taille du tableau
++// Parametre: __scalar__ x
++//    Signification: valeur pour initialiser le tableau
++ArrOf__Scalar__::ArrOf__Scalar__(entier n, __scalar__ x) :
++  p_(new V__Scalar__data(n, STANDARD)),
++  data_(p_->get_data()),
++  size_array_(n),
++  memory_size_(n),
++  smart_resize_(0),
++  storage_type_(STANDARD)
++{
++  *this = x;
++}
++
++// Description:
++//     Constructeur par copie. On alloue une nouvelle zone de memoire
++//     et on copie le contenu du tableau. L'attribut smart_resize_ est
++//     copie aussi.
++//     Si le tableau A est de taille nulle, on cree un tableau "detache",
++//     sinon on cree un tableau "normal".
++// Parametre: const ArrOf__Scalar__& A
++//    Signification: le tableau a copier
++ArrOf__Scalar__::ArrOf__Scalar__(const ArrOf__Scalar__& A)
++{
++  const entier size = A.size_array();
++  if (size > 0)
++    {
++      // Creation d'un tableau "normal"
++      storage_type_ = STANDARD;
++      p_ = new V__Scalar__data(size, STANDARD);
++      data_ = p_->get_data();
++      size_array_ = size;
++      memory_size_ = size;
++      smart_resize_ = A.smart_resize_;
++      inject_array(A);
++    }
++  else
++    {
++      // Creation d'un tableau "detache"
++      p_ = 0;
++      data_ = 0;
++      size_array_ = 0;
++      memory_size_ = 0;
++      smart_resize_ = 0;
++      storage_type_ = STANDARD;
++    }
++}
++
++// Description:
++//   Change le mode d'allocation memoire lors des resize
++//   (voir V__Scalar__data et __Scalar___ptr_trav)
++//   Exemple pour creer un tableau avec allocation temporaire:
++//    DoubleTab tab; // Creation d'un tableau vide
++//    tab.set_mem_storage(TEMP_STORAGE); // Changement de mode d'allocation
++//    tab.resize(n); // Allocation memoire
++void ArrOf__Scalar__::set_mem_storage(const Storage storage)
++{
++  storage_type_ = storage;
++}
++
++// Description:
++//   Renvoie le mode d'allocation du tableau (qui sera utilise
++//   lors du prochain resize si changement de taille).
++//   (voir V__Scalar__data et __Scalar___ptr_trav)
++enum ArrOf__Scalar__::Storage ArrOf__Scalar__::get_mem_storage() const
++{
++  return storage_type_;
++}
++
++// Description:
++//   Change le mode l'allocation memoire: reallocation d'un tableau
++//   a chaque changement de taille (flag = 0) ou reallocation
++//   uniquement si la taille augmente et par doublement de la taille
++//   du tableau (flag = 1).
++void ArrOf__Scalar__::set_smart_resize(entier flag)
++{
++  assert(flag == 0 || flag == 1);
++  smart_resize_ = flag;
++}
++
++// Description:
++//    Remet le tableau dans l'etat obtenu avec le constructeur par defaut
++//    (libere la memoire mais conserve le mode d'allocation memoire actuel)
++void ArrOf__Scalar__::reset()
++{
++  detach_array();
++}
++
++// Description:
++//    Copie les donnees du tableau m.
++//    Si "m" n'a pas la meme taille que "*this", on fait un resize_array.
++//    Ensuite, on copie les valeurs de "m" dans "*this".
++//    Le type de tableau (methode d'allocation) n'est pas copie.
++// Precondition:
++//    Si le tableau n'a pas la meme taille que "m", alors *this doit
++//    etre "resizable" (ne pas etre de type "ref_data" et "ref_count == 1")
++// Parametre: const ArrOf__Scalar__& m
++//    Signification: la tableau a copier
++// Retour:  ArrOf__Scalar__&
++//    Signification: *this
++ArrOf__Scalar__& ArrOf__Scalar__::operator=(const ArrOf__Scalar__& m)
++{
++  if (&m != this)
++    {
++      const entier new_size = m.size_array();
++      // Le code suivant est quasiment une copie de ArrOf__Scalar__::resize()
++      // SAUF: memory_resize est appele avec NO_INITIALIZE (la zone de memoire
++      //  n'est pas initialisee)
++      if (new_size != size_array())
++        {
++          if ((smart_resize_ == 0) || (new_size > memory_size_))
++            memory_resize(new_size, 0); // Pas d'initialisation
++          size_array_ = new_size;
++        }
++      inject_array(m);
++    }
++  return *this;
++}
++
++
++// Description:
++//     x est affecte a toutes les cases
++// Precondition:
++// Parametre: __scalar__ x
++//    Signification: la valeur a affecter a toutes les cases du tableau
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOf__Scalar__&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOf__Scalar__& ArrOf__Scalar__::operator=(__scalar__ x)
++{
++  const entier n = size_array();
++  __scalar__ *data = addr();
++  for (entier i = 0; i < n; i++)
++    {
++      data[i] = x;
++    }
++  return *this;
++}
++
++// Description: appelle operator=(a)
++ArrOf__Scalar__& ArrOf__Scalar__::copy_array(const ArrOf__Scalar__ & a)
++{
++  operator=(a);
++  return *this;
++}
++
++// Description:
++//  Si besoin, alloue une nouvelle zone de memoire,
++//  copie les donnees et efface l'ancienne zone de memoire.
++//  Attention, on suppose que cette methode est appelee par
++//  resize_array().
++//  Attention: si ref_count_>1, l'appel a resize_array() est
++//  autorise uniquement si la nouvelle taille est identique
++//  a la precedente.
++// Precondition:
++//  Le tableau doit etre de type "detache" ou "normal" avec
++//  ref_count==1, et il faut new_size >= 0
++//  On suppose que size_array contient encore le nombre d'elements
++//  valides avant changement de taille.
++// Parametre: new_size
++//  Signification: nouvelle taille demandee pour le tableau.
++// Parametre: options
++//  Signification: COPY_OLD => on recopie les anciennes donnees dans le nouveau
++//                  tableau (jusqu'au max de l'ancienne et de la nouvelle taille).
++//                 INITIALIZE_NEW => initialisation des cases non copiees
++// Postcondition:
++//  p_ et data_ sont mis a jour, mais pas size_array_ !!!
++//  (on suppose que c'est fait dans resize_array()).
++//  Si la nouvelle taille est nulle, on detache le tableau.
++void  ArrOf__Scalar__::memory_resize(entier new_size, entier options)
++{
++  assert(new_size >= 0);
++
++  // Occupation memoire de l'ancien tableau:
++  entier old_mem_size = 0;
++  if (p_)
++    old_mem_size = p_->get_size();
++
++  // Occupation memoire du nouveau tableau :
++  // Si smart_resize, on prend au moins deux fois la taille
++  // precedente, ou new_size
++  entier new_mem_size = new_size;
++  if (smart_resize_ && (old_mem_size * 2 > new_size))
++    new_mem_size = old_mem_size * 2;
++
++  if (new_mem_size != old_mem_size)
++    {
++      // detach_array() efface le contenu de size_array_. On le met de cote:
++      const entier old_size_array = size_array_;
++      // On va reellement changer l'adresse du tableau.
++      // Il ne faut pas qu'il existe d'autre reference a ce tableau.
++      assert(data_ == 0 || (p_ != 0 && ref_count() == 1));
++      if (new_mem_size == 0)
++        {
++          // La nouvelle taille est nulle, on cree un tableau "detache"
++          detach_array();
++        }
++      else
++        {
++          // Allocation d'une nouvelle zone
++          V__Scalar__data * new_p = new V__Scalar__data(new_mem_size, storage_type_);
++          __scalar__ * new_data = new_p->get_data();
++          // Raccourci si le tableau etait "detache", inutile de copier
++          // les anciennes donnees. On copie si COPY_OLD est demande
++          entier copy_size = 0;
++          if (data_ != 0)
++            {
++              // Calcul du nombre d'elements a copier vers la nouvelle
++              // zone de memoire : c'est le min de l'ancienne et de
++              // la nouvelle taille.
++              if (options & COPY_OLD)
++                {
++                  copy_size = size_array_;
++                  if (new_size < copy_size)
++                    copy_size = new_size;
++                  // Copie des valeurs dans le nouveau tableau
++                  for (entier i = 0; i < copy_size; i++)
++                    new_data[i] = data_[i];
++                }
++              // Destruction de l'ancienne zone (si plus aucune reference)
++              detach_array();
++            }
++          // On attache la nouvelle zone de memoire
++          p_ = new_p;
++          data_ = new_data;
++          memory_size_ = new_mem_size;
++          // Initialisation des cases supplementaires avec une valeur par defaut
++          if (options & INITIALIZE_NEW)
++            fill_default_value(copy_size, new_mem_size - copy_size);
++          // Restaure l'ancienne valeur de size_array_
++          size_array_ = old_size_array;
++        }
++    }
++}
++
++// Description:
++//  Remplit "nb" cases consecutives du tableau a partir de la case "first"
++//  avec une valeur par defaut.
++//  Cette fonction est appelee lors d'un resize pour initialiser les
++//  cases nouvellement creees.
++//  Le comportement depend actuellement du type de tableau :
++//  * Tableau de type "smart_resize":
++//    * en mode debug (macro NDEBUG non definie) le tableau est initialise
++//      avec une valeur invalide.
++//    * en optimise, le tableau n'est pas initialise
++//  * Tableau normal :
++//    Le tableau est initialise avec la valeur 0. Ce comportement est choisi
++//    pour des raisons de compatibilite avec l'implementation precedente.
++//    Cette specification pourrait etre modifiee prochainement pour des raisons
++//    de performances (pour ne pas avoir a initialiser inutilement les tableaux).
++//    DONC: il faut supposer desormais que les nouvelles cases ne sont pas
++//    initialisees lors d'un resize.
++// Parametre: first
++//  Signification: premiere case a initialiser.
++//  Contrainte:    (nb==0) ou (0 <= first < memory_size_)
++// Parametre: nb
++//  Signification: nombre de cases a initialiser.
++//  Contrainte:    (nb==0) ou (0 < nb <= memory_size_ - first)
++void  ArrOf__Scalar__::fill_default_value(entier first, entier nb)
++{
++  assert((nb == 0) || (first >= 0 && first < memory_size_));
++  assert((nb == 0) || (nb > 0 && nb <= memory_size_ - first));
++  __scalar__ * data = addr();
++  assert(data!=0 || nb==0);
++  data += first;
++  if (smart_resize_)
++    {
++      // On initialise uniquement en mode debug
++#ifndef NDEBUG
++      __IntOnlyBegin__
++      static const entier ENTIER_INVALIDE = INT_MIN;
++      for (entier i = 0; i < nb; i++)
++        data[i] = ENTIER_INVALIDE;
++      __IntOnlyEnd__
++      __DoubleOnlyBegin__
++      // Ceci represente un NAN. N'importe quelle operation avec ca fait encore un NAN.
++      // Si c'est pas portable, on peut remplacer par DMAX_FLOAT sur les autres machines.
++      static const unsigned long long  VALEUR_INVALIDE =
++        0x7ff7ffffffffffffULL;
++
++      // On utilise "memcpy" et non "=" car "=" peut provoquer une exception
++      // si la copie passe par le fpu.
++      for (entier i = 0; i < nb; i++)
++        memcpy(data + i, & VALEUR_INVALIDE, sizeof(__scalar__));
++      __DoubleOnlyEnd__
++#endif
++    }
++  else
++    {
++      // Comportement pour les tableaux normaux : compatibilite avec la
++      // version precedente : on initialise avec 0.
++      for (entier i = 0; i < nb; i++)
++        data[i] = (__scalar__) 0;
++    }
++}
++
++// ****************************************************************
++//
++//         Fonctions non membres de la classe ArrOf__Scalar__
++//
++// ****************************************************************
++
++// Description:
++//  Renvoie 1 si les tableaux "v" et "a" sont de la meme taille
++//  et contiennent les memes valeurs au sens strict, sinon renvoie 0.
++//  Le test est !(v[i]!=a[i])
++entier operator==(const ArrOf__Scalar__& v, const ArrOf__Scalar__& a)
++{
++  const entier n = v.size_array();
++  const entier na = a.size_array();
++  entier resu = 1;
++  if (n != na)
++    {
++      resu = 0;
++    }
++  else
++    {
++      const __scalar__* vv = v.addr();
++      const __scalar__* av = a.addr();
++      entier i;
++      for (i = 0; i < n; i++)
++        {
++          if (av[i] != vv[i])
++            {
++              resu = 0;
++              break;
++            }
++        }
++    }
++  return resu;
++}
++
++// Description:
++//    Retourne l'indice du min ou -1 si le tableau est vide
++// Precondition:
++// Parametre: const ArrOf__Scalar__& dx
++//    Signification: tableau a utiliser
++// Retour: int
++//    Signification: indice du min
++entier imin_array(const ArrOf__Scalar__& dx)
++{
++  entier indice_min = -1;
++  const entier size = dx.size_array();
++  if (size > 0)
++    {
++      indice_min = 0;
++      __scalar__ valeur_min = dx[0];
++      for(entier i = 1; i < size; i++)
++        {
++          const __scalar__ val = dx[i];
++          if(val < valeur_min)
++            {
++              indice_min = i;
++              valeur_min = val;
++            }
++        }
++    }
++  return indice_min;
++}
++
++// Description:
++//    Retourne l'indice du max ou -1 si le tableau est vide
++// Precondition:
++// Parametre: const ArrOf__Scalar__& dx
++//    Signification: tableau a utiliser
++// Retour: int
++//    Signification: indice du max
++entier imax_array(const ArrOf__Scalar__& dx)
++{
++  entier indice_max = -1;
++  const entier size = dx.size_array();
++  if (size > 0)
++    {
++      indice_max = 0;
++      __scalar__ valeur_max = dx[0];
++      for(entier i = 1; i < size; i++)
++        {
++          const __scalar__ val = dx[i];
++          if(val > valeur_max)
++            {
++              indice_max = i;
++              valeur_max = val;
++            }
++        }
++    }
++  return indice_max;
++}
++
++// Description:
++//    Retourne la valeur minimale
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOf__Scalar__& dx
++//    Signification: tableau a utiliser
++// Retour: __scalar__
++//    Signification: valeur du min
++__scalar__ min_array(const ArrOf__Scalar__& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  __scalar__ valeur_min = dx[0];
++  for(entier i = 1; i < size; i++)
++    {
++      const __scalar__ val = dx[i];
++      if (val < valeur_min)
++        valeur_min = val;
++    }
++  return valeur_min;
++}
++
++// Description:
++//    Retourne la valeur maximale
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOf__Scalar__& dx
++//    Signification: tableau a utiliser
++// Retour: __scalar__
++//    Signification: valeur du max
++__scalar__ max_array(const ArrOf__Scalar__& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  __scalar__ valeur_max = dx[0];
++  for(entier i = 1; i < size; i++)
++    {
++      const __scalar__ val = dx[i];
++      if (val > valeur_max)
++        valeur_max = val;
++    }
++  return valeur_max;
++}
++
++// Description:
++//   Fonction de comparaison utilisee pour trier le tableau
++//   dans ArrOf__Scalar__::trier(). Voir man qsort
++static int fonction_compare_arrof__scalar___ordonner(const void * data1, const void * data2)
++{
++  const __scalar__ x = *(const __scalar__*)data1;
++  const __scalar__ y = *(const __scalar__*)data2;
++  __DoubleOnlyBegin__
++  if (x < y)
++    return -1;
++  else if (x > y)
++    return 1;
++  else
++    return 0;
++  __DoubleOnlyEnd__
++  __IntOnlyBegin__
++  return x - y;
++  __IntOnlyEnd__
++}
++
++// Description:
++//   Tri des valeurs du tableau dans l'ordre croissant.
++//   La fonction utilisee est qsort de stdlib (elle est en n*log(n)).
++void ArrOf__Scalar__::ordonne_array()
++{
++  const entier size = size_array();
++  if (size > 1)
++    {
++      __scalar__ * data = addr();
++      qsort(data, size, sizeof(__scalar__),
++            fonction_compare_arrof__scalar___ordonner);
++    }
++}
++
++// Description:
++//    Fait pointer le tableau vers les memes donnees qu'un tableau
++//    existant. Le tableau sera du meme type que le tableau m ("detache",
++//    "normal"). Le tableau m ne doit pas etre de type "ref_data"
++//    Les donnes existantes sont perdues si elles
++//    ne sont pas referencees ailleurs.
++// Precondition:
++// Parametre: const ArrOf__Scalar__& m
++//    Signification: le tableau a referencer (pas de type "ref_data"
++//                   et different de *this !!!)
++// Retour: ArrOf__Scalar__&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOf__Scalar__& ArrOf__Scalar__::ref_array(const ArrOf__Scalar__& m)
++{
++  assert(&m != this);
++  // La condition 'm n'est pas de type "ref_data"' est necessaire pour
++  // attach_array().
++  detach_array();
++  attach_array(m);
++  return *this;
++}
++
++// Description:
++//    Fait pointer le tableau vers la zone de memoire "data_".
++//    On detache la zone de memoire existante. Le tableau devient
++//    de type "ref_data". Attention : ptr doit etre non nul.
++//    La taille est initialisee avec size.
++//    Cette methode est appelee notamment par __Scalar__Vect::adopter.
++// Parametre: __scalar__*
++//    Signification: le tableau a recuperer. Si pointeur nul alors size
++//                   doit etre nulle aussi et le tableau reste detache
++// Parametre: entier size
++//    Signification: le nombre d'elements du tableau.
++// Retour: ArrOf__Scalar__&
++//    Signification: *this
++ArrOf__Scalar__& ArrOf__Scalar__::ref_data(__scalar__* ptr, entier size)
++{
++  assert(ptr != 0 || size == 0);
++  assert(size >= 0);
++  detach_array();
++  data_ = ptr;
++  size_array_ = size;
++  return *this;
++}
++
++// Description:
++//  Amene le tableau dans l'etat "detache". C'est a dire:
++//  Si le tableau est "detache" :
++//   * ne rien faire
++//  Si le tableau est "normal" :
++//   * decremente le nombre de references a *p
++//   * detruit *p si p->ref_count==0
++//   * annule p_, data_ et size_array_
++//  Si le tableau est "ref_data" :
++//   * annule data_ et size_array_
++// Retour: int
++//    Signification: 1 si les donnees du tableau ont ete supprimees
++// Precondition:
++// Postcondition:
++//  On a p_==0, data_==0 et size_array_==0, memory_size_ = 0
++//  L'attribut smart_resize_ est conserve.
++entier ArrOf__Scalar__::detach_array()
++{
++  entier retour = 0;
++  if (p_)
++    {
++      // Le tableau est de type "normal"
++      // Si la zone de memoire n'est plus utilisee par personne,
++      // on la detruit.
++      if ((p_->suppr_one_ref()) == 0)
++        {
++          delete p_;
++          retour = 1;
++        }
++      p_ = 0;
++    }
++  data_ = 0;
++  size_array_ = 0;
++  memory_size_ = 0;
++  return retour;
++}
++
++// Description:
++//    Amene le tableau dans l'etat "normal", "detache" ou "ref_array"
++//    en associant la meme zone de memoire que le tableau m.
++// Precondition:
++//    Le tableau doit etre "detache"
++// Parametre: const ArrOf__Scalar__& m
++//    Signification: tableau a utiliser
++//                   le tableau doit etre different de *this !!!
++// Retour:
++//    Signification:
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++//    Si m est detache, le tableau reste detache,
++//    si m est "ref_array", le tableau devient "ref_array",
++//    sinon le tableau est "normal", avec ref_count > 1
++//    Si m est de taille nulle, le tableau reste detache + Warning dans fichier .log
++void ArrOf__Scalar__::attach_array(const ArrOf__Scalar__& m)
++{
++  // Le tableau doit etre detache
++  assert(data_ == 0 && p_ == 0);
++  // Le tableau doit etre different de *this
++  assert(&m != this);
++
++  if (m.size_array() > 0)
++    {
++      p_ = m.p_;
++      if (p_)
++        p_->add_one_ref();
++      data_ = m.data_;
++      size_array_ = m.size_array_;
++      memory_size_ = m.memory_size_;
++      smart_resize_ = m.smart_resize_;
++    }
++  else
++    {
++      // Cas particulier ou on attache un tableau de taille nulle:
++      //  en theorie, c'est pareil qu'un tableau de taille non nulle, MAIS
++      //  dans les operateurs (ex:Op_Dift_VDF_Face_Axi), une ref est construite
++      //  avant que le tableau ne prenne sa taille definitive. Donc, pour ne pas
++      //  empecher le resize, il ne faut pas attacher le tableau s'il n'a pas
++      //  encore la bonne taille. Solution propre: reecrire les operateurs pour
++      //  qu'ils ne prennent pas une ref avant que le tableau ne soit valide
++      //  et faire p_ = m.p_ dans tous les cas.
++    }
++}
++
++// Description:
++//    Copie les elements source[first_element_source + i]
++//    dans les elements  (*this)[first_element_dest + i] pour 0 <= i < nb_elements
++//    Les autres elements de (*this) sont inchanges.
++// Precondition:
++// Parametre:       const ArrOf__Scalar__& m
++//  Signification:   le tableau a utiliser, doit etre different de *this !
++// Parametre:       entier nb_elements
++//  Signification:   nombre d'elements a copier, nb_elements >= -1.
++//                   Si nb_elements==-1, on copie tout le tableau m.
++//  Valeurs par defaut: -1
++// Parametre:       entier first_element_dest
++//  Valeurs par defaut: 0
++// Parametre:       entier first_element_source
++//  Valeurs par defaut: 0
++// Retour: ArrOf__Scalar__&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++//    Sort en erreur si la taille du tableau m est plus grande que la
++//    taille de tableau this.
++// Effets de bord:
++// Postcondition:
++ArrOf__Scalar__& ArrOf__Scalar__::inject_array(const ArrOf__Scalar__& source,
++    entier nb_elements,
++    entier first_element_dest,
++    entier first_element_source)
++{
++  assert(&source != this);
++  assert(nb_elements >= -1);
++  assert(first_element_dest >= 0);
++  assert(first_element_source >= 0);
++
++  if (nb_elements < 0)
++    nb_elements = source.size_array();
++
++  assert(first_element_source + nb_elements <= source.size_array());
++  assert(first_element_dest + nb_elements <= size_array());
++
++  if (nb_elements > 0)
++    {
++      __scalar__ * addr_dest = addr() + first_element_dest;
++      const __scalar__ * addr_source = source.addr() + first_element_source;
++      // memcpy(addr_dest , addr_source, nb_elements * sizeof(__scalar__));
++      entier i;
++      for (i = 0; i < nb_elements; i++)
++        {
++          addr_dest[i] = addr_source[i];
++        }
++    }
++  return *this;
++}
++
++// Description:
++//    Retourne le nombre de references des donnees du tableau
++//    si le tableau est "normal", -1 s'il est "detache" ou "ref_data"
++// Retour: int
++//    Signification: ref_count_
++entier ArrOf__Scalar__::ref_count() const
++{
++  if (p_)
++    return p_->ref_count();
++  else
++    return -1;
++}
++
++// Description:
++//    Addition case a case sur toutes les cases du tableau
++// Precondition:
++//    la taille de y doit etre au moins egale a la taille de this
++// Parametre: const ArrOf__Scalar__& y
++//    Signification: tableau a ajouter
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOf__Scalar__&
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOf__Scalar__& ArrOf__Scalar__::operator+=(const ArrOf__Scalar__& y)
++{
++  assert(size_array()==y.size_array());
++  __scalar__* dx = addr();
++  const __scalar__* dy = y.addr();
++  const entier n = size_array();
++  for (entier i=0; i<n; i++)
++    dx[i] += dy[i];
++  return *this;
++}
++
++// Description:
++//     ajoute la meme valeur a toutes les cases du tableau
++// Precondition:
++// Parametre: const __scalar__ dy
++//    Signification: valeur a ajouter
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: ArrOf__Scalar__
++//    Signification: *this
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++ArrOf__Scalar__& ArrOf__Scalar__::operator+=(const __scalar__ dy)
++{
++  __scalar__ * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] += dy;
++  return *this;
++}
++// Description:
++//    Soustraction case a case sur toutes les cases du tableau
++// Parametre: const ArrOf__Scalar__& y
++//    Signification: tableau de meme taille que *this
++// Retour: ArrOf__Scalar__&
++//    Signification: *this
++ArrOf__Scalar__& ArrOf__Scalar__::operator-=(const ArrOf__Scalar__& y)
++{
++  const entier size = size_array();
++  assert(size == y.size_array());
++  __scalar__ * data = addr();
++  const __scalar__ * data_y = y.addr();
++  for (entier i=0; i < size; i++)
++    data[i] -= data_y[i];
++  return *this;
++}
++
++
++// Description:
++//     soustrait la meme valeur a toutes les cases
++// Retour: ArrOf__Scalar__ &
++//    Signification: *this
++ArrOf__Scalar__& ArrOf__Scalar__::operator-=(const __scalar__ dy)
++{
++  __scalar__ * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] -= dy;
++  return *this;
++}
++
++// Description:
++//   Renvoie un pointeur sur le premier element du tableau.
++//   Le pointeur est nul si le tableau est "detache".
++//   Attention, l'adresse peut changer apres un appel
++//   a resize_array(), ref_data, ref_array, ...
++// Precondition:
++// Retour: const __scalar__*
++//   Signification: pointeur sur le premier element du tableau
++const __scalar__* ArrOf__Scalar__::addr() const
++{
++  return data_;
++}
++
++// Description:
++//   Renvoie un pointeur sur le premier element du tableau.
++//   Le pointeur est nul si le tableau est "detache".
++// Precondition:
++// Retour: const __scalar__*
++//    Signification: la zone memoire du tableau
++__scalar__* ArrOf__Scalar__::addr()
++{
++  return data_;
++}
++
++__DoubleOnlyBegin__
++
++// Description:
++//    Retourne le max des abs(i)
++// Precondition:
++//    Le tableau doit contenir au moins une valeur
++// Parametre: const ArrOf__Scalar__& dx
++//    Signification: tableau a utiliser
++//    Valeurs par defaut:
++//    Contraintes:
++//    Acces:
++// Retour: __scalar__
++//    Signification: valeur du max des valeurs absolues
++//    Contraintes:
++// Exception:
++// Effets de bord:
++// Postcondition:
++__scalar__ max_abs_array(const ArrOf__Scalar__& dx)
++{
++  const entier size = dx.size_array();
++  assert(size > 0);
++  __scalar__ valeur_max = fabs(dx[0]);
++  for(entier i = 1; i < size; i++)
++    {
++      const __scalar__ val = fabs(dx[i]);
++      if (val > valeur_max)
++        valeur_max = val;
++    }
++  return valeur_max;
++}
++
++// Description:
++//     muliplie toutes les cases par dy
++// Retour: ArrOf__Scalar__ &
++//    Signification: *this
++ArrOf__Scalar__& ArrOf__Scalar__::operator*= (const __scalar__ dy)
++{
++  __scalar__ * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] *= dy;
++  return *this;
++}
++
++
++// Description:
++//     divise toutes les cases par dy
++// Retour: ArrOf__Scalar__ &
++//    Signification: *this
++ArrOf__Scalar__& ArrOf__Scalar__::operator/= (const __scalar__ dy)
++{
++  // En theorie: les deux lignes suivantes sont plus efficaces, mais
++  //  cela produit des differences sur certains cas tests
++  //  (Hyd_C_VEF_Smago et Lambda_var_VEF_turb). Ca veut dire qu'il y
++  //  a un probleme autre part mais pour l'instant on laisse l'ancien
++  //  codage.
++  // const __scalar__ i_dy = 1. / dy;
++  // operator*=(i_dy);
++
++  __scalar__ * data = addr();
++  const entier n = size_array();
++  for(entier i=0; i < n; i++)
++    data[i] /= dy;
++
++  return *this;
++}
++__DoubleOnlyEnd__
++
++__Scalar__Tab::__Scalar__Tab()
++{
++  nb_dim_ = 2;
++  dimensions_[0] = 0;
++  dimensions_[1] = 0;
++}
++
++__Scalar__Tab::__Scalar__Tab(const __Scalar__Tab& tab) :
++  ArrOf__Scalar__(tab)
++{
++  nb_dim_ = tab.nb_dim_;
++  dimensions_[0] = tab.dimensions_[0];
++  dimensions_[1] = tab.dimensions_[1];
++}
++__Scalar__Tab::__Scalar__Tab(const entier i, const entier j) :
++  ArrOf__Scalar__(i*j)
++{
++  nb_dim_ = 2;
++  dimensions_[0] = i;
++  dimensions_[1] = j;
++}
++
++__Scalar__Tab& __Scalar__Tab::operator=(const __Scalar__Tab& tab)
++{
++  ArrOf__Scalar__::operator=(tab);
++  nb_dim_ = tab.nb_dim_;
++  dimensions_[0] = tab.dimensions_[0];
++  dimensions_[1] = tab.dimensions_[1];
++  return *this;
++}
++
++void __Scalar__Tab::reset()
++{
++  ArrOf__Scalar__::reset();
++  nb_dim_ = 2;
++  dimensions_[0] = 0;
++  dimensions_[1] = 0;
++}
+diff --git a/databases/readers/Lata/ArrOf_Scalar_Prototype.h b/databases/readers/Lata/ArrOf_Scalar_Prototype.h
+new file mode 100644
+index 0000000..689932f
+--- /dev/null
++++ b/databases/readers/Lata/ArrOf_Scalar_Prototype.h
+@@ -0,0 +1,357 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++
++#ifndef ArrOf__Scalar___H
++#define ArrOf__Scalar___H
++
++#include <assert.h>
++#include <arch.h>
++#include <Objet_U.h>
++
++__DoubleOnlyBegin__
++#define DMAXFLOAT 1e40
++__DoubleOnlyEnd__
++
++class V__Scalar__data;
++
++class ArrOf__Scalar__
++{
++public:
++  //
++  // Destructeur
++  //
++  virtual ~ArrOf__Scalar__();
++  //
++  // Constructeurs
++  //
++  ArrOf__Scalar__();
++  ArrOf__Scalar__(entier size);
++  ArrOf__Scalar__(entier size, __scalar__ initial_value);
++  // Constructeur par copie : deep copy (on duplique les donnees)
++  ArrOf__Scalar__(const ArrOf__Scalar__& );
++  //
++  // Methodes de construction tardive (on cree un tableau vide avec ArrOf__Scalar__()
++  // puis on appelle ces methodes pour modifier les caracteristiques du tableau :
++  //
++  // Change le nombre d'elements du tableau
++  inline ArrOf__Scalar__& resize_array(entier new_size);
++
++  // Methodes de gestion de l'allocation memoire:
++  // Assigne une valeur au drapeau "smart_resize"
++  // (reallocation uniquement si la taille augmente)
++  void    set_smart_resize(entier flag);
++  // Gestion du type de memoire alouee (standard ou pool de memoire Trio-U)
++  enum    Storage { STANDARD, TEMP_STORAGE };
++  void    set_mem_storage(const Storage storage);
++  Storage get_mem_storage() const;
++
++  // Construction de tableaux qui pointent vers des donnees existantes
++  // !!! Utiliser ref_data avec precaution (attention a size_array_)
++  ArrOf__Scalar__& ref_data(__scalar__* ptr, entier size);
++  ArrOf__Scalar__& ref_array(const ArrOf__Scalar__&);
++  // Operateur copie
++  ArrOf__Scalar__& operator=(const ArrOf__Scalar__&);
++  // Remise du tableau dans l'etat initial (obtenu par le constructeur par defaut)
++  virtual void reset();
++
++  //
++  // Methodes d'acces aux donnees et aux caracteristiques du tableau
++  //
++  // Remplit le tableau avec la valeur en parametre
++  ArrOf__Scalar__& operator=(__scalar__ valeur);
++
++  inline       __scalar__& operator[](entier i);
++  inline const __scalar__& operator[](entier i) const;
++
++  // Ces methodes renvoient un pointeur vers le premier element du tableau.
++  const __scalar__ * addr() const;
++  __scalar__ * addr();
++  // Renvoie le nombre d'elements du tableau (et non la taille allouee)
++  inline entier size_array() const;
++  // Renvoie le nombre de tableaux qui pointent vers la stucture "*p_"
++  entier ref_count() const;
++  // Ajoute une case en fin de tableau et y stocke la "valeur"
++  inline void   append_array(__scalar__ valeur);
++
++  //
++  // Operateurs divers
++  //
++  ArrOf__Scalar__& operator+=(const ArrOf__Scalar__&);
++  ArrOf__Scalar__& operator+=(const __scalar__);
++  ArrOf__Scalar__& operator-=(const ArrOf__Scalar__&);
++  ArrOf__Scalar__& operator-=(const __scalar__);
++  ArrOf__Scalar__& inject_array(const ArrOf__Scalar__ & source,
++                                entier nb_elements = -1,
++                                entier first_element_dest = 0,
++                                entier first_element_source = 0);
++  ArrOf__Scalar__& copy_array(const ArrOf__Scalar__&);
++
++  __DoubleOnlyBegin__
++  ArrOf__Scalar__& operator*= (const __scalar__) ;
++  ArrOf__Scalar__& operator/= (const __scalar__) ;
++  __DoubleOnlyEnd__
++
++  void             ordonne_array();
++
++protected:
++  //
++  // Methodes accessibles depuis les descendants de ArrOf__Scalar__
++  //
++  void   attach_array(const ArrOf__Scalar__&);
++  entier detach_array();
++  void   fill_default_value(entier first, entier nb);
++private:
++  // B. Mathieu 22/06/2004 : je mets ces membres "private" pour forcer
++  // le passage par les accesseurs dans les classes derivees, au cas ou
++  // on voudrait modifier l'implementation.
++
++  // Zone de memoire contenant les valeurs du tableau.
++  // Pointeur nul => le tableau est "detache" ou "ref_data"
++  // Pointeur non nul => le tableau est "normal"
++  V__Scalar__data* p_;
++
++  // Pointeur vers le premier element du tableau (egal a p_->data si p_!=0)
++  // Pointeur nul => le tableau est "detache".
++  // Pointeur non nul => le tableau est "normal" ou "ref_data"
++  __scalar__*   data_;
++
++  // Nombre d'elements du tableau (inferieur ou egal a memory_size_).
++  // Si le tableau est "detache", alors size_array_=0
++  entier    size_array_;
++  // Taille memoire reellement allouee pour le tableau
++  // (pour le mecanisme smart_resize_). memory_size_ est nul
++  // si le tableau est de type "ref_data". Sinon memory_size_
++  // est egal a p_->size_.
++  entier    memory_size_;
++
++  // Drapeau indiquant si on applique une strategie d'allocation
++  // preventive (la memoire alouee augmente d'un facteur constant
++  // si la taille devient insuffisante).
++  // Si smart_resize_ == 0, alors on a toujours p_->size_ == size
++  entier    smart_resize_;
++
++  // Drapeau indiquant si l'allocation memoire a lieu avec un new classique
++  // ou dans le pool de memoire temporaire de Trio
++  Storage   storage_type_;
++
++  // Partie non inline de resize_array():
++  // Declaration des constantes pour les options de memory_resize
++  static const entier COPY_OLD;
++  static const entier INITIALIZE_NEW;
++  void memory_resize(entier new_size, entier options);
++};
++
++#define MAXDIM__Scalar__Tab 2
++
++class __Scalar__Tab : public ArrOf__Scalar__
++{
++public:
++  __Scalar__Tab();
++  __Scalar__Tab(const __Scalar__Tab&);
++  __Scalar__Tab(const entier i, const entier j);
++  __Scalar__Tab&    operator=(const __Scalar__Tab&);
++  void              reset();
++
++  inline __scalar__& operator()(entier i, entier j);
++  inline __scalar__   operator()(entier i, entier j) const;
++
++  inline entier resize(entier i, entier j);
++  inline entier dimension(entier i) const;
++  inline entier dimension_tot(entier i) const;
++
++protected:
++  // In order to mimic TRUST behavior, operator[] is forbidden
++  // for 2 dimensionnal matrices, you must cast to ArrOf to use it..
++  double&        operator[](entier i);
++  const double& operator[](entier i) const;
++
++private:
++  entier nb_dim_;
++  entier dimensions_[MAXDIM__Scalar__Tab];
++};
++
++inline __scalar__& __Scalar__Tab::operator()(entier i, entier j)
++{
++  assert(nb_dim_ == 2);
++  assert(i >= 0 && i < dimensions_[0] && j >= 0 && j < dimensions_[1]);
++  const entier n = i * dimensions_[1] + j;
++  __scalar__ & x = ArrOf__Scalar__::operator[] (n);
++  return x;
++}
++
++inline __scalar__   __Scalar__Tab::operator()(entier i, entier j) const
++{
++  assert(nb_dim_ == 2);
++  assert(i >= 0 && i < dimensions_[0] && j >= 0 && j < dimensions_[1]);
++  const entier n = i * dimensions_[1] + j;
++  __scalar__ x = ArrOf__Scalar__::operator[] (n);
++  return x;
++}
++
++inline entier __Scalar__Tab::resize(entier i, entier j)
++{
++  assert(i >= 0 && j >= 0);
++  nb_dim_ = 2;
++  dimensions_[0] = i;
++  dimensions_[1] = j;
++  ArrOf__Scalar__::resize_array(i * j);
++  return i*j;
++}
++
++inline entier __Scalar__Tab::dimension(entier i) const
++{
++  assert(i >= 0 && i < nb_dim_);
++  return dimensions_[i];
++}
++
++// Description: renvoie la meme valeur que dimension.
++inline entier __Scalar__Tab::dimension_tot(entier i) const
++{
++  return dimension(i);
++}
++
++//
++// Declarations des fonctions non membres de la classe ArrOf__Scalar__
++//
++entier operator==(const ArrOf__Scalar__& x, const ArrOf__Scalar__& y) ;
++entier imin_array(const ArrOf__Scalar__&) ;
++entier imax_array(const ArrOf__Scalar__&) ;
++__scalar__ min_array(const ArrOf__Scalar__&) ;
++__scalar__ max_array(const ArrOf__Scalar__&) ;
++
++__DoubleOnlyBegin__
++__scalar__ max_abs_array(const ArrOf__Scalar__&) ;
++__DoubleOnlyEnd__
++
++// ******************************************************************
++//                   FONCTIONS MEMBRES DE ArrOf__Scalar__
++// ******************************************************************
++
++// Description :
++//  Change le nombre d'elements du tableau. Cette fonction est inline
++//  car elle doit etre tres rapide dans le cas ou smart_resize_==1
++//  (utilisation frequente de resize_array())
++//  Si smart_resize est non nul :
++//   Si la nouvelle taille est inferieure ou egale a la taille
++//   alouee (p->get_size()) on ne realloue pas de memoire
++//   sinon, on realloue et on copie les donnees existantes.
++//  Astuce pour ne pas copier les anciennes donnees:
++//   resize(0); resize(n);
++//  Si smart_resize est nul, on realloue une nouvelle zone memoire
++//   uniquement si la nouvelle taille est differente de l'ancienne.
++// Precondition :
++//  Si "new_size" est egal a la taille du tableau, aucune condition.
++//  Sinon, le tableau doit etre soit detache, soit normal (pas de type "ref_data")
++//  et ref_count doit etre egal a 1 (pas d'autre reference au tableau).
++//
++inline ArrOf__Scalar__& ArrOf__Scalar__::resize_array(entier new_size)
++{
++  assert(new_size >= 0);
++  // Soit le tableau est detache (data_==0), soit il est normal (p_!=0)
++  // S'il est normal, il ne faut pas qu'il y ait d'autre reference au tableau,
++  // ou alors la taille ne doit pas changer.
++  assert(new_size == size_array_ || data_ == 0 || (p_ != 0 && ref_count() == 1));
++
++  if ((smart_resize_ == 0) || (new_size > memory_size_))
++    memory_resize(new_size, COPY_OLD + INITIALIZE_NEW);
++  size_array_ = new_size;
++  return *this;
++}
++
++// Description:
++//     operateur [] retourne le ieme element du tableau
++// Precondition:
++// Parametre: entier i
++//    Signification: indice dans l'intervalle 0 <= i < size_array()
++// Exception:
++__DoubleOnlyBegin__
++//    assert si la valeur sort de l'intervalle : [ -DMAXFLOAT,DMAXFLOAT ]
++__DoubleOnlyEnd__
++//    assert si i n'est pas dans l'intervalle
++inline __scalar__& ArrOf__Scalar__::operator[](entier i)
++{
++  assert(i >= 0 && i < size_array_);
++  __DoubleOnlyBegin__
++  assert(data_[i] > -DMAXFLOAT && data_[i] < DMAXFLOAT);
++  __DoubleOnlyEnd__
++  return data_[i];
++}
++
++// Description:
++//     operateur [] retourne le ieme element du tableau
++// Precondition:
++// Parametre: entier i
++//    Signification: indice dans l'intervalle 0 <= i < size_array()
++// Exception:
++__DoubleOnlyBegin__
++//    assert si la valeur sort de l'intervalle : [ -DMAXFLOAT,DMAXFLOAT ]
++__DoubleOnlyEnd__
++//    assert si i n'est pas dans l'intervalle
++inline const __scalar__& ArrOf__Scalar__::operator[](entier i) const
++{
++  assert(i >= 0 && i < size_array_);
++  __DoubleOnlyBegin__
++  assert(data_[i] > -DMAXFLOAT && data_[i] < DMAXFLOAT);
++  __DoubleOnlyEnd__
++  return data_[i];
++}
++
++// Description:
++//    Renvoie la taille du tableau (nombre d'elements declares
++//    a la construction ou a resize_array()).
++//    C'est le nombre d'elements accessibles a operator[]
++// Retour: entier
++inline entier  ArrOf__Scalar__::size_array() const
++{
++  return size_array_;
++}
++
++// Description:
++//  Ajoute une case en fin de tableau et y stocke la "valeur"
++// Precondition:
++//  Tableau doit etre de type "smart_resize" (sinon, ecroulement
++//  des performances). De plus, le tableau ne doit pas etre "ref_data",
++//  et il ne doit pas y avoir plus d'une reference a la zone de
++//  memoire pointee (meme precondition que resize_array())
++inline void   ArrOf__Scalar__::append_array(__scalar__ valeur)
++{
++  assert(smart_resize_);
++  // Soit le tableau est detache (data_==0), soit il est normal (p_!=0)
++  // S'il est normal, il ne faut pas qu'il y ait d'autre reference au tableau.
++  assert(data_ == 0 || (p_ != 0 && ref_count() == 1));
++
++  if (size_array_+1 > memory_size_)
++    memory_resize(size_array_+1, COPY_OLD);
++  data_[size_array_] = valeur;
++  size_array_++;
++}
++
++// ArrOf__Scalar___H
++#endif
+diff --git a/databases/readers/Lata/CMakeLists.txt b/databases/readers/Lata/CMakeLists.txt
+new file mode 100644
+index 0000000..be611f3
+--- /dev/null
++++ b/databases/readers/Lata/CMakeLists.txt
+@@ -0,0 +1,35 @@
++set(SOURCES
++  avtlataFileFormat.C
++  LataDB.C
++  LataFilter.C
++  LataStructures.C
++  Lata_tools.C
++  LataV1_field_definitions.C
++  LataWriter.C
++  LmlReader.C
++  OpenDXWriter.C
++  OperatorBoundary.C
++  OperatorDualMesh.C
++  OperatorFacesMesh.C
++  OperatorReconnect.C
++  OperatorRegularize.C
++  Rebuild_virtual_layer.C
++  UserFields.C
++  ArrOfBit.C
++  ArrOfDouble.C
++  ArrOfFloat.C
++  ArrOfInt.C
++  Connectivite_som_elem.C
++  Motcle.C
++  Octree_Double.C
++  Octree_Int.C
++  Static_Int_Lists.C
++  )
++
++MESSAGE("Here I am")
++
++ADD_VISIT_READER(VisItLataReader "1.0"
++  VISIT_READER_TYPE "MTMD"
++  VISIT_READER_NAME "avtlataFileFormat"
++  SERVER_SOURCES ${SOURCES}
++  )
+diff --git a/databases/readers/Lata/Connectivite_som_elem.C b/databases/readers/Lata/Connectivite_som_elem.C
+new file mode 100644
+index 0000000..2a268cc
+--- /dev/null
++++ b/databases/readers/Lata/Connectivite_som_elem.C
+@@ -0,0 +1,189 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <Connectivite_som_elem.h>
++#include <Static_Int_Lists.h>
++#include <IntTab.h>
++
++// Description: construction de la structure som_elem pour la zone donnee
++//  On cree pour chaque sommet i la liste des elements adjacents a ce sommet
++//  (c'est la liste des elements k tels que il existe j tel que les_elems(k,j) == i)
++// Parametre:   nb_sommets
++// Description: nombre de sommets utilises dans les elements (som_elem contiendra
++//              autant de listes). Si include_virtual==1, c'est le nombre de sommets
++//              total, sinon c'est le nombre de sommets reels
++// Parametre:   les_elems
++// Description: tableau des elements (contient les numeros des sommets de chaque element)
++//              Les valeurs du tableau doivent etre inferieurs a nb_sommets.
++// Parametre:   som_elem
++// Description: la structure dans laquelle on stocke le resultat. L'ancien
++//   contenu est perdu. Chaque liste d'elements est triee dans l'ordre croissant
++// Parametre:   include_virtual
++// Description: 0 => seuls les elements reels sont inclus dans la structure
++//              1 => on inclut les elements virtuels (donc les sommets virtuels)
++void construire_connectivite_som_elem(const entier       nb_sommets,
++                                      const IntTab&      les_elems,
++                                      Static_Int_Lists& som_elem,
++                                      const entier       include_virtual)
++{
++  // Nombre d'elements du domaine
++  const entier nb_elem = (include_virtual) ? les_elems.dimension_tot(0) : les_elems.dimension(0);
++  // Nombre de sommets par element
++  const entier nb_sommets_par_element = les_elems.dimension(1);
++
++  // Construction d'un tableau initialise a zero : pour chaque sommet,
++  // nombre d'elements voisins de ce sommet
++  ArrOfInt nb_elements_voisins(nb_sommets, 0);
++
++  // Premier passage : on calcule le nombre d'elements voisins de chaque
++  // sommet pour creer la structure de donnees
++  entier elem, i;
++
++  for (elem = 0; elem < nb_elem; elem++)
++    {
++      for (i = 0; i < nb_sommets_par_element; i++)
++        {
++          entier sommet = les_elems(elem, i);
++          // GF cas des polyedres
++          if (sommet==-1) break;
++          nb_elements_voisins[sommet]++;
++        }
++    }
++
++  som_elem.set_list_sizes(nb_elements_voisins);
++
++  // On reutilise le tableau pour stocker le nombre d'elements dans
++  // chaque liste pendant qu'on la remplit
++  nb_elements_voisins = 0;
++
++  // Remplissage du tableau des elements voisins.
++  for (elem = 0; elem < nb_elem; elem++)
++    {
++      for (i = 0; i < nb_sommets_par_element; i++)
++        {
++          entier sommet = les_elems(elem, i);
++          // GF cas des polyedres
++          if (sommet==-1) break;
++          entier n = (nb_elements_voisins[sommet])++;
++          som_elem.set_value(sommet, n, elem);
++        }
++    }
++
++  // Tri de toutes les listes dans l'ordre croissant
++  som_elem.trier_liste(-1);
++}
++
++// Description: Cherche les elements qui contiennent tous les sommets
++//  du tableau sommets_to_find (permet de trouver les elements
++//  adjacents a une face ou une arete)
++// Parametre:     som_elem
++// Signification: pour chaque sommet, liste triee des elements adjacents
++//                (voir construire_connectivite_som_elem)
++// Parametre:     sommets_to_find
++// Signification: une liste de sommets
++// Parametre:     elements
++// Signification: resultat de la recherche: la liste des elements qui
++//                contiennent tous les sommets de sommets_to_find.
++//                Si sommets_to_find est vide, on renvoie un tableau vide.
++//                (en cas d'appels repetes a cette fonction, il est
++//                 conseille de mettre le drapeau "smart_resize")
++void find_adjacent_elements(const Static_Int_Lists& som_elem,
++                            const ArrOfInt& sommets_to_find,
++                            ArrOfInt& elements)
++{
++  entier nb_som_to_find = sommets_to_find.size_array();
++  // on retire les sommets valant -1 (cas ou plusieurs types de faces)
++  while (sommets_to_find[nb_som_to_find-1]==-1) nb_som_to_find--;
++  if (nb_som_to_find == 0)
++    {
++      elements.resize_array(0);
++      return;
++    }
++  // Algorithme: on initialise elements avec tous les elements adjacents
++  //  au premier sommet de la liste.
++  //  Puis pour chacun des autres sommets de la liste, on retire du tableau
++  //  "elements" les elements qui ne sont pas voisins du sommet.
++  //  A la fin, il ne reste que les elements qui sont dans toutes les listes.
++  {
++    // Initialisation avec les elements adjacents au premier sommet
++    const entier sommet = sommets_to_find[0];
++    som_elem.copy_list_to_array(sommet, elements);
++  }
++  entier nb_elem_found = elements.size_array();
++  entier i_sommet;
++  for (i_sommet = 1; i_sommet < nb_som_to_find; i_sommet++)
++    {
++      const entier sommet = sommets_to_find[i_sommet];
++      // Calcul des elements communs entre elements[.] et som_elem(sommet,.)
++      // Nombre d'elements communs entre elements et la nouvelle liste de sommets
++      entier nb_elems_restants = 0;
++      // Nombre d'elements adjacents au "sommet"
++      const entier nb_elem_liste = som_elem.get_list_size(sommet);
++      // On suppose que les listes d'elements sont triees dans l'ordre croissant
++      // On parcourt simultanement les deux listes et on conserve les elements
++      // communs.
++      entier i = 0;
++      entier j = 0;
++      if (nb_elem_found == 0)
++        break;
++      if (nb_elem_liste > 0)
++        {
++          while (1)
++            {
++              const entier elem_i = elements[i];
++              const entier elem_j = som_elem(sommet, j);
++              if (elem_i == elem_j)
++                {
++                  // Element commun aux deux listes, on le garde
++                  elements[nb_elems_restants] = elem_i;
++                  nb_elems_restants++;
++                }
++              if (elem_i >= elem_j)
++                {
++                  j++;
++                  if (j >= nb_elem_liste)
++                    break;
++                }
++              if (elem_j >= elem_i)
++                {
++                  i++;
++                  if (i >= nb_elem_found)
++                    break;
++                }
++            }
++        }
++      else
++        {
++          nb_elems_restants = 0;
++        }
++      nb_elem_found = nb_elems_restants;
++    }
++  elements.resize_array(nb_elem_found);
++}
++
+diff --git a/databases/readers/Lata/Connectivite_som_elem.h b/databases/readers/Lata/Connectivite_som_elem.h
+new file mode 100644
+index 0000000..758b030
+--- /dev/null
++++ b/databases/readers/Lata/Connectivite_som_elem.h
+@@ -0,0 +1,44 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++
++#include <arch.h>
++
++class IntTab;
++class ArrOfInt;
++class Static_Int_Lists;
++
++void construire_connectivite_som_elem(const entier       nb_sommets,
++                                      const IntTab&      les_elems,
++                                      Static_Int_Lists& som_elem,
++                                      const entier       include_virtual);
++
++void find_adjacent_elements(const Static_Int_Lists& som_elem,
++                            const ArrOfInt& sommets_to_find,
++                            ArrOfInt& elements);
+diff --git a/databases/readers/Lata/DoubleTab.h b/databases/readers/Lata/DoubleTab.h
+new file mode 100644
+index 0000000..1731563
+--- /dev/null
++++ b/databases/readers/Lata/DoubleTab.h
+@@ -0,0 +1,30 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <ArrOfDouble.h>
+diff --git a/databases/readers/Lata/EFichier.h b/databases/readers/Lata/EFichier.h
+new file mode 100644
+index 0000000..3cf0ee8
+--- /dev/null
++++ b/databases/readers/Lata/EFichier.h
+@@ -0,0 +1,60 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef EFichier_H
++#define EFichier_H
++#include <Entree.h>
++class EFichier : public Entree
++{
++public:
++  int ouvrir(const char *name)
++  {
++    is_.open(name);
++    return is_.good();
++  }
++  operator std::istream& ()
++  {
++    return is_;
++  }
++  int eof()
++  {
++    return is_.eof();
++  }
++  int good()
++  {
++    return is_.good();
++  }
++  std::istream& get_istream()
++  {
++    return is_;
++  }
++private:
++  std::ifstream is_;
++};
++#endif
+diff --git a/databases/readers/Lata/Entree.h b/databases/readers/Lata/Entree.h
+new file mode 100644
+index 0000000..2f36fea
+--- /dev/null
++++ b/databases/readers/Lata/Entree.h
+@@ -0,0 +1,77 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef Entree_H
++#define Entree_H
++#include <iostream>
++#include <fstream>
++#include <Motcle.h>
++// This class emulates the main functionalities of the Entree and EFichier classes in TRUST
++class Entree
++{
++public:
++  virtual operator std::istream& () = 0;
++  virtual int eof() = 0;
++  virtual int good() = 0;
++  virtual ~Entree() {};
++  virtual std::istream& get_istream() = 0;
++};
++
++inline Entree& operator>>(Entree& is, double& t)
++{
++  is.get_istream() >> t;
++  return is;
++}
++inline Entree& operator>>(Entree& is, float& t)
++{
++  is.get_istream() >> t;
++  return is;
++}
++inline Entree& operator>>(Entree& is, Nom& n)
++{
++  is.get_istream() >> n;
++  return is;
++}
++inline Entree& operator>>(Entree& is, Motcle& n)
++{
++  is.get_istream() >> n;
++  return is;
++}
++inline Entree& operator>>(Entree& is, entier& n)
++{
++  is.get_istream() >> n;
++  return is;
++}
++class ArrOfInt;
++// For Static_Int_Lists:
++inline Entree& operator>>(Entree& is, ArrOfInt& t)
++{
++  throw;
++}
++#endif
+diff --git a/databases/readers/Lata/FloatTab.h b/databases/readers/Lata/FloatTab.h
+new file mode 100644
+index 0000000..351313d
+--- /dev/null
++++ b/databases/readers/Lata/FloatTab.h
+@@ -0,0 +1,30 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <ArrOfFloat.h>
+diff --git a/databases/readers/Lata/IntTab.h b/databases/readers/Lata/IntTab.h
+new file mode 100644
+index 0000000..c8cb65c
+--- /dev/null
++++ b/databases/readers/Lata/IntTab.h
+@@ -0,0 +1,31 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <ArrOfInt.h>
++
+diff --git a/databases/readers/Lata/LataDB.C b/databases/readers/Lata/LataDB.C
+new file mode 100644
+index 0000000..84e4cc4
+--- /dev/null
++++ b/databases/readers/Lata/LataDB.C
+@@ -0,0 +1,2313 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <errno.h>
++#include <LataDB.h>
++#include <stdio.h>
++#include <EFichier.h>
++#include <LataV1_field_definitions.h>
++#include <iostream>
++#include <fstream>
++#include <string.h>
++#include <stdlib.h>
++
++#include <LataDBmed.h>
++
++// Verbose level for which main lata file interpretation should be printed:
++//  Dump one line for the whole file at verb_level-1
++//  Dump one line for each Geometry, Temps, or Champ at verb_level
++//  Detailed Geometry and Champ metadata is printed out at verb_level+1
++#define verb_level 4
++// Verbose level for data bloc reading:
++//  Dump one line for each read data bloc at this level
++//  Dump detailed subbloc interpretation at level+1
++#define verb_level_data_bloc 5
++
++typedef int LataDBInt32;
++typedef long long int LataDBInt64;
++
++void arch_check()
++{
++  if (sizeof(LataDBInt32)!=4)
++    Journal() << "Error in LataDB arch_check : wrong LataDBInt32" << endl;
++  if (sizeof(LataDBInt64)!=8)
++    Journal() << "Error in LataDB arch_check : wrong LataDBInt64" << endl;
++}
++
++const char * LataDBField::memory_buffer_file()
++{
++  return "MEMORY_BUFFERED_DATA";
++}
++
++Field_UName::Field_UName()
++{
++}
++
++Field_UName::Field_UName(const Field_UName & f) :
++  geometry_(f.geometry_), field_name_(f.field_name_), loc_(f.loc_)
++{
++}
++
++Field_UName::Field_UName(const char *domain_name, const char *field_name, const char *loc) :
++  geometry_(domain_name), field_name_(field_name), loc_(loc)
++{
++  if (loc_ == "??")
++    loc_ = "";
++}
++
++Field_UName & Field_UName::operator=(const Field_UName & f)
++{
++  geometry_ = f.geometry_;
++  field_name_ = f.field_name_;
++  loc_ = f.loc_;
++  return *this;
++}
++
++Nom Field_UName::build_string() const
++{
++  Nom n(geometry_);
++  n += "_";
++  n += field_name_;
++  if (loc_ != "" && loc_ != "??") {
++    n += "_";
++    n += loc_;
++  }
++  return n;
++}
++
++void Field_UName::set_field_name(const Nom & n)
++{
++  field_name_ = n;
++}
++
++int Field_UName::operator==(const Field_UName & f) const
++{
++  return (geometry_ == f.geometry_) && (field_name_ == f.field_name_) && (loc_ == f.loc_);
++}
++
++std::ostream & operator<<(std::ostream & os, const Field_UName & uname)
++{
++  os << uname.build_string();
++  return os;
++}
++
++// This is a duplicate of Domain... only used for old latav1 compatibility
++// (otherwise, LataDB should not have to know about element types !)
++LataDB::Element LataDB::element_type_from_string(const Motcle & type_elem)
++{
++  Element type;
++  if (type_elem == "HEXAEDRE")
++    type=hexa;
++  else if (type_elem == "HEXAEDRE_AXI")
++    type=hexa;
++  else if (type_elem == "HEXAEDRE_VEF")
++    type=hexa;
++  else if (type_elem == "QUADRANGLE")
++    type=quadri;
++  else if (type_elem == "QUADRANGLE_3D")
++    type=quadri;
++  else if (type_elem == "RECTANGLE")
++    type=quadri;
++  else if (type_elem == "RECTANGLE_2D_AXI")
++    type=quadri;
++  else if (type_elem == "RECTANGLE_AXI")
++    type=quadri;
++  else if (type_elem == "SEGMENT")
++    type=line;
++  else if (type_elem == "SEGMENT_2D")
++    type=line;
++  else if (type_elem == "TETRAEDRE")
++    type=tetra;
++  else if (type_elem == "TRIANGLE")
++    type=triangle;
++  else if (type_elem == "TRIANGLE_3D")
++    type=triangle;
++  else if (type_elem.debute_par("POLYEDRE"))
++    type=polyedre;
++  else if (type_elem.debute_par("POLYGONE"))
++    type=polygone;
++  else {
++    Journal() << "Error in elem_type_from_string: unknown element type " << type_elem << endl;
++    throw(LataDBError(LataDBError::BAD_ELEM_TYPE));
++  }
++  return type;
++}
++
++void LataDB::get_element_data(const Motcle & elemtype, entier & dimension, entier & elem_shape, entier & face_shape, entier & nb_elem_faces)
++{
++  Element elem = element_type_from_string(elemtype);
++  switch(elem) {
++  case line:        dimension = 2; elem_shape=2; face_shape=1; nb_elem_faces=2; break;
++  case triangle:    dimension = (elemtype=="TRIANGLE") ? 2 : 3; 
++    elem_shape=3; face_shape=2; nb_elem_faces=3; break;
++  case quadri:      dimension = (elemtype=="QUADRANGLE_3D") ? 3 : 2;
++    elem_shape=4; face_shape=2; nb_elem_faces=4; break;
++  case tetra:       dimension = 3; elem_shape=4; face_shape=3; nb_elem_faces=4; break;
++  case hexa:        dimension = 3; elem_shape=8; face_shape=4; nb_elem_faces=6; break;
++  case polyedre:    dimension = 3; elem_shape=-1; face_shape=-1; nb_elem_faces=-1; break;
++  case polygone:    dimension = 2; elem_shape=-1; face_shape=-1; nb_elem_faces=-1; break;
++  default:
++    Journal() << "LataDB::get_element_data element is unspecified" << endl;
++    throw(LataDBError(LataDBError::BAD_ELEM_TYPE));
++  }    
++}
++
++// Description: in lata v1 format, the number of components in a Champ entry
++//  is implicitely defined by the field name and the discretisation
++entier LataDB::lata_v1_get_nb_comp(const Nom & fieldname, const Motcle & localisation, 
++                                   const LataDBGeometry & dom, entier dim, LataDBField::Nature & nature,
++                                   LataDBDataType::DataOrdering & ordering)
++{
++  // Search component name in std_components
++  entier nb_comp = latav1_component_shape(fieldname);
++  Motcle maj_field(fieldname);
++  ordering = LataDBDataType::C_ORDERING;
++  nature = LataDBField::SCALAR;
++  Journal(verb_level+1) << " LataV2 known component name found : " << fieldname << endl;
++  if (nb_comp == -1) {
++    // This is a vector component. If it's not a VDF faces, nb_comp = dimension of the problem
++    Element elt = element_type_from_string(dom.elem_type_);
++    if (localisation == "FACES" && (elt == quadri || elt == hexa)) {
++      nb_comp = 1;
++      Journal(verb_level+1) << " Vector field. Detected a VDF faces discretisation => nb_comp=1" << endl;
++    } else {
++      nb_comp = dim;
++      nature = LataDBField::VECTOR;
++      ordering = LataDBDataType::F_ORDERING;
++      Journal(verb_level+1) << " Vector field. nb_comp = dimension = " << nb_comp << endl;
++      Journal(verb_level+1) << " Assume fortran ordering" << endl;
++    }
++  } else if (nb_comp == -2) {
++    // This is the vorticity: scalar in 2D, vector in 3D
++    if (dim == 2)
++    {
++      nb_comp = 1;
++      Journal(verb_level+1) << " Scalar field, nb_comp=" << nb_comp << endl; 
++    }
++    else 
++    {
++      nb_comp = dim;
++      nature = LataDBField::VECTOR;
++      ordering = LataDBDataType::F_ORDERING;
++      Journal(verb_level+1) << " Vector field. nb_comp = dimension = " << nb_comp << endl;
++      Journal(verb_level+1) << " Assume fortran ordering" << endl;      
++    }
++  } else {
++    //if (maj_field == "K_EPS") {
++    if (nb_comp>1) {
++      ordering = LataDBDataType::F_ORDERING;
++      Journal(verb_level+1) << " Special K_EPS => Assume fortran ordering" << endl;
++    }
++    Journal(verb_level+1) << " Scalar field, nb_comp=" << nb_comp << endl; 
++  }
++  return nb_comp;
++}
++
++// Description: in lata v1 format, the localisation is implicitely defined by the
++//  file name of the data file:
++void lata_v1_get_localisation(const char * filename, Nom & localisation_)
++{
++  if (strstr(filename, ".SOM."))
++    localisation_ = "SOM";
++  else if (strstr(filename, ".ELEM."))
++    localisation_ = "ELEM";
++  else if (strstr(filename, ".FACES."))
++    localisation_ = "FACES";
++  else {
++    Journal() << "Error in lata_v1_get_localisation. Unable to find localisation in filename\n"
++              << filename << endl;
++    throw(LataDBError(LataDBError::READ_ERROR));
++  }
++}
++
++class LataDataFile
++{
++public:
++  enum Mode { READ, WRITE, APPEND };
++  LataDataFile(std::iostream & mem_buffer, const char *prefix, const char *name, const LataDBDataType::MSB& msb, Mode mode = READ)
++  {
++    exception_ = 1;
++    msb_=msb;
++    if (strcmp(name, LataDBField::memory_buffer_file()) == 0) {
++      stream_ = &mem_buffer;
++      fname_ = name;
++      Journal(verb_level_data_bloc) << "LataDB: opening internal memory_buffer for read/write" << endl;
++      if (mode == READ)
++        (*stream_).seekg(0, std::ios::beg);
++      else if (mode == WRITE) 
++      { // on ne repositionne pas sur un fichier vide, Visual ne supporte pas
++        // et c'est inutil
++        if ((*stream_).tellp()>=0)
++          (*stream_).seekp(0, std::ios::beg);
++      }
++      else
++      {
++        if ((*stream_).tellp()>=0)
++          (*stream_).seekp(0, std::ios::end);
++      }
++      Journal(verb_level_data_bloc+1) << " current position: " << position() << endl;
++      if (!fstream_.good()) {
++        Journal() << "LataDataFile: Memory stream error" << endl;
++        throw LataDBError(LataDBError::DATA_ERROR);
++      }
++    } else {
++      stream_ = &fstream_;
++      fname_ = prefix;;
++      fname_ += name;
++      Journal(verb_level_data_bloc) << "LataDB: opening data file " << fname_ << endl;
++      if (msb_ == LataDBDataType::ASCII) {
++      switch(mode) {
++      case READ: fstream_.open(fname_, std::fstream::in); break;
++      case WRITE: fstream_.open(fname_, std::fstream::out); break;
++      case APPEND: fstream_.open(fname_, std::fstream::out | std::fstream::app); break;
++      }
++      }
++      else 
++        {
++          if (msb_ != LataDBDataType::machine_msb_) {
++            Journal() << "LataDB LataDataFile::write(int) not coded for reverse binary msb" << endl;
++            throw;
++          }
++          switch(mode) {
++          case READ: fstream_.open(fname_, std::fstream::in|std::fstream::binary); break;
++          case WRITE: fstream_.open(fname_, std::fstream::out|std::fstream::binary); break;
++          case APPEND: fstream_.open(fname_, std::fstream::out | std::fstream::app|std::fstream::binary); break;
++          }
++        }
++      if (!fstream_.good()) {
++        Journal() << "File not found " << fname_ << endl;
++        throw LataDBError(LataDBError::FILE_NOT_FOUND);
++      }
++    }
++  }
++  void set_exception(int i) { exception_ = i; }
++  FileOffset position() { return (*stream_).tellp(); };
++  enum SeekType { ABSOLUTE, RELATIVE };
++  void seek(FileOffset pos, SeekType seekt) {
++    Journal(verb_level_data_bloc+1) << "Seeking file " << fname_ 
++                                    << ((seekt == ABSOLUTE) ? " absolute position " : " relative position ")
++                                    << pos << endl;
++    if (seekt == ABSOLUTE)
++      (*stream_).seekg(pos, std::ios::beg);
++    else
++      (*stream_).seekg(pos, std::ios::cur);
++  
++    if (exception_ && !(*stream_).good()) {
++      Journal() << "Error seeking to position " << pos << " in file " << fname_ << endl;
++      throw LataDBError(LataDBError::DATA_ERROR);
++    }
++  }
++  void set_encoding(LataDBDataType::MSB msb, LataDBDataType::Type type) { msb_ = msb; type_ = type; };
++  void set_err_message(const char *message) { message_ = message; };
++  LataDataFile & operator>>(LataDBInt32 & x) { read(&x, 1); return *this; };
++  LataDataFile & operator>>(float & x) { read(&x, 1); return *this; };
++  LataDataFile & operator>>(Nom & n) {
++    n = "";
++    if (msb_ != LataDBDataType::ASCII) {
++      for (;;) {
++        char c[2];
++        c[1] = 0;
++        (*stream_).get(c[0]);
++
++        if (!(*stream_).good())
++          break;
++
++        if (c[0] == '\0')
++          break;
++
++        n += c;
++      }
++    } else {
++      std::string tmp;
++      (*stream_) >> tmp;
++      if ((*stream_).good())
++        n = tmp.c_str();
++    }
++    if (exception_ && !(*stream_).good()) {
++      Journal() << "Error reading string in file " << fname_ << endl;
++      throw LataDBError(LataDBError::DATA_ERROR);
++    }
++    return *this;
++  }
++  void read(LataDBInt32 *ptr, BigEntier n);
++  void read(float *ptr, BigEntier n);
++  LataDataFile & operator<<(LataDBInt32 & x) { write(&x, 1, 1); return *this; };
++  LataDataFile & operator<<(float & x) { write(&x, 1, 1); return *this; };
++  void write(const LataDBInt32 *ptr, BigEntier n, BigEntier col);
++  void write(const float *ptr, BigEntier n, BigEntier col);
++
++protected:
++  Nom fname_;
++  const char * message_; // Message printed if error.
++  std::fstream fstream_;
++  std::iostream *stream_; // Points to fstream_ or mem_buffer passed to constructor
++  LataDBDataType::MSB msb_;
++  LataDBDataType::Type type_;
++  int exception_;
++};
++
++void LataDataFile::read(LataDBInt32 *ptr, BigEntier n)
++{
++  if (type_ != LataDBDataType::INT32 && type_ != LataDBDataType::INT64) {
++    Journal() << "Error in lataDB bloc read: trying to read non integer data into integer array" << endl;
++    throw LataDBError(LataDBError::DATA_ERROR); 
++  }
++  if (msb_ == LataDBDataType::ASCII) {
++    BigEntier i;
++    if (ptr)
++      Journal(verb_level_data_bloc+1) << "Reading ascii int data bloc size=" << n << endl;
++    else
++      Journal(verb_level_data_bloc+1) << "Skipping ascii int data bloc size=" << n << endl;
++    LataDBInt32 toto;
++    for (i = 0; i < n; i++) {
++      if (ptr)
++        (*stream_) >> ptr[i];
++      else
++        (*stream_) >> toto;
++      if (exception_ && !(*stream_).good()) {
++        Journal() << "Error reading ascii file " << fname_ << " LataDBInt32[" << n << "] at index " 
++                  << i << endl << (message_?message_:"") << endl;
++        throw LataDBError(LataDBError::DATA_ERROR);
++      }
++    }
++  } else {
++    if (type_ != LataDBDataType::INT32) {
++      Journal() << "Internal error in LataDB.cpp LataDataFile::read(LataDBInt32) : size conversion not coded" << endl;
++      throw;
++    }
++    if (ptr) {
++      Journal(verb_level_data_bloc+1) << "Reading binary int data bloc size=" << n << endl;
++      (*stream_).read((char*)ptr, n * sizeof(LataDBInt32));
++    } else {
++      Journal(verb_level_data_bloc+1) << "Skipping binary int data bloc size=" << n << endl;
++      seek(n * sizeof(LataDBInt32), RELATIVE);
++    }
++    if (exception_ && !(*stream_).good()) {
++      Journal() << "Error reading binary file " << fname_ << " LataDBInt32[" << n << "]" 
++                << endl << (message_?message_:"") << endl;
++      throw LataDBError(LataDBError::DATA_ERROR);
++    }
++    if (msb_ != LataDBDataType::machine_msb_) {
++      Journal() << "LataDB LataDataFile::read(LataDBInt32) not coded for reverse binary msb" << endl;
++      throw;
++      // Put code here (and test !) to reverse bytes in the binary bloc:
++    }
++  } 
++}
++
++void LataDataFile::read(float *ptr, BigEntier n)
++{
++  if (type_ != LataDBDataType::REAL32) {
++    Journal() << "Error in lataDB bloc read: trying to read non float data into float array" << endl;
++    throw LataDBError(LataDBError::DATA_ERROR); 
++  }
++  if (msb_ == LataDBDataType::ASCII) {
++    BigEntier i;
++    if (ptr)
++      Journal(verb_level_data_bloc+1) << "Reading ascii float data bloc size=" << n << endl;
++    else
++      Journal(verb_level_data_bloc+1) << "Skipping ascii float data bloc size=" << n << endl;
++    float toto;
++    for (i = 0; i < n; i++) {
++      if (ptr)
++        (*stream_) >> ptr[i];
++      else
++        (*stream_) >> toto;
++      if (exception_ && !(*stream_).good()) {
++        Journal() << "Error reading ascii file " << fname_ << " float[" << n << "] at index " 
++                  << i << endl << message_ << endl;
++        throw LataDBError(LataDBError::DATA_ERROR);
++      }
++    }
++  } else {
++    if (ptr) {
++      Journal(verb_level_data_bloc+1) << "Reading binary float data bloc size=" << n << endl;
++      (*stream_).read((char*)ptr, n * sizeof(float));
++    } else {
++      Journal(verb_level_data_bloc+1) << "Skipping binary float data bloc size=" << n << endl;
++      seek(n * sizeof(float), RELATIVE);
++    }
++    if (exception_ && !(*stream_).good()) {
++      Journal() << "Error reading binary file " << fname_ << " float[" << n << "]" 
++                << endl << message_ << endl;
++      throw LataDBError(LataDBError::DATA_ERROR);
++    }
++    if (msb_ != LataDBDataType::machine_msb_) {
++      Journal() << "LataDB LataDataFile::read(float) not coded for reverse binary msb" << endl;
++      throw;
++      // Put code here (and test !) to reverse bytes in the binary bloc:
++    }
++  } 
++}
++
++void LataDataFile::write(const LataDBInt32 *ptr, BigEntier n, BigEntier columns)
++{
++  Journal(verb_level_data_bloc+1) << "Writing int data bloc size=" << n << endl;
++  if (type_ != LataDBDataType::INT32) {
++    Journal() << "Error in lataDB bloc write: trying to write integer data to non integer file block" << endl;
++    throw LataDBError(LataDBError::DATA_ERROR); 
++  }
++  if (msb_ == LataDBDataType::ASCII) {
++    for (BigEntier i = 0; i < n; i+=columns) {
++      BigEntier j;
++      for (j = 0; j < columns-1; j++)
++        (*stream_) << ptr[i+j] << " ";
++      (*stream_) << ptr[i+j] << endl;
++    }
++  } else {
++    if (msb_ != LataDBDataType::machine_msb_) {
++      Journal() << "LataDB LataDataFile::write(int) not coded for reverse binary msb" << endl;
++      throw;
++      // Put code here (and test !) to reverse bytes in the binary bloc:
++    }
++    (*stream_).write((char*)ptr, n * sizeof(LataDBInt32));    
++  }
++  (*stream_).seekg(0, std::ios::end);
++  if (exception_ && !(*stream_).good()) {
++    Journal() << "Error writing file " << fname_ << " int[" << n << "]" 
++              << endl << message_ << endl;
++    throw LataDBError(LataDBError::DATA_ERROR);
++  }
++}
++
++void LataDataFile::write(const float *ptr, BigEntier n, BigEntier columns)
++{
++  Journal(verb_level_data_bloc+1) << "Writing float data bloc size=" << n << endl;
++  if (type_ != LataDBDataType::REAL32) {
++    Journal() << "Error in lataDB bloc write: trying to write float data to non float file block" << endl;
++    throw LataDBError(LataDBError::DATA_ERROR); 
++  }
++  if (msb_ == LataDBDataType::ASCII) {
++    for (BigEntier i = 0; i < n; i+=columns) {
++      BigEntier j;
++      for (j = 0; j < columns-1; j++)
++        (*stream_) << ptr[i+j] << " ";
++      (*stream_) << ptr[i+j] << endl;
++    }
++  } else {
++    if (msb_ != LataDBDataType::machine_msb_) {
++      Journal() << "LataDB LataDataFile::write(float) not coded for reverse binary msb" << endl;
++      throw;
++      // Put code here (and test !) to reverse bytes in the binary bloc:
++    }
++    (*stream_).write((char*)ptr, n * sizeof(float));    
++  }
++  (*stream_).seekg(0, std::ios::end);
++  if (exception_ && !(*stream_).good()) {
++    Journal() << "Error writing file " << fname_ << " float[" << n << "]" 
++              << endl << message_ << endl;
++    throw LataDBError(LataDBError::DATA_ERROR);
++  }
++}
++
++// Description: skips a fortran bloc size descriptor.
++void skip_blocksize(LataDataFile & f, const LataDBDataType & type)
++{
++  if (type.fortran_bloc_markers_ == LataDBDataType::NO_BLOC_MARKER)
++    return;
++  f.set_err_message("Error reading fortran blocsize");
++  f.set_encoding(type.msb_, type.bloc_marker_type_);
++  int i;
++  f >> i;
++  Journal(verb_level_data_bloc+1) << "Skipping blocsize marker value=" << i << endl;
++}
++
++template<class DEST_TYPE>
++DEST_TYPE int_conversion(LataDBInt64 x, const char * err_msg = 0)
++{
++  DEST_TYPE result = (DEST_TYPE) x;
++  if ((LataDBInt64) result != x) {
++    if (err_msg)
++      Journal() << "LataDB integer conversion failed: " << err_msg << endl;
++    else 
++      Journal() << "LataDB integer conversion failed: " << endl;
++    throw(LataDBError(LataDBError::INTEGER_OVERFLOW));
++  }
++  return result;
++}
++
++void write_blocksize(LataDataFile & f, const LataDBDataType & type, entier sz)
++{
++  if (type.fortran_bloc_markers_ == LataDBDataType::NO_BLOC_MARKER)
++    return;
++
++  Journal(verb_level_data_bloc+1) << "Writing blocsize marker value=" << sz << endl;
++  f.set_err_message("Error writing fortran blocsize");
++  f.set_encoding(type.msb_, type.bloc_marker_type_);
++  f << sz;
++}
++
++void bloc_read_skip(LataDataFile & f, LataDBDataType::MSB msb, LataDBDataType::Type type, BigEntier size)
++{
++  f.set_encoding(msb, type);
++  switch(type) {
++  case LataDBDataType::INT32: f.read((LataDBInt32*) 0, size); break;
++  case LataDBDataType::REAL32: f.read((float*) 0, size); break;
++  default:
++    Journal() << "Internal error: bloc read skip not code for this type" << endl;
++    throw;
++  }
++}
++
++// Description: Read "tab.size_array()" values from file "f" at current file location
++//  into the "tab" array. "msb" and "type" must match the data type written in the file.
++void bloc_read(LataDataFile & f, LataDBDataType::MSB msb, LataDBDataType::Type type,
++               ArrOfInt & tab)
++{
++  f.set_encoding(msb, type);
++  f.read(tab.addr(), tab.size_array());
++}
++
++void bloc_read(LataDataFile & f, LataDBDataType::MSB msb, LataDBDataType::Type type,
++               ArrOfFloat & tab)
++{
++  f.set_encoding(msb, type);
++  f.read(tab.addr(), tab.size_array());
++}
++
++void bloc_write(LataDataFile & f, LataDBDataType::MSB msb, LataDBDataType::Type type,
++                const ArrOfInt & tab, int columns)
++{
++  f.set_encoding(msb, type);
++  f.write(tab.addr(), tab.size_array(), columns);
++}
++
++void bloc_write(LataDataFile & f, LataDBDataType::MSB msb, LataDBDataType::Type type,
++                const ArrOfFloat & tab, int columns)
++{
++  f.set_encoding(msb, type);
++  f.write(tab.addr(), tab.size_array(), columns);
++}
++
++LataDBDataType::MSB LataDBDataType::machine_msb_ = (mymachine_msb) ? LataDBDataType::MSB_BIG_ENDIAN : LataDBDataType::MSB_LITTLE_ENDIAN;
++
++void LataDB::add(entier tstep, const LataDBGeometry & item)
++{
++  Noms names = geometry_names(tstep);
++  if (names.rang(item.name_) >= 0) {
++    Journal() << "Error in LataDBTimestep::add(const LataDBGeometry &): duplicate geometry name " << item.name_ << endl;
++    throw(LataDBError(LataDBError::READ_ERROR));
++  }
++  timesteps_[tstep].geoms_.add(item);
++}
++
++void LataDB::add(entier tstep, const LataDBField & item)
++{
++  LataDBField & field = timesteps_[tstep].fields_.add(item);
++  field.timestep_ = tstep;
++  field.uname_ = Field_UName(item.geometry_, item.name_, item.localisation_);
++  Journal(verb_level+1) << "LataDB::add " << tstep << " " << field.uname_ << endl;
++}
++
++// Description: returns the number of timesteps in the database
++//  (timestep 0 contains geometries and fields defined before the first TEMPS entry,
++//   hence nb_timesteps() == number of TEMPS entries plus 1)
++// Exceptions: BAD_TIMESTEP
++entier LataDB::nb_timesteps() const
++{ 
++  return timesteps_.size(); 
++}
++
++// Description: returns the physical time for this timestep
++// Exceptions: BAD_TIMESTEP
++double LataDB::get_time(entier tstep) const
++{
++  return get_tstep(tstep).time_;
++}
++
++// Description: returns the requested geometry in the requested timestep
++//  "where" tells where to seach this geometry (in the current timestep or
++//  also in the first timestep.
++// Exceptions: BAD_TIMESTEP NAME_NOT_FOUND
++const LataDBGeometry & LataDB::get_geometry(entier tstep, const char* name,
++                                            TStepSelector where) const
++{
++  if (!name)
++    throw(LataDBError(LataDBError::NAME_NOT_FOUND));
++  while (1) {
++    const LataDBTimestep & t = get_tstep(tstep);
++    const entier n = t.geoms_.size();
++    for (entier i = 0; i < n; i++) {
++      const LataDBGeometry & geom = t.geoms_[i];
++      if (geom.name_ == name)
++        return geom;
++    }
++    if (where == FIRST_AND_CURRENT && tstep > 0)
++      tstep = 0;
++    else
++      break;
++  }
++  throw(LataDBError(LataDBError::NAME_NOT_FOUND));
++}
++
++// Description: returns the requested field in the requested timestep.
++// Exceptions: BAD_TIMESTEP NAME_NOT_FOUND
++const LataDBField & LataDB::get_field(entier tstep, const Field_UName & uname,
++                                      TStepSelector where) const
++{
++  while (1) {
++    const LataDBTimestep & t = get_tstep(tstep);
++    const entier n = t.fields_.size();
++    for (entier i = 0; i < n; i++) {
++      const LataDBField & field = t.fields_[i];
++      if (field.uname_ == uname)
++        return field;
++    }
++    if (where == FIRST_AND_CURRENT && tstep > 0)
++      tstep = 0;
++    else
++      break;
++  }
++  throw(LataDBError(LataDBError::NAME_NOT_FOUND));
++}
++
++// Description: shortcut, works only if the specified field exists and is unique.
++const LataDBField & LataDB::get_field(entier tstep, const char *geom, const char *name, const char *loc,
++                                      TStepSelector which_tstep) const
++{
++  Field_UNames fields = field_unames(tstep, geom, name, which_tstep);
++  if (fields.size() > 1)
++    cerr << "get_field(char *geom, char *name, ...) returned more than one field !" << endl;
++  if (fields.size() != 1)
++    throw(LataDBError(LataDBError::NAME_NOT_FOUND));
++  return get_field(tstep, fields[0], which_tstep);
++}
++
++// Description: return 1 if the field exists AND is unique. (means you can call get_field with the
++//  same parameters)
++entier LataDB::field_exists(entier tstep, const char *geom, const char *name, 
++                            TStepSelector which_tstep) const
++{
++  Field_UNames fields = field_unames(tstep, geom, name, which_tstep);
++  return fields.size() == 1;
++}
++
++
++LataDBField & LataDB::getset_field(entier tstep, const Field_UName & uname, TStepSelector which_tstep)
++{
++  return (LataDBField&) get_field(tstep, uname, which_tstep);
++}
++
++// Description: returns the names of all geometries defined in the timestep
++//  which_tstep tell where to search for geometries.
++// Exceptions: BAD_TIMESTEP 
++Noms LataDB::geometry_names(entier tstep, TStepSelector which_tstep) const
++{
++  Noms names;
++  const LataDBTimestep & t = get_tstep(tstep);
++  entier n = t.geoms_.size();
++  for (entier i = 0; i < n; i++)
++    names.add(t.geoms_[i].name_);
++  if (which_tstep == FIRST_AND_CURRENT && tstep > 0) {
++    const LataDBTimestep & t0 = get_tstep(0);
++    entier n2 = t0.geoms_.size();
++    for (entier i = 0; i < n2; i++)
++      // add if not:
++      if (names.rang(t0.geoms_[i].name_) < 0)
++        names.add(t0.geoms_[i].name_);
++  }
++  return names;
++}
++
++// Description: returns the unique_identifiers of all fields defined in the timestep and for which
++//  the associated geometry is "geometry" and the name is "name". Some fields may have no associated geometry,
++//  give a null pointer or empty string to get these fields.
++//  If geometry="*", returns list for all geometries
++//  If name="*", returns list for all field names
++// Exceptions: BAD_TIMESTEP 
++LataVector<Field_UName> LataDB::field_unames(entier tstep, const char * geometry, const char * name, TStepSelector which_tstep) const
++{
++  LataVector<Field_UName> unames;
++  if (!geometry)
++    geometry = "";
++  for (;;) {
++    const LataDBTimestep & t = get_tstep(tstep);
++    entier n = t.fields_.size();
++    for (entier i = 0; i < n; i++) {
++      const LataDBField & field = t.fields_[i];
++      if ((field.geometry_ == geometry || strcmp(geometry, "*")==0 )
++          && (field.name_ == name || strcmp(name,"*")==0 ))
++        unames.add(field.uname_);
++    }
++    if (tstep == 0 || which_tstep != FIRST_AND_CURRENT)
++      break;
++    tstep = 0;
++  }
++  return unames;
++}
++
++void check(Entree & is, const char * msg)
++{
++  if (!is.good()) {
++    Journal() << "LataDB::read_master_file " << msg << endl;
++    throw(LataDBError(LataDBError::READ_ERROR));
++  }
++}
++void read_keyword_nom(Entree & is, Nom& motlu)
++{
++  is >> motlu;
++  if (is.eof()) {
++    Journal(verb_level) << "LataDB::read_master_file end of file" << endl;
++    motlu = "Fin";
++  } else {
++    check(is, "read string error but not eof !");
++  }
++  
++}
++
++void read_keyword(Entree & is, Nom& nomlu, Motcle& motlu)
++{
++  read_keyword_nom(is,nomlu);
++  motlu=nomlu;
++}
++
++// On suppose que motlu contient "blabla=VALEUR". On extrait valeur et on la met dans "param".
++// Bidouille: pour traiter le cas "blabla= VALEUR", s'il n'y a rien apres "=" dans motlu, on 
++//  relit un mot dans is.
++void read_long_param(Entree & is, const Motcle & motlu, LataDBInt64 & param, const char * err_msg)
++{
++  // Cherche le "="
++  const char *s = motlu;
++  while (((*s) != ('=')) && ((*s) != 0))
++    s++;
++  if (s==0) {
++    Journal() << "LataDB::read_master_file error: " << err_msg << endl;
++    throw(LataDBError(LataDBError::READ_ERROR));
++  }
++  s++;
++  Nom tmp;
++  if (*s==0) {
++    // il y a une espace entre le = et le parametre ?
++    read_keyword_nom(is, tmp);
++    s = tmp;
++  }
++  errno = 0;
++  char *errorptr = 0;
++  param = strtoll(s, &errorptr, 0 /* base 10 par defaut */);
++  if (errno || *errorptr != 0) {
++    Journal() << "LataDB::read_master_file error: " << err_msg << endl
++              << "Error converting a string to type long int : string = " << s << endl;
++    throw(LataDBError(LataDBError::READ_ERROR));
++  }
++}
++
++void read_int_param(Entree & is, const Motcle & motlu, LataDBInt32 & param, const char * err_msg)
++{
++  LataDBInt64 i;
++  read_long_param(is, motlu, i, err_msg);
++  param = int_conversion<LataDBInt32>(i, err_msg);
++}
++
++
++// Idem que read_int_param pour des chaines de caracteres.
++void read_string_param(Entree & is, const Nom & motlu, Nom & param, const char * err_msg)
++{
++  // Cherche le "="
++  const char *s = motlu;
++  while (((*s) != ('=')) && ((*s) != 0))
++    s++;
++  if (s==0) {
++    Journal() << "LataDB::read_master_file error: " << err_msg << endl;
++    throw(LataDBError(LataDBError::READ_ERROR));
++  }
++  s++;
++  param = s;
++  // S'il n'y a rien apres =, on lit un mot de plus.
++  if (param == "")
++    read_keyword_nom(is, param);
++}
++
++
++void read_noms_param(Entree & is, const Nom & motlu, Noms & param, const char * err_msg)
++{
++  Nom tmp;
++  read_string_param(is,motlu,tmp,err_msg);
++  /*
++
++  a faire extraire pour de vrai les differents mots de motlu
++  Nom motlu2(tmp);
++  int nb_comp=1;
++  {
++    const char *s = tmp;
++    int p=0;
++    while ( ((*s) != 0))
++      {
++        if ((*s) == (','))
++          {
++            nb_comp++;
++            //    motlu2[p]='\0';
++          }
++        p++;
++        s++;
++      }
++  }
++  //  cerr<<nb_comp<<" "<<motlu2<<endl;
++  // provisoire non fini
++  param=Noms(nb_comp);
++  {
++    const char *s=motlu2;
++    for (int i=0;i<nb_comp;i++)
++      {
++        
++        int j=motlu2.find(",");
++        if (j==-1) j=0;
++        param[i]=(s+j);
++        cerr<<param[i]<<endl;
++      }
++  }
++  */
++}
++
++// Description: internal tool: checks for valid i and returns the timestep
++// Exceptions: BAD_TIMESTEP
++const LataDBTimestep & LataDB::get_tstep(entier i) const
++{
++  if (i < 0 || i >= timesteps_.size()) {
++    Journal() << "LataDB::timestep(" << i << ") : wrong timestep" << endl;
++    throw(LataDBError(LataDBError::BAD_TIMESTEP));
++  }
++  return timesteps_[i];
++}
++
++// Description: clears the database
++void LataDB::reset()
++{
++  path_prefix_ = "";
++  header_ = "";
++  case_ = "";
++  software_id_ = "";
++  timesteps_.reset();
++  std::string empty;
++  internal_data_buffer_.str(empty);
++}
++
++// We update only fields found in the string
++// A string can contain both an int type and a float type: we get both in int_type and float_type
++static void read_format_string(const Motcle & n, LataDBDataType & data_type, 
++                               LataDBDataType::Type & int_type,
++                               LataDBDataType::Type & float_type)
++{
++  int_type = LataDBDataType::UNKNOWN_TYPE;
++  float_type = LataDBDataType::UNKNOWN_TYPE;
++
++  if (n.find("ASCII")>=0)
++    data_type.msb_ = LataDBDataType::ASCII;
++  if (n.find("BIG_ENDIAN")>=0)
++    data_type.msb_ = LataDBDataType::MSB_BIG_ENDIAN;
++  if (n.find("LITTLE_ENDIAN")>=0)
++    data_type.msb_ = LataDBDataType::MSB_LITTLE_ENDIAN;
++
++  if (n.find("INT32")>=0) {
++    int_type = data_type.type_ = LataDBDataType::INT32;
++    data_type.bloc_marker_type_ = LataDBDataType::INT32;
++  }
++  if (n.find("INT64")>=0) {
++    int_type = data_type.type_ = LataDBDataType::INT64;
++    data_type.bloc_marker_type_ = LataDBDataType::INT64;
++  }
++  if (n.find("REAL32")>=0)
++    float_type = data_type.type_ = LataDBDataType::REAL32;
++  if (n.find("REAL64")>=0)
++    float_type = data_type.type_ = LataDBDataType::REAL64;
++
++  if (n.find("C_INDEXING")>=0)
++    data_type.array_index_ = LataDBDataType::C_INDEXING;
++  if (n.find("F_INDEXING")>=0)
++    data_type.array_index_ = LataDBDataType::F_INDEXING;
++  if (n.find("NO_INDEXING")>=0)
++    data_type.array_index_ = LataDBDataType::NOT_AN_INDEX;
++  
++  if (n.find("C_ORDERING")>=0)
++    data_type.data_ordering_ = LataDBDataType::C_ORDERING;
++  if (n.find("F_ORDERING")>=0)
++    data_type.data_ordering_ = LataDBDataType::F_ORDERING;
++
++  if (n.find("F_MARKERS_NO")>=0)
++    data_type.fortran_bloc_markers_ = LataDBDataType::NO_BLOC_MARKER;
++  if (n.find("F_MARKERS_SINGLE")>=0)
++    data_type.fortran_bloc_markers_ = LataDBDataType::BLOC_MARKERS_SINGLE_WRITE;
++  if (n.find("F_MARKERS_MULTIPLE")>=0)
++    data_type.fortran_bloc_markers_ = LataDBDataType::BLOC_MARKERS_MULTIPLE_WRITES;
++
++  // Fortran bloc markers are tested after INT32 and INT64 because they
++  //  override the default value:
++  if (n.find("MARKERS32")>=0)
++    data_type.bloc_marker_type_ = LataDBDataType::INT32;
++  if (n.find("MARKERS64")>=0)
++    data_type.bloc_marker_type_ = LataDBDataType::INT64;
++}
++
++// This must work together with read_format_string:
++void build_format_string(const LataDBDataType & default_type, 
++                         const LataDBDataType & type,
++                         Motcle & n)
++{
++  n = "";
++  if (type.msb_ != default_type.msb_) {
++    switch(type.msb_) {
++    case LataDBDataType::ASCII: n += "ASCII,"; break;
++    case LataDBDataType::MSB_BIG_ENDIAN: n += "BIG_ENDIAN,"; break;
++    case LataDBDataType::MSB_LITTLE_ENDIAN: n += "LITTLE_ENDIAN,"; break;
++    default: 
++      Journal() << "write master lata: invalid MSB" << endl;
++      throw(LataDBError(LataDBError::INVALID_OPERATION));
++    }
++  }
++
++  // Is an integer type specified in the format string: then the default
++  //  fortran bloc marker_type will be changed (look for MARKER32 in read_format_string)
++  LataDBDataType::Type default_fortran_bloc_type = default_type.bloc_marker_type_;
++
++  if (type.type_ != default_type.type_) {
++    switch(type.type_) {
++    case LataDBDataType::INT32: n += "INT32,"; default_fortran_bloc_type = LataDBDataType::INT32; break;
++    case LataDBDataType::INT64: n += "INT64,"; default_fortran_bloc_type = LataDBDataType::INT64; break;
++    case LataDBDataType::REAL32: n += "REAL32,"; break;
++    case LataDBDataType::REAL64: n += "REAL64,"; break;
++    default:
++      Journal() << "write master lata: invalid type" << endl;
++      throw(LataDBError(LataDBError::INVALID_OPERATION));
++    }
++  }
++
++  // Specify indexing only if integer type:
++  if ((type.type_ == LataDBDataType::INT32 || type.type_ == LataDBDataType::INT64)
++      && type.array_index_ != default_type.array_index_)
++    switch(type.array_index_) {
++    case LataDBDataType::C_INDEXING: n += "C_INDEXING,"; break;
++    case LataDBDataType::F_INDEXING: n += "F_INDEXING,"; break;
++    case LataDBDataType::NOT_AN_INDEX: n += "NO_INDEXING,"; break;
++    default:
++      Journal() << "write master lata: invalid array_index_" << endl;
++      throw(LataDBError(LataDBError::INVALID_OPERATION));
++    }
++
++  if (type.data_ordering_ != default_type.data_ordering_) {
++    switch(type.data_ordering_) {
++    case LataDBDataType::C_ORDERING: n += "C_ORDERING,"; break;
++    case LataDBDataType::F_ORDERING: n += "F_ORDERING,"; break;
++    default:
++      Journal() << "write master lata: invalid data_ordering_" << endl;
++      throw(LataDBError(LataDBError::INVALID_OPERATION));
++    }
++  }
++
++  if (type.fortran_bloc_markers_ != default_type.fortran_bloc_markers_) {
++    switch(type.fortran_bloc_markers_) {
++    case LataDBDataType::NO_BLOC_MARKER: n += "F_MARKERS_NO,"; break;
++    case LataDBDataType::BLOC_MARKERS_SINGLE_WRITE: n += "F_MARKERS_SINGLE,"; break;
++    case LataDBDataType::BLOC_MARKERS_MULTIPLE_WRITES: n += "F_MARKERS_MULTIPLE,"; break;
++    default:
++      Journal() << "write master lata: invalid fortran_bloc_markers_" << endl;
++      throw(LataDBError(LataDBError::INVALID_OPERATION));
++    }
++  }
++  
++  // Warning : tricky code to determine if we have to specify fortran bloc marker size:
++  // If we specify a type_ and this type_ is an integer type, then the fortran bloc
++  //  marker has implicitely the same type. We want to override this type if
++  //  this assumption is wrong:
++  if (type.fortran_bloc_markers_ != LataDBDataType::NO_BLOC_MARKER
++      && default_fortran_bloc_type != type.bloc_marker_type_) {
++    switch(type.bloc_marker_type_) {
++    case LataDBDataType::INT32: n += "MARKER32,"; break;
++    case LataDBDataType::INT64: n += "MARKER64,"; break;
++    default:
++      Journal() << "write master lata: invalid fortran bloc marker type" << endl;
++      throw(LataDBError(LataDBError::INVALID_OPERATION));
++    }
++  }
++
++  // Remove trailing "," if any.
++  n.prefix(",");
++}
++
++// Description: returns the content of the third line of the file
++// Exceptions: FILE_NOT_FOUND, BAD_HEADER (means that this is not a lata file)
++Nom LataDB::read_master_file_options(const char *filename)
++{
++  LataDB db;
++  EFichier is;
++  db.read_master_file_header(filename, is);
++  return db.software_id_; // Returns the content of the third line
++}
++
++// Description:
++//  Opens the file and reads the three firt lines.
++//  Fills the following attributes of the class:
++//   header_
++//   case_
++//   software_id_
++//   old_style_lata_
++void LataDB::read_master_file_header(const char *filename, EFichier & is)
++{
++  if (!filename)
++    filename = ""; // Will trigger an error for sure !
++  is.ouvrir(filename);
++  if (!is.good()) { // isnogood ?
++    Journal() << "LataDB::read_master_file_options failed opening file " << filename << endl;
++    throw(LataDBError(LataDBError::FILE_NOT_FOUND));
++  }
++  Journal(verb_level-1) << "Trying to read master lata file format LATA " 
++                        << filename << endl;
++
++  const entier bufsize=1024;
++  char s[bufsize+1];
++  // Lecture de l'entete:
++  is.get_istream().getline(s, bufsize);
++  check(is, "failed reading line 1");
++  const char * lata_header = "LATA_V2.";
++  old_style_lata_ = 0;
++  if (strncmp(s, lata_header, strlen(lata_header)) == 0) {
++    Journal(2) << "LataDB::read_master_file found lata format " << lata_header << endl;
++    old_style_lata_ = 0;
++  } else if ((Motcle(s).debute_par("Trio_U"))||(Motcle(s).debute_par("TRUST"))) {
++    Journal(2) << "LataDB::read_master_file found old style lata format" << endl;
++    old_style_lata_ = 1;
++  } else {
++    Journal(2) << "LataDB::read_master_file error reading header: expected LATA_V2.0 or TRUST" 
++               << " instead of " << s << endl;
++    throw(LataDBError(LataDBError::BAD_HEADER));
++  }
++  header_ = s;
++  is.get_istream().getline(s, bufsize);
++  check(is, "failed reading line 2");
++  case_ = s;
++  is.get_istream().getline(s, bufsize);
++  check(is, "failed reading line 3");
++  software_id_ = s; 
++}
++
++int is_med(const char* filename)
++{
++  Motcle motcle_nom_fic(filename);
++  
++  if (motcle_nom_fic.finit_par(".med"))
++    return 1;
++  return 0;
++}
++
++// Description: Reads the .lata database in the given file indicating than the 
++//  associated data files will be found in directory "prefix".
++//  If not empty, "prefix" must finish with a '/'.
++//  For "prefix" and "filename", if they do not begin with '/', are relative to pwd.
++// Exceptions: 
++//  BAD_HEADER  means that the header found in this stream is not LATA_V2
++//  READ_ERROR  means that an error has been found in the file (premature eof,
++//              io error, bad keyword, ...)
++//  FILE_NOT_FOUND means that, well, the lata file could not be opened
++void LataDB::read_master_file(const char *prefix, const char *filename)
++{
++  reset();
++
++  if (!prefix)
++    prefix = "";
++  path_prefix_ = prefix;
++
++  if (is_med(filename)) 
++    {
++      path_prefix_ = ""; 
++      read_master_file_med(prefix,filename);
++      return;
++    }
++
++  //Journal() << "RECOMPILED PLUGIN !" << endl;
++
++  EFichier is;
++  read_master_file_header(filename, is);
++
++  // Defaults for lataV1
++  default_type_int_.msb_ = LataDBDataType::ASCII;
++  default_type_int_.type_ = LataDBDataType::INT32;
++  default_type_int_.array_index_ = LataDBDataType::F_INDEXING;
++  default_type_int_.data_ordering_ = LataDBDataType::C_ORDERING;
++  default_type_int_.fortran_bloc_markers_ = LataDBDataType::BLOC_MARKERS_SINGLE_WRITE;
++  default_type_int_.bloc_marker_type_ = LataDBDataType::INT32;
++  default_float_type_ = LataDBDataType::REAL32;
++  
++  // Create timestep 0 (global domain and fields)
++  timesteps_.add(LataDBTimestep());
++  entier interface_file_not_found = 0;
++  Nom nomlu;
++  Motcle motlu;
++  read_keyword(is, nomlu,motlu);
++
++  while (1) {
++    if (motlu == "Fin") 
++      {
++        Journal(verb_level) << "End of file by FIN" << endl;
++        break;
++      } 
++    else if (motlu == "Format") 
++      {
++        Journal(verb_level) << "Reading Format " << endl;
++        read_keyword(is, nomlu, motlu);
++        LataDBDataType::Type tmp_int_type;
++        read_format_string(motlu, default_type_int_, tmp_int_type, default_float_type_);
++        default_type_int_.type_ = tmp_int_type;
++        read_keyword(is, nomlu, motlu);
++      } 
++    else if (motlu == "Temps") 
++      {
++        LataDBTimestep & t = timesteps_.add(LataDBTimestep());
++        const entier i = timesteps_.size() - 1;
++        is >> t.time_;
++        check(is, "failed reading time parameter");
++        Journal(verb_level) << "Reading timestep " << i << " t=" << t.time_ << endl;
++        read_keyword(is, nomlu, motlu);
++      }
++    else if (motlu == "Geom")
++      {
++        // This is the new syntax to declare a geometry.
++        // nodes, elements faces, files are declared in separate "champ" entries
++        LataDBGeometry dom;
++        dom.timestep_ = timesteps_.size()-1;
++        is >> dom.name_;
++        check(is, "failed reading domain name");
++        Journal(verb_level) << "New domain " << dom.name_ << endl;
++        while (1) {
++          read_keyword(is, nomlu, motlu);
++          if (motlu.debute_par("type_elem=")) {
++            read_string_param(is, motlu, dom.elem_type_, "error reading type_elem parameter");
++            Journal(verb_level+1) << " type_elem=" << dom.elem_type_ << endl;
++          } else
++            break;
++        }
++        if (dom.elem_type_ == "") {
++          Journal() << "Error reading Geometry: missing type_elem parameter" << endl;
++          throw(LataDBError(LataDBError::READ_ERROR));
++        }
++        add(timesteps_.size() - 1, dom);
++      }
++    else if (motlu == "Geometrie") 
++      {
++        // Declare a geometry: nodes and elements are embedded in a single file described here
++        // (legacy syntax)
++        LataDBGeometry dom;
++        LataDBField som;
++        // Name
++        is >> dom.name_;
++        dom.timestep_ = timesteps_.size()-1;
++        check(is, "failed reading domain name");
++        Journal(verb_level) << "Reading domain " << dom.name_ << endl;
++        som.name_ = "SOMMETS";
++        som.geometry_ = dom.name_;
++        // Filenames
++        Nom n;
++        is >> n;
++        check(is, "failed reading domain filename");
++        som.filename_ = n;
++        long long nb_elem = -1;
++        long long nb_faces = -1;
++        entier nproc = -1;
++        Nom file_decal_som;
++        Nom file_decal_elem;
++        Nom file_decal_faces;
++        while (1) {
++          read_keyword(is, nomlu, motlu);
++          if (motlu.debute_par("nb_som_tot=")) {
++            read_long_param(is, motlu, som.size_, "bad nb_som_tot parameter");
++          } else if (motlu.debute_par("nb_elem_tot=")) {
++            read_long_param(is, motlu, nb_elem, "bad nb_elem_tot parameter");
++          } else if (motlu.debute_par("type_elem=")) {
++            read_string_param(is, motlu, dom.elem_type_, "error reading type_elem parameter");
++          } else if (motlu.debute_par("nb_faces_tot=")) {
++            read_long_param(is, motlu, nb_faces, "bad nb_elem_tot parameter");
++          } else if (motlu.debute_par("format=")) {
++            Motcle fmt;
++            read_string_param(is, motlu, fmt, "bad format parameter");
++            if (fmt=="BINARY") {
++              default_type_int_.msb_ = LataDBDataType::machine_msb_;
++            }
++          } else if (motlu.debute_par("joints_sommets")) {
++            read_keyword(is, nomlu, motlu);
++            read_int_param(is, motlu, nproc, "bad nproc parameter");
++            read_keyword(is, nomlu, motlu);
++            read_string_param(is, nomlu, file_decal_som, "bad decalage file parameter");
++            Journal(verb_level+1) << " decal_som " << nproc;
++          } else if (motlu.debute_par("joints_elements")) {
++            read_keyword(is, nomlu, motlu);
++            read_int_param(is, motlu, nproc, "bad nproc parameter");
++            read_keyword(is, nomlu, motlu);
++            read_string_param(is, nomlu, file_decal_elem, "bad decalage file parameter");            
++            Journal(verb_level+1) << " decal_elem " << nproc;
++          } else if (motlu.debute_par("joints_faces")) {
++            read_keyword(is, nomlu, motlu);
++            read_int_param(is, motlu, nproc, "bad nproc parameter");
++            read_keyword(is, nomlu, motlu);
++            read_string_param(is, nomlu, file_decal_faces, "bad decalage file parameter");            
++            Journal(verb_level+1) << " decal_faces " << nproc;
++          } else
++            break;
++          Journal(verb_level+1) << " " << motlu << endl;
++        }
++        som.datatype_ = default_type_float();
++        LataDBField elem(som);
++        elem.size_ = nb_elem;
++        elem.datatype_ = default_type_int_;
++        LataDBField faces(elem); // copy filename_
++        faces.size_ = nb_faces;
++        LataDBField elem_faces(elem);
++        elem_faces.size_ = nb_elem;
++        elem.name_ = "ELEMENTS";
++        faces.name_ = "FACES";
++        elem_faces.name_ = "ELEM_FACES";
++        elem.geometry_ = dom.name_;
++        faces.geometry_ = dom.name_;
++        elem_faces.geometry_ = dom.name_;
++
++        if (som.size_ < 0 || elem.size_ < 0) {
++          Journal() << "Error reading Geometry: missing or bad nb_som_tot or nb_elem_tot parameter" << endl;
++          throw(LataDBError(LataDBError::READ_ERROR));
++        }
++        if (dom.elem_type_ == "") {
++          Journal() << "Error reading Geometry: missing type_elem parameter" << endl;
++          throw(LataDBError(LataDBError::READ_ERROR));
++        }
++        get_element_data(dom.elem_type_, som.nb_comp_, elem.nb_comp_, faces.nb_comp_, elem_faces.nb_comp_);
++
++        // Add domain and som which are complete. We need the "som" to be in the database
++        //  for the "old lata 2D hack" in read_data2_()
++        add(timesteps_.size() - 1, dom);
++        add(timesteps_.size() - 1, som);
++        // Parse the geometry file to find file_offsets 
++        {
++          Journal(verb_level) << " Parsing geometry file to find file offset of data blocs" << endl;
++          LataDataFile f(internal_data_buffer_, path_prefix_, som.filename_,som.datatype_.msb_);
++          IntTab * null = 0; // Null pointer => don't actually read the data
++          read_data2_(f, som, null);
++          elem.datatype_.file_offset_ = f.position();
++          Journal(verb_level+1) << "  elements at file offset " << elem.datatype_.file_offset_ << endl;
++          if (faces.size_ >= 0) {
++            read_data2_(f, elem, null);
++            faces.datatype_.file_offset_ = f.position();
++            Journal(verb_level+1) << "  faces at file offset " << faces.datatype_.file_offset_ << endl;
++            read_data2_(f, faces, null);
++            elem_faces.datatype_.file_offset_ = f.position();
++            Journal(verb_level+1) << "  elem_faces at file offset " << elem_faces.datatype_.file_offset_ << endl;
++          }
++        }
++
++        add(timesteps_.size() - 1, elem);
++        if (faces.size_ >= 0) {
++          Journal(verb_level+1) << " Adding FACES and ELEM_FACES " << faces.size_ << endl;
++          add(timesteps_.size() - 1, faces);
++          add(timesteps_.size() - 1, elem_faces);
++        }
++        if (nproc > -1) {
++          LataDBField joint(elem);
++          joint.datatype_.file_offset_ = 0;
++          joint.size_ = nproc;
++          joint.nb_comp_ = 2;
++          joint.reference_ = "";
++          joint.name_ = "JOINTS_SOMMETS";
++          joint.filename_ = file_decal_som;
++          add(timesteps_.size() - 1, joint);
++          joint.reference_ = "";
++          joint.name_ = "JOINTS_ELEMENTS";
++          joint.filename_ = file_decal_elem;
++          add(timesteps_.size() - 1, joint);
++          if (file_decal_faces != "??") {
++            joint.reference_ = "";
++            joint.name_ = "JOINTS_FACES";
++            joint.filename_ = file_decal_faces;
++            add(timesteps_.size() - 1, joint);
++          }
++        }
++      }
++    else if (motlu == "Champ")
++      {
++        LataDBField field;
++        field.datatype_ = default_type_float();
++        is >> field.name_;
++        check(is, "failed reading field name");
++        Journal(verb_level) << "Reading field " << field.name_ << endl; 
++        Nom n;
++        is >> n;
++        check(is, "failed reading field filename");
++        field.filename_ = n;
++        Journal(verb_level+1) << " filename=" << n << endl;
++
++        if ((field.name_ == "INTERFACES" || field.name_ == "PARTICULES") && old_style_lata_) {
++          // This is the old dirty syntax for moving meshes
++
++          Journal(verb_level+1) << " Parsing an oldstyle interface file" << endl;
++          // Open the file and read the content
++          try {
++            LataDBDataType::MSB msb = default_type_int_.msb_;
++            LataDataFile f(internal_data_buffer_, path_prefix_, field.filename_,msb);
++           
++            LataDBDataType::Type int_type = default_type_int_.type_;
++            LataDBDataType::Type float_type = default_float_type_;
++            LataDBGeometry dom;
++            dom.timestep_ = timesteps_.size()-1;
++            dom.name_ = field.name_;
++            LataDBField som;
++            som.name_ = "SOMMETS";
++            som.filename_ = field.filename_;
++            som.geometry_ = field.name_;
++            som.datatype_ = default_type_float();
++            som.datatype_.fortran_bloc_markers_ = LataDBDataType::NO_BLOC_MARKER;
++            ArrOfInt tmptab(2);
++            bloc_read(f, msb, int_type, tmptab);
++            som.nb_comp_ = tmptab[0]; // dimension
++            som.size_ = tmptab[1]; // nb nodes
++            Journal(verb_level+1) << " Nb nodes=" << som.size_ << " dimension=" << som.nb_comp_ << endl;
++            som.datatype_.file_offset_ = f.position();
++            bloc_read_skip(f, msb, float_type, som.size_ * som.nb_comp_);
++            LataDBField elem;
++            elem.name_ = "ELEMENTS";
++            elem.filename_ = field.filename_;
++            elem.geometry_ = field.name_;
++            elem.datatype_ = default_type_int_;
++            elem.datatype_.fortran_bloc_markers_ = LataDBDataType::NO_BLOC_MARKER;
++            elem.datatype_.array_index_ = LataDBDataType::C_INDEXING;
++            bloc_read(f, msb, int_type, tmptab);
++            elem.nb_comp_ = tmptab[0];
++            elem.size_ = tmptab[1];
++            Journal(verb_level+1) << " Nb elements=" << elem.size_ << " shape=" << elem.nb_comp_ << endl;
++            if (field.name_ == "PARTICULES") {
++              // Special case for front-tracking markers
++              Journal(verb_level+1) << " PARTICULES: element type = point" << endl;
++              dom.elem_type_ = "POINT";
++            } else {
++              if (elem.nb_comp_ == 2)
++                dom.elem_type_ = "SEGMENT";
++              else if (elem.nb_comp_ == 3)
++                dom.elem_type_ = "TRIANGLE_3D";
++              else {
++                Journal() << "Error reading an interface: invalid element shape " << elem.nb_comp_ << endl;
++                throw(LataDBError(LataDBError::READ_ERROR));
++              }
++            }
++            elem.datatype_.file_offset_ = f.position();
++            bloc_read_skip(f, msb, int_type, elem.size_ * elem.nb_comp_);
++            add(timesteps_.size() - 1, dom);
++            add(timesteps_.size() - 1, som);
++            add(timesteps_.size() - 1, elem);
++            // Read components:
++            while(1) {
++              LataDBField fieldbis;
++              f.set_encoding(msb, int_type);
++              f.set_exception(0);
++              f >> fieldbis.localisation_;
++              f.set_exception(1);
++              if (fieldbis.localisation_ == "")
++                break;
++              fieldbis.filename_ = som.filename_;
++              fieldbis.geometry_ = som.geometry_;
++              fieldbis.datatype_ = som.datatype_;
++              tmptab.resize_array(1);
++              bloc_read(f, msb, int_type, tmptab);
++              fieldbis.nb_comp_ = tmptab[0];
++              if (fieldbis.nb_comp_ == som.nb_comp_)
++                fieldbis.nature_ = LataDBField::VECTOR;
++              else
++                fieldbis.nature_ = LataDBField::SCALAR;
++              f >> fieldbis.name_;
++              if (fieldbis.localisation_ == "SOM") {
++                fieldbis.size_ = som.size_;
++              } else {
++                fieldbis.size_ = elem.size_;
++              }
++              Journal(verb_level+1) << " Interface field " << fieldbis.localisation_ << " "
++                                    << fieldbis.name_ << endl;
++              fieldbis.datatype_.file_offset_ = f.position();
++              bloc_read_skip(f, msb, float_type, fieldbis.size_ * fieldbis.nb_comp_);
++              add(timesteps_.size() - 1, fieldbis);
++            }
++          }
++          catch (LataDBError err) {
++            // If file is missing, issue the "missing file" message and continue
++            if (err.err_ != LataDBError::FILE_NOT_FOUND)
++              throw;
++            else
++              interface_file_not_found++;
++          }
++          // Read next keyword:
++          read_keyword(is, nomlu, motlu);
++        } else {
++          if (old_style_lata_) {
++            // Old (legacy) syntax for champs: we must guess the properties from the filename!
++
++            field.datatype_ = default_type_float();
++            // Extract other data from filename (nb_comp_, localisation_, etc)
++            // find geometry name
++            Noms dom_names = geometry_names(0 /* timestep */);
++            const entier nb_geom = dom_names.size();
++            entier i;
++            for (i = 0; i < nb_geom; i++) {
++              Nom testname(".");
++              testname += dom_names[i];
++              testname += ".";
++              if (Motcle(n).find(testname)>=0)
++                break;
++            }
++            if (i == nb_geom) {
++              Journal() << "Error in LataDB_V1::read_master_file: could not find domain for Champ " << n << endl;
++              throw(LataDBError(LataDBError::READ_ERROR));
++            }
++            Journal(verb_level+1) << " geometry=" << dom_names[i] << endl;
++            const LataDBGeometry & dom = get_geometry(0, dom_names[i]);
++            field.geometry_ = dom_names[i];
++            lata_v1_get_localisation(n, field.localisation_);
++            Journal(verb_level+1) << " localisation=" << field.localisation_ << endl;
++            const LataDBField & sommets = get_field(0 /* timestep */, dom_names[i], "SOMMETS", "*");
++            const entier dim = sommets.nb_comp_;
++            field.nb_comp_ = lata_v1_get_nb_comp(field.name_, field.localisation_, dom, dim, field.nature_, field.datatype_.data_ordering_);
++            Journal(verb_level+1) << " composantes=" << field.nb_comp_ << endl;
++            if (field.localisation_.debute_par("SOM"))
++              field.size_ = sommets.size_;
++            else if (field.localisation_.debute_par("ELEM"))
++              field.size_ = get_field(0 /* timestep */, dom_names[i], "ELEMENTS", "*").size_;
++            else if (field.localisation_.debute_par("FACE"))
++              field.size_ = get_field(0 /* timestep */, dom_names[i], "FACES", "*").size_;
++            else {
++              Journal() << "Error in LataDB_V1::read_master_file: invalid localisation "
++                        << field.localisation_ << endl;
++              throw(LataDBError(LataDBError::READ_ERROR));
++            }
++            // Read next keyword:
++            read_keyword(is, nomlu, motlu);
++          } else {
++            // NEW LATAV2 SYNTAX for fields
++            // The default data type is "float_"
++            field.datatype_ = default_type_float();
++            field.size_ = -1;
++            while(1) {
++              read_keyword(is, nomlu, motlu);
++              if (motlu.debute_par("geometrie=")) {
++                read_string_param(is, nomlu, field.geometry_, "error reading geometrie parameter");
++                // Check that the geometry exists
++                get_geometry(timesteps_.size() - 1, field.geometry_, FIRST_AND_CURRENT);
++              } else if (motlu.debute_par("composantes=")) {
++                read_int_param(is, motlu, field.nb_comp_, "bad composantes parameter");
++              } else if (motlu.debute_par("localisation=")) {
++                read_string_param(is, motlu, field.localisation_, "error reading localisation parameter");
++              } else if (motlu.debute_par("format=")) {
++                LataDBDataType::Type tmp_int_type; // Unused
++                LataDBDataType::Type tmp_float_type; // unused
++                read_format_string(motlu, field.datatype_, tmp_int_type, tmp_float_type);
++              } else if (motlu.debute_par("size=")) {
++                read_long_param(is, motlu, field.size_, "error reading size parameter");
++              } else if (motlu.debute_par("file_offset=")) {
++                read_long_param(is, motlu, field.datatype_.file_offset_, "error reading file offset parameter");
++              } else if (motlu.debute_par("nature=")) {
++                Motcle nat;
++                read_string_param(is, motlu, nat, "error reading nature parameter");
++                if (nat.find("SCALAR")>=0)
++                  field.nature_ = LataDBField::SCALAR;
++                else if (nat.find("VECTOR")>=0)
++                  field.nature_ = LataDBField::VECTOR;
++                else {
++                  Journal() << "Error in LataDB_V1::read_master_file: invalid nature "
++                            << nat << endl;
++                  throw(LataDBError(LataDBError::READ_ERROR));
++                }
++              } else if (motlu.debute_par("reference=")) {
++                Nom ref;
++                read_string_param(is, motlu, ref, "error reading reference parameter");
++                field.reference_ = ref;
++              } else if (motlu.debute_par("noms_compo=")) {
++                Noms ref;
++                read_noms_param(is, motlu, ref, "error reading noms_compo");
++                Journal(verb_level+1)<<"noms_compos pas interprete "<<motlu<<endl;
++              }
++              else
++                break;
++              Journal(verb_level+1) << " " << motlu << endl;
++            }
++            if (field.size_ < 0) {
++              // This is untested. Deactivate for the moment.
++              //              Journal(verb_level) << " No size parameter given. Take size of the localisation field: ";
++              // if (field_exists(timesteps_.size() - 1, field.geometry_, field.localisation_, FIRST_AND_CURRENT)) {
++              // field.size_ = get_field(timesteps_.size() - 1, field.geometry_, field.localisation_, FIRST_AND_CURRENT).size_;
++              // } else {
++              Journal() << " Error, no size parameter for field " << field.name_ << " and localisation " << field.localisation_ 
++                        << " does not match any existing field" << endl;
++              throw(LataDBError(LataDBError::READ_ERROR));
++              // }
++            }
++          }
++          add(timesteps_.size() - 1, field);
++        }
++      }
++    else if (motlu == "import_file")
++      {
++        // Load another lata master file recursively and merge timesteps
++        Nom filenamebis;
++        is >> filenamebis; // Read filename (without prefix)
++        LataDB newdb;
++        Nom filename2(prefix);
++        filename2 += filenamebis;
++        Journal(verb_level) << "Importing another lata database from file: " << filename << endl;
++        newdb.read_master_file(prefix, filename2);
++      }
++    else
++      {
++        Journal() << "Error: unknown keyword: " << motlu << endl;
++        throw(LataDBError(LataDBError::READ_ERROR));
++      }
++  }
++  if (interface_file_not_found)
++    throw LataDBError(LataDBError::FILE_NOT_FOUND);
++}
++
++// Read field data from file f into data array "data".
++//  If data is a null pointer, just skip the data bloc and leave the file pointer
++//  at the beginning of the next data bloc (used to parse the geometry file if file_offset
++//  are not specified in the lata master file)
++template <class C_Tab>
++void LataDB::read_data2_(LataDataFile & f,
++                         const LataDBField & fld,
++                         C_Tab * const data, // const pointer to non const data !
++                         long long debut, entier n, const ArrOfInt *lines_to_read) const
++{
++
++  if (is_med(fld.filename_))
++    {
++      read_data2_med_(fld,data,debut,n,lines_to_read);
++      return;
++    }
++  // Si file_offset_ vaut 0 on y va car on peut avoir lu a un autre endroit avant.
++  if (fld.datatype_.file_offset_ >= 0) {
++    Journal(verb_level_data_bloc+1) << " Seeking at position " << fld.datatype_.file_offset_ << endl; 
++    f.seek(fld.datatype_.file_offset_, LataDataFile::ABSOLUTE);
++  }
++  if (n < 0) {
++    if (lines_to_read)
++      n = lines_to_read->size_array();
++    else
++      n = fld.size_;
++  }
++
++  // in old lata format, 2d data is written as 3d:
++  // Yeah: dirty specs make dirty code...
++  long long size_in_file = fld.size_;
++  entier nb_comp_in_file = fld.nb_comp_;
++  // entier old_lata_hack = 0;
++  if (old_style_lata_ && (Motcle(fld.geometry_) != "INTERFACES") && (Motcle(fld.geometry_) != "PARTICULES")) {
++    const LataDBField & som = get_field(0, fld.geometry_, "SOMMETS", "*");
++    if (som.nb_comp_ == 2) {
++      //old_lata_hack = 1;
++      if (fld.name_ == "ELEMENTS") {
++        nb_comp_in_file *= 2;
++      } else if (fld.name_ == "SOMMETS") {
++        nb_comp_in_file = 3; // all coordinates in 3D
++        size_in_file *= 2;
++      } // else if (fld.localisation_.debute_par("SOM")) {
++        // size_in_file *= 2;
++      // }
++      Journal(verb_level_data_bloc+1) << "Old lata hack for 2D" << endl;
++    }
++  }
++  
++  if (fld.nb_comp_ < 0 || fld.size_ < 0) {
++    Journal() << "Error in LataDB::read_data_: nb_comp_ or size_ not initialized for component " << fld.name_ << endl;
++    throw;
++  }
++
++  if ((!lines_to_read) && (debut < 0 || debut + n > fld.size_)) {
++    Journal() << "Error in LataDB::read_data_: [debut,debut+n] invalid range (size=" << fld.size_ << ")" << endl;
++    throw;
++  }
++
++  if (data)
++    data->resize(n, nb_comp_in_file);
++
++  switch (fld.datatype_.data_ordering_) {
++  case LataDBDataType::C_ORDERING:
++    // data written like this: tab(0,0) tab(0,1) tab(0,2) ... tab(1,0) tab(1,1) tab(1,2) ...
++    if (fld.datatype_.fortran_bloc_markers_ == LataDBDataType::BLOC_MARKERS_MULTIPLE_WRITES) {
++      Journal() << "Error in LataDB::read_data_: fortran_bloc_markers_=MULTIPLE_WRITES is incompatible with data_ordering=C" << endl;
++      throw LataDBError(LataDBError::DATA_ERROR);
++    }
++    skip_blocksize(f, fld.datatype_);
++    if (data) {
++      if (!lines_to_read) {
++        bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, (FileOffset)debut * nb_comp_in_file);
++        bloc_read(f, fld.datatype_.msb_, fld.datatype_.type_, *data);
++        bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, (FileOffset)(size_in_file - debut - n) * nb_comp_in_file);
++      } else {
++        C_Tab tmp;
++        // Read 1024 lines chunks at a time even if only some values are needed inside
++        long long chunk_size = 0;
++        long long current_chunk_pos = 0;
++        long long current_file_pos = 0;
++        const entier nl = lines_to_read->size_array();
++        for (entier i = 0; i < nl; i++) {
++          const long long next_line = (*lines_to_read)[i];
++          // Is this line in the current chunk ?
++          if (next_line >= current_chunk_pos + chunk_size) {
++            // No => read the chunk containing this line
++            chunk_size = size_in_file - next_line;
++            if (chunk_size > 1024)
++              chunk_size = 1024;
++            tmp.resize(chunk_size, nb_comp_in_file);
++            bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, (next_line - current_file_pos) * nb_comp_in_file);
++            bloc_read(f, fld.datatype_.msb_, fld.datatype_.type_, tmp);
++            current_chunk_pos = next_line;
++            current_file_pos = next_line + chunk_size;
++          }
++          // Extract data from tmp array
++          const long long tmp_index = next_line - current_chunk_pos;
++          for (entier j = 0; j < nb_comp_in_file; j++)
++            (*data)(i, j) = tmp(tmp_index, j);
++        }
++        if (current_file_pos != size_in_file)
++          bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, (size_in_file - current_file_pos) * nb_comp_in_file);
++      }
++    } else {
++      // just skip the data
++      bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, size_in_file *  nb_comp_in_file);
++    }
++    skip_blocksize(f, fld.datatype_);
++    break;
++  case LataDBDataType::F_ORDERING:
++    {
++      // data written like this: tab(0,0) tab(1,0) tab(2,0) ... tab(0,1) tab(1,1) tab(2,1) ... tab(0,2) tab(1,2) tab(2,2) ...
++      entier multiple_bloc_markers = (fld.datatype_.fortran_bloc_markers_ == LataDBDataType::BLOC_MARKERS_MULTIPLE_WRITES);
++      // reverse rows and columns of the array
++      C_Tab tmp;
++      if (!multiple_bloc_markers)
++        skip_blocksize(f, fld.datatype_);
++      for (entier i = 0; i < nb_comp_in_file; i++) {
++        if (multiple_bloc_markers)
++          skip_blocksize(f, fld.datatype_);
++        if (data) {
++          if (!lines_to_read) {
++            tmp.resize(n, 1);
++            bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, debut);
++            bloc_read(f, fld.datatype_.msb_, fld.datatype_.type_, tmp);
++            bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, size_in_file - debut - n);
++            for (entier j = 0; j < n; j++)
++              (*data)(j, i) = tmp(j, 0);
++          } else {
++
++            // Read 1024 lines chunks at a time even if only some values are needed inside
++            long long chunk_size = 0;
++            long long current_chunk_pos = 0;
++            long long current_file_pos = 0;
++            const entier nl = lines_to_read->size_array();
++            for (entier j = 0; j < nl; j++) {
++              const long long next_line = (*lines_to_read)[j];
++              // Is this line in the current chunk ?
++              if (next_line >= current_chunk_pos + chunk_size) {
++                // No => read the chunk containing this line
++                chunk_size = size_in_file - next_line;
++                if (chunk_size > 1024)
++                  chunk_size = 1024;
++                tmp.resize(chunk_size, 1);
++                bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, (next_line - current_file_pos));
++                bloc_read(f, fld.datatype_.msb_, fld.datatype_.type_, tmp);
++                current_chunk_pos = next_line;
++                current_file_pos = next_line + chunk_size;
++              }
++              // Extract data from tmp array
++              const entier tmp_index = (entier)(next_line - current_chunk_pos);
++              (*data)(j, i) = tmp(tmp_index, 0);
++            }
++            if (current_file_pos != size_in_file)
++              bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, (size_in_file - current_file_pos));
++          }
++        } else {
++          bloc_read_skip(f, fld.datatype_.msb_, fld.datatype_.type_, size_in_file);
++        }
++        if (multiple_bloc_markers)
++          skip_blocksize(f, fld.datatype_);
++      }
++      if (!multiple_bloc_markers)
++        skip_blocksize(f, fld.datatype_);
++      break;
++    }
++  default:
++    Journal() << "Error in LataDB::read_data_: data_ordering not implemented" << endl;
++    throw;
++  }
++  
++  // old lata 2d hack :
++  if (data && nb_comp_in_file != fld.nb_comp_) {
++    // drop column in data array
++    C_Tab tmp(*data);
++    data->resize(n, fld.nb_comp_);
++    for (entier i = 0; i < n; i++) 
++      for (entier j = 0; j < fld.nb_comp_; j++)
++        (*data)(i,j) = tmp(i,j);
++  }
++}
++
++// Description: 
++//  Read n * fld.nb_comp_ values in the file filename_, starting from debut * fld.nb_comp_
++template <class C_Tab>
++void LataDB::read_data_(const LataDBField & fld, 
++                        C_Tab & data, long long debut, entier n) const
++{
++  Journal(verb_level_data_bloc) << "LataDB::read_data(" << fld.timestep_ << "," << fld.uname_
++                                << ") Reading " << path_prefix_ << fld.filename_ << " start at " << debut << " size "
++                                << n << endl;
++
++  LataDataFile f(internal_data_buffer_, path_prefix_, fld.filename_,fld.datatype_.msb_);
++  read_data2_(f, fld, &data, debut, n);
++
++}
++
++// Description: 
++//  Read n * fld.nb_comp_ values in the file filename_, starting from debut * fld.nb_comp_
++template <class C_Tab>
++void LataDB::read_data_(const LataDBField & fld,
++                        C_Tab & data, const ArrOfInt & lines_to_read) const
++{
++  Journal(verb_level_data_bloc) << "LataDB::read_data(" << fld.timestep_ << "," << fld.uname_
++                                << ") Reading " << path_prefix_ << fld.filename_ << ",  " << lines_to_read.size_array() << " non contiguous lines" 
++                                << endl;
++
++  LataDataFile f(internal_data_buffer_, path_prefix_, fld.filename_,fld.datatype_.msb_);
++  read_data2_(f, fld, &data, -1, -1, &lines_to_read);
++}
++
++// Description: reads n * nb_comp values in the file filename_ starting from debut*nb_comp_
++//  If array_index is F_STYLE, substract 1 to all values.
++void LataDB::read_data(const LataDBField & fld, IntTab & data, long long debut, entier n) const
++{
++  read_data_(fld, data, debut, n);
++  if (fld.datatype_.array_index_ == LataDBDataType::F_INDEXING) {
++    ArrOfInt & data2 = data;
++    const entier n2 = data2.size_array();
++    for (entier i = 0; i < n2; i++)
++      data2[i]--;
++  }
++}
++
++// Description: reads n * nb_comp values in the file filename_ starting from debut*nb_comp_
++void LataDB::read_data(const LataDBField & fld, DoubleTab & data, long long debut, entier n) const
++{
++  Journal() << "LataDB::read_data not coded for double" << endl;
++  throw;
++}
++
++void LataDB::read_data(const LataDBField & fld, FloatTab & data, long long debut, entier n) const
++{
++  read_data_(fld, data, debut, n);
++}
++
++// Description: reads lines_to_read.size_array() * nb_comp values.
++//  If array_index is F_STYLE, substract 1 to all values.
++void LataDB::read_data(const LataDBField & fld, IntTab & data, const ArrOfInt & lines_to_read) const
++{
++  read_data_(fld, data, lines_to_read);
++  if (fld.datatype_.array_index_ == LataDBDataType::F_INDEXING) {
++    ArrOfInt & data2 = data;
++    const entier n = data2.size_array();
++    for (entier i = 0; i < n; i++)
++      data2[i]--;
++  }
++}
++
++// Description: reads lines_to_read.size_array() * nb_comp values.
++void LataDB::read_data(const LataDBField & fld, DoubleTab & data, const ArrOfInt & lines_to_read) const
++{
++  Journal() << "LataDB::read_data not coded for double" << endl;
++  throw;
++}
++
++// Description: reads lines_to_read.size_array() * nb_comp values.
++void LataDB::read_data(const LataDBField & fld, FloatTab & data, const ArrOfInt & lines_to_read) const
++{
++  read_data_(fld, data, lines_to_read);
++}
++
++
++// Description: copy the source LataDB object, keeping only timesteps, geometries and fields
++//  that are specified (timestep 0 is always included, do not put it in the list).
++//  field_nms can contain field.name_ (like VITESSE), or extended name with localisation
++//  (like VITESSE_ELEM)
++void LataDB::filter_db(const LataDB & source,
++                       const Motcles & geometry_nms,
++                       const Motcles & field_nms,
++                       const ArrOfInt & timesteps)
++{
++  path_prefix_ = source.path_prefix_;
++  header_ = source.header_;
++  case_ = source.case_;
++  software_id_ = source.software_id_;
++  old_style_lata_ = source.old_style_lata_;
++  default_type_int_ = source.default_type_int_;
++  default_float_type_ = source.default_float_type_;
++  
++  const entier nb_tsteps = timesteps.size_array();
++  for (entier it = 0; it < nb_tsteps + 1; it++) {
++    entier src_tstep = 0;
++    if (it > 0)
++      src_tstep = timesteps[it-1];
++    LataDBTimestep & tstep = timesteps_.add(LataDBTimestep());
++    tstep.time_ = source.get_time(src_tstep);
++    // Copy geometries
++    Motcles geoms = noms_to_motcles(source.geometry_names(src_tstep));
++    entier ig;
++    for (ig = 0; ig < geoms.size(); ig++)
++      if (geometry_nms.rang(geoms[ig]) >= 0)
++        tstep.geoms_.add(source.get_geometry(src_tstep, geoms[ig]));
++    // Copy fields
++    geoms = noms_to_motcles(geometry_names(nb_timesteps()-1, FIRST_AND_CURRENT));
++    for (ig = 0; ig < geoms.size(); ig++) {
++      LataVector<Field_UName> unames = source.field_unames(src_tstep, geoms[ig], "*");
++      for (entier i_f = 0; i_f < unames.size(); i_f++) {
++        const LataDBField & src = source.get_field(src_tstep, unames[i_f]);
++        Nom name_loc = src.name_;
++        name_loc += "_";
++        name_loc += src.localisation_;
++        if (field_nms.rang(src.name_) >= 0 || field_nms.rang(name_loc) >= 0) 
++          tstep.fields_.add(src);
++      }
++    }
++  }
++}
++
++// Description: set the default value of the path prefix where write_data() will write the data
++// Warning: there is no check that the master lata file is actually written at the same place 
++//  and that all the files and data blocks mentionned in the database actually exist.
++// For the file_offset_ field, -2 is considered "unknown".
++void LataDB::set_path_prefix(const char * s)
++{
++  path_prefix_ = s;
++}
++
++#define UPDATE_MACRO(x,unknown) if (((old_type.x==unknown)||(type.x==old_type.x))&&(new_type.x!=unknown)) type.x=new_type.x
++
++// Description: changes the data type of all fields in the database.
++//  The property "x" is changed to "new_type.x" if "new_type.x" is not "unknown"
++//  and if "old_type.x" is "unknown" or "equal to the previous property" 
++// Example: convert all data to ASCII:
++//   LataDBDataType old_type; // All defaults to "unknown" => we update all fields
++//   LataDBDataType new_type;
++//   new_type.msb_ = LataDBDataType::ASCII; // Change msb_ property to ASCII:
++// Example 2: change all REAL32 data to REAL64
++//   LataDBDataType old_type;
++//   old_type.type_ = LataDBDataType::REAL32;
++//   LataDBDataType new_type;
++//   new_type.msb_ = LataDBDataType::REAL64;
++void LataDB::change_all_data_types(const LataDBDataType & old_type, const LataDBDataType & new_type)
++{
++  const entier nb_tsteps = timesteps_.size();
++  for (entier src_tstep = 0; src_tstep < nb_tsteps; src_tstep++) {
++    LataVector<LataDBField> & fields = timesteps_[src_tstep].fields_;
++    const entier nb_fields = fields.size();
++    for (entier i_field = 0; i_field < nb_fields; i_field++) {
++      LataDBDataType & type = fields[i_field].datatype_;
++      // For each field, if "old_type" is "unknown" or equal to the previous value,
++      //  and if "new_type" is not "unknown, then update the field
++      UPDATE_MACRO(msb_, LataDBDataType::UNKNOWN_MSB);
++      UPDATE_MACRO(type_, LataDBDataType::UNKNOWN_TYPE);
++      UPDATE_MACRO(array_index_, LataDBDataType::UNKNOWN_ARRAYINDEX);
++      UPDATE_MACRO(data_ordering_, LataDBDataType::UNKNOWN_ORDERING);
++      UPDATE_MACRO(fortran_bloc_markers_, LataDBDataType::UNKNOWN_MARKERS);
++      UPDATE_MACRO(bloc_marker_type_, LataDBDataType::UNKNOWN_TYPE);
++    }
++  }
++}
++#undef UPDATE_MACRO
++
++void LataDB::change_all_data_filenames(const Nom & old_prefix, const Nom & new_prefix)
++{
++  const entier nb_tsteps = timesteps_.size();
++  for (entier i = 0; i < nb_tsteps; i++) {
++    LataVector<LataDBField> & fields = timesteps_[i].fields_;
++    // Browse all fields:
++    const entier nb_fields = fields.size();
++    for (entier j = 0; j < nb_fields; j++) {
++      Nom & filename = fields[j].filename_;
++      Nom old_filename = filename;
++      filename = new_prefix;
++      if (old_filename.debute_par(old_prefix)) {
++        const entier n = old_filename.longueur()-1;
++        const char * s = old_filename;
++        for (entier ii = old_prefix.longueur()-1; ii < n; ii++)
++          filename += Nom(s[ii]);
++      } else if (old_filename == LataDBField::memory_buffer_file()) {
++        filename += Nom(".data");
++      } else {
++        filename += Nom('_');
++        filename += old_filename;
++      }
++      Journal(verb_level+1) << " Changing filename " << old_filename << " -> " << filename << endl;
++    }
++  } 
++}
++
++// This method takes all filenames mentionned in the database and sets the file_offset_ entry:
++//  - set to 0 for the first field where a given filename appears,
++//  - then for all subsequent files referring to the same name:
++//      If split_files != 0, rename the files by appending a "_number" and set file_offset to 0
++//      otherwise set file_offset_ to 1
++void LataDB::check_all_data_fileoffsets(entier split_files)
++{
++  Noms existing_filenames;
++  ArrOfInt counts; // For each filenames, number of fields referring to it
++  counts.set_smart_resize(1);
++
++  const entier nb_tsteps = timesteps_.size();
++  for (entier i = 0; i < nb_tsteps; i++) {
++    LataVector<LataDBField> & fields = timesteps_[i].fields_;
++    // Browse all fields:
++    const entier nb_fields = fields.size();
++    for (entier j = 0; j < nb_fields; j++) {
++      LataDBField & field = fields[j];
++      const entier rank = existing_filenames.rang(field.filename_);
++      if (rank < 0) {
++        // New filename
++        existing_filenames.add(field.filename_);
++        counts.append_array(1);
++        field.datatype_.file_offset_ = 0;
++        Journal(verb_level+1) << " Changing fileoffset to 0 for file " << field.filename_ 
++                              << " " << field.name_ << endl;
++      } else {
++        // Existing filename
++        if (split_files) {
++          entier n = counts[rank]++;
++          field.filename_ += "_";
++          field.filename_ += Nom(n);
++          field.datatype_.file_offset_ = 0;
++          Journal(verb_level+1) << " Changing fileoffset to 0 and renaming file " << field.filename_  
++                                << " " << field.name_ << endl;
++        } else {
++          field.datatype_.file_offset_ = 1;
++          Journal(verb_level+1) << " Changing fileoffset to 1 for file " << field.filename_  
++                                << " " << field.name_ << endl; 
++        }
++      }
++    }
++  }  
++}
++
++// Returns the rank of the created timestep (always at the end)
++entier LataDB::add_timestep(double time)
++{
++  const entier n = nb_timesteps();
++  // Timestep 0 can have any time: test only versus other timesteps:
++  if (n > 1 && time <= get_time(n-1)) {
++    Journal() << "Error in LataDB::add_timestep(" << time 
++              << "): time is below or equal to last timestep " << get_time(n-1) << endl;
++    throw(LataDBError(LataDBError::INVALID_OPERATION));
++  }
++  LataDBTimestep & t = timesteps_.add(LataDBTimestep());
++  t.time_ = time;
++  Journal(verb_level+1) << "LataDB::add_timestep " << n << " " << time << endl;
++  return n;
++}
++
++static void add_geom_check(const LataDBGeometry & geom, entier test_flag, const char *message)
++{
++  if (!test_flag) {
++    Journal() << "Error in LataDB::add_geometry, name_=" << geom.name_ << endl
++              << " geometry data is invalid because of: " << message << endl;
++    throw(LataDBError(LataDBError::INVALID_OPERATION));
++  }
++}
++
++void LataDB::add_geometry(const LataDBGeometry & geom)
++{  
++  add_geom_check(geom, geom.timestep_ >= 0 && geom.timestep_ < nb_timesteps(), "timestep");
++  Noms geoms= geometry_names(geom.timestep_, CURRENT);
++  add_geom_check(geom, geom.name_ != "" && geom.name_ != "??" && geoms.rang(geom.name_) < 0, "empty or already existing name"); 
++
++  add(geom.timestep_, geom);
++  Journal(verb_level+1) << "LataDB::add_geometry " << geom.name_ << endl;
++}
++
++void LataDB::set_elemtype(entier tstep, const char *geom_name, const char *elem_type)
++{
++  LataDBGeometry & geom = (LataDBGeometry&) get_geometry(tstep, geom_name);
++  geom.elem_type_ = elem_type;
++}
++
++
++static void add_field_check(const LataDBField & field, entier test_flag, const char *message)
++{
++  if (!test_flag) {
++    Journal() << "Error in LataDB::add_field, name_=" << field.name_ << " geometry=" << field.geometry_ << endl
++              << " field data is invalid because of: " << message << endl;
++    throw(LataDBError(LataDBError::INVALID_OPERATION));
++  }
++}
++
++// Adds a new field to the database.
++// The field.datatype_.file_offset_ will be interpreted in a particular way if the data is
++//  written with write_data(), see write_data() documentation.
++// Take special care if the same file is referenced more than once in the database:
++//  only one file should have file_offset_ <= 0 and this one will have to be written first 
++//  with write_data()  (or you know what you are doing...)
++void LataDB::add_field(const LataDBField & field)
++{
++  add_field_check(field, field.timestep_ >= 0 && field.timestep_ < nb_timesteps(), "timestep");
++  add_field_check(field, field.filename_ != "" && field.filename_ != "??", "filename");
++  add_field_check(field, field.nb_comp_ > 0, "nb_comp");
++  Noms geoms = geometry_names(field.timestep_, FIRST_AND_CURRENT);
++  add_field_check(field, field.geometry_ == "" || geoms.rang(field.geometry_) >= 0, "unknown geometry name");
++  add_field_check(field, field.name_ != "" && field.name_ != "??", "empty name"); 
++  add_field_check(field, field.component_names_.size() == 0 || field.component_names_.size() == field.nb_comp_, "number of component_names");
++  add_field_check(field, field.size_ >= 0, "size");
++  add_field_check(field, field.datatype_.msb_ != LataDBDataType::UNKNOWN_MSB, "datatype msb unspecified");
++  add_field_check(field, field.datatype_.type_ == LataDBDataType::INT32
++                  || field.datatype_.type_ == LataDBDataType::INT64
++                  || field.datatype_.type_ == LataDBDataType::REAL32
++                  || field.datatype_.type_ == LataDBDataType::REAL64, "datatype type unspecified");
++  // If integer type, we must say the indexing type:
++  add_field_check(field, 
++                  field.datatype_.type_ == LataDBDataType::REAL32
++                  || field.datatype_.type_ == LataDBDataType::REAL64
++                  || field.datatype_.array_index_ != LataDBDataType::UNKNOWN_ARRAYINDEX, 
++                  "datatype array indexing unspecified");
++  add_field_check(field, field.datatype_.data_ordering_ != LataDBDataType::UNKNOWN_ORDERING, "datatype data ordering unspecified");
++  add_field_check(field, field.datatype_.fortran_bloc_markers_ != LataDBDataType::UNKNOWN_MARKERS, "datatype fortran bloc markers unspecified");
++  add_field_check(field, field.datatype_.file_offset_ >= 0, "datatype file_offset_");
++  // ouf...
++  add(field.timestep_, field);
++  Journal(verb_level+1) << "LataDB::add_field : " << field.name_ << " " << field.geometry_ << " " << field.filename_ << " " << field.uname_ << endl;
++}
++
++LataDBDataType LataDB::default_type_float() const
++{
++  LataDBDataType type = default_type_int_;
++  type.type_ = default_float_type_;
++  return type;
++}
++
++// Description: Writes the lata master file to filename (filename must contain the path
++//  if you don't want to write in the current working directory). All data contained
++//  in the database is dumped to the file. 
++void LataDB::write_master_file(const char *filename) const
++{
++  if (!filename) {
++    Journal() << "LataDB::write_master_file got a null filename !!!" << endl;
++    throw(LataDBError(LataDBError::INVALID_OPERATION));    
++  }
++  std::ofstream os(filename);
++  if (!os.good()) { // isnogood ?
++    Journal() << "LataDB::write_master_file failed opening file " << filename << endl;
++    throw(LataDBError(LataDBError::FILE_NOT_FOUND));
++  }
++  // Try to write, if error, catch and close the file:
++  Journal(verb_level-1) << "Writing lata master file:" << filename << endl;
++  os << "LATA_V2.1" << endl;
++  os << case_ << endl;
++  os << software_id_ << endl;
++  
++  // ****************************************************************
++  // Writing data format information:
++  {
++    Motcle fmt, fmt2;
++    build_format_string(LataDBDataType(), default_type_int_, fmt);
++    build_format_string(default_type_int_, default_type_float(), fmt2);
++    os << "Format " << fmt << "," << fmt2 << endl;
++  }
++
++  // ***************************************************************
++  // Writing timesteps:
++  const entier nb_tsteps = nb_timesteps();
++  for (entier tstep = 0; tstep < nb_tsteps; tstep++) {
++    if (tstep > 0)
++      os << "TEMPS " << get_time(tstep) << endl;
++
++    Noms geoms = geometry_names(tstep);
++    const entier nb_geoms = geoms.size();
++    for (entier i_geom = 0; i_geom < nb_geoms; i_geom++) {
++      const LataDBGeometry & geom = get_geometry(tstep, geoms[i_geom], FIRST_AND_CURRENT);
++      // Do not write geometries of the first timestep
++      if (geom.timestep_ == tstep)
++        os << "GEOM  " << geom.name_ << " type_elem=" << geom.elem_type_ << endl;
++    }
++    Field_UNames unames = field_unames(tstep, "*", "*");
++    for (entier i_field = 0; i_field < unames.size(); i_field++) {
++      const LataDBField & field = get_field(tstep, unames[i_field]);
++      os << "CHAMP " << field.name_ 
++         << " " << field.filename_;
++      if (field.geometry_ != "")
++        os << " geometrie=" << field.geometry_;
++      os << " size=" << field.size_;
++      os << " composantes=" << field.nb_comp_;
++      if (field.localisation_ != "??" && field.localisation_ != "")
++        os << " localisation=" << field.localisation_;
++      if (field.component_names_.size() > 0) {
++        os << " noms_compo=";
++        const entier n = field.component_names_.size();
++        for (entier i = 0; i < n; i++) {
++          os << field.component_names_[i];
++          if (i < n-1)
++            os << ",";
++        }
++      }
++      switch(field.nature_) {
++      case LataDBField::UNKNOWN: break;
++      case LataDBField::SCALAR: os << " nature=scalar"; break;
++      case LataDBField::VECTOR: os << " nature=vector"; break;
++      default:
++        Journal() << "LataDB::write_master_file error: unknown NATURE" << endl;
++        throw(LataDBError(LataDBError::INVALID_OPERATION));
++      }
++      if (field.reference_ != "" && field.reference_ != "??")
++        os << " reference=" << field.reference_;
++      Motcle format_string;
++      build_format_string(default_type_float(), field.datatype_, format_string);
++      if (format_string != "") 
++        os << " format=" << format_string;
++      if (field.datatype_.file_offset_ > 0)
++        os << " file_offset=" << field.datatype_.file_offset_;
++      os << endl;
++    }
++  }
++  os << "FIN" << endl;
++  write_master_file_to_call_ = 0;
++}
++
++// Description: internal template to write a data block. We provide explicit methods write_data()
++//  to the user instead of a template.
++template <class C_Tab>
++FileOffset LataDB::write_data_(entier tstep, const Field_UName & uname, const C_Tab & data)
++{
++  LataDBField & fld = getset_field(tstep, uname);
++
++  LataDataFile f(internal_data_buffer_, path_prefix_, fld.filename_,
++                 fld.datatype_.msb_,
++                 (fld.datatype_.file_offset_ <= 0) ? LataDataFile::WRITE : LataDataFile::APPEND);
++  fld.datatype_.file_offset_ = f.position();
++  Journal(verb_level_data_bloc) << "Writing block data at offset " << fld.datatype_.file_offset_ << endl;
++  if (fld.nb_comp_ != data.dimension(1) || fld.size_ != data.dimension(0)) {
++    Journal() << "Error in LataDB::write_data_: nb_comp_ or size_ declared in the field doesnt match array dimensions." << fld.name_ << endl;
++    throw;
++  }
++
++  const entier n = fld.size_;
++  
++  switch (fld.datatype_.data_ordering_) {
++  case LataDBDataType::C_ORDERING: 
++    {
++      if (fld.datatype_.fortran_bloc_markers_ == LataDBDataType::BLOC_MARKERS_MULTIPLE_WRITES) {
++        Journal() << "Error in LataDB::write_data_: fortran_bloc_markers_=MULTIPLE_WRITES is incompatible with data_ordering=C" << endl;
++        throw LataDBError(LataDBError::DATA_ERROR);
++      }
++      const entier sz = data.size_array();
++      write_blocksize(f, fld.datatype_, sz);
++      bloc_write(f, fld.datatype_.msb_, fld.datatype_.type_, data, fld.nb_comp_);
++      write_blocksize(f, fld.datatype_, sz);
++      break;
++    }
++  case LataDBDataType::F_ORDERING:
++    {
++      entier multiple_bloc_markers = (fld.datatype_.fortran_bloc_markers_ == LataDBDataType::BLOC_MARKERS_MULTIPLE_WRITES);
++      // reverse rows and columns of the array
++      C_Tab tmp;
++      tmp.resize(n, 1);
++      if (!multiple_bloc_markers)
++        write_blocksize(f, fld.datatype_, data.size_array());
++      for (entier i = 0; i < fld.nb_comp_; i++) {
++        if (multiple_bloc_markers)
++          write_blocksize(f, fld.datatype_, n);
++        for (entier j = 0; j < n; j++)
++          tmp(j, 0) = data(j, i);
++        bloc_write(f, fld.datatype_.msb_, fld.datatype_.type_, tmp, 1);
++        if (multiple_bloc_markers)
++          write_blocksize(f, fld.datatype_, n);
++      }
++      if (!multiple_bloc_markers)
++        write_blocksize(f, fld.datatype_, data.size_array());
++      break;
++    }
++  default:
++    Journal() << "Error in LataDB::write_data_: data_ordering not implemented" << endl;
++    throw;
++  }
++  write_master_file_to_call_ = 1;
++  return f.position();
++}
++
++// Writes the data to disk according to datatype_ of the field.
++// The filename will be "path_prefix_ + field.filename_".
++// The path_prefix_ can be changed with set_path_prefix()
++// If field.datatype_.file_offset_<=0, any existing file is deleted and the data is written at offset 0
++// otherwise the data is written at the end of the file and file_offset_ for this field is updated.
++// Returns the FileOffset of the file pointer after writing the data (points to the end of the file)
++// The call to write_master_file() must be done after all write_data (otherwise the file_offset_ might be wrong)
++FileOffset LataDB::write_data(entier tstep, const Field_UName & uname, const DoubleTab &tab)
++{
++  Journal() << " LataDB::write_data not coded for double" << endl;
++  throw;
++  return 0;
++}
++
++// See write_data(..., const DoubleTab &)
++FileOffset LataDB::write_data(entier tstep, const Field_UName & uname, const FloatTab &tab)
++{
++  return write_data_(tstep, uname, tab);
++}
++
++// See write_data(..., const DoubleTab &)
++FileOffset LataDB::write_data(entier tstep, const Field_UName & uname, const IntTab &tab)
++{
++  if (get_field(tstep, uname).datatype_.array_index_ == LataDBDataType::F_INDEXING) {
++    IntTab tmp;
++    tmp.set_smart_resize(1);
++    tmp.resize(tab.dimension(0), tab.dimension(1));
++    ArrOfInt & array = tmp;
++    const ArrOfInt & src = tab;
++    for (entier i = 0; i < array.size_array(); i++)
++      array[i] = src[i] + 1;
++    return write_data_(tstep, uname, tmp);
++  }
++
++  return write_data_(tstep, uname, tab);
++}
++
++LataDB::~LataDB()
++{
++#if 0
++  if (write_master_file_to_call_) {
++    Journal() << "Internal Error !!! write_data() has been called without calling write_master_file() after." << endl;
++//    exit(); // In c++ it is forbidden to throw exceptions in a destructor.
++  }
++#endif
++}
++
++const char *LataDBError::describe() const
++{
++  switch(err_) {
++  case READ_ERROR: return "READ_ERROR"; break;
++  case BAD_HEADER: return "BAD_HEADER"; break;
++  case BAD_TIMESTEP: return "BAD_TIMESTEP"; break;
++  case NAME_NOT_FOUND: return "NAME_NOT_FOUND"; break;
++  case DATA_ERROR: return "DATA_ERROR"; break;
++  case FILE_NOT_FOUND: return "FILE_NOT_FOUND"; break;
++  case BAD_ELEM_TYPE: return "BAD_ELEM_TYPE"; break;
++  case INVALID_OPERATION: return "INVALID_OPERATION"; break;
++  case INTEGER_OVERFLOW: return "INTEGER_OVERFLOW"; break;
++  default: ;
++  }
++  return "LataDB_unknown_error";
++}
++#undef verb_level
++#undef verb_level_data_bloc
+diff --git a/databases/readers/Lata/LataDB.h b/databases/readers/Lata/LataDB.h
+new file mode 100644
+index 0000000..8862d3c
+--- /dev/null
++++ b/databases/readers/Lata/LataDB.h
+@@ -0,0 +1,303 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef LataDB_include_
++#define LataDB_include_
++#include <Lata_tools.h>
++#include <sstream>
++
++// This file describes the LataDB class and all associated data structures.
++//  LataDB stores all the meta contained in the .lata master file, and not more.
++//  It provides services to add meta-data, read data to a user specified array,
++//  and write data to a lata file.
++
++typedef BigEntier FileOffset;
++
++// .Description: LataDBError is the type used for thrown exceptions in LataDBxxx classes
++class LataDBError
++{
++public:
++  // READ_ERROR: low level io error while reading .lata file
++  // BAD_HEADER: the header in the .lata file is not correct
++  // BAD_TIMESTEP: request for a non existant timestep
++  // NAME_NOT_FOUND: request for a non existant domain or field name
++  // DATA_ERROR: low level io error while reading a data bloc file
++  // FILE_NOT_FOUND: a file (.lata or data) couldn't be opened on disc.
++  // INVALID_OPERATION: trying to read from a modified database, etc...
++  // INTEGER_OVERFLOW: trying to convert an integer to a too small data type
++  //  (if error when reading a data file, you must recompile with typedef long long entier,
++  //   if error when writing a data file, you must use INT64 type_ for data blocks)
++  enum ErrType { READ_ERROR, BAD_HEADER, BAD_TIMESTEP, NAME_NOT_FOUND, DATA_ERROR,
++                 FILE_NOT_FOUND, BAD_ELEM_TYPE, INVALID_OPERATION, INTEGER_OVERFLOW };
++  LataDBError(ErrType err) : err_(err) {};
++  ErrType err_;
++  const char *describe() const;
++};
++
++// .Description: This is the data type for a specific part of a data bloc.
++//  In order to read a data bloc, we need a LataDBDataType for the "bloc size" id (this is an integer),
++//  and a LataDBDataType for the bloc content. LataDBGeometry blocs need two types, one for
++//  the node coordinates and one for the elements
++class LataDBDataType
++{
++public:
++  enum MSB { UNKNOWN_MSB, MSB_BIG_ENDIAN, MSB_LITTLE_ENDIAN, ASCII };
++  MSB msb_;
++  enum Type { UNKNOWN_TYPE, INT32, INT64, REAL32, REAL64 };
++  Type type_;
++  // Array index is ignored if type_ is REAL.
++  // NOT_AN_INDEX: array does not contain indexes.
++  // C_INDEXING: If array contains indexes to other items, 0 <= array[i] < nb_items
++  // F_INDEXING: 1 <= array[i] <= nb_items (Fortran index)
++  // See LataDB::read_data
++  enum ArrayIndex { UNKNOWN_ARRAYINDEX, NOT_AN_INDEX, C_INDEXING, F_INDEXING };
++  ArrayIndex array_index_;
++  // C_ORDERING: If multidimensionnal array is read, data ordering is like in C
++  //               (all components for first node, then all components for second node, etc)
++  // F_ORDERING: like in fortran (first all values for component 0 then all values for compo 1 etc)
++  enum DataOrdering { UNKNOWN_ORDERING, C_ORDERING, F_ORDERING };
++  DataOrdering data_ordering_;
++
++  //   _NO_BLOC:         no fortran bloc marker
++  //   _SINGLE_WRITE:    all data written in one fortran write instruction
++  //   _MULTIPLE_WRITES: one fortran write instruction for each component
++  enum FortranBlocMarkers { UNKNOWN_MARKERS, NO_BLOC_MARKER, BLOC_MARKERS_SINGLE_WRITE, BLOC_MARKERS_MULTIPLE_WRITES };
++  FortranBlocMarkers fortran_bloc_markers_;
++
++  // The data type for fortran bloc markers
++  Type bloc_marker_type_;
++
++  // Data is located at this offset in the file
++  FileOffset file_offset_;
++
++  LataDBDataType() : msb_(UNKNOWN_MSB), type_(UNKNOWN_TYPE), array_index_(UNKNOWN_ARRAYINDEX), 
++                     data_ordering_(UNKNOWN_ORDERING), fortran_bloc_markers_(UNKNOWN_MARKERS), bloc_marker_type_(UNKNOWN_TYPE),
++                     file_offset_(0)
++  {};
++  static MSB machine_msb_;
++};
++
++// .Description: Description of a geometry (= a mesh)
++class LataDBGeometry
++{
++public:
++  LataDBGeometry() { timestep_ = -1; }
++  // Item name
++  Nom name_;
++  // Type of elements
++  Motcle elem_type_;
++  entier timestep_;
++};
++
++// This is a unique identifier for fields
++//  at this time, contains domain name, field name and localisation,
++//  might be further extended if needed
++class Field_UName
++{
++public:
++  Field_UName();
++  Field_UName(const char *domain_name, const char *field_name, const char *loc);
++  Field_UName(const Field_UName &);
++  int operator==(const Field_UName &) const;
++  Field_UName & operator=(const Field_UName &);
++  Nom build_string() const;
++  const Motcle & get_localisation() const { return loc_; }
++  const Motcle & get_field_name() const { return field_name_; }
++  const Motcle & get_geometry() const { return geometry_; }
++  void        set_field_name(const Nom &);
++protected:
++  Motcle geometry_;
++  Motcle field_name_;
++  Motcle loc_;
++};
++
++std::ostream & operator<<(std::ostream &, const Field_UName &);
++
++typedef LataVector<Field_UName> Field_UNames;
++class EFichier;
++
++// .Description: Description of a field
++class LataDBField
++{
++public:
++  LataDBField() { timestep_ = -1; nb_comp_ = -1; nature_ = UNKNOWN; size_ = -1; }
++
++  // Unique identifier
++  Field_UName uname_;
++  // Field name (without localisation spec)
++  Nom name_;
++  // Where is it ?
++  int timestep_;
++  // Filename containing the data
++  // Special names: memory_buffer_file() => data stored in the LataDB memory buffer.
++  Nom filename_;
++  // Number of components
++  entier nb_comp_;
++  // LataDBGeometry
++  Nom geometry_;
++  // Name of the components
++  Noms component_names_;
++  Noms unites_;
++  // Scalar or vector ?
++  enum Nature { UNKNOWN, SCALAR, VECTOR };
++  Nature nature_;
++  // Type and formatting info of the data
++  LataDBDataType datatype_;
++  // Localisation (elem, som, faces, ...)
++  Motcle localisation_;
++  // Ref
++  Nom reference_;
++  // Size (number of lines) 
++  long long size_;
++  
++  static const char * memory_buffer_file();
++};
++
++// .Description: Description of one timestep (contains a vector of items)
++class LataDBTimestep
++{
++public:
++  LataDBTimestep() { time_ = -1.; }
++  double time_;
++protected:
++  friend class LataDB;
++  LataVector<LataDBGeometry> geoms_;
++  LataVector<LataDBField> fields_;
++};
++
++class LataDataFile;
++class ArrOfInt;
++class LataDB
++{
++public:
++  LataDB() : internal_data_buffer_(std::ios::in | std::ios::out | std::ios::app | std::ios::binary) { old_style_lata_ = 0; path_prefix_ = ""; write_master_file_to_call_ = 0; }
++  LataDB(const LataDB & src) :
++    header_(src.header_),
++    case_(src.case_),
++    software_id_(src.software_id_),
++    default_type_int_(src.default_type_int_),
++    default_float_type_(src.default_float_type_),
++    timesteps_(src.timesteps_),    
++    path_prefix_(src.path_prefix_),
++    old_style_lata_(src.old_style_lata_),
++    write_master_file_to_call_(src.write_master_file_to_call_) {
++    // Note B.M. il faudrait copier internal_data_buffer_ pour faire marcher lml->lata mais je ne sais pas faire...
++  }
++  virtual ~LataDB();
++  void reset();
++  virtual void read_master_file(const char * path_prefix_, const char * filename);
++  void read_master_file_med(const char *prefix, const char *filename);
++  static Nom   read_master_file_options(const char * filename);
++  
++  virtual void filter_db(const LataDB & source,
++                         const Motcles & geometry_names,
++                         const Motcles & field_names,
++                         const ArrOfInt & timesteps);
++
++  entier                 nb_timesteps() const;
++  double                 get_time(entier tstep) const;
++  enum TStepSelector { CURRENT, FIRST_AND_CURRENT };
++  Noms                   geometry_names(entier tstep, TStepSelector which_tstep = CURRENT) const;
++  Field_UNames           field_unames(entier tstep, const char * geometry, const char * name, TStepSelector which_tstep = CURRENT) const;
++  const LataDBGeometry & get_geometry(entier tstep, const char * name, TStepSelector which_tstep = CURRENT) const;
++  entier                 field_exists(entier tstep, const char *geom, const char *name, TStepSelector which_tstep = CURRENT) const;
++  const LataDBField &    get_field(entier tstep, const Field_UName & uname, TStepSelector which_tstep = CURRENT) const;
++  const LataDBField &    get_field(entier tstep, const char *geom, const char *name, const char *loc, TStepSelector which_tstep = CURRENT) const;
++  const Nom &            path_prefix() const { return path_prefix_; };
++  void                   set_path_prefix(const char * s);
++
++  // First line in the .lata file
++  Nom header_;
++  // Second line in the .lata file
++  Nom case_;
++  // Third line in the .lata file
++  Nom software_id_;
++
++  LataDBDataType default_type_float() const; // Everything same as int, but type_=default_float_type_
++  LataDBDataType default_type_int_;
++  LataDBDataType::Type default_float_type_;
++
++  virtual void read_data(const LataDBField &, DoubleTab & data, long long debut = 0, entier n = -1) const;
++  virtual void read_data(const LataDBField &, FloatTab & data, long long debut = 0, entier n = -1) const;
++  virtual void read_data(const LataDBField &, IntTab & data, long long debut = 0, entier n = -1) const;
++  virtual void read_data(const LataDBField &, DoubleTab & data, const ArrOfInt & lines_to_read) const;
++  virtual void read_data(const LataDBField &, FloatTab & data, const ArrOfInt & lines_to_read) const;
++  virtual void read_data(const LataDBField &, IntTab & data, const ArrOfInt & lines_to_read) const;
++
++  enum Element { line, triangle, quadri, tetra, hexa, triangle_3D, quadri_3D, polyedre,polygone, unspecified };
++  static Element element_type_from_string(const Motcle & type_elem);
++
++  // Tools to create/update the database and write lata data to disk
++  void   change_all_data_types(const LataDBDataType & old_type, const LataDBDataType & new_type);
++  void   change_all_data_filenames(const Nom & old_prefix, const Nom & new_prefix);
++  void   check_all_data_fileoffsets(entier split_files);
++  entier add_timestep(double time);
++  void   add_geometry(const LataDBGeometry & geom);
++  void   set_elemtype(entier tstep, const char *geom_name, const char *elem_type);  
++  entier check_duplicate_filename(const char *filename) const;
++  void   add_field(const LataDBField & field);
++  void   write_master_file(const char *filename) const;
++  FileOffset write_data(entier tstep, const Field_UName &, const DoubleTab &);
++  FileOffset write_data(entier tstep, const Field_UName &, const FloatTab &);
++  FileOffset write_data(entier tstep, const Field_UName &, const IntTab &);
++
++protected:
++  LataDBField & getset_field(entier tstep, const Field_UName & uname, TStepSelector which_tstep = CURRENT);
++  void          read_master_file_header(const char *filename, EFichier & is);
++  static entier lata_v1_dim_from_elem_type(const Motcle & elem_type);
++  static entier lata_v1_get_nb_comp(const Nom & fieldname, const Motcle & localisation, const LataDBGeometry & dom, entier dim, LataDBField::Nature & nature, LataDBDataType::DataOrdering &);
++  static void get_element_data(const Motcle & elemtype, entier & dimension, entier & elem_shape, entier & face_shape, entier & nb_elem_faces);
++
++  const LataDBTimestep & get_tstep(entier i) const;
++  void add(entier tstep, const LataDBGeometry & item);
++  void add(entier tstep, const LataDBField & item);
++  template <class C_Tab> void read_data_(const LataDBField &, C_Tab & data, long long debut, entier n) const;
++  template <class C_Tab> void read_data_(const LataDBField &, C_Tab & data, const ArrOfInt & lines_to_read) const;
++  template <class C_Tab> void read_data2_(LataDataFile & f, const LataDBField & fld, C_Tab * const data, long long debut = 0, entier n = -1, const ArrOfInt *lines_to_read = 0) const;
++  template <class C_Tab> void read_data2_med_( const LataDBField & fld, C_Tab * const data, entier debut = 0, entier n = -1, const ArrOfInt *lines_to_read = 0) const;
++  template <class C_Tab> FileOffset write_data_(entier tstep, const Field_UName & uname, const C_Tab &);
++
++  // Timestep 0 contains global domains and field definition
++  // Timestep 1..size()-1 contain the data for each "TEMPS" entry
++  LataVector<LataDBTimestep> timesteps_;
++
++  // Path prefix for all data blocks (used by read_data() and write_data())
++  Nom path_prefix_;
++
++  // Is this an old-style lata file ? (with INTERFACES special files and 2D elements expanded to 3D elements)
++  entier old_style_lata_;
++
++  // This flag tells if some write_data calls have been made since the last write_master_file
++  // If yes, issue a message to say that's wrong !
++  mutable entier write_master_file_to_call_;
++
++  // This is a memory buffer where data can be written to create a temporary data base
++  mutable std::stringstream internal_data_buffer_;
++};
++#endif
+diff --git a/databases/readers/Lata/LataDBmed.h b/databases/readers/Lata/LataDBmed.h
+new file mode 100644
+index 0000000..13cfdbe
+--- /dev/null
++++ b/databases/readers/Lata/LataDBmed.h
+@@ -0,0 +1,586 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++//#define WITH_MEDLOADER
++#ifndef WITH_MEDLOADER
++void LataDB::read_master_file_med(const char *prefix, const char *filename)
++{
++  Journal() << "MED PLUGIN not compiled!" << endl;
++  throw;
++}
++template <class C_Tab> void LataDB::read_data2_med_(
++                         const LataDBField & fld,
++                         C_Tab * const data, // const pointer to non const data !
++                         entier debut, entier n, const ArrOfInt *lines_to_read) const
++{
++   Journal() << "MED PLUGIN not compiled!" << endl;
++  
++   throw;    
++}
++#else
++
++#include <MEDLoader.hxx>
++#include <MEDCouplingMemArray.hxx>
++#include <MEDCouplingUMesh.hxx>
++#include <MEDCouplingFieldDouble.hxx>
++#include <CellModel.hxx>
++#include <MEDFileField.hxx>
++
++using std::vector;
++using std::pair;
++using std::string;
++
++
++Nom latadb_name_from_type_geo(const med_geometry_type& type_geo)
++{
++  Nom type_elem;
++  switch(type_geo)
++    {
++      case MED_QUAD4:
++        type_elem="Rectangle";
++        break;
++      case MED_HEXA8:
++        type_elem="Hexaedre";      
++        break;
++      case MED_TRIA3:
++        type_elem="Triangle";break;
++      case MED_TETRA4:
++        type_elem="Tetraedre";break;
++      case MED_PENTA6:
++        type_elem="Prisme";break;
++      case MED_POLYHEDRON:
++        type_elem="Polyedre"; break;
++      case MED_POLYGON:
++        type_elem="Polygone"; break;
++      case MED_SEG2:
++        type_elem="Segment"; break;
++      default:
++        Cerr<<"type_geo " << (int)type_geo <<" is not a supported element."<<finl;
++      throw;
++        break;
++      }
++  return type_elem;
++}
++
++
++// passage de la connectivite trio a MED si sens=1
++// de MED a trio si sens=-1
++ArrOfInt renum_conn(const LataDB::Element& type)
++{
++  //  cerr<<"type elem "<<type_elem<<endl;
++  ArrOfInt filter;
++  if (type==LataDB::quadri ) {
++      filter.resize_array(4) ;
++   
++      filter[0] = 0 ;
++      filter[1] = 2 ;
++      filter[2] = 3 ;
++      filter[3] = 1 ;
++
++      
++    }
++ 
++  if (type== LataDB::hexa  )  {
++      filter.resize_array(8) ;
++ 
++        
++      filter[0] = 0 ;
++      filter[1] = 2 ;
++      filter[2] = 3 ;
++      filter[3] = 1 ;
++      filter[4] = 4 ;
++      filter[5] = 6 ;
++      filter[6] = 7 ;
++      filter[7] = 5 ;        
++      
++    }
++   
++    
++  return filter;
++
++}
++
++extern med_geometry_type typmai3[MED_N_CELL_FIXED_GEO];
++
++void latadb_get_info_mesh_med(const char* filename,const char* meshname,med_geometry_type& type_geo,int& ncells,int& nnodes,int& spacedim, int &nbcomp,int& is_structured, std::vector<int>& NIJK)
++{
++    is_structured=0;
++  int meshDim, i;
++  try {
++  std::vector< std::vector< std::pair<INTERP_KERNEL::NormalizedCellType,int> > > res = MEDCoupling::GetUMeshGlobalInfo(filename, meshname, meshDim, spacedim, nnodes);
++  
++
++  // on prend que la dimension la plus grande et on verifie que l'on a qu'un type elt 
++  if (res.size()>1)
++    {
++      cerr<<"error multi dimension in "<<meshname<<endl;
++      //throw;
++    }
++  if (res[0].size()>1)
++    { 
++      cerr<<"error multi elements in "<<meshname<<endl;
++      throw;
++    } 
++  type_geo=typmai3[res[0][0].first];
++
++  if ((type_geo==MED_POLYGON)||(type_geo==MED_POLYHEDRON))
++    {
++      //on est force de lire le maillage pour avoir le bon nombre de cellules  
++      MEDCoupling::MEDCouplingUMesh * mesh=  MEDCoupling::ReadUMeshFromFile(filename,meshname);
++      ncells = mesh->getNumberOfCells();
++      const int *idx = mesh->getNodalConnectivityIndex()->getConstPointer();
++      for (i = 0, nbcomp = 0; i < ncells; i++) if (nbcomp < idx[i + 1] - idx[i] - 1) nbcomp = idx[i + 1] - idx[i] - 1;
++      mesh->decrRef();
++    }
++  else
++    ncells=res[0][0].second;
++    }
++  catch (...)
++  {
++    // No UMesh try CMesh
++      MEDCoupling::MEDCouplingMesh* mesh=  MEDCoupling::ReadMeshFromFile(filename, meshname);
++      /* 
++        type_geo,int& ncells,int& nnodes,int& spacedim, int &nbcomp
++       */
++      MEDCoupling::MEDCouplingCMesh* cmesh = dynamic_cast<MEDCoupling::MEDCouplingCMesh*>(mesh);
++      spacedim=cmesh-> getSpaceDimension() ;
++      
++      NIJK= cmesh->getNodeGridStructure();
++      ncells=mesh->getNumberOfCells();
++      nnodes=mesh->getNumberOfNodes();
++      
++    
++   // std::cout << ncells<< " "<<sizes[2]<<std::endl;
++      mesh->decrRef();
++      
++      if (spacedim==3)
++            type_geo =MED_HEXA8;
++      else if (spacedim==2)
++           type_geo =MED_QUAD4;
++        else 
++         abort();
++        is_structured=1;
++      //abort();
++      return;
++  }
++}
++
++
++
++// Description: Reads the .lata database in the given file indicating than the 
++//  associated data files will be found in directory "prefix".
++//  If not empty, "prefix" must finish with a '/'.
++//  For "prefix" and "filename", if they do not begin with '/', are relative to pwd.
++// Exceptions: 
++//  BAD_HEADER  means that the header found in this stream is not LATA_V2
++//  READ_ERROR  means that an error has been found in the file (premature eof,
++//              io error, bad keyword, ...)
++//  FILE_NOT_FOUND means that, well, the lata file could not be opened
++void LataDB::read_master_file_med(const char *prefix, const char *filename)
++{
++  
++  
++  Journal() << "MED PLUGIN !" << endl;
++
++  // Defaults for lataV1
++  default_type_int_.msb_ = LataDBDataType::ASCII;
++  default_type_int_.type_ = LataDBDataType::INT32;
++  default_type_int_.array_index_ = LataDBDataType::F_INDEXING;
++  default_type_int_.data_ordering_ = LataDBDataType::C_ORDERING;
++  default_type_int_.fortran_bloc_markers_ = LataDBDataType::BLOC_MARKERS_SINGLE_WRITE;
++  default_type_int_.bloc_marker_type_ = LataDBDataType::INT32;
++  default_float_type_ = LataDBDataType::REAL32;
++  
++  
++
++  // Create timestep 0 (global domain and fields)
++  timesteps_.add(LataDBTimestep());
++
++
++  // on ajoute les geom 
++  // on verra apres pour les champs elem et som
++  vector<string> geoms= MEDCoupling::GetMeshNames(filename);
++  
++  vector<double> times;
++  LataDBTimestep  table; 
++  int first=1;
++  
++  for (int i=0;i<geoms.size();i++)
++    {
++      LataDBGeometry dom;
++      dom.timestep_ = timesteps_.size()-1;
++      dom.name_=geoms[i];
++      med_geometry_type type_geo;
++      int ncells,nnodes,spacedim, nbcomp;
++      int is_structured;
++      std::vector<int> NIJK;
++      latadb_get_info_mesh_med(filename,geoms[i].c_str(),type_geo,ncells,nnodes,spacedim,nbcomp,is_structured,NIJK);
++            
++      dom.elem_type_=latadb_name_from_type_geo(type_geo);
++
++      if (is_structured==0)
++      {
++      LataDBField som;
++      som.name_ = "SOMMETS";
++      som.geometry_ = dom.name_;
++      som.filename_ = filename;
++      som.size_=nnodes;
++      som.datatype_ = default_type_float(); // ??
++      som.nb_comp_=spacedim;
++      
++      LataDBField elem;
++      elem.name_ = "ELEMENTS";
++      elem.geometry_ = dom.name_;
++      elem.filename_ = filename;
++      elem.size_=ncells;
++      elem.datatype_ = default_type_float(); // ??
++
++      int dim,ff,ef;
++      get_element_data(dom.elem_type_, dim, elem.nb_comp_, ff, ef);
++      if (elem.nb_comp_ == -1) elem.nb_comp_ = nbcomp;
++      
++      add(timesteps_.size() - 1, dom);
++      add(timesteps_.size() - 1, som);
++      add(timesteps_.size() - 1, elem);
++      }
++      else
++      {
++      add(timesteps_.size() - 1, dom);
++       {
++        LataDBField som;
++        som.name_ = "SOMMETS_IJK_I";
++        som.geometry_ = dom.name_;
++        som.filename_ = filename;
++        som.size_=NIJK[0];
++        som.datatype_ = default_type_float(); // ??
++        som.nb_comp_=1;
++        add(timesteps_.size() - 1, som);
++      }
++       {
++        LataDBField som;
++        som.name_ = "SOMMETS_IJK_J";
++        som.geometry_ = dom.name_;
++        som.filename_ = filename;
++        som.size_=NIJK[1];
++        som.datatype_ = default_type_float(); // ??
++        som.nb_comp_=1;
++        add(timesteps_.size() - 1, som);
++      }
++       {
++        LataDBField som;
++        som.name_ = "SOMMETS_IJK_K";
++        som.geometry_ = dom.name_;
++        som.filename_ = filename;
++        som.size_=NIJK[2];
++        som.datatype_ = default_type_float(); // ??
++        som.nb_comp_=1;
++        add(timesteps_.size() - 1, som);
++      }
++          
++      }
++      
++    
++  vector<string> fields; 
++  fields= MEDCoupling::GetAllFieldNamesOnMesh(filename,dom.name_.getString());
++  
++
++  for (int i=0;i<fields.size();i++)
++    {
++      LataDBField som;
++      som.name_ = fields[i];
++      
++      som.filename_ = filename;
++      
++      som.datatype_ = default_type_float(); // ??
++      
++      som.nature_ = LataDBField::SCALAR;
++  
++  
++      const Nom& meshname = dom.name_; 
++      som.geometry_ = meshname;
++      Motcle newname(fields[i].c_str());
++      Motcle ajout("_");
++
++      // cerr<<"field " <<fields[i]<< " "<< meshname<<" ";
++      vector< MEDCoupling::TypeOfField > ltypes=MEDCoupling::GetTypesOfField(filename,meshname.getString(),fields[i].c_str());
++      //if (ltypes.size()!=1) throw;
++      for (int t=0;t<ltypes.size();t++)
++      {
++      switch (ltypes[t])
++      {
++        //    case :
++      case MEDCoupling::ON_CELLS :
++        //cerr<<"elem"<<endl;
++        som.size_=ncells;
++        som.localisation_="ELEM";
++        break;
++      case  MEDCoupling::ON_NODES :
++        //cerr<<"som"<<endl;
++        som.size_=nnodes;
++        som.localisation_="SOM";
++        break;
++      default:
++        cerr<<"type inconnu "<<endl;throw;
++      }
++
++      som.nb_comp_=1;
++      // pour recupere nb_comp !!!
++      
++      som.nb_comp_=MEDCoupling::GetComponentsNamesOfField(filename,fields[i].c_str()).size();
++
++      
++      if (spacedim==som.nb_comp_)
++      som.nature_ = LataDBField::VECTOR;
++      ajout+=som.localisation_;
++      ajout+="_";
++      ajout+=meshname;
++      newname=newname.prefix(ajout);
++     
++      som.name_=newname;
++     
++      //som.uname_= Field_UName(meshname, newname, som.localisation_);
++      
++      table.fields_.add(som);
++    
++      if (1) 
++      {
++      if (ltypes.size()>1)
++        {
++          vector<pair< int, int > > iters= MEDCoupling::GetFieldIterations(ltypes[t],filename,meshname.getString(),fields[i].c_str());
++          for (int iter=0;iter<iters.size();iter++)
++            {
++              double t= MEDCoupling::GetTimeAttachedOnFieldIteration(filename,fields[i].c_str(),iters[iter].first,iters[iter].second);
++              if (first==1)
++                {
++                  times.push_back(t);
++                  //cerr<<"M ici  "<<t <<" "<<iters[iter].first<<" "<<iters[iter].second<<endl;
++                }
++              else
++                {
++                  if (times[iter]!=t)
++                    {
++                      cerr<<"field " <<fields[i]<<" M time "<< t << " diff "<<times[iter] << endl;
++                      //throw;
++                    }
++                }
++            }
++          
++        }
++      else
++        {
++          vector<pair<pair<int,int>,double> > vtimes=MEDCoupling::GetAllFieldIterations(filename,/*meshname,*/fields[i].c_str());
++          for (int it=0;it<vtimes.size();it++)
++            {
++              
++              double t=vtimes[it].second;
++              if (first==1)
++                {
++                  times.push_back(t);
++                  //  cerr<<" ici  "<<t <<endl;
++                }
++              else
++                {
++                  if (times[it]!=t)
++                    {
++                      cerr<<"field " <<fields[i]<<" time "<< t << " diff "<<times[it] << endl;
++                      //throw;
++                    }
++                }
++            }
++
++        }
++      }
++      first=0;
++    }
++    }
++    }
++  if (times.size()>0)
++    for (int i=0;i<times.size();i++)
++    {
++      
++      //LataDBTimestep & t = timesteps_.add(table);
++      LataDBTimestep& t = timesteps_.add(LataDBTimestep());
++      t.time_=times[i];
++      for (int f=0;f<table.fields_.size();f++)
++      add(i+1,table.fields_[f]);
++    
++    }
++  for (int i=0;i<times.size()*0;i++)
++    cerr<<" time "<<times[i]<<endl;
++}
++
++
++template <class C_Tab>
++void LataDB::read_data2_med_(
++                         const LataDBField & fld,
++                         C_Tab * const data, // const pointer to non const data !
++                         entier debut, entier n, const ArrOfInt *lines_to_read) const
++{
++  assert(debut==0);
++  //assert(n==-1);
++  assert(lines_to_read==NULL);
++ 
++  if (fld.name_=="SOMMETS")
++    {
++      //    cerr<<"load sommets "<<endl;
++      MEDCoupling::MEDCouplingUMesh * mesh=  MEDCoupling::ReadUMeshFromFile(fld.filename_.getString(),fld.geometry_.getString());
++      const  MEDCoupling::DataArrayDouble* coords=mesh->getCoords();
++      data->resize(fld.size_,fld.nb_comp_);
++      for (int i=0;i<fld.size_;i++)
++      for (int j=0;j<fld.nb_comp_;j++)
++        {
++          (*data)(i,j)=coords->getIJ(i,j);
++        }
++      mesh->decrRef();
++      
++    }
++  else if (fld.name_=="ELEMENTS")
++    {
++      // cerr<<"load elements "<<endl;
++      Nom type_elem=get_geometry(fld.timestep_,fld.geometry_).elem_type_;
++      LataDB::Element type =LataDB::element_type_from_string(type_elem);
++      ArrOfInt filter=renum_conn(type);
++      MEDCoupling::MEDCouplingUMesh * mesh=  MEDCoupling::ReadUMeshFromFile(fld.filename_.getString(),fld.geometry_.getString());
++      const  MEDCoupling::DataArrayInt *elems = mesh->getNodalConnectivity(), *idx = mesh->getNodalConnectivityIndex();
++      const int *ptr_elems=elems->getConstPointer(), *ptr_idx = idx->getConstPointer();
++      data->resize(fld.size_,fld.nb_comp_);
++      int compt=0;
++      for (int i=0;i<fld.size_;i++)
++      {
++          compt++;
++          for (int j=0;j<fld.nb_comp_;j++)
++          {
++              int reel = j + ptr_idx[i] + 1 < ptr_idx[i + 1];
++              (*data)(i,filter.size_array()>0 ? filter[j] : j) = reel ? ptr_elems[compt] + 1 : 0;
++              compt += reel;
++          }
++      }
++      mesh->decrRef();
++    }
++  else if (fld.name_.debute_par("SOMMETS_IJK_"))
++    {
++      MEDCoupling::MEDCouplingMesh * mesh=  MEDCoupling::ReadMeshFromFile(fld.filename_.getString(),fld.geometry_.getString());
++      data->resize(fld.size_,fld.nb_comp_);
++      MEDCoupling::MEDCouplingCMesh* cmesh = dynamic_cast<MEDCoupling::MEDCouplingCMesh*>(mesh);
++      int dir;
++      if (fld.name_=="SOMMETS_IJK_I")
++          dir=0;
++      else  if (fld.name_=="SOMMETS_IJK_J")
++          dir=1;
++      else if (fld.name_=="SOMMETS_IJK_K")
++          dir=2;
++      else
++          abort();
++      const MEDCoupling::DataArrayDouble* coords=cmesh->getCoordsAt(dir);
++      for (int i=0;i<fld.size_;i++)
++      for (int j=0;j<fld.nb_comp_;j++)
++        {
++          (*data)(i,j)=coords->getIJ(i,j);
++        }
++      mesh->decrRef();
++    }
++  
++  else 
++    {
++      
++      data->resize(fld.size_,fld.nb_comp_);
++     
++      //  if (fld.timestep_==1) iter.first=1;
++      // double t;
++      Nom fieldname=fld.name_;
++      fieldname+="_";
++      fieldname+=fld.localisation_;
++      fieldname+="_";
++      fieldname+=fld.geometry_;
++      
++      int ok=0;
++   
++      vector<string> fields= MEDCoupling::GetAllFieldNamesOnMesh(fld.filename_.getString(),fld.geometry_.getString());
++      
++      for (int f=0;f<fields.size();f++)
++      {
++        if (fieldname==fields[f].c_str())
++          {
++            ok=1;
++            break;
++          }
++      }
++      if (ok==0)
++      {
++        fieldname=fld.name_;
++      }
++      vector<pair<pair<int,int>,double> > vtimes=MEDCoupling::GetAllFieldIterations(fld.filename_.getString(),fieldname.getString());
++
++      int it=fld.timestep_-1;
++      pair <int,int> iter(fld.timestep_-1,-1);
++      if (fld.timestep_==1) it=0;
++      //Cerr<<iter.first <<" 00 "<<vtimes.size()<<finl;
++    
++      iter.first=vtimes[it].first.first;
++      iter.second=vtimes[it].first.second;
++      // Cerr<<"iiii"<<iter.first<<" "<< it<<finl;
++      double t=MEDCoupling::GetTimeAttachedOnFieldIteration(fld.filename_.getString(),fieldname.getString(),iter.first,iter.second);
++        
++      
++      MEDCoupling::TypeOfField type;
++      if (fld.localisation_=="ELEM")
++      type=MEDCoupling::ON_CELLS;
++      else
++      {
++        type=MEDCoupling::ON_NODES;
++        assert(fld.localisation_=="SOM");
++      }
++      MEDCoupling::MEDFileField1TS *  field ;
++      
++      
++      field =  MEDCoupling::MEDFileField1TS::New(fld.filename_.getString(),fieldname.getString(),iter.first,iter.second);
++
++      const MEDCoupling::DataArrayDouble * values=field->getUndergroundDataArray();
++     
++      if (field->getNumberOfComponents()!=fld.nb_comp_)
++      {
++        cerr<<field->getNumberOfComponents()<<" test "<< endl;
++        Journal()<<fieldname<<" not loaded "<<endl;
++      }
++      else
++      {
++        assert(field->getNumberOfComponents()==fld.nb_comp_);
++        const double* ptr=values->getConstPointer();
++        for (int i=0;i<fld.size_;i++)
++          {
++            for (int j=0;j<fld.nb_comp_;j++)
++              {                
++                (*data)(i,j)=ptr[i*fld.nb_comp_+j];
++              }
++          }
++      }
++      field->decrRef();
++    }
++}
++#endif
+diff --git a/databases/readers/Lata/LataFilter.C b/databases/readers/Lata/LataFilter.C
+new file mode 100644
+index 0000000..5c4a764
+--- /dev/null
++++ b/databases/readers/Lata/LataFilter.C
+@@ -0,0 +1,1106 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <iostream>
++#include <fstream>
++#include <stdlib.h>
++#include <stdio.h>
++#include <stdarg.h>
++#include <math.h>
++#include <assert.h>
++#include <LataFilter.h>
++#include <list>
++#include <Static_Int_Lists.h>
++#include <Connectivite_som_elem.h>
++#include <LataDB.h>
++#include <Lata_tools.h>
++#include <Operator.h>
++#include <errno.h>
++#include <UserFields.h>
++#include <string.h>
++static const entier cache_info_level = 5;
++static const entier filter_info_level = 4;
++
++entier LataOptions::read_int_opt(const Nom & s)
++{
++  const char *ptr = strstr(s, "=");
++  if (!ptr) 
++    ptr = s;
++  errno = 0;
++  char *errorptr = 0;
++  entier x = strtol(ptr+1, &errorptr, 0 /* base 10 par defaut */);
++  if (errno || *errorptr != 0) {
++    Journal() << "LataOptions error reading int parameter: " << s << endl;
++    throw;
++  }
++  return x;
++}
++
++double LataOptions::read_float_opt(const Nom & s)
++{
++  const char *ptr = strstr(s, "=");
++  if (!ptr) 
++    ptr = s;
++  errno = 0;
++  char *errorptr = 0;
++  double x = strtod(ptr+1, &errorptr);
++  if (errno || *errorptr != 0) {
++    Journal() << "LataOptions error reading float parameter: " << s << endl;
++    throw;
++  }
++  return x;
++}
++
++Nom LataOptions::read_string_opt(const Nom & s)
++{
++  const char *ptr = strstr(s, "=");
++  if (!ptr) 
++    return s;
++  else
++    return Nom(ptr+1);
++}
++
++Noms extract_list(const Nom & n) 
++{
++  Noms liste;
++  if (n == "")
++    return liste;
++  const char *ptr = n;
++  Nom tmp("");
++  while (*ptr) {
++    if (*ptr == ',') {
++      liste.add(tmp);
++      tmp = "";
++    } else {
++      tmp += Nom(*ptr);
++    }
++  }
++  liste.add(tmp);
++  return liste;
++}
++
++void LataOptions::describe()
++{
++  cerr << "Data processing options (provided by the LataFilter module)" << endl;
++  cerr << " reconnect=tolerance : Find duplicate positions, and redefine connections to use" << endl;
++  cerr << "           always the same positions. tolerance is the maximum distance between" << endl;
++  cerr << "           positions that are considered equal." << endl;
++  cerr << "           Useful for results of parallel runs, where the domain could" << endl;
++  cerr << "           appear fragmented in as many subdomains as procs used." << endl;
++  cerr << "           This operator modifies the loaded domain, does not create a new domain." << endl;
++  cerr << " regularize=tolerance : Try to transform the irregular domain in a ijk domain." << endl;
++  cerr << "            tolerance is the maximum dx, dy or dz between positions that are" << endl;
++  cerr << "            considered to have the same x, y or z." << endl;
++  cerr << "            !Attention! regularize recalculates positions, connections, and fields" << endl;
++  cerr << "            Except in particularly simple cases, you cannot use a regularized domain" << endl;
++  cerr << "            for a field that has not been regularized the same way." << endl;
++  cerr << "            Create a new domain DOM -> DOM_IJK" << endl;
++  cerr << " regularize_polyedre=N : tells how to convert polyedre elements to VTK:" << endl;
++  cerr << "                         N=0 (default): any shape, handled as general VTK_CONVEX_POINT_SET" << endl;
++  cerr << "                         N=1: all elements are extruded in the Z direction (faster and nicer)" << endl;
++  cerr << " ijk_mesh_nb_parts=N : When loading an IJK mesh, automatically split the mesh into" << endl;
++  cerr << "            N blocks (N must be <= number of elements in the K direction, usefull in visit)" << endl;
++  cerr << " invalidate : together with regularize, create \"invalid positions\" and \"invalid connections\"" << endl;
++  cerr << "            components. Otherwise only set the values of the field to zeroes." << endl;
++  cerr << " extend_domain=n : When regularizing, add n nodes in each directions to have a layer" << endl;
++  cerr << "           of invalid positions and connections." << endl;
++  cerr << " dualmesh: Build and export the dual mesh" << endl;
++  cerr << "           (control volume for the velocities in VEF)" << endl;
++  cerr << "           data at faces become data at elements on the dual mesh." << endl;
++  cerr << "           Create a new domain DOM -> DOM_dual" << endl;
++  cerr << " facesmesh: Build and export the faces mesh" << endl;
++  cerr << "           (control volume for the velocities in VEF)" << endl;
++  cerr << "           data at faces become data at elements on the faces mesh." << endl;
++  cerr << "           Create a new domain DOM -> DOM_faces" << endl;
++
++  //cerr << " ncmesh:   Build and export a non-conforming mesh" << endl;
++  //cerr << "           (each mesh element has its proprietary nodes, elements are not topologically connected)" << endl;
++  //cerr << "           face dependent data become position dependent data on the new mesh." << endl;
++  //cerr << "           Create a new domain DOM -> DOM_nc" << endl;
++  cerr << " boundarymesh: Build new domains containing the boundaries only" << endl;
++  cerr << "            Create a new domain DOM -> DOM_Boundary" << endl;
++  //cerr << " clipbox=xmin,ymin,zmin,xmax,ymax,zmax : remove from all meshes all nodes," << endl;
++  //cerr << "           connections and faces outside of this box" << endl;
++  cerr << " load_virtual_elements: Read the VIRTUAL_ELEMENTS data in the input database, if available" << endl
++       << "           and merge nodes, elements and faces to each requested subdomain (using reconnect)" << endl;
++  cerr << "           Does not create a new domain, but modifies the loaded domain" << endl;
++  cerr << " ijk_virt_layer=N: load N layers of virtual elements if domain is ijk in lata file" << endl;
++  cerr << " reconnect_tolerance=: specify tolerance for all reconnect operations" << endl;
++  cerr << "           (reconnection is applied with load_virtual_elements)" << endl;
++  cerr << " user_fields: activate the User_Fields module (WARN: this module is often application specific," << endl;
++  cerr << "           it will fail if some requiered domains/fields are missing in the input database)" << endl;
++  cerr << " export_fields_at_faces: tells to export fields located at faces" << endl;
++  cerr << endl;
++  user_fields_options_.print_help_option();
++}
++
++entier LataOptions::parse_option(const Nom & s)
++{
++  if (s.debute_par("verbosity=")) {
++    entier level = read_int_opt(s);
++    set_Journal_level(level);
++  } else if (s.debute_par("regularize=")) {
++    regularize = true;
++    regularize_tolerance = read_float_opt(s);
++  } else if (s.debute_par("regularize_polyedre=")) {
++    regularize_polyedre = read_int_opt(s);
++  } else if (s.debute_par("extend_domain=")) {
++    extend_domain = read_int_opt(s);
++  } else if (s == "invalidate") {
++    invalidate = true;
++  } else if (s.debute_par("reconnect=")) {
++    reconnect = true;
++    reconnect_tolerance = read_float_opt(s);   
++  } else if (s.debute_par("reconnect_tolerance=")) {
++    reconnect_tolerance = read_float_opt(s);   
++  } else if (s == "dualmesh") {
++    dual_mesh = true;
++  } else if (s == "nodualmesh") {
++    dual_mesh = false;
++  } else if (s == "ncmesh") {
++    nc_mesh = true;
++  } else if (s == "facesmesh") {
++    faces_mesh = true;
++  } else if (s == "nofacesmesh") {
++    faces_mesh = false;
++  } else if (s == "boundarymesh") {
++    boundary_mesh = true;
++  } else if (s.debute_par("clipbox=")) {
++    Noms list = extract_list(((const char*)s)+8);
++    if (list.size() != 6) {
++      Journal() << "Error : clipbox parameters expects 6 values" << endl;
++      throw;
++    }
++    for (entier i = 0; i < 3; i++) {
++      clipbox_min[i] = read_float_opt(list[i]);
++      clipbox_max[i] = read_float_opt(list[i+3]);
++    }
++  } else if (s == "load_virtual_elements") {
++    load_virtual_elements = true;
++  } else if (s == "user_fields") {
++    user_fields_ = true;
++    Journal() << "Option: User_fields ON" << endl;
++  } else if (s.debute_par("ijk_mesh_nb_parts")) {
++    ijk_mesh_nb_parts_ = read_int_opt(s);
++  } else if (s == "export_fields_at_faces") {
++    export_fields_at_faces_ = 1;
++  } else if (s.debute_par("ijk_virt_layer=")) {
++    ijk_virt_layer = read_int_opt(s);
++  } else
++    return user_fields_options_.parse_option(s);;
++  return 1;
++}
++
++void LataFilterCache::set_cache_properties(entier clear_on_tstep_change, BigEntier mem_limit)
++{ 
++  clear_cache_on_tstep_change_ = clear_on_tstep_change;
++  cache_memory_limit_ = mem_limit;
++}
++
++// Description: if an entry with "id" tag and timestep exists in the cache,
++//  returns the entry, otherwise returns a reference to an empty DERIV that
++//  is stored in the cache and stores the associated "id" and timestep.
++//  The entry is locked and given a new last_access_time_ to show that it has
++//  been used recently.
++//  The entry must be released by release_item() when we are finished working
++//  with it.
++LataDeriv<LataObject> & LataFilterCache::get_item_(const Nom & id, entier tstep)
++{
++  entier i;
++  const entier n = data_.size();
++  for (i = 0; i < n; i++) {
++    const DataCacheItem & item = data_[i];
++    if (item.id_ == id && item.tstep_ == tstep)
++      break;
++  }
++  if (i == n) {
++    // Look for an empty slot:
++    for (i = 0; i < n; i++)
++      if (data_[i].id_ == "??")
++        break;
++    // No empty slot: create a new slot:
++    if (i == n)
++      data_.add();
++    DataCacheItem & item = data_[i];
++    item.id_ = id;
++    item.tstep_ = tstep;
++    item.lock_ = 0;
++    Journal(cache_info_level) << "LataFilterCache<C>::get " << id << " (new cache entry " << i << ")." << endl;
++  } else {
++    Journal(cache_info_level) << "LataFilterCache<C>::get " << id << " (existing cache entry " << i << ")." << endl;
++  }
++  // Mark item and lock it:
++  DataCacheItem & item = data_[i];
++  item.last_access_time_ = cache_data_access_count_++;
++  item.lock_++;
++  return item.item_;
++}
++
++
++// Description: tells that if needed the item can be deleted from cache
++//  (there is no reference to it anymore outside of the cache).
++//  We update the memory size of this item here.
++void LataFilterCache::release_item(const Nom & id)
++{
++  Journal(cache_info_level) << "LataFilterCache::release_item " << id << endl;
++  const entier n = data_.size();
++  entier i;
++  for (i = 0; i < n; i++) {
++    const DataCacheItem & item = data_[i];
++    if (item.id_ == id)
++      break;
++  }
++  if (i == n) {
++    Journal() << "LataFilterCache::release_item internal error: unknown item " << id << endl;
++    throw;
++  }
++  if (data_[i].lock_ <= 0) {
++    Journal() << "LataFilterCache::release_item internal error: item is already unlocked" << id << endl;
++    throw;
++  }
++  data_[i].last_access_time_ = cache_data_access_count_++;
++  data_[i].lock_--;
++  if (data_[i].item_.non_nul())
++    data_[i].memory_size_ = data_[i].item_.valeur().compute_memory_size();
++  else
++    data_[i].memory_size_ = 0;
++}
++
++// Description: removes from the cache the oldest items until the total
++//  memory used by the cache is below max_mem_size (in bytes), and
++//  if tstep_to_keep > 0, also removes all timesteps except 0 and tstep_to_keep
++void LataFilterCache::cleanup_cache(entier tstep_to_keep)
++{
++  if (clear_cache_on_tstep_change_ && tstep_to_keep > 0) {
++    Journal(cache_info_level) << "LataFilterCache::clear_cache_tsteps except 0 and " << tstep_to_keep << endl;
++    const entier n = data_.size();
++    for (entier i = 0; i < n; i++) {
++      DataCacheItem & item = data_[i];
++      if (item.id_ != "??") {
++        if (item.tstep_ == 0 || item.tstep_ == tstep_to_keep) {
++          Journal(cache_info_level+1) << " item " << item.id_ << " timestep " << item.tstep_ << " kept" << endl;
++        } else if (item.lock_) {
++          Journal(cache_info_level+1) << " item " << item.id_ << " locked" << endl;
++        } else {
++          Journal(cache_info_level) << " deleting item " << item.id_ << " " << item.tstep_ << endl;
++          item.item_.reset();
++          item.id_ = "??";
++          item.tstep_ = -1;
++        }
++      }
++    }
++  }
++  if (cache_memory_limit_ >= 0) {
++    Journal(cache_info_level) << "LataFilterCache::clear_cache_memory " << cache_memory_limit_ << endl;
++    do {
++      const entier n = data_.size();
++      // Scan cached data, looking for the oldest item and summing up memory
++      BigEntier total_memsize = 0;
++      entier oldest = -1;
++      BigEntier oldest_time = cache_data_access_count_;
++      for (entier i = 0; i < n; i++) {
++        const DataCacheItem & item = data_[i];
++        if (item.id_ != "??") {
++          total_memsize += item.memory_size_;
++          if (!item.lock_ && item.last_access_time_ < oldest_time) {
++            oldest_time = item.last_access_time_;
++            oldest = i;
++          }
++        }
++      }
++      if (oldest < 0 || total_memsize < cache_memory_limit_) 
++        break;
++      
++      DataCacheItem & item = data_[oldest];
++      Journal(cache_info_level) << " deleting item " << item.id_ << " " << item.tstep_ << endl;
++      item.item_.reset();
++      item.id_ = "??";
++      item.tstep_ = -1;
++    } while(1);
++  }
++}
++
++// Description: Cleanup everything, associate the lata_db and fills metadata information.
++void LataFilter::initialize(const LataOptions & opt, const LataDB & lata_db)
++{
++  opt_ = opt;
++  data_cache_.reset();
++  lataDB__ = &lata_db;
++  if (opt_.user_fields_) {
++    user_fields_.instancie(UserFields);
++    user_fields_.valeur().set_options(opt_.user_fields_options_);
++  }
++
++  get_all_metadata(geoms_metadata_, fields_metadata_);
++}
++
++void LataFilter::set_cache_properties(BigEntier max_memory, const entier keep_all_timesteps)
++{
++  data_cache_.set_cache_properties(!keep_all_timesteps, max_memory);
++}
++
++// Description: Return the number of timesteps in the database
++//   (=number of physical timesteps + one containing global definitions at timestep 0)
++entier LataFilter::get_nb_timesteps() const
++{
++  return lataDB().nb_timesteps();
++}
++
++// Description: Return the physical time for this timestep.
++//  returns -1.0 for timestep 0 (global definitions)
++double LataFilter::get_timestep(entier i) const
++{
++  if (i == 0)
++    return -1.0;
++  else
++    return lataDB().get_time(i);
++}
++
++static void add_fields_to_metadata_list(const LataDB & lataDB, 
++                                        const Nom & lata_geom, 
++                                        const Nom & dest_geom, 
++                                        const Nom & options,
++                                        entier dim,
++                                        LataVector<LataFieldMetaData> & fields_data,
++                                        const Motcle & source,
++                                        const Nom & source_domain)
++{
++  if (lataDB.nb_timesteps()<2) return;
++  // Query for existing fields in the latadb :
++  Field_UNames lata_fields = lataDB.field_unames(1, lata_geom, "*", LataDB::FIRST_AND_CURRENT);
++  const entier nb_fields = lata_fields.size();
++  for (entier i_field = 0; i_field < nb_fields; i_field++) {
++    const LataDBField & lata_field = lataDB.get_field(1, lata_fields[i_field], LataDB::FIRST_AND_CURRENT);
++    LataField_base::Elem_som loc = LataField_base::localisation_from_string(lata_field.localisation_);
++
++    // Hidden special fields
++    if (Motcle(lata_field.name_) == "INVALID_CONNECTIONS")
++      continue;
++   if (Motcle(lata_field.name_) == "ELEMENTS")
++      continue;
++   if (Motcle(lata_field.name_) == "FACES")
++      continue;
++   if (Motcle(lata_field.name_) == "ELEM_FACES")
++     continue;
++    LataFieldMetaData data;
++    data.name_ = lata_field.name_;
++    data.geometry_name_ = dest_geom;
++    data.component_names_ = lata_field.component_names_;
++    data.nb_components_ = lata_field.nb_comp_;
++    data.source_localisation_ = lata_field.localisation_;
++
++    if (options.find("to_vector")>=0) {
++      data.is_vector_ = 1;
++      data.nb_components_ = dim;
++    } else 
++      data.is_vector_ = (lata_field.nature_ == LataDBField::VECTOR);
++
++    if (options.find("to_elem")>=0)
++      data.localisation_ = LataField_base::ELEM;
++    else if (options.find("to_som")>=0)
++      data.localisation_ = LataField_base::SOM;
++    else if (options.find("to_faces")>=0)
++      data.localisation_ = LataField_base::FACES;
++    else
++      data.localisation_ = loc;
++
++    data.source_ = source;
++    data.uname_ = Field_UName(data.geometry_name_, 
++                              data.name_, 
++                              LataField_base::localisation_to_string(data.localisation_));
++    data.source_field_ = Field_UName(source_domain,
++                                     data.name_,
++                                     lata_fields[i_field].get_localisation());
++
++    if ((loc == LataField_base::ELEM && options.find("from_elem")>=0)
++        || (loc == LataField_base::SOM && options.find("from_som")>=0)
++        || (loc == LataField_base::FACES && options.find("from_faces")>=0)) {
++      Journal(filter_info_level) << " register field metadata: " << data.uname_ << endl;
++      fields_data.add(data);
++    }
++  }
++}
++
++// Process the content of the source LataDB structure and builds the metadata for
++//  all geometries and fields that the filter can export (depending on options,
++//  for example, provide dual mesh geometry and fields only if dualmesh option is on).
++void LataFilter::get_all_metadata(LataVector<LataGeometryMetaData> & geoms_data, LataVector<LataFieldMetaData> & fields_data)
++{
++  geoms_data.reset();
++  fields_data.reset();
++  entier current_tstep = 1;
++  // If no real timestep, just check timestep 0
++  if (lataDB().nb_timesteps() < 2)
++    current_tstep = 0;
++  Noms lata_geoms_names = lataDB().geometry_names(current_tstep, LataDB::FIRST_AND_CURRENT);
++  const entier nb_geoms = lata_geoms_names.size();
++  for (entier i_geom = 0; i_geom < nb_geoms; i_geom++) {
++    // Name of the current geometry (from lataDB)
++    const Nom & lata_geom_name = lata_geoms_names[i_geom];
++    const LataDBGeometry & lata_geom = lataDB().get_geometry(current_tstep, lata_geom_name, LataDB::FIRST_AND_CURRENT);
++    // Query properties from LataDB:
++    // Is it a dynamic mesh ?
++    const entier dynamic = lata_geom.timestep_ > 0;
++    // Element type ?
++    Domain::Element element_type = Domain::element_type_from_string(lata_geom.elem_type_);
++    // Query for dimension
++    const entier domain_already_ijk = lataDB().field_exists(current_tstep, lata_geom_name, "SOMMETS_IJK_I", LataDB::FIRST_AND_CURRENT);
++
++    // Do we have faces ?
++    const entier have_faces = 
++      domain_already_ijk ||
++      (lataDB().field_exists(current_tstep, lata_geom_name, "FACES", LataDB::FIRST_AND_CURRENT)
++       && lataDB().field_exists(current_tstep, lata_geom_name, "ELEM_FACES", LataDB::FIRST_AND_CURRENT));
++
++    entier dim = 1;
++    // Query for number of blocks in the lata file:
++    entier nblocks = 1;
++    if (domain_already_ijk) {
++      if (lataDB().field_exists(current_tstep, lata_geom_name, "SOMMETS_IJK_K", LataDB::FIRST_AND_CURRENT))
++        dim = 3;
++      else
++        dim = 2;
++      nblocks = opt_.ijk_mesh_nb_parts_;
++      Nom nom_sommets;
++      if (dim == 2)
++        nom_sommets = "SOMMETS_IJK_J";
++      else
++        nom_sommets = "SOMMETS_IJK_K";
++      const LataDBField & coord = lataDB().get_field(current_tstep, lata_geom_name, nom_sommets, "", LataDB::FIRST_AND_CURRENT);
++      // Nombre d'elements dans la direction du decoupage parallele:
++      const entier nelem = coord.size_ - 1;
++      // Si les tranches sont trop petites diminuer le nombre de blocs
++      if (nblocks > (nelem + 3) / 4)
++        nblocks = (nelem + 3) / 4;
++    } else {
++      dim = lataDB().get_field(current_tstep, lata_geom_name, "SOMMETS", "*", LataDB::FIRST_AND_CURRENT).nb_comp_;
++      if (lataDB().field_exists(current_tstep, lata_geom_name, "JOINTS_SOMMETS", LataDB::FIRST_AND_CURRENT))
++        nblocks = lataDB().get_field(current_tstep, lata_geom_name, "JOINTS_SOMMETS", "*", LataDB::FIRST_AND_CURRENT).size_;
++    }
++
++    // Initialize data common to all domains:
++    LataGeometryMetaData data;
++    data.dynamic_ = dynamic;
++    data.dimension_ = dim;
++    data.element_type_ = element_type;
++    data.is_ijk_=domain_already_ijk;
++     
++    // If we reconnect all subdomains, always load all of them:
++    if (!opt_.reconnect)
++      data.nblocks_ = nblocks;
++    else
++      data.nblocks_ = 1;
++
++    data.internal_name_ = lata_geom_name;
++    data.displayed_name_ = lata_geom_name;
++    
++    Nom separ("boundaries_");
++    int m=data.displayed_name_.find(separ);
++    if (m>0)
++      {
++      const Nom& name= data.displayed_name_;
++      // on remplace boundaries_ par boundaries/
++      const char* jj =name;
++      Nom disp(name);
++      disp.prefix(jj+m-1);
++      // GF le nom du domaine existe t il siuoi on a peut etre postraite sur un bord
++      if  (lata_geoms_names.rang(disp)>-1)
++        {
++          Nom bord(jj+m+separ.longueur()-1);
++          disp+=Nom("_boundaries/");
++          disp+=bord;
++          data.displayed_name_=disp;
++        }
++      }
++    //   cerr<< data.displayed_name_<<endl;
++    data.source_ = "latadb";
++    Journal(filter_info_level) << " metadata: adding geometry " << lata_geom_name << " displayed name=" << data.displayed_name_ << endl;
++    geoms_data.add(data);
++    // Add fields at som and elem:
++    add_fields_to_metadata_list(lataDB(), lata_geom_name, data.internal_name_,
++                                "from_elem,from_som,from_faces", dim, fields_data,
++                                "latadb",
++                                "??");
++    // It is regularizable ?
++    entier regularizable = (((element_type == Domain::quadri)&&(data.dimension_==2)) || ((element_type == Domain::hexa)&&(data.dimension_==3)))
++      && (lata_geom.elem_type_ != "HEXAEDRE_AXI") && (lata_geom.elem_type_ != "RECTANGLE_AXI");
++    Journal(filter_info_level) << " metadata: geometry " << lata_geom_name << " element type says regularizable=" << regularizable << endl;
++    if (regularizable && ((opt_.regularize_tolerance < 0) || (!opt_.regularize))) {
++      regularizable = 0;
++      Journal(filter_info_level) << " regularize option not set: don't build ijk domain" << endl;
++    }
++    if (regularizable && domain_already_ijk) {
++      regularizable = 0;
++      Journal(filter_info_level) << " domain is already IJK: do not regularize" << endl;
++    }
++
++    // opt_.regularize == 2 means: provide ijk only if faces are present
++    if (regularizable && opt_.regularize == 2) {
++      if (!have_faces) {
++        Journal(filter_info_level) << " regularize option==2 and no faces => do not regularize" << endl;
++        regularizable = 0;
++      }
++    }
++    if (regularizable) {
++      data.internal_name_ = lata_geom_name;
++      data.internal_name_ += "_IJK";
++      data.is_ijk_=1;
++      data.displayed_name_ = lata_geom_name;
++      data.source_ = "operator_ijk";
++      data.source_domain_ = lata_geom_name;
++      geoms_data.add(data);
++      Journal(filter_info_level) << " metadata: adding geometry " << data.internal_name_ << " displayed name=" << data.displayed_name_ << endl;
++      // Add fields at som and elem:
++      add_fields_to_metadata_list(lataDB(), lata_geom_name, data.internal_name_,
++                                  "from_elem,from_som,from_faces", dim, fields_data,
++                                  "operator_ijk",
++                                  data.source_domain_);
++    }
++
++    // Provide dual mesh
++    if (opt_.dual_mesh && have_faces) {
++      data.internal_name_ = lata_geom_name;
++      
++      // If it's quadri or hexa, we need the regular mesh
++      data.source_domain_ = data.internal_name_;
++      if (regularizable) {
++        data.internal_name_ += "_IJK";
++        data.source_domain_ += "_IJK";
++      data.is_ijk_=1;
++      }
++      data.internal_name_ += "_dual";
++      data.displayed_name_ += "_dual";
++
++      data.source_ = "operator_dual";
++      geoms_data.add(data);
++      Journal(filter_info_level) << " metadata: adding geometry " << data.internal_name_ << " displayed name=" << data.displayed_name_ << endl;
++      // Add fields at faces, localisation will be at elements,
++      //  forced to vector type if vdf:
++      Nom options("from_faces,to_elem");
++      if (regularizable)
++        options += ",to_vector";
++      add_fields_to_metadata_list(lataDB(), lata_geom_name, data.internal_name_,
++                                  options, dim, fields_data,
++                                  "operator_dual",
++                                  data.source_domain_);      
++    }
++
++    // Provide nc mesh if possible
++    if (opt_.nc_mesh && have_faces && !regularizable /* doesn't work for vdf */) {
++      data.internal_name_ = lata_geom_name;
++      data.internal_name_ += "_nc";
++      data.displayed_name_ = data.internal_name_;
++      data.source_ = "operator_nc";
++      data.source_domain_ = lata_geom_name;
++      geoms_data.add(data);
++      Journal(filter_info_level) << " metadata: adding geometry " << data.internal_name_ << " displayed name=" << data.displayed_name_ << endl;
++      // Add fields at faces, localisation will be at nodes
++      Nom options("from_faces,to_som");
++      add_fields_to_metadata_list(lataDB(), lata_geom_name, data.internal_name_,
++                                  options, dim, fields_data,
++                                  "operator_nc",
++                                  data.source_domain_);
++    }
++    // Provide faces mesh if possible
++    if (opt_.faces_mesh && have_faces && !regularizable /* doesn't work for vdf */ &&  !(domain_already_ijk) ) {
++   
++      data.internal_name_ = lata_geom_name;
++      data.internal_name_ += "_centerfaces";
++      data.displayed_name_ = data.internal_name_;
++      data.source_ = "operator_faces";
++      data.source_domain_ = lata_geom_name;
++      if (data.element_type_ == Domain::triangle)
++        data.element_type_=Domain::line;
++      else if ( data.element_type_ == Domain::tetra)
++        data.element_type_=Domain::triangle;
++
++      geoms_data.add(data);
++      Journal(filter_info_level) << " metadata: adding geometry " << data.internal_name_ << " displayed name=" << data.displayed_name_ << endl;
++      // Add fields at faces, localisation will be at nodes
++      Nom options("from_faces,to_elem");
++      add_fields_to_metadata_list(lataDB(), lata_geom_name, data.internal_name_,
++                                  options, dim, fields_data,
++                                  "operator_faces",
++                                  data.source_domain_);
++    }
++    // Provide boundary mesh
++    if (opt_.boundary_mesh && (element_type == Domain::hexa || element_type == Domain::tetra)) {
++      data.internal_name_ = lata_geom_name;
++      data.internal_name_ += "_Boundary";
++      data.displayed_name_ = data.internal_name_;
++      data.source_ = "operator_boundary";
++      data.source_domain_ = lata_geom_name;
++      geoms_data.add(data);
++      Journal(filter_info_level) << " metadata: adding geometry " << data.internal_name_ << " displayed name=" << data.displayed_name_ << endl;
++      Nom options("from_elem,from_som");
++      add_fields_to_metadata_list(lataDB(), lata_geom_name, data.internal_name_,
++                                  options, dim, fields_data,
++                                  "operator_boundary",
++                                  data.source_domain_);
++      options = "from_faces,to_elem";
++      add_fields_to_metadata_list(lataDB(), lata_geom_name, data.internal_name_,
++                                  options, dim, fields_data,
++                                  "operator_boundary",
++                                  data.source_domain_);
++    }
++  }
++
++  if (user_fields_.non_nul())
++    user_fields_.valeur().new_fields_metadata(*this, fields_data);
++}
++
++// Description: Return a list of domain names available from get_geometry_metadata()
++//  and that we want to show to the user.
++//  This includes the domains loaded from the lata file plus new constructed domains
++//  (nc_mesh, dual_mesh, boundary_mesh, etc) if requested in options and if available
++//  (depending if requiered data (eg faces, ...)
++Noms LataFilter::get_exportable_geometry_names() const
++{
++  Noms names;
++  entier i;
++  for (i = 0; i < geoms_metadata_.size(); i++)
++    names.add(geoms_metadata_[i].internal_name_);
++
++  // If an IJK domain is here, don't show the original domain:
++  Noms names2;
++  for (i = 0; i < names.size(); i++) {
++    Nom n(names[i]);
++    n += "_IJK";
++    if (names.rang(n) < 0)
++      names2.add(names[i]);
++  }
++  return names2;
++}
++
++// Description: the same, with field names...
++//  If geometry=="*", returns all fields
++//  Currently, doesn't show fields located at faces...
++Field_UNames LataFilter::get_exportable_field_unames(const char * geometry) const
++{
++  Field_UNames unames;
++  Motcle geom(geometry);
++  for (entier i = 0; i < fields_metadata_.size(); i++)
++    if (geom == fields_metadata_[i].geometry_name_ || geom == "*") 
++      // Do not show faces located fields to the user...
++      if (fields_metadata_[i].localisation_ != LataField_base::FACES || opt_.export_fields_at_faces_)
++        unames.add(fields_metadata_[i].uname_);
++
++  return unames;
++}
++
++// Description: fill "data" for the requested "geometry". "geometry" must be a name
++//  returned by get_exportable_geometry_names()
++const LataGeometryMetaData & LataFilter::get_geometry_metadata(const char * geometry) const
++{
++  Motcle geom(geometry);
++  for (entier i = 0; i < geoms_metadata_.size(); i++)
++    if (geom == geoms_metadata_[i].internal_name_)
++      return geoms_metadata_[i];
++
++  Journal() << "Error in LataFilter::get_geometry_metadata: unknown geometry " << geometry << endl;
++  throw LataError(LataError::INVALID_DOMAIN,"unknown geometry");
++  return geoms_metadata_[0];
++}
++
++// Description: fill "data" for the requested "geometry/field". "geometry"  and "field" must be names
++//  returned by get_exportable_geometry_names() and get_exportable_field_names()
++const LataFieldMetaData & LataFilter::get_field_metadata(const Field_UName & uname) const
++{
++  for (entier i = 0; i < fields_metadata_.size(); i++)
++    if (fields_metadata_[i].uname_ == uname)
++      return fields_metadata_[i];
++  
++  Journal() << "Error in LataFilter::get_field_metadata: unknown field " << uname << endl;
++  throw LataError(LataError::INVALID_COMPONENT,"unknown field");
++  return fields_metadata_[0];
++}
++
++// Description: 
++//  Returns a reference to the requested geometry.
++//  If the geometry is not found at the requested timestep, it
++//  is seached in the first timestep.
++//  If the geometry does not exist in the cache, all needed data is loaded
++//   and the geometry is allocated and built in the internal cache.
++//  The reference is valid until the user calls release_geometry()
++//  The user MUST call release_geometry() to allow the data to be
++//   removed from the data cache.
++const Domain & LataFilter::get_geometry(const Domain_Id & id)
++{
++  Journal(filter_info_level) << "LataFilter::get_geometry " 
++                             << id.name_ << " time=" << id.timestep_ 
++                             << " bloc=" << id.block_ << endl;
++  data_cache_.cleanup_cache(id.timestep_);
++
++  Domain_Id requested_id(id);
++  // Get the real timestep where this domain is stored:
++  const LataGeometryMetaData & geom_metadata = get_geometry_metadata(id.name_);
++  if (geom_metadata.dynamic_) 
++    requested_id.timestep_ = id.timestep_;
++  else
++    requested_id.timestep_ = 0;
++
++  LataDeriv<Domain> & dom_ptr = get_cached_domain(requested_id);
++  if (!dom_ptr.non_nul()) {
++    if (geom_metadata.source_ == "latadb") {
++      // Request for a native domain : load it from lataDB
++      // If reconnect and loading all subdomains, go ! Don't store the operator in cache since it's
++      //  not required to process fields.
++      
++      // Is it a structured or unstructured mesh ?
++      if (lataDB().field_exists(requested_id.timestep_, requested_id.name_, "SOMMETS")) 
++        {
++          DomainUnstructured & dom = dom_ptr.instancie(DomainUnstructured);
++      
++          if (opt_.reconnect) {
++            // Bloc demande, peut etre le bloc 0 ou le bloc -1:
++            const entier req_block = requested_id.block_;
++            if (requested_id.block_ > 0) {
++              Cerr << "Error: requesting block " << requested_id.block_ << " with reconnect option" << endl;
++            throw;
++            }
++            requested_id.block_ = -1; // load all blocks
++            dom.fill_domain_from_lataDB(lataDB(), requested_id, 1 /* faces */, 0);
++            Reconnect::reconnect_geometry(dom, opt_.reconnect_tolerance);
++            dom.id_.block_ = req_block;
++          } else {
++            dom.fill_domain_from_lataDB(lataDB(), requested_id, 1 /* faces */, opt_.load_virtual_elements ? 1 : 0);
++            if (opt_.load_virtual_elements && dom.nb_virt_items(LataField_base::ELEM) > 0) {
++              Reconnect::reconnect_geometry(dom, opt_.reconnect_tolerance,
++                                            dom.nb_nodes() - dom.nb_virt_items(LataField_base::SOM));
++            }
++          }
++        }
++      else
++        {
++          // Structured ijk:
++          DomainIJK & dom = dom_ptr.instancie(DomainIJK);
++          if (opt_.reconnect || requested_id.block_ < 0) {
++            dom.fill_domain_from_lataDB(lataDB(), requested_id, 1 /* parallel splitting */, 
++                                        0 /* no virtual elements */);
++          } else {
++            const entier nparts = opt_.ijk_mesh_nb_parts_;
++            const entier virtual_size = opt_.load_virtual_elements ? opt_.ijk_virt_layer : 0;
++            dom.fill_domain_from_lataDB(lataDB(), requested_id, nparts /* parallel splitting */, 
++                                        virtual_size /* with virtual elements */);
++          }
++        }
++    } else if (geom_metadata.source_.debute_par("OPERATOR")) {
++      const Domain & src_domain = get_geometry(Domain_Id(geom_metadata.source_domain_, 
++                                                         requested_id.timestep_,
++                                                         requested_id.block_));
++      Operator & op = get_set_operator(requested_id);
++      op.build_geometry(src_domain, dom_ptr);
++      dom_ptr.valeur().id_ = requested_id;
++      release_cached_operator(requested_id);
++      release_geometry(src_domain);
++    } else {
++      Journal() << "Unknown source in geometry metadata " << geom_metadata.source_ << endl;
++      throw;
++    }
++  }
++
++  return dom_ptr.valeur();
++}
++
++Operator & LataFilter::get_set_operator(const Domain_Id & id)
++{
++  LataDeriv<Operator> & op_ptr  = get_cached_operator(id);
++  if (!op_ptr.non_nul()) {
++    // Operator not in the cache ? Build it:
++    if (id.name_.finit_par("_IJK")) {
++      OperatorRegularize & op = op_ptr.instancie(OperatorRegularize);
++      op.set_tolerance(opt_.regularize_tolerance);
++      op.set_extend_layer(opt_.extend_domain);
++    } else if (id.name_.finit_par("_dual")) {
++      op_ptr.instancie(OperatorDualMesh);
++    } else if (id.name_.finit_par("_Boundary")) {
++      op_ptr.instancie(OperatorBoundary);
++    } else if (id.name_.finit_par("_centerfaces")) {
++      op_ptr.instancie(OperatorFacesMesh);
++    } else {
++      Journal() << "Internal error in LataFilter::get_operator: forgot to implement operator choice for " << id.name_ << endl;
++      throw;
++    }
++  }
++  return op_ptr.valeur();
++}
++
++
++// Description: returns the requested field, computing it if it is not
++//  already in the cache. You MUST call release_field() on the returned field
++//  when you don't need it any more...
++//  See also class Field_Id
++const LataField_base & LataFilter::get_field(const Field_Id & id)
++{
++  Journal(filter_info_level) << "LataFilter::get_field " 
++                             << id.uname_ << " time=" << id.timestep_ 
++                             << " bloc=" << id.block_ << endl;
++
++  data_cache_.cleanup_cache(id.timestep_);
++
++  const LataFieldMetaData & field_metadata = get_field_metadata(id.uname_);
++
++  LataDeriv<LataField_base> & field_ptr = get_cached_field(id);
++  if (!field_ptr.non_nul()) {
++    if (field_metadata.source_ == "latadb") {
++      // Request for a native field : load it from lataDB
++      const Domain & dom = get_geometry(id);
++      dom.fill_field_from_lataDB(lataDB(), id, field_ptr);
++      release_geometry(dom);
++    } else if (field_metadata.source_.debute_par("OPERATOR")) {
++      const Field_Id src_id(field_metadata.source_field_,
++                            id.timestep_,
++                            id.block_);
++      const Domain & src_domain = get_geometry(src_id);
++      const LataField_base & src_field = get_field(src_id);
++      const Domain & dest_domain = get_geometry(id);
++      Operator & op = get_set_operator(dest_domain.id_);
++      op.build_field(src_domain, src_field, dest_domain, field_ptr);
++      field_ptr.valeur().id_ = Field_Id(field_metadata.uname_, src_field.id_.timestep_, src_field.id_.block_);
++      release_field(src_field);
++      release_geometry(src_domain);
++      release_geometry(dest_domain);
++      release_cached_operator(dest_domain.id_);
++    } else if (field_metadata.source_ == "user_fields") {
++      Field<FloatTab> & f = field_ptr.instancie(Field<FloatTab> );
++      f = user_fields_.valeur().get_field(id);
++      // Force field id to correct value:
++      f.id_ = id;
++      f.component_names_ = field_metadata.component_names_;
++      f.nature_ = field_metadata.is_vector_ ? LataDBField::VECTOR : LataDBField::SCALAR;
++      f.localisation_ = field_metadata.localisation_;
++    }
++  }
++
++  return field_ptr.valeur();
++}
++
++// Description: returns the requested float field, computing it if it is not
++//  already in the cache. You MUST call release_field() on the returned field
++//  when you don't need it any more...
++//  See also class Field_Id
++const FieldFloat & LataFilter::get_float_field(const Field_Id & id) 
++{
++  const LataField_base & field = get_field(id);
++  const FieldFloat * float_field_ptr = dynamic_cast<const FieldFloat*>(&field);
++  if (! float_field_ptr) { /*assert(! float_field_ptr);*/ throw LataError(LataError::INVALID_COMPONENT,"unknown field");}
++  const FieldFloat & fld = *float_field_ptr;
++  return fld;
++}
++void LataFilter::release_geometry(const Domain & dom)
++{
++  Journal(filter_info_level) << "LataFilter::release_geometry " 
++                             << dom.id_.name_ << " time=" << dom.id_.timestep_ 
++                             << " bloc=" << dom.id_.block_ << endl;
++  release_cached_domain(dom.id_);
++}
++
++void LataFilter::release_field(const LataField_base & field)
++{
++  Journal(filter_info_level) << "LataFilter::release_field " 
++                             << field.id_.uname_ << " time=" << field.id_.timestep_ 
++                             << " bloc=" << field.id_.block_ << endl;
++  release_cached_field(field.id_);
++}
++  
++void build_mangeld_domain_name(const Domain_Id & id, Nom & name)
++{
++  name = id.name_;
++  name += "_";
++  name += Nom(id.timestep_);
++  name += "_";
++  name += Nom(id.block_);
++  name.majuscule();
++}
++
++void build_mangeld_field_name(const Field_Id & id, Nom & name)
++{
++  name = id.uname_.build_string();
++  name += "_";
++  name += Nom(id.timestep_);
++  name += "_";
++  name += Nom(id.block_);
++  name.majuscule();
++}
++
++LataDeriv<LataField_base> & LataFilter::get_cached_field(const Field_Id& id)
++{
++  Nom n;
++  build_mangeld_field_name(id, n);
++  return data_cache_.get_item<LataDeriv<LataField_base> >(n, id.timestep_);
++}
++LataDeriv<Domain> &     LataFilter::get_cached_domain(const Domain_Id& id)
++{
++  Nom n;
++  build_mangeld_domain_name(id, n);
++  return data_cache_.get_item<LataDeriv<Domain> >(n, id.timestep_);
++}
++LataDeriv<Operator> &   LataFilter::get_cached_operator(const Domain_Id& id)
++{
++  Nom n;
++  build_mangeld_domain_name(id, n);
++  n += "_OP";
++  return data_cache_.get_item<LataDeriv<Operator> >(n, id.timestep_);  
++}
++void LataFilter::release_cached_domain(const Domain_Id& id)
++{
++  Nom n;
++  build_mangeld_domain_name(id, n);
++  data_cache_.release_item(n);
++}
++void LataFilter::release_cached_field(const Field_Id& id)
++{
++  Nom n;
++  build_mangeld_field_name(id, n);
++  data_cache_.release_item(n);
++}
++void LataFilter::release_cached_operator(const Domain_Id& id)
++{
++  Nom n;
++  build_mangeld_domain_name(id, n);
++  n += "_OP";
++  data_cache_.release_item(n);  
++}
++
++void LataOptions::extract_path_basename(const char * s, Nom & path_prefix, Nom & basename)
++{
++  int i;
++  for (i=(int)strlen(s)-1;i>=0;i--)
++    if ((s[i]==PATH_SEPARATOR) ||(s[i]=='\\'))
++      break;
++  path_prefix = "";
++  int j;
++  for (j = 0; j <= i; j++)
++    path_prefix += Nom(s[j]);
++  
++  // Parse basename : if extension given, remove it
++  int n = (int)strlen(s);
++  if (n > 5 && strcmp(s+n-5,".lata") == 0)
++    n -= 5;
++  basename = "";
++  for (j = i+1; j < n; j++)
++    basename += Nom(s[j]);
++  //  Journal(9)<<" prefix "<<path_prefix<< " "<<i<<endl;
++}
++
++LataOptions::LataOptions()
++{
++  dual_mesh = false;
++  faces_mesh=false;
++  nc_mesh = false;
++  boundary_mesh = false;
++  reconnect = false;
++  reconnect_tolerance = 1e-6;
++  regularize = false;
++  extend_domain = 0;
++  regularize_tolerance = 1e-6;
++  invalidate = false;
++  load_virtual_elements = false;
++  user_fields_ = false;
++  ijk_mesh_nb_parts_ = 1;
++  ijk_virt_layer = 1;
++  export_fields_at_faces_ = 0;
++  regularize_polyedre=0;
++}
++
++void build_geometry_(Operator & op, const Domain & src, LataDeriv<Domain> & dest)
++{
++  Journal() << "Error in an operator: build_geometry not coded for this Operator/Domain" << endl;
++  throw;
++}
++
++void build_field_(Operator & op, const Domain & src, const Domain & dest, 
++                  const LataField_base & srcf, LataField_base & destf)
++{
++  Journal() << "Error in an operator: build_field not coded for this Operator/Domain/Field" << endl;
++  throw;  
++}
++
++void LataDB_apply_input_filter(const LataDB & lata_db, LataDB & filtered_db, 
++                        const ArrOfInt & input_timesteps_filter,
++                        const Noms & input_domains_filter,
++                        const Noms & input_components_filter)
++{
++  ArrOfInt timesteps_filter(input_timesteps_filter);
++  Noms domains_filter(input_domains_filter);
++  Noms components_filter(input_components_filter);
++
++  // Build a list of all available geometries and components
++  Noms list_all_domains = lata_db.geometry_names(lata_db.nb_timesteps()-1, LataDB::FIRST_AND_CURRENT);
++  Noms list_all_fields;
++  {
++    Field_UNames fields = lata_db.field_unames(lata_db.nb_timesteps()-1, "*", "*", LataDB::FIRST_AND_CURRENT);
++    for (entier i = 0; i < fields.size(); i++) {
++      const Nom & n = fields[i].get_field_name();
++      if (list_all_fields.rang(n) < 0)
++        list_all_fields.add(n);
++    }
++  }
++
++  if (timesteps_filter.size_array() == 0) {
++    // Add all timesteps, timestep 0 is implicitely added.
++    entier n = lata_db.nb_timesteps();
++    timesteps_filter.resize_array(n-1);
++    for (entier i = 1; i < n; i++)
++      timesteps_filter[i-1] = i;
++    Journal(3) << " Exporting all " << n-1 << " timesteps" << endl;
++  } else if (timesteps_filter[0] < 0) {
++    timesteps_filter.resize_array(0);
++    Journal(3) << " Request timestep -1: Exporting only global time independent data" << endl;
++  }
++  if (domains_filter.size() == 0) {
++    // Add all geometries
++    domains_filter = list_all_domains;
++    Journal(3) << " Exporting all geometries" << endl;
++  } 
++  if (components_filter.size() == 0) {
++    // Add all fields of the selected geometries
++    components_filter = list_all_fields;
++    Journal(3) << " Exporting all fields:" << endl;
++  } else {
++    // Add all known geometry data fields
++    components_filter.add("SOMMETS");
++    components_filter.add("ELEMENTS");
++    components_filter.add("FACES");
++    components_filter.add("ELEM_FACES");
++    components_filter.add("JOINTS_SOMMETS");
++    components_filter.add("JOINTS_ELEMENTS");
++    components_filter.add("JOINTS_FACES");
++    components_filter.add("VIRTUAL_ELEMENTS");
++    // these are for ijk meshs:
++    components_filter.add("SOMMETS_IJK_I");
++    components_filter.add("SOMMETS_IJK_J");
++    components_filter.add("SOMMETS_IJK_K");
++    components_filter.add("INVALID_CONNECTIONS");
++  }
++  filtered_db.filter_db(lata_db,
++                        noms_to_motcles(domains_filter),
++                        noms_to_motcles(components_filter),
++                        timesteps_filter);
++}
+diff --git a/databases/readers/Lata/LataFilter.h b/databases/readers/Lata/LataFilter.h
+new file mode 100644
+index 0000000..77f24d9
+--- /dev/null
++++ b/databases/readers/Lata/LataFilter.h
+@@ -0,0 +1,261 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef LATA_H_INCLUDE
++#define LATA_H_INCLUDE
++
++#include <LataDB.h>
++#include <LataStructures.h>
++#include <UserFields.h>
++
++typedef Field<FloatTab> FieldFloat;
++
++// This file provides the LataFilter class: it is a dynamic mesh
++//  and field generator which is able to load data from a lata file,
++//  apply operators. Once computed, the data is kept in a data cache
++//  to speed up further access to the same data.
++
++// This class holds the LataFilter configuration (determines which 
++//   combination of operators should be applied to the data)
++class LataOptions 
++{
++public :
++  static void extract_path_basename(const char * s, Nom & path_prefix, Nom & basename);
++  static entier read_int_opt(const Nom & s);
++  static double read_float_opt(const Nom & s);
++  static Nom read_string_opt(const Nom & s);
++
++  Nom basename; // Name of the case. 
++  Nom path_prefix; // Path for the case.
++
++  // Generate de the following meshes and associated data, if the flag is set.
++  bool dual_mesh;
++  bool nc_mesh;
++  bool faces_mesh;
++  bool boundary_mesh;
++
++  bool   reconnect;  // Do we want to reconnect multiblock meshes
++  float  reconnect_tolerance;
++  int regularize_polyedre ; // if 1 Treate polyedre as poyledre extruder
++  int    regularize;    // Do we want to force regularize the domain ie convert the mesh to a structured ijk (not necessary except for dual-mesh vdf)
++                        // special value 2 means "regularize if faces present and vdf"
++  int    extend_domain; // Extend the regularized domaine by n layers of cells
++  float  regularize_tolerance;
++  bool   invalidate; // invalidate unused positions and connections;
++  bool   load_virtual_elements; // Do we want to extend the loaded mesh subblocks with a layer of virtual elements
++  bool   export_fields_at_faces_; // Should we show these fields in exportable fields
++  
++  // When loading ijk regular meshes, virtually create this number of blocks in the K direction:
++  int    ijk_mesh_nb_parts_;
++  // When loading ijk regular meshes, merge N layers of virtual elements (default=1)
++  int    ijk_virt_layer;
++
++  bool   user_fields_; //activate user fields ?
++
++  ArrOfDouble clipbox_min;
++  ArrOfDouble clipbox_max;
++
++  UserFields_options user_fields_options_;
++
++  LataOptions();
++  virtual entier parse_option(const Nom &);
++  virtual void describe();
++  virtual ~LataOptions() {};
++};
++
++class Operator : public LataObject
++{
++public:
++  virtual void build_field(const Domain & src_domain, const LataField_base & src_field, 
++                           const Domain & dest_domain, LataDeriv<LataField_base> & dest) = 0;
++  virtual void build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest) = 0;
++protected:
++};
++
++struct LataGeometryMetaData
++{
++  Nom internal_name_; // Internal full name (eg DOM_IJK)
++  Nom displayed_name_; // Short name showed to the user (DOM for DOM_IJK, ?? if the geometry should not be exported)
++  entier dynamic_; // Is the geometry changing at each timestep ?
++  entier dimension_; // spatial dimension of coordinates
++  Domain::Element element_type_;
++  entier nblocks_; // Number of sub_blocks in the geometry (parallel computation)
++  Motcle source_; // How to build this domain ("latadb", "operator_ijk", "operator_dual", "operator_boundary", "user_fields")
++  Nom source_domain_;
++  entier is_ijk_;
++};
++
++struct LataFieldMetaData
++{
++  Field_UName uname_;
++  Nom name_;
++  Nom geometry_name_;
++  Noms component_names_;
++  entier nb_components_;
++  entier is_vector_; // Yes => nb_components is equal to spatial dimension
++  LataField_base::Elem_som localisation_;
++  Nom source_localisation_; // Localisation of source field (for displayed name in visit)
++  Motcle source_; // How to build this field ("latadb", "operator_ijk", "operator_dual", "operator_boundary", "user_fields")
++  Field_UName source_field_;
++};
++
++class DataCacheItem
++{
++public:
++  DataCacheItem() : tstep_(-1), last_access_time_(0), lock_(0), memory_size_(0) {}
++  LataDeriv<LataObject> item_; // The cached item
++  Nom id_; // The id for this item
++  entier tstep_; // The timestep of the cached data (for cache cleanup)
++  BigEntier last_access_time_; // Last time this item has been accessed (for cache cleanup)
++  // Is the item locked ? => cannot be deleted by clear_cache()
++  // This is a counter: get_item increases, release_item dereases.
++  // (this is when we simultaneously need several items, we must lock them to be sure)
++  entier lock_; 
++  // The memory size is computed when the item is released
++  BigEntier memory_size_;
++};
++
++class LataFilterCache 
++{
++public:
++  LataFilterCache() : cache_data_access_count_(0),
++                      clear_cache_on_tstep_change_(1), cache_memory_limit_(-1) {};
++  void reset() { data_.reset(); cache_data_access_count_ = 0; }
++  void set_cache_properties(entier clear_on_tstep_change, BigEntier mem_limit);
++  template<class C> C & get_item(const Nom & id, entier tstep)
++  {
++    LataDeriv<LataObject> & obj = get_item_(id, tstep);
++    if (obj.non_nul())
++      return obj.refcast(C);
++    else
++      return obj.instancie(C);
++  }
++  void release_item(const Nom & id);
++  void remove_item(const Nom & id);
++  void cleanup_cache(entier tstep_to_keep);
++protected:
++  LataDeriv<LataObject> & get_item_(const Nom & id, entier tstep);
++  // Stored data (depends on caching strategy)
++  // data_ grows when needed. 
++  LataVector<DataCacheItem> data_;
++  BigEntier cache_data_access_count_;
++  // If nonzero, whenever we ask a timestep,
++  //  remove all cached data from other timesteps
++  entier clear_cache_on_tstep_change_;
++  // If before getting a new geometry or field, the data cache
++  //  uses more than the limit, remove old data until we are below.
++  // -1 means "no limit"
++  BigEntier cache_memory_limit_; // Limit in bytes
++};
++
++// Description: This is the MAIN class for the lata filter tool:
++//  It reads data from a lata database on disk (initialize), 
++//   and proposes several geometries and fields (get_exportable...) to the user.
++//  The user can get them with get_geometry and get_field.
++//  He must then call release_geometry and release_field to free the memory.
++//  The user can also get metadata information (available without loading all
++//   the data from disk) for geometries and fields and also timestep informations.
++//  Timestep 0 contains global geometry and field definitions, timestep 1..n
++//  are associated with each "TEMPS" entry in the lata file.
++//
++// LataFilter uses a data cache internally: it keeps fields and geometries after
++// the user calls release_xxx(). The cache is controlled by set_cache_properties()
++class LataFilter {
++public:
++  LataFilter() : lataDB__(0) {};
++  void initialize(const LataOptions & opt, const LataDB & db);
++  void set_cache_properties(BigEntier max_memory, const entier keep_all_timesteps);
++  Noms get_exportable_geometry_names() const;
++  const LataGeometryMetaData & get_geometry_metadata(const char * geometry) const;
++  LataVector<Field_UName> get_exportable_field_unames(const char * geometry) const;
++  const LataFieldMetaData & get_field_metadata(const Field_UName & uname) const;
++  entier get_nb_timesteps() const;
++  double get_timestep(entier i) const;
++
++  const Domain &     get_geometry(const Domain_Id &);  
++
++  void               release_geometry(const Domain &);
++  const LataField_base & get_field(const Field_Id &);
++  const FieldFloat & get_float_field(const Field_Id &) ;
++
++  void               release_field(const LataField_base &);
++
++  const LataDB & get_lataDB() const { return lataDB(); }
++
++  const LataOptions & get_options() const { return opt_; }
++protected:
++  Operator &              get_set_operator(const Domain_Id & id);
++  LataDeriv<LataField_base> & get_cached_field(const Field_Id&);
++  LataDeriv<Domain> &     get_cached_domain(const Domain_Id&);
++  LataDeriv<Operator> &   get_cached_operator(const Domain_Id&);
++  void release_cached_domain(const Domain_Id&);
++  void release_cached_field(const Field_Id&);
++  void release_cached_operator(const Domain_Id&);
++  const Domain & get_geom_field_(const Field_Id & id, LataRef<const LataField_base> & field_result);
++  void get_all_metadata(LataVector<LataGeometryMetaData> & geoms_data, LataVector<LataFieldMetaData> & fields_data);
++  // LataDB       & lataDB() { return lataDB__; }
++  const LataDB & lataDB() const { assert(lataDB__); return *lataDB__; }
++
++  // We store in the cache objects of type:
++  //  LataDeriv<Domain>
++  //  derived types of Operator
++  //  LataDeriv<LataField_base>
++  LataFilterCache data_cache_;
++
++  // LataV2 masterfile database 
++  const LataDB *lataDB__;
++  LataOptions opt_;
++  // Metadata information for all fields and geometries (built in initialize)
++  LataVector<LataGeometryMetaData> geoms_metadata_;
++  LataVector<LataFieldMetaData>    fields_metadata_;
++
++  LataDeriv<UserFields> user_fields_;
++};
++
++struct LataError
++{
++  enum ErrorCode { NEED_REGULAR, NO_FACES, WRONG_ELT_TYPE, INVALID_TSTEP, INVALID_COMPONENT, 
++                   INVALID_DOMAIN, OTHER};
++  LataError(ErrorCode code, const char * msg) : code_(code), msg_(msg) {};
++  ErrorCode code_;
++  const char *msg_;
++};
++
++struct InternalError
++{
++  InternalError(const char *msg) : msg_(msg) {};
++  const char *msg_;
++};
++
++void LataDB_apply_input_filter(const LataDB & lata_db, LataDB & filtered_db, 
++                               const ArrOfInt & input_timesteps_filter,
++                               const Noms & input_domains_filter,
++                               const Noms & input_components_filter);
++#endif
++
+diff --git a/databases/readers/Lata/LataJournal.h b/databases/readers/Lata/LataJournal.h
+new file mode 100644
+index 0000000..acc68e3
+--- /dev/null
++++ b/databases/readers/Lata/LataJournal.h
+@@ -0,0 +1,36 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef LataJournal_H
++#define LataJournal_H
++#include <iostream>
++#include <arch.h>
++std::ostream & Journal(entier level=0);
++void set_Journal_level(entier level);
++#endif
+diff --git a/databases/readers/Lata/LataStructures.C b/databases/readers/Lata/LataStructures.C
+new file mode 100644
+index 0000000..390d289
+--- /dev/null
++++ b/databases/readers/Lata/LataStructures.C
+@@ -0,0 +1,743 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <LataStructures.h>
++#include <LataDB.h>
++#include <stdlib.h>
++static const entier info_level = 4;
++
++// Description: returns the number of items of the given type
++entier Domain::nb_items(const LataField_base::Elem_som loc) const
++{
++  entier n = -1;
++  switch (loc) {
++  case LataField_base::SOM: n = nb_nodes(); break;
++  case LataField_base::ELEM: n = nb_elements(); break;
++  case LataField_base::FACES: n = nb_faces(); break;
++  default:
++    Journal() << "Invalid localisation " << (int) loc << " in Domain::nb_items" << endl;
++    throw;
++  }
++  return n;
++}
++
++// Description: returns the offset in the lata block on disk of the first
++//  item for this Domain.id_.block_ (parallel computation).
++//  (this value must be set with set_lata_block_offset)
++entier Domain::lata_block_offset(const LataField_base::Elem_som loc) const
++{
++  entier n = -1;
++  switch (loc) {
++  case LataField_base::SOM: n = decal_nodes_lata_; break;
++  case LataField_base::ELEM: n = decal_elements_lata_; break;
++  case LataField_base::FACES: n = decal_faces_lata_; break;
++  default:
++    Journal() << "Invalid localisation " << (int) loc << " in Domain::lata_block_offset" << endl;
++    throw;
++  }
++  if (n < 0) {
++    Journal() << "Error: lata_block_offset not set for localisation " << (int) loc << endl;
++    throw;
++  }
++  return n;
++}
++
++// Description: set the lata_block_offset (see lata_block_offset)
++void Domain::set_lata_block_offset(const LataField_base::Elem_som loc, entier n)
++{
++  switch (loc) {
++  case LataField_base::SOM: decal_nodes_lata_ = n; break;
++  case LataField_base::ELEM: decal_elements_lata_ = n; break;
++  case LataField_base::FACES: decal_faces_lata_ = n; break;
++  default:
++    Journal() << "Invalid localisation " << (int) loc << " in Domain::set_lata_block_offset" << endl;
++    throw;
++  }
++}
++
++template<class TabType>
++void DomainUnstructured::compute_cell_center_coordinates(TabType & coord, entier index_begin) const
++{
++  const entier dim = nodes_.dimension(1);
++  const entier nb_elem = elements_.dimension(0);
++  const entier nb_som_elem = elements_.dimension(1);
++  const double facteur = 1. / (double) nb_som_elem;
++  double tmp[3];
++  for (int i = 0; i < nb_elem; i++) {
++    int j, k;
++    tmp[0] = tmp[1] = tmp[2] = 0.;
++    for (j = 0; j < nb_som_elem; j++) {
++      int som = elements_(i, j);
++      for (k = 0; k < loop_max(dim, 3); k++) {
++        tmp[k] += nodes_(som, k);
++        break_loop(k, dim);
++      }
++    }
++    for (k = 0; k < loop_max(dim, 3); k++) {
++      coord(index_begin + i, k) = tmp[k] * facteur;
++      break_loop(k, dim);
++    }
++  }
++}
++
++template
++void DomainUnstructured::compute_cell_center_coordinates(FloatTab & coord, entier index_begin) const;
++template
++void DomainUnstructured::compute_cell_center_coordinates(DoubleTab & coord, entier index_begin) const;
++
++
++LataField_base::Elem_som LataField_base::localisation_from_string(const Motcle & loc)
++{
++  if (loc.debute_par("SOM"))
++    return SOM;
++  else if (loc.debute_par("ELEM"))
++    return ELEM;
++  else if (loc.debute_par("FACE"))
++    return FACES;
++  else
++    return UNKNOWN;
++}
++
++Nom LataField_base::localisation_to_string(const Elem_som loc)
++{
++  Nom n;
++  switch(loc) {
++  case SOM: n = "SOM"; break;
++  case ELEM: n = "ELEM"; break;
++  case FACES: n = "FACES"; break;
++  case UNKNOWN: n = "";
++  }
++  return n;
++}
++
++Motcle Domain::lata_element_name(Domain::Element type)
++{
++  switch(type) {
++  case point: return "POINT"; break;
++  case line: return "SEGMENT"; break;
++  case triangle: return "TRIANGLE"; break;
++  case quadri: return "QUADRANGLE"; break;
++  case tetra: return "TETRAEDRE"; break;
++  case hexa: return "HEXAEDRE"; break;
++  case prism6: return "PRISM6"; break;
++  case polyedre: return "POLYEDRE"; break;
++  case polygone: return "POLYGONE"; break;
++  default: return "UNSPECIFIED";
++  }
++  return "UNSPECIFIED";
++}
++
++Domain::Element Domain::element_type_from_string(const Motcle & type_elem)
++{
++  Element type;
++  if (type_elem == "HEXAEDRE")
++    type=hexa;
++  else if (type_elem == "HEXAEDRE_AXI")
++    type=hexa;
++  else if (type_elem == "HEXAEDRE_VEF")
++    type=hexa;
++  else if (type_elem == "QUADRANGLE")
++    type=quadri;
++  else if (type_elem == "QUADRANGLE_3D")
++    type=quadri;
++  else if (type_elem == "RECTANGLE")
++    type=quadri;
++  else if (type_elem == "RECTANGLE_2D_AXI")
++    type=quadri;
++  else if (type_elem == "RECTANGLE_AXI")
++    type=quadri;
++  else if (type_elem == "SEGMENT")
++    type=line;
++  else if (type_elem == "SEGMENT_2D")
++    type=line;
++  else if (type_elem == "TETRAEDRE")
++    type=tetra;
++  else if (type_elem == "TRIANGLE")
++    type=triangle;
++  else if (type_elem == "TRIANGLE_3D")
++    type=triangle;
++  else if (type_elem == "POINT")
++    type=point;
++  else if ((type_elem == "PRISM6")||(type_elem == "PRISME"))
++    type=prism6;
++  else if (type_elem.debute_par("POLYEDRE"))
++    type=polyedre;
++  else if (type_elem.debute_par("POLYGONE"))
++    type=polygone;
++  else {
++    Journal() << "Error in elem_type_from_string: unknown element type " << type_elem << endl;
++    throw;
++  }
++  return type;
++}
++
++Nom Domain::element_type_to_string(Element type)
++{
++  Nom n;
++  switch(type) {
++  case point:       n = "POINT"; break;
++  case line:        n = "SEGMENT"; break;
++  case triangle:    n = "TRIANGLE"; break;
++  case quadri:      n = "QUADRANGLE"; break;
++  case tetra:       n = "TETRAEDRE"; break;
++  case hexa:        n = "HEXAEDRE"; break;
++  case prism6:      n = "PRISM6"; break;
++  case polyedre:    n = "POLYEDRE_0"; break;
++  case polygone:    n = "POLYGONE"; break;
++  case unspecified: n = "UNKNOWN"; break;
++  }
++  return n;
++}
++
++// Description: read the specified geometry from the lataDB_ structure and put it in "dom".
++//  load_faces: flag, tells if we should read faces definitions in the lata file
++//  merge_virtual_elements: flag, if a "VIRTUAL_ELEMENTS" array is present in the lata file,
++//   merges these elements to the requested block.
++void DomainUnstructured::fill_domain_from_lataDB(const LataDB & lataDB,
++                                                 const Domain_Id & id,
++                                                 entier load_faces, 
++                                                 entier merge_virtual_elements) 
++{
++  operator=(DomainUnstructured()); // Reset all data.
++
++  id_ = id;
++  const LataDBGeometry & geom = lataDB.get_geometry(id.timestep_, id.name_);
++
++  // ********************************
++  // 1) Look for the sub-block items to read (parallel computation)
++  entier decal_nodes = 0;
++  entier decal_elements = 0;
++  entier decal_faces = 0;
++  entier nb_sommets = -1;
++  entier nbelements = -1;
++  entier nbfaces = -1;
++
++  entier domain_has_faces = load_faces && lataDB.field_exists(id.timestep_, id.name_, "FACES");
++  
++  // Tableau de 3 joints (SOM, ELEM et FACES)
++  LataVector<IntTab> joints;
++  entier nproc = 1;
++  for (entier i_item = 0; i_item < 3; i_item++) {
++    //    LataField_base::Elem_som loc = LataField_base::SOM;
++    Nom nom("JOINTS_SOMMETS");
++    Nom nom2("SOMMETS");
++    if (i_item == 1) {
++      //loc = LataField_base::ELEM;
++      nom = "JOINTS_ELEMENTS";
++      nom2 = "ELEMENTS";
++    } else if (i_item == 2) {
++      // loc = LataField_base::FACES;
++      nom = "JOINTS_FACES";
++      nom2 = "FACES";
++    }
++
++    IntTab & joint = joints.add();
++    if (lataDB.field_exists(id.timestep_, id.name_, nom)) {
++      entier nbitems = lataDB.get_field(id.timestep_, id.name_, nom2, "*").size_;
++      IntTab tmp;
++      lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, nom, "*"), tmp);
++      nproc = tmp.dimension(0);
++      // Recalcule la deuxieme colonne en fonction de la premiere
++      joint.resize(nproc, 2);
++      for (entier i = 0; i < nproc; i++) {
++        joint(i, 0) = tmp(i, 0);
++        if (i < nproc-1)
++          joint(i, 1) = tmp(i+1, 0) - tmp(i, 0);
++        else 
++          joint(i, 1) = nbitems - tmp(i, 0);
++      }
++    } 
++  }
++
++  if (id_.block_ < 0 || nproc == 1) {
++    // read all blocks at once default values are ok
++    set_joints(LataField_base::SOM) = joints[0];
++    set_joints(LataField_base::ELEM) = joints[1];
++    set_joints(LataField_base::FACES) = joints[2];
++  } else {
++    if (id_.block_ >= nproc) {
++      Journal() << "LataFilter::get_geometry : request non existant block " << id.block_ 
++                << " in geometry " << id.name_ << endl;
++      throw;
++    }
++    const entier n = id_.block_;
++    decal_nodes = joints[0](n, 0);
++    nb_sommets = joints[0](n, 1);
++    decal_elements = joints[1](n, 0);
++    nbelements = joints[1](n, 1);
++    if (domain_has_faces) {
++      decal_faces = joints[2](n, 0);
++      nbfaces = joints[2](n, 1);
++    }
++  }
++
++  // ******************************
++  // 2) Read nodes, elements and faces data
++  elt_type_ = Domain::element_type_from_string(geom.elem_type_);
++
++  lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "SOMMETS", "*"), nodes_, decal_nodes, nb_sommets);
++  lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "ELEMENTS", "*"), elements_, decal_elements, nbelements);
++  set_lata_block_offset(LataField_base::SOM, decal_nodes);
++  set_lata_block_offset(LataField_base::ELEM, decal_elements);
++  if (decal_nodes > 0) {
++    // Nodes are stored with global numbering in the lata file: transform to sub_block numbering :
++    elements_ -= decal_nodes;
++  }
++  if (domain_has_faces) {
++    set_lata_block_offset(LataField_base::FACES, decal_faces);
++    lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "FACES", "*"), faces_, decal_faces, nbfaces);
++    if (decal_nodes > 0)
++      faces_ -= decal_nodes;
++    lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "ELEM_FACES", "*"), elem_faces_, decal_elements, nbelements);
++    if (decal_faces > 0)
++      elem_faces_ -= decal_faces;
++  }
++
++  // *************************
++  // 3) Merge virtual elements if requested
++  if (merge_virtual_elements && lataDB.field_exists(id.timestep_, id.name_, "VIRTUAL_ELEMENTS") && id.block_ >= 0) 
++    {
++      Journal(info_level) << " Merging virtual elements" << endl;
++      // joints_virt_elems(sub_block, 0) = index of first virtual element in the VIRTUAL_ELEMENTS array
++      IntTab joints_virt_elems;
++      // Load the virtual elements (nodes are in global numbering)
++      //  First: find the index and number of virtual elements for block number id.block_:
++      lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "JOINTS_VIRTUAL_ELEMENTS", "*"), joints_virt_elems);
++      entier nb_virt_elems;
++      if (id.block_ < nproc-1)
++        nb_virt_elems = joints_virt_elems(id.block_+1, 0) - joints_virt_elems(id.block_, 0);
++      else
++        nb_virt_elems = lataDB.get_field(id.timestep_, id.name_, "VIRTUAL_ELEMENTS", "*").size_ - joints_virt_elems(id.block_, 0);
++      Journal(info_level+1) << " Number of virtual elements for block " << id.block_ << "=" << nb_virt_elems << endl;
++      //  Second: load the indexes of the virtual elements to load:
++      IntTab virt_elems;
++      lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "VIRTUAL_ELEMENTS", "*"), virt_elems, joints_virt_elems(id.block_,0), nb_virt_elems);
++      set_virt_items(LataField_base::ELEM, virt_elems);
++
++      {
++        //  Third: load the virtual elements (virt_elems contains the global indexes of the elements to
++        //  load and virt_elem_som will contain global nodes indexes of the virtual elements)
++        IntTab virt_elem_som;
++        lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "ELEMENTS", "*"), virt_elem_som, virt_elems);
++        // Find which virtual nodes are required and load them: virtual nodes to load are
++        // all nodes of the virtual elements (they have duplicates).
++        ArrOfInt index;
++        ArrOfInt & virt_elem_som_array = virt_elem_som; // Array seen as monodimensionnal
++        array_sort_indirect(virt_elem_som_array, index);
++        // Global nodes indexes of needed virtual nodes 
++        ArrOfInt nodes_to_read;
++        nodes_to_read.set_smart_resize(1);
++        {
++          const entier n = index.size_array();
++          // Global index of the last loaded node:
++          entier last_node = -1;
++          // Local index of the new loaded node:
++          entier new_node_index = nodes_.dimension(0)-1;
++          for (entier i = 0; i < n; i++) {
++            // Take nodes to load in ascending order of their global numbers:
++            const entier idx = index[i];
++            const entier node = virt_elem_som_array[idx];
++            if (node != last_node) {
++              // Node not yet encountered
++              nodes_to_read.append_array(node);
++              new_node_index++;
++              last_node = node;
++            }
++            virt_elem_som_array[idx] = new_node_index;
++          }
++        }
++        set_virt_items(LataField_base::SOM, nodes_to_read);
++        // Copy virtual elements to elements_
++        entier debut = elements_.size_array();
++        elements_.resize(elements_.dimension(0) + virt_elem_som.dimension(0),
++                         elements_.dimension(1));
++        elements_.inject_array(virt_elem_som, virt_elem_som.size_array(), debut);
++        // Load virtual nodes
++        FloatTab tmp_nodes;
++        lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "SOMMETS", "*"), tmp_nodes, nodes_to_read);
++        // Copy to nodes_
++        debut = nodes_.size_array();
++        nodes_.resize(nodes_.dimension(0) + tmp_nodes.dimension(0),
++                      nodes_.dimension(1));
++        nodes_.inject_array(tmp_nodes, tmp_nodes.size_array(), debut);
++      }
++
++      if (domain_has_faces) {
++        // Find which virtual faces are required and load them
++        // For each virtual element, index of its faces (like virt_elem_som)
++        IntTab virt_elem_faces; 
++        lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "ELEM_FACES", "*"), virt_elem_faces, virt_elems);
++        // Build the list of missing faces:
++        ArrOfInt index;
++        ArrOfInt & virt_elem_faces_array = virt_elem_faces; // Array seen as monodimensionnal
++        array_sort_indirect(virt_elem_faces_array, index);
++        ArrOfInt faces_to_read;
++        faces_to_read.set_smart_resize(1);
++        {
++          const entier n = index.size_array();
++          // Global index of the last loaded face:
++          entier last_face = -1;
++          // Local index of the new loaded node:
++          entier new_face_index = faces_.dimension(0)-1;
++          for (entier i = 0; i < n; i++) {
++            // Take nodes to load in ascending order of their global numbers:
++            const entier idx = index[i];
++            const entier face = virt_elem_faces_array[idx];
++            if (face != last_face) {
++              // Node not yet encountered
++              faces_to_read.append_array(face);
++              new_face_index++;
++              last_face = face;
++            }
++            virt_elem_faces_array[idx] = new_face_index;
++          }
++        }
++        set_virt_items(LataField_base::FACES, faces_to_read);
++        // Copy virtual elem_faces to elem_faces
++        entier debut = elem_faces_.size_array();
++        elem_faces_.resize(elem_faces_.dimension(0) + virt_elem_faces.dimension(0),
++                           elem_faces_.dimension(1));
++        elem_faces_.inject_array(virt_elem_faces, virt_elem_faces.size_array(), debut);
++
++        // Load virtual faces
++        IntTab tmp_faces_nodes;
++        lataDB.read_data(lataDB.get_field(id.timestep_, id.name_, "FACES", "*"), tmp_faces_nodes, faces_to_read);
++        // Convert global nodes indexes to local loaded nodes indexes in tmp_faces_nodes
++        {
++          // sort tmp_faces in ascending order so that the search requires linear time
++          ArrOfInt & array_tmp_faces_nodes = tmp_faces_nodes;
++          index.reset();
++          array_sort_indirect(array_tmp_faces_nodes, index);
++          const entier n = array_tmp_faces_nodes.size_array();
++          // Take nodes in tmp_faces_nodes in ascending order and find the corresponding node in nodes_to_read
++          // (which is also in sorted)
++          entier i1; // index in array_tmp_faces_nodes (the current node to convert)
++          entier i2 = 0; // index in nodes_to_read
++          const entier index_of_first_virtual_node = nodes_.dimension(0) - nb_virt_items(LataField_base::SOM);
++          const ArrOfInt & nodes_to_read = get_virt_items(LataField_base::SOM);
++          const entier max_i2 = nodes_to_read.size_array();
++          for (i1 = 0; i1 < n; i1++) {
++            const entier j = index[i1];
++            const entier global_node_index_to_find = array_tmp_faces_nodes[j];
++            // find the matching node in nodes_to_read (nodes_to_read is in ascending order)
++            while (nodes_to_read[i2] != global_node_index_to_find) {
++              i2++;
++              if (i2 >= max_i2) {
++                cerr << "Internal error in DomainUnstructured::fill_domain_from_lataDB:\n"
++                     << " node " << global_node_index_to_find << " of a virtual face does not belong to a virtual element" << endl;
++              throw;
++              }
++            }
++            array_tmp_faces_nodes[j] = index_of_first_virtual_node + i2; // index of this node in the local nodes_ array
++          }
++        }
++        // Copy to faces_ array
++        debut = faces_.size_array();
++        faces_.resize(faces_.dimension(0) + tmp_faces_nodes.dimension(0),
++                      faces_.dimension(1));
++        faces_.inject_array(tmp_faces_nodes, tmp_faces_nodes.size_array(), debut);
++      }
++    }
++}
++
++void Domain::fill_field_from_lataDB(const LataDB & lataDB,
++                                    const Field_Id & id, 
++                                    LataDeriv<LataField_base> & field) const
++{
++  Journal() << "Error : fill_field_from_lataDB not coded for this domain type" << endl;
++  throw;
++}
++
++// Reads the requested field to "field" structure.
++// id.block_ is not used, the data block read is the same as the domain.
++void DomainUnstructured::fill_field_from_lataDB(const LataDB & lataDB,
++                                                const Field_Id & id, 
++                                                LataDeriv<LataField_base> & field) const
++{
++  const LataDBField & lata_field = lataDB.get_field(id.timestep_, id.uname_);
++  LataField_base::Elem_som loc = LataField_base::localisation_from_string(lata_field.localisation_);
++  const entier decal = lata_block_offset(loc);
++
++  const ArrOfInt & virt_items = get_virt_items(loc);
++  const entier virt_size = virt_items.size_array();
++  const entier size = nb_items(loc) - virt_size;
++
++  const LataDBDataType & type = lata_field.datatype_;
++  switch(type.type_) {
++  case LataDBDataType::REAL32: {
++    FloatTab & data = field.instancie(Field<FloatTab> ).data_;
++    lataDB.read_data(lata_field, data, decal, size);
++    if (virt_size > 0) {
++      FloatTab tmp;
++      lataDB.read_data(lata_field, tmp, virt_items);
++      const entier debut = data.size_array();
++      data.resize(data.dimension(0)+virt_size, data.dimension(1));
++      data.inject_array(tmp, virt_size, debut);
++    }
++    break;
++  }
++  case LataDBDataType::REAL64: {
++    DoubleTab & data = field.instancie(Field<DoubleTab> ).data_; 
++    lataDB.read_data(lata_field, data, decal, size);
++    if (virt_size > 0) {
++      DoubleTab tmp;
++      lataDB.read_data(lata_field, tmp, virt_items);
++      const entier debut = data.size_array();
++      data.resize(data.dimension(0)+virt_size, data.dimension(1));
++      data.inject_array(tmp, virt_size, debut);
++    }
++    break;
++  }
++  case LataDBDataType::INT32:
++  case LataDBDataType::INT64: {
++    IntTab & data = field.instancie(Field<IntTab> ).data_; 
++    lataDB.read_data(lata_field, data, decal, size);
++    if (virt_size > 0) {
++      IntTab tmp;
++      lataDB.read_data(lata_field, tmp, virt_items);
++      const entier debut = data.size_array();
++      data.resize(data.dimension(0)+virt_size, data.dimension(1));
++      data.inject_array(tmp, virt_size, debut);
++    }
++    break;
++  }
++  default:
++    Journal() << "LataFilter::get_field_from_lataDB " << id.uname_ << ": data type not implemented" << endl;
++    throw;
++  }
++  field.valeur().id_ = id;
++  field.valeur().component_names_ = lata_field.component_names_;
++  field.valeur().localisation_ = loc;
++  field.valeur().nature_ = lata_field.nature_;
++}
++
++DomainIJK::DomainIJK()
++{
++  part_begin_ = 0;
++  part_end_ = 0;
++  virtual_layer_begin_ = 0;
++  virtual_layer_end_ = 0;
++}
++
++void DomainIJK::fill_domain_from_lataDB(const LataDB & lataDB,
++                                        const Domain_Id & id,                                        
++                                        entier split_in_N_parts,
++                                        const entier virt_layer_size)
++{
++  if (virt_layer_size < 0) {
++    Journal() << "Error in DomainIJK::fill_domain_from_lataDB: virt_layer_size < 0" << endl;
++    throw;
++  }
++  id_ = id;
++
++  Journal(info_level) << "Filling ijk domain " << id.name_ << " tstep " << id.timestep_ << " block " << id.block_ << endl;
++  coord_.reset();
++  entier dim3 = lataDB.field_exists(id.timestep_, id.name_, "SOMMETS_IJK_K", LataDB::FIRST_AND_CURRENT /* timestep */);
++  {
++    const LataDBField & coord = lataDB.get_field(id.timestep_, 
++                                                 Field_UName(id.name_, "SOMMETS_IJK_I", ""),
++                                                 LataDB::FIRST_AND_CURRENT /* timestep */);
++    FloatTab tmp;
++    lataDB.read_data(coord, tmp);
++    coord_.add();
++    coord_[0] = tmp;
++  }
++  {
++    const LataDBField & coord = lataDB.get_field(id.timestep_, 
++                                                 Field_UName(id.name_, "SOMMETS_IJK_J", ""),
++                                                 LataDB::FIRST_AND_CURRENT /* timestep */);
++    FloatTab tmp;
++    lataDB.read_data(coord, tmp);
++    coord_.add();
++    coord_[1] = tmp;
++  }
++  if (dim3) {
++    const LataDBField & coord = lataDB.get_field(id.timestep_, 
++                                                 Field_UName(id.name_, "SOMMETS_IJK_K", ""),
++                                                 LataDB::FIRST_AND_CURRENT /* timestep */);
++    FloatTab tmp;
++    lataDB.read_data(coord, tmp);
++    coord_.add();
++    coord_[2] = tmp;
++  }
++
++  elt_type_ = dim3 ? hexa : quadri;
++
++  entier block = (id.block_) < 0 ? 0 : id.block_;
++
++  if (id.block_ >= split_in_N_parts) {
++    Journal() << "Error in DomainIJK::fill_domain_from_lataDB: invalid block " << id.block_ << endl;
++    throw;
++  }
++
++  // Load the N-th part
++  //  The ijk domain is virtually split in the Z direction (or Y en 2D)
++  entier maxdim = coord_.size() - 1;
++  // Number of elements in the Z direction:
++  const entier nelem = coord_[maxdim].size_array() - 1;
++  entier part_size = nelem / split_in_N_parts;
++  if (part_size * split_in_N_parts < nelem)
++    part_size++;
++  
++  // Begin and end of the requested part:
++  part_begin_ = part_size * block - virt_layer_size;
++  if (part_begin_ < 0)
++    part_begin_ = 0;
++  part_end_ = part_size * block + part_size + virt_layer_size;
++  if (part_end_ > nelem)
++    part_end_ = nelem;
++  if (part_begin_ > part_end_)
++    // empty block
++    part_begin_ = part_end_ = 0; 
++
++  if (block > 0 && part_end_ > part_begin_)
++    // There is a virtual layer at the begin
++    virtual_layer_begin_ = virt_layer_size;
++  if (block < split_in_N_parts-1 && part_end_ > part_begin_)
++    virtual_layer_end_ = virt_layer_size;
++
++  // Extract coordinates:
++  ArrOfFloat tmp(coord_[maxdim]);
++  const entier n = part_end_ - part_begin_ + 1;
++  coord_[maxdim].resize_array(n);
++  for (entier i = 0; i < n; i++)
++    coord_[maxdim][i] = tmp[i + part_begin_];
++
++  Journal(info_level) << "Domain " << id.name_ << " has number of nodes: [ ";
++  for (entier dim = 0; dim < coord_.size(); dim++) 
++    Journal(info_level) << coord_[dim].size_array() << " ";
++  Journal(info_level) << "]" << endl;
++
++  if (part_end_ > part_begin_ // part might be empty if too many processors
++      && lataDB.field_exists(id.timestep_, id.name_, "INVALID_CONNECTIONS", LataDB::FIRST_AND_CURRENT /* timestep */))
++    {
++      Journal(info_level) << " loading invalid_connections" << endl;
++      IntTab Itmp;
++      entier ij = 0, offset = 0, sz = 0;
++      // Product of number of elements in directions I and J
++      ij = coord_[0].size_array() - 1;
++      if (coord_.size() > 2)
++        ij *= coord_[1].size_array() - 1;
++      // Select a range of elements in direction K
++      offset = ij * part_begin_;
++      sz = nb_elements();
++      const LataDBField & lata_field = lataDB.get_field(id.timestep_,  id.name_, "INVALID_CONNECTIONS", "ELEM",
++                                                        LataDB::FIRST_AND_CURRENT);
++      
++      lataDB.read_data(lata_field, Itmp, offset, sz);
++
++      invalid_connections_.resize_array(nb_elements());
++      invalid_connections_ = 0; // everything valid by default
++      
++      for (entier i = 0; i < sz; i++) {
++        if (Itmp(i, 0) != 0)
++          invalid_connections_.setbit(i);
++      }
++    }
++}
++
++void DomainIJK::fill_field_from_lataDB(const LataDB & lataDB,
++                                       const Field_Id & id, 
++                                       LataDeriv<LataField_base> & field) const
++{
++  const LataDBField & lata_field = lataDB.get_field(id.timestep_, id.uname_);
++  LataField_base::Elem_som loc = LataField_base::localisation_from_string(lata_field.localisation_);
++
++  entier ij = 0, offset = 0, sz = 0;
++  switch(loc) {
++  case LataField_base::ELEM: 
++    // Product of number of elements in directions I and J
++    ij = coord_[0].size_array() - 1;
++    if (coord_.size() > 2)
++      ij *= coord_[1].size_array() - 1;
++    // Select a range of elements in direction K
++    offset = ij * part_begin_;
++    sz = ij * (part_end_ - part_begin_);
++    break;
++  case LataField_base::SOM:
++  case LataField_base::FACES:
++    // Product of number of nodes in directions I and J
++    ij = coord_[0].size_array();
++    if (coord_.size() > 2)
++      ij *= coord_[1].size_array();
++    offset = ij * part_begin_;
++    sz = ij * (part_end_ + 1 - part_begin_);
++    break;
++  default:
++    Journal() << "Error in DomainIJK::fill_field_from_lataDB: unknown localisation" << endl;
++    throw;
++  }
++  
++  const LataDBDataType & type = lata_field.datatype_;
++  switch(type.type_) {
++  case LataDBDataType::REAL32: {
++    FloatTab & data = field.instancie(Field<FloatTab> ).data_;
++    lataDB.read_data(lata_field, data, offset, sz);
++    break;
++  }
++  case LataDBDataType::REAL64: {
++    DoubleTab & data = field.instancie(Field<DoubleTab> ).data_; 
++    lataDB.read_data(lata_field, data, offset, sz);
++    break;
++  }
++  case LataDBDataType::INT32:
++  case LataDBDataType::INT64: {
++    IntTab & data = field.instancie(Field<IntTab> ).data_; 
++    lataDB.read_data(lata_field, data, offset, sz);
++    break;
++  }
++  default:
++    Journal() << "LataFilter::get_field_from_lataDB " << id.uname_ << ": data type not implemented" << endl;
++    throw;
++  }
++  field.valeur().id_ = id;
++  field.valeur().component_names_ = lata_field.component_names_;
++  field.valeur().localisation_ = loc;
++  field.valeur().nature_ = lata_field.nature_;
++}
++
++
++Domain::DomainType Domain::get_domain_type() const
++{
++  const DomainUnstructured* geom_ptr = dynamic_cast<const DomainUnstructured*>(this);
++  if (geom_ptr!=0)
++    return UNSTRUCTURED;
++  const DomainIJK* ijk_ptr = dynamic_cast<const DomainIJK*>(this);
++  if (ijk_ptr!=0)
++    return IJK;
++  throw ("Not implemeneted");
++}
++const DomainUnstructured & Domain::cast_DomainUnstructured() const
++{
++  return dynamic_cast<const DomainUnstructured&>(*this);
++}
++const DomainIJK &  Domain::cast_DomainIJK() const
++{
++  return dynamic_cast<const DomainIJK&>(*this);
++}
+diff --git a/databases/readers/Lata/LataStructures.h b/databases/readers/Lata/LataStructures.h
+new file mode 100644
+index 0000000..74fa765
+--- /dev/null
++++ b/databases/readers/Lata/LataStructures.h
+@@ -0,0 +1,332 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef LataStructures_H
++#define LataStructures_H
++
++#include <ArrOfBit.h>
++#include <Lata_tools.h>
++#include <LataDB.h>
++
++// This file contains definitions of data structures containind meshes and fields
++//  used by LataFilter.
++
++// Description: Domain_Id is what you need to identify the content
++//  of a Domain object (at this time, the domain name, the timestep and the 
++//  parallel sub_block number)
++class Domain_Id
++{
++public:
++  Domain_Id(const char * name = "??", int t = 0, int block = -1) :
++    name_(name), timestep_(t), block_(block) {};
++  // Domain name
++  Nom name_;
++  // At which timestep (needed for dynamic domains)
++  int timestep_;
++  // Which block of the parallel computation ? -1 => all blocks
++  int block_;
++};
++
++// Description: Field_Id is what you need to identify the content of a
++//  LataField_base structure (at this time, the field uname, 
++//  the timestep and the parallel sub_block number)
++class Field_Id
++{
++public:
++  Field_Id() : timestep_(0) {};
++  Field_Id(const Field_UName & uname, int timestep, int block) :
++    timestep_(timestep), block_(block), uname_(uname)  {};
++  
++  int         timestep_;
++  int         block_;
++  Field_UName uname_;
++
++  operator Domain_Id() const { return Domain_Id(uname_.get_geometry(), timestep_, block_); }
++};
++
++// Description: This structure contains a discrete data array for a specific
++//  field, at one timestep, for one sub_block of the geometry, with
++//  one localisation (but many components)
++class LataField_base : public LataObject
++{
++public:
++  LataField_base() { localisation_ = UNKNOWN; nature_ = LataDBField::UNKNOWN; }
++  Field_Id  id_;
++  Noms      component_names_;
++  enum Elem_som { ELEM, SOM, FACES, UNKNOWN };
++  Elem_som  localisation_;
++  LataDBField::Nature nature_;
++
++  static Elem_som localisation_from_string(const Motcle &);
++  static Nom      localisation_to_string(const Elem_som);
++};
++class DomainUnstructured;
++class DomainIJK;
++
++// This class stores the geometry of a domain
++class Domain : public LataObject
++{
++public:
++  Domain_Id id_;
++  enum Element { point, line, triangle, quadri, tetra, hexa, prism6, polyedre, polygone, unspecified };
++  enum DomainType { IJK, UNSTRUCTURED };
++  static Element element_type_from_string(const Motcle & type_elem);
++  static Nom     element_type_to_string(Element type);
++  Element elt_type_;
++
++  Domain() : 
++    elt_type_(unspecified),
++    decal_nodes_lata_(-1), // -1 indicates: value not set. see lata_block_offset
++    decal_elements_lata_(-1), 
++    decal_faces_lata_(-1) {};
++    DomainType get_domain_type() const;
++    const DomainUnstructured & cast_DomainUnstructured() const;
++    const DomainIJK &  cast_DomainIJK() const;
++  virtual entier dimension() const = 0;
++  virtual entier nb_nodes() const = 0;
++  virtual entier nb_elements() const = 0;
++  virtual entier nb_faces() const = 0;
++  virtual entier nb_items(const LataField_base::Elem_som) const;
++  virtual entier lata_block_offset(const LataField_base::Elem_som) const;
++  virtual void   set_lata_block_offset(const LataField_base::Elem_som, entier n);
++
++  virtual void fill_field_from_lataDB(const LataDB & lataDB,
++                                      const Field_Id & id, 
++                                      LataDeriv<LataField_base> & field) const = 0;
++
++  static Motcle lata_element_name(Domain::Element type);
++
++protected:
++  // If the Domain has been loaded from a lata file and it's not the
++  // first block this is the offset in the lata file:
++  entier decal_nodes_lata_;
++  entier decal_elements_lata_;
++  entier decal_faces_lata_;
++};
++
++class DomainUnstructured : public Domain
++{
++public:
++  DomainUnstructured() { nb_virt_nodes_ = 0; nb_virt_elements_ = 0; nb_virt_faces_ = 0; }
++
++  FloatTab  nodes_;
++  // For each element, indexes of the nodes (first node is at index 0)
++  // Nodes ordering in an element is the same as in TRUST
++  IntTab    elements_;
++  // For each face, indexes of the nodes (if present in lata file)
++  IntTab    faces_;
++  // For each elements, indexes of the faces (first face at index 0, if present in lata file)
++  // Faces ordering in an element is the same as in TRUST
++  IntTab    elem_faces_;
++
++  entier dimension() const { return nodes_.dimension(1); }
++  entier nb_nodes() const { return nodes_.dimension(0); }
++  entier nb_elements() const { return elements_.dimension(0); }
++  entier nb_faces() const { return faces_.dimension(0); }
++  // Tests if the geometry contains faces description
++  entier faces_ok() const { return elem_faces_.dimension(0) == elements_.dimension(0); }
++  template<class TabType>
++  void compute_cell_center_coordinates(TabType & coord, entier index_begin) const;
++  BigEntier compute_memory_size() const
++  { return
++      memory_size(nodes_)
++      + memory_size(elements_)
++      + memory_size(faces_)
++      + memory_size(elem_faces_); 
++  }
++  const IntTab & get_joints(LataField_base::Elem_som loc) const { 
++    const IntTab * ptr = 0;
++    switch(loc) {
++    case LataField_base::SOM: ptr = &joints_sommets_; break;
++    case LataField_base::ELEM: ptr = &joints_elements_; break;
++    case LataField_base::FACES: ptr = &joints_faces_; break;
++    default: throw;
++    }
++    if (ptr->dimension(1) == 0) throw;
++    return *ptr;
++  }
++  IntTab & set_joints(LataField_base::Elem_som loc) {
++    IntTab * ptr = 0;
++    switch(loc) {
++    case LataField_base::SOM: ptr = &joints_sommets_; break;
++    case LataField_base::ELEM: ptr = &joints_elements_; break;
++    case LataField_base::FACES: ptr = &joints_faces_; break;
++    default: throw;
++    }
++    return *ptr;
++  }
++  const ArrOfInt & get_virt_items(LataField_base::Elem_som loc) const {
++    switch(loc) {
++    case LataField_base::SOM: return virt_nodes_; break;
++    case LataField_base::ELEM: return virt_elements_; break;
++    case LataField_base::FACES: return virt_faces_; break;
++    default: throw;
++    }
++    return virt_nodes_;
++  }
++  void set_virt_items(LataField_base::Elem_som loc, const ArrOfInt & list) {
++    switch(loc) {
++    case LataField_base::SOM: virt_nodes_ = list; nb_virt_nodes_ = list.size_array(); break;
++    case LataField_base::ELEM: virt_elements_ = list; nb_virt_elements_ = list.size_array(); break;
++    case LataField_base::FACES: virt_faces_ = list; nb_virt_faces_ = list.size_array(); break;
++    default: throw;
++    }
++  };
++  void set_nb_virt_items(LataField_base::Elem_som loc, entier n) {
++    switch(loc) {
++    case LataField_base::SOM:   nb_virt_nodes_ = n; break;
++    case LataField_base::ELEM:  nb_virt_elements_ = n; break;
++    case LataField_base::FACES: nb_virt_faces_ = n; break;
++    default: throw;
++    }
++  };
++  entier nb_virt_items(LataField_base::Elem_som loc) const {
++    switch(loc) {
++    case LataField_base::SOM: return nb_virt_nodes_; break;
++    case LataField_base::ELEM: return nb_virt_elements_; break;
++    case LataField_base::FACES: return nb_virt_faces_; break;
++    default: throw;
++    }
++    return nb_virt_nodes_;
++  }
++
++  virtual void fill_domain_from_lataDB(const LataDB & lataDB,
++                                       const Domain_Id & id,
++                                       entier load_faces = 1, 
++                                       entier merge_virtual_elements = 0);
++  virtual void fill_field_from_lataDB(const LataDB & lataDB,
++                                      const Field_Id & id, 
++                                      LataDeriv<LataField_base> & field) const;
++
++protected:
++  // data not always filled:
++  IntTab joints_sommets_;
++  IntTab joints_elements_;
++  IntTab joints_faces_;
++  ArrOfInt virt_nodes_; // Global indexes of virtual nodes to load
++  ArrOfInt virt_elements_; // Global indexes of virtual elements to load
++  ArrOfInt virt_faces_; // Global indexes of virtual faces to load
++  entier nb_virt_nodes_;
++  entier nb_virt_elements_;
++  entier nb_virt_faces_;
++};
++
++// This is a structured grid, grid axes aligned on X, Y and Z.
++// The grid can have "invalid_positions_" and "invalid_connections_".
++// Nodes are numbered like this:
++//  node_index(i,j,k) = (k * nb_nodes_y + j) * nb_nodes_x + i
++// Elements are numbered like this:
++//  element_index(i,j,k) = (k * nb_elements_y + j) * nb_elements_x + i
++// Faces are numbered like this: faces of each direction have a numbering starting at zero.
++//  The number of a particular face is the smallest number of its nodes.
++//  Hence some numbers are not used (le last face of each "row" depending on the
++//  direction)
++class DomainIJK : public Domain
++{
++public:
++  DomainIJK();
++  // In each spatial direction, ordered list of coordinates of the IJK grid
++  LataVector<ArrOfFloat> coord_;
++
++  // For each node and each element, flag indicates if it is valid or not
++  // (eg, has usable field values)
++  // If array is empty, all data is valid.
++  ArrOfBit invalid_positions_;
++  ArrOfBit invalid_connections_;
++
++  entier dimension() const { return coord_.size(); }
++  entier nb_nodes() const {
++    entier n = 1, d = coord_.size(); 
++    for (entier i=0; i<d; i++) 
++      n *= coord_[i].size_array();
++    return n; 
++  }
++  entier nb_elements() const {
++    entier n = 1, d = coord_.size(); 
++    for (entier i=0; i<d; i++) 
++      n *= coord_[i].size_array()-1;
++    return n; 
++  }
++  // Dimension(0) des tableaux de valeurs aux faces
++  //  (voir convention sur la numerotation des faces)
++  //  les champs associes aux faces des differentes directions sont
++  //  stockes dans les composantes du champ.
++  entier nb_faces() const { return nb_nodes(); }
++  BigEntier compute_memory_size() const
++  { 
++    BigEntier x = 0;
++    const entier n = coord_.size();
++    for (entier i = 0; i < n; i++) 
++      x += memory_size(coord_[i]);
++    return x + memory_size(invalid_positions_) + memory_size(invalid_connections_);
++  }
++
++  // renvoie le nombre de sommets dans la direction dir
++  //  (renvoie 1 si dir >= dimension())
++  entier nb_som_dir(entier dir) const {
++    if (dir >= dimension())
++      return 1;
++    else
++      return coord_[dir].size_array();
++  }
++  // renvoie le nombre d'elements dans la direction dir
++  //  (renvoie 1 si dir >= dimension())
++  entier nb_elem_dir(entier dir) const {
++    if (dir >= dimension())
++      return 1;
++    else
++      return coord_[dir].size_array() - 1;
++  }
++
++  virtual void fill_domain_from_lataDB(const LataDB & lataDB,
++                                       const Domain_Id & id,
++                                       const entier split_in_nparts = 1,
++                                       const entier virt_layer_size = 1);
++  virtual void fill_field_from_lataDB(const LataDB & lataDB,
++                                      const Field_Id & id, 
++                                      LataDeriv<LataField_base> & field) const;
++
++  // when loading fields, we will load elements (i,j,k) with 
++  //   part_begin_ <= k < part_end_
++  // (or j in 2D), part_begin_ and part_end_ include the virtual layer
++  entier part_begin_;
++  entier part_end_;
++  // number of layers of virtual elements at each side:
++  entier virtual_layer_begin_;
++  entier virtual_layer_end_;
++};
++
++template <class TabType>
++class Field : public LataField_base
++{
++public:
++  TabType data_;
++  BigEntier compute_memory_size() const { return memory_size(data_); }
++};
++#endif
+diff --git a/databases/readers/Lata/LataV1_field_definitions.C b/databases/readers/Lata/LataV1_field_definitions.C
+new file mode 100644
+index 0000000..7bb0e2f
+--- /dev/null
++++ b/databases/readers/Lata/LataV1_field_definitions.C
+@@ -0,0 +1,84 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <LataV1_field_definitions.h>
++#include <Motcle.h>
++
++typedef struct {
++  const char * name;
++  int shape; // Vector size (-1 => dimension of the problem)
++} StdComponents;
++
++// COMPOSANTES EN MAJUSCULES !!!!!
++// Components are checked in the same order than this array.
++// We assume that the component has been found if component
++// name begins with the string in this array. For example
++// if the lata file contains INDICATRICE_INTERF, we will
++// find that it is an "INDICATRICE" component.
++// Therefore, long names must be placed before short names:
++// If we have a component "K" and a component "K_EPS", then
++// "K_EPS" must be placed before "K", otherwise "K_EPS" will
++// never be found.
++const StdComponents std_components[] =
++  { 
++    { "VITESSE",             -1 },
++    { "primal",              -1 },
++    { "VORTICITE",           -2 },
++    { "MOYENNE_VITESSE",     -1 },
++    { "ECART_TYPE_VITESSE",  -1 },
++    { "MOYENNE_VORTICITE",   -2 },
++    { "ECART_TYPE_VORTICITE", -2 },
++    { "GRADIENT_PRESSION",            -1 },
++    { "DERIVEE_U_ETOILE",             -1 },
++    { "TERME_DIFFUSION_VITESSE",      -1 },
++    { "TERME_CONVECTION_VITESSE",     -1 },
++    { "TERME_SOURCE_VITESSE",         -1 },
++    { "GRAD",         -1 },
++    { "NORMALE_INTERFACE",            -1 },
++    { "K_EPS",                             2 },
++    { "ACCELERATION",        -1 },
++    { "CHAMP_VECTORIEL",     -1},
++    { "2_",     2},
++    { "3_",     3},
++    { "6_",     6},
++    { "9_",     9},
++    { "",                  1 }
++    // Empty label means end of the table
++  };
++
++int latav1_component_shape(const Motcle & compo)
++{
++  entier i = 0;
++  while (std_components[i].name[0] != 0) {
++    if (compo.debute_par(std_components[i].name))
++      return std_components[i].shape;
++    i++;
++  }
++  return 1;
++}
+diff --git a/databases/readers/Lata/LataV1_field_definitions.h b/databases/readers/Lata/LataV1_field_definitions.h
+new file mode 100644
+index 0000000..8aaca6a
+--- /dev/null
++++ b/databases/readers/Lata/LataV1_field_definitions.h
+@@ -0,0 +1,35 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++// This file is included in LataDB.cpp (and only there)
++// It contains fields definitions for the old LataV1 format
++// (separated from LataDB.cpp so that changes in this file are
++//  easily identified)
++class Motcle;
++int latav1_component_shape(const Motcle & compo);
+diff --git a/databases/readers/Lata/LataVector.h b/databases/readers/Lata/LataVector.h
+new file mode 100644
+index 0000000..18e46f6
+--- /dev/null
++++ b/databases/readers/Lata/LataVector.h
+@@ -0,0 +1,64 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef LataVector_H
++#define LataVector_H
++#include <assert.h>
++#include <arch.h>
++// This vector class uses an array of pointers so that objects stored are never
++// moved in memory when the array is resized.
++template <class C>
++class LataVector
++{
++public:
++  LataVector() : n_(0), data_(0) { }
++  LataVector(const LataVector<C> & x) : n_(0), data_(0) { operator=(x); }
++  LataVector(entier n) : n_(0), data_(0) { for (entier i=0; i<n; i++) add(); }
++  ~LataVector() { reset(); }
++  void reset() { for (int i=0; i<n_; i++) { delete data_[i]; }; delete[] data_; n_ = 0; data_ = 0; }
++  const C & operator[](entier i) const { assert(i>=0 && i<n_); return *(data_[i]); }
++  C & operator[](entier i) { assert(i>=0 && i<n_); return *(data_[i]); }
++  C & add(const C & item) { return add_item(new C(item)); }
++  C & add() { return add_item(new C); }
++  entier size() const { return n_; }
++  entier rang(const C & c) const { for (entier i = 0; i < n_; i++) if (*(data_[i]) == c) return i; return -1; }
++  LataVector<C> & operator=(const LataVector<C> & x) { reset(); for (int i=0; i<x.n_; i++) add(x[i]); return *this; }
++private:
++  C & add_item(C* added_item) {
++    C** old = data_; 
++    data_ = new C*[n_+1]; 
++    for (int i=0; i<n_; i++) data_[i] = old[i]; 
++    delete[] old;
++    data_[n_++] = added_item;
++    return *added_item;
++  }
++  entier n_;
++  C** data_;
++};
++#endif
+diff --git a/databases/readers/Lata/LataWriter.C b/databases/readers/Lata/LataWriter.C
+new file mode 100644
+index 0000000..3387570
+--- /dev/null
++++ b/databases/readers/Lata/LataWriter.C
+@@ -0,0 +1,331 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <LataWriter.h>
++#include <LataStructures.h>
++
++// Path, if not empty, must include a trailing '/'
++// basename must not include the .lata extension
++void LataWriter::init_file(const Nom & path, const Nom & basename,
++                           const LataDBDataType & default_int_format, 
++                           LataDBDataType::Type default_float_type)
++{
++  db_.reset();
++  db_.set_path_prefix(path);
++  basename_ = basename;
++  db_.default_type_int_ = default_int_format;
++  db_.default_float_type_ = default_float_type;
++  db_.header_ = "Lata V2";
++  db_.case_ = "lata2dx";
++  db_.software_id_ = "Trio_U";
++  //split_ = split;
++
++  // Global geometries and fields:
++  db_.add_timestep(0.);
++}
++
++// Add a new timestep to the lata database (new TEMPS entry)
++// Geometries and fields are always written in the last added timestep
++//  (the timestep stored within the domain or field is ignored)
++// Those written before the first call to write_time() go into global
++//  fields and geometry definitions.
++void LataWriter::write_time(double t)
++{
++  db_.add_timestep(t);
++}
++
++void LataWriter::write_geometry(const Domain & dom)
++{
++  // Index of the last timestep:
++  const entier tstep = db_.nb_timesteps() - 1;
++
++  // Build a geometry database entry and add it to database
++  LataDBGeometry geom;
++  geom.name_ = dom.id_.name_;
++  geom.elem_type_ = dom.element_type_to_string(dom.elt_type_);
++  geom.timestep_ = tstep;
++  db_.add_geometry(geom);
++
++  // Write geometry data
++  const DomainUnstructured * dom1_ptr = dynamic_cast<const DomainUnstructured*>(&dom);
++  const DomainIJK * dom2_ptr = dynamic_cast<const DomainIJK*>(&dom);
++  
++  if (dom1_ptr)
++    {
++      // For unstructured meshes, we write the following fields:
++      //  SOMMETS
++      //  ELEMENTS
++      //  [ FACES ]
++      //  [ ELEM_FACES ]
++      const DomainUnstructured & domain = *dom1_ptr;
++      LataDBField field;
++      // Write nodes
++      Nom fieldname = "SOMMETS";
++      field.uname_ = Field_UName(geom.name_, fieldname, "" /* localisation */);
++      field.name_ = fieldname;
++      field.timestep_ = tstep;
++
++      field.filename_ = basename_;
++      field.filename_ += ".lata.";
++      field.filename_ += fieldname;
++      field.filename_ += ".";
++      field.filename_ += geom.name_;
++      if (tstep > 0) { 
++        field.filename_ += ".";
++        field.filename_ += Nom(tstep);
++      }
++      field.nb_comp_ = domain.dimension();
++      field.geometry_ = geom.name_;
++      field.datatype_ = db_.default_type_float();
++      field.localisation_ = "";
++      field.reference_ = "";
++      field.size_ = domain.nb_nodes();
++
++      db_.add_field(field);
++      db_.write_data(tstep, field.uname_, domain.nodes_);
++
++      // Write elements
++      fieldname = "ELEMENTS";
++      field.uname_ = Field_UName(geom.name_, fieldname, "" /* localisation */);
++      field.name_ = fieldname;
++      field.timestep_ = tstep;
++
++      field.filename_ = basename_;
++      field.filename_ += ".lata.";
++      field.filename_ += fieldname;
++      field.filename_ += ".";
++      field.filename_ += geom.name_;
++      if (tstep > 0) { 
++        field.filename_ += ".";
++        field.filename_ += Nom(tstep);
++      }
++      field.nb_comp_ = domain.elements_.dimension(1);
++      field.geometry_ = geom.name_;
++      field.datatype_ = db_.default_type_int_;
++      field.localisation_ = "";
++      field.reference_ = "SOMMETS";
++      field.size_ = domain.nb_elements();
++      
++      db_.add_field(field);
++      db_.write_data(tstep, field.uname_, domain.elements_);
++
++      // Write faces
++      if (domain.faces_ok()) {
++       fieldname = "FACES";
++       field.uname_ = Field_UName(geom.name_, fieldname, "" /* localisation */);
++       field.name_ = fieldname;
++       field.timestep_ = tstep; 
++
++       field.filename_ = basename_;
++       field.filename_ += ".lata.";
++       field.filename_ += fieldname;
++       field.filename_ += ".";
++       field.filename_ += geom.name_;
++       if (tstep > 0) { 
++        field.filename_ += ".";
++        field.filename_ += Nom(tstep);
++       }
++       field.nb_comp_ = domain.faces_.dimension(1);
++       field.geometry_ = geom.name_;
++       field.datatype_ = db_.default_type_int_;
++       field.localisation_ = "";
++       field.reference_ = "SOMMETS";
++       field.size_ = domain.nb_faces();
++      
++       db_.add_field(field);
++       db_.write_data(tstep, field.uname_, domain.faces_);
++
++       fieldname = "ELEM_FACES";
++       field.uname_ = Field_UName(geom.name_, fieldname, "" /* localisation */);
++       field.name_ = fieldname;
++       field.timestep_ = tstep; 
++
++       field.filename_ = basename_;
++       field.filename_ += ".lata.";
++       field.filename_ += fieldname;
++       field.filename_ += ".";
++       field.filename_ += geom.name_;
++       if (tstep > 0) { 
++        field.filename_ += ".";
++        field.filename_ += Nom(tstep);
++       }
++       field.nb_comp_ = domain.elem_faces_.dimension(1);
++       field.geometry_ = geom.name_;
++       field.datatype_ = db_.default_type_int_;
++       field.localisation_ = "";
++       field.reference_ = "FACES";
++       field.size_ = domain.nb_elements();
++      
++       db_.add_field(field);
++       db_.write_data(tstep, field.uname_, domain.elem_faces_);
++     }
++    }
++  else if (dom2_ptr)
++    {
++      // For IJK we write 2 or 3 fields containing 1-dimensionnal arrays with
++      //  the nodes coordinates in each direction:
++      //  SOMMETS_IJK_I, SOMMETS_IJK_J, SOMMETS_IJK_K.
++
++      const DomainIJK & domain = *dom2_ptr;
++      // Write coordinates
++      const entier dim = domain.coord_.size();
++      if (dim > 3) {
++        Journal() << "Error in LataWriter::write_geometry: dimension > 3" << endl;
++        throw InternalError;
++      }
++      Noms dir_names(3);
++      dir_names[0] = "I";
++      dir_names[1] = "J";
++      dir_names[2] = "K";
++      for (entier i_dim = 0; i_dim < dim; i_dim++) {
++        FloatTab coord;
++        {
++          const ArrOfFloat & x = domain.coord_[i_dim];
++          const entier n = x.size_array();
++          coord.resize(n, 1);
++          for (entier i = 0; i < n; i++)
++            coord(i, 0) = x[i];
++        }
++        
++        Nom fieldname = "SOMMETS_IJK_";
++        fieldname += dir_names[i_dim];
++        LataDBField field;
++        field.uname_ = Field_UName(geom.name_, fieldname, "" /* localisation */);
++        field.name_ = fieldname;
++        field.timestep_ = tstep;
++
++        field.filename_ = basename_;
++        field.filename_ += ".lata.";
++        field.filename_ += fieldname;
++        field.filename_ += ".";
++        field.filename_ += geom.name_;
++        if (tstep > 0) { 
++          field.filename_ += ".";
++          field.filename_ += Nom(tstep);
++        }
++        field.nb_comp_ = 1;
++        field.geometry_ = geom.name_;
++        field.datatype_ = db_.default_type_float();
++        field.localisation_ = "";
++        field.reference_ = "";
++        field.size_ = coord.dimension(0);
++
++        db_.add_field(field);
++        db_.write_data(tstep, field.uname_, coord);
++      }
++      
++      if (domain.invalid_connections_.size_array() > 0) {
++        const entier n = domain.invalid_connections_.size_array();
++        IntTab tmp(n, 1);
++        for (entier i = 0; i < n; i++) 
++          tmp(i, 0) = domain.invalid_connections_[i];
++
++        Nom fieldname = "INVALID_CONNECTIONS";
++        LataDBField field;
++        field.uname_ = Field_UName(geom.name_, fieldname, "ELEM" /* localisation */);
++        field.name_ = fieldname;
++        field.timestep_ = tstep;
++
++        field.filename_ = basename_;
++        field.filename_ += ".lata.";
++        field.filename_ += fieldname;
++        field.filename_ += ".";
++        field.filename_ += geom.name_;
++        if (tstep > 0) { 
++          field.filename_ += ".";
++          field.filename_ += Nom(tstep);
++        }
++        field.nb_comp_ = 1;
++        field.geometry_ = geom.name_;
++        field.datatype_ = db_.default_type_int_;
++        field.datatype_.array_index_ = LataDBDataType::NOT_AN_INDEX;
++        field.localisation_ = "ELEM";
++        field.reference_ = "";
++        field.size_ = n;
++
++        db_.add_field(field);
++        db_.write_data(tstep, field.uname_, tmp);
++      }
++    }
++  else
++    {
++      Journal() << "Error LataWriter::write_geometry domain type not supported" << endl;
++      throw InternalError;
++    }
++}
++
++void LataWriter::write_component(const LataField_base & field)
++{
++  // Index of the last timestep:
++  const entier tstep = db_.nb_timesteps() - 1;
++  
++  LataDBField lata_field;
++  
++  lata_field.uname_ = field.id_.uname_;
++  lata_field.name_ = field.id_.uname_.get_field_name();
++  lata_field.timestep_ = tstep;
++  lata_field.filename_ = basename_;
++  lata_field.filename_ += ".lata.";
++  lata_field.filename_ += lata_field.uname_.build_string();
++  if (tstep > 0) { 
++    lata_field.filename_ += ".";
++    lata_field.filename_ += Nom(tstep);
++  }
++  lata_field.geometry_ = field.id_.uname_.get_geometry();
++  lata_field.component_names_ = field.component_names_;
++  // Unites a remplir
++  // Size = -1 => valeur par defaut cherchee dans la geometrie
++  lata_field.localisation_ = LataField_base::localisation_to_string(field.localisation_);
++  lata_field.nature_ = field.nature_;
++
++  const Field<FloatTab> * float_f = dynamic_cast<const Field<FloatTab>*>(&field);
++  const Field<IntTab>* int_f = dynamic_cast<const Field<IntTab>*>(&field);
++  if (int_f) {
++    lata_field.nb_comp_ = int_f->data_.dimension(1);
++    lata_field.size_ = int_f->data_.dimension(0);
++    lata_field.datatype_ = db_.default_type_int_;
++    lata_field.datatype_.array_index_ = LataDBDataType::NOT_AN_INDEX;
++    db_.add_field(lata_field);
++    db_.write_data(tstep, lata_field.uname_, int_f->data_);
++  } else if (float_f) {
++    lata_field.nb_comp_ = float_f->data_.dimension(1);
++    lata_field.size_ = float_f->data_.dimension(0);
++    lata_field.datatype_ = db_.default_type_float();
++    db_.add_field(lata_field);
++    db_.write_data(tstep, lata_field.uname_, float_f->data_);
++  }
++}
++
++void LataWriter::finish()
++{
++  Nom n(db_.path_prefix());
++  n += basename_;
++  n += ".lata";
++  db_.write_master_file(n);
++}
+diff --git a/databases/readers/Lata/LataWriter.h b/databases/readers/Lata/LataWriter.h
+new file mode 100644
+index 0000000..d17c413
+--- /dev/null
++++ b/databases/readers/Lata/LataWriter.h
+@@ -0,0 +1,61 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef LataWriter_H
++#define LataWriter_H
++#include <LataDB.h>
++class Domain;
++class LataField_base;
++
++// This class provides general services to write lata files
++//  from the "high level" objects Domain and Field (the LataDB class provides
++//  only low level services to write arrays)
++class LataWriter
++{
++public:
++  enum FileSplittingOption { MULTIPLE_FILES, SINGLE_FILE };
++  void init_file(const Nom & path, const Nom & basename,
++                 const LataDBDataType & default_int_format, 
++                 LataDBDataType::Type default_float_type);
++
++  void write_time(double t);
++  void write_geometry(const Domain & dom);
++  void write_component(const LataField_base & field);
++
++  void finish();
++  enum ERRORS { InternalError };
++
++protected:
++  // This is the database where we put all data...
++  LataDB db_;
++  // Basename for files and lata master file:
++  Nom basename_;
++  // FileSplittingOption split_;
++};
++#endif
+diff --git a/databases/readers/Lata/Lata_tools.C b/databases/readers/Lata/Lata_tools.C
+new file mode 100644
+index 0000000..fb97479
+--- /dev/null
++++ b/databases/readers/Lata/Lata_tools.C
+@@ -0,0 +1,128 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <Lata_tools.h>
++#include <ArrOfInt.h>
++#include <ArrOfDouble.h>
++#include <ArrOfFloat.h>
++#include <ArrOfBit.h>
++#include <sstream>
++#include <string.h>
++#include <stdlib.h>
++
++static int journal_level = 0;
++
++void set_Journal_level(entier level)
++{
++  if (journal_level==level) return;
++  journal_level = level;
++  Journal() << "Changed lata journal level: " << journal_level << endl;
++}
++
++static std::ostringstream junk_journal;
++
++std::ostream & Journal(entier level)
++{
++  if (level <= journal_level) {
++    cerr << "[" << level << "] ";
++    return cerr;
++  } else {
++    junk_journal.seekp(0);
++    return junk_journal;
++  }
++}
++
++// Description: this method must return the total memory consumption
++//  of the object (used to compute the size of the data cache)
++BigEntier LataObject::compute_memory_size() const
++{
++  Journal() << "Error in LataObject::compute_memory_size(): function not implemented" << endl;
++  throw;
++}
++
++BigEntier memory_size(const ArrOfInt & tab)
++{
++  // On ne tient pas compte du caractere smart_resize ou ref du tableau
++  // c'est pas tres grave pour l'instant pour ce qu'on en fait...
++  return ((BigEntier)sizeof(tab)) + ((BigEntier)tab.size_array()) * sizeof(entier);
++}
++
++BigEntier memory_size(const ArrOfDouble & tab)
++{
++  // on ne tient pas compte du caractere smart_resize ou ref du tableau
++  // c'est pas tres grave pour l'instant pour ce qu'on en fait...
++  return ((BigEntier)sizeof(tab)) + ((BigEntier)tab.size_array()) * sizeof(double);
++}
++
++BigEntier memory_size(const ArrOfFloat & tab)
++{
++  // on ne tient pas compte du caractere smart_resize ou ref du tableau
++  // c'est pas tres grave pour l'instant pour ce qu'on en fait...
++  return ((BigEntier)sizeof(tab)) + ((BigEntier)tab.size_array()) * sizeof(float);
++}
++
++BigEntier memory_size(const ArrOfBit & tab)
++{
++  return ((BigEntier)sizeof(tab)) + ((BigEntier)tab.size_array()) * sizeof(int) / 32; 
++}
++
++void split_path_filename(const char *s, Nom & path, Nom & filename)
++{
++  int i;
++  for (i=(int)strlen(s)-1;i>=0;i--)
++    if ((s[i]==PATH_SEPARATOR) || (s[i]=='\\'))
++      break;
++  path = "";
++  int j;
++  for (j = 0; j <= i; j++)
++    path += Nom(s[j]);
++  
++  // Parse basename : if extension given, remove it
++  filename = s+i+1;
++}
++
++static const ArrOfInt * array_to_sort_ptr = 0;
++int compare_indirect(const void *ptr1, const void *ptr2)
++{
++  entier i1 = *(const entier*)ptr1;
++  entier i2 = *(const entier*)ptr2;
++  entier diff = (*array_to_sort_ptr)[i1] - (*array_to_sort_ptr)[i2];
++  return (diff>0) ? 1 : ((diff==0) ? 0 : -1);
++}
++
++void array_sort_indirect(const ArrOfInt & array_to_sort, ArrOfInt & index)
++{
++  const entier n = array_to_sort.size_array();
++  index.set_smart_resize(1);
++  index.resize_array(n);
++  for (entier i = 0; i < n; i++)
++    index[i] = i;
++  array_to_sort_ptr = &array_to_sort;
++  qsort(index.addr(), n, sizeof(entier), compare_indirect);
++}
+diff --git a/databases/readers/Lata/Lata_tools.h b/databases/readers/Lata/Lata_tools.h
+new file mode 100644
+index 0000000..940fc54
+--- /dev/null
++++ b/databases/readers/Lata/Lata_tools.h
+@@ -0,0 +1,194 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef Lata_tools_include_
++#define Lata_tools_include_
++#include <assert.h>
++#include <arch.h>
++
++
++
++
++
++#ifdef WIN32
++#define __BIG_ENDIAN    111
++#define __LITTLE_ENDIAN 121
++#define __BYTE_ORDER __LITTLE_ENDIAN
++
++#define strtoll _strtoi64
++// This must be able to contain a total memory size
++// or a very big operation counter.
++typedef __int64 BigEntier;
++
++#else
++#ifdef __APPLE__
++// Assume we only have x86, x86_64 based Macs.
++#define __BIG_ENDIAN    111
++#define __LITTLE_ENDIAN 121
++#define __BYTE_ORDER __LITTLE_ENDIAN
++#endif
++
++// This must be able to contain a total memory size
++// or a very big operation counter.
++typedef long long BigEntier;
++#endif
++
++#ifndef __BYTE_ORDER
++#include <endian.h>
++#endif
++
++#include <LataVector.h>
++
++
++#define PATH_SEPARATOR '/'
++
++#ifndef __BYTE_ORDER
++#error "Byte order not defined."
++#endif
++#if (__BYTE_ORDER == __BIG_ENDIAN)
++const bool mymachine_msb =  true;
++#elif (__BYTE_ORDER == __LITTLE_ENDIAN)
++const bool mymachine_msb =  false;
++#else
++#error "Byte order is neither __BIG_ENDIAN nor __LITTLE_ENDIAN : "
++#endif
++
++class ArrOfInt;
++class ArrOfDouble;
++class ArrOfFloat;
++class ArrOfBit;
++BigEntier memory_size(const ArrOfInt &);
++BigEntier memory_size(const ArrOfDouble &);
++BigEntier memory_size(const ArrOfFloat &);
++BigEntier memory_size(const ArrOfBit &);
++
++class LataObject
++{
++public:
++  virtual ~LataObject() {};
++  virtual BigEntier compute_memory_size() const;
++};
++
++// A 'LataDeriv<X> ptr' object can hold an object of class Y which is any derived type of X.
++// The contained object can be accessed via "valeur()" (you get an object of type X)
++//   or "refcast()" (get an object of any derived type Z between X and Y)
++//   (refcast() throws an exception if you try to cast with a wrong type)
++// It can also be null (hold no object). valeur() will then throw an exception.
++// Example:
++//  LataDeriv<X> deriv_x;
++//  Y & y = deriv_x.instancie(Y); // Creates an instance of type Y within deriv_x
++//  X & x = deriv_x.valeur(); // Get a reference to the contained object
++//  Y & y2 = deriv_x.refcast(Y); // Same, but you get a reference of type Y
++//  Z & z = deriv_x.refcast(Z); // Throw an exception if Z is not a derived class of X and a base class of Y
++//  x.reset(); // Destroys the contained object (also destroyed when deriv_x is destroyed)
++#define instancie(x) instancie_(new x)
++#define refcast(x) refcast_((x*) 0)
++
++template <class C>
++class LataDeriv : public LataObject
++{
++public:
++  enum DERIV_ERROR { ERROR_TYPE, ERROR_NULL };
++  LataDeriv() : ptr_(0) { };
++  ~LataDeriv() { delete ptr_; ptr_ = 0; }
++  void reset() { delete ptr_; ptr_ = 0; }
++  entier non_nul() const { return ptr_ != 0; }
++  // operator C &() { return valeur(); }
++  // operator const C &() const { return valeur(); }
++  C & valeur() { if (!ptr_) throw ERROR_NULL; return *ptr_; }
++  const C & valeur() const { if (!ptr_) throw ERROR_NULL; return *ptr_; }
++  template<class DER_C> DER_C & instancie_(DER_C *ptr) {
++    reset();
++    ptr_ = ptr;
++    if (!dynamic_cast<C*>(ptr_)) {
++      delete ptr_;
++      throw ERROR_TYPE; // DER_C is not a derived type of C
++    }
++    return (DER_C &) (*ptr_); 
++  }
++  template<class DER_C> DER_C & refcast_(DER_C *cast_type) {
++    if (!ptr_)
++      throw ERROR_NULL;
++    DER_C * x = dynamic_cast<DER_C *>(ptr_);
++    if (!x)
++      throw ERROR_TYPE;
++    return *x;
++  }
++  BigEntier compute_memory_size() const { if (ptr_) return ptr_->compute_memory_size(); else return 0; }
++protected:
++  LataDeriv(const LataDeriv<C> & c) { ptr_ = 0; operator=(c); }
++  LataDeriv(const C & c) { ptr_ = 0; operator=(c); }
++  LataDeriv<C> & operator=(const LataDeriv<C> &);
++  LataDeriv<C> & operator=(const C &);
++  C *ptr_;
++};
++
++// This is a reference to an object of type C, but thr reference can be null
++template<class C>
++class LataRef
++{
++public:
++  enum REF_ERROR { ERROR_NULL };
++  LataRef() : ptr_(0) { }
++  ~LataRef() { ptr_ = 0; }
++  LataRef(const LataRef<C> & x) : ptr_(x.ptr_) { }
++  LataRef(C & x) : ptr_(&x) { }
++  LataRef<C> & operator=(LataRef<C> & x) { ptr_ = x.ptr_; return *this; }
++  LataRef<C> & operator=(C & x) { ptr_ = &x; return *this; }
++  void reset() { ptr_ = 0; }
++  operator C&() { if (!ptr_) throw ERROR_NULL; return *ptr_; }  
++  C& valeur() { if (!ptr_) throw ERROR_NULL; return *ptr_; }  
++  entier non_nul() const { return ptr_ != 0; }
++protected:
++  C *ptr_;
++};
++
++void array_sort_indirect(const ArrOfInt & array_to_sort, ArrOfInt & index);
++
++class Nom;
++void split_path_filename(const char *full_name, Nom & path, Nom & filename);
++
++// To optimize small loops: replace for(i=0;i<n;i++) with n<=3 by
++//  for (i=0; i<loop_max(n,3); i++) {
++//    loop_instructions();...
++//    break_loop(i,n);
++//  }
++#define loop_max(nloops,max) max
++#define break_loop(index,nloops) if (index >= nloops-1) break
++
++#include <LataJournal.h>
++#include <Motcle.h>
++#include <Noms.h>
++#include <DoubleTab.h>
++#include <IntTab.h>
++#include <FloatTab.h>
++
++Motcles noms_to_motcles(const Noms & noms);
++
++#endif
+diff --git a/databases/readers/Lata/LmlReader.C b/databases/readers/Lata/LmlReader.C
+new file mode 100644
+index 0000000..1b1b7d2
+--- /dev/null
++++ b/databases/readers/Lata/LmlReader.C
+@@ -0,0 +1,435 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#define BUFSZ 1000
++#include <iostream>
++#include <EFichier.h>
++#include <LataDB.h>
++#include <LataFilter.h>
++#include <stdlib.h>
++#include <string.h>
++// lml files contain double precision values that can overflow or underflow
++//  if converted to float. Check for overflow, ignore underflow
++static inline float double_to_float(double x)
++{
++  // Written like this, the code will also stop on NAN values:
++  if (!(x < 1.e38 && x > -1.e38)) {
++    Journal() << "lml reader: Error converting double value " << x << " to float" << endl;
++    throw LataDBError(LataDBError::READ_ERROR);
++  }
++  return (float) x;
++}
++
++// Reads the lml file, fills the lata_db and writes the data (coordinates, elements and
++//  fields data) to a unique file data_filename.
++// The default format used to write data in the data_filename is lata_db.default_type_*
++// data_filename must not contain the path but only a filename with extension.
++// The path to the data file must be set by lata_db.set_path_prefix() before.
++// If data_filename is a null pointer, data files are not written and file offsets in lata_db will
++//  be wrong (useful for just getting metadata)
++void lml_reader(const char * lmlfilename, const char * data_filename, LataDB & lata_db)
++{
++  Nom filename_in_master_file;
++  if (!data_filename)
++    filename_in_master_file = "DATA_NOT_WRITTEN";
++  else
++    filename_in_master_file = data_filename;
++  
++  const entier lmllevel=4;
++  EFichier is;
++  Journal(lmllevel) << "lml_reader: " << endl;
++  is.ouvrir(lmlfilename);
++  if (!is.good()) {
++    Journal() << "Error: cannot open lml file " << lmlfilename << endl;
++    throw;
++  }
++  char s[BUFSZ+1];
++  is.get_istream().getline(s, BUFSZ);
++  if (!is.good()) {
++    Journal() << "Lml file " << lmlfilename << " is empty" << endl;
++    // Just put an empty initial timestep:
++    lata_db.add_timestep(-1.);
++    return;
++  }
++  lata_db.header_ = s;
++  Journal(lmllevel) << "Header: " << s << endl;
++  is.get_istream().getline(s, BUFSZ);
++  lata_db.case_ = s;
++  Journal(lmllevel) << "Case: " << s << endl;
++  is.get_istream().getline(s, BUFSZ);
++  lata_db.software_id_ = s;
++  Journal(lmllevel) << "Software_id: " << s << endl;
++
++  Noms liste_noms_geoms;
++  Noms liste_noms_topo;
++  // Create first timestep (global definitions)
++  lata_db.add_timestep(-1.);
++  // file_offset_blurb:
++  // the file offset will be computed by LataDB::write_data(),
++  // but we must tell write_data() if it must put the data at the beginning
++  //  (file_offset==0) or append the data at the end of the file (file_offset!=0)
++  // file_offset is 0 for the first data block and it is incremented for each block.
++  entier file_offset = 0;
++  LataDBField sommets;
++  FloatTab nodes;
++  while(1) {
++    const entier tstep = lata_db.nb_timesteps() - 1;
++    Motcle motlu;
++    is >> motlu;
++    if (!is.good()) break;
++    if (motlu == "GRILLE") {
++      LataDBGeometry geom;
++      sommets.name_ = "SOMMETS";
++      geom.timestep_ = sommets.timestep_ = tstep;
++      sommets.filename_ = filename_in_master_file;
++      Nom mottmp;
++      is >> mottmp;
++      geom.name_ = ((const char*)mottmp)+7; // retire GRILLE_ du nom
++      Journal(lmllevel) << "lml_reader: GRILLE " << geom.name_ << endl;
++      is >> sommets.nb_comp_;
++      {
++      int tmp;
++      is >> tmp; 
++      sommets.size_ = tmp; // size_ est long long...
++      }
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      sommets.geometry_ = geom.name_;
++      sommets.uname_ = Field_UName(sommets.geometry_, sommets.name_, "");
++      sommets.datatype_ = lata_db.default_type_float();
++      sommets.datatype_.file_offset_ = file_offset++; // see file_offset_blurb
++      nodes.resize(sommets.size_, sommets.nb_comp_);
++      for (entier i = 0; i < sommets.size_; i++)
++        for (entier j = 0; j < sommets.nb_comp_; j++) {
++          double x;
++          is >> x;
++          if (!is.good())
++            throw LataDBError(LataDBError::READ_ERROR);
++          nodes(i,j) = double_to_float(x);
++        }
++      Journal(lmllevel+1) << "Finished reading nodes" << endl;
++      
++      lata_db.add_geometry(geom);
++      // Write nodes to disk later: in 2D they will be cropped
++    } else if (motlu == "TOPOLOGIE") {
++      LataDBField elements;
++      elements.name_ = "ELEMENTS";
++      elements.timestep_ = tstep;
++      elements.filename_ = filename_in_master_file;
++      elements.datatype_ = lata_db.default_type_int_;
++      elements.datatype_.file_offset_ = file_offset++; // see file_offset_blurb
++      Nom ident;
++      is >> ident; // Topologie_MAILLAGE_VOLUMIQUE_XXX
++      Nom mottmp;
++      is >> mottmp;
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      elements.geometry_ = ((const char*)mottmp)+7; // retire GRILLE_ du nom
++      elements.uname_ = Field_UName(elements.geometry_, elements.name_, "");
++      liste_noms_geoms.add(elements.geometry_);
++      liste_noms_topo.add(ident);
++      is >> motlu;
++      if (motlu != "MAILLE") {
++        Journal() << "Error reading TOPOLOGIE: expected MAILLE" << endl;
++        throw;
++      }
++      {
++      int tmp;
++      is >> tmp; // size_ est long long...
++      elements.size_ = tmp;
++      }
++      is >> motlu;
++      int borne_index_min=0;
++      if (motlu == "TETRA4") {
++        lata_db.set_elemtype(tstep, elements.geometry_, "TETRAEDRE");
++        elements.nb_comp_ = 4;
++      } else if (motlu == "TRIANGLE_3D") {
++        elements.nb_comp_ = 3;
++        lata_db.set_elemtype(tstep, elements.geometry_, "TRIANGLE_3D");
++      } else if (motlu == "QUADRANGLE_3D") {
++        elements.nb_comp_ = 4;
++        lata_db.set_elemtype(tstep, elements.geometry_, "QUADRANGLE_3D");
++      } else if (motlu == "VOXEL8") {
++        elements.nb_comp_ = 8;
++        lata_db.set_elemtype(tstep, elements.geometry_, "HEXAEDRE");
++      } else if (motlu == "SEGMENT") {
++        elements.nb_comp_ = 2;
++        lata_db.set_elemtype(tstep, elements.geometry_, "SEGMENT");
++      } else if (motlu == "POINT") {
++        elements.nb_comp_ = 1;
++        lata_db.set_elemtype(tstep, elements.geometry_, "POINT");
++      } else if (motlu == "PRISM6") {
++        lata_db.set_elemtype(tstep, elements.geometry_, "PRISM6");
++        elements.nb_comp_ = 6;
++      } else if (motlu.debute_par("POLYEDRE_")) {
++        lata_db.set_elemtype(tstep, elements.geometry_, motlu);
++        elements.nb_comp_ = atoi(((const char *)motlu) + strlen("polyedre_"));
++        borne_index_min=-1;
++      } else if (motlu.debute_par("POLYGONE_")) {
++        lata_db.set_elemtype(tstep, elements.geometry_, motlu);
++        elements.nb_comp_ = atoi(((const char *)motlu) + strlen("polygone_"));
++        borne_index_min=-1;
++      } else {
++        Journal() << "Error reading TOPOLOGIE: unknown element type" << endl;
++        throw;
++      }
++
++      Journal(lmllevel+1) << " " << elements.size_ << " elements " << motlu << endl;
++      IntTab elems;
++      elems.resize(elements.size_, elements.nb_comp_);
++      for (entier i = 0; i < elements.size_; i++) {
++        if (i != 0) {
++          is >> motlu; // element type
++          if (!is.good())
++            throw LataDBError(LataDBError::READ_ERROR);
++        }
++        entier j;
++        for (j = 0; j < elements.nb_comp_; j++) {
++          is >> elems(i,j);
++          if (!is.good())
++            throw LataDBError(LataDBError::READ_ERROR);
++          elems(i,j)--;
++          if (elems(i,j) < borne_index_min || elems(i,j) >= sommets.size_ ) {
++            Journal() << "Error reading TOPOLOGIE: bad node number elem(" << i << "," << j << ")=" << elems(i,j) << endl;
++            throw;
++          }
++        }
++      }
++      Journal(lmllevel+1) << " finished reading elements" << endl;
++      lata_db.add_field(sommets);
++      if (data_filename)
++        lata_db.write_data(tstep, sommets.uname_, nodes);
++      lata_db.add_field(elements);
++      if (data_filename)
++        lata_db.write_data(tstep, elements.uname_, elems);
++    } else if (motlu == "FACE") {
++      int n;
++      is >> n;
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      Journal(lmllevel+1) << " faces " << n << endl;      
++    } else if (motlu == "TEMPS") {
++      double t;
++      is >> t;
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      lata_db.add_timestep(t);
++      Journal(lmllevel+1) << " new time: " << t << endl;      
++    } else if (motlu == "CHAMPMAILLE" || motlu == "CHAMPPOINT") {
++      LataDBField field;
++      is >> field.name_;
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      Journal(lmllevel+1) << " new field: " << field.name_ << endl;      
++      field.timestep_ = tstep;
++      field.filename_ = filename_in_master_file;
++      if (motlu == "CHAMPMAILLE")
++        field.localisation_ = "ELEM";
++      else
++        field.localisation_ ="SOM";
++      Nom nom_topo;
++      is >> nom_topo;
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++
++      const entier rang_topo = liste_noms_topo.rang(nom_topo);
++      if (rang_topo < 0) {
++        Journal() << "Error reading lml file : unknown topology name " << nom_topo << endl;
++        throw;
++      }
++      field.geometry_ = liste_noms_geoms[rang_topo];
++      Motcle mottmp(field.name_);
++      Motcle tmp2("_");
++      tmp2 += field.localisation_;
++      tmp2 += "_";
++      tmp2 += field.geometry_;
++      mottmp.prefix(tmp2); // Retire _SOM_dom du nom
++      field.name_ = mottmp;
++      field.uname_ = Field_UName(field.geometry_, field.name_, field.localisation_);
++      double t;
++      is >> t; // Unused time value
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      is >> motlu; // Repeat fieldname
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      is >> field.nb_comp_;
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      Nom unit;
++      is >> unit;
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      field.unites_.add(unit);
++      is >> motlu; // type0
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      {
++      int tmp;
++      is >> tmp;
++      field.size_ = tmp; // long long convert
++      }
++      if (!is.good())
++        throw LataDBError(LataDBError::READ_ERROR);
++      // By default, 3 components fields are vectors:
++      if (field.nb_comp_ == 3) {
++        Journal(lmllevel+1) << " 3 components=> say it's a vector" << endl;
++        field.nature_ = LataDBField::VECTOR;
++      } else {
++        field.nature_ = LataDBField::SCALAR;
++      }
++      field.datatype_ = lata_db.default_type_float();
++      field.datatype_.file_offset_ = file_offset++; // see file_offset_blurb
++      FloatTab tab;
++      tab.resize(field.size_, field.nb_comp_);
++      for (entier i = 0; i < field.size_; i++) {
++        entier n;
++        is >> n;
++        if (!is.good())
++          throw LataDBError(LataDBError::READ_ERROR);
++        for (entier j = 0; j < field.nb_comp_; j++) {
++          double x;
++          is >> x;
++          if (!is.good())
++            throw LataDBError(LataDBError::READ_ERROR);
++          tab(i,j) = double_to_float(x);
++        }
++      }
++      Journal(lmllevel+1) << " finished reading field " << field.name_ << endl;
++      lata_db.add_field(field);
++      if (data_filename)
++        lata_db.write_data(tstep, field.uname_, tab);
++    } else if (motlu == "FIN") {
++      break;
++    } else {
++      Journal() << "Error reading lml file, unknown keyword " << motlu << endl;
++      throw;
++    }
++  }
++}
++
++void lml_to_lata(const char *lmlname, const char *latafilename, 
++                 entier ascii, entier fortran_blocs, entier fortran_ordering, entier fortran_indexing)
++{
++  const entier lmllevel=4;
++  Journal(lmllevel) << "lml_to_lata " << lmlname << " -> " << latafilename << endl;
++  LataDB lata_db;
++  Nom dest_prefix, dest_name;
++  LataOptions::extract_path_basename(latafilename, dest_prefix, dest_name);
++  // Nom du fichier .data a ecrire (sans le chemin)
++  Nom datafile(dest_name);
++  datafile += ".lata.data";
++  lata_db.set_path_prefix(dest_prefix);
++  // Nom complet du fichier lml a lire
++  LataDBDataType type;
++  if (ascii)
++    type.msb_ = LataDBDataType::ASCII;
++  else
++    type.msb_ = LataDBDataType::machine_msb_;
++  type.type_ = LataDBDataType::INT32;
++  type.array_index_ = fortran_indexing ? LataDBDataType::F_INDEXING : LataDBDataType::C_INDEXING;
++  type.data_ordering_ = fortran_ordering ? LataDBDataType::F_ORDERING : LataDBDataType::C_ORDERING;
++  type.fortran_bloc_markers_ = fortran_blocs ? LataDBDataType::BLOC_MARKERS_SINGLE_WRITE : LataDBDataType::NO_BLOC_MARKER;
++  type.bloc_marker_type_ = LataDBDataType::INT32;
++  type.file_offset_ = 0;
++  lata_db.default_type_int_ = type;
++  lata_db.default_float_type_ =  LataDBDataType::REAL32;
++  
++  lml_reader(lmlname, datafile, lata_db);
++  Journal(lmllevel) << "lml_to_lata writing lata master file" << endl;
++  lata_db.write_master_file(latafilename);
++}
++
++// Reads lml or lata file into lata_db. lml data is loaded in an internal memory buffer
++//  file: full name with path
++//  path_prefix: the path (used to access lata data files)
++// If dest_file_if_lml is not null, puts lml data into this file...
++// In this case, you must set lata_db.default_type* to tell which format to use.
++void read_any_format(const char * file, const Nom & path_prefix, LataDB & lata_db)
++{
++  // Is it an lml ?
++  Motcle motcle_nom_fic(file);
++  if (motcle_nom_fic.finit_par(".lml")) {
++    Journal(1) << "Detected lml file : " << file << endl;
++    // Nom complet du fichier lml a lire
++    Journal(1) << "Reading lml file to memory buffer" << endl;
++    // data will be put in an internal memory buffer.
++    // choose appropriate data format:
++    LataDBDataType type;
++    type.msb_ = LataDBDataType::machine_msb_;
++    type.type_ = LataDBDataType::INT32;
++    type.array_index_ = LataDBDataType::C_INDEXING;
++    type.data_ordering_ = LataDBDataType::C_ORDERING;
++    type.fortran_bloc_markers_ = LataDBDataType::NO_BLOC_MARKER;
++    type.bloc_marker_type_ = LataDBDataType::INT32;
++    type.file_offset_ = 0;
++    lata_db.default_type_int_ = type;
++    lata_db.default_float_type_ =  LataDBDataType::REAL32;
++    lml_reader(file, LataDBField::memory_buffer_file(), lata_db);
++  } else {
++    Journal(1) << "Detected lata file : " << file << endl;
++    lata_db.read_master_file(path_prefix, file);
++  }
++}
++
++// Description: if the file is a lata file, read the third line and interprets it as options
++//  if lml format, do nothing
++//  otherwise, error.
++void read_any_format_options(const char * file, LataOptions & opt)
++{
++  Motcle nom_fic(file);
++  if (nom_fic.finit_par(".lml")) {
++    // do nothing
++  } else if (nom_fic.finit_par(".med")) {
++        // do nothing
++  } else if (nom_fic.finit_par(".lata")) {
++    Journal(1) << "Lata file: Interpreting LataFilter options on third line" << endl;
++    Nom ligne = LataDB::read_master_file_options(file);
++    const char *s = ligne;
++    while (*s) {
++      Nom toto("");
++      while ((*s) != ' ' && (*s) != 0) {
++        toto += Nom(*s);
++        s++;
++      }
++      if ((toto != "Trio_U")&&(toto != "TRUST" )) {
++        if (!opt.parse_option(toto)) {
++          Journal(0) << "Interpreting option: " << toto <<"  Failed." << endl;
++          throw LataDBError::BAD_HEADER;
++        } else
++          Journal(1) << "Interpreting option: " << toto <<"  Success." << endl;
++      }
++      while ((*s) == ' ')
++        s++;
++    }
++  } else {
++    Journal(0) << "read_any_format_options: file " << nom_fic << " has unsupported extension" << endl;
++    throw LataDBError::BAD_HEADER;
++  }
++}
+diff --git a/databases/readers/Lata/LmlReader.h b/databases/readers/Lata/LmlReader.h
+new file mode 100644
+index 0000000..9a37ab5
+--- /dev/null
++++ b/databases/readers/Lata/LmlReader.h
+@@ -0,0 +1,38 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef LMLREADER_H
++#define LMLREADER_H
++void lml_reader(const char * lmlfilename, const char * data_filename, LataDB & lata_db);
++void lml_to_lata(const char *lmlfilename, const char *latafilename, 
++                 entier ascii = 0, entier fortran_blocs = 1, entier fortran_ordering = 0, entier fortran_indexing = 1);
++void read_any_format(const char * file, const Nom & path_prefix, LataDB & lata_db);
++void read_any_format_options(const char * file, LataOptions & opt);
++#endif
++
+diff --git a/databases/readers/Lata/Motcle.C b/databases/readers/Lata/Motcle.C
+new file mode 100644
+index 0000000..4227be6
+--- /dev/null
++++ b/databases/readers/Lata/Motcle.C
+@@ -0,0 +1,142 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <Motcle.h>
++#include <string.h>
++#include <istream>
++#include <ostream>
++#include <string>
++Nom& Nom::majuscule()
++{
++  const int n = longueur()-1;
++  for (int i = 0; i < n; i++)
++    {
++      char c = s_[i];
++      if (c >= 'a' && c <= 'z')
++        s_[i] = c + 'A' - 'a';
++    }
++  return *this;
++}
++
++static inline char char_uppercase(char c)
++{
++  if (c >= 'a' && c <= 'z')
++    c += 'A' - 'a';
++  return c;
++}
++
++
++// opt=0 => comparaison des chaines completes
++// opt=1 => le debut de n1 doit etre egal a n2
++int Motcle::strcmp_uppercase(const char *n1, const char *n2, int opt)
++{
++  entier i = 0;
++  unsigned char c1, c2;
++  entier delta;
++  do
++    {
++      c1 = (unsigned char) char_uppercase(n1[i]);
++      c2 = (unsigned char) char_uppercase(n2[i]);
++      delta = c1 - c2;
++      i++;
++      if (c2 == 0 && opt == 1)
++        {
++          // Fin de la deuxieme chaine et opt=1 (fonction "debute_par"):
++          // Test ok
++          return 0;
++        }
++    }
++  while ((delta == 0) && (c1 != 0) && (c2 != 0));
++  return delta;
++}
++
++int Nom::debute_par(const char * s) const
++{
++  const int l1 = longueur()-1;
++  const int l2 = (int)strlen(s);
++  return (l1>=l2) ? (strncmp(s_.c_str(), s, l2) == 0) : 0;
++}
++
++int Nom::finit_par(const char * s) const
++{
++  const int l1 = longueur()-1;
++  const int l2 = (int)strlen(s);
++  return (l1>=l2) ? (strncmp(s_.c_str()+(l1-l2), s, l2) == 0) : 0;
++}
++
++entier Nom::find(const char * n) const
++{
++  std::size_t x = s_.find(n);
++  return (x != std::string::npos) ? x : -1;
++}
++
++Nom& Nom::prefix(const char *s)
++{
++  if (finit_par(s))
++    {
++      entier n = strlen(s_.c_str());
++      entier n2 = strlen(s);
++      s_.erase(n-n2,n2);
++    }
++  return *this;
++}
++
++int Motcle::debute_par(const char * s) const
++{
++  return (strcmp_uppercase(s_.c_str(), s, 1) == 0);
++}
++
++int Motcle::finit_par(const char * s) const
++{
++  const int l1 = longueur()-1;
++  const int l2 = (int)strlen(s);
++  return (l1>=l2) ? (strcmp_uppercase(s_.c_str()+(l1-l2), s) == 0) : 0;
++}
++
++Motcles noms_to_motcles(const Noms& a)
++{
++  Motcles b;
++  entier n = a.size();
++  for (entier i = 0; i < n; i++)
++    b.add() = a[i]; // ouais, ecriture bizarre mais la plus efficace...
++  return b;
++}
++
++std::istream& operator>>(std::istream& is, Nom& nom)
++{
++  nom.read(is);
++  return is;
++}
++
++std::ostream& operator<<(std::ostream& os, const Nom& nom)
++{
++  nom.write(os);
++  return os;
++}
++
+diff --git a/databases/readers/Lata/Motcle.h b/databases/readers/Lata/Motcle.h
+new file mode 100644
+index 0000000..e1a992d
+--- /dev/null
++++ b/databases/readers/Lata/Motcle.h
+@@ -0,0 +1,150 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef LataMotcle_H
++#define LataMotcle_H
++#include <string>
++#include <iostream>
++#include <LataVector.h>
++#include <arch.h>
++// pour gcc 2.96:
++#include <stdio.h>
++
++class Motcle;
++
++class Nom
++{
++public:
++  Nom()
++  {
++    s_ = "??";
++  };
++
++
++
++  Nom(std::string str)
++  {
++    s_ = str;
++  }
++
++  inline const std::string& getString() const { return s_; }
++
++  virtual ~Nom() { };
++  Nom(const char * nom)  : s_(nom) { };
++  Nom(char c)
++  {
++    s_ = c;
++  };
++  Nom(int i)
++  {
++    char s[30];
++    sprintf(s, "%d", i);
++    s_ = s;
++  }
++  operator const char *() const
++  {
++    return s_.c_str();
++  }
++  virtual Nom& operator=(const char * nom)
++  {
++    s_ = nom;
++    return *this;
++  }
++  virtual entier longueur() const
++  {
++    return static_cast<entier>(s_.length())+1; /*ATTENTION: +1 pour compatibilite avec TRUST*/
++  }
++  virtual void read(std::istream& is)
++  {
++    is >> s_;
++  }
++  virtual void write(std::ostream& os) const
++  {
++    os << s_;
++  }
++  virtual int operator==(const char * s) const
++  {
++    return (s_ == s);
++  }
++  virtual int operator!=(const char * s) const
++  {
++    return !operator==(s);
++  }
++  virtual Nom& operator+=(const char * n)
++  {
++    s_ += n;
++    return *this;
++  }
++  virtual entier find(const char * n) const;
++  virtual int debute_par(const char * s) const;
++  virtual int finit_par(const char * s) const;
++  virtual Nom& prefix(const char * s);
++  Nom&          majuscule();
++protected:
++  friend class Motcle;
++  std::string s_;
++};
++
++class Motcle : public Nom
++{
++public:
++  Motcle() {};
++  Motcle(const char * s) : Nom(s) {};
++  Motcle(const Nom& n) : Nom(n) {};
++  ~Motcle() {};
++  int operator==(const char * s) const
++  {
++    return (strcmp_uppercase(s_.c_str(), s) == 0);
++  }
++  int operator!=(const char * s) const
++  {
++    return !operator==(s);
++  }
++  Motcle& operator+=(const char * n)
++  {
++    s_ += n;
++    return *this;
++  }
++  int debute_par(const char * s) const;
++  int finit_par(const char * s) const;
++
++  static int strcmp_uppercase(const char * s1, const char * s2, int opt = 0);
++  virtual entier find(const char * n) const
++  {
++    return Nom(*this).majuscule().find(Nom(n).majuscule());
++  }
++};
++
++typedef LataVector<Motcle> Motcles;
++typedef LataVector<Nom> Noms;
++
++std::istream& operator>>(std::istream& is, Nom& nom);
++std::ostream& operator<<(std::ostream& os, const Nom& nom);
++
++#endif
+diff --git a/databases/readers/Lata/Noms.h b/databases/readers/Lata/Noms.h
+new file mode 100644
+index 0000000..d9231d2
+--- /dev/null
++++ b/databases/readers/Lata/Noms.h
+@@ -0,0 +1,29 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
+diff --git a/databases/readers/Lata/Objet_U.h b/databases/readers/Lata/Objet_U.h
+new file mode 100644
+index 0000000..1f63425
+--- /dev/null
++++ b/databases/readers/Lata/Objet_U.h
+@@ -0,0 +1,41 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++// Class declared for compatibility with TRUST
++#ifndef Objet_U_inclu
++#define Objet_U_inclu
++#include <LataJournal.h>
++#include <Sortie.h>
++#include <Entree.h>
++#include <math.h>
++
++#define Cerr Journal()
++#define finl std::endl
++
++#endif
+diff --git a/databases/readers/Lata/Octree_Double.C b/databases/readers/Lata/Octree_Double.C
+new file mode 100644
+index 0000000..f7cb229
+--- /dev/null
++++ b/databases/readers/Lata/Octree_Double.C
+@@ -0,0 +1,395 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <Octree_Double.h>
++#include <DoubleTab.h>
++#include <FloatTab.h>
++
++Octree_Double::Octree_Double()
++{
++  dim_ = 0;
++}
++
++void Octree_Double::reset()
++{
++  dim_ = 0;
++  octree_int_.reset();
++  origin_.reset();
++  factor_.reset();
++}
++
++// Description: Convertit une coordonnees reele en coordonnee entiere pour l'octree_int
++// Valeur de retour: 1 si ok, 0 si coordonnee hors de l'octree
++inline entier Octree_Double::integer_position(double x, entier direction, entier& ix) const
++{
++  const double coord_max = (double) Octree_Int::coord_max_;
++  double rnd_x = (x - origin_[direction]) * factor_[direction];
++  // 0.49 permet d'accepter une coordonnee x egale a xmin ou xmax de l'octree,
++  //  sinon pour un octree cree a partir de sommets, il y a un risque
++  //  de ne pas trouver les coordonnees des points qu'on avait mis au bord de l'octree.
++  if (rnd_x >= -0.49 && rnd_x <= coord_max + 0.49)
++    {
++      ix = (entier) floor(rnd_x + 0.5);
++      return 1;
++    }
++  return 0;
++}
++
++// Valeur de retour: 1 s'il y a une intersection non vide avec l'octree, 0 sinon
++inline entier Octree_Double::integer_position_clip(double xmin, double xmax,
++    entier& x0, entier& x1,
++    entier direction) const
++{
++  const double coord_max = (double) Octree_Int::coord_max_;
++  xmin = (xmin - origin_[direction]) * factor_[direction];
++  xmax = (xmax - origin_[direction]) * factor_[direction];
++  // pas de marge ici comme on cherche avec une boite, l'epsilon est deja
++  // dans la dimension de la boite.
++  if (xmin > coord_max || xmax < 0.)
++    return 0;
++  if (xmin < .0)
++    x0 = 0;
++  else
++    x0 = (entier) (floor(xmin+0.5));
++  if (xmax > coord_max)
++    x1 = Octree_Int::coord_max_;
++  else
++    x1 = (entier) (floor(xmax+0.5));
++  return 1;
++}
++
++// Description: cherche les elements ou les points contenus dans l'octree_floor qui
++//  contient le point (x,y,z). Renvoie le nombre n de ces elements.
++//  Les indices des elements sont dans floor_elements()[index+i] pour 0 <= i < n
++entier Octree_Double::search_elements(double x, double y, double z, entier& index) const
++{
++  if (dim_ == 0)
++    return 0; // octree vide
++  entier ix = 0, iy = 0, iz = 0;
++  entier ok = integer_position(x, 0, ix)
++              && integer_position(y, 1, iy)
++              && integer_position(z, 2, iz);
++  if (ok)
++    {
++      return octree_int_.search_elements(ix, iy, iz, index);
++    }
++  else
++    {
++      return 0;
++    }
++}
++
++// Description: methode outil pour build_nodes et build_elements
++//  (calcul des facteurs de conversion entre reels et entiers pour Octree_Int
++void Octree_Double::compute_origin_factors(const DoubleTab& coords,
++    const double epsilon,
++    const entier include_virtual)
++{
++  // Recherche des coordonnees min et max du domaine
++  const entier nb_som = include_virtual ? coords.dimension_tot(0) : coords.dimension(0);
++  if (nb_som == 0)
++    return; // octree vide
++
++  const entier dim = coords.dimension(1);
++  dim_ = dim;
++  origin_.resize_array(3);
++  factor_.resize_array(3);
++  ArrOfDouble xmin(dim, 1.e37);
++  ArrOfDouble xmax(dim, -1.e-37);
++  assert(dim >= 1 && dim <= 3);
++  entier i, j;
++  for (i = 0; i < nb_som; i++)
++    {
++      for (j = 0; j < dim; j++)
++        {
++          const double x = coords(i, j);
++          if (x < xmin[j])
++            xmin[j] = x;
++          if (x > xmax[j])
++            xmax[j] = x;
++        }
++    }
++  const double coord_max = (double) Octree_Int::coord_max_;
++  for (j = 0; j < dim; j++)
++    {
++      xmin[j] -= epsilon;
++      xmax[j] += epsilon;
++      origin_[j] = xmin[j];
++      if (xmax[j] - xmin[j] > 0.)
++        {
++          factor_[j] = coord_max / (xmax[j] - xmin[j]);
++        }
++      else
++        factor_[j] = 0.;
++    }
++}
++void Octree_Double::compute_origin_factors(const FloatTab& coords,
++    const double epsilon,
++    const entier include_virtual)
++{
++  // Recherche des coordonnees min et max du domaine
++  const entier nb_som = include_virtual ? coords.dimension_tot(0) : coords.dimension(0);
++  if (nb_som == 0)
++    return; // octree vide
++
++  const entier dim = coords.dimension(1);
++  dim_ = dim;
++  origin_.resize_array(3);
++  factor_.resize_array(3);
++  ArrOfDouble xmin(dim, 1.e37);
++  ArrOfDouble xmax(dim, -1.e-37);
++  assert(dim >= 1 && dim <= 3);
++  entier i, j;
++  for (i = 0; i < nb_som; i++)
++    {
++      for (j = 0; j < dim; j++)
++        {
++          const double x = coords(i, j);
++          if (x < xmin[j])
++            xmin[j] = x;
++          if (x > xmax[j])
++            xmax[j] = x;
++        }
++    }
++  const double coord_max = (double) Octree_Int::coord_max_;
++  for (j = 0; j < dim; j++)
++    {
++      xmin[j] -= epsilon;
++      xmax[j] += epsilon;
++      origin_[j] = xmin[j];
++      if (xmax[j] - xmin[j] > 0.)
++        {
++          factor_[j] = coord_max / (xmax[j] - xmin[j]);
++        }
++      else
++        factor_[j] = 0.;
++    }
++}
++
++// Description: construit un octree contenant les points de coordonnees coords.
++//  Si include_virtual=1, on stocke coords.dimension_tot(0) elements, sinon on en
++//  stocke coords.dimension(0)
++void Octree_Double::build_nodes(const DoubleTab& coords, const entier include_virtual)
++{
++  octree_int_.reset();
++  compute_origin_factors(coords, 0. /* epsilon */, include_virtual);
++  const entier nb_som = include_virtual ? coords.dimension_tot(0) : coords.dimension(0);
++  if (nb_som == 0)
++    return; // octree vide
++  const entier dim = coords.dimension(1);
++  IntTab elements_boxes(nb_som, dim);
++  for (entier i = 0; i < nb_som; i++)
++    {
++      for (entier j = 0; j < dim; j++)
++        {
++          entier pos1 = 0;
++          const double x = coords(i, j);
++          if (!integer_position(x, j, pos1))
++            {
++              Cerr << "Fatal error in octree : integer position outside octree" << finl;
++              throw;
++            }
++          elements_boxes(i, j) = pos1;
++        }
++    }
++  octree_int_.build(dim, elements_boxes);
++}
++
++// Description: Construit un octree a partir d'elements volumiques decrits par des
++//  ensembles de sommets. On stocke dans l'octree les parallelipipdes englobant chaque
++//  element (contenant tous les sommets de l'element) plus une marge de epsilon.
++//  Si include_virtual=1, on stocke elements.dimension_tot(0) elements, sinon on en
++//  stocke elements.dimension(0)
++void Octree_Double::build_elements(const DoubleTab& coords, const IntTab& elements,
++                                   const double epsilon, const entier include_virtual)
++{
++  octree_int_.reset();
++  compute_origin_factors(coords, epsilon, include_virtual);
++
++  const entier nb_elems = include_virtual ? elements.dimension_tot(0) : elements.dimension(0);
++  const entier nb_som_elem = elements.dimension(1);
++  const entier dim = coords.dimension(1);
++  IntTab elements_boxes(nb_elems, dim * 2);
++  for (entier i = 0; i < nb_elems; i++)
++    {
++      for (entier j = 0; j < dim; j++)
++        {
++          double xmin = 1.e37;
++          double xmax = -1.e37;
++          for (entier k = 0; k < nb_som_elem; k++)
++            {
++              const entier som = elements(i, k);
++                        if (som>=0) { // polyedre som peut valoir -1
++              const double x = coords(som, j);
++              xmin = (x<xmin) ? x : xmin;
++              xmax = (x>xmax) ? x : xmax;
++                        }
++            }
++          entier pos1 = 0, pos2 = 0;
++          if (!integer_position(xmin, j, pos1) || !integer_position(xmax, j, pos2))
++            {
++              Cerr << "Fatal error in octree : integer position outside octree" << finl;
++              throw;
++            }
++          elements_boxes(i, j) = pos1;
++          elements_boxes(i, j+dim) = pos2;
++        }
++    }
++  octree_int_.build(dim, elements_boxes);
++}
++
++void Octree_Double::build_elements(const FloatTab& coords, const IntTab& elements,
++                                   const double epsilon, const entier include_virtual)
++{
++  octree_int_.reset();
++  compute_origin_factors(coords, epsilon, include_virtual);
++
++  const entier nb_elems = include_virtual ? elements.dimension_tot(0) : elements.dimension(0);
++  const entier nb_som_elem = elements.dimension(1);
++  const entier dim = coords.dimension(1);
++  IntTab elements_boxes(nb_elems, dim * 2);
++  for (entier i = 0; i < nb_elems; i++)
++    {
++      for (entier j = 0; j < dim; j++)
++        {
++          double xmin = 1.e37;
++          double xmax = -1.e37;
++          for (entier k = 0; k < nb_som_elem; k++)
++            {
++              const entier som = elements(i, k);
++                        if (som>=0) { // polyedre som peut valoir -1
++              const double x = coords(som, j);
++              xmin = (x<xmin) ? x : xmin;
++              xmax = (x>xmax) ? x : xmax;
++                        }
++            }
++          entier pos1 = 0, pos2 = 0;
++          if (!integer_position(xmin, j, pos1) || !integer_position(xmax, j, pos2))
++            {
++              Cerr << "Fatal error in octree : integer position outside octree" << finl;
++              throw;
++            }
++          elements_boxes(i, j) = pos1;
++          elements_boxes(i, j+dim) = pos2;
++        }
++    }
++  octree_int_.build(dim, elements_boxes);
++}
++
++// Description: cherche tous les elements ou points ayant potentiellement une intersection
++//  non vide avec la boite donnee.
++entier Octree_Double::search_elements_box(double xmin, double ymin, double zmin,
++    double xmax, double ymax, double zmax,
++    ArrOfInt& elements) const
++{
++  const entier dim = dim_;
++  if (dim == 0)
++    {
++      elements.resize_array(0);
++      return 0;
++    }
++  entier x0 = 0, x1 = 0, y0 = 0, y1 = 0, z0 = 0, z1 = 0;
++  entier ok = integer_position_clip(xmin, xmax, x0, x1, 0);
++  if (ok && dim >= 1)
++    {
++      ok = integer_position_clip(ymin, ymax, y0, y1, 1);
++      if (ok && dim >= 2)
++        ok = integer_position_clip(zmin, zmax, z0, z1, 2);
++    }
++  if (ok)
++    octree_int_.search_elements_box(x0, y0, z0, x1, y1, z1, elements);
++  else
++    elements.resize_array(0);
++  return elements.size_array();
++}
++
++// Description: cherche tous les elements ou points ayant potentiellement une intersection
++//  non vide avec la boite donnee (centre + ou - radius dans chaque direction)
++entier Octree_Double::search_elements_box(const ArrOfDouble& center, const double radius,
++    ArrOfInt& elements) const
++{
++  entier dim = center.size_array();
++  double x = center[0];
++  double y = (dim>=2) ? center[1] : 0.;
++  double z = (dim>2) ? center[2] : 0.;
++  entier i = search_elements_box(x-radius, y-radius, z-radius,
++                                 x+radius, y+radius, z+radius,
++                                 elements);
++  return i;
++}
++
++// Description: Methode hors classe
++//  Cherche parmi les sommets de la liste node_list ceux qui sont a une
++//  distance inferieure a epsilon du point (x,y,z). node_list contient des indices de
++//  sommets dans le tableau coords. La liste des noeuds verifiant le critere est mise
++//  dans node_list. On renvoie l'indice dans le tableau coords du sommet le plus proche.
++entier Octree_Double::search_nodes_close_to(double x, double y, double z,
++    const DoubleTab& coords, ArrOfInt& node_list,
++    double epsilon)
++{
++  const entier n = node_list.size_array();
++  double eps2 = epsilon * epsilon;
++  entier count = 0;
++  const entier dim = coords.dimension(1);
++  double dmin = eps2;
++  entier nearest = -1;
++  for (entier i = 0; i < n; i++)
++    {
++      const entier som = node_list[i];
++      double dx = x - coords(som, 0);
++      double dy = (dim >= 2) ? y - coords(som, 1) : 0.;
++      double dz = (dim >= 3) ? z - coords(som, 2) : 0.;
++      double d2 = dx * dx + dy * dy + dz * dz;
++      if (d2 < eps2)
++        {
++          node_list[count] = som;
++          if (d2 < dmin)
++            {
++              dmin = d2;
++              nearest = som;
++            }
++          count++;
++        }
++    }
++  node_list.resize_array(count);
++  return nearest;
++}
++
++// Description: Idem que search_nodes_close_to(double x, double y, double z, ...)
++entier Octree_Double::search_nodes_close_to(const ArrOfDouble& point,
++    const DoubleTab& coords, ArrOfInt& node_list,
++    double epsilon)
++{
++  entier dim = point.size_array();
++  double x = point[0];
++  double y = (dim>=2) ? point[1] : 0.;
++  double z = (dim>2) ? point[2] : 0.;
++  entier i = search_nodes_close_to(x, y, z, coords, node_list, epsilon);
++  return i;
++}
+diff --git a/databases/readers/Lata/Octree_Double.h b/databases/readers/Lata/Octree_Double.h
+new file mode 100644
+index 0000000..abf3258
+--- /dev/null
++++ b/databases/readers/Lata/Octree_Double.h
+@@ -0,0 +1,89 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++
++#ifndef Octree_Double_inclu
++#define Octree_Double_inclu
++#include <Octree_Int.h>
++#include <ArrOfDouble.h>
++class DoubleTab;
++class FloatTab;
++
++// .DESCRIPTION : Un octree permettant de chercher dans l'espace des elements ou des points
++//  decrits par des coordonnees reeles. Cet objet est base sur Octree_Int.
++class Octree_Double
++{
++public:
++  Octree_Double();
++  void   reset();
++  void   build_elements(const FloatTab& coords, const IntTab& elements,
++                        const double epsilon, const entier include_virtual);
++  void   build_elements(const DoubleTab& coords, const IntTab& elements,
++                        const double epsilon, const entier include_virtual);
++  void   build_nodes(const DoubleTab& coords, const entier include_virtual);
++  entier search_elements(double x, double y, double z, entier& index) const;
++  entier search_elements_box(double xmin, double ymin, double zmin,
++                             double xmax, double ymax, double zmax,
++                             ArrOfInt& elements) const;
++  static entier search_nodes_close_to(double x, double y, double z,
++                                      const DoubleTab& coords, ArrOfInt& node_list,
++                                      double epsilon);
++  entier search_elements_box(const ArrOfDouble& center, const double radius,
++                             ArrOfInt& elements) const;
++  static entier search_nodes_close_to(const ArrOfDouble& point,
++                                      const DoubleTab& coords, ArrOfInt& node_list,
++                                      double epsilon);
++  entier dimension() const
++  {
++    assert(dim_ > 0);
++    return dim_;
++  }
++  inline const ArrOfInt& floor_elements() const
++  {
++    return octree_int_.floor_elements();
++  };
++protected:
++  inline entier integer_position(double x, entier direction, entier& ix) const;
++  inline entier integer_position_clip(double xmin, double xmax,
++                                      entier& x0, entier& x1,
++                                      entier direction) const;
++  void compute_origin_factors(const DoubleTab& coords,
++                              const double epsilon,
++                              const entier include_virtual);
++  void compute_origin_factors(const FloatTab& coords,
++                              const double epsilon,
++                              const entier include_virtual);
++
++  Octree_Int octree_int_;
++  // Ces deux tableaux sont toujours de taille 3 par commodite
++  ArrOfDouble origin_;
++  ArrOfDouble factor_;
++  entier dim_;
++};
++#endif
+diff --git a/databases/readers/Lata/Octree_Int.C b/databases/readers/Lata/Octree_Int.C
+new file mode 100644
+index 0000000..4f96b7c
+--- /dev/null
++++ b/databases/readers/Lata/Octree_Int.C
+@@ -0,0 +1,485 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <Octree_Int.h>
++#include <ArrOfBit.h>
++
++static const entier max_levels_ = 32; // 1 de plus que le nombre de bits=1 dans coords_max
++// La valeur suivante doit etre une puissance de deux
++const entier Octree_Int::root_octree_half_width_ = 1073741824; /* 2^30   = 0100 0000  0000 0000  0000 0000  0000 0000b */
++// La valeur suivante doit etre egale a (root_octree_half_width_ * 2 - 1)
++const entier Octree_Int::coord_max_ = 2147483647;              /* 2^31-1 = 0111 1111  1111 1111  1111 1111  1111 1111b */
++
++// Description: construction d'un octree_id (voir octree_structure_)
++//  Si type==EMPTY, on l'octree_id est 0
++//  Si type==OCTREE, on suppose que index est un indice dans octree_structure_
++//  Si type==FLOOR, on suppose que index est un indice dans floor_elements_
++inline entier Octree_Int::octree_id(entier index, Octree_Type type)
++{
++  switch(type)
++    {
++    case EMPTY:
++      return 0;
++    case OCTREE:
++      return index + 1;
++    case FLOOR:
++      return - index - 1;
++    }
++  return -1;
++}
++
++// Description: calcul de l'index de l'octree dans octree_structure ou floor_elements
++//  en fonction du type de l'octree et de son octree_id.
++//  En general on a deja determine le type avant, on le passe en parametre pour optimiser.
++inline entier Octree_Int::octree_index(entier octree_id, Octree_Type type)
++{
++  assert(type==octree_type(octree_id));
++  switch(type)
++    {
++    case EMPTY:
++      return -1;
++    case OCTREE:
++      return octree_id - 1;
++    case FLOOR:
++      return - octree_id - 1;
++    }
++  return -1;
++}
++
++// Description: Renvoie le type d'un octree en fonction de son octree_id.
++inline Octree_Int::Octree_Type Octree_Int::octree_type(entier octree_id)
++{
++  if (octree_id > 0)
++    return OCTREE;
++  else if (octree_id == 0)
++    return EMPTY;
++  else
++    return FLOOR;
++}
++
++// Description: construction de l'octree. On donne la dimension (1, 2 ou 3)
++//  et un tableau d'elements a stocker dans l'octree. Deux possibilites:
++//  1) les elements sont ponctuels si elements_boxes.dimension(1) == dimension.
++//     Dans ce cas, chaque element se trouve dans un et un seul octree_floor
++//  2) les elements sont des parallelipipedes, si elements_boxes.dimension(1) == dimension*2
++//     Les "dimension" premieres colonnes sont les coordonnees inferieures,
++//     les "dimension" suivantes sont les coordonnees superieures.
++//     Un parallelipipede peut etre affecte a plusieurs octree_floor.
++//  Les coordonnees stockees dans elements_boxes peuvent aller de 0 a coord_max_ inclus.
++//  Il vaut mieux utiliser toute la plage des entiers en multipliant par un facteur adequat.
++void Octree_Int::build(const entier dimension, const IntTab& elements_boxes)
++{
++  assert(dimension >= 1 && dimension <= 3);
++  assert(elements_boxes.dimension(1) == dimension
++         || elements_boxes.dimension(1) == dimension * 2 );
++
++  const entier nb_elems = elements_boxes.dimension(0);
++  nb_elements_ = nb_elems;
++  entier i;
++  octree_structure_.set_smart_resize(1);
++  floor_elements_.set_smart_resize(1);
++  floor_elements_.resize_array(0);
++  const entier nb_octrees = 1 << dimension;
++  octree_structure_.resize(0, nb_octrees);
++
++  assert(elements_boxes.size_array() == 0
++         || (min_array(elements_boxes) >= 0 && max_array(elements_boxes) <= coord_max_));
++
++  VECT(ArrOfInt) tmp_elem_flags(max_levels_);
++  VECT(ArrOfInt) tmp_elem_list(max_levels_);
++  for (i = 0; i < max_levels_; i++)
++    {
++      tmp_elem_flags[i].set_smart_resize(1);
++      tmp_elem_list[i].set_smart_resize(1);
++    }
++  ArrOfInt& elements_list = tmp_elem_list[0];
++  elements_list.resize_array(nb_elems);
++  for (entier i = 0; i < nb_elems; i++)
++    elements_list[i] = i;
++
++  root_octree_id_ = build_octree_recursively(root_octree_half_width_,root_octree_half_width_,root_octree_half_width_,
++                    root_octree_half_width_,
++                    elements_boxes,
++                    tmp_elem_list,
++                    0,
++                    tmp_elem_flags);
++}
++
++// Description: renvoie la liste des elements contenant potentiellement le point (x,y,z)
++//  On renvoie n=nombre d'elements de la liste et les elements sont dans
++//  floor_elements()[index+i] pour 0 <= i < n.
++//  En realite on renvoie tous les elements qui ont une intersection non vide avec l'octree_floor
++//  contenant le point (x,y,z)
++entier Octree_Int::search_elements(entier x, entier y, entier z, entier& index) const
++{
++  const entier nb_octrees = octree_structure_.dimension(1);
++  if (nb_octrees == 2)
++    y = 0; // important pour ne pas tomber sur des cubes inexistants
++  if (nb_octrees <= 4)
++    z = 0; // idem
++  assert(x >= 0 && x <= coord_max_);
++  assert(y >= 0 && y <= coord_max_);
++  assert(z >= 0 && z <= coord_max_);
++
++  const entier octree_id = search_octree_floor(x, y, z);
++
++  if (octree_type(octree_id) == EMPTY)
++    {
++      return 0;
++    }
++  const entier idx = octree_index(octree_id, FLOOR);
++  const entier n = floor_elements_[idx];
++  index = idx + 1;
++  return n;
++}
++
++struct IntBoxData
++{
++  IntBoxData(entier xmin, entier ymin, entier zmin,
++             entier xmax, entier ymax, entier zmax,
++             ArrOfInt& elements,
++             ArrOfBit *markers) :
++    xmin_(xmin), ymin_(ymin), zmin_(zmin),
++    xmax_(xmax), ymax_(ymax), zmax_(zmax),
++    elements_(elements),
++    markers_(markers) { };
++  entier xmin_, ymin_, zmin_;
++  entier xmax_, ymax_, zmax_;
++  ArrOfInt& elements_;
++  ArrOfBit *markers_;
++};
++
++// Description: cherche les elements ayant potentiellement une intersection non vide avec la
++//  boite xmin..zmax. Le tableau elements doit etre de type smart_resize(1).
++//  Les elements peuvent apparaitre plusieurs fois dans le tableau "elements"
++entier Octree_Int::search_elements_box(entier xmin, entier ymin, entier zmin,
++                                       entier xmax, entier ymax, entier zmax,
++                                       ArrOfInt& elements) const
++{
++  const entier nb_octrees = octree_structure_.dimension(1);
++  if (nb_octrees == 2)
++    ymin = ymax = 0; // important pour ne pas tomber sur des cubes inexistants
++  if (nb_octrees <= 4)
++    zmin = zmax = 0; // idem
++  assert(xmin >= 0 && xmin <= coord_max_);
++  assert(ymin >= 0 && ymin <= coord_max_);
++  assert(zmin >= 0 && zmin <= coord_max_);
++  assert(xmax >= 0 && xmax <= coord_max_);
++  assert(ymax >= 0 && ymax <= coord_max_);
++  assert(zmax >= 0 && zmax <= coord_max_);
++
++  elements.resize_array(0);
++  IntBoxData boxdata(xmin, ymin, zmin, xmax, ymax, zmax, elements, 0);
++  switch(octree_type(root_octree_id_))
++    {
++    case FLOOR:
++      search_elements_box_floor(boxdata, root_octree_id_);
++      break;
++    case OCTREE:
++      search_elements_box_recursively(boxdata, root_octree_id_,
++                                      root_octree_half_width_,root_octree_half_width_,root_octree_half_width_,
++                                      root_octree_half_width_);
++      break;
++    case EMPTY:
++      break;
++    }
++  const entier n = elements.size_array();
++  return n;
++}
++
++// Description: ajoute des elements de l'octree_floor a boxdata.elements_
++void Octree_Int::search_elements_box_floor(IntBoxData& boxdata,
++    entier octree_floor_id) const
++{
++  const entier idx = octree_index(octree_floor_id, FLOOR);
++  const entier n = floor_elements_[idx];
++  if (boxdata.markers_)
++    for (entier i = 0; i < n; i++)
++      {
++        const entier elem = floor_elements_[idx+1+i];
++        if (!boxdata.markers_->testsetbit(elem))
++          boxdata.elements_.append_array(elem);
++      }
++  else
++    for (entier i = 0; i < n; i++)
++      {
++        const entier elem = floor_elements_[idx+1+i];
++        boxdata.elements_.append_array(elem);
++      }
++}
++
++// Pour chaque direction, drapeaux des cubes de la rangee inferieure
++static entier sub_cube_flags_min[3] = { 1+4+16+64, /* drapeaux des cubes 0,2,4,6 */
++                                        1+2+16+32, /* drapeaux des cubes 0,1,4,5 */
++                                        1+2+4+8    /* drapeaux des cubes 0,1,2,3 */
++                                      };
++static entier sub_cube_flags_max[3] = { 2+8+32+128, /* drapeaux des cubes 1,3,5,7 */
++                                        4+8+64+128, /* drapeaux des cubes 2,3,7,8 */
++                                        16+32+64+128 /* drapeaux des cubes 4,5,6,7 */
++                                      };
++
++// Description: cherche recursivement les elements inclus dans la boite
++//  boxdata pour l'octree_id donne, de centre cx, cy, cz.
++
++void Octree_Int::search_elements_box_recursively(IntBoxData& boxdata,
++    entier octree_id,
++    entier cx, entier cy, entier cz,
++    entier half_width) const
++{
++  entier flags = 255;
++  if (cx > boxdata.xmax_) // les cubes superieurs en x ne sont pas dedans
++    flags &= sub_cube_flags_min[0];
++  if (cx <= boxdata.xmin_) // les cubes inferieurs ne sont pas dedans
++    flags &= sub_cube_flags_max[0];
++  if (cy > boxdata.ymax_)
++    flags &= sub_cube_flags_min[1];
++  if (cy <= boxdata.ymin_)
++    flags &= sub_cube_flags_max[1];
++  if (cz > boxdata.zmax_)
++    flags &= sub_cube_flags_min[2];
++  if (cz <= boxdata.zmin_)
++    flags &= sub_cube_flags_max[2];
++  entier test_flag = 1;
++  const entier idx = octree_index(octree_id, OCTREE);
++  const entier half_width_2 = half_width >> 1;
++  const entier mhalf_width = - half_width_2;
++  entier cx2, cy2, cz2;
++  for (entier i = 0; i < 8; i++, test_flag <<= 1)
++    {
++      if ((flags & test_flag) != 0)
++        {
++          const entier id = octree_structure_(idx, i);
++          switch(octree_type(id))
++            {
++            case FLOOR:
++              search_elements_box_floor(boxdata, id);
++              break;
++            case OCTREE:
++              cx2 = cx + ((i & 1) ? half_width_2 : mhalf_width);
++              cy2 = cy + ((i & 2) ? half_width_2 : mhalf_width);
++              cz2 = cz + ((i & 4) ? half_width_2 : mhalf_width);
++              search_elements_box_recursively(boxdata, id,
++                                              cx2, cy2, cz2,
++                                              half_width_2);
++              break;
++            case EMPTY:
++              break;
++            }
++        }
++    }
++}
++
++void Octree_Int::reset()
++{
++  root_octree_id_ = octree_id(0, EMPTY);
++  nb_elements_ = 0;
++  octree_structure_.reset();
++  floor_elements_.reset();
++}
++
++// Description: construit un octree_floor avec la liste d'elements donnee et
++//  renvoie l'octree_id de cet octree_floor
++entier Octree_Int::build_octree_floor(const ArrOfInt& elements_list)
++{
++  const entier nb_elems = elements_list.size_array();
++  const entier index = floor_elements_.size_array();
++  floor_elements_.resize_array(index + nb_elems + 1);
++  floor_elements_[index] = nb_elems;
++  for (entier i = 0; i < nb_elems; i++)
++    floor_elements_[index + 1 + i] = elements_list[i];
++  return octree_id(index, FLOOR);
++}
++
++// Description:
++//  octree_center_i est le premier entier de la moitie superieure de l'octree dans la direction i.
++//  octree_half_width est une puissance de 2 egale a octree_center_i-octree_min_i (octree_min_i
++//   est le premier entier inclu dans cet octree dans la direction i)
++// Valeur de retour: octree_id de l'octree construit (void octree_structure_)
++entier Octree_Int::build_octree_recursively(const entier octree_center_x,
++    const entier octree_center_y,
++    const entier octree_center_z,
++    const entier octree_half_width,
++    const IntTab& elements_boxes,
++    VECT(ArrOfInt) & vect_elements_list,
++    const entier level,
++    VECT(ArrOfInt) & tmp_elem_flags)
++{
++  // Criteres d'arret de la subdivision:
++  // Nombre maximal d'elements dans un sous-cube floor
++  static const entier octree_floor_max_elems = 8;
++  // S'il y a beaucoup d'elements dupliques, mais pas trop, et que le nombre d'elements
++  //  dans l'octree est superieur a cette valeur, on subdivise quand-meme
++  static const entier octree_duplicate_elements_limit = 32;
++  const ArrOfInt& elements_list = vect_elements_list[level];
++  // Si le nombre d'elements est inferieur a la limite, on cree un floor_element,
++  // sinon on subdivise
++  const entier nb_elems = elements_list.size_array();
++  if (nb_elems == 0)
++    return octree_id(0, EMPTY);
++
++  if (nb_elems < octree_floor_max_elems || octree_half_width == 1 /* dernier niveau */)
++    {
++      const entier octree_id = build_octree_floor(elements_list);
++      return octree_id;
++    }
++
++  ArrOfInt& elem_flags = tmp_elem_flags[level];
++  elem_flags.resize_array(0); // Ne pas conserver les anciennes valeurs
++  elem_flags.resize_array(nb_elems);
++
++  const entier nb_octrees = octree_structure_.dimension(1);
++  assert(nb_octrees == 2 || nb_octrees == 4 || nb_octrees == 8);
++  const entier elem_box_dim = elements_boxes.dimension(1);
++  // Soit elements_boxes contient dimension colonnes, soit dimension*2
++  const entier box_delta = (elem_box_dim > 3) ? (elem_box_dim >> 1) : 0;
++  // Nombre d'elements stockes en double dans l'octree (a cause des elements a cheval
++  //  sur plusieurs sous-octrees)
++  entier nb_duplicate_elements = 0;
++  // On range les elements de la liste dans 8 sous-cubes (remplissage de elem_flags)
++  for (entier i_elem = 0; i_elem < nb_elems; i_elem++)
++    {
++      const entier elem = elements_list[i_elem];
++      // dir_flag vaut 1 pour la direction x, 2 pour y et 4 pour z
++      entier dir_flag = 1;
++      // sub_cube_flags contient 2^dim drapeaux binaires (1 par sous-cube),
++      // et indique les sous-cubes coupes par l'element
++      entier octree_flags = 255;
++      // dans combien de sous-octree cet element est-il stocke ?
++      entier nb_duplicates = 1;
++
++      for (entier direction = 0; direction < 3; direction++)
++        {
++          const entier elem_min = elements_boxes(elem, direction);
++          const entier elem_max = elements_boxes(elem, box_delta+direction);
++          assert(elem_max >= elem_min);
++          // coordonnee du centre du cube dans la direction j:
++          const entier center = (direction==0) ? octree_center_x : ((direction==1) ? octree_center_y : octree_center_z);
++          // L'element coupe-t-il la partie inferieure et la partie superieure du cube dans la "direction" ?
++          if (elem_min >= center) // non -> on retire les flags des cubes de la partie inferieure
++            octree_flags &= sub_cube_flags_max[direction];
++          else if (elem_max < center) // non -> on retire les flags des cubes de la partie superieure
++            octree_flags &= sub_cube_flags_min[direction];
++          else
++            nb_duplicates <<= 1; // l'element coupe les deux parties !
++          dir_flag = dir_flag << 1;
++          if (dir_flag == nb_octrees)
++            break;
++        }
++      elem_flags[i_elem] = octree_flags;
++      nb_duplicate_elements += nb_duplicates - 1;
++    }
++
++  // Critere un peu complique : s'il y a vraiment beaucoup d'elements
++  //  dans cet octree, on autorise jusqu'a dupliquer tous les elements,
++  //  ce qui permet de ranger des elements tres alonges qui sont forcement
++  //  dupliques dans une direction (>octree_duplicate_elements_limit).
++  if ((nb_duplicate_elements * 2 >= nb_elems && nb_elems < octree_duplicate_elements_limit)
++      || nb_duplicate_elements > nb_elems)
++    {
++      const entier octree_id = build_octree_floor(elements_list);
++      // On renvoie un index d'octreefloor
++      return octree_id;
++    }
++
++  // On reserve une case a la fin de octree_structure pour stocker cet octree:
++  const entier index_octree = octree_structure_.dimension(0);
++  octree_structure_.resize(index_octree + 1, nb_octrees);
++  ArrOfInt& new_liste_elems = vect_elements_list[level+1];
++  new_liste_elems.resize_array(0);
++  const entier width = octree_half_width >> 1;
++  const entier m_width = - width;
++  // Traitement recursif des sous-cubes de l'octree:
++  entier i_cube;
++  for (i_cube = 0; i_cube < nb_octrees; i_cube++)
++    {
++      const entier octree_flag = 1 << i_cube;
++      new_liste_elems.resize_array(0); // ne pas conserver les anciennes valeurs
++      new_liste_elems.resize_array(nb_elems);
++      entier count = 0;
++      // Liste des elements inclus dans le sous-cube:
++      for (entier i_elem = 0; i_elem < nb_elems; i_elem++)
++        if ((elem_flags[i_elem] & octree_flag) != 0)
++          new_liste_elems[count++] = elements_list[i_elem];
++      new_liste_elems.resize_array(count);
++
++      entier sub_octree_id;
++      if (new_liste_elems.size_array() == 0)
++        {
++          sub_octree_id = octree_id(-1, EMPTY);
++        }
++      else
++        {
++          // Coordonnees du nouveau sous-cube
++          const entier cx = octree_center_x + ((i_cube&1) ? width : m_width);
++          const entier cy = octree_center_y + ((i_cube&2) ? width : m_width);
++          const entier cz = octree_center_z + ((i_cube&4) ? width : m_width);
++          sub_octree_id = build_octree_recursively(cx, cy, cz, width,
++                          elements_boxes,
++                          vect_elements_list,
++                          level+1,
++                          tmp_elem_flags);
++        }
++      octree_structure_(index_octree, i_cube) = sub_octree_id;
++    }
++
++  return octree_id(index_octree, OCTREE);
++}
++
++// Description: renvoie l'octree_id de l'octree_floor contenant le sommet (x,y,z)
++//  (peut renvoyer l'octree EMPTY)
++entier Octree_Int::search_octree_floor(entier x, entier y, entier z) const
++{
++  if (octree_type(root_octree_id_) != OCTREE)
++    return root_octree_id_;
++  // Le test pour savoir si on est dans la partie superieure ou
++  // inferieure d'un octree au niveau i consiste simplement a tester
++  // le i-ieme bit de la position.
++  entier flag = root_octree_half_width_;
++
++  entier index = octree_index(root_octree_id_, OCTREE);
++
++  // Descendre dans la hierarchie d'octree subdivises jusqu'au cube
++  //  le plus petit
++  while (1)
++    {
++      // Numero du sous-cube dans lequel se trouve le sommet x,y,z
++      const entier ix = (x & flag) ? 1 : 0;
++      const entier iy = (y & flag) ? 2 : 0;
++      const entier iz = (z & flag) ? 4 : 0;
++      entier i_sous_cube = ix + iy + iz;
++      // On entre dans le sous-cube :
++      const entier octree_id = octree_structure_(index, i_sous_cube);
++      if (octree_type(octree_id) != OCTREE)
++        return octree_id;
++
++      index = octree_index(octree_id, OCTREE);
++      flag >>= 1;
++    }
++  return -1; // On n'arrive jamais ici !
++}
+diff --git a/databases/readers/Lata/Octree_Int.h b/databases/readers/Lata/Octree_Int.h
+new file mode 100644
+index 0000000..ace9c2d
+--- /dev/null
++++ b/databases/readers/Lata/Octree_Int.h
+@@ -0,0 +1,103 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef Octree_Int_inclus
++#define Octree_Int_inclus
++#include <IntTab.h>
++#include <VectArrOfInt.h>
++
++struct IntBoxData;
++class ArrOfBit;
++
++// .DESCRIPTION : Un octree permettant de retrouver des objets ponctuels ou
++//   parallelipipediques dans un espace 1D, 2D ou 3D et des coordonnees entieres
++class Octree_Int
++{
++public:
++  void   build(const entier dimension, const IntTab& elements_boxes);
++  entier search_elements(entier x, entier y, entier z, entier& floor_elements_index) const;
++  entier search_elements_box(entier xmin, entier ymin, entier zmin,
++                             entier xmax, entier ymax, entier zmax,
++                             ArrOfInt& elements) const;
++  void   reset();
++
++  inline const ArrOfInt& floor_elements() const
++  {
++    return floor_elements_;
++  };
++
++  // Le plus grand entier autorise pour les coordonnees (du type 2^n - 1)
++  static const entier coord_max_;
++  // Premier entier de la moitie superieure de l'octree root (si coord_max_=2^n-1, half_width_=2^(n-1))
++  static const entier root_octree_half_width_;
++protected:
++  entier build_octree_recursively(const entier octree_center_x, const entier octree_center_y, const entier octree_center_z,
++                                  const entier octree_half_width,
++                                  const IntTab& elements_boxes,
++                                  VECT(ArrOfInt) & vect_elements_list,
++                                  const entier level,
++                                  VECT(ArrOfInt) & tmp_elem_flags);
++  entier build_octree_floor(const ArrOfInt& elements_list);
++
++  entier search_octree_floor(entier x_pos, entier y_pos, entier z_pos) const;
++  void   search_elements_box_floor(IntBoxData& boxdata,
++                                   entier octree_floor_id) const;
++  void   search_elements_box_recursively(IntBoxData& boxdata,
++                                         entier octree_id,
++                                         entier cx, entier cy, entier cz,
++                                         entier half_width) const;
++
++  // Un octree peut etre soit vide, soit subdivise en nb_octrees autres octrees,
++  // soit un octree_floor contenant une liste d'elements.
++  enum Octree_Type { EMPTY, OCTREE, FLOOR };
++
++  static inline entier octree_id(entier index, Octree_Type type);
++  static inline entier octree_index(entier octree_id, Octree_Type type);
++  static inline Octree_Type octree_type(entier octree_id);
++
++  // Octree_id du cube principal : peut etre EMPTY, OCTREE ou FLOOR
++  entier root_octree_id_;
++  // Nombre d'elements stockes (dimension(0) du tableau elements_boxes)
++  entier nb_elements_;
++  // Tableau contenant tous les cubes qui sont divises en sous-cubes
++  //  octree_structure_(i, j) decrit le contenu du sous-cube j du cube d'index i.
++  //  pour 0 <= j < nombre de sous-cubes par cube.
++  //  On appelle "octree_id" une valeur X=octree_structure_(i,j) (identifiant octree)
++  //  L'octree id encode a la fois le type de l'octree et l'index ou
++  //  il se trouve dans les tableaux (voir octree_id(entier, Octree_Type))
++  IntTab octree_structure_;
++
++  // Tableau contenant la liste des elements de chaque sous-cube final non subdivise.
++  // Si X < 0, on note i_debut = -X-1.
++  // floor_elements_(i_debut) = n = nombre d'elements dans ce sous-cube
++  // floor_elements_[i_debut+j] = numero d'un element qui coupe ce sous-cube pour 1 <= j <= n
++  ArrOfInt floor_elements_;
++};
++
++#endif
+diff --git a/databases/readers/Lata/OpenDXWriter.C b/databases/readers/Lata/OpenDXWriter.C
+new file mode 100644
+index 0000000..7add5ed
+--- /dev/null
++++ b/databases/readers/Lata/OpenDXWriter.C
+@@ -0,0 +1,335 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <OpenDXWriter.h>
++#include <LataFilter.h>
++#include <iostream>
++#include <fstream>
++#include <iosfwd>
++
++class DX_stream;
++
++class DX_stream
++{
++public:
++  DX_stream() : os_to_cout_(0), os_(0) {};
++  void init_cout(int is_ascii) 
++  { 
++    reset();
++    os_to_cout_ = 1;
++    ascii_ = is_ascii;
++    os_ = &std::cout;
++  }
++  void init_file(const char *fname, int is_ascii)
++  {
++    reset();
++    os_to_cout_ = 0;
++    ascii_ = is_ascii;
++    os_ = new std::ofstream(fname);
++  }
++  ~DX_stream() { reset(); }
++  void reset()
++  {
++    if (!os_to_cout_)
++      delete os_;
++    os_ = 0;
++    os_to_cout_ = 0;
++  }
++  DX_stream & operator<<(const float f) { (*os_) << f; return *this; }
++  DX_stream & operator<<(const int i) { (*os_) << i; return *this; }
++  DX_stream & operator<<(const char * s) { (*os_) << s; return *this; }
++  DX_stream & operator<<(DX_stream & f(DX_stream &)) { return f(*this); }
++
++  void write(char * ptr, int sz) { os_->write(ptr, sz); }
++  entier ok() { return os_ != 0; }
++  entier ascii() { return ascii_; }
++  std::ostream & stream() { return *os_; }
++protected:
++  int os_to_cout_;
++  int ascii_;
++  std::ostream *os_;
++};
++
++DX_stream & endl(DX_stream & os) 
++{ 
++  os.stream() << std::endl; 
++  return os; 
++}
++
++void DX_write_vect(DX_stream & os, int dxobject, const ArrOfFloat & v)
++{
++  const int places = v.size_array();
++  os << "object " << dxobject << " class array" << endl;
++  os << "type float rank 1 shape 1 items " << places << " ";
++
++  if (!os.ascii()) {
++    os << (mymachine_msb ? "msb ieee" : "lsb ieee") << " data follows" << endl;
++    os.write((char*)v.addr(), sizeof(float) * places);
++  } else {
++    os << "ascii data follows" << endl;
++    for (int i=0;i<places;i++) {
++      os << v[i] << " ";
++      os << endl;
++    }
++  }
++}
++void DX_write_vect(DX_stream & os, int dxobject, const FloatTab & v)
++{
++  const int places = v.dimension(0);
++  const int shape  = v.dimension(1);
++  os << "object " << dxobject << " class array" << endl;
++  os << "type float rank 1 shape " << shape << " items " << places << " ";
++
++  if (!os.ascii()) {
++    os << (mymachine_msb ? "msb ieee" : "lsb ieee") << " data follows" << endl;
++    os.write((char*)v.addr(), sizeof(float) * places * shape);
++  } else {
++    os << "ascii data follows" << endl;
++    for (int i=0;i<places;i++) {
++      for (int j=0;j<shape;j++)
++        os << v(i, j) << " ";
++      os << endl;
++    }
++  }
++}
++
++void DX_write_vect(DX_stream & os, int dxobject, const IntTab & v)
++{
++  if (sizeof(int) != 4) {
++    Journal() << "Error DX_write_vect : int size != 32 bits" << endl;
++    throw OpenDXWriter::DXInternalError;
++  }
++  const int places = v.dimension(0);
++  const int shape  = v.dimension(1);
++  os << "object " << dxobject << " class array" << endl;
++  os << "type int rank 1 shape " << shape << " items " << places << " ";
++
++  if (!os.ascii()) {
++    os << (mymachine_msb ? "msb ieee" : "lsb ieee") << " data follows" << endl;
++    os.write((char*)v.addr(), sizeof(int) * places * shape);
++  } else {
++    os << "ascii data follows" << endl;
++    for (int i=0;i<places;i++) {
++      for (int j=0;j<shape;j++)
++        os << v(i, j) << " ";
++      os << endl;
++    }
++  }
++}
++
++OpenDXWriter::OpenDXWriter()
++{
++  os_ = new DX_stream;
++}
++
++OpenDXWriter::~OpenDXWriter()
++{
++  delete os_;
++}
++
++void OpenDXWriter::reset()
++{
++  index_counter_ = 0;
++  fields_indexes_.resize_array(0);
++  fields_indexes_.set_smart_resize(1);
++  fields_names_ = Noms();
++  nodes_index_ = -1;
++  finish_geometry(); // reset geometry data
++}
++
++void OpenDXWriter::init_cout(double time, int ascii)
++{
++  reset();
++  os_->init_cout(ascii);
++  dx_time_index_ = ++index_counter_;
++  FloatTab t;
++  t.resize(1,1);
++  t(0,0) = time;
++  DX_write_vect(*os_, dx_time_index_, t);
++}
++
++void OpenDXWriter::init_file(double time, Nom & filename_, int ascii)
++{
++  reset();
++  os_->init_file(filename_, ascii);
++  dx_time_index_ = ++index_counter_;
++  FloatTab t;
++  t.resize(1,1);
++  t(0,0) = time;
++  DX_write_vect(*os_, dx_time_index_, t);
++}
++
++const char * DX_element_name(Domain::Element elem)
++{
++  switch(elem) {
++  case Domain::line: return "lines";
++  case Domain::triangle: return "triangles";
++  case Domain::quadri: return "quads";
++  case Domain::tetra: return "tetrahedra";
++  case Domain::hexa: return "cubes";
++  default:
++    Journal() << "DX_element_name unknown element" << endl;
++    throw OpenDXWriter::DXInternalError;
++  }
++}
++
++void OpenDXWriter::write_geometry(const Domain & dom)
++{
++  // Write last geometry and begin a new one
++  finish_geometry();
++  const DomainUnstructured * dom1 = dynamic_cast<const DomainUnstructured*>(&dom);
++  const DomainIJK * dom2 = dynamic_cast<const DomainIJK*>(&dom);
++  DX_stream & os = *os_;
++  if (dom1) {
++    nodes_index_ = ++index_counter_;
++    DX_write_vect(os, nodes_index_, dom1->nodes_);
++    elements_index_ = ++index_counter_;
++    DX_write_vect(os, elements_index_, dom1->elements_);
++    os << "attribute \"element type\" string \"" << DX_element_name(dom.elt_type_) << "\"" << endl;
++    os << "attribute \"ref\" string \"positions\"" << endl;
++  } else if (dom2) {
++    const entier dim = dom.dimension();
++    ArrOfInt dx_coord_index(dim);
++    for (entier i = 0; i < dim; i++) {
++      dx_coord_index[i] = ++index_counter_;
++      const entier n = dom2->coord_[i].size_array();
++      FloatTab tmp;
++      tmp.resize(n, 3);
++      for (entier j = 0; j < n; j++)
++        tmp(j, i) = dom2->coord_[i][j];
++      DX_write_vect(os, dx_coord_index[i], tmp);
++    }
++    nodes_index_ = ++index_counter_;
++    os << "object " << nodes_index_ << " class productarray" << endl;
++    entier i;
++    for (i = dim-1; i >= 0; i--)
++      os << " term " << dx_coord_index[i] << endl;
++    elements_index_ = ++index_counter_;
++    os << "object " << elements_index_ << " class gridconnections counts";
++    for (i = dim-1; i >= 0; i--)
++      os << " " << dom2->coord_[i].size_array();
++    os << endl;
++    os << "attribute \"element type\" string \"" << ((dim==2)?"quads":"cubes") << "\"" << endl;
++    os << "attribute \"ref\" string \"positions\"" << endl;
++    const entier n1 = dom2->invalid_positions_.size_array();
++    if (n1 > 0) {
++      invalid_positions_ = ++index_counter_;
++      IntTab tmp;
++      tmp.resize(n1, 1);
++      ArrOfInt & array = tmp;
++      for (entier ii = 0; ii < n1; ii++) array[ii] = dom2->invalid_positions_[ii];
++      DX_write_vect(os, invalid_positions_, tmp);
++      os << "attribute \"ref\" string \"positions\"" << endl;
++    }
++#if 0
++    if (n2 > 0) {
++      IntTab tmp;
++      tmp.resize(n2, 1);
++      ArrOfInt & array = tmp;
++      for (entier i = 0; i < n2; i++) array[i] = dom2->invalid_connections_[i];
++      DX_write_vect(os, invalid_connections_, tmp);
++      os << "attribute \"ref\" string \"connections\"" << endl;
++    }
++#endif
++  } else {
++    Journal() << "Error OpenDXWriter::write_geometry domain type not supported" << endl;
++    throw DXInternalError;
++  }
++  fields_names_.add(dom.id_.name_);
++}
++
++void OpenDXWriter::finish_geometry()
++{
++  if (nodes_index_ >= 0) {
++    index_counter_++;
++    fields_indexes_.append_array(index_counter_);
++    DX_stream & os = *os_;
++    os << "object " << index_counter_ << " class field" << endl;
++    os << " component \"positions\" " << nodes_index_ << endl;
++    os << " component \"connections\" " << elements_index_ << endl;
++    if (invalid_positions_ >= 0)
++      os << " component \"invalid positions\" " << invalid_positions_ << endl;
++    if (invalid_connections_ >= 0)
++      os << " component \"invalid connections\" " << invalid_connections_ << endl;
++    os << " component \"TIME\" " << dx_time_index_ << endl;
++
++    for (entier i=0; i < components_indexes_.size_array(); i++)
++      os << " component \"" << components_names_[i] << "\" " << components_indexes_[i] << endl;
++  }
++  nodes_index_ = -1;
++  elements_index_ = -1;
++  components_indexes_.resize_array(0);
++  components_indexes_.set_smart_resize(1);
++  components_names_ = Noms();
++  invalid_positions_ = -1;
++  invalid_connections_ = -1;
++}
++
++void OpenDXWriter::write_component(const LataField_base & field)
++{
++  index_counter_++;
++  const Field<IntTab> * int_field = dynamic_cast<const Field<IntTab>*>(&field);
++  const Field<FloatTab> * float_field = dynamic_cast<const Field<FloatTab>*>(&field);
++  if (int_field)
++    DX_write_vect(*os_, index_counter_, int_field->data_);
++  else if (float_field)
++    DX_write_vect(*os_, index_counter_, float_field->data_);
++  else {
++    Journal() << "Error OpenDXWriter::write_component: unknown field type" << endl;
++    throw;
++  }
++  if (field.localisation_ == LataField_base::ELEM)
++    (*os_) << "attribute \"dep\" string \"connections\"" << endl;
++  else if (field.localisation_ == LataField_base::SOM)
++    (*os_) << "attribute \"dep\" string \"positions\"" << endl;
++  else
++   {
++    ; // no attribute
++   }
++  components_indexes_.append_array(index_counter_);
++  Nom n = field.id_.uname_.get_field_name();
++  n += "_";
++  n += field.id_.uname_.get_localisation();
++  components_names_.add(n);
++}
++
++entier OpenDXWriter::finish(int force_group)
++{
++  DX_stream & os = *os_;
++  finish_geometry();
++  if (force_group || fields_indexes_.size_array() > 1) {
++    //DX_stream & os = *os_;
++    os << "object " << ++index_counter_ << " class group" << endl;
++    for (entier i = 0; i < fields_indexes_.size_array(); i++) {
++      os << " member \"" << fields_names_[i] << "\" value " << fields_indexes_[i] << endl;
++    }
++  }
++  os << "END" << endl;
++  return index_counter_;
++}
+diff --git a/databases/readers/Lata/OpenDXWriter.h b/databases/readers/Lata/OpenDXWriter.h
+new file mode 100644
+index 0000000..e8f6358
+--- /dev/null
++++ b/databases/readers/Lata/OpenDXWriter.h
+@@ -0,0 +1,83 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef OpenDXWriter_H_
++#define OpenDXWriter_H_
++#include <ArrOfInt.h>
++#include <Lata_tools.h>
++
++class Domain;
++class LataField_base;
++// Usage:
++//   init_cout(...) or init_file(...)
++//   for (i=0; i < nb_geometries; i++) {
++//     write_geometry(...);
++//     for (j=0; j < nb_fields; j++)
++//       write_component(...);
++//   }
++//   finish();
++class DX_stream;
++class OpenDXWriter
++{
++public:
++  OpenDXWriter();
++  ~OpenDXWriter();
++  void init_cout(double time, int ascii = 0);
++  void init_file(double time, Nom & filename_, int ascii = 0);
++
++  void write_geometry(const Domain & dom);
++  void write_component(const LataField_base & field);
++
++  entier finish(int force_group = 0);
++  enum DXErrors { DXInternalError };
++protected:
++  void reset();
++  void finish_geometry();
++
++  int dx_time_index_;
++  int index_counter_;
++  // Indexes of all DXfield objects in the file (to build the final group)
++  ArrOfInt fields_indexes_;
++  // Names of the DXfields:
++  Noms fields_names_;
++
++  // Index of the nodes array of the last geometry
++  int nodes_index_;
++  // Index of the elements array of the last geometry
++  int elements_index_;
++  // Index of these arrays:
++  int invalid_positions_;
++  int invalid_connections_;
++  // Indexes of the components associated with the last geometry
++  ArrOfInt components_indexes_;
++  Noms components_names_;
++
++  DX_stream * os_;
++};
++#endif
+diff --git a/databases/readers/Lata/Operator.h b/databases/readers/Lata/Operator.h
+new file mode 100644
+index 0000000..2ae94bf
+--- /dev/null
++++ b/databases/readers/Lata/Operator.h
+@@ -0,0 +1,224 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef OPERATORS_H
++#define OPERATORS_H
++#include <LataFilter.h>
++
++// A tool to "reconnect" several subdomains of a parallel computation:
++//  reconnect_geometry() searches for duplicate node coordinates and 
++//  changes the elements_ and faces_ arrays to use the smallest node
++//  index that has the same coordinate. Hence, we recover the connectivity
++//  between blocks.
++class Reconnect
++{
++public:
++  static void reconnect_geometry(DomainUnstructured & geom, double tolerance, entier nb_nodes_untouched = 0);
++  static void apply_renumbering(const ArrOfInt & nodes_renumber, ArrOfInt & data);
++  static void search_duplicate_nodes(const FloatTab & src_coord,
++                                     ArrOfInt & nodes_renumber,
++                                     double eps,
++                                     entier nb_nodes_untouched = 0);
++};
++
++class OperatorClipbox : public Operator
++{
++public:
++  void build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest);
++  void build_field(const Domain & src_domain, const LataField_base & src_field, 
++                   const Domain & dest_domain, LataDeriv<LataField_base> & dest);
++  // Renumerotation des sommets, elements et faces par rapport aux donnees brutes lues
++  // renum_truc_[new_index] = index in lata file;
++  // La renumerotation vient de clip_box et de regularize
++  ArrOfInt renum_nodes_;
++  ArrOfInt renum_elements_;
++  ArrOfInt renum_faces_;
++};
++
++class OperatorBoundary : public Operator
++{
++public:
++  OperatorBoundary() { geom_init_ = 0; }
++  void build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest);
++  void build_field(const Domain & src_domain, const LataField_base & src_field, 
++                   const Domain & dest_domain, LataDeriv<LataField_base> & dest);
++  BigEntier compute_memory_size() const {
++    return
++      memory_size(src_nodes_)
++      + memory_size(src_element_)
++      + memory_size(src_face_);
++  }
++  // Renumerotation des sommets, elements et faces par rapport aux donnees brutes lues
++  // renum_truc_[new_index] = index in lata file;
++  // La renumerotation vient de clip_box et de regularize
++  ArrOfInt src_nodes_; // for each boundary node, which node is it in source domain ?
++  ArrOfInt src_element_; // same for boundary face vs source domain element
++  ArrOfInt src_face_; // local face number on src_element_
++  entier geom_init_;
++};
++
++class OperatorRegularize : public Operator
++{
++public:
++  OperatorRegularize() { tolerance_ = -1.; geom_init_ = 0; extend_layer_ = 0; }
++  void set_tolerance(double epsilon) { tolerance_ = epsilon; }
++  void set_extend_layer(entier n) { if (n >= 0) extend_layer_ = n; else extend_layer_ = 0; }
++  void build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest);
++  void build_field(const Domain & src_domain, const LataField_base & src_field, 
++                   const Domain & dest_domain, LataDeriv<LataField_base> & dest);
++  
++  BigEntier compute_memory_size() const {
++    return
++      memory_size(renum_nodes_)
++      + memory_size(renum_elements_)
++      + memory_size(renum_faces_);
++  }
++  // Renumerotation des sommets, elements et faces par rapport aux donnees brutes lues
++  // renum_truc_[old_index] = new_index;
++  ArrOfInt renum_nodes_;
++  ArrOfInt renum_elements_;
++  // Pour les faces: les faces de chaque direction du domaine ijk sont numerotees 
++  //  separement: faces de normales X entre 0 et N, faces de normales Y entre 0 et N, etc...
++  // Le numero d'une face est egal au plus petit des numeros de ses sommets du le maillage ijk.
++  // Renum faces contient le codage suivant:
++  //  numero de la face = renum_faces_[i] >> 2;
++  //  direction de la face  = (renum_faces_ & 3)
++  ArrOfInt renum_faces_;
++  double tolerance_;
++  entier extend_layer_;
++  entier geom_init_;
++};
++
++class OperatorDualMesh : public Operator
++{
++public:
++  void build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest);
++  void build_field(const Domain & src_domain, const LataField_base & src_field, 
++                   const Domain & dest_domain, LataDeriv<LataField_base> & dest);
++  BigEntier compute_memory_size() const { return 0; }
++};
++class OperatorFacesMesh : public Operator
++{
++public:
++  void build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest);
++  void build_field(const Domain & src_domain, const LataField_base & src_field, 
++                   const Domain & dest_domain, LataDeriv<LataField_base> & dest);
++  BigEntier compute_memory_size() const { return 0; }
++};
++
++class OperatorNCMesh : public Operator
++{
++public:
++  void build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest);
++  void build_field(const Domain & src_domain, const LataField_base & src_field, 
++                   const Domain & dest_domain, LataDeriv<LataField_base> & dest);  
++  BigEntier compute_memory_size() const { return 0; }
++};
++
++// These generic methods just say that the particular function does not exist:
++void build_geometry_(Operator & op, const Domain & src, LataDeriv<Domain> & dest);
++void build_field_(Operator & op, const Domain & src, const Domain & dest, 
++                  const LataField_base & srcf, LataField_base & destf);
++
++template<class Op>
++void apply_geometry(Op & op, const Domain & src_domain, LataDeriv<Domain> & dest)
++{
++  const DomainUnstructured *src1 = dynamic_cast<const DomainUnstructured*>(&src_domain);
++  const DomainIJK *src2 = dynamic_cast<const DomainIJK*>(&src_domain);
++
++  if (src1) {
++    build_geometry_(op, *src1, dest);
++  } else if (src2) {
++    build_geometry_(op, *src2, dest);
++  } else {
++    Journal() << "Error in OperatorDualMesh::build_geometry: unsupported domain type" << endl;
++    throw;
++  } 
++}
++
++// See apply_field
++template <class Op, class DomSrc, class DomDest>
++void apply_field3(Op & op, const DomSrc & src_domain, const LataField_base & src_field,
++                  const DomDest & dest_domain, LataDeriv<LataField_base> & dest)
++{
++  const Field<DoubleTab> *src1 = dynamic_cast<const Field<DoubleTab>*> (&src_field);
++  const Field<FloatTab>  *src2 = dynamic_cast<const Field<FloatTab>*> (&src_field);
++  const Field<IntTab>    *src3 = dynamic_cast<const Field<IntTab>*> (&src_field);
++  
++  if (src1)
++    build_field_(op, src_domain, dest_domain, *src1, dest.instancie(Field<DoubleTab> ));
++  else if (src2)
++    build_field_(op, src_domain, dest_domain, *src2, dest.instancie(Field<FloatTab> ));
++  else if (src3)
++    build_field_(op, src_domain, dest_domain, *src3, dest.instancie(Field<IntTab> ));
++  else {
++    Journal() << "Error in apply_field3: unsupported field type" << endl;
++    throw;
++  }
++}
++
++// See apply_field
++template <class Op, class DomSrc>
++void apply_field2(Op & op, const DomSrc & src_domain, const LataField_base & src_field,
++                  const Domain & dest_domain, LataDeriv<LataField_base> & dest)
++{
++  const DomainUnstructured *d1 = dynamic_cast<const DomainUnstructured*>(&dest_domain);
++  const DomainIJK          *d2 = dynamic_cast<const DomainIJK*>(&dest_domain);
++  if (d1)
++    apply_field3(op, src_domain, src_field, *d1, dest);
++  else if (d2)
++    apply_field3(op, src_domain, src_field, *d2, dest);
++  else {
++    Journal() << "Error in apply_field2: unsupported destination domain type" << endl;
++    throw;
++  }
++}
++
++// This template calls the appropriate "build_field_()" method in the given operator.
++//  The operator should implement non virtual methods for any usefull combination
++//  of source domain type, destination domain type and source field type. This template
++//  will call the correct method depending on the effective type of the parameters
++//  (determined with dynamic_cast).
++template <class Op>
++void apply_field(Op & op, const Domain & src_domain, const LataField_base & src_field,
++                 const Domain & dest_domain, LataDeriv<LataField_base> & dest)
++{
++  const DomainUnstructured *d1 = dynamic_cast<const DomainUnstructured*>(&src_domain);
++  const DomainIJK          *d2 = dynamic_cast<const DomainIJK*>(&src_domain);
++  if (d1)
++    apply_field2(op, *d1, src_field, dest_domain, dest);
++  else if (d2)
++    apply_field2(op, *d2, src_field, dest_domain, dest);
++  else {
++    Journal() << "Error in apply_field: unsupported source domain type" << endl;
++    throw;
++  }
++}
++
++#endif
+diff --git a/databases/readers/Lata/OperatorBoundary.C b/databases/readers/Lata/OperatorBoundary.C
+new file mode 100644
+index 0000000..1e10d1a
+--- /dev/null
++++ b/databases/readers/Lata/OperatorBoundary.C
+@@ -0,0 +1,227 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <LataFilter.h>
++#include <Operator.h>
++#include <Static_Int_Lists.h>
++#include <Connectivite_som_elem.h>
++
++// Journal level for messages
++#define verb_level 4
++
++void build_ref_elem_face(const Domain::Element elt_type, IntTab & ref_elem_face)
++{
++  static entier faces_sommets_tetra[4][3] = 
++    { { 1, 2, 3 },
++      { 0, 3, 2 },
++      { 3, 0, 1 },
++      { 0, 2, 1 } };
++  static entier faces_sommets_hexa[6][4] = 
++    { { 0, 2, 4, 6 },
++      { 0, 1, 4, 5 },
++      { 0, 1, 2, 3 },
++      { 1, 3, 5, 7 },
++      { 2, 3, 6, 7 },
++      { 4, 5, 6, 7 } };
++
++  int i, j;
++  switch(elt_type) {
++  case Domain::tetra:
++    ref_elem_face.resize(4,3);
++    for(i=0;i<4;i++)
++      for(j=0;j<3;j++)
++        ref_elem_face(i,j) = faces_sommets_tetra[i][j];
++    break;
++  case Domain::hexa:
++    ref_elem_face.resize(6,4);
++    for(i=0;i<6;i++)
++      for(j=0;j<4;j++)
++        ref_elem_face(i,j) = faces_sommets_hexa[i][j];
++    break;
++  default:
++    Journal() << "build_ref_elem_face : non code pour element "
++              << endl;
++  }
++}
++
++void build_geometry_(OperatorBoundary & op,
++                     const DomainUnstructured & src, LataDeriv<Domain> & dest_domain)
++{
++  Journal(verb_level) << "OperatorBoundary domain " << src.id_.name_ << endl;
++  DomainUnstructured & dest = dest_domain.instancie(DomainUnstructured);
++  switch(src.elt_type_) {
++  case Domain::tetra: dest.elt_type_ = Domain::triangle; break;
++  case Domain::hexa:  dest.elt_type_ = Domain::quadri; break;
++  default:
++    Journal() << "Error in OperatorBoundary: element type not supported" << endl;
++    throw;
++  }
++
++  Static_Int_Lists som_elem;
++  construire_connectivite_som_elem(src.nb_nodes(), src.elements_, som_elem, 0);
++  // For each element:
++  //  for each face of this element
++  //    how many neighbouring elements ?
++  //      if only one neighbour, it's a boundary face !
++
++  IntTab element_faces;
++  build_ref_elem_face(src.elt_type_, element_faces);
++  op.src_element_.set_smart_resize(1);
++  op.src_face_.set_smart_resize(1);
++  op.src_nodes_.set_smart_resize(1);
++  const int nb_nodes_per_face = element_faces.dimension(1);
++  const int nb_faces_per_element = element_faces.dimension(0);
++
++  ArrOfInt one_face(nb_nodes_per_face);
++  ArrOfInt adjacent_elements;
++
++  // For each node in the source domain, node number on the boundary:
++  ArrOfInt nodes_renumber;
++  nodes_renumber.resize_array(src.nb_nodes());
++  nodes_renumber = -1;
++
++  entier element_index, local_face_index;
++  // Browse only real elements (so we don't see boundaries between processors)
++  const entier nelem = src.nb_elements() - src.nb_virt_items(LataField_base::ELEM);
++  entier i;
++  entier count = 0;
++  for (element_index = 0; element_index < nelem; element_index++) {
++    for (local_face_index = 0; local_face_index < nb_faces_per_element; local_face_index++) {
++      for (i = 0; i < nb_nodes_per_face; i++) {
++        int local_node = element_faces(local_face_index, i);
++        int node = src.elements_(element_index, local_node);
++        one_face[i] = node;
++      }
++      find_adjacent_elements(som_elem, one_face, adjacent_elements);
++      if (adjacent_elements.size_array() == 1) {
++        op.src_element_.append_array(element_index);
++        op.src_face_.append_array(local_face_index);
++        for (i = 0; i < nb_nodes_per_face; i++) {
++          const entier node = one_face[i];
++          entier dest_node = nodes_renumber[node];
++          if (dest_node < 0) {
++            dest_node = count++;
++            op.src_nodes_.append_array(node);
++            nodes_renumber[node] = dest_node;
++          }
++        }
++      }
++    }
++  }
++
++  // Build nodes
++  const entier nb_nodes = op.src_nodes_.size_array();
++  const entier dim = src.nodes_.dimension(1);
++  dest.nodes_.resize(nb_nodes, dim);
++  for (i = 0; i < nb_nodes; i++) {
++    const entier n = op.src_nodes_[i];
++    for (entier j = 0; j < dim; j++) 
++      dest.nodes_(i, j) = src.nodes_(n, j);
++  }
++
++  // Build elements
++  const entier nb_elems = op.src_element_.size_array();
++  dest.elements_.resize(nb_elems, nb_nodes_per_face);
++  for (i = 0; i < nb_elems; i++) {
++    const entier elem = op.src_element_[i];
++    const entier face = op.src_face_[i];
++    for (entier j = 0; j < nb_nodes_per_face; j++) {
++      const entier src_node = src.elements_(elem, element_faces(face, j));
++      dest.elements_(i, j) = nodes_renumber[src_node];
++    }
++  }
++  op.geom_init_ = 1;
++}
++
++template <class TabType>
++void build_field_(OperatorBoundary & op,
++                  const DomainUnstructured & src_domain,
++                  const DomainUnstructured & dest_domain,
++                  const Field<TabType> & src,
++                  Field<TabType> & dest)
++{
++  if (!op.geom_init_) {
++    // Must fill the renum_.... arrays first !
++    LataDeriv<Domain> destb;
++    op.build_geometry(src_domain, destb);
++  }
++  dest.component_names_ = src.component_names_;
++  dest.localisation_ = src.localisation_;
++  dest.nature_ = src.nature_;
++  if (dest.localisation_ == LataField_base::FACES)
++    dest.localisation_ = LataField_base::ELEM;
++
++  const entier nb_compo = src.data_.dimension(1);
++  entier i, sz = 0;
++  switch(src.localisation_) {
++  case LataField_base::ELEM:
++    sz = dest_domain.nb_elements();
++    dest.data_.resize(sz, nb_compo);
++    for (i = 0; i < sz; i++) {
++      const entier old_i = op.src_element_[i];
++      for (entier j = 0; j < nb_compo; j++)
++        dest.data_(i, j) = src.data_(old_i, j);
++    }
++    break;
++  case LataField_base::SOM:
++    sz = dest_domain.nb_nodes();
++    dest.data_.resize(sz, nb_compo);
++    for (i = 0; i < sz; i++) {
++      const entier old_i = op.src_nodes_[i];
++      for (entier j = 0; j < nb_compo; j++)
++        dest.data_(i, j) = src.data_(old_i, j);
++    }
++    break;
++  case LataField_base::FACES:
++    sz = dest_domain.nb_elements();
++    dest.data_.resize(sz, nb_compo);
++    for (i = 0; i < sz; i++) {
++      const entier old_i = src_domain.elem_faces_(op.src_element_[i], op.src_face_[i]);
++      for (entier j = 0; j < nb_compo; j++)
++        dest.data_(i, j) = src.data_(old_i, j);
++    }
++    break;
++  default:
++    Journal() << "Error in OperatorRegularize::build_field_: unknown localisation" << endl;
++    throw;   
++  }
++}
++
++void OperatorBoundary::build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest)
++{
++  apply_geometry(*this, src_domain, dest);
++}
++
++void OperatorBoundary::build_field(const Domain & src_domain, const LataField_base & src_field,
++                                   const Domain & dest_domain, LataDeriv<LataField_base> & dest)
++{
++  apply_field(*this, src_domain, src_field, dest_domain, dest);
++}
++
++#undef verb_level
+diff --git a/databases/readers/Lata/OperatorDualMesh.C b/databases/readers/Lata/OperatorDualMesh.C
+new file mode 100644
+index 0000000..9ecd859
+--- /dev/null
++++ b/databases/readers/Lata/OperatorDualMesh.C
+@@ -0,0 +1,222 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <LataFilter.h>
++#include <Operator.h>
++
++// Journal level
++#define verb_level 4
++
++void build_geometry_(OperatorDualMesh & op,
++                     const DomainUnstructured & src, LataDeriv<Domain> & dest_domain)
++{
++  Journal(verb_level) << "OperatorDualMesh geometry(unstructured) " << src.id_.name_ << endl;
++  if (!src.faces_ok()) {
++    Journal() << "Error in OperatorDualMesh::build_geometry: source domain has no faces data" << endl;
++    throw;
++  }
++  const int max_nb_som_face = 3; // for tetrahedra
++  if (src.elt_type_ != Domain::triangle && src.elt_type_ != Domain::tetra) {
++    Journal() << "Error in OperatorDualMesh::build_geometry: cannot operate on unstructured mesh with this element type" << endl;
++    throw;
++  }
++  const entier nb_som = src.nodes_.dimension(0);
++  const entier nb_elem = src.elem_faces_.dimension(0); // Not elements_, in case elem_faces_ has no virtual data.
++  const entier dim = src.dimension();
++
++  DomainUnstructured & dest = dest_domain.instancie(DomainUnstructured);
++  dest.id_ = src.id_;
++  dest.id_.name_ += "_dual";
++  dest.elt_type_ = src.elt_type_;
++
++  dest.nodes_ = src.nodes_;
++  dest.nodes_.resize(nb_som + nb_elem, dim);
++  src.compute_cell_center_coordinates(dest.nodes_, nb_som);
++
++  const entier nb_faces_elem = src.elem_faces_.dimension(1);
++  const entier nb_som_face = src.faces_.dimension(1);
++  const entier nb_som_elem = src.elements_.dimension(1);
++  dest.elements_.resize(nb_elem * nb_faces_elem, nb_som_elem);
++  int index = 0;
++  for (int i = 0; i < nb_elem; i++) {
++    const int central_node = nb_som + i;
++    for (int j = 0; j < nb_faces_elem; j++) {
++      const int face = src.elem_faces_(i, j);
++      dest.elements_(index, 0) = central_node;
++      for (int k = 0; k < loop_max(nb_som_face, max_nb_som_face); k++) {
++        dest.elements_(index, k+1) = src.faces_(face, k);
++        break_loop(k, nb_som_face);
++      }
++      index++;
++    }
++  }
++  const entier nb_elem_virt = src.nb_virt_items(LataField_base::ELEM);
++  dest.set_nb_virt_items(LataField_base::ELEM, nb_elem_virt * nb_faces_elem);
++}
++
++// Builds a field on the dual domain from the field on the source domain.
++// Source field must be located at faces.
++// (destination field is located at the elements. the value for an element
++//  is the value associated to the adjacent face of the source domain).
++template <class TabType>
++void build_field_(OperatorDualMesh & op,
++                  const DomainUnstructured & src_domain,
++                  const DomainUnstructured & dest_domain,
++                  const Field<TabType> & src,
++                  Field<TabType> & dest)
++{
++  Journal(verb_level) << "OperatorDualMesh field(unstructured) " << src.id_.uname_ << endl;
++  dest.component_names_ = src.component_names_;
++  dest.localisation_ = LataField_base::ELEM;
++  dest.nature_ = src.nature_;
++  const entier nb_elem = src_domain.elements_.dimension(0);
++  const entier nb_face_elem = src_domain.elem_faces_.dimension(1);
++  const entier nb_comp = src.data_.dimension(1);
++  dest.data_.resize(nb_elem * nb_face_elem, nb_comp);
++  int index = 0;
++  for (int i = 0; i < nb_elem; i++) {
++    for (int j = 0; j < nb_face_elem; j++) {
++      const int face = src_domain.elem_faces_(i, j);
++      for (int k = 0; k < nb_comp; k++)
++        dest.data_(index, k) = src.data_(face, k);
++      index++;
++    }
++  }
++}
++
++void build_geometry_(OperatorDualMesh & op,
++                     const DomainIJK & src, LataDeriv<Domain> & dest_domain)
++{
++  Journal(verb_level) << "OperatorDualMesh geometry(ijk) " << src.id_.name_ << endl;
++  if (src.elt_type_ != Domain::quadri && src.elt_type_ != Domain::hexa) {
++    Journal() << "Error in OperatorDualMesh::build_geometry: cannot operate on unstructured mesh with this element type" << endl;
++    throw;
++  }
++
++  DomainIJK & dest = dest_domain.instancie(DomainIJK);
++  dest.elt_type_ = src.elt_type_;
++  const entier dim = src.dimension();
++  for (entier i_dim = 0; i_dim < dim; i_dim++) {
++    const ArrOfFloat & c1 = src.coord_[i_dim];
++    ArrOfFloat & c2 = dest.coord_.add(ArrOfFloat());
++    const int n = c1.size_array() - 1;
++    c2.resize_array(n*2+1);
++    for (int i = 0; i < n; i++) {
++      c2[i*2] = c1[i];
++      c2[i*2+1] = (c1[i] + c1[i+1]) * 0.5;
++    }
++    c2[n*2] = c1[n];
++  }
++
++  if (src.invalid_connections_.size_array() > 0) {
++    dest.invalid_connections_.resize_array(dest.nb_elements());
++    dest.invalid_connections_ = 0;
++    int index = 0;
++    
++    const entier ni = dest.coord_[0].size_array()-1;
++    const entier nj = dest.coord_[1].size_array()-1;
++    const entier nk = (dim==3) ? (dest.coord_[2].size_array()-1) : 1;
++    const entier ni_src = src.coord_[0].size_array() - 1;
++    const entier nj_src = src.coord_[1].size_array() - 1;
++    for (int k = 0; k < nk; k++) {
++      const int k_src = k / 2;
++      for (int j = 0; j < nj; j++) {
++        const int j_src = j / 2;
++        const int idx_source = (k_src * nj_src + j_src) * ni_src;
++        for (int i = 0; i < ni; i++) {
++          const int idx = idx_source + i / 2;
++          if (src.invalid_connections_[idx])
++            dest.invalid_connections_.setbit(index);
++          index++;
++        }
++      }
++    }
++  }
++  dest.virtual_layer_begin_ = 2 * src.virtual_layer_begin_;
++  dest.virtual_layer_end_ = 2 * src.virtual_layer_end_;
++}
++#define IJK(i,j,k) (k*nj_ni_src + j*ni_src + i)
++
++template <class TabType>
++void build_field_(OperatorDualMesh & op,
++                  const DomainIJK & src_domain,
++                  const DomainIJK & dest_domain,
++                  const Field<TabType> & src,
++                  Field<TabType> & dest)
++{
++  Journal(verb_level) << "OperatorDualMesh field(ijk) " << src.id_.uname_ << endl;
++  dest.component_names_ = src.component_names_;
++  dest.localisation_ = LataField_base::ELEM;
++  dest.nature_ = LataDBField::VECTOR;
++  const entier dim = src_domain.dimension();
++  int index = 0;
++
++  // Loop on destination elements
++  const entier ni = dest_domain.coord_[0].size_array()-1;
++  const entier nj = dest_domain.coord_[1].size_array()-1;
++  const entier nk = (dim==3) ? (dest_domain.coord_[2].size_array()-1) : 1;
++  dest.data_.resize(ni*nj*nk, dim);
++  const entier ni_src = src_domain.coord_[0].size_array();
++  const entier nj_ni_src = src_domain.coord_[1].size_array() * ni_src;
++  for (int k = 0; k < nk; k++) {
++    const int k2 = k/2;
++    const int k3 = (k+1)/2;
++    for (int j = 0; j < nj; j++) {
++      const int j2 = j/2;
++      const int j3 = (j+1)/2;
++      for (int i = 0; i < ni; i++) {
++        const int i2 = i/2;
++        const int i3 = (i+1)/2;
++        dest.data_(index, 0) = src.data_(IJK(i3,j2,k2), 0);
++        dest.data_(index, 1) = src.data_(IJK(i2,j3,k2), 1);
++        if (dim==3)
++          dest.data_(index, 2) = src.data_(IJK(i2,j2,k3), 2);
++        index++;
++      }
++    }
++  }
++}
++
++#undef IJK
++
++void OperatorDualMesh::build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest)
++{
++  apply_geometry(*this, src_domain, dest);
++}
++
++void OperatorDualMesh::build_field(const Domain & src_domain, const LataField_base & src_field,
++                                   const Domain & dest_domain, LataDeriv<LataField_base> & dest)
++{
++  if (src_field.localisation_ != LataField_base::FACES) {
++    Journal() << "Error in OperatorDualMesh::build_field: source field is not located at faces" << endl;
++    throw;
++  }
++  apply_field(*this, src_domain, src_field, dest_domain, dest);
++}
++#undef level
+diff --git a/databases/readers/Lata/OperatorFacesMesh.C b/databases/readers/Lata/OperatorFacesMesh.C
+new file mode 100644
+index 0000000..6aa85a5
+--- /dev/null
++++ b/databases/readers/Lata/OperatorFacesMesh.C
+@@ -0,0 +1,130 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <LataFilter.h>
++#include <Operator.h>
++
++// Journal level
++#define verb_level 4
++
++void build_geometry_(OperatorFacesMesh & op,
++                     const DomainUnstructured & src, LataDeriv<Domain> & dest_domain)
++{
++  Journal(verb_level) << "OperatorFacesMesh geometry(unstructured) " << src.id_.name_ << endl;
++  if (!src.faces_ok()) {
++    Journal() << "Error in OperatorFacesMesh::build_geometry: source domain has no faces data" << endl;
++    throw;
++  }
++  // const int max_nb_som_face = 3; // for tetrahedra
++  if (src.elt_type_ != Domain::triangle && src.elt_type_ != Domain::polygone && src.elt_type_ != Domain::tetra && src.elt_type_ != Domain::polyedre) {
++    Journal() << "Error in OperatorFacesMesh::build_geometry: cannot operate on unstructured mesh with this element type" << endl;
++    throw;
++  }
++  //  const entier nb_som = src.nodes_.dimension(0);
++  // const entier nb_elem = src.elem_faces_.dimension(0); // Not elements_, in case elem_faces_ has no virtual data.
++  //const entier dim = src.dimension();
++
++  DomainUnstructured & dest = dest_domain.instancie(DomainUnstructured);
++  dest.id_ = src.id_;
++  dest.id_.name_ += "_centerfaces";
++  if (src.elt_type_ == Domain::triangle || src.elt_type_ == Domain::polygone)
++    dest.elt_type_=Domain::line;
++  else if ( src.elt_type_ == Domain::tetra)
++    dest.elt_type_=Domain::triangle;
++  else if ( src.elt_type_ == Domain::polyedre)
++    dest.elt_type_=Domain::polygone;
++
++  dest.nodes_ = src.nodes_;
++  dest.elements_ = src.faces_;
++      
++    
++
++  
++  const entier nb_elem_virt = src.nb_virt_items(LataField_base::FACES);
++  dest.set_nb_virt_items(LataField_base::ELEM, nb_elem_virt );
++}
++
++// Builds a field on the dual domain from the field on the source domain.
++// Source field must be located at faces.
++// (destination field is located at the elements. the value for an element
++//  is the value associated to the adjacent face of the source domain).
++template <class TabType>
++void build_field_(OperatorFacesMesh & op,
++                  const DomainUnstructured & src_domain,
++                  const DomainUnstructured & dest_domain,
++                  const Field<TabType> & src,
++                  Field<TabType> & dest)
++{
++  Journal(verb_level) << "OperatorFacesMesh field(unstructured) " << src.id_.uname_ << endl;
++  dest.component_names_ = src.component_names_;
++  dest.localisation_ = LataField_base::ELEM;
++  dest.nature_ = src.nature_;
++
++  dest.data_=src.data_;
++   
++  
++} 
++
++void build_geometry_(OperatorFacesMesh & op,
++                     const DomainIJK & src, LataDeriv<Domain> & dest_domain)
++{
++  Journal(verb_level) << "OperatorFacesMesh geometry(ijk) " << src.id_.name_ << endl;
++  Journal() << "Error in OperatorFacesMesh::build_geometry: cannot operate on domainIJK" << endl;
++  throw;
++
++}
++template <class TabType>
++void build_field_(OperatorFacesMesh & op,
++                  const DomainIJK & src_domain,
++                  const DomainIJK & dest_domain,
++                  const Field<TabType> & src,
++                  Field<TabType> & dest)
++{
++  Journal(verb_level) << "OperatorFacesMesh field(ijk) " << src.id_.uname_ << endl;
++  Journal() << "Error in OperatorFacesMesh::build_geometry: cannot operate on domainIJK" << endl;
++  throw;
++} 
++
++
++
++void OperatorFacesMesh::build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest)
++{
++  apply_geometry(*this, src_domain, dest);
++}
++
++void OperatorFacesMesh::build_field(const Domain & src_domain, const LataField_base & src_field,
++                                   const Domain & dest_domain, LataDeriv<LataField_base> & dest)
++{
++  if (src_field.localisation_ != LataField_base::FACES) {
++    Journal() << "Error in OperatorFacesMesh::build_field: source field is not located at faces" << endl;
++    throw;
++  }
++  apply_field(*this, src_domain, src_field, dest_domain, dest);
++}
++#undef level
+diff --git a/databases/readers/Lata/OperatorReconnect.C b/databases/readers/Lata/OperatorReconnect.C
+new file mode 100644
+index 0000000..4cabccc
+--- /dev/null
++++ b/databases/readers/Lata/OperatorReconnect.C
+@@ -0,0 +1,125 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <Operator.h>
++#include <Octree_Double.h>
++
++#define verb_level 4
++
++// Description: Find duplicate coordinates in the "coord" array.
++//  nodes_renumber will have dimension src_coord.dimension(0)
++//  nodes_renumber[i] = i if the node imust be conserved,
++//  nodes_renumber[i] = j if the node i is identical to node j. We always have j<i
++//  eps = tolerance in each direction to consider that two nodes are identical
++//  nb_nodes_untouched : do not search duplicate nodes in the "nb_nodes_untouched"
++//   first nodes. The remaining nodes are still compared to all nodes.
++void Reconnect::search_duplicate_nodes(const FloatTab & src_coord,
++                                       ArrOfInt & nodes_renumber,
++                                       double eps,
++                                       entier nb_nodes_untouched)
++{
++  // Create a temporary DoubleTab (coords are normally float)
++  const entier nb_nodes = src_coord.dimension(0);
++  const entier dim = src_coord.dimension(1);
++  entier i;
++  // Build an octree with all coordinates
++  Journal(verb_level+1) << " Building octree" << endl;
++  DoubleTab coords;
++  coords.resize(nb_nodes, dim);
++  for (i = 0; i < nb_nodes; i++) 
++    for (entier j = 0; j < dim; j++)
++      coords(i,j) = src_coord(i,j);
++  Octree_Double octree;
++  octree.build_nodes(coords, 0 /* no virtual nodes */);
++  
++  Journal(verb_level+1) << " Searching duplicate nodes" << endl;
++  nodes_renumber.resize_array(nb_nodes);
++  for (i = 0; i < nb_nodes; i++)
++    nodes_renumber[i] = i;
++  // For each node, are there several nodes within epsilon ?
++  ArrOfInt node_list;
++  node_list.set_smart_resize(1);
++  entier count = 0; // Number of nodes renumbered
++  for (i = 0; i < nb_nodes; i++) {
++    if (nodes_renumber[i] != i)
++      continue; // node already suppressed
++
++    const double x = coords(i, 0);
++    const double y = (dim>1) ? coords(i, 1) : 0.;
++    const double z = (dim>2) ? coords(i, 2) : 0.;
++    octree.search_elements_box(x-eps, y-eps, z-eps,
++                               x+eps, y+eps, z+eps,
++                               node_list);
++    Octree_Double::search_nodes_close_to(x, y, z,
++                                         coords, node_list,
++                                         eps);
++    const entier n = node_list.size_array();
++    if (n > 1) {
++      for (entier j = 0; j < n; j++) {
++        // Change only nodes with rank > i
++        const entier node = node_list[j];
++        if (node > j) {
++          nodes_renumber[node] = i;
++          count++;
++        }
++      }
++    }
++  }
++  Journal(verb_level+1) << " " << count << " duplicate nodes will be removed" << endl;
++}
++
++void Reconnect::apply_renumbering(const ArrOfInt & nodes_renumber, ArrOfInt & data)
++{
++  entier ntot = data.size_array();
++  entier i;
++  for (i = 0; i < ntot; i++) {
++    const entier node = data[i];
++    const entier n = nodes_renumber[node];
++    if (n != node)
++      data[i] = n;
++  }  
++}
++
++// Description: updates the elements_ and faces_ arrays of the domain so that
++//  all nodes having the same coordinates are replaced by one unique node
++//  in these arrays. See search_duplicate_nodes for nb_nodes_untouched description.
++void Reconnect::reconnect_geometry(DomainUnstructured & geom, double tolerance, entier nb_nodes_untouched)
++{
++  Journal(verb_level) << "Reconnect domain " << geom.id_.name_ << endl;
++
++  ArrOfInt nodes_renumber;
++  search_duplicate_nodes(geom.nodes_, nodes_renumber, tolerance, nb_nodes_untouched);
++
++  apply_renumbering(nodes_renumber, geom.elements_);
++  
++  if (geom.faces_ok()) 
++    apply_renumbering(nodes_renumber, geom.faces_);
++}
++
++#undef verb_level
+diff --git a/databases/readers/Lata/OperatorRegularize.C b/databases/readers/Lata/OperatorRegularize.C
+new file mode 100644
+index 0000000..5bbde88
+--- /dev/null
++++ b/databases/readers/Lata/OperatorRegularize.C
+@@ -0,0 +1,296 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <LataFilter.h>
++#include <Operator.h>
++
++#define verb_level 4
++
++template<class T, class Tab> int search_in_ordered_vect(T x, const Tab & v, const T epsilon) {
++  if (!v.size_array())
++    return -1;
++  int i1=0;
++  int i;
++  int i2 = (int)v.size_array()-1;
++  while (i1 != i2) {
++    i = (i1+i2)/2;
++    if (epsilon+ v[i] < x)
++      i1=i+1;
++    else
++      i2=i;
++  }
++  if (v[i1] == x)
++    return i1;
++  if (((v[i1] - x) * (v[i1] - x))<= (epsilon*epsilon) )
++    return i1;
++
++  return -1;
++}
++
++template<class T, class Tab>
++static void retirer_doublons(Tab & tab, const T epsilon)
++{
++  int i = 0;
++  int j;
++  const int n = tab.size_array();
++  T last_tab_i = -1e40;
++  for (j = 0; j < n; j++) {
++    const T x = tab[j];
++    assert(x >= last_tab_i); // Array must be sorted
++    if (x - last_tab_i > epsilon) {
++      tab[i] = x;
++      last_tab_i = x;
++      i++;
++    }
++  }
++  tab.resize_array(i);
++}
++
++void build_geometry_(OperatorRegularize & op,
++                     const DomainUnstructured & src, LataDeriv<Domain> & dest_domain)
++{
++  Journal(verb_level) << "OperatorRegularize domain " << src.id_.name_ << endl;
++  if (src.elt_type_ != Domain::quadri && src.elt_type_ != Domain::hexa) {
++    Journal() << "Error in OperatorRegularize::build_geometry: cannot operate on unstructured mesh with this element type" << endl;
++    throw;
++  }
++
++  DomainIJK & dest = dest_domain.instancie(DomainIJK);
++  dest.elt_type_ = src.elt_type_;
++  const entier nsom = src.nodes_.dimension(0);
++  const entier dim = src.nodes_.dimension(1);
++  ArrOfInt nb_som_dir(dim);
++  {
++    double product_n = 1.;
++    for (entier i_dim = 0; i_dim < dim; i_dim++) {
++      ArrOfFloat & coord = dest.coord_.add(ArrOfFloat());
++      coord.resize_array(nsom);
++      entier i;
++      for (i = 0; i < nsom; i++)
++        coord[i] = src.nodes_(i, i_dim);
++      coord.ordonne_array();
++      retirer_doublons(coord, op.tolerance_);
++      product_n *= coord.size_array();
++      // Add extended domain layer:
++      if (coord.size_array() > 1) {
++        const entier n = coord.size_array();
++        const entier l = op.extend_layer_;
++        coord.resize_array(n + l * 2);
++        double x0 = coord[n-1];
++        double delta = coord[n-2] - x0;
++        for (i = 1; i <= l; i++)
++          coord[n + l + i] = x0 + delta * i;
++        for (i = l-1; i >= 0; i--)
++          coord[i + l] = coord[i];
++        x0 = coord[l];
++        delta = coord[l+1] - x0;
++        for (i = 1; i <= l; i++)
++          coord[l - i] = x0 - delta * i;
++      }
++      nb_som_dir[i_dim] = coord.size_array();
++    }
++    // Verifying that unique has deleted many points...
++    // If well organised, nsom=nx*ny*nz
++    // If chaos, nsom=(nx+ny+nz)/3
++    // We want to verify that we are nearer to organisation than to chaos !
++    if (product_n > (double) nsom * (double) nsom - 1.) {
++      Journal() << "Positions do not seam regular !" << endl;
++      throw;
++    }
++  }
++  int i;
++  op.renum_nodes_.resize_array(nsom);
++  int nb_som_ijk = 1;
++  for (i = 0; i < dim; i++) 
++    nb_som_ijk *= nb_som_dir[i];
++  IntTab ijk_indexes;
++  ijk_indexes.resize(nsom, dim);
++  for (i = 0; i < nsom; i++) {
++    entier ijk_index = 0;
++    for (int j = dim-1; j >= 0; j--) {
++      const double x = src.nodes_(i,j);
++      int index = search_in_ordered_vect(x, dest.coord_[j],op.tolerance_);
++      if (index < 0) {
++        Journal() << "Error: coordinate (" << i << "," << j << ") = " << x << " not found in regularize" << endl
++                  << "Try reducing regularize tolerance value (option regularize=epsilon)" << endl;
++        throw;
++      }
++      ijk_indexes(i, j) = index;
++      ijk_index += index;
++      if (j)
++        ijk_index *= nb_som_dir[j-1];
++    }
++    op.renum_nodes_[i] = ijk_index;
++  }
++  const int max_index = max_array(nb_som_dir);
++  int nb_elems_ijk = 1;
++  for (i = 0; i < dim; i++)
++    nb_elems_ijk *= nb_som_dir[i] - 1;
++  dest.invalid_connections_.resize_array(nb_elems_ijk);
++  dest.invalid_connections_ = 1; // Everything invalid by default
++  const int nelem = src.elements_.dimension(0);
++  const int nb_som_elem = src.elements_.dimension(1);
++  op.renum_elements_.resize_array(nelem);
++  // Pour chaque element, indice dans le maillage ijk du plus sommet le plus proche de l'origine
++  // (pour les faces...)
++  ArrOfInt idx_elem_som;
++  idx_elem_som.resize_array(nelem);
++  int min_index[3];
++  for (i = 0; i < nelem; i++) {
++    min_index[0] = min_index[1] = min_index[2] = max_index;
++    for (int j = 0; j < nb_som_elem; j++) {
++      int node = src.elements_(i,j);
++      for (int k = 0; k < loop_max(dim, 3); k++) {
++        int idx = ijk_indexes(node, k);
++        min_index[k] = (idx < min_index[k]) ? idx : min_index[k];
++        break_loop(k,dim);
++      }
++    }
++    entier idx = 0;
++    entier idx_som = 0;
++    if (dim == 1) {
++      idx = min_index[0];
++      idx_som = idx;
++    } else if (dim == 2) {
++      idx = min_index[1] * (nb_som_dir[0]-1) + min_index[0];
++      idx_som = min_index[1] * nb_som_dir[0] + min_index[0];
++    } else if (dim == 3) {
++      idx = (min_index[2] * (nb_som_dir[1]-1) + min_index[1]) * (nb_som_dir[0]-1) + min_index[0];
++      idx_som = (min_index[2] * nb_som_dir[1] + min_index[1]) * nb_som_dir[0] + min_index[0];
++    } else
++      throw;
++    op.renum_elements_[i] = idx;
++    dest.invalid_connections_.clearbit(idx);
++    idx_elem_som[i] = idx_som;
++  }
++  
++  if (src.faces_ok()) {
++    const int nfaces = src.faces_.dimension(0);
++    op.renum_faces_.resize_array(nfaces);
++    op.renum_faces_ = -1;
++    const int nb_elem_face = src.elem_faces_.dimension(1);
++    ArrOfInt delta_dir(dim);
++    delta_dir[0] = 1;
++    for (i = 1; i < dim; i++)
++      delta_dir[i] = delta_dir[i-1] * nb_som_dir[i-1];
++    for (i = 0; i < nelem; i++) {
++      // Les faces haut, gauche et arriere du cube a l'origine portent le numero 0
++      // Voir DomaineIJK pour la convention sur la numerotation des faces
++      for (entier j = 0; j < nb_elem_face; j++) {
++        const entier i_face = src.elem_faces_(i, j);
++        entier dir = j % dim;
++        entier index = idx_elem_som[i];
++        if (j>=dim) 
++          index += delta_dir[dir];
++        // Encodage du numero de la face et de la direction
++        index = (index << 2) + dir;
++        if (op.renum_faces_[i_face] < 0) {
++          op.renum_faces_[i_face] = index;
++        } else if (op.renum_faces_[i_face] != index) {
++          Journal() << "Error in OperatorRegularize: faces renumbering failed" << endl;
++          throw;
++        }
++      }
++    }
++  }
++  op.geom_init_ = 1;
++}
++
++template <class TabType>
++void build_field_(OperatorRegularize & op,
++                  const DomainUnstructured & src_domain,
++                  const DomainIJK          & dest_domain,
++                  const Field<TabType> & src,
++                  Field<TabType> & dest)
++{
++  Journal(verb_level) << "OperatorRegularize field " << src.id_.uname_ << endl;
++  if (!op.geom_init_) {
++    // Must fill the renum_.... arrays first !
++    LataDeriv<Domain> destr;
++    op.build_geometry(src_domain, destr);
++  }
++  dest.component_names_ = src.component_names_;
++  dest.localisation_ = src.localisation_;
++  dest.nature_ = src.nature_;
++  const entier sz = src.data_.dimension(0);
++  const entier nb_compo = src.data_.dimension(1);
++  entier i;
++  switch(src.localisation_) {
++  case LataField_base::ELEM:
++    dest.data_.resize(dest_domain.nb_elements(), nb_compo);
++    for (i = 0; i < sz; i++) {
++      const entier new_i = op.renum_elements_[i];
++      for (entier j = 0; j < nb_compo; j++)
++        dest.data_(new_i, j) = src.data_(i, j);
++    }
++    break;
++  case LataField_base::SOM:
++    dest.data_.resize(dest_domain.nb_nodes(), nb_compo);
++    for (i = 0; i < sz; i++) {
++      const entier new_i = op.renum_nodes_[i];
++      for (entier j = 0; j < nb_compo; j++)
++        dest.data_(new_i, j) = src.data_(i, j);
++    }
++    break;
++  case LataField_base::FACES:
++    {
++      if (nb_compo != 1) {
++        Journal() << "Error in OperatorRegularize: field at faces has nb_compo != 1" << endl;
++        throw;
++      }
++      dest.nature_ = LataDBField::VECTOR;
++      const entier nb_dim = dest_domain.dimension();
++      dest.data_.resize(dest_domain.nb_faces(), nb_dim);
++      // Field is interpreted as normal component to the face
++      for (i = 0; i < sz; i++) {
++        const entier code = op.renum_faces_[i];
++        // decodage numero et direction de la face:
++        const entier new_i = code >> 2;
++        const entier direction = (code & 3);
++        dest.data_(new_i, direction) = src.data_(i, 0);
++      }
++    }
++    break;
++  default:
++    Journal() << "Error in OperatorRegularize::build_field_: unknown localisation" << endl;
++    throw;
++  }
++}
++
++void OperatorRegularize::build_geometry(const Domain & src_domain, LataDeriv<Domain> & dest)
++{
++  apply_geometry(*this, src_domain, dest);
++}
++
++void OperatorRegularize::build_field(const Domain & src_domain, const LataField_base & src_field,
++                                     const Domain & dest_domain, LataDeriv<LataField_base> & dest)
++{
++  apply_field(*this, src_domain, src_field, dest_domain, dest);
++}
++#undef verb_level
+diff --git a/databases/readers/Lata/Rebuild_virtual_layer.C b/databases/readers/Lata/Rebuild_virtual_layer.C
+new file mode 100644
+index 0000000..ac29742
+--- /dev/null
++++ b/databases/readers/Lata/Rebuild_virtual_layer.C
+@@ -0,0 +1,141 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <LataFilter.h>
++#include <Connectivite_som_elem.h>
++#include <Operator.h>
++#include <Static_Int_Lists.h>
++#include <Rebuild_virtual_layer.h>
++void find_virtual_layer(DomainUnstructured & domain,
++                        IntTab & virtual_elements,
++                        IntTab & joints_virtual_elements,
++                        double tolerance)
++{
++  Journal(4) << "Searching virtual elements for domain " << domain.id_.name_ << endl;
++  // Step 1 : find duplicate nodes
++  ArrOfInt nodes_renumber;
++  Reconnect::search_duplicate_nodes(domain.nodes_,
++                                    nodes_renumber,
++                                    tolerance,
++                                    0);
++ 
++  // Build reconnected elements
++  Reconnect::apply_renumbering(nodes_renumber, domain.elements_);
++  
++  Static_Int_Lists som_elem;
++  construire_connectivite_som_elem(domain.nb_nodes(),
++                                   domain.elements_,
++                                   som_elem,
++                                   0 /* include virtual */);
++
++  virtual_elements.resize(0, 1);
++  virtual_elements.set_smart_resize(1);
++
++  // Step 2 : for each sub_zone, add to virtual_elements list all elements 
++  // touching the zone and not included in the zone
++  const IntTab & joints_sommets = domain.get_joints(LataField_base::SOM);
++  const IntTab & joints_elements = domain.get_joints(LataField_base::ELEM);
++  const entier nprocs = joints_sommets.dimension(0);
++  joints_virtual_elements.resize(nprocs, 2);
++  ArrOfInt tmp;
++  tmp.set_smart_resize(1);
++  for (entier i_proc = 0; i_proc < nprocs; i_proc++) {
++    entier first_elem_zone = joints_elements(i_proc, 0);
++    entier end_elems_zone = first_elem_zone + joints_elements(i_proc, 1);
++    entier first_node_zone = joints_sommets(i_proc, 0);
++    entier end_nodes_zone = first_node_zone + joints_sommets(i_proc, 1);
++    const entier first_virtual_element = virtual_elements.dimension(0);
++    tmp.resize_array(0);
++    for (entier i_node = first_node_zone; i_node < end_nodes_zone; i_node++) {
++      const entier renum_node = nodes_renumber[i_node];
++      const entier nb_elems_voisins = som_elem.get_list_size(renum_node);
++      for (entier i = 0; i < nb_elems_voisins; i++) {
++        const entier elem = som_elem(renum_node, i);
++        if (elem < first_elem_zone || elem >= end_elems_zone)
++          tmp.append_array(elem);
++      }
++    }
++    // Retirer les doublons
++    tmp.ordonne_array();
++    const entier n = tmp.size_array();
++    entier last = -1;
++    for (entier i = 0; i < n; i++) {
++      const entier elem = tmp[i];
++      if (elem != last) {
++        const entier idx = virtual_elements.dimension(0);
++        virtual_elements.resize(idx+1, 1);
++        virtual_elements(idx, 0) = elem;
++        last = elem;
++      }
++    }
++    joints_virtual_elements(i_proc, 0) = first_virtual_element;
++    joints_virtual_elements(i_proc, 1) = virtual_elements.dimension(0) - first_virtual_element;
++    Journal(5) << "Zone " << i_proc << " has " << joints_virtual_elements(i_proc, 1) << " virtual elements" << endl;
++  }
++}
++
++entier rebuild_virtual_layer(LataDB & lataDB, Domain_Id id, double reconnect_tolerance)
++{
++  Journal(4) << "rebuilt_virtual_layer domain " << id.name_ << " " << id.timestep_ << endl;
++  if (lataDB.field_exists(id.timestep_, id.name_, "VIRTUAL_ELEMENTS")) {
++    Journal(4) << " Virtual elements data already exist. Skip" << endl;
++    return 1;
++  }
++  if (!lataDB.field_exists(id.timestep_, id.name_, "JOINTS_ELEMENTS")) {
++    Journal(4) << " Domain has no processor splitting information. Skip" << endl;
++    return 0;
++  }
++  // Load all domain, without faces:
++  id.block_ = -1;
++  DomainUnstructured dom;
++  dom.fill_domain_from_lataDB(lataDB, id, 0 /* no faces */);
++  // Compute virtual zones:
++  IntTab joints_virtual_elements;
++  IntTab virtual_elements;
++  find_virtual_layer(dom, virtual_elements, joints_virtual_elements, reconnect_tolerance);
++  // Write data to disk
++  const LataDBField & joints = lataDB.get_field(id.timestep_, id.name_, "JOINTS_ELEMENTS", "*");
++  LataDBField fld(joints);
++  // Append virtual_elements data to JOINTS_ELEMENTS, same format, etc
++  fld.name_ = "JOINTS_VIRTUAL_ELEMENTS";
++  fld.uname_ = Field_UName(fld.geometry_, fld.name_, "");
++  fld.nb_comp_ = 2;
++  fld.datatype_.file_offset_ = 0;
++  fld.filename_ += ".ghostdata";
++  lataDB.add_field(fld);
++  lataDB.write_data(id.timestep_, fld.uname_, joints_virtual_elements);
++  fld.name_ = "VIRTUAL_ELEMENTS";
++  fld.uname_ = Field_UName(fld.geometry_, fld.name_, "");
++  fld.nb_comp_ = 1;
++  fld.datatype_.file_offset_ = 1; // append
++  fld.size_ = virtual_elements.dimension(0);
++  lataDB.add_field(fld);
++  lataDB.write_data(id.timestep_, fld.uname_, virtual_elements);
++  return 1;
++}
+diff --git a/databases/readers/Lata/Rebuild_virtual_layer.h b/databases/readers/Lata/Rebuild_virtual_layer.h
+new file mode 100644
+index 0000000..f2666dd
+--- /dev/null
++++ b/databases/readers/Lata/Rebuild_virtual_layer.h
+@@ -0,0 +1,35 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++void find_virtual_layer(DomainUnstructured & domain,
++                        IntTab & virtual_elements,
++                        IntTab & joints_virtual_elements,
++                        double tolerance);
++
++entier rebuild_virtual_layer(LataDB & lataDB, Domain_Id id, double reconnect_tolerance);
+diff --git a/databases/readers/Lata/Sortie.h b/databases/readers/Lata/Sortie.h
+new file mode 100644
+index 0000000..69c967e
+--- /dev/null
++++ b/databases/readers/Lata/Sortie.h
+@@ -0,0 +1,44 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef Sortie_h_inclu
++#define Sortie_h_inclu
++#include <ostream>
++//using namespace std;
++using std::cerr;
++using std::endl;
++#define Sortie std::ostream
++class ArrOfInt;
++// for Static_Int_Lists
++inline Sortie& operator<<(Sortie& is, const ArrOfInt& t)
++{
++  throw;
++  return is;
++}
++#endif
+diff --git a/databases/readers/Lata/Static_Int_Lists.C b/databases/readers/Lata/Static_Int_Lists.C
+new file mode 100644
+index 0000000..4c3f065
+--- /dev/null
++++ b/databases/readers/Lata/Static_Int_Lists.C
+@@ -0,0 +1,128 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <Static_Int_Lists.h>
++// Description: detruit toutes les listes
++void Static_Int_Lists::reset()
++{
++  index_.resize_array(0);
++  valeurs_.resize_array(0);
++}
++
++// Description: detruit les listes existantes et en cree de nouvelles.
++//  On cree autant de listes que d'elements dans le tableau sizes.
++//  La i-ieme liste a une taille sizes[i]
++//  Les valeurs sizes doivent etre positives ou nulles.
++void Static_Int_Lists::set_list_sizes(const ArrOfInt& sizes)
++{
++  reset();
++
++  const entier nb_listes = sizes.size_array();
++  index_.resize_array(nb_listes + 1);
++  // Construction du tableau d'index
++  index_[0];
++  entier i;
++  for (i = 0; i < nb_listes; i++)
++    {
++      assert(sizes[i] >= 0);
++      index_[i+1] = index_[i] + sizes[i];
++    }
++  const entier somme_sizes = index_[nb_listes];
++  valeurs_.resize_array(somme_sizes);
++}
++
++// Description: tri par ordre croissant des valeurs de la i-ieme liste.
++//  Si num_liste < 0, on trie toutes les listes.
++void Static_Int_Lists::trier_liste(entier num_liste)
++{
++  const entier i_debut = (num_liste < 0) ? 0 : num_liste;
++  const entier i_fin   = (num_liste < 0) ? index_.size_array() - 1 : num_liste + 1;
++
++  entier i;
++  ArrOfInt valeurs_liste;
++  for (i = i_debut; i < i_fin; i++)
++    {
++      const entier index = index_[i];
++      const entier size  = index_[i+1] - index;
++      entier * data      = valeurs_.addr() + index;
++      valeurs_liste.ref_data(data, size);
++      valeurs_liste.ordonne_array();
++    }
++}
++
++// Description: copie la i-ieme liste dans le tableau fourni
++//  Le tableau array doit etre resizable.
++void Static_Int_Lists::copy_list_to_array(entier i, ArrOfInt& array) const
++{
++  const entier n = get_list_size(i);
++  array.resize_array(0); // Ne pas copier les donnees d'origine
++  array.resize_array(n);
++  entier index = index_[i];
++  entier j = 0;
++  for (j = 0; j < n; index++, j++)
++    array[j] = valeurs_[index];
++}
++
++Sortie& Static_Int_Lists::printOn(Sortie& os) const
++{
++  os << index_   << " ";
++  os << valeurs_ << " ";
++  return os;
++}
++
++Entree& Static_Int_Lists::readOn(Entree& is)
++{
++  reset();
++  is >> index_;
++  is >> valeurs_;
++  return is;
++}
++
++Sortie& Static_Int_Lists::ecrire(Sortie& os) const
++{
++  os << "nb lists       : " << get_nb_lists() << finl;
++  os << "sizes of lists : ";
++  for (entier i=0; i<get_nb_lists(); ++i)
++    {
++      os << get_list_size(i) << " ";
++    }
++  os << finl;
++
++  for (entier i=0; i<get_nb_lists(); ++i)
++    {
++      os << "{ " ;
++      const entier sz = get_list_size(i);
++      for (entier j=0; j<sz; ++j)
++        {
++          os <<  valeurs_[(index_[i]+j)] << " ";
++        }
++      os << "}" << finl;
++    }
++  return os;
++}
+diff --git a/databases/readers/Lata/Static_Int_Lists.h b/databases/readers/Lata/Static_Int_Lists.h
+new file mode 100644
+index 0000000..3f28783
+--- /dev/null
++++ b/databases/readers/Lata/Static_Int_Lists.h
+@@ -0,0 +1,110 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef Static_Int_Lists_def
++#define Static_Int_Lists_def
++
++#include <ArrOfInt.h>
++
++// .DESCRIPTION
++//  Cette classe permet de stocker des listes d'entiers accessibles
++//  en temps constant. La taille des listes ne peut pas changer sans
++//  perdre le contenu (ce sont des listes statiques).
++//  Exemple:
++//   Static_Int_List l;
++//   ArrOfInt tailles(3);
++//   tailles[0] = 2; tailles[1] = 3; tailles[2] = 0;
++//   // On reserve la memoire pour trois listes de taille 2, 3 et 0:
++//   l.set_list_sizes(tailles);
++//   // On affecte une valeur au deuxieme element de la premiere liste:
++//   l.set_value(0,1,765);
++//   // Affiche la valeur
++//   cout << l(0,1);
++class Static_Int_Lists
++{
++public:
++  void set_list_sizes(const ArrOfInt& sizes);
++  void reset();
++  void copy_list_to_array(entier i_liste, ArrOfInt& array) const;
++
++  inline void   set_value(entier i_liste, entier i_element, entier valeur);
++  inline entier operator() (entier i_liste, entier i_element) const;
++  inline entier get_list_size(entier i_liste) const;
++  inline entier get_nb_lists() const;
++
++  void trier_liste(entier i);
++
++  Sortie& printOn(Sortie& os) const;
++  Entree& readOn(Entree& is);
++
++  Sortie& ecrire(Sortie& os) const;
++
++private:
++  // Les listes d'entiers sont stockees de facon contigue
++  // dans le tableau valeurs_.
++  // Le premier element de la liste i est valeurs_[index_[i]]
++  // et le dernier element est valeurs_[index_[i+1]-1]
++  // (c'est comme le stockage morse des matrices).
++  ArrOfInt index_;
++  ArrOfInt valeurs_;
++};
++
++// Description: affecte la "valeur" au j-ieme element de la i-ieme liste avec
++//  0 <= i < get_nb_lists()  et  0 <= j < get_list_size(i)
++inline void Static_Int_Lists::set_value(entier i, entier j, entier valeur)
++{
++  const entier index = index_[i] + j;
++  assert(index < index_[i+1]);
++  valeurs_[index] = valeur;
++}
++
++// Description: renvoie le j-ieme element de la i-ieme liste avec
++//  0 <= i < get_nb_lists()  et  0 <= j < get_list_size(i)
++inline entier Static_Int_Lists::operator() (entier i, entier j) const
++{
++  const entier index = index_[i] + j;
++  assert(index < index_[i+1]);
++  const entier val = valeurs_[index];
++  return val;
++}
++
++// Description: renvoie le nombre d'elements de la liste i
++inline entier Static_Int_Lists::get_list_size(entier i) const
++{
++  const entier size = index_[i+1] - index_[i];
++  return size;
++}
++
++// Description: renvoie le nombre de listes stockees
++inline entier Static_Int_Lists::get_nb_lists() const
++{
++  return index_.size_array() - 1;
++}
++
++#endif
+diff --git a/databases/readers/Lata/UserFields.C b/databases/readers/Lata/UserFields.C
+new file mode 100644
+index 0000000..575c231
+--- /dev/null
++++ b/databases/readers/Lata/UserFields.C
+@@ -0,0 +1,1038 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#include <UserFields.h>
++#include <LataFilter.h>
++#include <stdlib.h>
++// ********************************************************************************
++// METHODES OUTILS DE GESTION
++//  (normalement, on n'a pas besoin de les modifier mais on peut en ajouter...)
++// ********************************************************************************
++
++// Implementation de la classe Geometry_handle
++// (utiliser cette classe pour eviter d'avoir a faire des dynamic_cast
++//  compliques et pour ne pas avoir a gerer get_geometry et release_geometry a la main)
++// Exemple d'utilisation: voir interpoler_elem_vers_som()
++Geometry_handle::Geometry_handle()
++{
++}
++void Geometry_handle::set(LataFilter & lata_filter, const Domain_Id & id)
++{
++  lata_filter_ = lata_filter;
++  geom_ = lata_filter.get_geometry(id);
++}
++Geometry_handle::Geometry_handle(Geometry_handle & handle)
++{
++  operator=(handle);
++}
++Geometry_handle & Geometry_handle::operator=(Geometry_handle & handle)
++{
++  reset();
++  lata_filter_ = handle.lata_filter_;
++  // Get another reference from the lata filter (to increment ref counter in the cache)
++  geom_ = lata_filter_.valeur().get_geometry(handle.geom_.valeur().id_);
++  return *this;
++}
++Geometry_handle::~Geometry_handle()
++{
++  reset();
++}
++void Geometry_handle::reset()
++{
++  if (geom_.non_nul())
++    lata_filter_.valeur().release_geometry(geom_.valeur());
++  geom_.reset();
++  lata_filter_.reset();
++}
++const DomainUnstructured & Geometry_handle::geom()
++{
++  if (!geom_.non_nul()) {
++    Journal() << "Internal error in Geometry_handle::geom() : nul pointer" << endl;
++    throw;
++  }
++  const DomainUnstructured* ptr = dynamic_cast<const DomainUnstructured *>(&geom_.valeur());
++  if (!ptr) {
++    Journal() << "Error in Geometry_handle::geom() : domain " 
++              << geom_.valeur().id_.name_ << " is not unstructured" << endl;
++    throw;
++  }
++  return *ptr;
++}
++const DomainIJK & Geometry_handle::geom_ijk()
++{
++  if (!geom_.non_nul()) {
++    Journal() << "Internal error in Geometry_handle::geom() : nul pointer" << endl;
++    throw;
++  }
++  const DomainIJK* ptr = dynamic_cast<const DomainIJK *>(&geom_.valeur());
++  if (!ptr) {
++    Journal() << "Error in Geometry_handle::geom() : domain " 
++              << geom_.valeur().id_.name_ << " is not IJK" << endl;
++    throw;
++  }
++  return *ptr;
++}
++entier Geometry_handle::test_ijk()
++{
++  if (!geom_.non_nul()) {
++    Journal() << "Internal error in Geometry_handle::geom() : nul pointer" << endl;
++    throw;
++  }
++  const DomainIJK* ptr = dynamic_cast<const DomainIJK *>(&geom_.valeur());
++  if (ptr)
++    return 1;
++  else
++    return 0;
++}
++
++// Petite fonction outil qui construit l'objet LataFieldMetaData en changeant uniquement 
++//  le nom du champ (dimension, localisation, geometrie, nombre de composantes sont identiques)
++//  Le champ "source" est rempli avec une reference a source, on pourra donc appeler
++//  get_champ_source() (voir interpoler_elem_vers_som pour un exemple)
++// Voir new_fields_metadata() pour un exemple d'utilisation.
++static LataFieldMetaData declare_new_name(const LataFieldMetaData & source, 
++                                          const char * name)
++{
++  LataFieldMetaData dest = source;
++  // Lorsqu'on demandera ce champ, on saura que c'est UserFields qui devra le calculer
++  dest.source_ = "user_fields";
++  // On change le nom du champ:
++  dest.name_ = name;
++  dest.uname_.set_field_name(name);
++  // On remplit le champ source
++  dest.source_field_ = source.uname_;
++  
++  return dest;
++}
++
++// Fonction identique a declare_new_name, mais pour declarer un champ avec une localisation
++//  differente.
++// Voir new_fields_metadata() pour un exemple d'utilisation.
++static LataFieldMetaData declare_new_name_localisation(const LataFieldMetaData & source, 
++                                                       const char * name,
++                                                       LataField_base::Elem_som loc)
++{
++  LataFieldMetaData dest = source;
++  // Lorsqu'on demandera ce champ, on saura que c'est UserFields qui devra le calculer
++  dest.source_ = "user_fields";
++  // On change le nom du champ et la localisation:
++  dest.name_ = name;
++  dest.uname_ = Field_UName(source.uname_.get_geometry(),
++                            name,
++                            LataField_base::localisation_to_string(loc));
++  // On remplit le champ source
++  dest.source_field_ = source.uname_;
++
++  // En plus: je change la localisation:
++  dest.localisation_ = loc;
++
++  return dest;
++}
++
++// Fonction identique a declare_new_name, mais pour declarer un champ avec une localisation
++//  differente de type vectoriel.
++// Voir new_fields_metadata() pour un exemple d'utilisation.
++static LataFieldMetaData declare_new_vector_field(const LataFieldMetaData & source, 
++                                                  const char * name,
++                                                  LataField_base::Elem_som loc,
++                                                  const entier dim)
++{
++  LataFieldMetaData dest = source;
++  // Lorsqu'on demandera ce champ, on saura que c'est UserFields qui devra le calculer
++  dest.source_ = "user_fields";
++  // On change le nom du champ et la localisation:
++  dest.name_ = name;
++  dest.uname_ = Field_UName(source.uname_.get_geometry(),
++                            name,
++                            LataField_base::localisation_to_string(loc));
++  // On remplit le champ source
++  dest.source_field_ = source.uname_;
++
++  // En plus: je change la localisation:
++  dest.localisation_ = loc;
++
++  // et le type (vecteur)
++  dest.component_names_.reset();
++  dest.nb_components_ = dim;
++  dest.is_vector_ = 1;
++
++  return dest;
++}
++
++// Description: demande a la classe LataFilter le champ source du champ "id"
++//  qui a ete declare quand on a appele declare_new_name() au debut
++// Voir filtre_boite() pour un exemple d'utilisation.
++FieldType UserFields::get_champ_source(const Field_Id & id)
++{
++  // Cherche la structure LataFieldMetaData du champ "id":
++  const LataFieldMetaData & data = lata_filter_.valeur().get_field_metadata(id.uname_);
++  Field_Id id2(data.source_field_, id.timestep_, id.block_);
++  FieldType tmp;
++  const LataField_base & field = lata_filter_.valeur().get_field(id2);
++  const FieldType* ptr = dynamic_cast<const FieldType *>(&field);
++  if (!ptr) {
++    Journal() << "Error in UserFields::get_champ_source : field " << id.uname_ 
++              << " is not a floattab" << endl;
++    throw;
++  }
++  // Copie le contenu du champ dans un tableau temporaire:
++  tmp = *ptr;
++  // Libere le champ d'origine
++  lata_filter_.valeur().release_field(field);
++  return tmp;
++}
++
++// Description: demande a la classe LataFilter le champ de nom "nom" et dont
++//  la geometrie, le pas de temps et la localisation sont celles de "id".
++FieldType UserFields::get_champ(const Nom & nom, const Field_Id & id)
++{
++  FieldType tmp;
++  // Construit un Field_Id identique, seul le nom du champ chamge:
++  Field_Id id2(id);
++  id2.uname_.set_field_name(nom);
++  const LataField_base & field = lata_filter_.valeur().get_field(id2);
++  const FieldType* ptr = dynamic_cast<const FieldType *>(&field);
++  if (!ptr) {
++    Journal() << "Error in UserFields::get_champ : field " << id.uname_ 
++              << " is not a floattab" << endl;
++    throw;
++  }
++  // Copie le contenu du champ dans un tableau temporaire:
++  tmp = *ptr;
++  // Libere le champ d'origine
++  lata_filter_.valeur().release_field(field);
++
++  return tmp;
++}
++
++// Description: idem, mais cherche un champ avec une localisation differente de id
++FieldType UserFields::get_champ_loc(const Nom & nom, LataField_base::Elem_som loc, const Field_Id & id)
++{
++  FieldType tmp;
++  // Construit un Field_Id identique, seul le nom du champ chamge:
++  Field_Id id2(id);
++  id2.uname_ = Field_UName(id.uname_.get_geometry(), nom, LataField_base::localisation_to_string(loc));
++  
++  const LataField_base & field = lata_filter_.valeur().get_field(id2);
++  const FieldType* ptr = dynamic_cast<const FieldType *>(&field);
++  if (!ptr) {
++    Journal() << "Error in UserFields::get_champ : field " << id.uname_ 
++              << " is not a floattab" << endl;
++    throw;
++  }
++  // Copie le contenu du champ dans un tableau temporaire:
++  tmp = *ptr;
++  // Libere le champ d'origine
++  lata_filter_.valeur().release_field(field);
++
++  return tmp;
++}
++
++// Description: renvoie un objet Geometry_handle qui pointe sur le domaine
++//  support du champ "id".
++// Voir interpoler_elem_vers_som() pour un exemple d'utilisation
++void UserFields::get_geometry(const Domain_Id & id, Geometry_handle & h)
++{
++  h.set(lata_filter_.valeur(), id);
++}
++
++// ********************************************************************************
++//  METHODES OUTILS DE CALCUL
++//  Ces methodes sont des fonctions qui calculent un champ en fonction d'un autre champ.
++//  On peut les modifier comme on veut, en ajouter, etc... 
++//  Lachez-vous...
++// ********************************************************************************
++
++// Description:
++//  Fonction d'interpolation qui transforme un champ aux "elements"
++//  en un champ aux "sommets".
++//  Dans cet exemple, on a deux algorithmes selon que le champ est sur
++//  un maillage ijk ou non.
++//  La valeur aux sommets est la moyenne des valeurs sur les elements adjacents.
++FieldType UserFields::interpoler_elem_vers_som(const Field_Id & id)
++{
++  // Recupere le champ a filtrer (champ aux elements)
++  FieldType source = get_champ_source(id);
++
++  FieldType resu;
++  // Remplissage des meta-data du champ:
++  resu.id_ = id;
++  resu.component_names_ = source.component_names_;
++  resu.localisation_ = LataField_base::SOM;
++  resu.nature_ = source.nature_;
++  
++  // Recupere la geometrie (domaine ijk ou non structure) sur laquelle est definie
++  //  le champ source:
++  Geometry_handle geom;
++  get_geometry(id, geom);
++  ArrOfFloat poids;
++
++  if (geom.test_ijk()) {
++    const DomainIJK & dom = geom.geom_ijk();
++    // Le code suivant marche en 1D, 2D et 3D:
++    const entier nbsom = dom.nb_nodes();
++    const entier nbcompo = source.data_.dimension(1);
++    resu.data_.resize(nbsom, nbcompo);
++    const entier nsom_x = dom.nb_som_dir(0);
++    const entier nsom_y = dom.nb_som_dir(1);
++    const entier nelem_x = dom.nb_elem_dir(0);
++    const entier nelem_y = dom.nb_elem_dir(1);
++    const entier nelem_z = dom.nb_elem_dir(2);
++    poids.resize_array(nbsom);
++    const entier ni = 2;
++    const entier nj = (dom.dimension() > 1) ? 2 : 1;
++    const entier nk = (dom.dimension() > 2) ? 2 : 1;
++
++    // Avec les boucles imbriquees comme ceci, on parcourt tous les
++    //  elements dans l'ordre croissant:
++    // (l'indice de l'element (i,j,k) est :
++    //    elem = (k * nelem_y + j) * nelem_x + i
++    entier elem = 0;
++    for (entier k = 0; k < nelem_z; k++) {
++      for (entier j = 0; j < nelem_y; j++) {
++        for (entier i = 0; i < nelem_x; i++) {
++          if (dom.invalid_connections_.size_array() == 0 || dom.invalid_connections_[elem] == 0) {
++            // Element valide:
++            // Boucle sur les sommets de l'element
++            const entier som0 = (k * nsom_y + j) * nsom_x + i;
++            for (entier kk = 0; kk < nk; kk++) {
++              for (entier jj = 0; jj < nj; jj++) {
++                for (entier ii = 0; ii < ni; ii++) {
++                  entier som = som0 + (kk * nsom_y + jj) * nsom_x + ii;
++                  for (entier compo = 0; compo < nbcompo; compo++)
++                    resu.data_(som, compo) += source.data_(elem, compo);
++                  poids[som] += 1.;
++                }
++              }
++            }
++          }
++          elem++;
++        }
++      }
++    }
++  } else {
++    const DomainUnstructured & dom = geom.geom();
++
++    const entier nbsom = dom.nb_nodes();
++    const entier nbcompo = source.data_.dimension(1);
++    resu.data_.resize(nbsom, nbcompo);
++    poids.resize_array(nbsom);
++    const IntTab & les_elem = dom.elements_;
++    const entier n = les_elem.dimension(0);
++    const entier m = les_elem.dimension(1);
++    int i, j, k;
++    for ( i = 0; i < n; i++) {
++      for (j = 0; j < m; j++) {
++        entier som = les_elem(i,j);
++        for (k = 0; k < nbcompo; k++) {
++          float x = source.data_(i, k);
++          resu.data_(som, k) += x;
++        }
++        poids[som] += 1.;
++      }
++    }
++  }
++  const entier nbsom = poids.size_array();
++  const entier nbcompo = resu.data_.dimension(1);
++  for (entier i = 0; i < nbsom; i++)
++    for (entier k = 0; k < nbcompo; k++)
++      resu.data_(i, k) /= poids[i];
++
++  return resu;
++}
++
++
++
++
++
++//  Attention: le constructeur par defaut n'initialise pas le vecteur !
++class Vecteur3
++{
++public:
++  Vecteur3() {};
++  Vecteur3(const Vecteur3 & w) {
++    v[0] = w.v[0]; v[1] = w.v[1]; v[2] = w.v[2];
++  }
++  Vecteur3(double x, double y, double z) {
++    v[0] = x; v[1] = y; v[2] = z;
++  }
++  void  set(double x, double y, double z) {
++    v[0] = x; v[1] = y; v[2] = z;
++  }
++  double length() const { return sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); };
++  Vecteur3(const DoubleTab & tab, entier i) {
++    //assert(tab.line_size() == 3);
++    assert(i >= 0 && i < tab.dimension_tot(0));
++    const double *ptr = tab.addr() + i * 3;
++    v[0] = ptr[0];
++    v[1] = ptr[1];
++    v[2] = ptr[2];
++  }
++  Vecteur3 & operator=(double x) {
++    v[0] = x; v[1] = x; v[2] = x;
++    return *this;
++  }
++  Vecteur3 & operator*=(double x) {
++    v[0] *= x; v[1] *= x; v[2] *= x;
++    return *this;
++  }
++
++  Vecteur3 & operator=(const Vecteur3 & w) {
++    v[0] = w.v[0]; v[1] = w.v[1]; v[2] = w.v[2];
++    return *this;
++  }
++  double               operator[](entier i) const { assert(i>=0 && i<3); return v[i]; }
++  double &             operator[](entier i)       { assert(i>=0 && i<3); return v[i]; }
++  inline        double norme_Linfini();
++  static inline void   produit_vectoriel(const Vecteur3 & x, const Vecteur3 & y, Vecteur3 & resu);
++  static inline double produit_scalaire(const Vecteur3 & x, const Vecteur3 & y);
++  friend Vecteur3 operator-(const Vecteur3 &, const Vecteur3 &);
++protected:
++  double v[3];
++};
++
++
++inline void Vecteur3::produit_vectoriel(const Vecteur3 & x, const Vecteur3 & y, Vecteur3 & z)
++{
++  z.v[0] = x.v[1] * y.v[2] - x.v[2] * y.v[1];
++  z.v[1] = x.v[2] * y.v[0] - x.v[0] * y.v[2];
++  z.v[2] = x.v[0] * y.v[1] - x.v[1] * y.v[0];
++}
++
++inline double Vecteur3::produit_scalaire(const Vecteur3 & x, const Vecteur3 & y)
++{
++  double r = x.v[0] * y.v[0] + x.v[1] * y.v[1] + x.v[2] * y.v[2];
++  return r;
++}
++
++// Description: norme L_infini, c'est le max des abs(v[i])
++inline double Vecteur3::norme_Linfini()
++{
++  double x = fabs(v[0]);
++  double y = fabs(v[1]);
++  double z = fabs(v[2]);
++  double resu = ((x > y) ? x : y);
++  resu = ((resu > z) ? resu : z);
++  return resu;  
++}
++
++inline Vecteur3 operator-(const Vecteur3 & x, const Vecteur3 & y)
++{
++  Vecteur3 z;
++  z.v[0] = x.v[0] - y.v[0];
++  z.v[1] = x.v[1] - y.v[1];
++  z.v[2] = x.v[2] - y.v[2];
++  return z;
++}
++
++double largest_angle_2(const DoubleTab& coords)
++        
++{
++  if (((coords.dimension(0)!=4)&&(coords.dimension(0)!=3))||(coords.dimension(1)!=3))
++    {
++      Cerr<<" cas nn prevu"<<endl; 
++      throw;
++    }
++  int nb_face=coords.dimension(0);
++  Vecteur3 normals[4];
++  Vecteur3 edge[2],opp;
++  edge[1].set(0,0,1);
++  for (int n=0;n<nb_face;n++)
++    {
++     
++      int prem=0;
++      if (n==0) prem=1;
++      int compteur=0;
++      for (int s=0;s<nb_face;s++)
++        {
++
++          if ((s!=n) && (s!=prem))
++            {
++              edge[compteur].set(coords(s,0)-coords(prem,0),
++                                 coords(s,1)-coords(prem,1),
++                                 coords(s,2)-coords(prem,2));
++              compteur++;
++            }
++        }
++      if (compteur!=nb_face-2) throw;
++      opp.set(coords(n,0)-coords(prem,0),
++              coords(n,1)-coords(prem,1),
++              coords(n,2)-coords(prem,2));
++      Vecteur3::produit_vectoriel(edge[0],edge[1],normals[n]);
++      //normals[n]=edge[0]*edge[1];
++      normals[n]*=1./normals[n].length();
++      if (Vecteur3::produit_scalaire(normals[n],opp)<0)
++        normals[n]*=-1;
++    }
++  // on a les 4 normals orientes vers l'interieur
++  double max_pscal=-100;
++  for (int n1=0;n1<nb_face;n1++)
++    for (int n2=n1+1;n2<nb_face;n2++)
++      {
++        double pscal=Vecteur3::produit_scalaire(normals[n1],normals[n2]);
++        //min_pscal=pscal;
++        if (pscal>max_pscal)
++          max_pscal=pscal;
++      }
++  double tet=acos(max_pscal)/acos(-1.)*180; // PL: acos(-1) ne compile pas sur de multiples plateformes
++  
++  tet=180-tet;
++  return tet;
++}
++
++
++
++FieldType UserFields::calculer_angle(const Field_Id & id)
++{
++  // Recupere le champ a filtrer (champ aux elements)
++  //  FieldType source = get_champ_source(id);
++  
++  FieldType resu;
++  // Remplissage des meta-data du champ:
++  resu.id_ = id;
++  const LataFieldMetaData & data = lata_filter_.valeur().get_field_metadata(id.uname_);
++  resu.component_names_ = data.component_names_;
++  resu.localisation_ = data.localisation_;
++  resu.nature_ = LataDBField::SCALAR;
++  
++  // Recupere la geometrie (domaine ijk ou non structure) sur laquelle est definie
++  //  le champ source:
++  Geometry_handle geom;
++  get_geometry(id, geom);
++
++  if (geom.test_ijk()) {
++    Journal() <<    "non code" <<endl;
++    throw;
++  } else {
++    const DomainUnstructured & dom = geom.geom();
++    const entier nbcompo = dom.dimension();
++    //poids.resize_array(nbsom);
++    const IntTab & les_elem = dom.elements_;
++    const entier n = les_elem.dimension(0);
++ 
++    resu.data_.resize(n, nbcompo);
++    
++    const FloatTab& nodes_=dom.nodes_;
++    int nb_som_elem=les_elem.dimension(1);
++    DoubleTab coords(nb_som_elem,3);
++    for ( int i = 0; i < n; i++) {
++      for (int s=0;s<nb_som_elem;s++)
++        for (int d=0;d<nodes_.dimension(1);d++)
++          coords(s,d)=nodes_(les_elem(i,s),d);
++      resu.data_(i, 0) = largest_angle_2(coords);
++        
++    }
++  
++  }
++  return resu;
++}
++
++FieldType UserFields::calculer_normale(const Field_Id & id)
++{
++
++  // Recupere le champ a filtrer (champ aux elements)
++  //  FieldType source = get_champ_source(id);
++
++  FieldType resu;
++  // Remplissage des meta-data du champ:
++  resu.id_ = id;
++  const LataFieldMetaData & data = lata_filter_.valeur().get_field_metadata(id.uname_);
++  resu.component_names_ = data.component_names_;
++  resu.localisation_ = data.localisation_;
++  resu.nature_ = LataDBField::VECTOR;
++  
++  // Recupere la geometrie (domaine ijk ou non structure) sur laquelle est definie
++  //  le champ source:
++  Geometry_handle geom;
++  get_geometry(id, geom);
++
++  if (geom.test_ijk()) {
++    Journal() <<    "non code" <<endl;
++    throw;
++  } else {
++    const DomainUnstructured & dom = geom.geom();
++    const entier nbcompo = dom.dimension();
++    const IntTab & les_elem = dom.elements_;
++    const entier n = les_elem.dimension(0);
++ 
++    resu.data_.resize(n, nbcompo);
++    
++    const FloatTab& nodes_=dom.nodes_;
++    
++    ArrOfFloat v1( nbcompo),v2(nbcompo);
++    ArrOfDouble nor(nbcompo);
++    for ( int i = 0; i < n; i++) {
++      // calcul de la normale
++      entier som0 = les_elem(i,0);
++      entier som1 = les_elem(i,1);
++      for (int j=0;j<nbcompo;j++)
++        v1[j]=nodes_(som1,j)-nodes_(som0,j);
++      if (nbcompo==3)
++        {
++          entier som2 = les_elem(i,2);
++          for (int j=0;j<nbcompo;j++)
++            v2[j]=nodes_(som2,j)-nodes_(som0,j);
++          
++          nor[0]=v1[1]*v2[2]-v1[2]*v2[1];
++          nor[1]=v1[2]*v2[0]-v1[0]*v2[2];
++          nor[2]=v1[0]*v2[1]-v1[1]*v2[0];
++          nor/=2.;
++        }
++      else
++        {
++          assert(nbcompo==2);
++          nor[0]=v1[1];
++          nor[1]=-v1[0];
++          
++        }
++      for (int k = 0; k < nbcompo; k++) {
++        resu.data_(i, k) = nor[k];
++      }
++       
++    }
++    
++  }
++  
++
++  return resu;
++}
++
++// Description:
++//  Fonction d'interpolation qui transforme un champ de vitesse VDF aux "faces"
++//  en un champ aux "elements".
++//  Ne fonctionne que sur les maillages ijk !
++//  On attend un champ scalaire a une composante en entree (champ source)
++//  et on fournit en sortie un champ vectoriel a "dimension" composantes.
++FieldType UserFields::interpoler_faces_vdf_vers_elem(const Field_Id & id)
++{
++  // Recupere le champ a filtrer (champ aux elements)
++  FieldType source = get_champ_source(id);
++  
++  if (source.localisation_ != LataField_base::FACES) {
++    Journal() << "Error in UserFields::interpoler_faces_vdf_vers_elem: source field " << id.uname_.build_string()
++              << " is not at faces !" << endl;
++    throw;
++  }
++
++  // Get geometry:
++  Geometry_handle geom;
++  get_geometry(id, geom);
++  if (!geom.test_ijk()) {
++    Journal() << "Error in UserFields::interpoler_faces_vdf_vers_elem: geometry of field " << id.uname_.build_string()
++              << " is not IJK" << endl;
++    throw;
++  }
++  const DomainIJK & dom = geom.geom_ijk();
++
++  const entier dim = dom.dimension();
++  
++  if (source.data_.dimension(1) != dim) {
++    Journal() << "Error in UserFields::interpoler_faces_vdf_vers_elem: source field " << id.uname_.build_string()
++              << " must have " << dim << " components !" << endl;
++    throw;
++  }
++
++  FieldType resu;
++  // Remplissage des meta-data du champ:
++  resu.id_ = id;
++  resu.component_names_.reset();
++  resu.localisation_ = LataField_base::ELEM;
++  resu.nature_ = LataDBField::VECTOR;
++
++  // Le code suivant marche en 1D, 2D et 3D:
++  const entier nbelem = dom.nb_elements();
++  const entier nbcompo = dim;
++  resu.data_.resize(nbelem, nbcompo);
++  const entier nelem_x = dom.nb_elem_dir(0);
++  const entier nelem_y = dom.nb_elem_dir(1);
++  const entier nelem_z = dom.nb_elem_dir(2);
++  const entier nfaces_x = dom.nb_som_dir(0);
++  const entier nfaces_y = dom.nb_som_dir(1);
++  // Avec les boucles imbriquees comme ceci, on parcourt tous les
++  //  elements dans l'ordre croissant:
++  // (l'indice de l'element (i,j,k) est :
++  //    elem = (k * nelem_y + j) * nelem_x + i
++  entier elem = 0;
++  for (entier k = 0; k < nelem_z; k++) {
++    for (entier j = 0; j < nelem_y; j++) {
++      for (entier i = 0; i < nelem_x; i++) {
++        if (dom.invalid_connections_.size_array() == 0 || dom.invalid_connections_[elem] == 0) {
++          // Element valide:
++          // Boucle sur les trois directions:
++          for (entier dir = 0; dir < dim; dir++) {
++            // indices des deux faces opposees de l'element dan la direction dir:
++            const entier face1 = (k * nfaces_y + j) * nfaces_x + i;
++            entier face2;
++            if (dir == 0)
++              face2 = face1 + 1;
++            else if (dir == 1)
++              face2 = face1 + nfaces_x;
++            else
++              face2 = face1 + nfaces_y * nfaces_x;
++            // On fait la moyenne des vitesses sur les deux faces
++            double v_moy = (source.data_(face1, dir) + source.data_(face2, dir)) * 0.5;
++            resu.data_(elem, dir) = v_moy;
++          }
++        }
++        elem++;
++      }
++    }
++  }
++  return resu;
++}
++
++// **********************************************************************************
++// METHODES UTILISATEUR: ces methodes sont a mettre a jour en fonction des besoins
++//  specifiques...
++// **********************************************************************************
++
++// Description: Constructeur de la classe.
++//  Attention: penser a initialiser toutes les variables de la classe (options)
++UserFields_options::UserFields_options()
++{
++  demie_largeur_filtre_boite_ = 1;
++}
++
++// Cette methode est appelee avec les options en ligne de commande ou sur la troisieme
++//  ligne. Il faut renvoyer 0 si on ne comprend pas l'option, sinon 1.
++entier UserFields_options::parse_option(const Nom & option)
++{
++  if (option.debute_par("demie_largeur_filtre_boite=")) {
++    demie_largeur_filtre_boite_ = LataOptions::read_int_opt(option);
++  } else {
++    return 0;
++  }
++  return 1;
++}
++
++// Cette methode est appelee par lata2dx en ligne de commande pour afficher une aide.
++// On peut decrire toutes les options...
++void UserFields_options::print_help_option() const
++{
++  cerr << "Options provided by UserFields:" << endl;
++  cerr << " demie_largeur_filtre_boite=N  (see filtre_boite implementation)" << endl;
++}
++
++// Description:
++//  Cette methode est appelee par lata2dx au debut pour connaitre la liste
++//  des champs que UserFields est capable de calculer.
++//  fields_data contient en entree tous les champs deja fournis par lata2dx
++//   (champs presents dans le fichier .lata, plus les champs resultant des operateurs
++//    standards (regularize, dualmesh etc...)
++//  On doit ajouter dans fields_data la description des champs supplementaires 
++//   que UserFields peut calculer.
++void UserFields::new_fields_metadata(LataFilter & filter,
++                                     LataVector<LataFieldMetaData> & fields_data)
++{
++  lata_filter_ = filter;
++
++  const Noms geoms = filter.get_exportable_geometry_names();
++  
++  const entier nb_geometries = geoms.size();
++  
++  for (int i = 0; i < nb_geometries; i++) {
++    const LataGeometryMetaData data = filter.get_geometry_metadata(geoms[i]);
++    
++    // Si on a des faces, proposer la normale aux faces
++    int topo_dim=data.dimension_;
++    
++    switch(data.element_type_) {
++    case Domain::point:     topo_dim = 0; break;
++    case Domain::line:      topo_dim = 1; break;
++    case Domain::triangle:
++    case Domain::polygone:
++    case Domain::quadri:    topo_dim = 2; break;
++    case Domain::tetra:
++    case Domain::prism6:
++    case Domain::polyedre:
++    case Domain::hexa:      topo_dim = 3; break;
++    default:
++      cerr << "avtlataFileFormat::PopulateDatabaseMetaData error: unknown element type" << endl;
++      throw;
++    }
++    if ((data.dimension_>1)&&(topo_dim!=data.dimension_)) {
++      Journal(1)<<"Ajout de la normale"<<endl;
++      LataFieldMetaData dest;
++      dest.name_ = "normals/NORMALE";
++      dest.geometry_name_ = data.internal_name_;
++      dest.component_names_.reset() ;
++      
++      dest.nb_components_ = data.dimension_;
++      dest.is_vector_ = 1;
++      dest.localisation_ = LataField_base::ELEM;
++      dest.source_localisation_ = "ELEM";
++      dest.source_ = "user_fields";
++      // source_field_ inutile.
++      
++      dest.uname_ = Field_UName(dest.geometry_name_,
++                                dest.name_,
++                                LataField_base::localisation_to_string(dest.localisation_));
++      fields_data.add(dest);
++    }
++    else
++    if (data.element_type_==Domain::triangle||data.element_type_==Domain::tetra)
++      
++      {
++         Journal(1)<<"Ajout de mesh_quality/LargestAngle"<<endl;
++         LataFieldMetaData dest;
++         dest.name_ = "mesh_quality/LargestAngle";
++         dest.geometry_name_ = data.internal_name_;
++         dest.component_names_.reset() ;
++      
++         dest.nb_components_ = 1;
++         dest.is_vector_ = 0;
++         dest.localisation_ = LataField_base::ELEM;
++         dest.source_localisation_ = "ELEM";
++         dest.source_ = "user_fields";
++         // source_field_ inutile.
++      
++         dest.uname_ = Field_UName(dest.geometry_name_,
++                                   dest.name_,
++                                   LataField_base::localisation_to_string(dest.localisation_));
++         fields_data.add(dest);
++      }
++  }
++  // on laisse les lignes pour verifier la compilation
++  if ( 0) {
++  const entier nb_fields_debut = fields_data.size();
++  
++  // On fait une boucle sur tous les champs disponibles dans le filtre
++  //  (nb_fields_debut est le nombre de champs existant avant qu'on 
++  //   commence a en ajouter dans le tableau fields_data)
++
++  for (int i_in = 0; i_in < nb_fields_debut; i_in++) 
++    {
++      // On cherche si le champ de temperature aux elements existe
++      //  sur une geometrie IJK (Motcle permet d'ignorer majuscule/minuscule)
++      const LataFieldMetaData data = fields_data[i_in];
++
++      // Les deux if suivants sont des EXEMPLES
++
++      if (Motcle(data.name_) == "TEMPERATURE"
++          && data.localisation_ == LataField_base::ELEM
++          && Motcle(data.geometry_name_).finit_par("_IJK"))
++        {
++          // On declare un champ identique qui s'appelle MOYENNE_TEMPERATURE
++          fields_data.add(declare_new_name(data, "MOYENNE_TEMPERATURE"));
++        }
++
++      // Si le champ est aux elements, on propose une interpolation aux sommets
++      // On reconnaitra le champ parce que son nom finira par elem_vers_som (voir get_field())
++      if (data.localisation_ == LataField_base::ELEM)
++        {
++          Nom nom = data.name_;
++          nom += "_elem_vers_som";
++          fields_data.add(declare_new_name_localisation(data, nom, LataField_base::SOM));
++        }
++
++      // Si le champ est aux faces et le maillage est ijk, on propose
++      //  une interpolation aux elements
++      if (data.localisation_ == LataField_base::FACES
++          && Motcle(data.geometry_name_).finit_par("_IJK"))
++        {
++          Nom nom = data.name_;
++          nom += "_faces_vers_elem";
++          // Le champ aux faces a deja dimension composantes
++          const entier dim = data.nb_components_;
++          fields_data.add(declare_new_vector_field(data, nom, LataField_base::ELEM, dim));
++        }
++    }
++  }
++}
++
++// Description:
++//  Cette methode publique est appelee par lata2dx pour obtenir les champs declares dans
++//  new_fields_metadata. Il faut tester "id" et calculer le champ demande.
++//  On a le droit d'appeler get_champ() pour obtenir d'autres champs.
++FieldType UserFields::get_field(const Field_Id & id)
++{
++  // Convertit le nom du champ en majuscules:
++  Motcle nom(id.uname_.get_field_name());
++
++  // Ces deux lignes sont des EXEMPLES (a remplacer par les champs qu'on veut
++  //  effectivement calculer)
++  if (nom == "moyenne_temperature")    return filtre_boite(id);
++  else if (nom.finit_par("_elem_vers_som")) return interpoler_elem_vers_som(id);
++  else if (nom.finit_par("_faces_vers_elem")) return interpoler_faces_vdf_vers_elem(id);
++  else if (nom.debute_par("normals/NORMALE")) return calculer_normale(id);
++  else if (nom.debute_par("mesh_quality/LargestAngle")) return calculer_angle(id);
++  // Ceci doit rester:
++  else {
++    Journal() << "Error in UserFields::get_field: unknown field " << nom << endl;
++    throw;
++  }
++}
++
++class FiltreSpatial
++{   
++public:
++  FiltreSpatial(LataFilter & lata, const Domain_Id & id, entier demi_pas) :
++    demi_pas_(-1), pbDim_(-1), nx_(-1), ny_(-1), nz_(-1), dx_(-1.), dy_(-1.), dz_(-1.)
++  {
++    init(lata, id, demi_pas); 
++  }
++  FieldType filtrer(const FieldType & f, const Field_Id & id) const;
++  FieldType gradient(const FieldType & f, const Field_Id & id) const;
++  float volume() const { return dx_ * dy_ * dz_; }
++protected:
++  void init(LataFilter & lata, const Domain_Id & id, entier demi_pas);
++  FloatTab calculer_somme_dir(const FloatTab & src, const int dir) const;
++  FloatTab annu_bord(const FloatTab & input, int epaisseur) const;
++  int ijk_index(int i, int j, int k) const {
++    if (i < 0)
++      i = 0;
++    else if (i >= nx_)
++      i = nx_-1;
++    if (j < 0)
++      j = 0;
++    else if (j >= ny_)
++      j = ny_ - 1;
++    if (k < 0)
++      k = 0;
++    else if (k >= nz_)
++      k = nz_-1; 
++    return k * ny_ * nx_ + j * nx_ + i;
++  } 
++
++  // Tableau: pour chaque element, 1 s'il est INVALIDE, 0 s'il est OK
++  ArrOfBit invalid_connections_;
++
++  entier demi_pas_;
++  int pbDim_; // dimension
++  int nx_;
++  int ny_;
++  int nz_;
++  float dx_;
++  float dy_;
++  float dz_;
++};
++
++void FiltreSpatial::init(LataFilter & lata, const Domain_Id & id, entier demi_pas)
++{
++  const Domain & dom = lata.get_geometry(id);
++  const DomainIJK * ptr = dynamic_cast<const DomainIJK *>(&dom);
++  if (!ptr) {
++    Journal() << "Error in FiltreSpatial::init : domain " << id.name_ << " is not IJK" << endl;
++    throw;
++  }
++  demi_pas_ = demi_pas;
++  pbDim_ = ptr->coord_.size();
++  nx_ = ptr->coord_[0].size_array() - 1;
++  ny_ = ptr->coord_[1].size_array() - 1;
++  if (pbDim_ == 3)
++    nz_ = ptr->coord_[2].size_array() - 1;
++  else
++    nz_ = 1;
++
++  dx_ = ptr->coord_[0][1] - ptr->coord_[0][0];
++  dy_ = ptr->coord_[1][1] - ptr->coord_[1][0];
++  if (pbDim_ == 3)
++    dz_ = ptr->coord_[2][1] - ptr->coord_[2][0];
++  else
++    dz_ = 1.;
++
++  invalid_connections_ = ptr->invalid_connections_;
++
++  if (invalid_connections_.size_array() == 0) {
++    invalid_connections_.resize_array(ptr->nb_elements());
++    invalid_connections_ = 0;
++  }
++
++  lata.release_geometry(dom);
++}
++
++FloatTab FiltreSpatial::calculer_somme_dir(const FloatTab & src, const int dir) const
++{
++  const int n = src.dimension(0);
++  const int nb_compo = src.dimension(1);
++  FloatTab tmp;
++  tmp.resize(n, nb_compo);
++
++  int index_resu = 0;
++  for (int k = 0; k < nz_; k++) {
++    for (int j = 0; j < ny_; j++) {
++      for (int i = 0; i < nx_; i++) {
++        for (int count = -demi_pas_; count <= demi_pas_; count++) {
++          int index;
++          switch(dir) {
++          case 0: index = ijk_index(i+count, j, k); break;
++          case 1: index = ijk_index(i, j+count, k); break;
++          case 2: index = ijk_index(i, j, k+count); break;
++          default:
++            throw;
++          }
++
++          if (invalid_connections_[index] == 1 && dir == 0) {
++            // element invalide !
++          } else {
++            // element ok !
++            for (int compo = 0; compo < nb_compo; compo++)
++              tmp(index_resu, compo) += src(index, compo);
++          }
++        }
++        index_resu++;
++      }
++    }
++  }
++  return tmp;
++}
++
++FieldType FiltreSpatial::filtrer(const FieldType & source, const Field_Id & id) const
++{
++  // On copie tout pour avoir les noms des composantes, localisation etc...
++  FieldType resu = source;
++  resu.id_ = id;
++
++  FloatTab somme_x = calculer_somme_dir(source.data_, 0);
++  FloatTab somme_y = calculer_somme_dir(somme_x, 1);
++  if (pbDim_ == 3)
++    resu.data_ = calculer_somme_dir(somme_y, 2);
++  else
++    resu.data_ = somme_y;
++
++  entier pas = demi_pas_ * 2 + 1;
++  double fact = pas * pas;
++  if (pbDim_ == 3)
++    fact *= pas;
++  resu.data_ *= (1. / fact);
++
++  return resu;
++}
++
++FieldType UserFields::filtre_boite(const Field_Id & id)
++{
++  FieldType source = get_champ_source(id);
++
++  FiltreSpatial filtre(lata_filter_.valeur(), id, opt_.demie_largeur_filtre_boite_);
++
++  FieldType resu = filtre.filtrer(source, id);
++
++  return resu;
++}
++
+diff --git a/databases/readers/Lata/UserFields.h b/databases/readers/Lata/UserFields.h
+new file mode 100644
+index 0000000..8e2052c
+--- /dev/null
++++ b/databases/readers/Lata/UserFields.h
+@@ -0,0 +1,108 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef UserFields_H
++#define UserFields_H
++#include <Lata_tools.h>
++#include <LataStructures.h>
++
++template<class F> class Field;
++class FloatTab;
++typedef Field<FloatTab> FieldType;
++class Field_Id;
++class LataFilter;
++struct LataFieldMetaData;
++class DomainUnstructured;
++class DomainIJK;
++
++// Description: classe outil pour acceder a une geometrie dans LataFilter.
++//  La geometrie est chargee en memoire quand cet objet est cree,
++//  elle est dechargee quand il est detruit.
++// Exemple d'utilisation dans UserFields::interpoler_elem_vers_som
++class Geometry_handle
++{
++public:
++  Geometry_handle();
++  Geometry_handle(Geometry_handle &);
++  Geometry_handle & operator=(Geometry_handle &);
++  ~Geometry_handle();
++  void set(LataFilter & filter, const Domain_Id &);
++  const DomainUnstructured & geom();
++  const DomainIJK &          geom_ijk();
++  entier                     test_ijk();
++protected:
++  void                       reset();
++  LataRef<LataFilter> lata_filter_;
++  LataRef<const Domain> geom_;
++};
++
++class UserFields_options
++{
++public:
++  UserFields_options();
++  entier parse_option(const Nom &);
++  void   print_help_option() const;
++
++  // Exemple de parametre en option (commentaires bienvenus !)
++
++  // demie-largeur du filtre_boite en mailles
++  entier demie_largeur_filtre_boite_;
++};
++
++class UserFields
++{
++public:
++  void set_options(const UserFields_options & opt) { opt_ = opt; }
++
++  void   new_fields_metadata(LataFilter & filter,
++                             LataVector<LataFieldMetaData> & fields_data);
++
++  FieldType get_field(const Field_Id & id);
++
++  BigEntier compute_memory_size() { return 0; }
++
++protected:
++  // Declaration de methodes outils
++  FieldType get_champ_source(const Field_Id & id);
++  FieldType get_champ(const Nom & nom, const Field_Id & id);
++  FieldType get_champ_loc(const Nom & nom, LataField_base::Elem_som loc, const Field_Id & id);
++  void      get_geometry(const Domain_Id & id, Geometry_handle &);
++
++  FieldType filtre_boite(const Field_Id & id);
++  FieldType calculer_normale(const Field_Id & id);
++  FieldType calculer_angle(const Field_Id & id);
++  FieldType interpoler_elem_vers_som(const Field_Id & id);
++  FieldType interpoler_faces_vdf_vers_elem(const Field_Id & id);
++
++  // Reference a la classe LataFilter (pour recuperer les champs sources)
++  LataRef<LataFilter> lata_filter_;
++
++  UserFields_options opt_;
++};
++#endif
+diff --git a/databases/readers/Lata/Vect.h b/databases/readers/Lata/Vect.h
+new file mode 100644
+index 0000000..a650806
+--- /dev/null
++++ b/databases/readers/Lata/Vect.h
+@@ -0,0 +1,34 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef Vect_h_inclu
++#define Vect_h_inclu
++#include <LataVector.h>
++#define VECT(x) LataVector<x >
++#endif
+diff --git a/databases/readers/Lata/VectArrOfInt.h b/databases/readers/Lata/VectArrOfInt.h
+new file mode 100644
+index 0000000..c666311
+--- /dev/null
++++ b/databases/readers/Lata/VectArrOfInt.h
+@@ -0,0 +1,34 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef VectArrOfInt_h_inclu
++#define VectArrOfInt_h_inclu
++#include <ArrOfInt.h>
++#include <Vect.h>
++#endif
+diff --git a/databases/readers/Lata/arch.h b/databases/readers/Lata/arch.h
+new file mode 100644
+index 0000000..68c5800
+--- /dev/null
++++ b/databases/readers/Lata/arch.h
+@@ -0,0 +1,34 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++
++#ifndef arch_include_
++#define arch_include_
++typedef int entier;
++#endif
++
+diff --git a/databases/readers/Lata/avtlataFileFormat.C b/databases/readers/Lata/avtlataFileFormat.C
+new file mode 100644
+index 0000000..2c4d27c
+--- /dev/null
++++ b/databases/readers/Lata/avtlataFileFormat.C
+@@ -0,0 +1,865 @@
++/*****************************************************************************
++ *
++ * Copyright (c) 2000 - 2015, Lawrence Livermore National Security, LLC
++ * Produced at the Lawrence Livermore National Laboratory
++ * All rights reserved.
++ *
++ * This file is part of VisIt. For details, see http://www.llnl.gov/visit/. The
++ * full copyright notice is contained in the file COPYRIGHT located at the root
++ * of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.
++ *
++ * Redistribution  and  use  in  source  and  binary  forms,  with  or  without
++ * modification, are permitted provided that the following conditions are met:
++ *
++ *  - Redistributions of  source code must  retain the above  copyright notice,
++ *    this list of conditions and the disclaimer below.
++ *  - Redistributions in binary form must reproduce the above copyright notice,
++ *    this  list of  conditions  and  the  disclaimer (as noted below)  in  the
++ *    documentation and/or materials provided with the distribution.
++ *  - Neither the name of the UC/LLNL nor  the names of its contributors may be
++ *    used to  endorse or  promote products derived from  this software without
++ *    specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS "AS IS"
++ * AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE
++ * ARE  DISCLAIMED.  IN  NO  EVENT  SHALL  THE  REGENTS  OF  THE  UNIVERSITY OF
++ * CALIFORNIA, THE U.S.  DEPARTMENT  OF  ENERGY OR CONTRIBUTORS BE  LIABLE  FOR
++ * ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR
++ * SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER
++ * CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT
++ * LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY
++ * OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ *
++ *****************************************************************************/
++
++// ************************************************************************* //
++//                            avtlataFileFormat.C                           //
++// ************************************************************************* //
++
++#include <avtlataFileFormat.h>
++
++#include <LmlReader.h>
++#include <LataJournal.h>
++
++#include <avtDatabaseMetaData.h>
++#include <avtGhostData.h>
++#include <DebugStream.h>
++#include <Expression.h>
++#include <InvalidVariableException.h>
++
++#include <vtkCellData.h>
++#include <vtkCellType.h>
++#include <vtkFloatArray.h>
++#include <vtkInformation.h>
++#include <vtkIntArray.h>
++#include <vtkRectilinearGrid.h>
++#include <vtkStreamingDemandDrivenPipeline.h>
++#include <vtkStructuredGrid.h>
++#include <vtkUnsignedCharArray.h>
++#include <vtkUnstructuredGrid.h>
++
++#include <string>
++#include <fstream>
++#include <iostream>
++#include <visitstream.h>
++#include <vector>
++
++// ****************************************************************************
++//  Method: avtlata constructor
++//
++//  Programmer: fauchet -- generated by xml2avt
++//
++// ****************************************************************************
++
++avtlataFileFormat::avtlataFileFormat(const char *filename)
++  : avtMTMDFileFormat(filename)
++{
++  debug1 << "avtlataFileFormat constructor " << filename << endl;
++  try {
++    set_Journal_level(0);
++
++    LataOptions opt;
++    LataOptions::extract_path_basename(filename, opt.path_prefix, opt.basename);
++    opt.dual_mesh = true;
++    opt.faces_mesh = true;
++    opt.regularize = 2;
++    opt.regularize_tolerance = 1e-7;
++    opt.user_fields_=true;
++    read_any_format_options(filename, opt);
++    debug1 << "avtlataFileFormat: initializing filter" << endl;
++    // Read the source file to the lata database
++    read_any_format(filename, opt.path_prefix, lata_db_);
++    filter_.initialize(opt, lata_db_);
++  }
++  catch (LataDBError err) {
++    cerr << "Error in LataFilter::initialize " << filename << " " << err.describe() << endl;
++    throw;
++  }
++}
++
++avtlataFileFormat::~avtlataFileFormat()
++{
++}
++
++// ****************************************************************************
++//  Method: avtEMSTDFileFormat::GetNTimesteps
++//
++//  Purpose:
++//      Tells the rest of the code how many timesteps there are in this file.
++//
++//  Programmer: fauchet -- generated by xml2avt
++//
++// ****************************************************************************
++
++int
++avtlataFileFormat::GetNTimesteps(void)
++{
++  int n;
++  try {
++    n = filter_.get_nb_timesteps();
++    // Timestep 0 contains global definitions.
++    // If we have "real" timesteps, do not show timestep 0
++    if (n > 1)
++      n--;
++  }
++  catch (LataDBError err) {
++    cerr << "Error in getntimesteps " << filename << " " << err.describe() << endl;
++    throw;
++  }
++  return n;
++}
++
++void avtlataFileFormat::GetTimes(std::vector<double>& times) 
++{ 
++  int n;
++  try {
++    n = filter_.get_nb_timesteps();
++    if (n == 1)
++      times.push_back(0.);
++    else
++      for (int i = 1; i < n; i++)
++        times.push_back(filter_.get_timestep(i));
++  }
++  catch (LataDBError err) {
++    cerr << "Error in gettimes " << filename << " " << err.describe() << endl;
++    throw;
++  }
++  return;
++}
++
++// ****************************************************************************
++//  Method: avtlataFileFormat::FreeUpResources
++//
++//  Purpose:
++//      When VisIt is done focusing on a particular timestep, it asks that
++//      timestep to free up any resources (memory, file descriptors) that
++//      it has associated with it.  This method is the mechanism for doing
++//      that.
++//
++//  Programmer: fauchet -- generated by xml2avt
++//
++// ****************************************************************************
++
++void
++avtlataFileFormat::FreeUpResources(void)
++{
++}
++
++
++// ****************************************************************************
++//  Method: avtlataFileFormat::PopulateDatabaseMetaData
++//
++//  Purpose:
++//      This database meta-data object is like a table of contents for the
++//      file.  By populating it, you are telling the rest of VisIt what
++//      information it can request from you.
++//
++//  Programmer: fauchet -- generated by xml2avt
++//
++// ****************************************************************************
++
++void
++avtlataFileFormat::PopulateDatabaseMetaData(avtDatabaseMetaData *md, int timeState)
++{
++  try {
++  debug1 << "avtlataFileFormat::PopulateDatabaseMetaData : " 
++         << filename << " " << timeState << endl;
++
++  const char *suffix_vector_names[] = { "_X", "_Y", "_Z" };
++  const char *suffix_vector_expr[] = { "[0]", "[1]", "[2]" };
++
++  const Noms geoms = filter_.get_exportable_geometry_names();
++
++  for (int i_geom = 0; i_geom < geoms.size(); i_geom++) {
++    debug1 << " Domain : " << geoms[i_geom] << endl;
++    const LataGeometryMetaData data = filter_.get_geometry_metadata(geoms[i_geom]);
++
++    avtMeshType mt = AVT_UNSTRUCTURED_MESH;
++    
++    if (data.is_ijk_==1)
++      {
++        mt = AVT_RECTILINEAR_MESH;
++      }
++    int block_origin = 0;
++    int topo_dim;
++    switch(data.element_type_) {
++    case Domain::point:     topo_dim = 0; mt = AVT_POINT_MESH; break;
++    case Domain::line:      topo_dim = 1; break;
++    case Domain::triangle: 
++    case Domain::polygone:
++    case Domain::quadri:    topo_dim = 2; break;
++    case Domain::tetra:
++    case Domain::prism6:
++    case Domain::polyedre:
++    case Domain::hexa:      topo_dim = 3; break;
++    default:
++      cerr << "avtlataFileFormat::PopulateDatabaseMetaData error: unknown element type" << endl;
++      topo_dim = 3; ///TODO: this should be an error in default case!
++      EXCEPTION1(InvalidVariableException, 
++                 "avtlataFileFormat::PopulateDatabaseMetaData error: unknown element type");
++      throw;
++    }
++
++    int mesh_faces=0;
++    if  (data.internal_name_.finit_par("_centerfaces"))
++      {
++        //cerr<<"la "<<data.internal_name_<<endl;
++        mesh_faces=1;
++      }
++    double *extents = NULL;
++    const std::string geom_name(data.displayed_name_);
++    AddMeshToMetaData(md, geom_name, mt, extents, data.nblocks_, block_origin,
++                      data.dimension_, topo_dim);
++    mesh_username_.add(data.displayed_name_);
++    mesh_latafilter_name_.add(data.internal_name_);
++
++    Field_UNames fields = filter_.get_exportable_field_unames(geoms[i_geom]);
++
++    for (int i_field = 0; i_field < fields.size(); i_field++) {
++      const LataFieldMetaData data2 = filter_.get_field_metadata(fields[i_field]);
++      avtCentering cent;
++      switch (data2.localisation_) {
++      case LataField_base::ELEM: cent = AVT_ZONECENT; break;
++      case LataField_base::SOM:  cent = AVT_NODECENT; break;
++      default:
++        // Do not export fields that cannot be shown
++        continue;
++      }
++
++      // Take localisation of source field
++      Nom loc = data2.source_localisation_;
++      std::string varname(data2.name_);
++      varname += "_";
++      varname += loc;
++      varname += "_";
++      varname += geom_name;
++      if (data2.nb_components_ == 1) {
++        // Scalar field
++        // We append the geometry name to the component name:
++        register_fieldname(varname.c_str(), fields[i_field], 0);
++        if (mesh_faces==0)
++        AddScalarVarToMetaData(md, varname, geom_name, cent);
++      } else if (data2.is_vector_ && data2.nb_components_ == data.dimension_) {
++        // Vector field
++        register_fieldname(varname.c_str(), fields[i_field], -1);
++        AddVectorVarToMetaData(md, varname, geom_name, cent, data2.nb_components_);
++        if (mesh_faces==0)
++          {
++        std::string n;
++        for (entier i = 0; i < data2.nb_components_; i++) {
++          Expression v;
++          n = data2.name_;
++          n += suffix_vector_names[i];
++          n += "_";
++          n += loc;
++          n += "_";
++          n += geom_name;
++          v.SetName(n);
++          n = varname;
++          n += suffix_vector_expr[i];
++          v.SetDefinition(n);
++          v.SetType(Expression::ScalarMeshVar);
++          md->AddExpression(&v);
++        }
++      if (varname.find_first_of("/",0)==std::string::npos)
++      {
++         // On calcule la norme des vecteurs de premier niveau (pas de / dans le chemin)
++           Expression norme_v;
++           n = "norme_";
++           n += varname;
++           norme_v.SetName(n);
++           n = "magnitude(";
++           n += varname;
++           n += ")";
++           norme_v.SetDefinition(n);
++           norme_v.SetType(Expression::ScalarMeshVar);
++           md->AddExpression(&norme_v);
++      }
++          }
++      } else {
++        // Multiscalar field 
++        // I chose to postfix the varname with the component name, perhaps not the best choice.
++        if (mesh_faces==0)
++          {
++        for (entier i_compo = 0; i_compo < data2.nb_components_; i_compo++) { 
++          std::string varname2(data2.name_);
++          varname2 += "_";
++          if (data2.component_names_.size() == data2.nb_components_) {
++            varname2 += data2.component_names_[i_compo];
++          } else {
++            Nom n(i_compo);
++            varname2 += n;
++          }
++          varname2 += "_";
++          varname2 += loc; 
++          varname2 += "_";
++          varname2 += geom_name;
++          register_fieldname(varname2.c_str(), fields[i_field], i_compo);
++          AddScalarVarToMetaData(md, varname2, geom_name, cent);
++        }
++          }
++      }
++    }
++  }
++  debug1 << "End avtlataFileFormat::PopulateDatabaseMetaData" << endl;
++  }
++  catch (LataDBError err) {
++    cerr << "Error in PopulateDatabaseMetaData " << err.describe() << endl;
++    throw;
++  }
++}
++
++void
++avtlataFileFormat::register_fieldname(const char *visit_name, const Field_UName & uname, int component)
++{
++  if (field_username_.rang(visit_name) >= 0) {
++    cerr << "Error in avtlataFileFormat::register_fieldname: duplicate field name " << visit_name << endl;
++    cerr << "Ignoring field" << endl;
++    return;
++  }
++  field_username_.add(visit_name);
++  field_uname_.add(uname);
++  field_component_.add(component);
++}
++
++void
++avtlataFileFormat::register_meshname(const char *visit_name, const char *latafilter_name)
++{
++  if (mesh_username_.rang(visit_name) >= 0) {
++    cerr << "Error in avtlataFileFormat::register_meshname: duplicate name " << visit_name << endl;
++    cerr << "Ignoring mesh" << endl;
++    return;    
++  }
++  mesh_username_.add(visit_name);
++  mesh_latafilter_name_.add(latafilter_name);
++}
++
++// ****************************************************************************
++//  Method: avtlataFileFormat::GetMesh
++//
++//  Purpose:
++//      Gets the mesh associated with this file.  The mesh is returned as a
++//      derived type of vtkDataSet (ie vtkRectilinearGrid, vtkStructuredGrid,
++//      vtkUnstructuredGrid, etc).
++//
++//  Arguments:
++//      timestate   The index of the timestate.  If GetNTimesteps returned
++//                  'N' time steps, this is guaranteed to be between 0 and N-1.
++//      domain      The index of the domain.  If there are NDomains, this
++//                  value is guaranteed to be between 0 and NDomains-1,
++//                  regardless of block origin.
++//      meshname    The name of the mesh of interest.  This can be ignored if
++//                  there is only one mesh.
++//
++//  Programmer: fauchet -- generated by xml2avt
++//
++// ****************************************************************************
++
++vtkDataSet *
++avtlataFileFormat::GetMesh(int timestate, int block, const char *meshname)
++{
++  vtkDataSet *return_value = 0;
++  try {
++  debug1 << " avtlataFileFormat::GetMesh ts=" << timestate 
++         << " block=" << block 
++         << " meshname=" << meshname << endl;
++
++  // We have real timesteps in the database, add one to timestep index:
++  if (filter_.get_nb_timesteps() > 1)
++    timestate++;
++
++  const entier index = mesh_username_.rang(meshname);
++  if (index < 0) {
++    cerr << "internal error in avtlataFileFormat::GetMesh: name " << meshname << " not found" << endl;
++    throw;
++  }
++  Domain_Id id(mesh_latafilter_name_[index], timestate, block);
++  const Domain & geometry = filter_.get_geometry(id);
++
++  const DomainUnstructured * geom_ptr = dynamic_cast<const DomainUnstructured*>(&geometry);
++  const DomainIJK          * ijk_ptr = dynamic_cast<const DomainIJK*>(&geometry);
++
++  if (geom_ptr) {
++    const DomainUnstructured & geom = *geom_ptr;
++
++    vtkUnstructuredGrid *ugrid = vtkUnstructuredGrid::New();
++    vtkPoints *points = vtkPoints::New();
++    const FloatTab & pos = geom.nodes_;
++    const int nnodes = pos.dimension(0);
++    const int dim3 = pos.dimension(1) == 3;
++    points->SetNumberOfPoints(nnodes);
++    float* pts = (float *) points->GetVoidPointer(0);
++    int jl=0;
++    int i;
++    for (i = 0; i < nnodes; i++) {
++      pts[jl]   = pos(i,0);
++      pts[jl+1] = pos(i,1);
++      pts[jl+2] = dim3 ? pos(i,2) : 0.;
++      jl+=3;
++    }
++    ugrid->SetPoints(points);
++    points->Delete();
++    
++    const IntTab & conn = geom.elements_;
++    const IntTab & elem_faces = geom.elem_faces_;
++    const IntTab & faces = geom.faces_;
++    const int ncells = conn.dimension(0);
++    int nverts = conn.dimension(1);
++    
++    int type_cell;
++    switch (geom.elt_type_) {
++    case Domain::point:
++      type_cell=VTK_VERTEX; 
++      if (ncells == 0) 
++        nverts = 1;
++      break;
++    case Domain::line:
++      type_cell=VTK_LINE;
++      break;
++    case Domain::triangle:
++      type_cell=VTK_TRIANGLE;
++      break;
++    case Domain::quadri:
++      type_cell=VTK_QUAD;
++      break;
++    case Domain::tetra:
++      type_cell=VTK_TETRA;
++      break;
++    case Domain::prism6:
++      type_cell=VTK_WEDGE;
++      break;
++    case Domain::hexa:
++      type_cell=VTK_HEXAHEDRON;
++      break;
++    case Domain::polygone:
++      type_cell=VTK_POLYGON;
++      break;
++    case Domain::polyedre:
++      type_cell= elem_faces.dimension(0) > 0 ? VTK_POLYHEDRON : VTK_CONVEX_POINT_SET;
++      break;
++    default:
++      type_cell=-1;
++      cerr<<"avtlataFileFormat::GetMesh unknown elt type "<<endl;
++      throw;
++      break;
++    }
++    vtkIdType *verts = new vtkIdType[nverts];
++    std::vector<vtkIdType> poly_p, poly_f;
++    if (type_cell == VTK_VERTEX && ncells == 0) {
++      // Cells are implicit. Create them:
++      ugrid->Allocate(nnodes);
++      for (i = 0; i < nnodes; i++) {
++        verts[0] = i;
++        ugrid->InsertNextCell(type_cell, nverts, verts);
++      }
++    } else {
++      ugrid->Allocate(ncells);
++      for (i = 0; i < ncells; i++) {
++        if (type_cell==VTK_QUAD) {
++          // Nodes order is different in visit than in trio_u
++          verts[0]=conn(i,0);
++          verts[1]=conn(i,1);
++          verts[2]=conn(i,3);
++          verts[3]=conn(i,2);
++        } else if (type_cell==VTK_HEXAHEDRON) {
++          // Nodes order is different in visit than in trio_u
++          verts[0]=conn(i,0);
++          verts[1]=conn(i,1);
++          verts[2]=conn(i,3);
++          verts[3]=conn(i,2);
++          verts[4]=conn(i,4);
++          verts[5]=conn(i,5);
++          verts[6]=conn(i,7);
++          verts[7]=conn(i,6);
++        } else if (type_cell==VTK_POLYHEDRON) { 
++          //polyhedra, face by face
++          int j, nfaces = 0, npts = 0, k, i_f, s, f;
++          poly_p.resize(0), poly_f.resize(0);
++          for (j = 0; j < conn.dimension(1); j++) if ((s = conn(i, j)) >= 0) poly_p.push_back(s), npts++;
++          for (j = 0; j < elem_faces.dimension(1); j++) if ((f = elem_faces(i, j)) >= 0)
++            for (k = 0, nfaces++, i_f = poly_f.size(), poly_f.push_back(0); k < faces.dimension(1) ; k++) if ((s = faces(f, k)) >= 0)
++              poly_f.push_back(s), poly_f[i_f]++;
++          ugrid->InsertNextCell(type_cell, npts, &poly_p[0], nfaces, &poly_f[0]);
++        } else if ((type_cell==VTK_CONVEX_POINT_SET)||(type_cell==VTK_POLYGON)) {
++          int nverts_loc=nverts;
++          for (int j = 0; j < nverts; j++) 
++            {
++              verts[j] = conn(i,j);
++             
++              if (verts[j]<=-1)
++                {  
++                  nverts_loc=j; 
++                  break;
++                }    
++  /*            else
++              {
++              if (verts[j]<-1)
++              {
++              std::cerr<<i<<" iiiii "<< j<<" "<<verts[j]<<finl;
++}
++
++}     */
++            }
++          int  nb_som_max_to_regularize=0;
++          if (filter_.get_options().regularize_polyedre!=0)
++            {
++              nb_som_max_to_regularize=8;
++              if (filter_.get_options().regularize_polyedre==-1)
++                  nb_som_max_to_regularize=32000;
++            }
++          if ( geom.elt_type_==Domain::polygone)
++              nb_som_max_to_regularize=-1;
++          if ((nb_som_max_to_regularize>=6) && (nverts_loc==6))
++            ugrid->InsertNextCell(VTK_WEDGE, nverts_loc, verts);
++          else if ((nb_som_max_to_regularize>=12)&&(nverts_loc==12))
++            ugrid->InsertNextCell(VTK_HEXAGONAL_PRISM, nverts_loc, verts);
++          else if ((nb_som_max_to_regularize>=8)&&(nverts_loc==8))
++            {
++                        // Nodes order is different in visit than in trio_u
++              verts[0]=conn(i,0);
++              verts[1]=conn(i,1);
++              verts[2]=conn(i,3);
++              verts[3]=conn(i,2);
++              verts[4]=conn(i,4);
++              verts[5]=conn(i,5);
++              verts[6]=conn(i,7);
++              verts[7]=conn(i,6);
++              ugrid->InsertNextCell(VTK_HEXAHEDRON, nverts_loc, verts);
++               
++            }
++          else
++            ugrid->InsertNextCell(type_cell, nverts_loc, verts);
++        }
++        else {
++          for (int j = 0; j < nverts; j++) 
++            verts[j] = conn(i,j);
++        }
++        if ((type_cell!=VTK_POLYHEDRON) &&(type_cell!=VTK_CONVEX_POINT_SET) && (type_cell!=VTK_POLYGON))
++         
++          ugrid->InsertNextCell(type_cell, nverts, verts);
++      }
++    }
++    delete [] verts;
++    verts = 0;
++    // Declare ghost elements:
++    const int n = geom.nb_virt_items(LataField_base::ELEM);
++    if (n > 0) {
++      unsigned char realVal = 0;
++      unsigned char ghost   = 0; // Sera modifie par AddGhostZoneType
++      avtGhostData::AddGhostZoneType(ghost, DUPLICATED_ZONE_INTERNAL_TO_PROBLEM);
++      vtkUnsignedCharArray *ghostcells = vtkUnsignedCharArray::New();
++      ghostcells->SetName("avtGhostZones");
++      ghostcells->SetNumberOfTuples(ncells);
++      unsigned char *dat = (unsigned char *) ghostcells->GetVoidPointer(0);
++      for (i = 0; i < ncells - n; i++)
++        dat[i] = realVal;
++      for (i = ncells - n; i < ncells; i++)
++        dat[i] = ghost;
++      ugrid->GetCellData()->AddArray(ghostcells);
++      ugrid->GetInformation()->Set(
++        vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), 0);
++      ghostcells->Delete();
++    }
++    return_value = ugrid;
++    
++  } else if (ijk_ptr) {
++    const DomainIJK & geom = *ijk_ptr;
++
++    // Maillage regulier : on transmet la grille ijk
++    vtkRectilinearGrid *sgrid = vtkRectilinearGrid::New();
++
++    const int dim = geom.coord_.size();
++    ArrOfInt ncoord(3, 1);
++    int i;
++    for (i = 0; i < dim; i++) 
++      ncoord[i] = geom.coord_[i].size_array();
++    sgrid->SetDimensions(ncoord[0], ncoord[1], ncoord[2]);
++
++    for (i = 0; i < 3; i++) {
++      float *data;
++      vtkFloatArray *c;
++      c = vtkFloatArray::New();
++      const int n = ncoord[i];
++      c->SetNumberOfTuples(n);
++      data = (float *) c->GetVoidPointer(0);
++      if (i < dim) {
++        const ArrOfFloat & coord = geom.coord_[i];
++        for (int j = 0; j < n; j++)
++          data[j] = coord[j];
++      } else {
++        data[0] = 0.;
++      }
++      switch(i) {
++      case 0: sgrid->SetXCoordinates(c); break;
++      case 1: sgrid->SetYCoordinates(c); break;
++      case 2: sgrid->SetZCoordinates(c); break;
++      default: ;
++      }
++      c->Delete();
++    }
++    // Create "invalid cells" data (GettingDataIntoVisit.pdf, page 136)
++    // and "ghost cells"
++    const int n = geom.invalid_connections_.size_array();
++    if (n > 0 || geom.virtual_layer_begin_ || geom.virtual_layer_end_) {
++      const int ncells = geom.nb_elements();
++      unsigned char realVal = 0;
++      unsigned char invalid = 0; // Sera modifie par AddGhostZoneType
++      unsigned char ghost   = 0;
++      avtGhostData::AddGhostZoneType(invalid, ZONE_NOT_APPLICABLE_TO_PROBLEM);
++      avtGhostData::AddGhostZoneType(ghost, DUPLICATED_ZONE_INTERNAL_TO_PROBLEM);
++      vtkUnsignedCharArray *ghostcells = vtkUnsignedCharArray::New();
++      ghostcells->SetName("avtGhostZones");
++      ghostcells->SetNumberOfTuples(ncells);
++      unsigned char *dat = (unsigned char *) ghostcells->GetVoidPointer(0);
++
++      for (i = 0; i < ncells; i++)
++          dat[i] = realVal;
++
++      if (n > 0) {
++        // invalid cells
++        for (i = 0; i < ncells; i++) {
++          if (geom.invalid_connections_[i])
++            dat[i] = invalid;
++        }
++      }
++      
++      // ghost cells
++      entier ij = 1;
++      for (i = 0; i < dim-1; i++)
++        ij *= ncoord[i]-1;
++      if (geom.virtual_layer_begin_) {
++        // first layer of cells is ghost
++        for (i = 0; i < ij * geom.virtual_layer_begin_; i++)
++          dat[i] += ghost;
++      }
++      if (geom.virtual_layer_end_) {
++        // last layer of cells is ghost
++        for (i = ncells - ij * geom.virtual_layer_end_; i < ncells; i++)
++          dat[i] += ghost;
++      }
++      
++      sgrid->GetCellData()->AddArray(ghostcells);
++      sgrid->GetInformation()->Set(
++        vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), 0);
++      ghostcells->Delete();
++    }
++
++    return_value = sgrid;
++  } else {
++    cerr << "Error in avtlataFileFormat::GetMesh: unknown geometry type" << endl;
++    throw;
++  }
++
++  filter_.release_geometry(geometry);
++  }
++  catch (LataDBError err) {
++    cerr << "Error in getmesh " << timestate << " " << block << " " << meshname << " " << err.describe() << endl;
++    throw;
++  }
++
++  return return_value;
++}
++
++
++// ****************************************************************************
++//  Method: avtlataFileFormat::GetVar
++//
++//  Purpose:
++//      Gets a scalar variable associated with this file.  Although VTK has
++//      support for many different types, the best bet is vtkFloatArray, since
++//      that is supported everywhere through VisIt.
++//
++//  Arguments:
++//      timestate  The index of the timestate.  If GetNTimesteps returned
++//                 'N' time steps, this is guaranteed to be between 0 and N-1.
++//      domain     The index of the domain.  If there are NDomains, this
++//                 value is guaranteed to be between 0 and NDomains-1,
++//                 regardless of block origin.
++//      varname    The name of the variable requested.
++//
++//  Programmer: fauchet -- generated by xml2avt
++//
++// ****************************************************************************
++
++vtkDataArray *
++avtlataFileFormat::GetVar(int timestate, int block, const char *varname)
++{
++  vtkDataArray * return_value = 0;
++  try {
++  debug1 << "Getvar time:" << timestate
++         << " block:" << block
++         << " varname:" << varname << endl;
++
++  if (filter_.get_nb_timesteps() > 1)
++    timestate++;
++
++  Field_UName field_uname;
++  int component;
++  get_field_info_from_visitname(varname, field_uname, component);
++
++  if (component < 0) {
++    cerr << "Error: avtlataFileFormat::GetVar called for vector field" << endl;
++    throw;
++  }
++
++  Field_Id id(field_uname, timestate, block);
++
++  const LataField_base & field = filter_.get_field(id);
++
++  const Field<FloatTab> * float_field_ptr = dynamic_cast<const Field<FloatTab>*>(&field);
++  const Field<IntTab> * int_field_ptr = dynamic_cast<const Field<IntTab>*>(&field);
++
++  if (float_field_ptr) {
++    vtkFloatArray *rv = vtkFloatArray::New();
++    const Field<FloatTab> & fld = *float_field_ptr;
++    const FloatTab & values = fld.data_;
++    int ntuples = values.dimension(0);
++    rv->SetNumberOfTuples(ntuples);
++    float * data = rv->GetPointer(0);
++    for (int i = 0; i < ntuples; i++) 
++      data[i] = values(i, component);
++    return_value = rv;
++  } else if (int_field_ptr) {
++    vtkIntArray *rv = vtkIntArray::New();
++    const Field<IntTab> & fld = *int_field_ptr;
++    const IntTab & values = fld.data_;
++    int ntuples = values.dimension(0);
++    rv->SetNumberOfTuples(ntuples);
++    int * data = rv->GetPointer(0);
++    for (int i = 0; i < ntuples; i++) 
++      data[i] = values(i, component);    
++    return_value = rv;
++  } else {
++    cerr << "Error in avtlataFileFormat::GetVar: unknown data type" << endl;
++    throw;
++  }
++  filter_.release_field(field);
++  }
++  catch (LataDBError err) {
++    cerr << "Error in getvar " << timestate << " " << block << " " << varname << " " << err.describe() << endl;
++    throw;
++  }
++  return return_value; 
++}
++
++
++// ****************************************************************************
++//  Method: avtlataFileFormat::GetVectorVar
++//
++//  Purpose:
++//      Gets a vector variable associated with this file.  Although VTK has
++//      support for many different types, the best bet is vtkFloatArray, since
++//      that is supported everywhere through VisIt.
++//
++//  Arguments:
++//      timestate  The index of the timestate.  If GetNTimesteps returned
++//                 'N' time steps, this is guaranteed to be between 0 and N-1.
++//      domain     The index of the domain.  If there are NDomains, this
++//                 value is guaranteed to be between 0 and NDomains-1,
++//                 regardless of block origin.
++//      varname    The name of the variable requested.
++//
++//  Programmer: fauchet -- generated by xml2avt
++//
++// ****************************************************************************
++
++vtkDataArray *
++avtlataFileFormat::GetVectorVar(int timestate, int block, const char *varname)
++{
++  vtkDataArray * return_value = 0;
++  try {
++  debug1 << "Getvectorvar time:" << timestate
++         << " block:" << block
++         << " varname:" << varname << endl;
++
++  if (filter_.get_nb_timesteps() > 1)
++    timestate++;
++
++  Field_UName field_uname;
++  int component;
++  get_field_info_from_visitname(varname, field_uname, component);
++
++  if (component >= 0) {
++    cerr << "Error: avtlataFileFormat::GetVectorVar called for scalar field" << endl;
++    throw;
++  }
++
++  Field_Id id(field_uname, timestate, block);
++
++  const LataField_base & field = filter_.get_field(id);
++
++  const Field<FloatTab> * float_field_ptr = dynamic_cast<const Field<FloatTab>*>(&field);
++  const Field<IntTab> * int_field_ptr = dynamic_cast<const Field<IntTab>*>(&field);
++
++  if (float_field_ptr) {
++    vtkFloatArray *rv = vtkFloatArray::New();
++    const Field<FloatTab> & fld = *float_field_ptr;
++    const FloatTab & values = fld.data_;
++    int ntuples = values.dimension(0);
++    int dim = values.dimension(1);
++    rv->SetNumberOfComponents(3);
++    rv->SetNumberOfTuples(ntuples);
++    float* data= rv->WritePointer(0,3*ntuples);
++    for (int i = 0; i < ntuples; i++)
++      for (int j = 0; j < 3; j++)
++        data[i*3+j] = (j<dim) ? values(i, j) : 0.;
++    return_value = rv;
++  } else if (int_field_ptr) {
++    vtkIntArray *rv = vtkIntArray::New();
++    const Field<IntTab> & fld = *int_field_ptr;
++    const IntTab & values = fld.data_;
++    int ntuples = values.dimension(0);
++    int dim = values.dimension(1);
++    rv->SetNumberOfComponents(3);
++    rv->SetNumberOfTuples(ntuples);
++    int* data= rv->WritePointer(0,3*ntuples);
++    for (int i = 0; i < ntuples; i++) 
++      for (int j = 0; j < 3; j++)
++        data[i*3+j] = (j<dim) ? values(i, j) : 0;
++    return_value = rv;
++  } else {
++    cerr << "Error in avtlataFileFormat::GetVectorVar: unknown data type" << endl;
++    throw;
++  }
++  filter_.release_field(field);
++  }
++  catch (LataDBError err) {
++    cerr << "Error in getvectorvar " << timestate << " " << block << " " << varname << " " << err.describe() << endl;
++    throw;
++  }
++  return return_value; 
++}
++
++void avtlataFileFormat::get_field_info_from_visitname(const char *varname, Field_UName & uname, int & component) const
++{
++  const int k = field_username_.rang(varname);
++  if (k < 0) {
++    cerr << "Error in avtlataFileFormat::get_field_info_from_visitname: field " << varname << " not found" << endl;
++    throw  ;
++  }
++  uname = field_uname_[k];
++  component = field_component_[k];
++}
+diff --git a/databases/readers/Lata/avtlataFileFormat.h b/databases/readers/Lata/avtlataFileFormat.h
+new file mode 100644
+index 0000000..3dd8e43
+--- /dev/null
++++ b/databases/readers/Lata/avtlataFileFormat.h
+@@ -0,0 +1,114 @@
++/*****************************************************************************
++*
++* Copyright (c) 2000 - 2012, Lawrence Livermore National Security, LLC
++* Produced at the Lawrence Livermore National Laboratory
++* All rights reserved.
++*
++* This file is part of VisIt. For details, see http://www.llnl.gov/visit/. The
++* full copyright notice is contained in the file COPYRIGHT located at the root
++* of the VisIt distribution or at http://www.llnl.gov/visit/copyright.html.
++*
++* Redistribution  and  use  in  source  and  binary  forms,  with  or  without
++* modification, are permitted provided that the following conditions are met:
++*
++*  - Redistributions of  source code must  retain the above  copyright notice,
++*    this list of conditions and the disclaimer below.
++*  - Redistributions in binary form must reproduce the above copyright notice,
++*    this  list of  conditions  and  the  disclaimer (as noted below)  in  the
++*    documentation and/or materials provided with the distribution.
++*  - Neither the name of the UC/LLNL nor  the names of its contributors may be
++*    used to  endorse or  promote products derived from  this software without
++*    specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT  HOLDERS AND CONTRIBUTORS "AS IS"
++* AND ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING,  BUT NOT  LIMITED TO, THE
++* IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE
++* ARE  DISCLAIMED.  IN  NO  EVENT  SHALL  THE  REGENTS  OF  THE  UNIVERSITY OF
++* CALIFORNIA, THE U.S.  DEPARTMENT  OF  ENERGY OR CONTRIBUTORS BE  LIABLE  FOR
++* ANY  DIRECT,  INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR CONSEQUENTIAL
++* DAMAGES (INCLUDING, BUT NOT  LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR
++* SERVICES; LOSS OF  USE, DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER
++* CAUSED  AND  ON  ANY  THEORY  OF  LIABILITY,  WHETHER  IN  CONTRACT,  STRICT
++* LIABILITY, OR TORT  (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY  WAY
++* OUT OF THE  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
++* DAMAGE.
++*
++*****************************************************************************/
++
++// ************************************************************************* //
++//                            avtlataFileFormat.h                           //
++// ************************************************************************* //
++
++#ifndef AVT_lata_FILE_FORMAT_H
++#define AVT_lata_FILE_FORMAT_H
++
++#include <avtMTMDFileFormat.h>
++
++#include <vector>
++#include "LataFilter.h"
++
++// ****************************************************************************
++//  Class: avtlataFileFormat
++//
++//  Purpose:
++//      Reads in lata files as a plugin to VisIt.
++//
++//  Programmer: fauchet -- generated by xml2avt
++//
++// ****************************************************************************
++
++class avtlataFileFormat : public avtMTMDFileFormat
++{
++  public:
++    avtlataFileFormat(const char *);
++    virtual ~avtlataFileFormat();
++
++    //
++    // This is used to return unconvention data -- ranging from material
++    // information to information about block connectivity.
++    //
++    // virtual void      *GetAuxiliaryData(const char *var, const char *type,
++    //                                     int timestep, int domain,void *args, 
++    //                                     DestructorFunction &);
++    //
++
++    //
++    // If you know the times and cycle numbers, overload this function.
++    // Otherwise, VisIt will make up some reasonable ones for you.
++    //
++    // virtual void        GetCycles(std::vector<int> &);
++    // virtual void        GetTimes(std::vector<double> &);
++    //
++
++    virtual int            GetNTimesteps(void);
++
++    virtual const char    *GetType(void)   { return "lata"; };
++    virtual void           FreeUpResources(void); 
++
++    virtual vtkDataSet    *GetMesh(int, int, const char *);
++    virtual vtkDataArray  *GetVar(int, int, const char *);
++    virtual vtkDataArray  *GetVectorVar(int, int, const char *);
++    virtual void GetTimes(std::vector<double>& times);
++  protected:
++    // DATA MEMBERS
++
++    virtual void           PopulateDatabaseMetaData(avtDatabaseMetaData *, int);
++
++    void register_fieldname(const char *visit_name, const Field_UName &, int component);
++    void register_meshname(const char *visit_name, const char *latafilter_name);
++    void get_field_info_from_visitname(const char *varname, Field_UName &, int & component) const;
++
++    LataDB      lata_db_; // Source database
++    LataFilter  filter_; // Data processor and cache
++    Noms field_username_;
++    Field_UNames field_uname_;
++
++    Noms mesh_username_;
++    Noms mesh_latafilter_name_;
++
++    // For each name, which component is it in the source field:
++    LataVector<int> field_component_;
++};
++
++
++#endif
+diff --git a/databases/readers/Lata/simd_interface.h b/databases/readers/Lata/simd_interface.h
+new file mode 100644
+index 0000000..e14c409
+--- /dev/null
++++ b/databases/readers/Lata/simd_interface.h
+@@ -0,0 +1,31 @@
++/*****************************************************************************
++*
++* Copyright (c) 2011 - 2013, CEA
++* All rights reserved.
++* Redistribution and use in source and binary forms, with or without
++* modification, are permitted provided that the following conditions are met:
++*
++*     * Redistributions of source code must retain the above copyright
++*       notice, this list of conditions and the following disclaimer.
++*     * Redistributions in binary form must reproduce the above copyright
++*       notice, this list of conditions and the following disclaimer in the
++*       documentation and/or other materials provided with the distribution.
++*     * Neither the name of CEA, nor the
++*       names of its contributors may be used to endorse or promote products
++*       derived from this software without specific prior written permission.
++*
++* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
++* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
++* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
++* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
++* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
++* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
++* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*
++*****************************************************************************/
++#ifdef WITH_SIMD
++#include "simd_tools.h"
++#endif
+diff --git a/databases/visit_readers.xml b/databases/visit_readers.xml
+index 0b1405c..05aa776 100644
+--- a/databases/visit_readers.xml
++++ b/databases/visit_readers.xml
+@@ -781,6 +781,19 @@
+      </Hints>
+     </SourceProxy>
++    <SourceProxy name="VisItLataReader" class="vtkVisItLataReader"
++    base_proxygroup="internal_readers" base_proxyname="VisItReaderBase">
++    <Documentation
++       long_help="Lata file reader">
++       Note this reader is automatically generated from wrapping a third party reader. For more information on the reader see https://wci.llnl.gov/codes/visit
++       The default file extensions is .lata
++    </Documentation>
++     <Hints>
++       <ReaderFactory extensions="lata"
++                      file_description="Lata Files" />
++     </Hints>
++    </SourceProxy>
++
+     <SourceProxy name="VisItM3DReader" class="vtkVisItM3DReader"
+       base_proxygroup="internal_readers" base_proxyname="VisItReaderBase">
+     <Documentation
+-- 
+2.17.0
+
diff --git a/config/patches/paraview.0002-vtkUnstructuredGridRelevantPointsFilter-fix-for-poly.patch b/config/patches/paraview.0002-vtkUnstructuredGridRelevantPointsFilter-fix-for-poly.patch
new file mode 100644 (file)
index 0000000..b3e0610
--- /dev/null
@@ -0,0 +1,118 @@
+From 84627355e5b1d42754c655fdc5958695db11a25d Mon Sep 17 00:00:00 2001
+From: Antoine Gerschenfeld <antoine.gerschenfeld@cea.fr>
+Date: Fri, 13 Mar 2020 10:48:30 +0100
+Subject: [PATCH 2/3] vtkUnstructuredGridRelevantPointsFilter: fix for
+ polyhedra
+
+---
+ .../vtkUnstructuredGridRelevantPointsFilter.C | 67 ++++++++-----------
+ 1 file changed, 27 insertions(+), 40 deletions(-)
+
+diff --git a/Library/VisItLib/visit_vtk/full/vtkUnstructuredGridRelevantPointsFilter.C b/Library/VisItLib/visit_vtk/full/vtkUnstructuredGridRelevantPointsFilter.C
+index 5c73502..c4e772c 100644
+--- a/Library/VisItLib/visit_vtk/full/vtkUnstructuredGridRelevantPointsFilter.C
++++ b/Library/VisItLib/visit_vtk/full/vtkUnstructuredGridRelevantPointsFilter.C
+@@ -116,29 +116,21 @@ vtkUnstructuredGridRelevantPointsFilter::RequestData(
+     {
+     pointMap[i] = -1;
+     }
+-  vtkCellArray *cells = input->GetCells();
+-  auto cellIter = vtk::TakeSmartPointer(cells->NewIterator());
++
+   int numOutPts = 0;
+-  for (cellIter->GoToFirstCell();
+-       !cellIter->IsDoneWithTraversal();
+-       cellIter->GoToNextCell())
++  vtkIdList *list = vtkIdList::New();
++  for (i = 0; i < numCells; i++)
+     {
+-    vtkIdList *cell = cellIter->GetCurrentCell();
+-    int npts = static_cast<int>(cell->GetNumberOfIds());
+-    for (j = 0 ; j < npts ; j++)
+-      {
+-      int oldPt = static_cast<int>(cell->GetId(j));
+-      if (pointMap[oldPt] == -1)
+-        pointMap[oldPt] = numOutPts++;
+-      }
++    input->GetCellPoints(i, list);
++    for (j = 0; j < list->GetNumberOfIds(); j++) if (pointMap[list->GetId(j)] < 0) pointMap[list->GetId(j)] = numOutPts++;
+     }
+-  vtkPoints *newPts = vtkPoints::New(input->GetPoints()->GetDataType());
+-  newPts->SetNumberOfPoints(numOutPts);
+   vtkPointData *inputPD  = input->GetPointData();
+   vtkPointData *outputPD = output->GetPointData();
+   outputPD->CopyAllocate(inputPD, numOutPts);
+   
++  vtkPoints *newPts = vtkPoints::New(input->GetPoints()->GetDataType());
++  newPts->SetNumberOfPoints(numOutPts);
+   for (j = 0 ; j < numInPts ; j++)
+     {
+     if (pointMap[j] != -1)
+@@ -149,43 +141,38 @@ vtkUnstructuredGridRelevantPointsFilter::RequestData(
+       outputPD->CopyData(inputPD, j, pointMap[j]);
+       }
+     }
++  output->SetPoints(newPts);
+   vtkCellData  *inputCD = input->GetCellData();
+   vtkCellData  *outputCD = output->GetCellData();
+   outputCD->PassData(inputCD);
+-  
+-  vtkIdList *cellIds = vtkIdList::New();
+-
+-  output->SetPoints(newPts);
+-
+-  // now work through cells, changing associated point id to coincide
+-  // with the new ones as specified in the pointmap;
+-  vtkIdList *oldIds = vtkIdList::New(); 
+-  vtkIdList *newIds = vtkIdList::New();
+-  int id, cellType;
+-  cellIter = vtk::TakeSmartPointer(cells->NewIterator());
+-  for (cellIter->GoToFirstCell();
+-       !cellIter->IsDoneWithTraversal();
+-       cellIter->GoToNextCell())
++  std::vector<vtkIdType> points, faces;
++  for (i = 0; i < numCells; i++)
+     {
+-    vtkIdList *cell = cellIter->GetCurrentCell();
+-    cellType = input->GetCellType(cellIter->GetCurrentCellId());
+-    int npts = static_cast<int>(cell->GetNumberOfIds());
++      int CellType = input->GetCellType(i);
++      points.resize(0), faces.resize(0);
++      input->GetCellPoints(i, list);
++      
++      for (j = 0; j < list->GetNumberOfIds(); j++) points.push_back(pointMap[list->GetId(j)]);
+-    newIds->SetNumberOfIds(npts);
+-    for (j = 0; j < npts ; j++)
++      if (CellType == VTK_POLYHEDRON) //must deal with faces stream
+       {
+-      id = cell->GetId(j);
+-      newIds->SetId(j, pointMap[id]);
++        input->GetFaceStream(i, list);
++        int nfaces = list->GetId(0), idx = 1;
++        for (j = 0; j < nfaces; j++)
++        {
++          int npts = list->GetId(idx);
++          faces.push_back(npts), idx++;
++          for (int k = 0; k < npts; k++) faces.push_back(pointMap[list->GetId(idx)]), idx++;
++        }
++        output->InsertNextCell(CellType, points.size(), &points[0], nfaces, &faces[0]);
+       }
+-      output->InsertNextCell(cellType, newIds);
++      else output->InsertNextCell(CellType, points.size(), &points[0]);      
+     }
+   newPts->Delete();
+-  oldIds->Delete();
+-  newIds->Delete();
+-  cellIds->Delete();
++  list->Delete();
+   delete [] pointMap;
+   return 1;
+-- 
+2.17.0
+
diff --git a/config/patches/paraview.0003-ParaViewClient.patch b/config/patches/paraview.0003-ParaViewClient.patch
new file mode 100644 (file)
index 0000000..5245133
--- /dev/null
@@ -0,0 +1,10 @@
+--- ParaView-5.8.0-RC2.orig/CMake/ParaViewClient.cmake 2020-03-02 15:38:53.791382799 +0300
++++ ParaView-5.8.0-RC2.new/CMake/ParaViewClient.cmake  2020-03-02 18:31:04.304698442 +0300
+@@ -516,6 +516,7 @@
+     NAMES xmlpatterns-qt5 xmlpatterns
+     HINTS "${Qt5_DIR}/../../../bin"
+           "${Qt5_DIR}/../../../libexec/qt5/bin"
++    NO_CMAKE_PATH
+     DOC   "Path to xmlpatterns")
+   mark_as_advanced(qt_xmlpatterns_executable)
diff --git a/config/patches/paraview.0004-ParaView_hdf5.patch b/config/patches/paraview.0004-ParaView_hdf5.patch
new file mode 100644 (file)
index 0000000..699226f
--- /dev/null
@@ -0,0 +1,14 @@
+diff -Naur ParaView-5.8.0_SRC_orig/VTK/ThirdParty/hdf5/CMakeLists.txt ParaView-5.8.0_SRC_modif/VTK/ThirdParty/hdf5/CMakeLists.txt
+--- ParaView-5.8.0_SRC_orig/VTK/ThirdParty/hdf5/CMakeLists.txt 2020-03-31 15:23:53.279485815 +0300
++++ ParaView-5.8.0_SRC_modif/VTK/ThirdParty/hdf5/CMakeLists.txt        2020-03-31 13:59:17.768118278 +0300
+@@ -10,8 +10,8 @@
+   EXTERNAL
+     PACKAGE       HDF5
+     COMPONENTS    C HL
+-    TARGETS       hdf5::hdf5
+-                  hdf5::hdf5_hl
++    TARGETS       hdf5::hdf5-shared
++                  hdf5::hdf5_hl-shared
+     USE_VARIABLES HDF5_IS_PARALLEL
+     STANDARD_INCLUDE_DIRS)
diff --git a/config/patches/paraview.0005-ParaView_find_cgns.patch b/config/patches/paraview.0005-ParaView_find_cgns.patch
new file mode 100644 (file)
index 0000000..d636c32
--- /dev/null
@@ -0,0 +1,15 @@
+diff -Naur ParaView-5.8.0_SRC_orig/CMake/FindCGNS.cmake ParaView-5.8.0_SRC_modif/CMake/FindCGNS.cmake
+--- ParaView-5.8.0_SRC_orig/CMake/FindCGNS.cmake       2020-03-23 13:27:34.000000000 +0300
++++ ParaView-5.8.0_SRC_modif/CMake/FindCGNS.cmake      2020-04-09 16:21:57.263362265 +0300
+@@ -5,6 +5,11 @@
+ # CGNS_LIBRARIES   - List of fully qualified libraries to link against when using CGNS.
+ # CGNS_FOUND       - Do not attempt to use CGNS if "no" or undefined.
++SET(CGNS_ROOT_DIR $ENV{CGNS_ROOT_DIR} CACHE PATH "Path to the CGNS.")
++IF(CGNS_ROOT_DIR)
++  LIST(APPEND CMAKE_PREFIX_PATH "${CGNS_ROOT_DIR}")
++ENDIF(CGNS_ROOT_DIR)
++
+ find_path(CGNS_INCLUDE_DIR
+   NAMES
+     cgnslib.h
diff --git a/config/patches/paraview.0006-ParaView_find_libxml2.patch b/config/patches/paraview.0006-ParaView_find_libxml2.patch
new file mode 100644 (file)
index 0000000..a741d50
--- /dev/null
@@ -0,0 +1,14 @@
+--- ParaView-5.8.0_SRC_orig/VTK/CMake/FindLibXml2.cmake        2020-03-23 22:17:27.000000000 +0100
++++ ParaView-5.8.0_SRC_modif/VTK/CMake/FindLibXml2.cmake       2020-04-10 09:56:00.627562062 +0200
+@@ -53,6 +53,11 @@
+ PKG_CHECK_MODULES(PC_LIBXML QUIET libxml-2.0)
+ set(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER})
++SET(LIBXML2_ROOT_DIR $ENV{LIBXML2_ROOT_DIR} CACHE PATH "Path to the LIBXML2.")
++IF(LIBXML2_ROOT_DIR)
++ LIST(APPEND CMAKE_PREFIX_PATH "${LIBXML2_ROOT_DIR}")
++ENDIF(LIBXML2_ROOT_DIR)
++
+ find_path(LIBXML2_INCLUDE_DIR NAMES libxml/xpath.h
+    HINTS
+    ${PC_LIBXML_INCLUDEDIR}
diff --git a/config/patches/paraview.0007-ParaView_find_freetype.patch b/config/patches/paraview.0007-ParaView_find_freetype.patch
new file mode 100644 (file)
index 0000000..04e86fa
--- /dev/null
@@ -0,0 +1,15 @@
+diff -Naur ParaView-5.8.0_SRC_orig/VTK/CMake/FindFreetype.cmake ParaView-5.8.0_SRC_modif/VTK/CMake/FindFreetype.cmake
+--- ParaView-5.8.0_SRC_orig/VTK/CMake/FindFreetype.cmake       2020-03-23 13:31:26.000000000 +0300
++++ ParaView-5.8.0_SRC_modif/VTK/CMake/FindFreetype.cmake      2020-04-10 22:27:24.194525121 +0300
+@@ -63,6 +63,11 @@
+ # I'm going to attempt to cut out the middleman and hope
+ # everything still works.
++SET(FREETYPE_ROOT_DIR $ENV{FREETYPE_ROOT_DIR} CACHE PATH "Path to the FreeType.")
++IF(FREETYPE_ROOT_DIR)
++  LIST(APPEND CMAKE_PREFIX_PATH "${FREETYPE_ROOT_DIR}")
++ENDIF(FREETYPE_ROOT_DIR)
++
+ set(FREETYPE_FIND_ARGS
+   HINTS
+     ENV FREETYPE_DIR
diff --git a/config/patches/paraview.001_against_multiple_py_sv_thr.patch b/config/patches/paraview.001_against_multiple_py_sv_thr.patch
deleted file mode 100644 (file)
index 33059a2..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-diff -ruN ParaView/VTK/Utilities/PythonInterpreter/vtkPythonInterpreter.cxx ParaView_new/VTK/Utilities/PythonInterpreter/vtkPythonInterpreter.cxx
---- ParaView/VTK/Utilities/PythonInterpreter/vtkPythonInterpreter.cxx  2019-05-28 08:19:55.673481437 +0200
-+++ ParaView_new/VTK/Utilities/PythonInterpreter/vtkPythonInterpreter.cxx      2019-05-28 08:08:21.000000000 +0200
-@@ -260,8 +260,11 @@
-     vtkPythonInterpreter::InitializedOnce = true;
- #ifdef VTK_PYTHON_FULL_THREADSAFE
--    PyEval_InitThreads(); // safe to call this multiple time
--    PyEval_SaveThread(); // release GIL
-+    if(PyEval_ThreadsInitialized() == 0)
-+    {
-+      PyEval_InitThreads(); // safe to call this multiple time
-+      PyEval_SaveThread(); // release GIL
-+    }
- #endif
-     // HACK: Calling PyRun_SimpleString for the first time for some reason results in
diff --git a/config/patches/paraview.002_statestorage_bug.patch b/config/patches/paraview.002_statestorage_bug.patch
deleted file mode 100644 (file)
index 0115740..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-diff -Naur ParaView-5.6.0-bfaf7b82_SRC_orig/VTK/Rendering/OpenGL2/vtkStateStorage.h ParaView-5.6.0-bfaf7b82_SRC_modif/VTK/Rendering/OpenGL2/vtkStateStorage.h
---- ParaView-5.6.0-bfaf7b82_SRC_orig/VTK/Rendering/OpenGL2/vtkStateStorage.h   2019-06-25 16:00:38.000000000 +0300
-+++ ParaView-5.6.0-bfaf7b82_SRC_modif/VTK/Rendering/OpenGL2/vtkStateStorage.h  2019-07-12 11:32:00.000000000 +0300
-@@ -51,8 +51,11 @@
- #include <algorithm>
- #include <string>
-+#include <vector>
--#ifndef NDEBUG // a debug implementation
-+// uncomment the folowing line to add in state debugging information
-+//#define USE_STATE_DEBUGGING 1
-+#ifdef USE_STATE_DEBUGGING
- class VTKRENDERINGOPENGL2_EXPORT vtkStateStorage
- {
-@@ -120,7 +123,7 @@
-   this->Storage.insert(this->Storage.end(), start, start + sizeof(T));
- }
--#else // release implementation
-+#else // normal implementation
- class VTKRENDERINGOPENGL2_EXPORT vtkStateStorage
- {
-@@ -157,7 +160,7 @@
-   this->Storage.insert(this->Storage.end(), start, start + sizeof(T));
- }
--#endif // Release implementation
-+#endif // normal implementation
- #endif // vtkStateStorage_h
diff --git a/config/patches/paraview.004_forwarding.patch b/config/patches/paraview.004_forwarding.patch
deleted file mode 100644 (file)
index 22f698a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -Naur ParaView-5.0.0_SRC_orig/CMake/pvForwardingExecutable.cmake ParaView-5.0.0_SRC_modif/CMake/pvForwardingExecutable.cmake
---- ParaView-5.0.0_SRC_orig/CMake/pvForwardingExecutable.cmake 2015-12-16 20:09:48.000000000 +0300
-+++ ParaView-5.0.0_SRC_modif/CMake/pvForwardingExecutable.cmake        2016-01-15 18:01:57.000000000 +0300
-@@ -81,7 +81,7 @@
-       add_executable(${exe_name}${PV_EXE_SUFFIX}
-         ${CMAKE_CURRENT_BINARY_DIR}/${exe_name}-forward.c)
-       set_target_properties(${exe_name}${PV_EXE_SUFFIX} PROPERTIES
--        RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/launcher)
-+        RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/launcher COMPILE_FLAGS -O2)
-       set_target_properties(${exe_name}${PV_EXE_SUFFIX} PROPERTIES
-         OUTPUT_NAME ${exe_name})
-       add_dependencies(${exe_name}${PV_EXE_SUFFIX} ${exe_name})