source: XIOS/dev/dev_ym/XIOS_SERVICES/src/node/context.cpp @ 1765

Last change on this file since 1765 was 1765, checked in by ymipsl, 5 years ago

Some cleaning On XIOS services branch

YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 78.0 KB
RevLine 
[219]1#include "context.hpp"
[352]2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
[219]5
6#include "calendar_type.hpp"
[278]7#include "duration.hpp"
[219]8
[300]9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
[346]12#include "node_type.hpp"
[352]13#include "message.hpp"
14#include "type.hpp"
[591]15#include "xios_spl.hpp"
[1158]16#include "timer.hpp"
17#include "memtrack.hpp"
[1215]18#include <limits>
[1349]19#include <fstream>
[992]20#include "server.hpp"
[1349]21#include "distribute_file_server2.hpp"
[1761]22#include "services_manager.hpp"
23#include "contexts_manager.hpp"
24#include "cxios.hpp"
25#include "client.hpp"
[697]26
[335]27namespace xios {
[509]28
[1542]29  std::shared_ptr<CContextGroup> CContext::root;
[509]30
[219]31   /// ////////////////////// Définitions ////////////////////// ///
32
33   CContext::CContext(void)
34      : CObjectTemplate<CContext>(), CContextAttributes()
[983]35      , calendar(), hasClient(false), hasServer(false)
[1139]36      , isPostProcessed(false), finalized(false)
[1761]37      , idServer_(), client(nullptr), server(nullptr)
[1764]38      , allProcessed(false), countChildContextFinalized_(0), isProcessingEvent_(false)
[1622]39
[219]40   { /* Ne rien faire de plus */ }
41
42   CContext::CContext(const StdString & id)
43      : CObjectTemplate<CContext>(id), CContextAttributes()
[983]44      , calendar(), hasClient(false), hasServer(false)
[1139]45      , isPostProcessed(false), finalized(false)
[1761]46      , idServer_(), client(nullptr), server(nullptr)
[1764]47      , allProcessed(false), countChildContextFinalized_(0), isProcessingEvent_(false)
[219]48   { /* Ne rien faire de plus */ }
49
50   CContext::~CContext(void)
[509]51   {
[597]52     delete client;
53     delete server;
[1071]54     for (std::vector<CContextClient*>::iterator it = clientPrimServer.begin(); it != clientPrimServer.end(); it++)  delete *it;
55     for (std::vector<CContextServer*>::iterator it = serverPrimServer.begin(); it != serverPrimServer.end(); it++)  delete *it;
[1139]56
[300]57   }
[219]58
59   //----------------------------------------------------------------
[509]60   //! Get name of context
[219]61   StdString CContext::GetName(void)   { return (StdString("context")); }
62   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
63   ENodeType CContext::GetType(void)   { return (eContext); }
64
65   //----------------------------------------------------------------
[640]66
[509]67   /*!
68   \brief Get context group (context root)
69   \return Context root
70   */
[347]71   CContextGroup* CContext::getRoot(void)
[1622]72   TRY
[509]73   {
[1542]74      if (root.get()==NULL) root=std::shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
[509]75      return root.get();
[219]76   }
[1622]77   CATCH
[219]78
[640]79   //----------------------------------------------------------------
[509]80
81   /*!
82   \brief Get calendar of a context
83   \return Calendar
84   */
[1542]85   std::shared_ptr<CCalendar> CContext::getCalendar(void) const
[1622]86   TRY
[219]87   {
88      return (this->calendar);
89   }
[1622]90   CATCH
[509]91
[219]92   //----------------------------------------------------------------
[640]93
[509]94   /*!
95   \brief Set a context with a calendar
96   \param[in] newCalendar new calendar
97   */
[1542]98   void CContext::setCalendar(std::shared_ptr<CCalendar> newCalendar)
[1622]99   TRY
[219]100   {
101      this->calendar = newCalendar;
102   }
[1622]103   CATCH_DUMP_ATTR
[509]104
[219]105   //----------------------------------------------------------------
[509]106   /*!
107   \brief Parse xml file and write information into context object
108   \param [in] node xmld node corresponding in xml file
109   */
[219]110   void CContext::parse(xml::CXMLNode & node)
[1622]111   TRY
[219]112   {
113      CContext::SuperClass::parse(node);
114
115      // PARSING POUR GESTION DES ENFANTS
[278]116      xml::THashAttributes attributes = node.getAttributes();
[219]117
[278]118      if (attributes.end() != attributes.find("src"))
119      {
120         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
[462]121         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
122            ERROR("void CContext::parse(xml::CXMLNode & node)",
123                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
[278]124         if (!ifs.good())
125            ERROR("CContext::parse(xml::CXMLNode & node)",
126                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
[462]127         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
[278]128      }
129
[219]130      if (node.getElementName().compare(CContext::GetName()))
[421]131         DEBUG("Le noeud is wrong defined but will be considered as a context !");
[219]132
133      if (!(node.goToChildElement()))
134      {
135         DEBUG("Le context ne contient pas d'enfant !");
136      }
137      else
138      {
139         do { // Parcours des contextes pour traitement.
140
141            StdString name = node.getElementName();
142            attributes.clear();
143            attributes = node.getAttributes();
144
145            if (attributes.end() != attributes.find("id"))
[509]146            {
147              DEBUG(<< "Definition node has an id,"
148                    << "it will not be taking account !");
149            }
[219]150
151#define DECLARE_NODE(Name_, name_)    \
152   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
[549]153   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
[219]154#define DECLARE_NODE_PAR(Name_, name_)
155#include "node_type.conf"
[286]156
[421]157            DEBUG(<< "The element \'"     << name
158                  << "\' in the context \'" << CContext::getCurrent()->getId()
159                  << "\' is not a definition !");
[219]160
161         } while (node.goToNextElement());
162
163         node.goToParentElement(); // Retour au parent
164      }
165   }
[1622]166   CATCH_DUMP_ATTR
[219]167
168   //----------------------------------------------------------------
[509]169   //! Show tree structure of context
[219]170   void CContext::ShowTree(StdOStream & out)
[1622]171   TRY
[219]172   {
[549]173      StdString currentContextId = CContext::getCurrent() -> getId();
[347]174      std::vector<CContext*> def_vector =
[346]175         CContext::getRoot()->getChildList();
[347]176      std::vector<CContext*>::iterator
[219]177         it = def_vector.begin(), end = def_vector.end();
178
179      out << "<? xml version=\"1.0\" ?>" << std::endl;
180      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
[509]181
[219]182      for (; it != end; it++)
183      {
[509]184         CContext* context = *it;
185         CContext::setCurrent(context->getId());
[219]186         out << *context << std::endl;
187      }
[509]188
[219]189      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
[509]190      CContext::setCurrent(currentContextId);
[219]191   }
[1622]192   CATCH
[346]193
[219]194   //----------------------------------------------------------------
195
[509]196   //! Convert context object into string (to print)
[219]197   StdString CContext::toString(void) const
[1622]198   TRY
[219]199   {
200      StdOStringStream oss;
201      oss << "<" << CContext::GetName()
202          << " id=\"" << this->getId() << "\" "
203          << SuperClassAttribute::toString() << ">" << std::endl;
204      if (!this->hasChild())
205      {
206         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
207      }
208      else
209      {
210
211#define DECLARE_NODE(Name_, name_)    \
[346]212   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
213   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
[219]214#define DECLARE_NODE_PAR(Name_, name_)
215#include "node_type.conf"
216
217      }
218      oss << "</" << CContext::GetName() << " >";
219      return (oss.str());
220   }
[1622]221   CATCH
[219]222
223   //----------------------------------------------------------------
224
[509]225   /*!
226   \brief Find all inheritace among objects in a context.
227   \param [in] apply (true) write attributes of parent into ones of child if they are empty
228                     (false) write attributes of parent into a new container of child
229   \param [in] parent unused
230   */
[445]231   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
[1622]232   TRY
[219]233   {
234#define DECLARE_NODE(Name_, name_)    \
[354]235   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
[445]236     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
[219]237#define DECLARE_NODE_PAR(Name_, name_)
238#include "node_type.conf"
239   }
[1622]240   CATCH_DUMP_ATTR
[219]241
242   //----------------------------------------------------------------
243
[509]244   //! Verify if all root definition in the context have child.
[219]245   bool CContext::hasChild(void) const
[1622]246   TRY
[219]247   {
248      return (
249#define DECLARE_NODE(Name_, name_)    \
[346]250   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
[219]251#define DECLARE_NODE_PAR(Name_, name_)
252#include "node_type.conf"
253      false);
254}
[1622]255   CATCH
[219]256
257   //----------------------------------------------------------------
258
259   void CContext::CleanTree(void)
[1622]260   TRY
[219]261   {
[549]262#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
[219]263#define DECLARE_NODE_PAR(Name_, name_)
264#include "node_type.conf"
265   }
[1622]266   CATCH
267
[219]268   ///---------------------------------------------------------------
[509]269
[1761]270
[1765]271    /*!
[1330]272    Sets client buffers.
273    \param [in] contextClient
274    \param [in] bufferForWriting True if buffers are used for sending data for writing
275    This flag is only true for client and server-1 for communication with server-2
276  */
277   void CContext::setClientServerBuffer(CContextClient* contextClient, bool bufferForWriting)
[1622]278   TRY
[509]279   {
[1201]280      // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
[1372]281     const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
[1201]282
283      // Ensure there is at least some room for 20 of such events in the buffers
284      size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
285
[583]286#define DECLARE_NODE(Name_, name_)    \
[731]287     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
[583]288#define DECLARE_NODE_PAR(Name_, name_)
289#include "node_type.conf"
[719]290#undef DECLARE_NODE
291#undef DECLARE_NODE_PAR
292
[1201]293     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
[917]294     std::map<int, StdSize> maxEventSize;
[1330]295     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize, contextClient, bufferForWriting);
296     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize, contextClient, bufferForWriting);
[729]297
[909]298     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
[731]299     for (it = dataBufferSize.begin(); it != ite; ++it)
300       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
301
[1227]302     // Apply the buffer size factor, check that we are above the minimum buffer size and below the maximum size
[909]303     ite = bufferSize.end();
304     for (it = bufferSize.begin(); it != ite; ++it)
305     {
306       it->second *= CXios::bufferSizeFactor;
307       if (it->second < minBufferSize) it->second = minBufferSize;
[1227]308       if (it->second > CXios::maxBufferSize) it->second = CXios::maxBufferSize;
[909]309     }
310
[1201]311     // Leaders will have to send some control events so ensure there is some room for those in the buffers
[1184]312     if (contextClient->isServerLeader())
[598]313     {
[1184]314       const std::list<int>& ranks = contextClient->getRanksServerLeader();
[729]315       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[1201]316       {
317         if (!bufferSize.count(*itRank))
318         {
319           bufferSize[*itRank] = minBufferSize;
320           maxEventSize[*itRank] = minEventSize;
321         }
322       }
[598]323     }
[1184]324     contextClient->setBufferSize(bufferSize, maxEventSize);
[509]325   }
[1622]326   CATCH_DUMP_ATTR
[509]327
328   //! Verify whether a context is initialized
[461]329   bool CContext::isInitialized(void)
[1622]330   TRY
[461]331   {
[549]332     return hasClient;
[461]333   }
[1622]334   CATCH_DUMP_ATTR
[509]335
[1761]336
337   void CContext::init(CServerContext* parentServerContext, MPI_Comm intraComm, int serviceType)
338   TRY
339   {
340     parentServerContext_ = parentServerContext ;
341     if (serviceType==CServicesManager::CLIENT) 
342       initClient(intraComm, serviceType) ;
343     else
344       initServer(intraComm, serviceType) ;
345    }
346    CATCH_DUMP_ATTR
347
348
349
350//! Initialize client side
351   void CContext::initClient(MPI_Comm intraComm, int serviceType)
352   TRY
353   {
354      intraComm_=intraComm ;
355      serviceType_ = CServicesManager::CLIENT ;
356      if (serviceType_==CServicesManager::CLIENT)
357      {
358        hasClient=true ;
359        hasServer=false ;
360      }
361      contextId_ = getId() ;
362     
363      attached_mode=true ;
364      if (!CXios::isUsingServer()) attached_mode=false ;
365
366
367      string contextRegistryId=getId() ;
368      registryIn=new CRegistry(intraComm);
369      registryIn->setPath(contextRegistryId) ;
370     
371      int commRank ;
372      MPI_Comm_rank(intraComm_,&commRank) ;
373      if (commRank==0) registryIn->fromFile("xios_registry.bin") ;
374      registryIn->bcastRegistry() ;
375      registryOut=new CRegistry(intraComm_) ;
376      registryOut->setPath(contextRegistryId) ;
377     
378   }
379   CATCH_DUMP_ATTR
380
381   
382   void CContext::initServer(MPI_Comm intraComm, int serviceType)
383   TRY
384   {
385     hasServer=true;
386     intraComm_=intraComm ;
387     serviceType_=serviceType ;
388
389     if (serviceType_==CServicesManager::GATHERER)
390     {
391       hasClient=true ;
392       hasServer=true ;
393     }
394     else if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER)
395     {
396       hasClient=false ;
397       hasServer=true ;
398     }
399
400     CXios::getContextsManager()->getContextId(getId(), contextId_, intraComm) ;
401     
402     registryIn=new CRegistry(intraComm);
403     registryIn->setPath(contextId_) ;
404     
405     int commRank ;
406     MPI_Comm_rank(intraComm_,&commRank) ;
407     if (commRank==0) registryIn->fromFile("xios_registry.bin") ;
408   
409     registryIn->bcastRegistry() ;
410     registryOut=new CRegistry(intraComm) ;
411     registryOut->setPath(contextId_) ;
412
413   }
414   CATCH_DUMP_ATTR
415
416
417  void CContext::createClientInterComm(MPI_Comm interCommClient, MPI_Comm interCommServer) // for servers
418  TRY
419  {
420    MPI_Comm intraCommClient ;
421    MPI_Comm_dup(intraComm_, &intraCommClient);
422    comms.push_back(intraCommClient);
[1764]423    // attached_mode=parentServerContext_->isAttachedMode() ; //ym probably inherited from source context
[1761]424    server = new CContextServer(this,intraComm_, interCommServer); // check if we need to dupl. intraComm_ ?
425    client = new CContextClient(this,intraCommClient,interCommClient);
426
427  }
428  CATCH_DUMP_ATTR
429
430  void CContext::createServerInterComm(void) 
431  TRY
432  {
433   
434    MPI_Comm interCommClient, interCommServer ;
435
436    if (serviceType_ == CServicesManager::CLIENT)
437    {
438
439      int commRank ;
440      MPI_Comm_rank(intraComm_,&commRank) ;
441      if (commRank==0)
442      {
443        if (attached_mode) CXios::getContextsManager()->createServerContext(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, getContextId()) ;
444        else if (CXios::usingServer2) CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId()) ;
445        else  CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId()) ;
446      }
447
448      MPI_Comm interComm ;
449     
450      if (attached_mode)
451      {
452        parentServerContext_->createIntercomm(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, getContextId(), intraComm_, 
453                                              interCommClient, interCommServer) ;
454        int type ; 
455        if (commRank==0) CXios::getServicesManager()->getServiceType(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, type) ;
456        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
457        setIdServer(CXios::getContextsManager()->getServerContextName(CClient::getPoolRessource()->getId(), CXios::defaultServerId, 0, type, getContextId())) ;
458        setCurrent(getId()) ; // getCurrent/setCurrent may be supress, it can cause a lot of trouble
459      }
460      else if (CXios::usingServer2)
461      { 
462//      CXios::getContextsManager()->createServerContextIntercomm(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId(), intraComm_, interComm) ;
463        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultGathererId, 0, getContextId(), intraComm_,
464                                              interCommClient, interCommServer) ;
465        int type ; 
466        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultGathererId, 0, type) ;
467        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
468        setIdServer(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultGathererId, 0, type, getContextId())) ;
469      }
470      else
471      {
472        //CXios::getContextsManager()->createServerContextIntercomm(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId(), intraComm_, interComm) ;
473        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultServerId, 0, getContextId(), intraComm_,
474                                              interCommClient, interCommServer) ;
475        int type ; 
476        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultServerId, 0, type) ;
477        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
478        setIdServer(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultServerId, 0, type, getContextId())) ;
479      }
480
481        // intraComm client is not duplicated. In all the code we use client->intraComm for MPI
482        // in future better to replace it by intracommuncator associated to the context
[1765]483   
[1761]484      MPI_Comm intraCommClient, intraCommServer ;
485      intraCommClient=intraComm_ ;
486      MPI_Comm_dup(intraComm_, &intraCommServer) ;
487      client = new CContextClient(this, intraCommClient, interCommClient);
488      server = new CContextServer(this, intraCommServer, interCommServer);
489   
490    }
491   
492    if (serviceType_ == CServicesManager::GATHERER)
493    {
494      int commRank ;
495      MPI_Comm_rank(intraComm_,&commRank) ;
496     
497      int nbPartitions ;
498      if (commRank==0) 
499      { 
500        CXios::getServicesManager()->getServiceNbPartitions(CXios::defaultPoolId, CXios::defaultServerId, 0, nbPartitions) ;
501        for(int i=0 ; i<nbPartitions; i++)
502          CXios::getContextsManager()->createServerContext(CXios::defaultPoolId, CXios::defaultServerId, i, getContextId()) ;
503      }     
504      MPI_Bcast(&nbPartitions, 1, MPI_INT, 0, intraComm_) ;
505     
506      MPI_Comm interComm ;
507      for(int i=0 ; i<nbPartitions; i++)
508      {
509        parentServerContext_->createIntercomm(CXios::defaultPoolId, CXios::defaultServerId, i, getContextId(), intraComm_, interCommClient, interCommServer) ;
510        int type ; 
511        if (commRank==0) CXios::getServicesManager()->getServiceType(CXios::defaultPoolId, CXios::defaultServerId, 0, type) ;
512        MPI_Bcast(&type,1,MPI_INT,0,intraComm_) ;
513        primServerId_.push_back(CXios::getContextsManager()->getServerContextName(CXios::defaultPoolId, CXios::defaultServerId, i, type, getContextId())) ;
514
515        // intraComm client is not duplicated. In all the code we use client->intraComm for MPI
516        // in future better to replace it by intracommuncator associated to the context
517     
518        MPI_Comm intraCommClient, intraCommServer ;
519
520        intraCommClient=intraComm_ ;
521        MPI_Comm_dup(intraComm_, &intraCommServer) ;
522
523
524        clientPrimServer.push_back(new CContextClient(this, intraCommClient, interCommClient));
525        serverPrimServer.push_back(new CContextServer(this, intraCommServer, interCommServer)); 
526     
527      }
528    }
529  }
530  CATCH_DUMP_ATTR
531
532 
[1639]533   void CContext::initServer(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtClient /*= 0*/)
[1622]534   TRY
[300]535   {
[549]536     hasServer=true;
537     server = new CContextServer(this,intraComm,interComm);
[697]538
[1316]539/* for registry take the id of client context */
540/* for servers, supress the _server_ from id  */
541     string contextRegistryId=getId() ;
542     size_t pos=contextRegistryId.find("_server_") ;
543     if (pos!=std::string::npos)  contextRegistryId=contextRegistryId.substr(0,pos) ;
544       
[1071]545     registryIn=new CRegistry(intraComm);
[1316]546     registryIn->setPath(contextRegistryId) ;
[1071]547     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
548     registryIn->bcastRegistry() ;
549     registryOut=new CRegistry(intraComm) ;
[1316]550     registryOut->setPath(contextRegistryId) ;
[775]551
[1639]552     MPI_Comm intraCommClient, interCommClient;
[597]553     if (cxtClient) // Attached mode
554     {
555       intraCommClient = intraComm;
556       interCommClient = interComm;
557     }
558     else
559     {
[1639]560       MPI_Comm_dup(intraComm, &intraCommClient);
[1071]561       comms.push_back(intraCommClient);
[1639]562       MPI_Comm_dup(interComm, &interCommClient);
[1071]563       comms.push_back(interCommClient);
[597]564     }
[1158]565     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
[509]566   }
[1622]567   CATCH_DUMP_ATTR
[300]568
[1761]569 
570
571  bool CContext::eventLoop(bool enableEventsProcessing)
572  {
573    bool finished=true; 
574
575    if (client!=nullptr && !finalized) client->checkBuffers();
576   
577    for (int i = 0; i < clientPrimServer.size(); ++i)
578    {
579      if (!finalized) clientPrimServer[i]->checkBuffers();
580      if (!finalized) finished &= serverPrimServer[i]->eventLoop(enableEventsProcessing);
581    }
582
583    if (server!=nullptr) if (!finalized) finished &= server->eventLoop(enableEventsProcessing);
584 
585    return finalized && finished ;
586  }
587
[1765]588 
[1764]589 
590  void CContext::globalEventLoop(void)
591  {
592    CXios::getDaemonsManager()->eventLoop() ;
593    setCurrent(getId()) ;
594  }
[1761]595
596
597   void CContext::finalize(void)
598   TRY
599   {
[1764]600      registryOut->hierarchicalGatherRegistry() ;
601      if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
602
603      if (hasClient && !hasServer)
[1761]604      {
[1764]605        doPreTimestepOperationsForEnabledReadModeFiles(); // For now we only use server level 1 to read data
[1761]606
[1764]607        info(100)<<"DEBUG: context "<<getId()<<" Send client finalize"<<endl ;
608        client->finalize();
609        info(100)<<"DEBUG: context "<<getId()<<" Client finalize sent"<<endl ;
610        while (client->havePendingRequests()) client->checkBuffers();
611        info(100)<<"DEBUG: context "<<getId()<<" no pending request ok"<<endl ;
[1761]612        bool notifiedFinalized=false ;
613        do
614        {
615          notifiedFinalized=client->isNotifiedFinalized() ;
616        } while (!notifiedFinalized) ;
617        client->releaseBuffers();
618        info(100)<<"DEBUG: context "<<getId()<<" release client ok"<<endl ;
[1764]619      }
620      else if (hasClient && hasServer)
621      {
[1761]622         for (int i = 0; i < clientPrimServer.size(); ++i)
623         {
624           clientPrimServer[i]->finalize();
625           bool bufferReleased;
626           do
627           {
628             clientPrimServer[i]->checkBuffers();
629             bufferReleased = !clientPrimServer[i]->havePendingRequests();
630           } while (!bufferReleased);
631           
632           bool notifiedFinalized=false ;
633           do
634           {
635             notifiedFinalized=clientPrimServer[i]->isNotifiedFinalized() ;
636           } while (!notifiedFinalized) ;
637           clientPrimServer[i]->releaseBuffers();
638         }
[1764]639         closeAllFile();
[1761]640
[1764]641      }
642      else if (!hasClient && hasServer)
643      {
644        closeAllFile();
645      }
646
647      freeComms() ;
[1761]648       
[1764]649      parentServerContext_->freeComm() ;
650      finalized = true;
651      info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
[1761]652   }
[1622]653   CATCH_DUMP_ATTR
[1054]654
[1071]655   //! Free internally allocated communicators
656   void CContext::freeComms(void)
[1622]657   TRY
[1071]658   {
[1639]659     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
660       MPI_Comm_free(&(*it));
[1071]661     comms.clear();
662   }
[1622]663   CATCH_DUMP_ATTR
[509]664
[1130]665   //! Deallocate buffers allocated by clientContexts
666   void CContext::releaseClientBuffers(void)
[1622]667   TRY
[1130]668   {
669     client->releaseBuffers();
670     for (int i = 0; i < clientPrimServer.size(); ++i)
671       clientPrimServer[i]->releaseBuffers();
672   }
[1622]673   CATCH_DUMP_ATTR
[1130]674
[1025]675   void CContext::postProcessingGlobalAttributes()
[1622]676   TRY
[300]677   {
[1144]678     if (allProcessed) return; 
[1025]679     
[1761]680    // create intercommunicator with servers.
681    // not sure it is the good place to be called here
682    createServerInterComm() ;
683
684
[1144]685     // After xml is parsed, there are some more works with post processing
686     postProcessing();
[983]687
[1144]688     // Check grid and calculate its distribution
[1232]689     checkGridEnabledFields();
690 
[1208]691     // Distribute files between secondary servers according to the data size
692     distributeFiles();
693
[1330]694     setClientServerBuffer(client, (hasClient && !hasServer));
[1255]695     for (int i = 0; i < clientPrimServer.size(); ++i)
[1330]696         setClientServerBuffer(clientPrimServer[i], true);
[300]697
[983]698     if (hasClient)
[510]699     {
[509]700      // Send all attributes of current context to server
701      this->sendAllAttributesToServer();
[459]702
[549]703      // Send all attributes of current calendar
704      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
705
[509]706      // We have enough information to send to server
[1021]707      // First of all, send all enabled files
[1232]708      sendEnabledFiles(this->enabledWriteModeFiles);
709      // We only use server-level 1 (for now) to read data
710      if (!hasServer)
711        sendEnabledFiles(this->enabledReadModeFiles);
[509]712
[1232]713      // Then, send all enabled fields     
714      sendEnabledFieldsInFiles(this->enabledWriteModeFiles);
715      if (!hasServer)
716        sendEnabledFieldsInFiles(this->enabledReadModeFiles);
[1021]717
[1239]718      // Then, check whether we have domain_ref, axis_ref or scalar_ref attached to the enabled fields
719      // If any, so send them to server
[1232]720       sendRefDomainsAxisScalars(this->enabledWriteModeFiles);
721      if (!hasServer)
722        sendRefDomainsAxisScalars(this->enabledReadModeFiles);       
[1021]723
[1239]724       // Check whether enabled fields have grid_ref, if any, send this info to server
[1237]725      sendRefGrid(this->enabledFiles);
726      // This code may be useful in the future when we want to seperate completely read and write
727      // sendRefGrid(this->enabledWriteModeFiles);
728      // if (!hasServer)
729      //   sendRefGrid(this->enabledReadModeFiles);
[1239]730     
731      // A grid of enabled fields composed of several components which must be checked then their
732      // checked attributes should be sent to server
733      sendGridComponentEnabledFieldsInFiles(this->enabledFiles); // This code can be seperated in two (one for reading, another for writing)
[1021]734
[983]735       // We have a xml tree on the server side and now, it should be also processed
[1239]736      sendPostProcessing();
[1232]737       
[1239]738      // Finally, we send information of grid itself to server
739      sendGridEnabledFieldsInFiles(this->enabledWriteModeFiles);       
740      if (!hasServer)
[1232]741        sendGridEnabledFieldsInFiles(this->enabledReadModeFiles);       
[983]742     }
[1025]743     allProcessed = true;
744   }
[1622]745   CATCH_DUMP_ATTR
[983]746
[1025]747   void CContext::sendPostProcessingGlobalAttributes()
[1622]748   TRY
[1025]749   {
[1027]750      // Use correct context client to send message
[1030]751     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
752    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]753     for (int i = 0; i < nbSrvPools; ++i)
754     {
755       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
756       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
[987]757
[1027]758       if (contextClientTmp->isServerLeader())
759       {
760         CMessage msg;
[1099]761         if (hasServer)
762           msg<<this->getIdServer(i);
763         else
764           msg<<this->getIdServer();
[1027]765         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
766         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
767           event.push(*itRank,1,msg);
768         contextClientTmp->sendEvent(event);
769       }
770       else contextClientTmp->sendEvent(event);
[1025]771     }
772   }
[1622]773   CATCH_DUMP_ATTR
[1025]774
775   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
[1622]776   TRY
[1025]777   {
778      CBufferIn* buffer=event.subEvents.begin()->buffer;
779      string id;
780      *buffer>>id;
[1099]781      get(id)->recvPostProcessingGlobalAttributes(*buffer);
[1025]782   }
[1622]783   CATCH
[1025]784
785   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
[1622]786   TRY
[1144]787   {     
[1025]788      postProcessingGlobalAttributes();
789   }
[1622]790   CATCH_DUMP_ATTR
[1025]791
792   /*!
793   \brief Close all the context defintion and do processing data
794      After everything is well defined on client side, they will be processed and sent to server
795   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
796   all necessary information to server, from which each server can build its own database.
797   Because the role of server is to write out field data on a specific netcdf file,
798   the only information that it needs is the enabled files
799   and the active fields (fields will be written onto active files)
800   */
[1622]801
[1025]802   void CContext::closeDefinition(void)
[1622]803   TRY
[1025]804   {
[1761]805     CTimer::get("Context : close definition").resume() ;
806   
807    //
[1025]808    postProcessingGlobalAttributes();
[983]809
[1130]810    if (hasClient) sendPostProcessingGlobalAttributes();
811
812    // There are some processings that should be done after all of above. For example: check mask or index
[1025]813    this->buildFilterGraphOfEnabledFields();
814   
[1130]815     if (hasClient && !hasServer)
[509]816    {
[1130]817      buildFilterGraphOfFieldsWithReadAccess();
[1358]818      postProcessFilterGraph();
[509]819    }
[1144]820   
[1232]821    checkGridEnabledFields();   
[509]822
[1025]823    if (hasClient) this->sendProcessingGridOfEnabledFields();
[1077]824    if (hasClient) this->sendCloseDefinition();
[510]825
[584]826    // Nettoyage de l'arborescence
[983]827    if (hasClient) CleanTree(); // Only on client side??
[510]828
[598]829    if (hasClient)
830    {
831      sendCreateFileHeader();
[983]832      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
[598]833    }
[1158]834    CTimer::get("Context : close definition").suspend() ;
[300]835   }
[1622]836   CATCH_DUMP_ATTR
[509]837
[1232]838   void CContext::findAllEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]839   TRY
[300]840   {
[1232]841     for (unsigned int i = 0; i < activeFiles.size(); i++)
842     (void)activeFiles[i]->getEnabledFields();
[300]843   }
[1622]844   CATCH_DUMP_ATTR
[300]845
[775]846   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
[1622]847   TRY
[775]848   {
849      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
850        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
851   }
[1622]852   CATCH_DUMP_ATTR
[775]853
[1239]854   void CContext::sendGridComponentEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]855   TRY
[1239]856   {
857     int size = activeFiles.size();
858     for (int i = 0; i < size; ++i)
859     {       
860       activeFiles[i]->sendGridComponentOfEnabledFields();
861     }
862   }
[1622]863   CATCH_DUMP_ATTR
[1239]864
[1232]865   /*!
866      Send active (enabled) fields in file from a client to others
867      \param [in] activeFiles files contains enabled fields to send
868   */
869   void CContext::sendGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]870   TRY
[1025]871   {
[1232]872     int size = activeFiles.size();
[1025]873     for (int i = 0; i < size; ++i)
[1099]874     {       
[1232]875       activeFiles[i]->sendGridOfEnabledFields();
[1025]876     }
877   }
[1622]878   CATCH_DUMP_ATTR
[1025]879
[1099]880   void CContext::checkGridEnabledFields()
[1622]881   TRY
[1099]882   {
[1232]883     int size = enabledFiles.size();
[1099]884     for (int i = 0; i < size; ++i)
885     {
[1232]886       enabledFiles[i]->checkGridOfEnabledFields();       
[1099]887     }
888   }
[1622]889   CATCH_DUMP_ATTR
[1025]890
[1232]891   /*!
892      Check grid of active (enabled) fields in file
893      \param [in] activeFiles files contains enabled fields whose grid needs checking
894   */
895   void CContext::checkGridEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]896   TRY
[1232]897   {
898     int size = activeFiles.size();
899     for (int i = 0; i < size; ++i)
900     {
901       activeFiles[i]->checkGridOfEnabledFields();       
902     }
903   }
[1622]904   CATCH_DUMP_ATTR
[1232]905
906    /*!
907      Go up the hierachical tree via field_ref and do check of attributes of fields
908      This can be done in a client then all computed information will be sent from this client to others
909      \param [in] sendToServer Flag to indicate whether calculated information will be sent
910   */
[823]911   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
[1622]912   TRY
[823]913   {
914     int size = this->enabledFiles.size();
915     for (int i = 0; i < size; ++i)
916     {
917       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
918     }
919
920     for (int i = 0; i < size; ++i)
921     {
922       this->enabledFiles[i]->generateNewTransformationGridDest();
923     }
924   }
[1622]925   CATCH_DUMP_ATTR
[823]926
[1232]927    /*!
928      Go up the hierachical tree via field_ref and do check of attributes of fields.
929      The transformation can be done in this step.
930      All computed information will be sent from this client to others.
931      \param [in] sendToServer Flag to indicate whether calculated information will be sent
932   */
[1129]933   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
[1622]934   TRY
[300]935   {
[509]936     int size = this->enabledFiles.size();
937     for (int i = 0; i < size; ++i)
938     {
[1129]939       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
[509]940     }
[300]941   }
[1622]942   CATCH_DUMP_ATTR
[300]943
[640]944   void CContext::buildFilterGraphOfEnabledFields()
[1622]945   TRY
[640]946   {
947     int size = this->enabledFiles.size();
948     for (int i = 0; i < size; ++i)
949     {
950       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
951     }
952   }
[1622]953   CATCH_DUMP_ATTR
[640]954
[1358]955   void CContext::postProcessFilterGraph()
[1622]956   TRY
[1358]957   {
958     int size = enabledFiles.size();
959     for (int i = 0; i < size; ++i)
960     {
961        enabledFiles[i]->postProcessFilterGraph();
962     }
963   }
[1622]964   CATCH_DUMP_ATTR
[1358]965
[598]966   void CContext::startPrefetchingOfEnabledReadModeFiles()
[1622]967   TRY
[598]968   {
969     int size = enabledReadModeFiles.size();
970     for (int i = 0; i < size; ++i)
971     {
972        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
973     }
974   }
[1622]975   CATCH_DUMP_ATTR
[598]976
[1358]977   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
[1622]978   TRY
[1358]979   {
980     int size = enabledReadModeFiles.size();
981     for (int i = 0; i < size; ++i)
982     {
983        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
984     }
985   }
[1622]986   CATCH_DUMP_ATTR
[1358]987
[1318]988   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
[1622]989   TRY
[598]990   {
991     int size = enabledReadModeFiles.size();
992     for (int i = 0; i < size; ++i)
993     {
[1318]994        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
[598]995     }
996   }
[1622]997   CATCH_DUMP_ATTR
[598]998
[593]999  void CContext::findFieldsWithReadAccess(void)
[1622]1000  TRY
[593]1001  {
1002    fieldsWithReadAccess.clear();
1003    const vector<CField*> allFields = CField::getAll();
1004    for (size_t i = 0; i < allFields.size(); ++i)
1005    {
[740]1006      CField* field = allFields[i];
1007
1008      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
1009        field->read_access = true;
1010      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
1011        fieldsWithReadAccess.push_back(field);
[593]1012    }
1013  }
[1622]1014  CATCH_DUMP_ATTR
[593]1015
1016  void CContext::solveAllRefOfFieldsWithReadAccess()
[1622]1017  TRY
[593]1018  {
1019    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
1020      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
1021  }
[1622]1022  CATCH_DUMP_ATTR
[593]1023
[640]1024  void CContext::buildFilterGraphOfFieldsWithReadAccess()
[1622]1025  TRY
[640]1026  {
1027    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
1028      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
1029  }
[1622]1030  CATCH_DUMP_ATTR
[640]1031
[445]1032   void CContext::solveAllInheritance(bool apply)
[1622]1033   TRY
[300]1034   {
1035     // Résolution des héritages descendants (càd des héritages de groupes)
1036     // pour chacun des contextes.
[445]1037      solveDescInheritance(apply);
[300]1038
1039     // Résolution des héritages par référence au niveau des fichiers.
[549]1040      const vector<CFile*> allFiles=CFile::getAll();
[540]1041      const vector<CGrid*> allGrids= CGrid::getAll();
[300]1042
[983]1043      if (hasClient && !hasServer)
1044      //if (hasClient)
[540]1045      {
[510]1046        for (unsigned int i = 0; i < allFiles.size(); i++)
1047          allFiles[i]->solveFieldRefInheritance(apply);
[540]1048      }
1049
1050      unsigned int vecSize = allGrids.size();
1051      unsigned int i = 0;
1052      for (i = 0; i < vecSize; ++i)
1053        allGrids[i]->solveDomainAxisRefInheritance(apply);
1054
[300]1055   }
[1622]1056  CATCH_DUMP_ATTR
[300]1057
1058   void CContext::findEnabledFiles(void)
[1622]1059   TRY
[300]1060   {
[347]1061      const std::vector<CFile*> allFiles = CFile::getAll();
[1158]1062      const CDate& initDate = calendar->getInitDate();
[300]1063
1064      for (unsigned int i = 0; i < allFiles.size(); i++)
1065         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
[430]1066         {
[300]1067            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
[1158]1068            {
[1489]1069              if (allFiles[i]->output_freq.isEmpty())
[1488]1070              {
1071                 ERROR("CContext::findEnabledFiles()",
1072                     << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1073                     <<" \".")
1074              }
[1158]1075              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1076              {
1077                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1078                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1079                    <<"\" is less than the time step. File will not be written."<<endl;
1080              }
1081              else
[300]1082               enabledFiles.push_back(allFiles[i]);
[1158]1083            }
[430]1084         }
[1158]1085         else
1086         {
[1489]1087           if (allFiles[i]->output_freq.isEmpty())
[1488]1088           {
1089              ERROR("CContext::findEnabledFiles()",
1090                  << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1091                  <<" \".")
1092           }
[1158]1093           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1094           {
1095             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1096                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1097                 <<"\" is less than the time step. File will not be written."<<endl;
1098           }
1099           else
1100             enabledFiles.push_back(allFiles[i]); // otherwise true by default
1101         }
[300]1102
1103      if (enabledFiles.size() == 0)
1104         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
1105               << getId() << "\" !");
[1021]1106
[300]1107   }
[1622]1108   CATCH_DUMP_ATTR
[300]1109
[1208]1110   void CContext::distributeFiles(void)
[1622]1111   TRY
[1208]1112   {
[1349]1113     bool distFileMemory=false ;
1114     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
1115
1116     if (distFileMemory) distributeFileOverMemoryBandwith() ;
1117     else distributeFileOverBandwith() ;
1118   }
[1622]1119   CATCH_DUMP_ATTR
[1349]1120
1121   void CContext::distributeFileOverBandwith(void)
[1622]1122   TRY
[1349]1123   {
[1215]1124     double eps=std::numeric_limits<double>::epsilon()*10 ;
1125     
[1208]1126     // If primary server
1127     if (hasServer && hasClient)
1128     {
[1349]1129       std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
[1212]1130       int nbPools = clientPrimServer.size();
1131
[1208]1132       // (1) Find all enabled files in write mode
[1232]1133       // for (int i = 0; i < this->enabledFiles.size(); ++i)
1134       // {
1135       //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1136       //    enabledWriteModeFiles.push_back(enabledFiles[i]);
1137       // }
[1208]1138
1139       // (2) Estimate the data volume for each file
1140       int size = this->enabledWriteModeFiles.size();
[1215]1141       std::vector<std::pair<double, CFile*> > dataSizeMap;
1142       double dataPerPool = 0;
1143       int nfield=0 ;
[1349]1144       ofs<<size<<endl ;
[1208]1145       for (size_t i = 0; i < size; ++i)
1146       {
1147         CFile* file = this->enabledWriteModeFiles[i];
[1349]1148         ofs<<file->getId()<<endl ;
[1215]1149         StdSize dataSize=0;
[1208]1150         std::vector<CField*> enabledFields = file->getEnabledFields();
1151         size_t numEnabledFields = enabledFields.size();
[1349]1152         ofs<<numEnabledFields<<endl ;
1153         for (size_t j = 0; j < numEnabledFields; ++j)
1154         {
1155           dataSize += enabledFields[j]->getGlobalWrittenSize() ;
1156           ofs<<enabledFields[j]->grid->getId()<<endl ;
1157           ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
1158         }
[1215]1159         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1160         double dataSizeSec= dataSize/ outFreqSec;
[1349]1161         ofs<<dataSizeSec<<endl ;
[1215]1162         nfield++ ;
1163// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
1164         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
1165         dataPerPool += dataSizeSec;
[1208]1166       }
[1212]1167       dataPerPool /= nbPools;
[1208]1168       std::sort(dataSizeMap.begin(), dataSizeMap.end());
1169
[1212]1170       // (3) Assign contextClient to each enabled file
[1215]1171
1172       std::multimap<double,int> poolDataSize ;
1173// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
1174
1175       int j;
1176       double dataSize ;
1177       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
1178             
[1212]1179       for (int i = dataSizeMap.size()-1; i >= 0; --i)
[1208]1180       {
[1215]1181         dataSize=(*poolDataSize.begin()).first ;
1182         j=(*poolDataSize.begin()).second ;
1183         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
1184         dataSize+=dataSizeMap[i].first;
1185         poolDataSize.erase(poolDataSize.begin()) ;
1186         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
[1208]1187       }
[1212]1188
[1215]1189       for (std::multimap<double,int>:: iterator it=poolDataSize.begin() ; it!=poolDataSize.end(); ++it) info(30)<<"Load Balancing for servers (perfect=1) : "<<it->second<<" :  ratio "<<it->first*1./dataPerPool<<endl ;
1190 
[1212]1191       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
[1232]1192       {
1193         enabledReadModeFiles[i]->setContextClient(client);         
1194       }
[1208]1195     }
1196     else
1197     {
1198       for (int i = 0; i < this->enabledFiles.size(); ++i)
1199         enabledFiles[i]->setContextClient(client);
1200     }
1201   }
[1622]1202   CATCH_DUMP_ATTR
[1208]1203
[1349]1204   void CContext::distributeFileOverMemoryBandwith(void)
[1622]1205   TRY
[1349]1206   {
1207     // If primary server
1208     if (hasServer && hasClient)
1209     {
1210       int nbPools = clientPrimServer.size();
1211       double ratio=0.5 ;
1212       ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1213
1214       int nFiles = this->enabledWriteModeFiles.size();
1215       vector<SDistFile> files(nFiles);
1216       vector<SDistGrid> grids;
1217       map<string,int> gridMap ;
1218       string gridId; 
1219       int gridIndex=0 ;
1220
1221       for (size_t i = 0; i < nFiles; ++i)
1222       {
1223         StdSize dataSize=0;
1224         CFile* file = this->enabledWriteModeFiles[i];
1225         std::vector<CField*> enabledFields = file->getEnabledFields();
1226         size_t numEnabledFields = enabledFields.size();
1227
1228         files[i].id_=file->getId() ;
1229         files[i].nbGrids_=numEnabledFields;
1230         files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1231         
1232         for (size_t j = 0; j < numEnabledFields; ++j)
1233         {
1234           gridId=enabledFields[j]->grid->getId() ;
1235           if (gridMap.find(gridId)==gridMap.end())
1236           {
1237              gridMap[gridId]=gridIndex  ;
1238              SDistGrid newGrid; 
1239              grids.push_back(newGrid) ;
1240              gridIndex++ ;
1241           }
1242           files[i].assignedGrid_[j]=gridMap[gridId] ;
1243           grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1244           dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1245         }
1246         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1247         files[i].bandwith_= dataSize/ outFreqSec ;
1248       }
1249
1250       double bandwith=0 ;
1251       double memory=0 ;
1252   
1253       for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1254       for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1255
1256       for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1257       for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1258       
1259       distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1260
1261       vector<double> memorySize(nbPools,0.) ;
1262       vector< set<int> > serverGrids(nbPools) ;
1263       vector<double> bandwithSize(nbPools,0.) ;
1264       
1265       for (size_t i = 0; i < nFiles; ++i)
1266       {
1267         bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1268         for(int j=0 ; j<files[i].nbGrids_;j++)
1269         {
1270           if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1271           {
1272             memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1273             serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1274           }
1275         }
1276         enabledWriteModeFiles[i]->setContextClient(clientPrimServer[files[i].assignedServer_]) ;
1277         delete [] files[i].assignedGrid_ ;
1278       }
1279
1280       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned file bandwith "<<bandwithSize[i]*86400.*4./1024/1024.<<" Mb / days"<<endl ;
1281       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1282
1283
1284       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1285       {
1286         enabledReadModeFiles[i]->setContextClient(client);         
1287       }
1288
1289   }
1290   else
1291   {
1292     for (int i = 0; i < this->enabledFiles.size(); ++i)
1293        enabledFiles[i]->setContextClient(client);
1294   }
1295}
[1622]1296   CATCH_DUMP_ATTR
[1349]1297
[1232]1298   /*!
1299      Find all files in write mode
1300   */
1301   void CContext::findEnabledWriteModeFiles(void)
[1622]1302   TRY
[1232]1303   {
1304     int size = this->enabledFiles.size();
1305     for (int i = 0; i < size; ++i)
1306     {
1307       if (enabledFiles[i]->mode.isEmpty() || 
1308          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1309        enabledWriteModeFiles.push_back(enabledFiles[i]);
1310     }
1311   }
[1622]1312   CATCH_DUMP_ATTR
[1232]1313
1314   /*!
1315      Find all files in read mode
1316   */
[598]1317   void CContext::findEnabledReadModeFiles(void)
[1622]1318   TRY
[598]1319   {
1320     int size = this->enabledFiles.size();
1321     for (int i = 0; i < size; ++i)
1322     {
1323       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1324        enabledReadModeFiles.push_back(enabledFiles[i]);
1325     }
1326   }
[1622]1327   CATCH_DUMP_ATTR
[598]1328
[300]1329   void CContext::closeAllFile(void)
[1622]1330   TRY
[300]1331   {
[347]1332     std::vector<CFile*>::const_iterator
[300]1333            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
[509]1334
[300]1335     for (; it != end; it++)
1336     {
1337       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1338       (*it)->close();
1339     }
1340   }
[1622]1341   CATCH_DUMP_ATTR
[509]1342
1343   /*!
1344   \brief Dispatch event received from client
1345      Whenever a message is received in buffer of server, it will be processed depending on
1346   its event type. A new event type should be added in the switch list to make sure
1347   it processed on server side.
1348   \param [in] event: Received message
1349   */
[300]1350   bool CContext::dispatchEvent(CEventServer& event)
[1622]1351   TRY
[300]1352   {
[509]1353
[549]1354      if (SuperClass::dispatchEvent(event)) return true;
[300]1355      else
1356      {
1357        switch(event.type)
1358        {
1359           case EVENT_ID_CLOSE_DEFINITION :
[549]1360             recvCloseDefinition(event);
1361             return true;
1362             break;
[584]1363           case EVENT_ID_UPDATE_CALENDAR:
[549]1364             recvUpdateCalendar(event);
1365             return true;
1366             break;
[300]1367           case EVENT_ID_CREATE_FILE_HEADER :
[549]1368             recvCreateFileHeader(event);
1369             return true;
1370             break;
[509]1371           case EVENT_ID_POST_PROCESS:
[549]1372             recvPostProcessing(event);
1373             return true;
[697]1374            case EVENT_ID_SEND_REGISTRY:
1375             recvRegistry(event);
1376             return true;
[1025]1377             break;
1378            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
1379             recvPostProcessingGlobalAttributes(event);
1380             return true;
1381             break;
1382            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
1383             recvProcessingGridOfEnabledFields(event);
1384             return true;
1385             break;
[300]1386           default :
1387             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
[549]1388                    <<"Unknown Event");
1389           return false;
[300]1390         }
1391      }
1392   }
[1622]1393   CATCH
[509]1394
1395   //! Client side: Send a message to server to make it close
[300]1396   void CContext::sendCloseDefinition(void)
[1622]1397   TRY
[300]1398   {
[987]1399     // Use correct context client to send message
[1030]1400     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1401     for (int i = 0; i < nbSrvPools; ++i)
[300]1402     {
[1009]1403       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1404       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1405       if (contextClientTmp->isServerLeader())
1406       {
1407         CMessage msg;
1408         if (hasServer)
1409           msg<<this->getIdServer(i);
1410         else
1411           msg<<this->getIdServer();
1412         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1413         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1414           event.push(*itRank,1,msg);
1415         contextClientTmp->sendEvent(event);
1416       }
1417       else contextClientTmp->sendEvent(event);
[300]1418     }
1419   }
[1622]1420   CATCH_DUMP_ATTR
[509]1421
1422   //! Server side: Receive a message of client announcing a context close
[300]1423   void CContext::recvCloseDefinition(CEventServer& event)
[1622]1424   TRY
[300]1425   {
1426      CBufferIn* buffer=event.subEvents.begin()->buffer;
1427      string id;
[549]1428      *buffer>>id;
[509]1429      get(id)->closeDefinition();
[300]1430   }
[1622]1431   CATCH
[509]1432
1433   //! Client side: Send a message to update calendar in each time step
[300]1434   void CContext::sendUpdateCalendar(int step)
[1622]1435   TRY
[300]1436   {
[987]1437     // Use correct context client to send message
[1030]1438    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1439     for (int i = 0; i < nbSrvPools; ++i)
1440     {
1441       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1442       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
[987]1443
[1009]1444         if (contextClientTmp->isServerLeader())
1445         {
1446           CMessage msg;
1447           if (hasServer)
1448             msg<<this->getIdServer(i)<<step;
1449           else
1450             msg<<this->getIdServer()<<step;
1451           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1452           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1453             event.push(*itRank,1,msg);
1454           contextClientTmp->sendEvent(event);
1455         }
1456         else contextClientTmp->sendEvent(event);
1457     }
[300]1458   }
[1622]1459   CATCH_DUMP_ATTR
[509]1460
1461   //! Server side: Receive a message of client annoucing calendar update
[300]1462   void CContext::recvUpdateCalendar(CEventServer& event)
[1622]1463   TRY
[300]1464   {
1465      CBufferIn* buffer=event.subEvents.begin()->buffer;
1466      string id;
[549]1467      *buffer>>id;
1468      get(id)->recvUpdateCalendar(*buffer);
[300]1469   }
[1622]1470   CATCH
[509]1471
1472   //! Server side: Receive a message of client annoucing calendar update
[300]1473   void CContext::recvUpdateCalendar(CBufferIn& buffer)
[1622]1474   TRY
[300]1475   {
[549]1476      int step;
1477      buffer>>step;
1478      updateCalendar(step);
[987]1479      if (hasClient && hasServer)
1480      {       
1481        sendUpdateCalendar(step);
1482      }
[300]1483   }
[1622]1484   CATCH_DUMP_ATTR
[509]1485
1486   //! Client side: Send a message to create header part of netcdf file
[300]1487   void CContext::sendCreateFileHeader(void)
[1622]1488   TRY
[300]1489   {
[987]1490     // Use correct context client to send message
[1030]1491     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1492     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1493     for (int i = 0; i < nbSrvPools; ++i)
1494     {
1495       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1496       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
[983]1497
[1009]1498       if (contextClientTmp->isServerLeader())
1499       {
1500         CMessage msg;
1501         if (hasServer)
1502           msg<<this->getIdServer(i);
1503         else
1504           msg<<this->getIdServer();
1505         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1506         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1507           event.push(*itRank,1,msg) ;
1508         contextClientTmp->sendEvent(event);
1509       }
1510       else contextClientTmp->sendEvent(event);
[300]1511     }
1512   }
[1622]1513   CATCH_DUMP_ATTR
[509]1514
1515   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1516   void CContext::recvCreateFileHeader(CEventServer& event)
[1622]1517   TRY
[300]1518   {
1519      CBufferIn* buffer=event.subEvents.begin()->buffer;
1520      string id;
[549]1521      *buffer>>id;
1522      get(id)->recvCreateFileHeader(*buffer);
[300]1523   }
[1622]1524   CATCH
[509]1525
1526   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1527   void CContext::recvCreateFileHeader(CBufferIn& buffer)
[1622]1528   TRY
[300]1529   {
[987]1530      if (!hasClient && hasServer) 
1531        createFileHeader();
[300]1532   }
[1622]1533   CATCH_DUMP_ATTR
[509]1534
1535   //! Client side: Send a message to do some post processing on server
[1025]1536   void CContext::sendProcessingGridOfEnabledFields()
[1622]1537   TRY
[1025]1538   {
1539      // Use correct context client to send message
[1030]1540     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]1541     for (int i = 0; i < nbSrvPools; ++i)
1542     {
1543       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1544       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
[1025]1545
[1027]1546       if (contextClientTmp->isServerLeader())
1547       {
1548         CMessage msg;
[1099]1549         if (hasServer)
1550           msg<<this->getIdServer(i);
1551         else
1552           msg<<this->getIdServer();
[1027]1553         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1554         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1555           event.push(*itRank,1,msg);
1556         contextClientTmp->sendEvent(event);
1557       }
1558       else contextClientTmp->sendEvent(event);
[1025]1559     }
1560   }
[1622]1561   CATCH_DUMP_ATTR
[1025]1562
1563   //! Server side: Receive a message to do some post processing
1564   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
[1622]1565   TRY
[1025]1566   {
1567      CBufferIn* buffer=event.subEvents.begin()->buffer;
1568      string id;
[1144]1569      *buffer>>id;     
[1025]1570   }
[1622]1571   CATCH
[1025]1572
1573   //! Client side: Send a message to do some post processing on server
[509]1574   void CContext::sendPostProcessing()
[1622]1575   TRY
[509]1576   {
[987]1577      // Use correct context client to send message
[1030]1578     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1579     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1580     for (int i = 0; i < nbSrvPools; ++i)
[509]1581     {
[1009]1582       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1583       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1584       if (contextClientTmp->isServerLeader())
1585       {
1586         CMessage msg;
1587         if (hasServer)
1588           msg<<this->getIdServer(i);
1589         else
1590           msg<<this->getIdServer();
1591         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1592         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[987]1593         event.push(*itRank,1,msg);
[1009]1594         contextClientTmp->sendEvent(event);
1595       }
1596       else contextClientTmp->sendEvent(event);
[509]1597     }
1598   }
[1622]1599   CATCH_DUMP_ATTR
[509]1600
1601   //! Server side: Receive a message to do some post processing
1602   void CContext::recvPostProcessing(CEventServer& event)
[1622]1603   TRY
[509]1604   {
1605      CBufferIn* buffer=event.subEvents.begin()->buffer;
1606      string id;
1607      *buffer>>id;
1608      get(id)->recvPostProcessing(*buffer);
1609   }
[1622]1610   CATCH
[509]1611
1612   //! Server side: Receive a message to do some post processing
1613   void CContext::recvPostProcessing(CBufferIn& buffer)
[1622]1614   TRY
[509]1615   {
[549]1616      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
[509]1617      postProcessing();
1618   }
[1622]1619   CATCH_DUMP_ATTR
[509]1620
[1761]1621   void CContext::setIdServer(const StdString& idServer)
1622   TRY
1623   {
1624      idServer_=idServer ;
1625   }
1626   CATCH_DUMP_ATTR
1627
1628   
[511]1629   const StdString& CContext::getIdServer()
[1622]1630   TRY
[511]1631   {
[1761]1632      return idServer_;
1633   }
1634   CATCH_DUMP_ATTR
1635
1636   const StdString& CContext::getIdServer(const int i)
1637   TRY
1638   {
1639//     return idServer_ + std::to_string(static_cast<unsigned long long>(i));
1640      return primServerId_[i] ;
1641   }
1642   CATCH_DUMP_ATTR
1643
1644/*
1645   const StdString& CContext::getIdServer()
1646   TRY
1647   {
[511]1648      if (hasClient)
1649      {
1650        idServer_ = this->getId();
1651        idServer_ += "_server";
1652        return idServer_;
1653      }
1654      if (hasServer) return (this->getId());
1655   }
[1622]1656   CATCH_DUMP_ATTR
[511]1657
[1009]1658   const StdString& CContext::getIdServer(const int i)
[1622]1659   TRY
[1009]1660   {
1661     idServer_ = this->getId();
1662     idServer_ += "_server_";
[1542]1663     idServer_ += std::to_string(static_cast<unsigned long long>(i));
[1009]1664     return idServer_;
1665   }
[1622]1666   CATCH_DUMP_ATTR
[1761]1667*/
[1009]1668
[1761]1669
[509]1670   /*!
1671   \brief Do some simple post processings after parsing xml file
1672      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1673   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1674   which will be written out into netcdf files, are processed
1675   */
1676   void CContext::postProcessing()
[1622]1677   TRY
[509]1678   {
1679     if (isPostProcessed) return;
1680
[549]1681      // Make sure the calendar was correctly created
1682      if (!calendar)
1683        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1684      else if (calendar->getTimeStep() == NoneDu)
1685        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
[550]1686      // Calendar first update to set the current date equals to the start date
1687      calendar->update(0);
[509]1688
1689      // Find all inheritance in xml structure
1690      this->solveAllInheritance();
1691
[992]1692//      ShowTree(info(10));
[983]1693
[676]1694      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1695      // Warning: This must be done after solving the inheritance and before the rest of post-processing
[1025]1696      checkAxisDomainsGridsEligibilityForCompressedOutput();     
[676]1697
[711]1698      // Check if some automatic time series should be generated
[1144]1699      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
[711]1700
[1025]1701      // The timeseries should only be prepared in client
1702      if (hasClient && !hasServer) prepareTimeseries();
1703
[509]1704      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
[1232]1705      findEnabledFiles();
1706      findEnabledWriteModeFiles();
1707      findEnabledReadModeFiles();
1708
[1025]1709      // For now, only read files with client and only one level server
[1232]1710      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
[509]1711
[1232]1712      // Find all enabled fields of each file     
1713      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1714      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1715
[1025]1716      // For now, only read files with client and only one level server
[1232]1717      // if (hasClient && !hasServer)
1718      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
[509]1719
[1144]1720      if (hasClient && !hasServer)
1721      {
[1232]1722        initReadFiles();
1723        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1724        this->readAttributesOfEnabledFieldsInReadModeFiles();
[1144]1725      }
1726
[823]1727      // Only search and rebuild all reference objects of enable fields, don't transform
[1099]1728      this->solveOnlyRefOfEnabledFields(false);
[823]1729
[1099]1730      // Search and rebuild all reference object of enabled fields, and transform
[1129]1731      this->solveAllRefOfEnabledFieldsAndTransform(false);
[1099]1732
[593]1733      // Find all fields with read access from the public API
[1025]1734      if (hasClient && !hasServer) findFieldsWithReadAccess();
[593]1735      // and solve the all reference for them
[1025]1736      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
[593]1737
[509]1738      isPostProcessed = true;
1739   }
[1622]1740   CATCH_DUMP_ATTR
[509]1741
[917]1742   /*!
1743    * Compute the required buffer size to send the attributes (mostly those grid related).
1744    * \param maxEventSize [in/out] the size of the bigger event for each connected server
[1330]1745    * \param [in] contextClient
1746    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1747      This flag is only true for client and server-1 for communication with server-2
[917]1748    */
[1330]1749   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize,
1750                                                           CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
[1622]1751   TRY
[509]1752   {
[1372]1753         // As calendar attributes are sent even if there are no active files or fields, maps are initialized according the size of calendar attributes
1754     std::map<int, StdSize> attributesSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1755     maxEventSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
[731]1756
[1370]1757     std::vector<CFile*>& fileList = this->enabledFiles;
1758     size_t numEnabledFiles = fileList.size();
1759     for (size_t i = 0; i < numEnabledFiles; ++i)
[731]1760     {
[1370]1761//         CFile* file = this->enabledWriteModeFiles[i];
1762        CFile* file = fileList[i];
1763        std::vector<CField*> enabledFields = file->getEnabledFields();
1764        size_t numEnabledFields = enabledFields.size();
1765        for (size_t j = 0; j < numEnabledFields; ++j)
1766        {
1767          const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient, bufferForWriting);
1768          std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1769          for (; it != itE; ++it)
1770          {
1771                     // If attributesSize[it->first] does not exist, it will be zero-initialized
1772                     // so we can use it safely without checking for its existence
1773             if (attributesSize[it->first] < it->second)
1774                           attributesSize[it->first] = it->second;
[917]1775
[1370]1776                     if (maxEventSize[it->first] < it->second)
1777                           maxEventSize[it->first] = it->second;
1778          }
1779        }
[731]1780     }
1781     return attributesSize;
1782   }
[1622]1783   CATCH_DUMP_ATTR
[731]1784
[917]1785   /*!
1786    * Compute the required buffer size to send the fields data.
1787    * \param maxEventSize [in/out] the size of the bigger event for each connected server
[1330]1788    * \param [in] contextClient
1789    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1790      This flag is only true for client and server-1 for communication with server-2
[917]1791    */
[1330]1792   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize,
1793                                                      CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
[1622]1794   TRY
[731]1795   {
[730]1796     std::map<int, StdSize> dataSize;
[509]1797
1798     // Find all reference domain and axis of all active fields
[1330]1799     std::vector<CFile*>& fileList = bufferForWriting ? this->enabledWriteModeFiles : this->enabledReadModeFiles;
1800     size_t numEnabledFiles = fileList.size();
[730]1801     for (size_t i = 0; i < numEnabledFiles; ++i)
[509]1802     {
[1330]1803       CFile* file = fileList[i];
[1193]1804       if (file->getContextClient() == contextClient)
[1184]1805       {
[1370]1806         std::vector<CField*> enabledFields = file->getEnabledFields();
1807         size_t numEnabledFields = enabledFields.size();
1808         for (size_t j = 0; j < numEnabledFields; ++j)
[509]1809         {
[1370]1810           // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1811           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient,bufferForWriting);
1812           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1813           for (; it != itE; ++it)
[509]1814           {
[1370]1815             // If dataSize[it->first] does not exist, it will be zero-initialized
1816             // so we can use it safely without checking for its existance
1817                 if (CXios::isOptPerformance)
1818               dataSize[it->first] += it->second;
1819             else if (dataSize[it->first] < it->second)
1820               dataSize[it->first] = it->second;
[917]1821
[1370]1822                 if (maxEventSize[it->first] < it->second)
1823               maxEventSize[it->first] = it->second;
[598]1824           }
[509]1825         }
1826       }
1827     }
[730]1828     return dataSize;
[509]1829   }
[1622]1830   CATCH_DUMP_ATTR
[509]1831
1832   //! Client side: Send infomation of active files (files are enabled to write out)
[1232]1833   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
[1622]1834   TRY
[509]1835   {
[1232]1836     int size = activeFiles.size();
[509]1837
1838     // In a context, each type has a root definition, e.g: axis, domain, field.
1839     // Every object must be a child of one of these root definition. In this case
1840     // all new file objects created on server must be children of the root "file_definition"
1841     StdString fileDefRoot("file_definition");
1842     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
[1158]1843
[509]1844     for (int i = 0; i < size; ++i)
1845     {
[1232]1846       CFile* f = activeFiles[i];
1847       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1848       f->sendAllAttributesToServer(f->getContextClient());
1849       f->sendAddAllVariables(f->getContextClient());
[509]1850     }
1851   }
[1622]1852   CATCH_DUMP_ATTR
[509]1853
1854   //! Client side: Send information of active fields (ones are written onto files)
[1232]1855   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[1622]1856   TRY
[509]1857   {
[1232]1858     int size = activeFiles.size();
[509]1859     for (int i = 0; i < size; ++i)
1860     {
[1232]1861       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
[509]1862     }
1863   }
[1622]1864   CATCH_DUMP_ATTR
[509]1865
[676]1866   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1867   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
[1622]1868   TRY
[676]1869   {
1870     if (!hasClient) return;
1871
1872     const vector<CAxis*> allAxis = CAxis::getAll();
1873     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1874       (*it)->checkEligibilityForCompressedOutput();
1875
1876     const vector<CDomain*> allDomains = CDomain::getAll();
1877     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1878       (*it)->checkEligibilityForCompressedOutput();
1879
1880     const vector<CGrid*> allGrids = CGrid::getAll();
1881     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1882       (*it)->checkEligibilityForCompressedOutput();
1883   }
[1622]1884   CATCH_DUMP_ATTR
[676]1885
[711]1886   //! Client side: Prepare the timeseries by adding the necessary files
1887   void CContext::prepareTimeseries()
[1622]1888   TRY
[711]1889   {
1890     if (!hasClient) return;
1891
1892     const std::vector<CFile*> allFiles = CFile::getAll();
1893     for (size_t i = 0; i < allFiles.size(); i++)
1894     {
1895       CFile* file = allFiles[i];
1896
[1158]1897       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1898       for (size_t k = 0; k < vars.size(); k++)
1899       {
1900         CVariable* var = vars[k];
1901
1902         if (var->ts_target.isEmpty()
1903              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1904           fileVars.push_back(var);
1905
1906         if (!var->ts_target.isEmpty()
1907              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1908           fieldVars.push_back(var);
1909       }
1910
[711]1911       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1912       {
[1158]1913         StdString fileNameStr("%file_name%") ;
1914         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1915         
1916         StdString fileName=file->getFileOutputName();
1917         size_t pos=tsPrefix.find(fileNameStr) ;
1918         while (pos!=std::string::npos)
1919         {
1920           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1921           pos=tsPrefix.find(fileNameStr) ;
1922         }
1923       
[711]1924         const std::vector<CField*> allFields = file->getAllFields();
1925         for (size_t j = 0; j < allFields.size(); j++)
1926         {
1927           CField* field = allFields[j];
1928
1929           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1930           {
1931             CFile* tsFile = CFile::create();
1932             tsFile->duplicateAttributes(file);
1933
[1158]1934             // Add variables originating from file and targeted to timeserie file
1935             for (size_t k = 0; k < fileVars.size(); k++)
1936               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1937
1938           
[711]1939             tsFile->name = tsPrefix + "_";
1940             if (!field->name.isEmpty())
1941               tsFile->name.get() += field->name;
1942             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1943               tsFile->name.get() += field->field_ref;
1944             else
1945               tsFile->name.get() += field->getId();
1946
1947             if (!field->ts_split_freq.isEmpty())
1948               tsFile->split_freq = field->ts_split_freq;
1949
1950             CField* tsField = tsFile->addField();
1951             tsField->field_ref = field->getId();
1952
[1158]1953             // Add variables originating from file and targeted to timeserie field
1954             for (size_t k = 0; k < fieldVars.size(); k++)
1955               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1956
1957             vars = field->getAllVariables();
1958             for (size_t k = 0; k < vars.size(); k++)
1959             {
1960               CVariable* var = vars[k];
1961
1962               // Add variables originating from field and targeted to timeserie field
1963               if (var->ts_target.isEmpty()
1964                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1965                 tsField->getVirtualVariableGroup()->addChild(var);
1966
1967               // Add variables originating from field and targeted to timeserie file
1968               if (!var->ts_target.isEmpty()
1969                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1970                 tsFile->getVirtualVariableGroup()->addChild(var);
1971             }
1972
[711]1973             tsFile->solveFieldRefInheritance(true);
1974
1975             if (file->timeseries == CFile::timeseries_attr::exclusive)
1976               field->enabled = false;
1977           }
1978         }
1979
1980         // Finally disable the original file is need be
1981         if (file->timeseries == CFile::timeseries_attr::only)
1982          file->enabled = false;
1983       }
1984     }
1985   }
[1622]1986   CATCH_DUMP_ATTR
[711]1987
[509]1988   //! Client side: Send information of reference grid of active fields
[1232]1989   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
[1622]1990   TRY
[509]1991   {
1992     std::set<StdString> gridIds;
[1232]1993     int sizeFile = activeFiles.size();
[509]1994     CFile* filePtr(NULL);
1995
1996     // Firstly, find all reference grids of all active fields
1997     for (int i = 0; i < sizeFile; ++i)
1998     {
[1232]1999       filePtr = activeFiles[i];
[509]2000       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
2001       int sizeField = enabledFields.size();
2002       for (int numField = 0; numField < sizeField; ++numField)
2003       {
2004         if (0 != enabledFields[numField]->getRelGrid())
2005           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
2006       }
2007     }
2008
2009     // Create all reference grids on server side
2010     StdString gridDefRoot("grid_definition");
2011     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
2012     std::set<StdString>::const_iterator it, itE = gridIds.end();
2013     for (it = gridIds.begin(); it != itE; ++it)
2014     {
2015       gridPtr->sendCreateChild(*it);
2016       CGrid::get(*it)->sendAllAttributesToServer();
[540]2017       CGrid::get(*it)->sendAllDomains();
2018       CGrid::get(*it)->sendAllAxis();
[887]2019       CGrid::get(*it)->sendAllScalars();
[509]2020     }
2021   }
[1622]2022   CATCH_DUMP_ATTR
[509]2023
[1232]2024   //! Client side: Send information of reference domain, axis and scalar of active fields
2025   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
[1622]2026   TRY
[569]2027   {
[887]2028     std::set<StdString> domainIds, axisIds, scalarIds;
[509]2029
[569]2030     // Find all reference domain and axis of all active fields
[1232]2031     int numEnabledFiles = activeFiles.size();
[569]2032     for (int i = 0; i < numEnabledFiles; ++i)
2033     {
[1232]2034       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
[569]2035       int numEnabledFields = enabledFields.size();
2036       for (int j = 0; j < numEnabledFields; ++j)
2037       {
[887]2038         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
2039         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
2040         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
2041         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
[569]2042       }
2043     }
2044
2045     // Create all reference axis on server side
[887]2046     std::set<StdString>::iterator itDom, itAxis, itScalar;
[569]2047     std::set<StdString>::const_iterator itE;
2048
[887]2049     StdString scalarDefRoot("scalar_definition");
2050     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
2051     itE = scalarIds.end();
2052     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
2053     {
2054       if (!itScalar->empty())
2055       {
2056         scalarPtr->sendCreateChild(*itScalar);
2057         CScalar::get(*itScalar)->sendAllAttributesToServer();
2058       }
2059     }
2060
[569]2061     StdString axiDefRoot("axis_definition");
2062     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
2063     itE = axisIds.end();
2064     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
2065     {
2066       if (!itAxis->empty())
2067       {
2068         axisPtr->sendCreateChild(*itAxis);
2069         CAxis::get(*itAxis)->sendAllAttributesToServer();
2070       }
2071     }
2072
2073     // Create all reference domains on server side
2074     StdString domDefRoot("domain_definition");
2075     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
2076     itE = domainIds.end();
2077     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
2078     {
2079       if (!itDom->empty()) {
2080          domPtr->sendCreateChild(*itDom);
2081          CDomain::get(*itDom)->sendAllAttributesToServer();
2082       }
2083     }
2084   }
[1622]2085   CATCH_DUMP_ATTR
[569]2086
[509]2087   //! Update calendar in each time step
[300]2088   void CContext::updateCalendar(int step)
[1622]2089   TRY
[300]2090   {
[1357]2091      int prevStep = calendar->getStep();
2092
2093      if (prevStep < step)
[639]2094      {
[1358]2095        if (hasClient && !hasServer) // For now we only use server level 1 to read data
2096        {
2097          doPreTimestepOperationsForEnabledReadModeFiles();
2098        }
2099
[1357]2100        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
2101        calendar->update(step);
2102        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
2103  #ifdef XIOS_MEMTRACK_LIGHT
2104        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
2105  #endif
2106
2107        if (hasClient && !hasServer) // For now we only use server level 1 to read data
2108        {
2109          doPostTimestepOperationsForEnabledReadModeFiles();
2110          garbageCollector.invalidate(calendar->getCurrentDate());
2111        }
[639]2112      }
[1357]2113      else if (prevStep == step)
2114        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
2115      else // if (prevStep > step)
2116        ERROR("void CContext::updateCalendar(int step)",
2117              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
[300]2118   }
[1622]2119   CATCH_DUMP_ATTR
[509]2120
[1232]2121   void CContext::initReadFiles(void)
[1622]2122   TRY
[1232]2123   {
2124      vector<CFile*>::const_iterator it;
2125
2126      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
2127      {
2128         (*it)->initRead();
2129      }
2130   }
[1622]2131   CATCH_DUMP_ATTR
[1232]2132
[509]2133   //! Server side: Create header of netcdf file
[1232]2134   void CContext::createFileHeader(void)
[1622]2135   TRY
[300]2136   {
[549]2137      vector<CFile*>::const_iterator it;
[509]2138
[300]2139      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
[1232]2140      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
[300]2141      {
[1232]2142         (*it)->initWrite();
[300]2143      }
[509]2144   }
[1622]2145   CATCH_DUMP_ATTR
[509]2146
2147   //! Get current context
[347]2148   CContext* CContext::getCurrent(void)
[1622]2149   TRY
[300]2150   {
[549]2151     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
[300]2152   }
[1622]2153   CATCH
[509]2154
2155   /*!
2156   \brief Set context with an id be the current context
2157   \param [in] id identity of context to be set to current
2158   */
[346]2159   void CContext::setCurrent(const string& id)
[1622]2160   TRY
[346]2161   {
2162     CObjectFactory::SetCurrentContextId(id);
2163     CGroupFactory::SetCurrentContextId(id);
2164   }
[1622]2165   CATCH
[509]2166
2167  /*!
2168  \brief Create a context with specific id
2169  \param [in] id identity of new context
2170  \return pointer to the new context or already-existed one with identity id
2171  */
[347]2172  CContext* CContext::create(const StdString& id)
[1622]2173  TRY
[346]2174  {
[549]2175    CContext::setCurrent(id);
[509]2176
[346]2177    bool hasctxt = CContext::has(id);
[347]2178    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
[549]2179    getRoot();
[347]2180    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
[346]2181
2182#define DECLARE_NODE(Name_, name_) \
2183    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
2184#define DECLARE_NODE_PAR(Name_, name_)
2185#include "node_type.conf"
2186
2187    return (context);
2188  }
[1622]2189  CATCH
[697]2190
2191     //! Server side: Receive a message to do some post processing
2192  void CContext::recvRegistry(CEventServer& event)
[1622]2193  TRY
[697]2194  {
2195    CBufferIn* buffer=event.subEvents.begin()->buffer;
2196    string id;
2197    *buffer>>id;
2198    get(id)->recvRegistry(*buffer);
2199  }
[1622]2200  CATCH
[697]2201
2202  void CContext::recvRegistry(CBufferIn& buffer)
[1622]2203  TRY
[697]2204  {
2205    if (server->intraCommRank==0)
2206    {
2207      CRegistry registry(server->intraComm) ;
2208      registry.fromBuffer(buffer) ;
2209      registryOut->mergeRegistry(registry) ;
2210    }
2211  }
[1622]2212  CATCH_DUMP_ATTR
[697]2213
2214  void CContext::sendRegistry(void)
[1622]2215  TRY
[1158]2216  {
[697]2217    registryOut->hierarchicalGatherRegistry() ;
2218
[1009]2219    // Use correct context client to send message
[1030]2220    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]2221    for (int i = 0; i < nbSrvPools; ++i)
2222    {
2223      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
2224      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
[1021]2225        if (contextClientTmp->isServerLeader())
[1009]2226        {
2227           CMessage msg ;
2228           if (hasServer)
2229             msg<<this->getIdServer(i);
2230           else
2231             msg<<this->getIdServer();
2232           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
[1021]2233           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
[1009]2234           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2235             event.push(*itRank,1,msg);
2236           contextClientTmp->sendEvent(event);
2237         }
2238         else contextClientTmp->sendEvent(event);
2239    }
[697]2240  }
[1622]2241  CATCH_DUMP_ATTR
[697]2242
[1764]2243 
2244  void CContext::sendFinalizeClient(CContextClient* contextClient, const string& contextClientId)
2245  TRY
2246  {
2247    CEventClient event(getType(),EVENT_ID_CONTEXT_FINALIZE_CLIENT);
2248    if (contextClient->isServerLeader())
2249    {
2250      CMessage msg;
2251      msg<<contextClientId ;
2252      const std::list<int>& ranks = contextClient->getRanksServerLeader();
2253      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2254           event.push(*itRank,1,msg);
2255      contextClient->sendEvent(event);
2256    }
2257    else contextClient->sendEvent(event);
2258  }
2259  CATCH_DUMP_ATTR
2260
2261 
2262  void CContext::recvFinalizeClient(CEventServer& event)
2263  TRY
2264  {
2265    CBufferIn* buffer=event.subEvents.begin()->buffer;
2266    string id;
2267    *buffer>>id;
2268    get(id)->recvFinalizeClient(*buffer);
2269  }
2270  CATCH
2271
2272  void CContext::recvFinalizeClient(CBufferIn& buffer)
2273  TRY
2274  {
2275    countChildContextFinalized_++ ;
2276  }
2277  CATCH_DUMP_ATTR
2278
2279
2280
2281
[1130]2282  /*!
2283  * \fn bool CContext::isFinalized(void)
[1139]2284  * Context is finalized if it received context post finalize event.
[1130]2285  */
[1054]2286  bool CContext::isFinalized(void)
[1622]2287  TRY
[1054]2288  {
[1139]2289    return finalized;
[1054]2290  }
[1622]2291  CATCH_DUMP_ATTR
2292  ///--------------------------------------------------------------
2293  StdString CContext::dumpClassAttributes(void)
2294  {
2295    StdString str;
2296    str.append("enabled files=\"");
2297    int size = this->enabledFiles.size();
2298    for (int i = 0; i < size; ++i)
2299    {
2300      str.append(enabledFiles[i]->getId());
2301      str.append(" ");
2302    }
2303    str.append("\"");
2304    return str;
2305  }
[1054]2306
[335]2307} // namespace xios
Note: See TracBrowser for help on using the repository browser.