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

Last change on this file since 2326 was 2326, checked in by ymipsl, 2 years ago

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