source: XIOS3/dev/XIOS_FILE_SERVICES/src/node/context.cpp @ 2453

Last change on this file since 2453 was 2453, checked in by ymipsl, 18 months ago

Implementation of files service on dev branch

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