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

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

Revisiting registry management and make it working.
YM

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