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

Last change on this file since 2498 was 2498, checked in by jderouillat, 14 months ago

Revert 2494 partially (keep initialisation of notifyType_), the associated wait managment causes deadlock in dynamico like test cases on JeanZay?

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