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

Last change on this file since 2240 was 2240, checked in by jderouillat, 3 years ago

Operate MPI windows free. Otherwise MPI will try to free it itself without respecting an adapted order, which will lead to a deadlock

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