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

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

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