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

Last change on this file since 2458 was 2458, checked in by ymipsl, 17 months ago

Merge XIOS_FILE_SERVICE dev branch into trunk

YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 85.7 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) ;
665      MPI_Bcast(&serviceType,1,MPI_INT,0,intraComm_) ;
666     
667      for(auto& clientServer : clientServers)     
668      {
669        if (serviceType==CServicesManager::WRITER) { writerClientOut_.push_back(clientServer.first)      ; writerServerOut_.push_back(clientServer.second) ; }
670        else if (serviceType==CServicesManager::READER) { readerClientOut_.push_back(clientServer.first) ; readerServerOut_.push_back(clientServer.second) ; }
671        else if (serviceType==CServicesManager::GATHERER) { writerClientOut_.push_back(clientServer.first) ; writerServerOut_.push_back(clientServer.second) ; }
672      }
673      serversMap_.insert(make_pair(make_pair(poolId,serviceId),clientServers)) ;
674    }
675
676  }
677
678  vector<CContextClient*> CContext::getContextClient(const string& poolId, const string& serviceId)
679  {
680    vector<pair<CContextClient*,CContextServer*>> clientServers ;
681    getServerInterComm(poolId, serviceId, clientServers ) ;
682    vector<CContextClient*> ret ;
683    for(auto& clientServer : clientServers) ret.push_back(clientServer.first) ;
684    return ret ;
685  }
686
687
688  void CContext::globalEventLoop(void)
689  {
690    lockContext() ;
691    CXios::getDaemonsManager()->eventLoop() ;
692    unlockContext() ;
693    setCurrent(getId()) ;
694  }
695
696  bool CContext::scheduledEventLoop(bool enableEventsProcessing) 
697  {
698    bool out, finished; 
699    size_t timeLine=timeLine_ ;
700    if (serviceType_==CServicesManager::CLIENT)
701    {
702      timeLine_++ ;
703      eventScheduler_->registerEvent(timeLine, hashId_) ;
704    }
705
706    do
707    { 
708      finished=eventLoop(enableEventsProcessing) ;
709      if (serviceType_==CServicesManager::CLIENT) 
710      { 
711        out = eventScheduler_->queryEvent(timeLine,hashId_) ;
712        if (out) eventScheduler_->popEvent() ;
713      }
714
715      else out=true ;
716    }  while(!out) ;
717   
718    return finished ;
719  }
720
721  bool CContext::eventLoop(bool enableEventsProcessing)
722  {
723    bool  finished(true); 
724    if (isLockedContext()) enableEventsProcessing=false;
725   
726    setCurrent(getId()) ;
727
728    if (!finalized)
729    {
730      for(auto client : writerClientOut_) client->eventLoop();
731      for(auto server : writerServerOut_) finished &= server->eventLoop(enableEventsProcessing);
732      for(auto client : writerClientIn_) client->eventLoop();
733      for(auto server : writerServerIn_) finished &= server->eventLoop(enableEventsProcessing);
734      for(auto client : readerClientOut_) client->eventLoop();
735      for(auto server : readerServerOut_) finished &= server->eventLoop(enableEventsProcessing);
736      for(auto client : readerClientIn_) client->eventLoop();
737      for(auto server : readerServerIn_) finished &= server->eventLoop(enableEventsProcessing);
738      for(auto couplerOut : couplerOutClient_) couplerOut.second->eventLoop();
739      for(auto couplerIn : couplerInClient_) couplerIn.second->eventLoop();
740      //for(auto couplerOut : couplerOutServer_) couplerOut.second->eventLoop(enableEventsProcessing);
741      //for(auto couplerIn : couplerInServer_) couplerIn.second->eventLoop(enableEventsProcessing);
742      for(auto couplerOut : couplerOutServer_) couplerOut.second->eventLoop();
743      for(auto couplerIn : couplerInServer_) couplerIn.second->eventLoop();
744    }
745    setCurrent(getId()) ;
746    return finalized && finished ;
747  }
748
749  void CContext::addCouplingChanel(const std::string& fullContextId, bool out)
750  {
751     int contextLeader ;
752     
753     if (out)
754     { 
755       if (couplerOutClient_.find(fullContextId)==couplerOutClient_.end()) 
756       {
757         bool ok=CXios::getContextsManager()->getContextLeader(fullContextId, contextLeader, getIntraComm()) ;
758     
759         MPI_Comm interComm, interCommClient, interCommServer  ;
760         MPI_Comm intraCommClient, intraCommServer ;
761
762         if (ok) MPI_Intercomm_create(getIntraComm(), 0, CXios::getXiosComm(), contextLeader, 0, &interComm) ;
763
764        MPI_Comm_dup(intraComm_, &intraCommClient) ;
765        MPI_Comm_dup(intraComm_, &intraCommServer) ;
766        MPI_Comm_dup(interComm, &interCommClient) ;
767        MPI_Comm_dup(interComm, &interCommServer) ;
768        CContextClient* client = CContextClient::getNew(this, intraCommClient, interCommClient);
769        CContextServer* server = CContextServer::getNew(this, intraCommServer, interCommServer);
770        client->setAssociatedServer(server) ;
771        server->setAssociatedClient(client) ;
772        MPI_Comm_free(&interComm) ;
773        couplerOutClient_[fullContextId] = client ;
774        couplerOutServer_[fullContextId] = server ;
775      }
776    }
777    else if (couplerInClient_.find(fullContextId)==couplerInClient_.end())
778    {
779      bool ok=CXios::getContextsManager()->getContextLeader(fullContextId, contextLeader, getIntraComm()) ;
780     
781       MPI_Comm interComm, interCommClient, interCommServer  ;
782       MPI_Comm intraCommClient, intraCommServer ;
783
784       if (ok) MPI_Intercomm_create(getIntraComm(), 0, CXios::getXiosComm(), contextLeader, 0, &interComm) ;
785
786       MPI_Comm_dup(intraComm_, &intraCommClient) ;
787       MPI_Comm_dup(intraComm_, &intraCommServer) ;
788       MPI_Comm_dup(interComm, &interCommServer) ;
789       MPI_Comm_dup(interComm, &interCommClient) ;
790       CContextServer* server = CContextServer::getNew(this, intraCommServer, interCommServer);
791       CContextClient* client = CContextClient::getNew(this, intraCommClient, interCommClient);
792       client->setAssociatedServer(server) ;
793       server->setAssociatedClient(client) ;
794       MPI_Comm_free(&interComm) ;
795
796       couplerInClient_[fullContextId] = client ;
797       couplerInServer_[fullContextId] = server ;       
798    }
799  }
800 
801   void CContext::finalize(void)
802   TRY
803   {
804      registryOut->hierarchicalGatherRegistry() ;
805      if (intraCommRank_==0) CXios::getRegistryManager()->merge(*registryOut) ;
806
807      if (serviceType_==CServicesManager::CLIENT)
808      {
809//ym        doPreTimestepOperationsForEnabledReadModeFiles(); // For now we only use server level 1 to read data
810        triggerLateFields() ;
811
812        // inform couplerIn that I am finished
813        for(auto& couplerInClient : couplerInClient_) sendCouplerInContextFinalized(couplerInClient.second) ;
814
815        // wait until received message from couplerOut that they have finished
816        bool couplersInFinalized ;
817        do
818        {
819          couplersInFinalized=true ;
820          for(auto& couplerOutClient : couplerOutClient_) couplersInFinalized &= isCouplerInContextFinalized(couplerOutClient.second) ; 
821          globalEventLoop() ;
822        } while (!couplersInFinalized) ;
823
824        CContextClient* client ;
825        CContextServer* server ;
826
827        /*
828        if (writerClientOut_.size()!=0)
829        {
830          client=writerClientOut_[0] ;
831          server=writerServerOut_[0] ;
832
833          info(100)<<"DEBUG: context "<<getId()<<" Send client finalize to writer"<<endl ;
834          client->finalize();
835          info(100)<<"DEBUG: context "<<getId()<<" Client finalize sent to writer"<<endl ;
836          while (client->havePendingRequests()) client->eventLoop();
837          info(100)<<"DEBUG: context "<<getId()<<" no pending request on writer ok"<<endl ;
838          bool notifiedFinalized=false ;
839          do
840          {
841            notifiedFinalized = client->isNotifiedFinalized() ;
842          } while (!notifiedFinalized) ;
843
844          server->releaseBuffers();
845          client->releaseBuffers();
846          info(100)<<"DEBUG: context "<<getId()<<" release client writer ok"<<endl ;
847        }
848        */
849
850        for(int n=0; n<writerClientOut_.size() ; n++)
851        {
852          client=writerClientOut_[n] ;
853          server=writerServerOut_[n] ;
854
855          info(100)<<"DEBUG: context "<<getId()<<" Send client finalize to writer"<<endl ;
856          client->finalize();
857          info(100)<<"DEBUG: context "<<getId()<<" Client finalize sent to writer"<<endl ;
858          bool bufferReleased;
859          do
860          {
861            client->eventLoop();
862            bufferReleased = !client->havePendingRequests();
863          } while (!bufferReleased);
864          info(100)<<"DEBUG: context "<<getId()<<" no pending request on writer ok"<<endl ;
865
866          bool notifiedFinalized=false ;
867          do
868          {
869            notifiedFinalized=client->isNotifiedFinalized() ;
870          } while (!notifiedFinalized) ;
871          server->releaseBuffers();
872          client->releaseBuffers();
873          info(100)<<"DEBUG: context "<<getId()<<" release client writer ok"<<endl ;
874        }
875       
876
877        if (readerClientOut_.size()!=0)
878        {
879          client=readerClientOut_[0] ;
880          server=readerServerOut_[0] ;
881
882          info(100)<<"DEBUG: context "<<getId()<<" Send client finalize to reader"<<endl ;
883          client->finalize();
884          info(100)<<"DEBUG: context "<<getId()<<" Client finalize sent to reader"<<endl ;
885          while (client->havePendingRequests()) client->eventLoop();
886          info(100)<<"DEBUG: context "<<getId()<<" no pending request on reader ok"<<endl ;
887          bool notifiedFinalized=false ;
888         do
889         {
890            notifiedFinalized = client->isNotifiedFinalized() ;
891         }   while (!notifiedFinalized) ;
892
893          server->releaseBuffers();
894          client->releaseBuffers();
895          info(100)<<"DEBUG: context "<<getId()<<" release client reader ok"<<endl ;
896        }
897      }
898      else if (serviceType_==CServicesManager::GATHERER)
899      {
900         for(auto& client : writerClientOut_)
901         {
902           client->finalize();
903           bool bufferReleased;
904           do
905           {
906             client->eventLoop();
907             bufferReleased = !client->havePendingRequests();
908           } while (!bufferReleased);
909           
910           bool notifiedFinalized=false ;
911           do
912           {
913             notifiedFinalized=client->isNotifiedFinalized() ;
914           } while (!notifiedFinalized) ;
915           client->releaseBuffers();
916         }
917         closeAllFile();
918         //ym writerClientIn & writerServerIn not released here ==> to check !!
919      }
920      else if (serviceType_==CServicesManager::WRITER)
921      {
922        closeAllFile();
923        writerClientIn_[0]->releaseBuffers();
924        writerServerIn_[0]->releaseBuffers();
925      }
926      else if (serviceType_==CServicesManager::READER)
927      {
928        closeAllFile();
929        readerClientIn_[0]->releaseBuffers();
930        readerServerIn_[0]->releaseBuffers();
931      }
932
933      freeComms() ;
934       
935      parentServerContext_->freeComm() ;
936      finalized = true;
937      info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
938   }
939   CATCH_DUMP_ATTR
940
941   //! Free internally allocated communicators
942   void CContext::freeComms(void)
943   TRY
944   {
945     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
946       MPI_Comm_free(&(*it));
947     comms.clear();
948   }
949   CATCH_DUMP_ATTR
950
951   
952   void CContext::setDefaultServices(void)
953   {
954     defaultPoolWriterId_ = CXios::defaultPoolId ;
955     defaultPoolReaderId_ = CXios::defaultPoolId ;
956     defaultPoolGathererId_ = CXios::defaultPoolId ;
957     defaultWriterId_ = CXios::defaultWriterId ;
958     defaultReaderId_ = CXios::defaultReaderId ;
959     defaultGathererId_ = CXios::defaultGathererId ;
960     defaultUsingServer2_ = CXios::usingServer2 ;
961     
962     if (!default_pool.isEmpty())  defaultPoolWriterId_ = defaultPoolReaderId_= defaultPoolGathererId_= default_pool ;
963     if (!default_pool_writer.isEmpty()) defaultPoolWriterId_ = default_pool_writer ;
964     if (!default_pool_reader.isEmpty()) defaultPoolReaderId_ = default_pool_reader ;
965     if (!default_pool_gatherer.isEmpty()) defaultPoolGathererId_ = default_pool_gatherer ;
966     if (!default_writer.isEmpty()) defaultWriterId_ = default_writer ;
967     if (!default_reader.isEmpty()) defaultWriterId_ = default_reader ;
968     if (!default_gatherer.isEmpty()) defaultGathererId_ = default_gatherer ;
969     if (!default_using_server2.isEmpty()) defaultUsingServer2_ = default_using_server2 ;
970   }
971
972   /*!
973   \brief Close all the context defintion and do processing data
974      After everything is well defined on client side, they will be processed and sent to server
975   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
976   all necessary information to server, from which each server can build its own database.
977   Because the role of server is to write out field data on a specific netcdf file,
978   the only information that it needs is the enabled files
979   and the active fields (fields will be written onto active files)
980   */
981  void CContext::closeDefinition(void)
982   TRY
983   {
984     CMemChecker::logMem( "CContext::closeDefinition" );
985
986     CTimer::get("Context : close definition").resume() ;
987         
988     // create intercommunicator with servers.
989     // not sure it is the good place to be called here
990     //createServerInterComm() ;
991
992
993     // After xml is parsed, there are some more works with post processing
994//     postProcessing();
995
996   
997    // Make sure the calendar was correctly created
998    if (serviceType_!=CServicesManager::CLIENT) CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
999    if (!calendar)
1000      ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1001    else if (calendar->getTimeStep() == NoneDu)
1002      ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1003    // Calendar first update to set the current date equals to the start date
1004    calendar->update(0);
1005
1006    // Résolution des héritages descendants (càd des héritages de groupes)
1007    // pour chacun des contextes.
1008    solveDescInheritance(true);
1009    setDefaultServices() ;
1010    // Check if some axis, domains or grids are eligible to for compressed indexed output.
1011    // Warning: This must be done after solving the inheritance and before the rest of post-processing
1012    // --> later ????    checkAxisDomainsGridsEligibilityForCompressedOutput();     
1013
1014      // Check if some automatic time series should be generated
1015      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1016
1017    // The timeseries should only be prepared in client
1018    prepareTimeseries();
1019
1020    //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1021    findEnabledFiles();
1022
1023    // Solve inheritance for field to know if enabled or not.
1024    for (auto field : CField::getAll()) field->solveRefInheritance();
1025
1026    findEnabledWriteModeFiles();
1027    findEnabledReadModeFiles();
1028    findEnabledCouplerIn();
1029    findEnabledCouplerOut();
1030    createCouplerInterCommunicator() ;
1031
1032    // Find all enabled fields of each file     
1033    vector<CField*>&& fileOutField = findAllEnabledFieldsInFileOut(this->enabledWriteModeFiles);
1034    vector<CField*>&& fileInField = findAllEnabledFieldsInFileIn(this->enabledReadModeFiles);
1035    vector<CField*>&& couplerOutField = findAllEnabledFieldsCouplerOut(this->enabledCouplerOut);
1036    vector<CField*>&& couplerInField = findAllEnabledFieldsCouplerIn(this->enabledCouplerIn);
1037    findFieldsWithReadAccess();
1038    vector<CField*>& fieldWithReadAccess = fieldsWithReadAccess_ ;
1039    vector<CField*> fieldModelIn ; // fields potentially from model
1040
1041    // define if files are on clientSied or serverSide
1042    if (serviceType_==CServicesManager::CLIENT)
1043    {
1044      for (auto& file : enabledWriteModeFiles) file->setClientSide() ;
1045      for (auto& file : enabledReadModeFiles) file->setClientSide() ;
1046    }
1047    else
1048    {
1049      for (auto& file : enabledWriteModeFiles) file->setServerSide() ;
1050      for (auto& file : enabledReadModeFiles) file->setServerSide() ;
1051    }
1052
1053   
1054    for (auto& field : couplerInField)
1055    {
1056      field->unsetGridCompleted() ;
1057    }
1058// find all field potentially at workflow end
1059    vector<CField*> endWorkflowFields ;
1060    endWorkflowFields.reserve(fileOutField.size()+couplerOutField.size()+fieldWithReadAccess.size()) ;
1061    endWorkflowFields.insert(endWorkflowFields.end(),fileOutField.begin(), fileOutField.end()) ;
1062    endWorkflowFields.insert(endWorkflowFields.end(),couplerOutField.begin(), couplerOutField.end()) ;
1063    endWorkflowFields.insert(endWorkflowFields.end(),fieldWithReadAccess.begin(), fieldWithReadAccess.end()) ;
1064
1065    bool workflowGraphIsCompleted ;
1066   
1067    bool first=true ;
1068   
1069    do
1070    {
1071      workflowGraphIsCompleted=true; 
1072      for(auto endWorkflowField : endWorkflowFields) 
1073      {
1074        workflowGraphIsCompleted &= endWorkflowField->buildWorkflowGraph(garbageCollector) ;
1075      }
1076   
1077      for(auto couplerIn : enabledCouplerIn) couplerIn->assignContext() ;
1078      for(auto field : couplerInField) field->makeGridAliasForCoupling();
1079      for(auto field : couplerInField) this->sendCouplerInReady(field->getContextClient()) ;
1080   
1081
1082      // assign context to coupler out and related fields
1083      for(auto couplerOut : enabledCouplerOut) couplerOut->assignContext() ;
1084      // for now supose that all coupling out endpoint are succesfull. The difficultie is client/server buffer evaluation
1085      for(auto field : couplerOutField) 
1086      {
1087        // connect to couplerOut -> to do
1088      }
1089
1090      bool couplersReady ;
1091      do 
1092      {
1093        couplersReady=true ;
1094        for(auto field : couplerOutField)
1095        {
1096          bool ready = isCouplerInReady(field->getContextClient()) ; 
1097          if (ready) field->sendFieldToCouplerOut() ;
1098          couplersReady &= ready ;
1099        }
1100        this->scheduledEventLoop() ;
1101
1102      } while (!couplersReady) ;
1103     
1104      first=false ;
1105      this->scheduledEventLoop() ;
1106
1107    } while (!workflowGraphIsCompleted) ;
1108
1109
1110    for( auto field : couplerInField) couplerInFields_.push_back(field) ;
1111
1112    // get all field coming potentially from model
1113    for (auto field : CField::getAll() ) if (field->getModelIn()) fieldModelIn.push_back(field) ;
1114
1115    // Distribute files between secondary servers according to the data size => assign a context to a file and then to fields
1116   
1117    if (serviceType_==CServicesManager::CLIENT || serviceType_==CServicesManager::GATHERER) distributeFiles(this->enabledWriteModeFiles) ;
1118    /*
1119    if (serviceType_==CServicesManager::CLIENT )
1120    {   
1121      if (CXios::usingServer2) distributeFiles(this->enabledWriteModeFiles, defaultPoolGathererId_, defaultGathererId_);
1122      else distributeFiles(this->enabledWriteModeFiles, defaultPoolWriterId_, defaultWriterId_);
1123    }
1124    if (serviceType_==CServicesManager::GATHERER ) distributeFiles(this->enabledWriteModeFiles, defaultPoolWriterId_, defaultWriterId_);
1125    */
1126
1127    // client side, assign context for file reading
1128//    if (serviceType_==CServicesManager::CLIENT) for(auto file : this->enabledReadModeFiles) file->setContextClient(readerClientOut_[0]) ;
1129    if (serviceType_==CServicesManager::CLIENT) for(auto file : this->enabledReadModeFiles) 
1130    {
1131      string poolReaderId ;
1132      string readerId ;
1133      file->getReaderServicesId(defaultPoolReaderId_, defaultReaderId_, poolReaderId, readerId) ;
1134      file->setContextClient(poolReaderId, readerId, 0) ;
1135    }
1136
1137    // server side, assign context where to send file data read
1138    if (serviceType_==CServicesManager::READER) for(auto file : this->enabledReadModeFiles) file->setContextClient(readerClientIn_[0]) ;
1139   
1140
1141    // workflow startpoint => data from server on client side
1142    // important : sendFieldToInputFileServer must be done prior sendFieldToFileServer because for the first case the grid remoteConnectorIn
1143    //             and grid remoteConnectorOut will be computed, and in the second case only the remoteConnectorOut.
1144    if (serviceType_==CServicesManager::CLIENT)
1145    {
1146      for(auto field : fileInField) 
1147      {
1148        field->sendFieldToInputFileServer() ;
1149        field->connectToServerInput(garbageCollector) ; // connect the field to server filter
1150        fileInFields_.push_back(field) ;
1151      }
1152    }
1153
1154    // workflow endpoint => sent to IO/SERVER
1155    if (serviceType_==CServicesManager::CLIENT || serviceType_==CServicesManager::GATHERER)
1156    {
1157      for(auto field : fileOutField) 
1158      {
1159        field->connectToFileServer(garbageCollector) ; // connect the field to server filter
1160      }
1161      for(auto field : fileOutField) field->sendFieldToFileServer() ;
1162    }
1163
1164    // workflow endpoint => write to file
1165    if (serviceType_==CServicesManager::WRITER)
1166    {
1167      for(auto field : fileOutField) 
1168      {
1169        field->connectToFileWriter(garbageCollector) ; // connect the field to server filter
1170      }
1171    }
1172   
1173    // workflow endpoint => Send data from server to client
1174    if (serviceType_==CServicesManager::READER || serviceType_==CServicesManager::GATHERER)
1175    {
1176      for(auto field : fileInField) 
1177      {
1178        field->connectToServerToClient(garbageCollector) ;
1179      }
1180    }
1181
1182    // workflow endpoint => sent to model on client side
1183    if (serviceType_==CServicesManager::CLIENT)
1184    {
1185      for(auto field : fieldWithReadAccess) field->connectToModelOutput(garbageCollector) ;
1186    }
1187
1188
1189    // workflow startpoint => data from model
1190    if (serviceType_==CServicesManager::CLIENT)
1191    {
1192      for(auto field : fieldModelIn) 
1193      {
1194        field->connectToModelInput(garbageCollector) ; // connect the field to server filter
1195        // grid index will be computed on the fly
1196      }
1197    }
1198   
1199    // workflow startpoint => data from client on server side
1200    if (serviceType_==CServicesManager::WRITER || serviceType_==CServicesManager::GATHERER)
1201    {
1202      for(auto field : fieldModelIn) 
1203      {
1204        field->connectToClientInput(garbageCollector) ; // connect the field to server filter
1205      }
1206    }
1207
1208   
1209    for(auto field : couplerInField) 
1210    {
1211      field->connectToCouplerIn(garbageCollector) ; // connect the field to server filter
1212    }
1213   
1214   
1215    for(auto field : couplerOutField) 
1216    {
1217      field->connectToCouplerOut(garbageCollector) ; // for now the same kind of filter that for file server
1218    }
1219
1220    // workflow startpoint => data read from file on server side
1221    if (serviceType_==CServicesManager::READER)
1222    {
1223      for(auto field : fileInField) 
1224      {
1225        field->connectToFileReader(garbageCollector) ;
1226      }
1227    }
1228   
1229    // construct slave server list
1230    map<string, CContextClient*> slaves ; // need an ordered list ;
1231    if (serviceType_==CServicesManager::CLIENT) 
1232    {
1233      for(auto field : fileOutField) slaves[clientsId_[field->getContextClient()]] = field->getContextClient() ; 
1234      for(auto field : fileInField) slaves[clientsId_[field->getContextClient()]] = field->getContextClient() ; 
1235    }
1236    else if (serviceType_==CServicesManager::GATHERER) 
1237      for(auto field : fileOutField) slaves[clientsId_[field->getContextClient()]] = field->getContextClient() ;
1238    for(auto& slave : slaves) slaveServers_.push_back(slave.second) ;   
1239
1240
1241    for(auto& slaveServer : slaveServers_) sendCloseDefinition(slaveServer) ;
1242
1243    if (serviceType_==CServicesManager::WRITER) 
1244    {
1245      createFileHeader();
1246    }
1247
1248    if (serviceType_==CServicesManager::CLIENT) startPrefetchingOfEnabledReadModeFiles();
1249   
1250    // send signal to couplerIn context that definition phasis is done
1251
1252    for(auto& couplerInClient : couplerInClient_) sendCouplerInCloseDefinition(couplerInClient.second) ;
1253
1254    // wait until all couplerIn signal that closeDefition is done.
1255    bool ok;
1256    do
1257    {
1258      ok = true ;
1259      for(auto& couplerOutClient : couplerOutClient_) ok &= isCouplerInCloseDefinition(couplerOutClient.second) ;
1260      this->scheduledEventLoop() ;
1261    } while (!ok) ;
1262
1263    // Now evaluate the size of the context client buffers
1264    map<CContextClient*,map<int,size_t>> fieldBufferEvaluation ;
1265    for(auto field : fileOutField) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // output to server
1266    for(auto field : couplerOutField) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // output to coupler
1267    for(auto field : fileInField) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // server to client (for io servers)
1268   
1269    // fix size for each context client
1270    for(auto& it : fieldBufferEvaluation) it.first->setBufferSize(it.second) ;
1271
1272
1273     CTimer::get("Context : close definition").suspend() ;
1274     CMemChecker::logMem( "CContext::closeDefinition_END" );
1275  }
1276  CATCH_DUMP_ATTR
1277
1278
1279  vector<CField*> CContext::findAllEnabledFieldsInFileOut(const std::vector<CFile*>& activeFiles)
1280   TRY
1281   {
1282     vector<CField*> fields ;
1283     for(auto file : activeFiles)
1284     {
1285        const vector<CField*>&& fieldList=file->getEnabledFields() ;
1286        for(auto field : fieldList) field->setFileOut(file) ;
1287        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1288     }
1289     return fields ;
1290   }
1291   CATCH_DUMP_ATTR
1292
1293   vector<CField*> CContext::findAllEnabledFieldsInFileIn(const std::vector<CFile*>& activeFiles)
1294   TRY
1295   {
1296     vector<CField*> fields ;
1297     for(auto file : activeFiles)
1298     {
1299        const vector<CField*>&& fieldList=file->getEnabledFields() ;
1300        for(auto field : fieldList) field->setFileIn(file) ;
1301        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1302     }
1303     return fields ;
1304   }
1305   CATCH_DUMP_ATTR
1306
1307   vector<CField*> CContext::findAllEnabledFieldsCouplerOut(const std::vector<CCouplerOut*>& activeCouplerOut)
1308   TRY
1309   {
1310     vector<CField*> fields ;
1311     for (auto couplerOut :activeCouplerOut)
1312     {
1313        const vector<CField*>&& fieldList=couplerOut->getEnabledFields() ;
1314        for(auto field : fieldList) field->setCouplerOut(couplerOut) ;
1315        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1316     }
1317     return fields ;
1318   }
1319   CATCH_DUMP_ATTR
1320
1321   vector<CField*> CContext::findAllEnabledFieldsCouplerIn(const std::vector<CCouplerIn*>& activeCouplerIn)
1322   TRY
1323   {
1324     vector<CField*> fields ;
1325     for (auto couplerIn :activeCouplerIn)
1326     {
1327        const vector<CField*>&& fieldList=couplerIn->getEnabledFields() ;
1328        for(auto field : fieldList) field->setCouplerIn(couplerIn) ;
1329        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1330     }
1331     return fields ;
1332   }
1333   CATCH_DUMP_ATTR
1334
1335 /*!
1336  * Send context attribute and calendar to file server, it must be done once by context file server
1337  * \param[in] client : context client to send   
1338  */ 
1339  void CContext::sendContextToFileServer(CContextClient* client)
1340  {
1341    if (sendToFileServer_done_.count(client)!=0) return ;
1342    else sendToFileServer_done_.insert(client) ;
1343   
1344    this->sendAllAttributesToServer(client); // Send all attributes of current context to server
1345    CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer(client); // Send all attributes of current cale
1346  }
1347
1348 
1349   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
1350   TRY
1351   {
1352      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1353        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
1354   }
1355   CATCH_DUMP_ATTR
1356
1357
1358   void CContext::postProcessFilterGraph()
1359   TRY
1360   {
1361     int size = enabledFiles.size();
1362     for (int i = 0; i < size; ++i)
1363     {
1364        enabledFiles[i]->postProcessFilterGraph();
1365     }
1366   }
1367   CATCH_DUMP_ATTR
1368
1369   void CContext::startPrefetchingOfEnabledReadModeFiles()
1370   TRY
1371   {
1372     int size = enabledReadModeFiles.size();
1373     for (int i = 0; i < size; ++i)
1374     {
1375        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
1376     }
1377   }
1378   CATCH_DUMP_ATTR
1379
1380   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
1381   TRY
1382   {
1383     int size = enabledReadModeFiles.size();
1384     for (int i = 0; i < size; ++i)
1385     {
1386        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
1387     }
1388   }
1389   CATCH_DUMP_ATTR
1390
1391   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
1392   TRY
1393   {
1394     int size = enabledReadModeFiles.size();
1395     for (int i = 0; i < size; ++i)
1396     {
1397        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
1398     }
1399   }
1400   CATCH_DUMP_ATTR
1401
1402  void CContext::findFieldsWithReadAccess(void)
1403  TRY
1404  {
1405    fieldsWithReadAccess_.clear();
1406    const vector<CField*> allFields = CField::getAll();
1407    for (size_t i = 0; i < allFields.size(); ++i)
1408    {
1409      CField* field = allFields[i];
1410      if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
1411      {
1412        fieldsWithReadAccess_.push_back(field);
1413        field->setModelOut() ;
1414      }
1415    }
1416  }
1417  CATCH_DUMP_ATTR
1418
1419 
1420   void CContext::solveAllInheritance(bool apply)
1421   TRY
1422   {
1423     // Résolution des héritages descendants (càd des héritages de groupes)
1424     // pour chacun des contextes.
1425      solveDescInheritance(apply);
1426
1427     // Résolution des héritages par référence au niveau des fichiers.
1428      const vector<CFile*> allFiles=CFile::getAll();
1429      const vector<CCouplerIn*> allCouplerIn=CCouplerIn::getAll();
1430      const vector<CCouplerOut*> allCouplerOut=CCouplerOut::getAll();
1431      const vector<CGrid*> allGrids= CGrid::getAll();
1432
1433      if (serviceType_==CServicesManager::CLIENT)
1434      {
1435        for (unsigned int i = 0; i < allFiles.size(); i++)
1436          allFiles[i]->solveFieldRefInheritance(apply);
1437
1438        for (unsigned int i = 0; i < allCouplerIn.size(); i++)
1439          allCouplerIn[i]->solveFieldRefInheritance(apply);
1440
1441        for (unsigned int i = 0; i < allCouplerOut.size(); i++)
1442          allCouplerOut[i]->solveFieldRefInheritance(apply);
1443      }
1444
1445      unsigned int vecSize = allGrids.size();
1446      unsigned int i = 0;
1447      for (i = 0; i < vecSize; ++i)
1448        allGrids[i]->solveElementsRefInheritance(apply);
1449
1450   }
1451  CATCH_DUMP_ATTR
1452
1453   void CContext::findEnabledFiles(void)
1454   TRY
1455   {
1456      const std::vector<CFile*> allFiles = CFile::getAll();
1457      const CDate& initDate = calendar->getInitDate();
1458
1459      for (unsigned int i = 0; i < allFiles.size(); i++)
1460         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
1461         {
1462            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
1463            {
1464              if (allFiles[i]->output_freq.isEmpty())
1465              {
1466                 ERROR("CContext::findEnabledFiles()",
1467                     << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1468                     <<" \".")
1469              }
1470              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1471              {
1472                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1473                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1474                    <<"\" is less than the time step. File will not be written."<<endl;
1475              }
1476              else
1477               enabledFiles.push_back(allFiles[i]);
1478            }
1479            else // Si l'attribut 'enabled' est fixé à faux.
1480            {
1481              // disabled all fields contained in file (used in findFieldsWithReadAccess through field_ref dependencies)
1482              const vector<CField*>&& fieldList=allFiles[i]->getEnabledFields() ;
1483              for(auto field : fieldList) field->enabled.setValue(false);
1484            }
1485         }
1486         else
1487         {
1488           if (allFiles[i]->output_freq.isEmpty())
1489           {
1490              ERROR("CContext::findEnabledFiles()",
1491                  << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1492                  <<" \".")
1493           }
1494           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1495           {
1496             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1497                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1498                 <<"\" is less than the time step. File will not be written."<<endl;
1499           }
1500           else
1501             enabledFiles.push_back(allFiles[i]); // otherwise true by default
1502         }
1503
1504      if (enabledFiles.size() == 0)
1505         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
1506               << getId() << "\" !");
1507
1508   }
1509   CATCH_DUMP_ATTR
1510
1511   void CContext::findEnabledCouplerIn(void)
1512   TRY
1513   {
1514      const std::vector<CCouplerIn*> allCouplerIn = CCouplerIn::getAll();
1515      bool enabled ;
1516      for (size_t i = 0; i < allCouplerIn.size(); i++)
1517      {
1518        if (allCouplerIn[i]->enabled.isEmpty()) enabled=true ;
1519        else enabled=allCouplerIn[i]->enabled ;
1520        if (enabled) enabledCouplerIn.push_back(allCouplerIn[i]) ;
1521      }
1522   }
1523   CATCH_DUMP_ATTR
1524
1525   void CContext::findEnabledCouplerOut(void)
1526   TRY
1527   {
1528      const std::vector<CCouplerOut*> allCouplerOut = CCouplerOut::getAll();
1529      bool enabled ;
1530      for (size_t i = 0; i < allCouplerOut.size(); i++)
1531      {
1532        if (allCouplerOut[i]->enabled.isEmpty()) enabled=true ;
1533        else enabled=allCouplerOut[i]->enabled ;
1534        if (enabled) enabledCouplerOut.push_back(allCouplerOut[i]) ;
1535      }
1536   }
1537   CATCH_DUMP_ATTR
1538
1539
1540
1541
1542   void CContext::distributeFiles(const vector<CFile*>& files)
1543   TRY
1544   {
1545     map< pair<string,string>, vector<CFile*>> fileMaps ;
1546     for(auto& file : files)
1547     {
1548       string poolWriterId ;
1549       string poolGathererId ;
1550       string writerId  ;
1551       string gathererId  ;
1552       bool usingServer2 ;
1553
1554       file->getWriterServicesId(defaultUsingServer2_, defaultPoolWriterId_, defaultWriterId_, defaultPoolGathererId_, defaultGathererId_,
1555                                 usingServer2, poolWriterId, writerId, poolGathererId, gathererId) ;
1556       if (serviceType_==CServicesManager::CLIENT && usingServer2) fileMaps[make_pair(poolGathererId,gathererId)].push_back(file) ;
1557       else fileMaps[make_pair(poolWriterId,writerId)].push_back(file) ;
1558     }
1559     for(auto& it : fileMaps) distributeFilesOnSameService(it.second, it.first.first, it.first.second) ;
1560   }
1561   CATCH_DUMP_ATTR
1562
1563
1564   void CContext::distributeFilesOnSameService(const vector<CFile*>& files, const string& poolId, const string& serviceId)
1565   TRY
1566   {
1567     bool distFileMemory=false ;
1568     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
1569
1570     auto writers = getContextClient(poolId, serviceId) ;
1571     int  nbPools = writers.size() ;
1572     
1573     if (nbPools==1) distributeFileOverOne(files, poolId, serviceId) ;
1574     else if (distFileMemory) distributeFileOverMemoryBandwith(files, poolId, serviceId) ;
1575     else distributeFileOverBandwith(files, poolId, serviceId) ;
1576   }
1577   CATCH_DUMP_ATTR
1578
1579   void CContext::distributeFileOverOne(const vector<CFile*>& files, const string& poolId, const string& serviceId)
1580   TRY
1581   {
1582     for(auto& file : files) file->setContextClient(poolId, serviceId,0) ;
1583   }
1584   CATCH_DUMP_ATTR
1585
1586   void CContext::distributeFileOverBandwith(const vector<CFile*>& files, const string& poolId, const string& serviceId)
1587   TRY
1588   {
1589     double eps=std::numeric_limits<double>::epsilon()*10 ;
1590     
1591     std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
1592     auto writers = getContextClient(poolId, serviceId) ;
1593     int nbPools = writers.size();
1594     //int nbPools = writerClientOut_.size();
1595
1596     // (1) Find all enabled files in write mode
1597     // for (int i = 0; i < this->enabledFiles.size(); ++i)
1598     // {
1599     //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1600     //    enabledWriteModeFiles.push_back(enabledFiles[i]);
1601     // }
1602
1603     // (2) Estimate the data volume for each file
1604     int size = files.size();
1605     std::vector<std::pair<double, CFile*> > dataSizeMap;
1606     double dataPerPool = 0;
1607     int nfield=0 ;
1608     ofs<<size<<endl ;
1609     for (size_t i = 0; i < size; ++i)
1610     {
1611       CFile* file = files[i];
1612       ofs<<file->getId()<<endl ;
1613       StdSize dataSize=0;
1614       std::vector<CField*> enabledFields = file->getEnabledFields();
1615       size_t numEnabledFields = enabledFields.size();
1616       ofs<<numEnabledFields<<endl ;
1617       for (size_t j = 0; j < numEnabledFields; ++j)
1618       {
1619         dataSize += enabledFields[j]->getGlobalWrittenSize() ;
1620         ofs<<enabledFields[j]->getGrid()->getId()<<endl ;
1621         ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
1622       }
1623       double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1624       double dataSizeSec= dataSize/ outFreqSec;
1625       ofs<<dataSizeSec<<endl ;
1626       nfield++ ;
1627// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
1628       dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
1629       dataPerPool += dataSizeSec;
1630     }
1631     dataPerPool /= nbPools;
1632     std::sort(dataSizeMap.begin(), dataSizeMap.end());
1633
1634     // (3) Assign contextClient to each enabled file
1635
1636     std::multimap<double,int> poolDataSize ;
1637// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
1638
1639     int j;
1640     double dataSize ;
1641     for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
1642             
1643     for (int i = dataSizeMap.size()-1; i >= 0; --i)
1644     {
1645       dataSize=(*poolDataSize.begin()).first ;
1646       j=(*poolDataSize.begin()).second ;
1647       dataSizeMap[i].second->setContextClient(poolId, serviceId, j);
1648       dataSize+=dataSizeMap[i].first;
1649       poolDataSize.erase(poolDataSize.begin()) ;
1650       poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
1651     }
1652
1653     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 ;
1654   }
1655   CATCH_DUMP_ATTR
1656
1657   void CContext::distributeFileOverMemoryBandwith(const vector<CFile*>& filesList, const string& poolId, const string& serviceId)
1658   TRY
1659   {
1660     auto writers = getContextClient(poolId, serviceId) ;
1661     int nbPools = writers.size();
1662   
1663     double ratio=0.5 ;
1664     ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1665
1666     int nFiles = filesList.size();
1667     vector<SDistFile> files(nFiles);
1668     vector<SDistGrid> grids;
1669     map<string,int> gridMap ;
1670     string gridId; 
1671     int gridIndex=0 ;
1672
1673     for (size_t i = 0; i < nFiles; ++i)
1674     {
1675       StdSize dataSize=0;
1676       CFile* file = filesList[i];
1677       std::vector<CField*> enabledFields = file->getEnabledFields();
1678       size_t numEnabledFields = enabledFields.size();
1679
1680       files[i].id_=file->getId() ;
1681       files[i].nbGrids_=numEnabledFields;
1682       files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1683         
1684       for (size_t j = 0; j < numEnabledFields; ++j)
1685       {
1686         gridId=enabledFields[j]->getGrid()->getId() ;
1687         if (gridMap.find(gridId)==gridMap.end())
1688         {
1689            gridMap[gridId]=gridIndex  ;
1690            SDistGrid newGrid; 
1691            grids.push_back(newGrid) ;
1692            gridIndex++ ;
1693         }
1694         files[i].assignedGrid_[j]=gridMap[gridId] ;
1695         grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1696         dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1697       }
1698       double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1699       files[i].bandwith_= dataSize/ outFreqSec ;
1700     }
1701
1702     double bandwith=0 ;
1703     double memory=0 ;
1704   
1705     for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1706     for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1707
1708     for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1709     for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1710       
1711     distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1712
1713     vector<double> memorySize(nbPools,0.) ;
1714     vector< set<int> > serverGrids(nbPools) ;
1715     vector<double> bandwithSize(nbPools,0.) ;
1716       
1717     for (size_t i = 0; i < nFiles; ++i)
1718     {
1719       bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1720       for(int j=0 ; j<files[i].nbGrids_;j++)
1721       {
1722         if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1723         {
1724           memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1725           serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1726         }
1727       }
1728       filesList[i]->setContextClient(poolId, serviceId, files[i].assignedServer_) ;
1729       delete [] files[i].assignedGrid_ ;
1730     }
1731
1732     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 ;
1733     for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1734
1735   }
1736   CATCH_DUMP_ATTR
1737
1738   /*!
1739      Find all files in write mode
1740   */
1741   void CContext::findEnabledWriteModeFiles(void)
1742   TRY
1743   {
1744     int size = this->enabledFiles.size();
1745     for (int i = 0; i < size; ++i)
1746     {
1747       if (enabledFiles[i]->mode.isEmpty() || 
1748          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1749        enabledWriteModeFiles.push_back(enabledFiles[i]);
1750     }
1751   }
1752   CATCH_DUMP_ATTR
1753
1754   /*!
1755      Find all files in read mode
1756   */
1757   void CContext::findEnabledReadModeFiles(void)
1758   TRY
1759   {
1760     int size = this->enabledFiles.size();
1761     for (int i = 0; i < size; ++i)
1762     {
1763       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1764        enabledReadModeFiles.push_back(enabledFiles[i]);
1765     }
1766   }
1767   CATCH_DUMP_ATTR
1768
1769   void CContext::closeAllFile(void)
1770   TRY
1771   {
1772     std::vector<CFile*>::const_iterator
1773            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
1774
1775     for (; it != end; it++)
1776     {
1777       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1778       (*it)->close();
1779     }
1780   }
1781   CATCH_DUMP_ATTR
1782
1783   /*!
1784   \brief Dispatch event received from client
1785      Whenever a message is received in buffer of server, it will be processed depending on
1786   its event type. A new event type should be added in the switch list to make sure
1787   it processed on server side.
1788   \param [in] event: Received message
1789   */
1790   bool CContext::dispatchEvent(CEventServer& event)
1791   TRY
1792   {
1793
1794      if (SuperClass::dispatchEvent(event)) return true;
1795      else
1796      {
1797        switch(event.type)
1798        {
1799           case EVENT_ID_CLOSE_DEFINITION :
1800             recvCloseDefinition(event);
1801             return true;
1802             break;
1803           case EVENT_ID_UPDATE_CALENDAR:
1804             recvUpdateCalendar(event);
1805             return true;
1806             break;
1807           case EVENT_ID_COUPLER_IN_READY:
1808             recvCouplerInReady(event);
1809             return true;
1810             break;
1811           case EVENT_ID_COUPLER_IN_CLOSE_DEFINITION:
1812             recvCouplerInCloseDefinition(event);
1813             return true;
1814             break;
1815           case EVENT_ID_COUPLER_IN_CONTEXT_FINALIZED:
1816             recvCouplerInContextFinalized(event);
1817             return true;
1818             break; 
1819           default :
1820             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
1821                    <<"Unknown Event");
1822           return false;
1823         }
1824      }
1825   }
1826   CATCH
1827
1828   //  ! Client side: Send a message to server to make it close
1829   void CContext::sendCloseDefinition(CContextClient* client)
1830   TRY
1831   {
1832      if (sendCloseDefinition_done_.count(client)!=0) return ;
1833      else sendCloseDefinition_done_.insert(client) ;
1834
1835      CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1836      if (client->isServerLeader())
1837      {
1838        CMessage msg;
1839        for(auto rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1840        client->sendEvent(event);
1841      }
1842     else client->sendEvent(event);
1843   }
1844   CATCH_DUMP_ATTR
1845
1846   //! Server side: Receive a message of client announcing a context close
1847   void CContext::recvCloseDefinition(CEventServer& event)
1848   TRY
1849   {
1850      CBufferIn* buffer=event.subEvents.begin()->buffer;
1851      getCurrent()->closeDefinition();
1852   }
1853   CATCH
1854
1855   //! Client side: Send a message to update calendar in each time step
1856   void CContext::sendUpdateCalendar(int step)
1857   TRY
1858   {
1859     for(auto client : slaveServers_) 
1860     {
1861       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1862       if (client->isServerLeader())
1863       {
1864         CMessage msg;
1865         msg<<step;
1866         for (auto& rank : client->getRanksServerLeader() ) event.push(rank,1,msg);
1867         client->sendEvent(event);
1868       }
1869       else client->sendEvent(event);
1870     }
1871   }
1872   CATCH_DUMP_ATTR
1873
1874   //! Server side: Receive a message of client annoucing calendar update
1875   void CContext::recvUpdateCalendar(CEventServer& event)
1876   TRY
1877   {
1878      CBufferIn* buffer=event.subEvents.begin()->buffer;
1879      getCurrent()->recvUpdateCalendar(*buffer);
1880   }
1881   CATCH
1882
1883   //! Server side: Receive a message of client annoucing calendar update
1884   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1885   TRY
1886   {
1887      int step;
1888      buffer>>step;
1889      updateCalendar(step);
1890      if (serviceType_==CServicesManager::GATHERER)
1891      {       
1892        sendUpdateCalendar(step);
1893      }
1894   }
1895   CATCH_DUMP_ATTR
1896
1897
1898   void CContext::createCouplerInterCommunicator(void)
1899   TRY
1900   {
1901      int rank=this->getIntraCommRank() ;
1902      map<string,list<CCouplerOut*>> listCouplerOut ; 
1903      map<string,list<CCouplerIn*>> listCouplerIn ; 
1904
1905      for(auto couplerOut : enabledCouplerOut) listCouplerOut[couplerOut->getCouplingContextId()].push_back(couplerOut) ;
1906      for(auto couplerIn : enabledCouplerIn) listCouplerIn[couplerIn->getCouplingContextId()].push_back(couplerIn) ;
1907
1908      CCouplerManager* couplerManager = CXios::getCouplerManager() ;
1909      if (rank==0)
1910      {
1911        for(auto couplerOut : listCouplerOut) couplerManager->registerCoupling(this->getContextId(),couplerOut.first) ;
1912        for(auto couplerIn : listCouplerIn) couplerManager->registerCoupling(couplerIn.first,this->getContextId()) ;
1913      }
1914
1915      do
1916      {
1917        for(auto couplerOut : listCouplerOut) 
1918        {
1919          bool isNextCoupling ;
1920          if (rank==0) isNextCoupling = couplerManager->isNextCoupling(this->getContextId(),couplerOut.first) ;
1921          MPI_Bcast(&isNextCoupling,1,MPI_C_BOOL, 0, getIntraComm()) ; 
1922          if (isNextCoupling) 
1923          {
1924            addCouplingChanel(couplerOut.first, true) ;
1925            listCouplerOut.erase(couplerOut.first) ;
1926            break ;
1927          }           
1928        }
1929        for(auto couplerIn : listCouplerIn) 
1930        {
1931          bool isNextCoupling ;
1932          if (rank==0) isNextCoupling = couplerManager->isNextCoupling(couplerIn.first,this->getContextId());
1933          MPI_Bcast(&isNextCoupling,1,MPI_C_BOOL, 0, getIntraComm()) ; 
1934          if (isNextCoupling) 
1935          {
1936            addCouplingChanel(couplerIn.first, false) ;
1937            listCouplerIn.erase(couplerIn.first) ;
1938            break ;
1939          }           
1940        }
1941
1942      } while (!listCouplerOut.empty() || !listCouplerIn.empty()) ;
1943
1944   }
1945   CATCH_DUMP_ATTR
1946
1947 
1948     //! Client side: Send infomation of active files (files are enabled to write out)
1949   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1950   TRY
1951   {
1952     int size = activeFiles.size();
1953
1954     // In a context, each type has a root definition, e.g: axis, domain, field.
1955     // Every object must be a child of one of these root definition. In this case
1956     // all new file objects created on server must be children of the root "file_definition"
1957     StdString fileDefRoot("file_definition");
1958     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1959
1960     for (int i = 0; i < size; ++i)
1961     {
1962       CFile* f = activeFiles[i];
1963       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1964       f->sendAllAttributesToServer(f->getContextClient());
1965       f->sendAddAllVariables(f->getContextClient());
1966     }
1967   }
1968   CATCH_DUMP_ATTR
1969
1970   //! Client side: Send information of active fields (ones are written onto files)
1971   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1972   TRY
1973   {
1974     int size = activeFiles.size();
1975     for (int i = 0; i < size; ++i)
1976     {
1977       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1978     }
1979   }
1980   CATCH_DUMP_ATTR
1981
1982 
1983   //! Client side: Prepare the timeseries by adding the necessary files
1984   void CContext::prepareTimeseries()
1985   TRY
1986   {
1987     const std::vector<CFile*> allFiles = CFile::getAll();
1988     for (size_t i = 0; i < allFiles.size(); i++)
1989     {
1990       CFile* file = allFiles[i];
1991
1992       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1993       for (size_t k = 0; k < vars.size(); k++)
1994       {
1995         CVariable* var = vars[k];
1996
1997         if (var->ts_target.isEmpty()
1998              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1999           fileVars.push_back(var);
2000
2001         if (!var->ts_target.isEmpty()
2002              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
2003           fieldVars.push_back(var);
2004       }
2005
2006       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
2007       {
2008         StdString fileNameStr("%file_name%") ;
2009         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
2010         
2011         StdString fileName=file->getFileOutputName();
2012         size_t pos=tsPrefix.find(fileNameStr) ;
2013         while (pos!=std::string::npos)
2014         {
2015           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
2016           pos=tsPrefix.find(fileNameStr) ;
2017         }
2018       
2019         const std::vector<CField*> allFields = file->getAllFields();
2020         for (size_t j = 0; j < allFields.size(); j++)
2021         {
2022           CField* field = allFields[j];
2023
2024           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
2025           {
2026             CFile* tsFile = CFile::create();
2027             tsFile->duplicateAttributes(file);
2028
2029             // Add variables originating from file and targeted to timeserie file
2030             for (size_t k = 0; k < fileVars.size(); k++)
2031               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
2032
2033           
2034             tsFile->name = tsPrefix + "_";
2035             if (!field->name.isEmpty())
2036               tsFile->name.get() += field->name;
2037             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
2038               tsFile->name.get() += field->field_ref;
2039             else
2040               tsFile->name.get() += field->getId();
2041
2042             if (!field->ts_split_freq.isEmpty())
2043               tsFile->split_freq = field->ts_split_freq;
2044
2045             CField* tsField = tsFile->addField();
2046             tsField->field_ref = field->getId();
2047
2048             // Add variables originating from file and targeted to timeserie field
2049             for (size_t k = 0; k < fieldVars.size(); k++)
2050               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
2051
2052             vars = field->getAllVariables();
2053             for (size_t k = 0; k < vars.size(); k++)
2054             {
2055               CVariable* var = vars[k];
2056
2057               // Add variables originating from field and targeted to timeserie field
2058               if (var->ts_target.isEmpty()
2059                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
2060                 tsField->getVirtualVariableGroup()->addChild(var);
2061
2062               // Add variables originating from field and targeted to timeserie file
2063               if (!var->ts_target.isEmpty()
2064                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
2065                 tsFile->getVirtualVariableGroup()->addChild(var);
2066             }
2067
2068             tsFile->solveFieldRefInheritance(true);
2069
2070             if (file->timeseries == CFile::timeseries_attr::exclusive)
2071               field->enabled = false;
2072           }
2073         }
2074
2075         // Finally disable the original file is need be
2076         if (file->timeseries == CFile::timeseries_attr::only)
2077          file->enabled = false;
2078       }
2079     }
2080   }
2081   CATCH_DUMP_ATTR
2082
2083 
2084   //! Client side: Send information of reference domain, axis and scalar of active fields
2085   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
2086   TRY
2087   {
2088     std::set<pair<StdString,CContextClient*>> domainIds, axisIds, scalarIds;
2089
2090     // Find all reference domain and axis of all active fields
2091     int numEnabledFiles = activeFiles.size();
2092     for (int i = 0; i < numEnabledFiles; ++i)
2093     {
2094       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
2095       int numEnabledFields = enabledFields.size();
2096       for (int j = 0; j < numEnabledFields; ++j)
2097       {
2098         CContextClient* contextClient=enabledFields[j]->getContextClient() ;
2099         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
2100         if ("" != prDomAxisScalarId[0]) domainIds.insert(make_pair(prDomAxisScalarId[0],contextClient));
2101         if ("" != prDomAxisScalarId[1]) axisIds.insert(make_pair(prDomAxisScalarId[1],contextClient));
2102         if ("" != prDomAxisScalarId[2]) scalarIds.insert(make_pair(prDomAxisScalarId[2],contextClient));
2103       }
2104     }
2105
2106     // Create all reference axis on server side
2107     std::set<StdString>::iterator itDom, itAxis, itScalar;
2108     std::set<StdString>::const_iterator itE;
2109
2110     StdString scalarDefRoot("scalar_definition");
2111     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
2112     
2113     for (auto itScalar = scalarIds.begin(); itScalar != scalarIds.end(); ++itScalar)
2114     {
2115       if (!itScalar->first.empty())
2116       {
2117         scalarPtr->sendCreateChild(itScalar->first,itScalar->second);
2118         CScalar::get(itScalar->first)->sendAllAttributesToServer(itScalar->second);
2119       }
2120     }
2121
2122     StdString axiDefRoot("axis_definition");
2123     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
2124     
2125     for (auto itAxis = axisIds.begin(); itAxis != axisIds.end(); ++itAxis)
2126     {
2127       if (!itAxis->first.empty())
2128       {
2129         axisPtr->sendCreateChild(itAxis->first, itAxis->second);
2130         CAxis::get(itAxis->first)->sendAllAttributesToServer(itAxis->second);
2131       }
2132     }
2133
2134     // Create all reference domains on server side
2135     StdString domDefRoot("domain_definition");
2136     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
2137     
2138     for (auto itDom = domainIds.begin(); itDom != domainIds.end(); ++itDom)
2139     {
2140       if (!itDom->first.empty()) {
2141          domPtr->sendCreateChild(itDom->first, itDom->second);
2142          CDomain::get(itDom->first)->sendAllAttributesToServer(itDom->second);
2143       }
2144     }
2145   }
2146   CATCH_DUMP_ATTR
2147
2148   void CContext::triggerLateFields(void)
2149   TRY
2150   {
2151    for(auto& field : fileInFields_) field->triggerLateField() ;
2152    for(auto& field : couplerInFields_) field->triggerLateField() ;
2153   }
2154   CATCH_DUMP_ATTR
2155
2156   //! Update calendar in each time step
2157   void CContext::updateCalendar(int step)
2158   TRY
2159   {
2160      int prevStep = calendar->getStep();
2161
2162      if (prevStep < step)
2163      {
2164        if (serviceType_==CServicesManager::CLIENT) // For now we only use server level 1 to read data
2165        {
2166          triggerLateFields();
2167        }
2168
2169        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
2170        calendar->update(step);
2171        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
2172  #ifdef XIOS_MEMTRACK_LIGHT
2173        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
2174  #endif
2175
2176        if (serviceType_==CServicesManager::CLIENT) // For now we only use server level 1 to read data
2177        {
2178          doPostTimestepOperationsForEnabledReadModeFiles();
2179          garbageCollector.invalidate(calendar->getCurrentDate());
2180        }
2181        CMemChecker::logMem( "CContext::updateCalendar_"+std::to_string(step) );
2182      }
2183      else if (prevStep == step)
2184        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
2185      else // if (prevStep > step)
2186        ERROR("void CContext::updateCalendar(int step)",
2187              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
2188   }
2189   CATCH_DUMP_ATTR
2190
2191   void CContext::initReadFiles(void)
2192   TRY
2193   {
2194      vector<CFile*>::const_iterator it;
2195
2196      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
2197      {
2198         (*it)->initRead();
2199      }
2200   }
2201   CATCH_DUMP_ATTR
2202
2203   //! Server side: Create header of netcdf file
2204   void CContext::createFileHeader(void)
2205   TRY
2206   {
2207      vector<CFile*>::const_iterator it;
2208
2209      //for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
2210      for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
2211      {
2212         (*it)->initWrite();
2213      }
2214   }
2215   CATCH_DUMP_ATTR
2216
2217   //! Get current context
2218   CContext* CContext::getCurrent(void)
2219   TRY
2220   {
2221     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
2222   }
2223   CATCH
2224
2225   /*!
2226   \brief Set context with an id be the current context
2227   \param [in] id identity of context to be set to current
2228   */
2229   void CContext::setCurrent(const string& id)
2230   TRY
2231   {
2232     CObjectFactory::SetCurrentContextId(id);
2233     CGroupFactory::SetCurrentContextId(id);
2234   }
2235   CATCH
2236
2237  /*!
2238  \brief Create a context with specific id
2239  \param [in] id identity of new context
2240  \return pointer to the new context or already-existed one with identity id
2241  */
2242  CContext* CContext::create(const StdString& id)
2243  TRY
2244  {
2245    CContext::setCurrent(id);
2246
2247    bool hasctxt = CContext::has(id);
2248    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
2249    getRoot();
2250    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
2251
2252#define DECLARE_NODE(Name_, name_) \
2253    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
2254#define DECLARE_NODE_PAR(Name_, name_)
2255#include "node_type.conf"
2256
2257    return (context);
2258  }
2259  CATCH
2260
2261 
2262  void CContext::sendFinalizeClient(CContextClient* contextClient, const string& contextClientId)
2263  TRY
2264  {
2265    CEventClient event(getType(),EVENT_ID_CONTEXT_FINALIZE_CLIENT);
2266    if (contextClient->isServerLeader())
2267    {
2268      CMessage msg;
2269      msg<<contextClientId ;
2270      const std::list<int>& ranks = contextClient->getRanksServerLeader();
2271      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2272           event.push(*itRank,1,msg);
2273      contextClient->sendEvent(event);
2274    }
2275    else contextClient->sendEvent(event);
2276  }
2277  CATCH_DUMP_ATTR
2278
2279 
2280  void CContext::recvFinalizeClient(CEventServer& event)
2281  TRY
2282  {
2283    CBufferIn* buffer=event.subEvents.begin()->buffer;
2284    string id;
2285    *buffer>>id;
2286    get(id)->recvFinalizeClient(*buffer);
2287  }
2288  CATCH
2289
2290  void CContext::recvFinalizeClient(CBufferIn& buffer)
2291  TRY
2292  {
2293    countChildContextFinalized_++ ;
2294  }
2295  CATCH_DUMP_ATTR
2296
2297
2298
2299
2300 //! Client side: Send a message  announcing that context can receive grid definition from coupling
2301   void CContext::sendCouplerInReady(CContextClient* client)
2302   TRY
2303   {
2304      if (sendCouplerInReady_done_.count(client)!=0) return ;
2305      else sendCouplerInReady_done_.insert(client) ;
2306
2307      CEventClient event(getType(),EVENT_ID_COUPLER_IN_READY);
2308
2309      if (client->isServerLeader())
2310      {
2311        CMessage msg;
2312        msg<<this->getId();
2313        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2314        client->sendEvent(event);
2315      }
2316      else client->sendEvent(event);
2317   }
2318   CATCH_DUMP_ATTR
2319
2320   //! Server side: Receive a message announcing that context can send grid definition for context coupling
2321   void CContext::recvCouplerInReady(CEventServer& event)
2322   TRY
2323   {
2324      CBufferIn* buffer=event.subEvents.begin()->buffer;
2325      getCurrent()->recvCouplerInReady(*buffer);
2326   }
2327   CATCH
2328
2329   //! Server side: Receive a message announcing that context can send grid definition for context coupling
2330   void CContext::recvCouplerInReady(CBufferIn& buffer)
2331   TRY
2332   {
2333      string contextId ;
2334      buffer>>contextId;
2335      couplerInReady_.insert(getCouplerOutClient(contextId)) ;
2336   }
2337   CATCH_DUMP_ATTR
2338
2339
2340
2341
2342
2343 //! Client side: Send a message  announcing that a coupling context have done it closeDefinition, so data can be sent now.
2344   void CContext::sendCouplerInCloseDefinition(CContextClient* client)
2345   TRY
2346   {
2347      if (sendCouplerInCloseDefinition_done_.count(client)!=0) return ;
2348      else sendCouplerInCloseDefinition_done_.insert(client) ;
2349
2350      CEventClient event(getType(),EVENT_ID_COUPLER_IN_CLOSE_DEFINITION);
2351
2352      if (client->isServerLeader())
2353      {
2354        CMessage msg;
2355        msg<<this->getId();
2356        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2357        client->sendEvent(event);
2358      }
2359      else client->sendEvent(event);
2360   }
2361   CATCH_DUMP_ATTR
2362
2363   //! Server side: Receive a message announcing that a coupling context have done it closeDefinition, so data can be sent now.
2364   void CContext::recvCouplerInCloseDefinition(CEventServer& event)
2365   TRY
2366   {
2367      CBufferIn* buffer=event.subEvents.begin()->buffer;
2368      getCurrent()->recvCouplerInCloseDefinition(*buffer);
2369   }
2370   CATCH
2371
2372   //! Server side: Receive a message announcing that a coupling context have done it closeDefinition, so data can be sent now.
2373   void CContext::recvCouplerInCloseDefinition(CBufferIn& buffer)
2374   TRY
2375   {
2376      string contextId ;
2377      buffer>>contextId;
2378      couplerInCloseDefinition_.insert(getCouplerOutClient(contextId)) ;
2379   }
2380   CATCH_DUMP_ATTR
2381
2382
2383
2384
2385//! Client side: Send a message  announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2386   void CContext::sendCouplerInContextFinalized(CContextClient* client)
2387   TRY
2388   {
2389      if (sendCouplerInContextFinalized_done_.count(client)!=0) return ;
2390      else sendCouplerInContextFinalized_done_.insert(client) ;
2391
2392      CEventClient event(getType(),EVENT_ID_COUPLER_IN_CONTEXT_FINALIZED);
2393
2394      if (client->isServerLeader())
2395      {
2396        CMessage msg;
2397        msg<<this->getId();
2398        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2399        client->sendEvent(event);
2400      }
2401      else client->sendEvent(event);
2402   }
2403   CATCH_DUMP_ATTR
2404
2405   //! Server side: Receive a message announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2406   void CContext::recvCouplerInContextFinalized(CEventServer& event)
2407   TRY
2408   {
2409      CBufferIn* buffer=event.subEvents.begin()->buffer;
2410      getCurrent()->recvCouplerInContextFinalized(*buffer);
2411   }
2412   CATCH
2413
2414   //! Server side: Receive a message announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2415   void CContext::recvCouplerInContextFinalized(CBufferIn& buffer)
2416   TRY
2417   {
2418      string contextId ;
2419      buffer>>contextId;
2420      couplerInContextFinalized_.insert(getCouplerOutClient(contextId)) ;
2421   }
2422   CATCH_DUMP_ATTR
2423
2424
2425
2426
2427  /*!
2428  * \fn bool CContext::isFinalized(void)
2429  * Context is finalized if it received context post finalize event.
2430  */
2431  bool CContext::isFinalized(void)
2432  TRY
2433  {
2434    return finalized;
2435  }
2436  CATCH_DUMP_ATTR
2437  ///--------------------------------------------------------------
2438  StdString CContext::dumpClassAttributes(void)
2439  {
2440    StdString str;
2441    str.append("enabled files=\"");
2442    int size = this->enabledFiles.size();
2443    for (int i = 0; i < size; ++i)
2444    {
2445      str.append(enabledFiles[i]->getId());
2446      str.append(" ");
2447    }
2448    str.append("\"");
2449    return str;
2450  }
2451
2452} // namespace xios
Note: See TracBrowser for help on using the repository browser.