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

Last change on this file since 2628 was 2628, checked in by jderouillat, 6 weeks ago

New timers integration/reporting

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