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

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

Reimplement coupling in the new infrastructure.
Tested for 2-way coupling toy model.

YM

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