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

Last change on this file since 2423 was 2423, checked in by jderouillat, 18 months ago

Introduce partially trunk's developement to manage N2 servers (especially to put in order the send of closeDefinition to N2 servers)

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