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

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

Tracking memory leak : release memory statically alocated

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.3 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()) return false;
683   
684    setCurrent(getId()) ;
685
686    if (client!=nullptr && !finalized) client->checkBuffers();
687   
688    for (int i = 0; i < clientPrimServer.size(); ++i)
689    {
690      if (!finalized) clientPrimServer[i]->checkBuffers();
691      if (!finalized) finished &= serverPrimServer[i]->eventLoop(enableEventsProcessing);
692    }
693
694    for (auto couplerOut : couplerOutClient_)
695      if (!finalized) couplerOut.second->checkBuffers();
696   
697    for (auto couplerIn : couplerInClient_)
698      if (!finalized) couplerIn.second->checkBuffers();
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->checkBuffers();
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]->checkBuffers();
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 || serviceType_==CServicesManager::GATHERER) 
1099    {
1100      for(auto field : fileOutField) slaveServers_.insert(field->getContextClient()) ; 
1101      for(auto field : fileInField)  slaveServers_.insert(field->getContextClient()) ; 
1102    }
1103
1104    for(auto& slaveServer : slaveServers_) sendCloseDefinition(slaveServer) ;
1105
1106    if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER) 
1107    {
1108      createFileHeader();
1109    }
1110
1111    if (serviceType_==CServicesManager::CLIENT) startPrefetchingOfEnabledReadModeFiles();
1112   
1113    // send signal to couplerIn context that definition phasis is done
1114
1115    for(auto& couplerInClient : couplerInClient_) sendCouplerInCloseDefinition(couplerInClient.second) ;
1116
1117    // wait until all couplerIn signal that closeDefition is done.
1118    bool ok;
1119    do
1120    {
1121      ok = true ;
1122      for(auto& couplerOutClient : couplerOutClient_) ok &= isCouplerInCloseDefinition(couplerOutClient.second) ;
1123      this->scheduledEventLoop() ;
1124    } while (!ok) ;
1125
1126    // Now evaluate the size of the context client buffers
1127    map<CContextClient*,map<int,size_t>> fieldBufferEvaluation ;
1128    for(auto field : fileOutField) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // output to server
1129    for(auto field : couplerOutField) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // output to coupler
1130    for(auto field : fieldModelIn) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // server to client (for io servers)
1131   
1132    // fix size for each context client
1133    for(auto& it : fieldBufferEvaluation) it.first->setBufferSize(it.second) ;
1134
1135
1136     CTimer::get("Context : close definition").suspend() ;
1137  }
1138  CATCH_DUMP_ATTR
1139
1140
1141  vector<CField*> CContext::findAllEnabledFieldsInFileOut(const std::vector<CFile*>& activeFiles)
1142   TRY
1143   {
1144     vector<CField*> fields ;
1145     for(auto file : activeFiles)
1146     {
1147        const vector<CField*>&& fieldList=file->getEnabledFields() ;
1148        for(auto field : fieldList) field->setFileOut(file) ;
1149        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1150     }
1151     return fields ;
1152   }
1153   CATCH_DUMP_ATTR
1154
1155   vector<CField*> CContext::findAllEnabledFieldsInFileIn(const std::vector<CFile*>& activeFiles)
1156   TRY
1157   {
1158     vector<CField*> fields ;
1159     for(auto file : activeFiles)
1160     {
1161        const vector<CField*>&& fieldList=file->getEnabledFields() ;
1162        for(auto field : fieldList) field->setFileIn(file) ;
1163        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1164     }
1165     return fields ;
1166   }
1167   CATCH_DUMP_ATTR
1168
1169   vector<CField*> CContext::findAllEnabledFieldsCouplerOut(const std::vector<CCouplerOut*>& activeCouplerOut)
1170   TRY
1171   {
1172     vector<CField*> fields ;
1173     for (auto couplerOut :activeCouplerOut)
1174     {
1175        const vector<CField*>&& fieldList=couplerOut->getEnabledFields() ;
1176        for(auto field : fieldList) field->setCouplerOut(couplerOut) ;
1177        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1178     }
1179     return fields ;
1180   }
1181   CATCH_DUMP_ATTR
1182
1183   vector<CField*> CContext::findAllEnabledFieldsCouplerIn(const std::vector<CCouplerIn*>& activeCouplerIn)
1184   TRY
1185   {
1186     vector<CField*> fields ;
1187     for (auto couplerIn :activeCouplerIn)
1188     {
1189        const vector<CField*>&& fieldList=couplerIn->getEnabledFields() ;
1190        for(auto field : fieldList) field->setCouplerIn(couplerIn) ;
1191        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1192     }
1193     return fields ;
1194   }
1195   CATCH_DUMP_ATTR
1196
1197 /*!
1198  * Send context attribute and calendar to file server, it must be done once by context file server
1199  * \param[in] client : context client to send   
1200  */ 
1201  void CContext::sendContextToFileServer(CContextClient* client)
1202  {
1203    if (sendToFileServer_done_.count(client)!=0) return ;
1204    else sendToFileServer_done_.insert(client) ;
1205   
1206    this->sendAllAttributesToServer(client); // Send all attributes of current context to server
1207    CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer(client); // Send all attributes of current cale
1208  }
1209
1210 
1211   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
1212   TRY
1213   {
1214      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1215        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
1216   }
1217   CATCH_DUMP_ATTR
1218
1219
1220   void CContext::postProcessFilterGraph()
1221   TRY
1222   {
1223     int size = enabledFiles.size();
1224     for (int i = 0; i < size; ++i)
1225     {
1226        enabledFiles[i]->postProcessFilterGraph();
1227     }
1228   }
1229   CATCH_DUMP_ATTR
1230
1231   void CContext::startPrefetchingOfEnabledReadModeFiles()
1232   TRY
1233   {
1234     int size = enabledReadModeFiles.size();
1235     for (int i = 0; i < size; ++i)
1236     {
1237        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
1238     }
1239   }
1240   CATCH_DUMP_ATTR
1241
1242   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
1243   TRY
1244   {
1245     int size = enabledReadModeFiles.size();
1246     for (int i = 0; i < size; ++i)
1247     {
1248        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
1249     }
1250   }
1251   CATCH_DUMP_ATTR
1252
1253   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
1254   TRY
1255   {
1256     int size = enabledReadModeFiles.size();
1257     for (int i = 0; i < size; ++i)
1258     {
1259        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
1260     }
1261   }
1262   CATCH_DUMP_ATTR
1263
1264  void CContext::findFieldsWithReadAccess(void)
1265  TRY
1266  {
1267    fieldsWithReadAccess_.clear();
1268    const vector<CField*> allFields = CField::getAll();
1269    for (size_t i = 0; i < allFields.size(); ++i)
1270    {
1271      CField* field = allFields[i];
1272      if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
1273      {
1274        fieldsWithReadAccess_.push_back(field);
1275        field->setModelOut() ;
1276      }
1277    }
1278  }
1279  CATCH_DUMP_ATTR
1280
1281 
1282   void CContext::solveAllInheritance(bool apply)
1283   TRY
1284   {
1285     // Résolution des héritages descendants (càd des héritages de groupes)
1286     // pour chacun des contextes.
1287      solveDescInheritance(apply);
1288
1289     // Résolution des héritages par référence au niveau des fichiers.
1290      const vector<CFile*> allFiles=CFile::getAll();
1291      const vector<CCouplerIn*> allCouplerIn=CCouplerIn::getAll();
1292      const vector<CCouplerOut*> allCouplerOut=CCouplerOut::getAll();
1293      const vector<CGrid*> allGrids= CGrid::getAll();
1294
1295      if (serviceType_==CServicesManager::CLIENT)
1296      {
1297        for (unsigned int i = 0; i < allFiles.size(); i++)
1298          allFiles[i]->solveFieldRefInheritance(apply);
1299
1300        for (unsigned int i = 0; i < allCouplerIn.size(); i++)
1301          allCouplerIn[i]->solveFieldRefInheritance(apply);
1302
1303        for (unsigned int i = 0; i < allCouplerOut.size(); i++)
1304          allCouplerOut[i]->solveFieldRefInheritance(apply);
1305      }
1306
1307      unsigned int vecSize = allGrids.size();
1308      unsigned int i = 0;
1309      for (i = 0; i < vecSize; ++i)
1310        allGrids[i]->solveElementsRefInheritance(apply);
1311
1312   }
1313  CATCH_DUMP_ATTR
1314
1315   void CContext::findEnabledFiles(void)
1316   TRY
1317   {
1318      const std::vector<CFile*> allFiles = CFile::getAll();
1319      const CDate& initDate = calendar->getInitDate();
1320
1321      for (unsigned int i = 0; i < allFiles.size(); i++)
1322         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
1323         {
1324            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
1325            {
1326              if (allFiles[i]->output_freq.isEmpty())
1327              {
1328                 ERROR("CContext::findEnabledFiles()",
1329                     << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1330                     <<" \".")
1331              }
1332              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1333              {
1334                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1335                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1336                    <<"\" is less than the time step. File will not be written."<<endl;
1337              }
1338              else
1339               enabledFiles.push_back(allFiles[i]);
1340            }
1341         }
1342         else
1343         {
1344           if (allFiles[i]->output_freq.isEmpty())
1345           {
1346              ERROR("CContext::findEnabledFiles()",
1347                  << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1348                  <<" \".")
1349           }
1350           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1351           {
1352             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1353                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1354                 <<"\" is less than the time step. File will not be written."<<endl;
1355           }
1356           else
1357             enabledFiles.push_back(allFiles[i]); // otherwise true by default
1358         }
1359
1360      if (enabledFiles.size() == 0)
1361         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
1362               << getId() << "\" !");
1363
1364   }
1365   CATCH_DUMP_ATTR
1366
1367   void CContext::findEnabledCouplerIn(void)
1368   TRY
1369   {
1370      const std::vector<CCouplerIn*> allCouplerIn = CCouplerIn::getAll();
1371      bool enabled ;
1372      for (size_t i = 0; i < allCouplerIn.size(); i++)
1373      {
1374        if (allCouplerIn[i]->enabled.isEmpty()) enabled=true ;
1375        else enabled=allCouplerIn[i]->enabled ;
1376        if (enabled) enabledCouplerIn.push_back(allCouplerIn[i]) ;
1377      }
1378   }
1379   CATCH_DUMP_ATTR
1380
1381   void CContext::findEnabledCouplerOut(void)
1382   TRY
1383   {
1384      const std::vector<CCouplerOut*> allCouplerOut = CCouplerOut::getAll();
1385      bool enabled ;
1386      for (size_t i = 0; i < allCouplerOut.size(); i++)
1387      {
1388        if (allCouplerOut[i]->enabled.isEmpty()) enabled=true ;
1389        else enabled=allCouplerOut[i]->enabled ;
1390        if (enabled) enabledCouplerOut.push_back(allCouplerOut[i]) ;
1391      }
1392   }
1393   CATCH_DUMP_ATTR
1394
1395
1396
1397
1398   void CContext::distributeFiles(const vector<CFile*>& files)
1399   TRY
1400   {
1401     bool distFileMemory=false ;
1402     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
1403
1404     if (distFileMemory) distributeFileOverMemoryBandwith(files) ;
1405     else distributeFileOverBandwith(files) ;
1406   }
1407   CATCH_DUMP_ATTR
1408
1409   void CContext::distributeFileOverBandwith(const vector<CFile*>& files)
1410   TRY
1411   {
1412     double eps=std::numeric_limits<double>::epsilon()*10 ;
1413     
1414     std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
1415     int nbPools = clientPrimServer.size();
1416
1417     // (1) Find all enabled files in write mode
1418     // for (int i = 0; i < this->enabledFiles.size(); ++i)
1419     // {
1420     //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1421     //    enabledWriteModeFiles.push_back(enabledFiles[i]);
1422     // }
1423
1424     // (2) Estimate the data volume for each file
1425     int size = files.size();
1426     std::vector<std::pair<double, CFile*> > dataSizeMap;
1427     double dataPerPool = 0;
1428     int nfield=0 ;
1429     ofs<<size<<endl ;
1430     for (size_t i = 0; i < size; ++i)
1431     {
1432       CFile* file = files[i];
1433       ofs<<file->getId()<<endl ;
1434       StdSize dataSize=0;
1435       std::vector<CField*> enabledFields = file->getEnabledFields();
1436       size_t numEnabledFields = enabledFields.size();
1437       ofs<<numEnabledFields<<endl ;
1438       for (size_t j = 0; j < numEnabledFields; ++j)
1439       {
1440         dataSize += enabledFields[j]->getGlobalWrittenSize() ;
1441         ofs<<enabledFields[j]->getGrid()->getId()<<endl ;
1442         ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
1443       }
1444       double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1445       double dataSizeSec= dataSize/ outFreqSec;
1446       ofs<<dataSizeSec<<endl ;
1447       nfield++ ;
1448// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
1449       dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
1450       dataPerPool += dataSizeSec;
1451     }
1452     dataPerPool /= nbPools;
1453     std::sort(dataSizeMap.begin(), dataSizeMap.end());
1454
1455     // (3) Assign contextClient to each enabled file
1456
1457     std::multimap<double,int> poolDataSize ;
1458// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
1459
1460     int j;
1461     double dataSize ;
1462     for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
1463             
1464     for (int i = dataSizeMap.size()-1; i >= 0; --i)
1465     {
1466       dataSize=(*poolDataSize.begin()).first ;
1467       j=(*poolDataSize.begin()).second ;
1468       dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
1469       dataSize+=dataSizeMap[i].first;
1470       poolDataSize.erase(poolDataSize.begin()) ;
1471       poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
1472     }
1473
1474     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 ;
1475   }
1476   CATCH_DUMP_ATTR
1477
1478   void CContext::distributeFileOverMemoryBandwith(const vector<CFile*>& filesList)
1479   TRY
1480   {
1481     int nbPools = clientPrimServer.size();
1482     double ratio=0.5 ;
1483     ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1484
1485     int nFiles = filesList.size();
1486     vector<SDistFile> files(nFiles);
1487     vector<SDistGrid> grids;
1488     map<string,int> gridMap ;
1489     string gridId; 
1490     int gridIndex=0 ;
1491
1492     for (size_t i = 0; i < nFiles; ++i)
1493     {
1494       StdSize dataSize=0;
1495       CFile* file = filesList[i];
1496       std::vector<CField*> enabledFields = file->getEnabledFields();
1497       size_t numEnabledFields = enabledFields.size();
1498
1499       files[i].id_=file->getId() ;
1500       files[i].nbGrids_=numEnabledFields;
1501       files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1502         
1503       for (size_t j = 0; j < numEnabledFields; ++j)
1504       {
1505         gridId=enabledFields[j]->getGrid()->getId() ;
1506         if (gridMap.find(gridId)==gridMap.end())
1507         {
1508            gridMap[gridId]=gridIndex  ;
1509            SDistGrid newGrid; 
1510            grids.push_back(newGrid) ;
1511            gridIndex++ ;
1512         }
1513         files[i].assignedGrid_[j]=gridMap[gridId] ;
1514         grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1515         dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1516       }
1517       double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1518       files[i].bandwith_= dataSize/ outFreqSec ;
1519     }
1520
1521     double bandwith=0 ;
1522     double memory=0 ;
1523   
1524     for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1525     for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1526
1527     for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1528     for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1529       
1530     distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1531
1532     vector<double> memorySize(nbPools,0.) ;
1533     vector< set<int> > serverGrids(nbPools) ;
1534     vector<double> bandwithSize(nbPools,0.) ;
1535       
1536     for (size_t i = 0; i < nFiles; ++i)
1537     {
1538       bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1539       for(int j=0 ; j<files[i].nbGrids_;j++)
1540       {
1541         if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1542         {
1543           memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1544           serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1545         }
1546       }
1547       filesList[i]->setContextClient(clientPrimServer[files[i].assignedServer_]) ;
1548       delete [] files[i].assignedGrid_ ;
1549     }
1550
1551     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 ;
1552     for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1553
1554   }
1555   CATCH_DUMP_ATTR
1556
1557   /*!
1558      Find all files in write mode
1559   */
1560   void CContext::findEnabledWriteModeFiles(void)
1561   TRY
1562   {
1563     int size = this->enabledFiles.size();
1564     for (int i = 0; i < size; ++i)
1565     {
1566       if (enabledFiles[i]->mode.isEmpty() || 
1567          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1568        enabledWriteModeFiles.push_back(enabledFiles[i]);
1569     }
1570   }
1571   CATCH_DUMP_ATTR
1572
1573   /*!
1574      Find all files in read mode
1575   */
1576   void CContext::findEnabledReadModeFiles(void)
1577   TRY
1578   {
1579     int size = this->enabledFiles.size();
1580     for (int i = 0; i < size; ++i)
1581     {
1582       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1583        enabledReadModeFiles.push_back(enabledFiles[i]);
1584     }
1585   }
1586   CATCH_DUMP_ATTR
1587
1588   void CContext::closeAllFile(void)
1589   TRY
1590   {
1591     std::vector<CFile*>::const_iterator
1592            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
1593
1594     for (; it != end; it++)
1595     {
1596       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1597       (*it)->close();
1598     }
1599   }
1600   CATCH_DUMP_ATTR
1601
1602   /*!
1603   \brief Dispatch event received from client
1604      Whenever a message is received in buffer of server, it will be processed depending on
1605   its event type. A new event type should be added in the switch list to make sure
1606   it processed on server side.
1607   \param [in] event: Received message
1608   */
1609   bool CContext::dispatchEvent(CEventServer& event)
1610   TRY
1611   {
1612
1613      if (SuperClass::dispatchEvent(event)) return true;
1614      else
1615      {
1616        switch(event.type)
1617        {
1618           case EVENT_ID_CLOSE_DEFINITION :
1619             recvCloseDefinition(event);
1620             return true;
1621             break;
1622           case EVENT_ID_UPDATE_CALENDAR:
1623             recvUpdateCalendar(event);
1624             return true;
1625             break;
1626           case EVENT_ID_CREATE_FILE_HEADER :
1627             recvCreateFileHeader(event);
1628             return true;
1629             break;
1630           case EVENT_ID_COUPLER_IN_READY:
1631             recvCouplerInReady(event);
1632             return true;
1633             break;
1634           case EVENT_ID_COUPLER_IN_CLOSE_DEFINITION:
1635             recvCouplerInCloseDefinition(event);
1636             return true;
1637             break;
1638           case EVENT_ID_COUPLER_IN_CONTEXT_FINALIZED:
1639             recvCouplerInContextFinalized(event);
1640             return true;
1641             break; 
1642           default :
1643             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
1644                    <<"Unknown Event");
1645           return false;
1646         }
1647      }
1648   }
1649   CATCH
1650
1651   //! Client side: Send a message to server to make it close
1652   // ym obsolete
1653   void CContext::sendCloseDefinition(void)
1654   TRY
1655   {
1656    int nbSrvPools ;
1657    if (serviceType_==CServicesManager::CLIENT) nbSrvPools = 1 ;
1658    else if (serviceType_==CServicesManager::GATHERER) nbSrvPools = this->clientPrimServer.size() ;
1659    else nbSrvPools = 0 ;
1660    CContextClient* contextClientTmp ;
1661
1662    for (int i = 0; i < nbSrvPools; ++i)
1663     {
1664       if (serviceType_==CServicesManager::CLIENT) contextClientTmp = client ;
1665       else if (serviceType_==CServicesManager::GATHERER ) contextClientTmp = clientPrimServer[i] ;
1666       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1667       if (contextClientTmp->isServerLeader())
1668       {
1669         CMessage msg;
1670         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1671         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1672           event.push(*itRank,1,msg);
1673         contextClientTmp->sendEvent(event);
1674       }
1675       else contextClientTmp->sendEvent(event);
1676     }
1677   }
1678   CATCH_DUMP_ATTR
1679   
1680   //  ! Client side: Send a message to server to make it close
1681   void CContext::sendCloseDefinition(CContextClient* client)
1682   TRY
1683   {
1684      if (sendCloseDefinition_done_.count(client)!=0) return ;
1685      else sendCloseDefinition_done_.insert(client) ;
1686
1687      CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1688      if (client->isServerLeader())
1689      {
1690        CMessage msg;
1691        for(auto rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1692        client->sendEvent(event);
1693      }
1694     else client->sendEvent(event);
1695   }
1696   CATCH_DUMP_ATTR
1697
1698   //! Server side: Receive a message of client announcing a context close
1699   void CContext::recvCloseDefinition(CEventServer& event)
1700   TRY
1701   {
1702      CBufferIn* buffer=event.subEvents.begin()->buffer;
1703      getCurrent()->closeDefinition();
1704   }
1705   CATCH
1706
1707   //! Client side: Send a message to update calendar in each time step
1708   void CContext::sendUpdateCalendar(int step)
1709   TRY
1710   {
1711     CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1712     for(auto client : slaveServers_) 
1713     {
1714       if (client->isServerLeader())
1715       {
1716         CMessage msg;
1717         msg<<step;
1718         for (auto& rank : client->getRanksServerLeader() ) event.push(rank,1,msg);
1719         client->sendEvent(event);
1720       }
1721       else client->sendEvent(event);
1722     }
1723   }
1724   CATCH_DUMP_ATTR
1725
1726   //! Server side: Receive a message of client annoucing calendar update
1727   void CContext::recvUpdateCalendar(CEventServer& event)
1728   TRY
1729   {
1730      CBufferIn* buffer=event.subEvents.begin()->buffer;
1731      getCurrent()->recvUpdateCalendar(*buffer);
1732   }
1733   CATCH
1734
1735   //! Server side: Receive a message of client annoucing calendar update
1736   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1737   TRY
1738   {
1739      int step;
1740      buffer>>step;
1741      updateCalendar(step);
1742      if (serviceType_==CServicesManager::GATHERER)
1743      {       
1744        sendUpdateCalendar(step);
1745      }
1746   }
1747   CATCH_DUMP_ATTR
1748
1749   //! Client side: Send a message to create header part of netcdf file
1750   void CContext::sendCreateFileHeader(void)
1751   TRY
1752   {
1753     int nbSrvPools ;
1754     if (serviceType_==CServicesManager::CLIENT) nbSrvPools = 1 ;
1755     else if (serviceType_==CServicesManager::GATHERER) nbSrvPools = this->clientPrimServer.size() ;
1756     else nbSrvPools = 0 ;
1757     CContextClient* contextClientTmp ;
1758
1759     for (int i = 0; i < nbSrvPools; ++i)
1760     {
1761       if (serviceType_==CServicesManager::CLIENT) contextClientTmp = client ;
1762       else if (serviceType_==CServicesManager::GATHERER ) contextClientTmp = clientPrimServer[i] ;
1763       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1764
1765       if (contextClientTmp->isServerLeader())
1766       {
1767         CMessage msg;
1768         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1769         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1770           event.push(*itRank,1,msg) ;
1771         contextClientTmp->sendEvent(event);
1772       }
1773       else contextClientTmp->sendEvent(event);
1774     }
1775   }
1776   CATCH_DUMP_ATTR
1777
1778   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1779   void CContext::recvCreateFileHeader(CEventServer& event)
1780   TRY
1781   {
1782      CBufferIn* buffer=event.subEvents.begin()->buffer;
1783      getCurrent()->recvCreateFileHeader(*buffer);
1784   }
1785   CATCH
1786
1787   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1788   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1789   TRY
1790   {
1791      if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER) 
1792        createFileHeader();
1793   }
1794   CATCH_DUMP_ATTR
1795
1796   void CContext::createCouplerInterCommunicator(void)
1797   TRY
1798   {
1799      int rank=this->getIntraCommRank() ;
1800      map<string,list<CCouplerOut*>> listCouplerOut ; 
1801      map<string,list<CCouplerIn*>> listCouplerIn ; 
1802
1803      for(auto couplerOut : enabledCouplerOut) listCouplerOut[couplerOut->getCouplingContextId()].push_back(couplerOut) ;
1804      for(auto couplerIn : enabledCouplerIn) listCouplerIn[couplerIn->getCouplingContextId()].push_back(couplerIn) ;
1805
1806      CCouplerManager* couplerManager = CXios::getCouplerManager() ;
1807      if (rank==0)
1808      {
1809        for(auto couplerOut : listCouplerOut) couplerManager->registerCoupling(this->getContextId(),couplerOut.first) ;
1810        for(auto couplerIn : listCouplerIn) couplerManager->registerCoupling(couplerIn.first,this->getContextId()) ;
1811      }
1812
1813      do
1814      {
1815        for(auto couplerOut : listCouplerOut) 
1816        {
1817          bool isNextCoupling ;
1818          if (rank==0) isNextCoupling = couplerManager->isNextCoupling(this->getContextId(),couplerOut.first) ;
1819          MPI_Bcast(&isNextCoupling,1,MPI_C_BOOL, 0, getIntraComm()) ; 
1820          if (isNextCoupling) 
1821          {
1822            addCouplingChanel(couplerOut.first, true) ;
1823            listCouplerOut.erase(couplerOut.first) ;
1824            break ;
1825          }           
1826        }
1827        for(auto couplerIn : listCouplerIn) 
1828        {
1829          bool isNextCoupling ;
1830          if (rank==0) isNextCoupling = couplerManager->isNextCoupling(couplerIn.first,this->getContextId());
1831          MPI_Bcast(&isNextCoupling,1,MPI_C_BOOL, 0, getIntraComm()) ; 
1832          if (isNextCoupling) 
1833          {
1834            addCouplingChanel(couplerIn.first, false) ;
1835            listCouplerIn.erase(couplerIn.first) ;
1836            break ;
1837          }           
1838        }
1839
1840      } while (!listCouplerOut.empty() || !listCouplerIn.empty()) ;
1841
1842   }
1843   CATCH_DUMP_ATTR
1844
1845 
1846     //! Client side: Send infomation of active files (files are enabled to write out)
1847   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1848   TRY
1849   {
1850     int size = activeFiles.size();
1851
1852     // In a context, each type has a root definition, e.g: axis, domain, field.
1853     // Every object must be a child of one of these root definition. In this case
1854     // all new file objects created on server must be children of the root "file_definition"
1855     StdString fileDefRoot("file_definition");
1856     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1857
1858     for (int i = 0; i < size; ++i)
1859     {
1860       CFile* f = activeFiles[i];
1861       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1862       f->sendAllAttributesToServer(f->getContextClient());
1863       f->sendAddAllVariables(f->getContextClient());
1864     }
1865   }
1866   CATCH_DUMP_ATTR
1867
1868   //! Client side: Send information of active fields (ones are written onto files)
1869   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1870   TRY
1871   {
1872     int size = activeFiles.size();
1873     for (int i = 0; i < size; ++i)
1874     {
1875       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1876     }
1877   }
1878   CATCH_DUMP_ATTR
1879
1880 
1881   //! Client side: Prepare the timeseries by adding the necessary files
1882   void CContext::prepareTimeseries()
1883   TRY
1884   {
1885     const std::vector<CFile*> allFiles = CFile::getAll();
1886     for (size_t i = 0; i < allFiles.size(); i++)
1887     {
1888       CFile* file = allFiles[i];
1889
1890       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1891       for (size_t k = 0; k < vars.size(); k++)
1892       {
1893         CVariable* var = vars[k];
1894
1895         if (var->ts_target.isEmpty()
1896              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1897           fileVars.push_back(var);
1898
1899         if (!var->ts_target.isEmpty()
1900              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1901           fieldVars.push_back(var);
1902       }
1903
1904       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1905       {
1906         StdString fileNameStr("%file_name%") ;
1907         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1908         
1909         StdString fileName=file->getFileOutputName();
1910         size_t pos=tsPrefix.find(fileNameStr) ;
1911         while (pos!=std::string::npos)
1912         {
1913           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1914           pos=tsPrefix.find(fileNameStr) ;
1915         }
1916       
1917         const std::vector<CField*> allFields = file->getAllFields();
1918         for (size_t j = 0; j < allFields.size(); j++)
1919         {
1920           CField* field = allFields[j];
1921
1922           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1923           {
1924             CFile* tsFile = CFile::create();
1925             tsFile->duplicateAttributes(file);
1926
1927             // Add variables originating from file and targeted to timeserie file
1928             for (size_t k = 0; k < fileVars.size(); k++)
1929               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1930
1931           
1932             tsFile->name = tsPrefix + "_";
1933             if (!field->name.isEmpty())
1934               tsFile->name.get() += field->name;
1935             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1936               tsFile->name.get() += field->field_ref;
1937             else
1938               tsFile->name.get() += field->getId();
1939
1940             if (!field->ts_split_freq.isEmpty())
1941               tsFile->split_freq = field->ts_split_freq;
1942
1943             CField* tsField = tsFile->addField();
1944             tsField->field_ref = field->getId();
1945
1946             // Add variables originating from file and targeted to timeserie field
1947             for (size_t k = 0; k < fieldVars.size(); k++)
1948               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1949
1950             vars = field->getAllVariables();
1951             for (size_t k = 0; k < vars.size(); k++)
1952             {
1953               CVariable* var = vars[k];
1954
1955               // Add variables originating from field and targeted to timeserie field
1956               if (var->ts_target.isEmpty()
1957                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1958                 tsField->getVirtualVariableGroup()->addChild(var);
1959
1960               // Add variables originating from field and targeted to timeserie file
1961               if (!var->ts_target.isEmpty()
1962                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1963                 tsFile->getVirtualVariableGroup()->addChild(var);
1964             }
1965
1966             tsFile->solveFieldRefInheritance(true);
1967
1968             if (file->timeseries == CFile::timeseries_attr::exclusive)
1969               field->enabled = false;
1970           }
1971         }
1972
1973         // Finally disable the original file is need be
1974         if (file->timeseries == CFile::timeseries_attr::only)
1975          file->enabled = false;
1976       }
1977     }
1978   }
1979   CATCH_DUMP_ATTR
1980
1981 
1982   //! Client side: Send information of reference domain, axis and scalar of active fields
1983   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
1984   TRY
1985   {
1986     std::set<pair<StdString,CContextClient*>> domainIds, axisIds, scalarIds;
1987
1988     // Find all reference domain and axis of all active fields
1989     int numEnabledFiles = activeFiles.size();
1990     for (int i = 0; i < numEnabledFiles; ++i)
1991     {
1992       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
1993       int numEnabledFields = enabledFields.size();
1994       for (int j = 0; j < numEnabledFields; ++j)
1995       {
1996         CContextClient* contextClient=enabledFields[j]->getContextClient() ;
1997         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1998         if ("" != prDomAxisScalarId[0]) domainIds.insert(make_pair(prDomAxisScalarId[0],contextClient));
1999         if ("" != prDomAxisScalarId[1]) axisIds.insert(make_pair(prDomAxisScalarId[1],contextClient));
2000         if ("" != prDomAxisScalarId[2]) scalarIds.insert(make_pair(prDomAxisScalarId[2],contextClient));
2001       }
2002     }
2003
2004     // Create all reference axis on server side
2005     std::set<StdString>::iterator itDom, itAxis, itScalar;
2006     std::set<StdString>::const_iterator itE;
2007
2008     StdString scalarDefRoot("scalar_definition");
2009     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
2010     
2011     for (auto itScalar = scalarIds.begin(); itScalar != scalarIds.end(); ++itScalar)
2012     {
2013       if (!itScalar->first.empty())
2014       {
2015         scalarPtr->sendCreateChild(itScalar->first,itScalar->second);
2016         CScalar::get(itScalar->first)->sendAllAttributesToServer(itScalar->second);
2017       }
2018     }
2019
2020     StdString axiDefRoot("axis_definition");
2021     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
2022     
2023     for (auto itAxis = axisIds.begin(); itAxis != axisIds.end(); ++itAxis)
2024     {
2025       if (!itAxis->first.empty())
2026       {
2027         axisPtr->sendCreateChild(itAxis->first, itAxis->second);
2028         CAxis::get(itAxis->first)->sendAllAttributesToServer(itAxis->second);
2029       }
2030     }
2031
2032     // Create all reference domains on server side
2033     StdString domDefRoot("domain_definition");
2034     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
2035     
2036     for (auto itDom = domainIds.begin(); itDom != domainIds.end(); ++itDom)
2037     {
2038       if (!itDom->first.empty()) {
2039          domPtr->sendCreateChild(itDom->first, itDom->second);
2040          CDomain::get(itDom->first)->sendAllAttributesToServer(itDom->second);
2041       }
2042     }
2043   }
2044   CATCH_DUMP_ATTR
2045
2046   void CContext::triggerLateFields(void)
2047   TRY
2048   {
2049    for(auto& field : fileInFields_) field->triggerLateField() ;
2050    for(auto& field : couplerInFields_) field->triggerLateField() ;
2051   }
2052   CATCH_DUMP_ATTR
2053
2054   //! Update calendar in each time step
2055   void CContext::updateCalendar(int step)
2056   TRY
2057   {
2058      int prevStep = calendar->getStep();
2059
2060      if (prevStep < step)
2061      {
2062        if (serviceType_==CServicesManager::CLIENT) // For now we only use server level 1 to read data
2063        {
2064          triggerLateFields();
2065        }
2066
2067        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
2068        calendar->update(step);
2069        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
2070  #ifdef XIOS_MEMTRACK_LIGHT
2071        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
2072  #endif
2073
2074        if (serviceType_==CServicesManager::CLIENT) // For now we only use server level 1 to read data
2075        {
2076          doPostTimestepOperationsForEnabledReadModeFiles();
2077          garbageCollector.invalidate(calendar->getCurrentDate());
2078        }
2079      }
2080      else if (prevStep == step)
2081        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
2082      else // if (prevStep > step)
2083        ERROR("void CContext::updateCalendar(int step)",
2084              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
2085   }
2086   CATCH_DUMP_ATTR
2087
2088   void CContext::initReadFiles(void)
2089   TRY
2090   {
2091      vector<CFile*>::const_iterator it;
2092
2093      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
2094      {
2095         (*it)->initRead();
2096      }
2097   }
2098   CATCH_DUMP_ATTR
2099
2100   //! Server side: Create header of netcdf file
2101   void CContext::createFileHeader(void)
2102   TRY
2103   {
2104      vector<CFile*>::const_iterator it;
2105
2106      //for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
2107      for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
2108      {
2109         (*it)->initWrite();
2110      }
2111   }
2112   CATCH_DUMP_ATTR
2113
2114   //! Get current context
2115   CContext* CContext::getCurrent(void)
2116   TRY
2117   {
2118     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
2119   }
2120   CATCH
2121
2122   /*!
2123   \brief Set context with an id be the current context
2124   \param [in] id identity of context to be set to current
2125   */
2126   void CContext::setCurrent(const string& id)
2127   TRY
2128   {
2129     CObjectFactory::SetCurrentContextId(id);
2130     CGroupFactory::SetCurrentContextId(id);
2131   }
2132   CATCH
2133
2134  /*!
2135  \brief Create a context with specific id
2136  \param [in] id identity of new context
2137  \return pointer to the new context or already-existed one with identity id
2138  */
2139  CContext* CContext::create(const StdString& id)
2140  TRY
2141  {
2142    CContext::setCurrent(id);
2143
2144    bool hasctxt = CContext::has(id);
2145    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
2146    getRoot();
2147    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
2148
2149#define DECLARE_NODE(Name_, name_) \
2150    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
2151#define DECLARE_NODE_PAR(Name_, name_)
2152#include "node_type.conf"
2153
2154    return (context);
2155  }
2156  CATCH
2157
2158 
2159  void CContext::sendFinalizeClient(CContextClient* contextClient, const string& contextClientId)
2160  TRY
2161  {
2162    CEventClient event(getType(),EVENT_ID_CONTEXT_FINALIZE_CLIENT);
2163    if (contextClient->isServerLeader())
2164    {
2165      CMessage msg;
2166      msg<<contextClientId ;
2167      const std::list<int>& ranks = contextClient->getRanksServerLeader();
2168      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2169           event.push(*itRank,1,msg);
2170      contextClient->sendEvent(event);
2171    }
2172    else contextClient->sendEvent(event);
2173  }
2174  CATCH_DUMP_ATTR
2175
2176 
2177  void CContext::recvFinalizeClient(CEventServer& event)
2178  TRY
2179  {
2180    CBufferIn* buffer=event.subEvents.begin()->buffer;
2181    string id;
2182    *buffer>>id;
2183    get(id)->recvFinalizeClient(*buffer);
2184  }
2185  CATCH
2186
2187  void CContext::recvFinalizeClient(CBufferIn& buffer)
2188  TRY
2189  {
2190    countChildContextFinalized_++ ;
2191  }
2192  CATCH_DUMP_ATTR
2193
2194
2195
2196
2197 //! Client side: Send a message  announcing that context can receive grid definition from coupling
2198   void CContext::sendCouplerInReady(CContextClient* client)
2199   TRY
2200   {
2201      if (sendCouplerInReady_done_.count(client)!=0) return ;
2202      else sendCouplerInReady_done_.insert(client) ;
2203
2204      CEventClient event(getType(),EVENT_ID_COUPLER_IN_READY);
2205
2206      if (client->isServerLeader())
2207      {
2208        CMessage msg;
2209        msg<<this->getId();
2210        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2211        client->sendEvent(event);
2212      }
2213      else client->sendEvent(event);
2214   }
2215   CATCH_DUMP_ATTR
2216
2217   //! Server side: Receive a message announcing that context can send grid definition for context coupling
2218   void CContext::recvCouplerInReady(CEventServer& event)
2219   TRY
2220   {
2221      CBufferIn* buffer=event.subEvents.begin()->buffer;
2222      getCurrent()->recvCouplerInReady(*buffer);
2223   }
2224   CATCH
2225
2226   //! Server side: Receive a message announcing that context can send grid definition for context coupling
2227   void CContext::recvCouplerInReady(CBufferIn& buffer)
2228   TRY
2229   {
2230      string contextId ;
2231      buffer>>contextId;
2232      couplerInReady_.insert(getCouplerOutClient(contextId)) ;
2233   }
2234   CATCH_DUMP_ATTR
2235
2236
2237
2238
2239
2240 //! Client side: Send a message  announcing that a coupling context have done it closeDefinition, so data can be sent now.
2241   void CContext::sendCouplerInCloseDefinition(CContextClient* client)
2242   TRY
2243   {
2244      if (sendCouplerInCloseDefinition_done_.count(client)!=0) return ;
2245      else sendCouplerInCloseDefinition_done_.insert(client) ;
2246
2247      CEventClient event(getType(),EVENT_ID_COUPLER_IN_CLOSE_DEFINITION);
2248
2249      if (client->isServerLeader())
2250      {
2251        CMessage msg;
2252        msg<<this->getId();
2253        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2254        client->sendEvent(event);
2255      }
2256      else client->sendEvent(event);
2257   }
2258   CATCH_DUMP_ATTR
2259
2260   //! Server side: Receive a message announcing that a coupling context have done it closeDefinition, so data can be sent now.
2261   void CContext::recvCouplerInCloseDefinition(CEventServer& event)
2262   TRY
2263   {
2264      CBufferIn* buffer=event.subEvents.begin()->buffer;
2265      getCurrent()->recvCouplerInCloseDefinition(*buffer);
2266   }
2267   CATCH
2268
2269   //! Server side: Receive a message announcing that a coupling context have done it closeDefinition, so data can be sent now.
2270   void CContext::recvCouplerInCloseDefinition(CBufferIn& buffer)
2271   TRY
2272   {
2273      string contextId ;
2274      buffer>>contextId;
2275      couplerInCloseDefinition_.insert(getCouplerOutClient(contextId)) ;
2276   }
2277   CATCH_DUMP_ATTR
2278
2279
2280
2281
2282//! Client side: Send a message  announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2283   void CContext::sendCouplerInContextFinalized(CContextClient* client)
2284   TRY
2285   {
2286      if (sendCouplerInContextFinalized_done_.count(client)!=0) return ;
2287      else sendCouplerInContextFinalized_done_.insert(client) ;
2288
2289      CEventClient event(getType(),EVENT_ID_COUPLER_IN_CONTEXT_FINALIZED);
2290
2291      if (client->isServerLeader())
2292      {
2293        CMessage msg;
2294        msg<<this->getId();
2295        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2296        client->sendEvent(event);
2297      }
2298      else client->sendEvent(event);
2299   }
2300   CATCH_DUMP_ATTR
2301
2302   //! Server side: Receive a message announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2303   void CContext::recvCouplerInContextFinalized(CEventServer& event)
2304   TRY
2305   {
2306      CBufferIn* buffer=event.subEvents.begin()->buffer;
2307      getCurrent()->recvCouplerInContextFinalized(*buffer);
2308   }
2309   CATCH
2310
2311   //! Server side: Receive a message announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2312   void CContext::recvCouplerInContextFinalized(CBufferIn& buffer)
2313   TRY
2314   {
2315      string contextId ;
2316      buffer>>contextId;
2317      couplerInContextFinalized_.insert(getCouplerOutClient(contextId)) ;
2318   }
2319   CATCH_DUMP_ATTR
2320
2321
2322
2323
2324  /*!
2325  * \fn bool CContext::isFinalized(void)
2326  * Context is finalized if it received context post finalize event.
2327  */
2328  bool CContext::isFinalized(void)
2329  TRY
2330  {
2331    return finalized;
2332  }
2333  CATCH_DUMP_ATTR
2334  ///--------------------------------------------------------------
2335  StdString CContext::dumpClassAttributes(void)
2336  {
2337    StdString str;
2338    str.append("enabled files=\"");
2339    int size = this->enabledFiles.size();
2340    for (int i = 0; i < size; ++i)
2341    {
2342      str.append(enabledFiles[i]->getId());
2343      str.append(" ");
2344    }
2345    str.append("\"");
2346    return str;
2347  }
2348
2349} // namespace xios
Note: See TracBrowser for help on using the repository browser.