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

Last change on this file since 2337 was 2337, checked in by jderouillat, 2 years ago

Set enabled to false for fields contained in disabled files. solveRefInheritance is operated after to propagate this attribure and so to deactivate, in the workflow, read_access field which could require data included in disabled file.

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