Skip to content
Snippets Groups Projects
FieldIO.cpp 59.5 KiB
Newer Older
////////////////////////////////////////////////////////////////////////////////
//
//  File: FieldIO.cpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  Permission is hereby granted, free of charge, to any person obtaining a
//  copy of this software and associated documentation files (the "Software"),
//  to deal in the Software without restriction, including without limitation
//  the rights to use, copy, modify, merge, publish, distribute, sublicense,
//  and/or sell copies of the Software, and to permit persons to whom the
//  Software is furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included
//  in all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
//  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
//  DEALINGS IN THE SOFTWARE.
//
//  Description: I/O routines relating to Fields
//
////////////////////////////////////////////////////////////////////////////////

#include <boost/format.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <boost/asio/ip/host_name.hpp>

#include <LibUtilities/BasicUtils/FieldIO.h>
#include <LibUtilities/BasicUtils/FileSystem.h>
#include <LibUtilities/BasicConst/GitRevision.h>

#ifdef NEKTAR_USE_MPI
#include <mpi.h>
#endif

// Buffer size for zlib compression/decompression
#define CHUNK 16384
#ifndef NEKTAR_VERSION
#define NEKTAR_VERSION "Unknown"
#endif

namespace ptime = boost::posix_time;
namespace ip = boost::asio::ip;

namespace Nektar
{
    namespace LibUtilities
    {
        /**
         * This function allows for data to be written to an FLD file when a
         * session and/or communicator is not instantiated. Typically used in
         * utilities which do not take XML input and operate in serial only.
         */
        void Write(     const std::string &outFile,
                        std::vector<FieldDefinitionsSharedPtr> &fielddefs,
                        std::vector<std::vector<NekDouble> >   &fielddata,
                        const FieldMetaDataMap &fieldinfomap)
#ifdef NEKTAR_USE_MPI
            int size;
            MPI_Comm_size( MPI_COMM_WORLD, &size );
            ASSERTL0(size == 1, "This function is not available in parallel.");
            CommSharedPtr c = GetCommFactory().CreateInstance("Serial", 0, 0);
            FieldIO f(c);
            f.Write(outFile, fielddefs, fielddata, fieldinfomap);
        /**
         * This function allows for data to be imported from an FLD file when
         * a session and/or communicator is not instantiated. Typically used in
         * utilities which only operate in serial.
         */
        LIB_UTILITIES_EXPORT void Import(
                        const std::string& infilename,
                        std::vector<FieldDefinitionsSharedPtr> &fielddefs,
                        std::vector<std::vector<NekDouble> > &fielddata,
                        FieldMetaDataMap &fieldinfomap,
                        const Array<OneD, int> ElementiDs)
        {
#ifdef NEKTAR_USE_MPI
            int size;
            MPI_Comm_size( MPI_COMM_WORLD, &size );
            ASSERTL0(size == 1, "This function is not available in parallel.");
#endif
            CommSharedPtr c = GetCommFactory().CreateInstance("Serial", 0, 0);
            FieldIO f(c);
            f.Import(infilename, fielddefs, fielddata, fieldinfomap, ElementiDs);
        FieldIO::FieldIO(
                LibUtilities::CommSharedPtr pComm)
            : m_comm(pComm)
        void FieldIO::Write(const std::string &outFile,
                   std::vector<FieldDefinitionsSharedPtr> &fielddefs,
                   std::vector<std::vector<NekDouble> > &fielddata, 
                   const FieldMetaDataMap &fieldmetadatamap)
            // Check everything seems sensible
            ASSERTL1(fielddefs.size() == fielddata.size(),
                      "Length of fielddefs and fielddata incompatible");
            for (int f = 0; f < fielddefs.size(); ++f)
            {
                ASSERTL1(fielddata[f].size() > 0,
                        "Fielddata vector must contain at least one value.");
                ASSERTL1(fielddata[f].size() ==
                             fielddefs[f]->m_fields.size() *
                             CheckFieldDefinition(fielddefs[f]),
                         "Invalid size of fielddata vector.");
            }

            // Prepare to write out data. In parallel, we must create directory
            // and determine the full pathname to the file to write out.
            // Any existing file/directory which is in the way is removed.
            std::string filename = SetUpOutput(outFile, fielddefs, fieldmetadatamap);

            // Create the file (partition)
            TiXmlDocument doc;
            TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "utf-8", "");
            doc.LinkEndChild(decl);

            cout << "Writing outfile: " << filename << endl;

            TiXmlElement * root = new TiXmlElement("NEKTAR");
            doc.LinkEndChild(root);

            AddInfoTag(root,fieldmetadatamap);

            for (int f = 0; f < fielddefs.size(); ++f)
            {
                //---------------------------------------------
                // Write ELEMENTS
                TiXmlElement * elemTag = new TiXmlElement("ELEMENTS");
                root->LinkEndChild(elemTag);

                // Write FIELDS
                std::string fieldsString;
                {
                    std::stringstream fieldsStringStream;
                    bool first = true;
                    for (std::vector<int>::size_type i = 0; i
                    < fielddefs[f]->m_fields.size(); i++)
                    {
                        if (!first)
                            fieldsStringStream << ",";
                        fieldsStringStream << fielddefs[f]->m_fields[i];
                        first = false;
                    }
                    fieldsString = fieldsStringStream.str();
                }
                elemTag->SetAttribute("FIELDS", fieldsString);

                // Write SHAPE
                std::string shapeString;
                {
                    std::stringstream shapeStringStream;
                    shapeStringStream << ShapeTypeMap[fielddefs[f]->m_shapeType];
                    if(fielddefs[f]->m_numHomogeneousDir == 1)
                    {
                        shapeStringStream << "-HomogenousExp1D";
                    }
                    else if (fielddefs[f]->m_numHomogeneousDir == 2)
                    {
                        shapeStringStream << "-HomogenousExp2D";
                    }

                    shapeString = shapeStringStream.str();
                }
                elemTag->SetAttribute("SHAPE", shapeString);

                // Write BASIS
                std::string basisString;
                {
                    std::stringstream basisStringStream;
                    bool first = true;
                    for (std::vector<BasisType>::size_type i = 0; i < fielddefs[f]->m_basis.size(); i++)
                    {
                        if (!first)
                            basisStringStream << ",";
                        basisStringStream
                        << BasisTypeMap[fielddefs[f]->m_basis[i]];
                        first = false;
                    }
                    basisString = basisStringStream.str();
                }
                elemTag->SetAttribute("BASIS", basisString);

                // Write homogeneuous length details
                if(fielddefs[f]->m_numHomogeneousDir)
                {
                    std::string homoLenString;
                    {
                        std::stringstream homoLenStringStream;
                        bool first = true;
                        for (int i = 0; i < fielddefs[f]->m_numHomogeneousDir; ++i)
                        {
                            if (!first)
                                homoLenStringStream << ",";
                            homoLenStringStream
                            << fielddefs[f]->m_homogeneousLengths[i];
                            first = false;
                        }
                        homoLenString = homoLenStringStream.str();
                    }
                    elemTag->SetAttribute("HOMOGENEOUSLENGTHS", homoLenString);
                }
				
                // Write homogeneuous planes/lines details
                if(fielddefs[f]->m_numHomogeneousDir)
                {
                    if(fielddefs[f]->m_homogeneousYIDs.size() > 0)
                    {
                        std::string homoYIDsString;
                        {
                            std::stringstream homoYIDsStringStream;
                            bool first = true;
                            for(int i = 0; i < fielddefs[f]->m_homogeneousYIDs.size(); i++)
                            {
                                if (!first)
                                    homoYIDsStringStream << ",";
                                homoYIDsStringStream << fielddefs[f]->m_homogeneousYIDs[i];
                                first = false;
                            }
                            homoYIDsString = homoYIDsStringStream.str();
                        }
                        elemTag->SetAttribute("HOMOGENEOUSYIDS", homoYIDsString);
                    }
                    
                    if(fielddefs[f]->m_homogeneousZIDs.size() > 0)
                    {
                        std::string homoZIDsString;
                        {
                            std::stringstream homoZIDsStringStream;
                            bool first = true;
                            for(int i = 0; i < fielddefs[f]->m_homogeneousZIDs.size(); i++)
                            {
                                if (!first)
                                    homoZIDsStringStream << ",";
                                homoZIDsStringStream << fielddefs[f]->m_homogeneousZIDs[i];
                                first = false;
                            }
                            homoZIDsString = homoZIDsStringStream.str();
                        }
                        elemTag->SetAttribute("HOMOGENEOUSZIDS", homoZIDsString);
                    }
                }
                
                // Write NUMMODESPERDIR
                std::string numModesString;
                {
                    std::stringstream numModesStringStream;

                    if (fielddefs[f]->m_uniOrder)
                    {
                        numModesStringStream << "UNIORDER:";
                        // Just dump single definition
                        bool first = true;
                        for (std::vector<int>::size_type i = 0; i
                                 < fielddefs[f]->m_basis.size(); i++)
                        {
                            if (!first)
                                numModesStringStream << ",";
                            numModesStringStream << fielddefs[f]->m_numModes[i];
                            first = false;
                        }
                    }
                    else
                    {
                        numModesStringStream << "MIXORDER:";
                        bool first = true;
                        for (std::vector<int>::size_type i = 0; i
                                 < fielddefs[f]->m_numModes.size(); i++)
                        {
                            if (!first)
                                numModesStringStream << ",";
                            numModesStringStream << fielddefs[f]->m_numModes[i];
                            first = false;
                        }
                    }
                    
                    numModesString = numModesStringStream.str();
                }
                elemTag->SetAttribute("NUMMODESPERDIR", numModesString);

                // Write ID
                // Should ideally look at ways of compressing this stream
                // if just sequential;
                std::string idString;
                {
                    std::stringstream idStringStream;
                    GenerateSeqString(fielddefs[f]->m_elementIDs,idString);
                }
                elemTag->SetAttribute("ID", idString);

                std::string compressedDataString;
                ASSERTL0(Z_OK == Deflate(fielddata[f], compressedDataString),
                        "Failed to compress field data.");

                // If the string length is not divisible by 3,
                // pad it. There is a bug in transform_width
                // that will make it reference past the end
                // and crash.
                switch (compressedDataString.length() % 3)
                case 1:
                    compressedDataString += '\0';
                case 2:
                    compressedDataString += '\0';
                    break;
                }

                // Convert from binary to base64.
                typedef boost::archive::iterators::base64_from_binary<
                        boost::archive::iterators::transform_width<
                        std::string::const_iterator, 6, 8> > base64_t;
                std::string base64string(base64_t(compressedDataString.begin()),
                        base64_t(compressedDataString.end()));
                elemTag->LinkEndChild(new TiXmlText(base64string));

            }
            doc.SaveFile(filename);
        void FieldIO::Import(const std::string& infilename,
                    std::vector<FieldDefinitionsSharedPtr> &fielddefs,
                    std::vector<std::vector<NekDouble> > &fielddata,
                    FieldMetaDataMap &fieldmetadatamap,
                    const Array<OneD, int> ElementIDs)
            std::string infile = infilename;
            fs::path pinfilename(infilename);            
            
            if(fs::is_directory(pinfilename)) // check to see that infile is a directory
                fs::path fullpath = pinfilename / infofile; 
                infile = PortablePath(fullpath);
                std::vector<std::string> filenames; 
                std::vector<std::vector<unsigned int> > elementIDs_OnPartitions;
                
            
                ImportMultiFldFileIDs(infile,filenames, elementIDs_OnPartitions,
                                      fieldmetadatamap);
                if(ElementIDs == NullInt1DArray) //load all fields
                {
                    for(int i = 0; i < filenames.size(); ++i)
                    {
                        fs::path pfilename(filenames[i]);
                        fullpath = pinfilename / pfilename; 
                        string fname = PortablePath(fullpath); 

                        TiXmlDocument doc1(fname);
                        bool loadOkay1 = doc1.LoadFile();
                        
                        std::stringstream errstr;
                        errstr << "Unable to load file: " << fname << std::endl;
                        errstr << "Reason: " << doc1.ErrorDesc() << std::endl;
                        errstr << "Position: Line " << doc1.ErrorRow() << ", Column " << doc1.ErrorCol() << std::endl;
                        ASSERTL0(loadOkay1, errstr.str());
                        
                        ImportFieldDefs(doc1, fielddefs, false);
                        ImportFieldData(doc1, fielddefs, fielddata);
                    }
                }
                else // only load relevant partitions
                {
                    int i,j;
                    map<int,int> FileIDs; 
                    set<int> LoadFile;
                    
                    for(i = 0; i < elementIDs_OnPartitions.size(); ++i)
                    {
                        for(j = 0; j < elementIDs_OnPartitions[i].size(); ++j)
                        {
                            FileIDs[elementIDs_OnPartitions[i][j]] = i;
                        }
                    }
                    
                    for(i = 0; i < ElementIDs.num_elements(); ++i)
                    {
                        ASSERTL1(FileIDs.count(ElementIDs[i]) != 0,
                                 "ElementIDs  not found in partitions");
                        
                        LoadFile.insert(FileIDs[ElementIDs[i]]);
                    }
                    
                    set<int>::iterator iter; 
                    for(iter = LoadFile.begin(); iter != LoadFile.end(); ++iter)
                    {
                        fs::path pfilename(filenames[*iter]);
                        fullpath = pinfilename / pfilename; 
                        string fname = PortablePath(fullpath); 
                        TiXmlDocument doc1(fname);
                        bool loadOkay1 = doc1.LoadFile();
                        
                        std::stringstream errstr;
                        errstr << "Unable to load file: " << fname << std::endl;
                        errstr << "Reason: " << doc1.ErrorDesc() << std::endl;
                        errstr << "Position: Line " << doc1.ErrorRow() << ", Column " << doc1.ErrorCol() << std::endl;
                        ASSERTL0(loadOkay1, errstr.str());
                        
                        ImportFieldDefs(doc1, fielddefs, false);
                        ImportFieldData(doc1, fielddefs, fielddata);
                    }
                }
            }
                
                TiXmlDocument doc(infile);
                bool loadOkay = doc.LoadFile();
                
                std::stringstream errstr;
                errstr << "Unable to load file: " << infile << std::endl;
                errstr << "Reason: " << doc.ErrorDesc() << std::endl;
                errstr << "Position: Line " << doc.ErrorRow() << ", Column " << 
                    doc.ErrorCol() << std::endl;
                ASSERTL0(loadOkay, errstr.str());
                
                ImportFieldMetaData(doc,fieldmetadatamap);
                ImportFieldDefs(doc, fielddefs, false);
                ImportFieldData(doc, fielddefs, fielddata);
            }
        }

        /**
         *
         */
        void FieldIO::WriteMultiFldFileIDs(const std::string &outFile,
                                  const std::vector<std::string> fileNames,
                                  std::vector<std::vector<unsigned int> > &elementList,
                                  const FieldMetaDataMap &fieldmetadatamap)
        {
            TiXmlDocument doc;
            TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "utf-8", "");
            doc.LinkEndChild(decl);

            ASSERTL0(fileNames.size() == elementList.size(),"Outfile names and list of elements ids does not match");

Dave Moxey's avatar
Dave Moxey committed
            cout << "Writing multi-file data: " << outFile << endl;

            TiXmlElement * root = new TiXmlElement("NEKTAR");
            doc.LinkEndChild(root);

            AddInfoTag(root,fieldmetadatamap);

            for (int t = 0; t < fileNames.size(); ++t)
            {

                ASSERTL1(elementList[t].size() > 0,
                         "Element list must contain at least one value.");

                TiXmlElement * elemIDs = new TiXmlElement("Partition");
                root->LinkEndChild(elemIDs);

                elemIDs->SetAttribute("FileName",fileNames[t]);

                string IDstring;

                GenerateSeqString(elementList[t],IDstring);

                elemIDs->LinkEndChild(new TiXmlText(IDstring));
            }

            doc.SaveFile(outFile);
        }


         void FieldIO::ImportMultiFldFileIDs(const std::string &inFile,
                                    std::vector<std::string> &fileNames,
                                    std::vector<std::vector<unsigned int> > &elementList,
                                    FieldMetaDataMap &fieldmetadatamap)
             TiXmlDocument doc(inFile);
             bool loadOkay = doc.LoadFile();
             
             
             std::stringstream errstr;
             errstr << "Unable to load file: " << inFile<< std::endl;
             errstr << "Reason: " << doc.ErrorDesc() << std::endl;
             errstr << "Position: Line " << doc.ErrorRow() << ", Column " << doc.ErrorCol() << std::endl;
             ASSERTL0(loadOkay, errstr.str());
             
             // Handle on XML document
             // Retrieve main NEKTAR tag - XML specification states one
             // top-level element tag per file.
             TiXmlElement* master = doc.FirstChildElement("NEKTAR");
             ASSERTL0(master, "Unable to find NEKTAR tag in file.");

             // Partition element tag name
             std::string strPartition = "Partition";

             // First attempt to get the first Partition element
             TiXmlElement* fldfileIDs = master->FirstChildElement(strPartition.c_str());
             if (!fldfileIDs)
                 // If this files try previous name
                 strPartition = "MultipleFldFiles";
                 fldfileIDs = master->FirstChildElement("MultipleFldFiles");
             }
             ASSERTL0(fldfileIDs,
                      "Unable to find 'Partition' or 'MultipleFldFiles' tag "
                      "within nektar tag.");

             while (fldfileIDs)
             {
                // Read file name of partition file
                const char *attr = fldfileIDs->Attribute("FileName");
                ASSERTL0(attr, "'FileName' not provided as an attribute of '"
                                + strPartition + "' tag.");
                fileNames.push_back(std::string(attr));

                const char* elementIDs = fldfileIDs->GetText();
                ASSERTL0(elementIDs, "Element IDs not specified.");

                std::string elementIDsStr(elementIDs);

                std::vector<unsigned int> idvec;
                ParseUtils::GenerateSeqVector(elementIDsStr.c_str(),idvec);

                elementList.push_back(idvec);

                fldfileIDs = fldfileIDs->NextSiblingElement(strPartition.c_str());
        void FieldIO::ImportFieldMetaData(std::string filename,
                                 FieldMetaDataMap &fieldmetadatamap)
        {
            TiXmlDocument doc(filename);
            bool loadOkay = doc.LoadFile();
            
            std::stringstream errstr;
            errstr << "Unable to load file: " << filename << std::endl;
            errstr << "Reason: " << doc.ErrorDesc() << std::endl;
            errstr << "Position: Line " << doc.ErrorRow() << ", Column " << doc.ErrorCol() << std::endl;
            ASSERTL0(loadOkay, errstr.str());
                    
            ImportFieldMetaData(doc,fieldmetadatamap);
        }
        

        void FieldIO::ImportFieldMetaData(TiXmlDocument &doc,
                                FieldMetaDataMap &fieldmetadatamap)
        {
            
            TiXmlHandle docHandle(&doc);
            TiXmlElement* master = 0;    // Master tag within which all data is contained.
            TiXmlElement* metadata = 0;
            
            master = doc.FirstChildElement("NEKTAR");
            ASSERTL0(master, "Unable to find NEKTAR tag in file.");
            std::string strLoop = "NEKTAR";

            // Retain original metadata structure for backwards compatibility
            // TODO: Remove old metadata format
            metadata = master->FirstChildElement("FIELDMETADATA");
            if(metadata)
            {
                TiXmlElement *param = metadata->FirstChildElement("P");
                while (param)
                {
                    TiXmlAttribute *paramAttr = param->FirstAttribute();
                    std::string attrName(paramAttr->Name());
                    std::string paramString;
                    if(attrName == "PARAM")
                    {
                        paramString.insert(0,paramAttr->Value());
                    }
                    else
                    {
                        ASSERTL0(false,"PARAM not provided as an attribute in FIELDMETADATA section");
                    }

                    // Now read body of param
                    std::string paramBodyStr;
                    TiXmlNode *paramBody = param->FirstChild();
                    paramBodyStr += paramBody->ToText()->Value();

                    fieldmetadatamap[paramString] = paramBodyStr;
                    param = param->NextSiblingElement("P");
                }
            }

            // New metadata format
            metadata = master->FirstChildElement("Metadata");
            if(metadata)
            {
                TiXmlElement *param = metadata->FirstChildElement();
                while (param)
                {
                    std::string paramString = param->Value();
                    if (paramString != "Provenance")
                        // Now read body of param
                        TiXmlNode *paramBody = param->FirstChild();
                        std::string paramBodyStr = paramBody->ToText()->Value();
                        fieldmetadatamap[paramString] = paramBodyStr;
                    }
                    param = param->NextSiblingElement();
        }
        

        /**
         * The bool decides if the FieldDefs are in <EXPANSIONS> or in <NEKTAR>.
         */
        void FieldIO::ImportFieldDefs(TiXmlDocument &doc, std::vector<FieldDefinitionsSharedPtr> &fielddefs,
                             bool expChild)
        {
            TiXmlHandle docHandle(&doc);
            TiXmlElement* master = NULL;    // Master tag within which all data is contained.

            master = doc.FirstChildElement("NEKTAR");
            ASSERTL0(master, "Unable to find NEKTAR tag in file.");
            std::string strLoop = "NEKTAR";
            TiXmlElement* loopXml = master;

            TiXmlElement *expansionTypes;
            if(expChild)
            {
                expansionTypes = master->FirstChildElement("EXPANSIONS");
                ASSERTL0(expansionTypes, "Unable to find EXPANSIONS tag in file.");
                loopXml = expansionTypes;
                strLoop = "EXPANSIONS";
            }

            // Loop through all nektar tags, finding all of the element tags.
            while (loopXml)
            {
                TiXmlElement* element = loopXml->FirstChildElement("ELEMENTS");
                ASSERTL0(element, "Unable to find ELEMENTS tag within nektar tag.");

                while (element)
                {
                    // Extract the attributes.
                    std::string idString;
                    std::string shapeString;
                    std::string basisString;
                    std::string homoLengthsString;
                    std::string homoZIDsString;
                    std::string homoYIDsString;
                    std::string numModesString;
                    std::string numPointsString;
                    std::string fieldsString;
                    std::string pointsString;
                    bool pointDef = false;
                    bool numPointDef = false;
                    TiXmlAttribute *attr = element->FirstAttribute();
                    while (attr)
                    {
                        std::string attrName(attr->Name());
                        if (attrName == "FIELDS")
                        {
                            fieldsString.insert(0, attr->Value());
                        }
                        else if (attrName == "SHAPE")
                        {
                            shapeString.insert(0, attr->Value());
                        }
                        else if (attrName == "BASIS")
                        {
                            basisString.insert(0, attr->Value());
                        }
                        else if (attrName == "HOMOGENEOUSLENGTHS")
                        {
                            homoLengthsString.insert(0,attr->Value());
                        }
                        else if (attrName == "HOMOGENEOUSZIDS")
                        {
                            homoZIDsString.insert(0,attr->Value());
                        }
                        else if (attrName == "HOMOGENEOUSYIDS")
                        {
                            homoYIDsString.insert(0,attr->Value());
                        }
                        else if (attrName == "NUMMODESPERDIR")
                        {
                            numModesString.insert(0, attr->Value());
                        }
                        else if (attrName == "ID")
                        {
                            idString.insert(0, attr->Value());
                        }
                        else if (attrName == "POINTSTYPE")
                        {
                            pointsString.insert(0, attr->Value());
                            pointDef = true;
                        }
                        else if (attrName == "NUMPOINTSPERDIR")
                        {
                            numPointsString.insert(0, attr->Value());
                            numPointDef = true;
                        }
                        else
                        {
                            std::string errstr("Unknown attribute: ");
                            errstr += attrName;
                            ASSERTL1(false, errstr.c_str());
                        }

                        // Get the next attribute.
                        attr = attr->Next();
                    }

                    // Check to see if homogeneous expansion and if so
                    // strip down the shapeString definition
                    int numHomoDir = 0;
                    size_t loc;
                    //---> This finds the first location of  'n'!
                    if((loc = shapeString.find_first_of("-"))!=string::npos)
                    {
                        if(shapeString.find("Exp1D")!=string::npos)
                        {
                            numHomoDir = 1;
                        }
                        else // HomogeneousExp1D
                        {
                            numHomoDir = 2;
                        }

                        shapeString.erase(loc,shapeString.length());
                    }

                    // Reconstruct the fielddefs.
                    std::vector<unsigned int> elementIds;
                    {
                        bool valid = ParseUtils::GenerateSeqVector(idString.c_str(), elementIds);
                        ASSERTL0(valid, "Unable to correctly parse the element ids.");
                    }

                    // Get the geometrical shape
                    ShapeType shape;
                    bool valid = false;
                    for (unsigned int j = 0; j < SIZE_ShapeType; j++)
                    {
                        if (ShapeTypeMap[j] == shapeString)
                        {
                            shape = (ShapeType) j;
                            valid = true;
                            break;
                        }
                    }

                    ASSERTL0(valid, std::string("Unable to correctly parse the shape type: ").append(shapeString).c_str());

                    // Get the basis
                    std::vector<std::string> basisStrings;
                    std::vector<BasisType> basis;
                    valid = ParseUtils::GenerateOrderedStringVector(basisString.c_str(), basisStrings);
                    ASSERTL0(valid, "Unable to correctly parse the basis types.");
                    for (std::vector<std::string>::size_type i = 0; i < basisStrings.size(); i++)
                    {
                        valid = false;
                        for (unsigned int j = 0; j < SIZE_BasisType; j++)
                        {
                            if (BasisTypeMap[j] == basisStrings[i])
                            {
                                basis.push_back((BasisType) j);
                                valid = true;
                                break;
                            }
                        }
                        ASSERTL0(valid, std::string("Unable to correctly parse the basis type: ").append(basisStrings[i]).c_str());
                    }

                    // Get homoLengths
                    std::vector<NekDouble> homoLengths;
                    if(numHomoDir)
                    {
                        valid = ParseUtils::GenerateUnOrderedVector(homoLengthsString.c_str(), homoLengths);
                        ASSERTL0(valid, "Unable to correctly parse the number of homogeneous lengths.");
                    }
					
					// Get Homogeneous points IDs
					std::vector<unsigned int> homoZIDs;
					std::vector<unsigned int> homoYIDs;
					
					if(numHomoDir == 1)
                    {
                        valid = ParseUtils::GenerateSeqVector(homoZIDsString.c_str(), homoZIDs);
                        ASSERTL0(valid, "Unable to correctly parse homogeneous planes IDs.");
                    }
					
					if(numHomoDir == 2)
					{
						valid = ParseUtils::GenerateSeqVector(homoZIDsString.c_str(), homoZIDs);
                        ASSERTL0(valid, "Unable to correctly parse homogeneous lines IDs in z-direction.");
						valid = ParseUtils::GenerateSeqVector(homoYIDsString.c_str(), homoYIDs);
                        ASSERTL0(valid, "Unable to correctly parse homogeneous lines IDs in y-direction.");
					}
					

                    // Get points type
                    std::vector<PointsType> points;

                    if(pointDef)
                    {
                        std::vector<std::string> pointsStrings;
                        valid = ParseUtils::GenerateOrderedStringVector(pointsString.c_str(), pointsStrings);
                        ASSERTL0(valid, "Unable to correctly parse the points types.");
                        for (std::vector<std::string>::size_type i = 0; i < pointsStrings.size(); i++)
                        {
                            valid = false;
                            for (unsigned int j = 0; j < SIZE_PointsType; j++)
                            {
                                if (kPointsTypeStr[j] == pointsStrings[i])
                                {
                                    points.push_back((PointsType) j);
                                    valid = true;
                                    break;
                                }
                            }

                            ASSERTL0(valid, std::string("Unable to correctly parse the points type: ").append(pointsStrings[i]).c_str());
                        }
                    }

                    // Get numModes
                    std::vector<unsigned int> numModes;
                    bool UniOrder = false;

                    if(strstr(numModesString.c_str(),"UNIORDER:"))
                    {
                        UniOrder  = true;
                    }

                    valid = ParseUtils::GenerateOrderedVector(numModesString.c_str()+9, numModes);
                    ASSERTL0(valid, "Unable to correctly parse the number of modes.");

                    // Get numPoints
                    std::vector<unsigned int> numPoints;
                    if(numPointDef)
                    {
                        valid = ParseUtils::GenerateOrderedVector(numPointsString.c_str(), numPoints);
                        ASSERTL0(valid, "Unable to correctly parse the number of points.");
                    }

                    // Get fields names
                    std::vector<std::string> Fields;
                    valid = ParseUtils::GenerateOrderedStringVector(fieldsString.c_str(), Fields);
                    ASSERTL0(valid, "Unable to correctly parse the number of fields.");

                    FieldDefinitionsSharedPtr fielddef  = MemoryManager<FieldDefinitions>::AllocateSharedPtr(shape, elementIds, basis, UniOrder, numModes, Fields, numHomoDir, homoLengths, homoZIDs, homoYIDs, points, pointDef, numPoints, numPointDef);
                    
                    fielddefs.push_back(fielddef);

                    element = element->NextSiblingElement("ELEMENTS");
                }
                loopXml = loopXml->NextSiblingElement(strLoop);
            }
        }


        /**
         *
         */
        void FieldIO::ImportFieldData(TiXmlDocument &doc, const std::vector<FieldDefinitionsSharedPtr> &fielddefs, std::vector<std::vector<NekDouble> > &fielddata)
        {
            int cntdumps = 0;

            TiXmlHandle docHandle(&doc);
            TiXmlElement* master = NULL;    // Master tag within which all data is contained.

            master = doc.FirstChildElement("NEKTAR");
            ASSERTL0(master, "Unable to find NEKTAR tag in file.");

            // Loop through all nektar tags, finding all of the element tags.
            while (master)
            {
                TiXmlElement* element = master->FirstChildElement("ELEMENTS");
                ASSERTL0(element, "Unable to find ELEMENTS tag within nektar tag.");
                while (element)
                {
                    // Extract the body, which the "data".
                    TiXmlNode* elementChild = element->FirstChild();
                    ASSERTL0(elementChild, "Unable to extract the data from the element tag.");
                    std::string elementStr;
                    while(elementChild)
                    {
                        if (elementChild->Type() == TiXmlNode::TEXT)
                        {
                            elementStr += elementChild->ToText()->ValueStr();
                        }
                        elementChild = elementChild->NextSibling();
                    }

                    // Convert from base64 to binary.
                    typedef boost::archive::iterators::transform_width<
                            boost::archive::iterators::binary_from_base64<
                            std::string::const_iterator>, 8, 6 > binary_t;
                    std::string vCompressed(binary_t(elementStr.begin()),
                                            binary_t(elementStr.end()));
                    std::vector<NekDouble> elementFieldData;
                    ASSERTL0(Z_OK == Inflate(vCompressed, elementFieldData),
                            "Failed to decompress field data.");

                    fielddata.push_back(elementFieldData);

                    int datasize = CheckFieldDefinition(fielddefs[cntdumps]);
                    ASSERTL0(fielddata[cntdumps].size() == datasize*fielddefs[cntdumps]->m_fields.size(),"Input data is not the same length as header infoarmation");

                    cntdumps++;

                    element = element->NextSiblingElement("ELEMENTS");
                }
                master = master->NextSiblingElement("NEKTAR");
            }
        }


        /**
         * \brief add information about provenance and fieldmetadata
         */
        void FieldIO::AddInfoTag(TiXmlElement * root,
                             const FieldMetaDataMap &fieldmetadatamap)
        {
            FieldMetaDataMap ProvenanceMap;

            // Nektar++ release version from VERSION file
            ProvenanceMap["NektarVersion"] = string(NEKTAR_VERSION);

            // Date/time stamp
            ptime::time_facet *facet = new ptime::time_facet("%d-%b-%Y %H:%M:%S");
            std::stringstream wss;
            wss.imbue(locale(wss.getloc(), facet));
            wss << ptime::second_clock::local_time();
            ProvenanceMap["Timestamp"] = wss.str();

            // Hostname
            boost::system::error_code ec;
            ProvenanceMap["Hostname"] = ip::host_name(ec);

            // Git information
            // If built from a distributed package, do not include this
Dave Moxey's avatar
Dave Moxey committed
            if (NekConstants::kGitSha1 != "GITDIR-NOTFOUND")
Dave Moxey's avatar
Dave Moxey committed
                ProvenanceMap["GitSHA1"]   = NekConstants::kGitSha1;
                ProvenanceMap["GitBranch"] = NekConstants::kGitBranch;

            TiXmlElement * infoTag = new TiXmlElement("Metadata");
            root->LinkEndChild(infoTag);

            TiXmlElement * v;
            FieldMetaDataMap::const_iterator infoit;