source: XIOS3/branches/xios-3.0-beta/src/node/context.cpp @ 2427

Last change on this file since 2427 was 2427, checked in by jderouillat, 19 months ago

Backport the system to log the memory consumption (commit ID [2418-2420,2425-2426])

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