--- /dev/null
+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
+