source: XIOS3/trunk/src/node/context.cpp @ 2507

Last change on this file since 2507 was 2507, checked in by ymipsl, 12 months ago

Merging XIOS3_ATTACHED branch into XIOS3 trunk.

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