source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/context.cpp @ 2123

Last change on this file since 2123 was 2123, checked in by ymipsl, 3 years ago

Possibly fix deadlock in attched mode
YM

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