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

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

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