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

Last change on this file since 2614 was 2614, checked in by ymipsl, 2 months ago
  • Permit now usage of contex_group into xml file for more modularity
  • Src path is now relative to parent file, except if path is an absolute path

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