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

Last change on this file since 2410 was 2410, checked in by jderouillat, 21 months ago

Fix for attached mode in the new service management

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