source: XIOS/dev/dev_trunk_graph/src/node/context.cpp @ 2019

Last change on this file since 2019 was 2019, checked in by yushan, 9 months ago

Graph intermedia commit to a tmp branch

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