source: XIOS3/trunk/src/node/context.cpp @ 2397

Last change on this file since 2397 was 2397, checked in by ymipsl, 22 months ago
  • Optimize remote connector computation in case of read (reverse way).
  • don't compute anymore clientFromServerConnector (and all intermediate computation) for non reading case.

YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
File size: 82.1 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     
643      }
644    }
645  }
646  CATCH_DUMP_ATTR
647
648  void CContext::globalEventLoop(void)
649  {
650    lockContext() ;
651    CXios::getDaemonsManager()->eventLoop() ;
652    unlockContext() ;
653    setCurrent(getId()) ;
654  }
655
656  bool CContext::scheduledEventLoop(bool enableEventsProcessing) 
657  {
658    bool out, finished; 
659    size_t timeLine=timeLine_ ;
660    if (serviceType_==CServicesManager::CLIENT)
661    {
662      timeLine_++ ;
663      eventScheduler_->registerEvent(timeLine, hashId_) ;
664    }
665
666    do
667    { 
668      finished=eventLoop(enableEventsProcessing) ;
669      if (serviceType_==CServicesManager::CLIENT) 
670      { 
671        out = eventScheduler_->queryEvent(timeLine,hashId_) ;
672        if (out) eventScheduler_->popEvent() ;
673      }
674
675      else out=true ;
676    }  while(!out) ;
677   
678    return finished ;
679  }
680
681  bool CContext::eventLoop(bool enableEventsProcessing)
682  {
683    bool  finished(true); 
684    if (isLockedContext()) enableEventsProcessing=false;
685   
686    setCurrent(getId()) ;
687
688    if (client!=nullptr && !finalized) client->eventLoop();
689   
690    for (int i = 0; i < clientPrimServer.size(); ++i)
691    {
692      if (!finalized) clientPrimServer[i]->eventLoop();
693      if (!finalized) finished &= serverPrimServer[i]->eventLoop(enableEventsProcessing);
694    }
695
696    for (auto couplerOut : couplerOutClient_)
697      if (!finalized) couplerOut.second->eventLoop();
698   
699    for (auto couplerIn : couplerInClient_)
700      if (!finalized) couplerIn.second->eventLoop();
701   
702    for (auto couplerOut : couplerOutServer_)
703      if (!finalized) couplerOut.second->eventLoop(enableEventsProcessing);
704
705    for (auto couplerIn : couplerInServer_)
706      if (!finalized) couplerIn.second->eventLoop(enableEventsProcessing);
707   
708    if (server!=nullptr) if (!finalized) finished &= server->eventLoop(enableEventsProcessing);
709    setCurrent(getId()) ;
710    return finalized && finished ;
711  }
712
713  void CContext::addCouplingChanel(const std::string& fullContextId, bool out)
714  {
715     int contextLeader ;
716     
717     if (out)
718     { 
719       if (couplerOutClient_.find(fullContextId)==couplerOutClient_.end()) 
720       {
721         bool ok=CXios::getContextsManager()->getContextLeader(fullContextId, contextLeader, getIntraComm()) ;
722     
723         MPI_Comm interComm, interCommClient, interCommServer  ;
724         MPI_Comm intraCommClient, intraCommServer ;
725
726         if (ok) MPI_Intercomm_create(getIntraComm(), 0, CXios::getXiosComm(), contextLeader, 0, &interComm) ;
727
728        MPI_Comm_dup(intraComm_, &intraCommClient) ;
729        MPI_Comm_dup(intraComm_, &intraCommServer) ;
730        MPI_Comm_dup(interComm, &interCommClient) ;
731        MPI_Comm_dup(interComm, &interCommServer) ;
732        CContextClient* client = CContextClient::getNew(this, intraCommClient, interCommClient);
733        CContextServer* server = CContextServer::getNew(this, intraCommServer, interCommServer);
734        client->setAssociatedServer(server) ;
735        server->setAssociatedClient(client) ;
736        MPI_Comm_free(&interComm) ;
737        couplerOutClient_[fullContextId] = client ;
738        couplerOutServer_[fullContextId] = server ;
739      }
740    }
741    else if (couplerInClient_.find(fullContextId)==couplerInClient_.end())
742    {
743      bool ok=CXios::getContextsManager()->getContextLeader(fullContextId, contextLeader, getIntraComm()) ;
744     
745       MPI_Comm interComm, interCommClient, interCommServer  ;
746       MPI_Comm intraCommClient, intraCommServer ;
747
748       if (ok) MPI_Intercomm_create(getIntraComm(), 0, CXios::getXiosComm(), contextLeader, 0, &interComm) ;
749
750       MPI_Comm_dup(intraComm_, &intraCommClient) ;
751       MPI_Comm_dup(intraComm_, &intraCommServer) ;
752       MPI_Comm_dup(interComm, &interCommServer) ;
753       MPI_Comm_dup(interComm, &interCommClient) ;
754       CContextServer* server = CContextServer::getNew(this, intraCommServer, interCommServer);
755       CContextClient* client = CContextClient::getNew(this, intraCommClient, interCommClient);
756       client->setAssociatedServer(server) ;
757       server->setAssociatedClient(client) ;
758       MPI_Comm_free(&interComm) ;
759
760       couplerInClient_[fullContextId] = client ;
761       couplerInServer_[fullContextId] = server ;       
762    }
763  }
764 
765   void CContext::finalize(void)
766   TRY
767   {
768      registryOut->hierarchicalGatherRegistry() ;
769      if (server->getIntraCommRank()==0) CXios::getRegistryManager()->merge(*registryOut) ;
770
771      if (serviceType_==CServicesManager::CLIENT)
772      {
773//ym        doPreTimestepOperationsForEnabledReadModeFiles(); // For now we only use server level 1 to read data
774
775        triggerLateFields() ;
776
777        // inform couplerIn that I am finished
778        for(auto& couplerInClient : couplerInClient_) sendCouplerInContextFinalized(couplerInClient.second) ;
779
780        // wait until received message from couplerOut that they have finished
781        bool couplersInFinalized ;
782        do
783        {
784          couplersInFinalized=true ;
785          for(auto& couplerOutClient : couplerOutClient_) couplersInFinalized &= isCouplerInContextFinalized(couplerOutClient.second) ; 
786          globalEventLoop() ;
787        } while (!couplersInFinalized) ;
788
789        info(100)<<"DEBUG: context "<<getId()<<" Send client finalize"<<endl ;
790        client->finalize();
791        info(100)<<"DEBUG: context "<<getId()<<" Client finalize sent"<<endl ;
792        while (client->havePendingRequests()) client->eventLoop();
793        info(100)<<"DEBUG: context "<<getId()<<" no pending request ok"<<endl ;
794        bool notifiedFinalized=false ;
795        do
796        {
797          notifiedFinalized=client->isNotifiedFinalized() ;
798        } while (!notifiedFinalized) ;
799
800        server->releaseBuffers();
801        client->releaseBuffers();
802        info(100)<<"DEBUG: context "<<getId()<<" release client ok"<<endl ;
803      }
804      else if (serviceType_==CServicesManager::GATHERER)
805      {
806         for (int i = 0; i < clientPrimServer.size(); ++i)
807         {
808           clientPrimServer[i]->finalize();
809           bool bufferReleased;
810           do
811           {
812             clientPrimServer[i]->eventLoop();
813             bufferReleased = !clientPrimServer[i]->havePendingRequests();
814           } while (!bufferReleased);
815           
816           bool notifiedFinalized=false ;
817           do
818           {
819             notifiedFinalized=clientPrimServer[i]->isNotifiedFinalized() ;
820           } while (!notifiedFinalized) ;
821           clientPrimServer[i]->releaseBuffers();
822         }
823         closeAllFile();
824
825      }
826      else if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER)
827      {
828        closeAllFile();
829        client->releaseBuffers();
830        server->releaseBuffers();
831      }
832
833      freeComms() ;
834       
835      parentServerContext_->freeComm() ;
836      finalized = true;
837      info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
838   }
839   CATCH_DUMP_ATTR
840
841   //! Free internally allocated communicators
842   void CContext::freeComms(void)
843   TRY
844   {
845     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
846       MPI_Comm_free(&(*it));
847     comms.clear();
848   }
849   CATCH_DUMP_ATTR
850
851   //! Deallocate buffers allocated by clientContexts
852   void CContext::releaseClientBuffers(void)
853   TRY
854   {
855     client->releaseBuffers();
856     for (int i = 0; i < clientPrimServer.size(); ++i)
857       clientPrimServer[i]->releaseBuffers();
858   }
859   CATCH_DUMP_ATTR
860
861   
862   /*!
863   \brief Close all the context defintion and do processing data
864      After everything is well defined on client side, they will be processed and sent to server
865   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
866   all necessary information to server, from which each server can build its own database.
867   Because the role of server is to write out field data on a specific netcdf file,
868   the only information that it needs is the enabled files
869   and the active fields (fields will be written onto active files)
870   */
871  void CContext::closeDefinition(void)
872   TRY
873   {
874     CTimer::get("Context : close definition").resume() ;
875     
876     // create intercommunicator with servers.
877     // not sure it is the good place to be called here
878     createServerInterComm() ;
879
880
881     // After xml is parsed, there are some more works with post processing
882//     postProcessing();
883
884   
885    // Make sure the calendar was correctly created
886    if (serviceType_!=CServicesManager::CLIENT) CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
887    if (!calendar)
888      ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
889    else if (calendar->getTimeStep() == NoneDu)
890      ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
891    // Calendar first update to set the current date equals to the start date
892    calendar->update(0);
893
894    // Résolution des héritages descendants (càd des héritages de groupes)
895    // pour chacun des contextes.
896    solveDescInheritance(true);
897 
898    // Check if some axis, domains or grids are eligible to for compressed indexed output.
899    // Warning: This must be done after solving the inheritance and before the rest of post-processing
900    // --> later ????    checkAxisDomainsGridsEligibilityForCompressedOutput();     
901
902      // Check if some automatic time series should be generated
903      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
904
905    // The timeseries should only be prepared in client
906    prepareTimeseries();
907
908    //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
909    findEnabledFiles();
910
911    // Solve inheritance for field to know if enabled or not.
912    for (auto field : CField::getAll()) field->solveRefInheritance();
913
914    findEnabledWriteModeFiles();
915    findEnabledReadModeFiles();
916    findEnabledCouplerIn();
917    findEnabledCouplerOut();
918    createCouplerInterCommunicator() ;
919
920    // Find all enabled fields of each file     
921    vector<CField*>&& fileOutField = findAllEnabledFieldsInFileOut(this->enabledWriteModeFiles);
922    vector<CField*>&& fileInField = findAllEnabledFieldsInFileIn(this->enabledReadModeFiles);
923    vector<CField*>&& couplerOutField = findAllEnabledFieldsCouplerOut(this->enabledCouplerOut);
924    vector<CField*>&& couplerInField = findAllEnabledFieldsCouplerIn(this->enabledCouplerIn);
925    findFieldsWithReadAccess();
926    vector<CField*>& fieldWithReadAccess = fieldsWithReadAccess_ ;
927    vector<CField*> fieldModelIn ; // fields potentially from model
928
929    // define if files are on clientSied or serverSide
930    if (serviceType_==CServicesManager::CLIENT)
931    {
932      for (auto& file : enabledWriteModeFiles) file->setClientSide() ;
933      for (auto& file : enabledReadModeFiles) file->setClientSide() ;
934    }
935    else
936    {
937      for (auto& file : enabledWriteModeFiles) file->setServerSide() ;
938      for (auto& file : enabledReadModeFiles) file->setServerSide() ;
939    }
940
941   
942    for (auto& field : couplerInField)
943    {
944      field->unsetGridCompleted() ;
945    }
946// find all field potentially at workflow end
947    vector<CField*> endWorkflowFields ;
948    endWorkflowFields.reserve(fileOutField.size()+couplerOutField.size()+fieldWithReadAccess.size()) ;
949    endWorkflowFields.insert(endWorkflowFields.end(),fileOutField.begin(), fileOutField.end()) ;
950    endWorkflowFields.insert(endWorkflowFields.end(),couplerOutField.begin(), couplerOutField.end()) ;
951    endWorkflowFields.insert(endWorkflowFields.end(),fieldWithReadAccess.begin(), fieldWithReadAccess.end()) ;
952
953    bool workflowGraphIsCompleted ;
954   
955    bool first=true ;
956   
957    do
958    {
959      workflowGraphIsCompleted=true; 
960      for(auto endWorkflowField : endWorkflowFields) 
961      {
962        workflowGraphIsCompleted &= endWorkflowField->buildWorkflowGraph(garbageCollector) ;
963      }
964   
965      for(auto couplerIn : enabledCouplerIn) couplerIn->assignContext() ;
966      for(auto field : couplerInField) field->makeGridAliasForCoupling();
967      for(auto field : couplerInField) this->sendCouplerInReady(field->getContextClient()) ;
968   
969
970      // assign context to coupler out and related fields
971      for(auto couplerOut : enabledCouplerOut) couplerOut->assignContext() ;
972      // for now supose that all coupling out endpoint are succesfull. The difficultie is client/server buffer evaluation
973      for(auto field : couplerOutField) 
974      {
975        // connect to couplerOut -> to do
976      }
977
978      bool couplersReady ;
979      do 
980      {
981        couplersReady=true ;
982        for(auto field : couplerOutField)
983        {
984          bool ready = isCouplerInReady(field->getContextClient()) ; 
985          if (ready) field->sendFieldToCouplerOut() ;
986          couplersReady &= ready ;
987        }
988        this->scheduledEventLoop() ;
989
990      } while (!couplersReady) ;
991     
992      first=false ;
993      this->scheduledEventLoop() ;
994
995    } while (!workflowGraphIsCompleted) ;
996
997
998    for( auto field : couplerInField) couplerInFields_.push_back(field) ;
999
1000    // get all field coming potentially from model
1001    for (auto field : CField::getAll() ) if (field->getModelIn()) fieldModelIn.push_back(field) ;
1002
1003    // Distribute files between secondary servers according to the data size => assign a context to a file and then to fields
1004    if (serviceType_==CServicesManager::GATHERER) distributeFiles(this->enabledWriteModeFiles);
1005    else if (serviceType_==CServicesManager::CLIENT) for(auto file : this->enabledWriteModeFiles) file->setContextClient(client) ;
1006
1007    // client side, assign context for file reading
1008    if (serviceType_==CServicesManager::CLIENT) for(auto file : this->enabledReadModeFiles) file->setContextClient(client) ;
1009   
1010    // server side, assign context where to send file data read
1011    if (serviceType_==CServicesManager::CServicesManager::GATHERER || serviceType_==CServicesManager::IO_SERVER) 
1012      for(auto file : this->enabledReadModeFiles) file->setContextClient(client) ;
1013   
1014
1015    // workflow startpoint => data from server on client side
1016    // important : sendFieldToInputFileServer must be done prior sendFieldToFileServer because for the first case the grid remoteConnectorIn
1017    //             and grid remoteConnectorOut will be computed, and in the second case only the remoteConnectorOut.
1018    if (serviceType_==CServicesManager::CLIENT)
1019    {
1020      for(auto field : fileInField) 
1021      {
1022        field->sendFieldToInputFileServer() ;
1023        field->connectToServerInput(garbageCollector) ; // connect the field to server filter
1024        fileInFields_.push_back(field) ;
1025      }
1026    }
1027
1028    // workflow endpoint => sent to IO/SERVER
1029    if (serviceType_==CServicesManager::CLIENT || serviceType_==CServicesManager::GATHERER)
1030    {
1031      for(auto field : fileOutField) 
1032      {
1033        field->connectToFileServer(garbageCollector) ; // connect the field to server filter
1034      }
1035      for(auto field : fileOutField) field->sendFieldToFileServer() ;
1036    }
1037
1038    // workflow endpoint => write to file
1039    if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER)
1040    {
1041      for(auto field : fileOutField) 
1042      {
1043        field->connectToFileWriter(garbageCollector) ; // connect the field to server filter
1044      }
1045    }
1046   
1047    // workflow endpoint => Send data from server to client
1048    if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::GATHERER)
1049    {
1050      for(auto field : fileInField) 
1051      {
1052        field->connectToServerToClient(garbageCollector) ;
1053      }
1054    }
1055
1056    // workflow endpoint => sent to model on client side
1057    if (serviceType_==CServicesManager::CLIENT)
1058    {
1059      for(auto field : fieldWithReadAccess) field->connectToModelOutput(garbageCollector) ;
1060    }
1061
1062
1063    // workflow startpoint => data from model
1064    if (serviceType_==CServicesManager::CLIENT)
1065    {
1066      for(auto field : fieldModelIn) 
1067      {
1068        field->connectToModelInput(garbageCollector) ; // connect the field to server filter
1069        // grid index will be computed on the fly
1070      }
1071    }
1072   
1073    // workflow startpoint => data from client on server side
1074    if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::GATHERER || serviceType_==CServicesManager::OUT_SERVER)
1075    {
1076      for(auto field : fieldModelIn) 
1077      {
1078        field->connectToClientInput(garbageCollector) ; // connect the field to server filter
1079      }
1080    }
1081
1082   
1083    for(auto field : couplerInField) 
1084    {
1085      field->connectToCouplerIn(garbageCollector) ; // connect the field to server filter
1086    }
1087   
1088   
1089    for(auto field : couplerOutField) 
1090    {
1091      field->connectToCouplerOut(garbageCollector) ; // for now the same kind of filter that for file server
1092    }
1093
1094    // workflow startpoint => data read from file on server side
1095    if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::GATHERER)
1096    {
1097      for(auto field : fileInField) 
1098      {
1099        field->connectToFileReader(garbageCollector) ;
1100      }
1101    }
1102   
1103    // construct slave server list
1104    if (serviceType_==CServicesManager::CLIENT) 
1105    {
1106      for(auto field : fileOutField) slaveServers_.insert(field->getContextClient()) ; 
1107      for(auto field : fileInField) slaveServers_.insert(field->getContextClient()) ; 
1108    }
1109    else if (serviceType_==CServicesManager::GATHERER) 
1110      for(auto field : fileOutField) slaveServers_.insert(field->getContextClient()) ; 
1111
1112    for(auto& slaveServer : slaveServers_) sendCloseDefinition(slaveServer) ;
1113
1114    if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER) 
1115    {
1116      createFileHeader();
1117    }
1118
1119    if (serviceType_==CServicesManager::CLIENT) startPrefetchingOfEnabledReadModeFiles();
1120   
1121    // send signal to couplerIn context that definition phasis is done
1122
1123    for(auto& couplerInClient : couplerInClient_) sendCouplerInCloseDefinition(couplerInClient.second) ;
1124
1125    // wait until all couplerIn signal that closeDefition is done.
1126    bool ok;
1127    do
1128    {
1129      ok = true ;
1130      for(auto& couplerOutClient : couplerOutClient_) ok &= isCouplerInCloseDefinition(couplerOutClient.second) ;
1131      this->scheduledEventLoop() ;
1132    } while (!ok) ;
1133
1134    // Now evaluate the size of the context client buffers
1135    map<CContextClient*,map<int,size_t>> fieldBufferEvaluation ;
1136    for(auto field : fileOutField) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // output to server
1137    for(auto field : couplerOutField) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // output to coupler
1138    for(auto field : fileInField) field->evaluateBufferSize(fieldBufferEvaluation, CXios::isOptPerformance) ; // server to client (for io servers)
1139   
1140    // fix size for each context client
1141    for(auto& it : fieldBufferEvaluation) it.first->setBufferSize(it.second) ;
1142
1143
1144     CTimer::get("Context : close definition").suspend() ;
1145  }
1146  CATCH_DUMP_ATTR
1147
1148
1149  vector<CField*> CContext::findAllEnabledFieldsInFileOut(const std::vector<CFile*>& activeFiles)
1150   TRY
1151   {
1152     vector<CField*> fields ;
1153     for(auto file : activeFiles)
1154     {
1155        const vector<CField*>&& fieldList=file->getEnabledFields() ;
1156        for(auto field : fieldList) field->setFileOut(file) ;
1157        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1158     }
1159     return fields ;
1160   }
1161   CATCH_DUMP_ATTR
1162
1163   vector<CField*> CContext::findAllEnabledFieldsInFileIn(const std::vector<CFile*>& activeFiles)
1164   TRY
1165   {
1166     vector<CField*> fields ;
1167     for(auto file : activeFiles)
1168     {
1169        const vector<CField*>&& fieldList=file->getEnabledFields() ;
1170        for(auto field : fieldList) field->setFileIn(file) ;
1171        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1172     }
1173     return fields ;
1174   }
1175   CATCH_DUMP_ATTR
1176
1177   vector<CField*> CContext::findAllEnabledFieldsCouplerOut(const std::vector<CCouplerOut*>& activeCouplerOut)
1178   TRY
1179   {
1180     vector<CField*> fields ;
1181     for (auto couplerOut :activeCouplerOut)
1182     {
1183        const vector<CField*>&& fieldList=couplerOut->getEnabledFields() ;
1184        for(auto field : fieldList) field->setCouplerOut(couplerOut) ;
1185        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1186     }
1187     return fields ;
1188   }
1189   CATCH_DUMP_ATTR
1190
1191   vector<CField*> CContext::findAllEnabledFieldsCouplerIn(const std::vector<CCouplerIn*>& activeCouplerIn)
1192   TRY
1193   {
1194     vector<CField*> fields ;
1195     for (auto couplerIn :activeCouplerIn)
1196     {
1197        const vector<CField*>&& fieldList=couplerIn->getEnabledFields() ;
1198        for(auto field : fieldList) field->setCouplerIn(couplerIn) ;
1199        fields.insert(fields.end(),fieldList.begin(),fieldList.end());
1200     }
1201     return fields ;
1202   }
1203   CATCH_DUMP_ATTR
1204
1205 /*!
1206  * Send context attribute and calendar to file server, it must be done once by context file server
1207  * \param[in] client : context client to send   
1208  */ 
1209  void CContext::sendContextToFileServer(CContextClient* client)
1210  {
1211    if (sendToFileServer_done_.count(client)!=0) return ;
1212    else sendToFileServer_done_.insert(client) ;
1213   
1214    this->sendAllAttributesToServer(client); // Send all attributes of current context to server
1215    CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer(client); // Send all attributes of current cale
1216  }
1217
1218 
1219   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
1220   TRY
1221   {
1222      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1223        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
1224   }
1225   CATCH_DUMP_ATTR
1226
1227
1228   void CContext::postProcessFilterGraph()
1229   TRY
1230   {
1231     int size = enabledFiles.size();
1232     for (int i = 0; i < size; ++i)
1233     {
1234        enabledFiles[i]->postProcessFilterGraph();
1235     }
1236   }
1237   CATCH_DUMP_ATTR
1238
1239   void CContext::startPrefetchingOfEnabledReadModeFiles()
1240   TRY
1241   {
1242     int size = enabledReadModeFiles.size();
1243     for (int i = 0; i < size; ++i)
1244     {
1245        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
1246     }
1247   }
1248   CATCH_DUMP_ATTR
1249
1250   void CContext::doPreTimestepOperationsForEnabledReadModeFiles()
1251   TRY
1252   {
1253     int size = enabledReadModeFiles.size();
1254     for (int i = 0; i < size; ++i)
1255     {
1256        enabledReadModeFiles[i]->doPreTimestepOperationsForEnabledReadModeFields();
1257     }
1258   }
1259   CATCH_DUMP_ATTR
1260
1261   void CContext::doPostTimestepOperationsForEnabledReadModeFiles()
1262   TRY
1263   {
1264     int size = enabledReadModeFiles.size();
1265     for (int i = 0; i < size; ++i)
1266     {
1267        enabledReadModeFiles[i]->doPostTimestepOperationsForEnabledReadModeFields();
1268     }
1269   }
1270   CATCH_DUMP_ATTR
1271
1272  void CContext::findFieldsWithReadAccess(void)
1273  TRY
1274  {
1275    fieldsWithReadAccess_.clear();
1276    const vector<CField*> allFields = CField::getAll();
1277    for (size_t i = 0; i < allFields.size(); ++i)
1278    {
1279      CField* field = allFields[i];
1280      if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
1281      {
1282        fieldsWithReadAccess_.push_back(field);
1283        field->setModelOut() ;
1284      }
1285    }
1286  }
1287  CATCH_DUMP_ATTR
1288
1289 
1290   void CContext::solveAllInheritance(bool apply)
1291   TRY
1292   {
1293     // Résolution des héritages descendants (càd des héritages de groupes)
1294     // pour chacun des contextes.
1295      solveDescInheritance(apply);
1296
1297     // Résolution des héritages par référence au niveau des fichiers.
1298      const vector<CFile*> allFiles=CFile::getAll();
1299      const vector<CCouplerIn*> allCouplerIn=CCouplerIn::getAll();
1300      const vector<CCouplerOut*> allCouplerOut=CCouplerOut::getAll();
1301      const vector<CGrid*> allGrids= CGrid::getAll();
1302
1303      if (serviceType_==CServicesManager::CLIENT)
1304      {
1305        for (unsigned int i = 0; i < allFiles.size(); i++)
1306          allFiles[i]->solveFieldRefInheritance(apply);
1307
1308        for (unsigned int i = 0; i < allCouplerIn.size(); i++)
1309          allCouplerIn[i]->solveFieldRefInheritance(apply);
1310
1311        for (unsigned int i = 0; i < allCouplerOut.size(); i++)
1312          allCouplerOut[i]->solveFieldRefInheritance(apply);
1313      }
1314
1315      unsigned int vecSize = allGrids.size();
1316      unsigned int i = 0;
1317      for (i = 0; i < vecSize; ++i)
1318        allGrids[i]->solveElementsRefInheritance(apply);
1319
1320   }
1321  CATCH_DUMP_ATTR
1322
1323   void CContext::findEnabledFiles(void)
1324   TRY
1325   {
1326      const std::vector<CFile*> allFiles = CFile::getAll();
1327      const CDate& initDate = calendar->getInitDate();
1328
1329      for (unsigned int i = 0; i < allFiles.size(); i++)
1330         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
1331         {
1332            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
1333            {
1334              if (allFiles[i]->output_freq.isEmpty())
1335              {
1336                 ERROR("CContext::findEnabledFiles()",
1337                     << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1338                     <<" \".")
1339              }
1340              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1341              {
1342                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1343                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1344                    <<"\" is less than the time step. File will not be written."<<endl;
1345              }
1346              else
1347               enabledFiles.push_back(allFiles[i]);
1348            }
1349            else // Si l'attribut 'enabled' est fixé à faux.
1350            {
1351              // disabled all fields contained in file (used in findFieldsWithReadAccess through field_ref dependencies)
1352              const vector<CField*>&& fieldList=allFiles[i]->getEnabledFields() ;
1353              for(auto field : fieldList) field->enabled.setValue(false);
1354            }
1355         }
1356         else
1357         {
1358           if (allFiles[i]->output_freq.isEmpty())
1359           {
1360              ERROR("CContext::findEnabledFiles()",
1361                  << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
1362                  <<" \".")
1363           }
1364           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
1365           {
1366             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
1367                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
1368                 <<"\" is less than the time step. File will not be written."<<endl;
1369           }
1370           else
1371             enabledFiles.push_back(allFiles[i]); // otherwise true by default
1372         }
1373
1374      if (enabledFiles.size() == 0)
1375         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
1376               << getId() << "\" !");
1377
1378   }
1379   CATCH_DUMP_ATTR
1380
1381   void CContext::findEnabledCouplerIn(void)
1382   TRY
1383   {
1384      const std::vector<CCouplerIn*> allCouplerIn = CCouplerIn::getAll();
1385      bool enabled ;
1386      for (size_t i = 0; i < allCouplerIn.size(); i++)
1387      {
1388        if (allCouplerIn[i]->enabled.isEmpty()) enabled=true ;
1389        else enabled=allCouplerIn[i]->enabled ;
1390        if (enabled) enabledCouplerIn.push_back(allCouplerIn[i]) ;
1391      }
1392   }
1393   CATCH_DUMP_ATTR
1394
1395   void CContext::findEnabledCouplerOut(void)
1396   TRY
1397   {
1398      const std::vector<CCouplerOut*> allCouplerOut = CCouplerOut::getAll();
1399      bool enabled ;
1400      for (size_t i = 0; i < allCouplerOut.size(); i++)
1401      {
1402        if (allCouplerOut[i]->enabled.isEmpty()) enabled=true ;
1403        else enabled=allCouplerOut[i]->enabled ;
1404        if (enabled) enabledCouplerOut.push_back(allCouplerOut[i]) ;
1405      }
1406   }
1407   CATCH_DUMP_ATTR
1408
1409
1410
1411
1412   void CContext::distributeFiles(const vector<CFile*>& files)
1413   TRY
1414   {
1415     bool distFileMemory=false ;
1416     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
1417
1418     if (distFileMemory) distributeFileOverMemoryBandwith(files) ;
1419     else distributeFileOverBandwith(files) ;
1420   }
1421   CATCH_DUMP_ATTR
1422
1423   void CContext::distributeFileOverBandwith(const vector<CFile*>& files)
1424   TRY
1425   {
1426     double eps=std::numeric_limits<double>::epsilon()*10 ;
1427     
1428     std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
1429     int nbPools = clientPrimServer.size();
1430
1431     // (1) Find all enabled files in write mode
1432     // for (int i = 0; i < this->enabledFiles.size(); ++i)
1433     // {
1434     //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1435     //    enabledWriteModeFiles.push_back(enabledFiles[i]);
1436     // }
1437
1438     // (2) Estimate the data volume for each file
1439     int size = files.size();
1440     std::vector<std::pair<double, CFile*> > dataSizeMap;
1441     double dataPerPool = 0;
1442     int nfield=0 ;
1443     ofs<<size<<endl ;
1444     for (size_t i = 0; i < size; ++i)
1445     {
1446       CFile* file = files[i];
1447       ofs<<file->getId()<<endl ;
1448       StdSize dataSize=0;
1449       std::vector<CField*> enabledFields = file->getEnabledFields();
1450       size_t numEnabledFields = enabledFields.size();
1451       ofs<<numEnabledFields<<endl ;
1452       for (size_t j = 0; j < numEnabledFields; ++j)
1453       {
1454         dataSize += enabledFields[j]->getGlobalWrittenSize() ;
1455         ofs<<enabledFields[j]->getGrid()->getId()<<endl ;
1456         ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
1457       }
1458       double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1459       double dataSizeSec= dataSize/ outFreqSec;
1460       ofs<<dataSizeSec<<endl ;
1461       nfield++ ;
1462// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
1463       dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
1464       dataPerPool += dataSizeSec;
1465     }
1466     dataPerPool /= nbPools;
1467     std::sort(dataSizeMap.begin(), dataSizeMap.end());
1468
1469     // (3) Assign contextClient to each enabled file
1470
1471     std::multimap<double,int> poolDataSize ;
1472// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
1473
1474     int j;
1475     double dataSize ;
1476     for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
1477             
1478     for (int i = dataSizeMap.size()-1; i >= 0; --i)
1479     {
1480       dataSize=(*poolDataSize.begin()).first ;
1481       j=(*poolDataSize.begin()).second ;
1482       dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
1483       dataSize+=dataSizeMap[i].first;
1484       poolDataSize.erase(poolDataSize.begin()) ;
1485       poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
1486     }
1487
1488     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 ;
1489   }
1490   CATCH_DUMP_ATTR
1491
1492   void CContext::distributeFileOverMemoryBandwith(const vector<CFile*>& filesList)
1493   TRY
1494   {
1495     int nbPools = clientPrimServer.size();
1496     double ratio=0.5 ;
1497     ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1498
1499     int nFiles = filesList.size();
1500     vector<SDistFile> files(nFiles);
1501     vector<SDistGrid> grids;
1502     map<string,int> gridMap ;
1503     string gridId; 
1504     int gridIndex=0 ;
1505
1506     for (size_t i = 0; i < nFiles; ++i)
1507     {
1508       StdSize dataSize=0;
1509       CFile* file = filesList[i];
1510       std::vector<CField*> enabledFields = file->getEnabledFields();
1511       size_t numEnabledFields = enabledFields.size();
1512
1513       files[i].id_=file->getId() ;
1514       files[i].nbGrids_=numEnabledFields;
1515       files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1516         
1517       for (size_t j = 0; j < numEnabledFields; ++j)
1518       {
1519         gridId=enabledFields[j]->getGrid()->getId() ;
1520         if (gridMap.find(gridId)==gridMap.end())
1521         {
1522            gridMap[gridId]=gridIndex  ;
1523            SDistGrid newGrid; 
1524            grids.push_back(newGrid) ;
1525            gridIndex++ ;
1526         }
1527         files[i].assignedGrid_[j]=gridMap[gridId] ;
1528         grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1529         dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1530       }
1531       double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1532       files[i].bandwith_= dataSize/ outFreqSec ;
1533     }
1534
1535     double bandwith=0 ;
1536     double memory=0 ;
1537   
1538     for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1539     for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1540
1541     for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1542     for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1543       
1544     distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1545
1546     vector<double> memorySize(nbPools,0.) ;
1547     vector< set<int> > serverGrids(nbPools) ;
1548     vector<double> bandwithSize(nbPools,0.) ;
1549       
1550     for (size_t i = 0; i < nFiles; ++i)
1551     {
1552       bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1553       for(int j=0 ; j<files[i].nbGrids_;j++)
1554       {
1555         if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1556         {
1557           memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1558           serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1559         }
1560       }
1561       filesList[i]->setContextClient(clientPrimServer[files[i].assignedServer_]) ;
1562       delete [] files[i].assignedGrid_ ;
1563     }
1564
1565     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 ;
1566     for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1567
1568   }
1569   CATCH_DUMP_ATTR
1570
1571   /*!
1572      Find all files in write mode
1573   */
1574   void CContext::findEnabledWriteModeFiles(void)
1575   TRY
1576   {
1577     int size = this->enabledFiles.size();
1578     for (int i = 0; i < size; ++i)
1579     {
1580       if (enabledFiles[i]->mode.isEmpty() || 
1581          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1582        enabledWriteModeFiles.push_back(enabledFiles[i]);
1583     }
1584   }
1585   CATCH_DUMP_ATTR
1586
1587   /*!
1588      Find all files in read mode
1589   */
1590   void CContext::findEnabledReadModeFiles(void)
1591   TRY
1592   {
1593     int size = this->enabledFiles.size();
1594     for (int i = 0; i < size; ++i)
1595     {
1596       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1597        enabledReadModeFiles.push_back(enabledFiles[i]);
1598     }
1599   }
1600   CATCH_DUMP_ATTR
1601
1602   void CContext::closeAllFile(void)
1603   TRY
1604   {
1605     std::vector<CFile*>::const_iterator
1606            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
1607
1608     for (; it != end; it++)
1609     {
1610       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1611       (*it)->close();
1612     }
1613   }
1614   CATCH_DUMP_ATTR
1615
1616   /*!
1617   \brief Dispatch event received from client
1618      Whenever a message is received in buffer of server, it will be processed depending on
1619   its event type. A new event type should be added in the switch list to make sure
1620   it processed on server side.
1621   \param [in] event: Received message
1622   */
1623   bool CContext::dispatchEvent(CEventServer& event)
1624   TRY
1625   {
1626
1627      if (SuperClass::dispatchEvent(event)) return true;
1628      else
1629      {
1630        switch(event.type)
1631        {
1632           case EVENT_ID_CLOSE_DEFINITION :
1633             recvCloseDefinition(event);
1634             return true;
1635             break;
1636           case EVENT_ID_UPDATE_CALENDAR:
1637             recvUpdateCalendar(event);
1638             return true;
1639             break;
1640           case EVENT_ID_CREATE_FILE_HEADER :
1641             recvCreateFileHeader(event);
1642             return true;
1643             break;
1644           case EVENT_ID_COUPLER_IN_READY:
1645             recvCouplerInReady(event);
1646             return true;
1647             break;
1648           case EVENT_ID_COUPLER_IN_CLOSE_DEFINITION:
1649             recvCouplerInCloseDefinition(event);
1650             return true;
1651             break;
1652           case EVENT_ID_COUPLER_IN_CONTEXT_FINALIZED:
1653             recvCouplerInContextFinalized(event);
1654             return true;
1655             break; 
1656           default :
1657             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
1658                    <<"Unknown Event");
1659           return false;
1660         }
1661      }
1662   }
1663   CATCH
1664
1665   //! Client side: Send a message to server to make it close
1666   // ym obsolete
1667   void CContext::sendCloseDefinition(void)
1668   TRY
1669   {
1670    int nbSrvPools ;
1671    if (serviceType_==CServicesManager::CLIENT) nbSrvPools = 1 ;
1672    else if (serviceType_==CServicesManager::GATHERER) nbSrvPools = this->clientPrimServer.size() ;
1673    else nbSrvPools = 0 ;
1674    CContextClient* contextClientTmp ;
1675
1676    for (int i = 0; i < nbSrvPools; ++i)
1677     {
1678       if (serviceType_==CServicesManager::CLIENT) contextClientTmp = client ;
1679       else if (serviceType_==CServicesManager::GATHERER ) contextClientTmp = clientPrimServer[i] ;
1680       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1681       if (contextClientTmp->isServerLeader())
1682       {
1683         CMessage msg;
1684         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1685         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1686           event.push(*itRank,1,msg);
1687         contextClientTmp->sendEvent(event);
1688       }
1689       else contextClientTmp->sendEvent(event);
1690     }
1691   }
1692   CATCH_DUMP_ATTR
1693   
1694   //  ! Client side: Send a message to server to make it close
1695   void CContext::sendCloseDefinition(CContextClient* client)
1696   TRY
1697   {
1698      if (sendCloseDefinition_done_.count(client)!=0) return ;
1699      else sendCloseDefinition_done_.insert(client) ;
1700
1701      CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1702      if (client->isServerLeader())
1703      {
1704        CMessage msg;
1705        for(auto rank : client->getRanksServerLeader()) event.push(rank,1,msg);
1706        client->sendEvent(event);
1707      }
1708     else client->sendEvent(event);
1709   }
1710   CATCH_DUMP_ATTR
1711
1712   //! Server side: Receive a message of client announcing a context close
1713   void CContext::recvCloseDefinition(CEventServer& event)
1714   TRY
1715   {
1716      CBufferIn* buffer=event.subEvents.begin()->buffer;
1717      getCurrent()->closeDefinition();
1718   }
1719   CATCH
1720
1721   //! Client side: Send a message to update calendar in each time step
1722   void CContext::sendUpdateCalendar(int step)
1723   TRY
1724   {
1725     for(auto client : slaveServers_) 
1726     {
1727       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
1728       if (client->isServerLeader())
1729       {
1730         CMessage msg;
1731         msg<<step;
1732         for (auto& rank : client->getRanksServerLeader() ) event.push(rank,1,msg);
1733         client->sendEvent(event);
1734       }
1735       else client->sendEvent(event);
1736     }
1737   }
1738   CATCH_DUMP_ATTR
1739
1740   //! Server side: Receive a message of client annoucing calendar update
1741   void CContext::recvUpdateCalendar(CEventServer& event)
1742   TRY
1743   {
1744      CBufferIn* buffer=event.subEvents.begin()->buffer;
1745      getCurrent()->recvUpdateCalendar(*buffer);
1746   }
1747   CATCH
1748
1749   //! Server side: Receive a message of client annoucing calendar update
1750   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1751   TRY
1752   {
1753      int step;
1754      buffer>>step;
1755      updateCalendar(step);
1756      if (serviceType_==CServicesManager::GATHERER)
1757      {       
1758        sendUpdateCalendar(step);
1759      }
1760   }
1761   CATCH_DUMP_ATTR
1762
1763   //! Client side: Send a message to create header part of netcdf file
1764   void CContext::sendCreateFileHeader(void)
1765   TRY
1766   {
1767     int nbSrvPools ;
1768     if (serviceType_==CServicesManager::CLIENT) nbSrvPools = 1 ;
1769     else if (serviceType_==CServicesManager::GATHERER) nbSrvPools = this->clientPrimServer.size() ;
1770     else nbSrvPools = 0 ;
1771     CContextClient* contextClientTmp ;
1772
1773     for (int i = 0; i < nbSrvPools; ++i)
1774     {
1775       if (serviceType_==CServicesManager::CLIENT) contextClientTmp = client ;
1776       else if (serviceType_==CServicesManager::GATHERER ) contextClientTmp = clientPrimServer[i] ;
1777       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
1778
1779       if (contextClientTmp->isServerLeader())
1780       {
1781         CMessage msg;
1782         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1783         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1784           event.push(*itRank,1,msg) ;
1785         contextClientTmp->sendEvent(event);
1786       }
1787       else contextClientTmp->sendEvent(event);
1788     }
1789   }
1790   CATCH_DUMP_ATTR
1791
1792   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1793   void CContext::recvCreateFileHeader(CEventServer& event)
1794   TRY
1795   {
1796      CBufferIn* buffer=event.subEvents.begin()->buffer;
1797      getCurrent()->recvCreateFileHeader(*buffer);
1798   }
1799   CATCH
1800
1801   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1802   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1803   TRY
1804   {
1805      if (serviceType_==CServicesManager::IO_SERVER || serviceType_==CServicesManager::OUT_SERVER) 
1806        createFileHeader();
1807   }
1808   CATCH_DUMP_ATTR
1809
1810   void CContext::createCouplerInterCommunicator(void)
1811   TRY
1812   {
1813      int rank=this->getIntraCommRank() ;
1814      map<string,list<CCouplerOut*>> listCouplerOut ; 
1815      map<string,list<CCouplerIn*>> listCouplerIn ; 
1816
1817      for(auto couplerOut : enabledCouplerOut) listCouplerOut[couplerOut->getCouplingContextId()].push_back(couplerOut) ;
1818      for(auto couplerIn : enabledCouplerIn) listCouplerIn[couplerIn->getCouplingContextId()].push_back(couplerIn) ;
1819
1820      CCouplerManager* couplerManager = CXios::getCouplerManager() ;
1821      if (rank==0)
1822      {
1823        for(auto couplerOut : listCouplerOut) couplerManager->registerCoupling(this->getContextId(),couplerOut.first) ;
1824        for(auto couplerIn : listCouplerIn) couplerManager->registerCoupling(couplerIn.first,this->getContextId()) ;
1825      }
1826
1827      do
1828      {
1829        for(auto couplerOut : listCouplerOut) 
1830        {
1831          bool isNextCoupling ;
1832          if (rank==0) isNextCoupling = couplerManager->isNextCoupling(this->getContextId(),couplerOut.first) ;
1833          MPI_Bcast(&isNextCoupling,1,MPI_C_BOOL, 0, getIntraComm()) ; 
1834          if (isNextCoupling) 
1835          {
1836            addCouplingChanel(couplerOut.first, true) ;
1837            listCouplerOut.erase(couplerOut.first) ;
1838            break ;
1839          }           
1840        }
1841        for(auto couplerIn : listCouplerIn) 
1842        {
1843          bool isNextCoupling ;
1844          if (rank==0) isNextCoupling = couplerManager->isNextCoupling(couplerIn.first,this->getContextId());
1845          MPI_Bcast(&isNextCoupling,1,MPI_C_BOOL, 0, getIntraComm()) ; 
1846          if (isNextCoupling) 
1847          {
1848            addCouplingChanel(couplerIn.first, false) ;
1849            listCouplerIn.erase(couplerIn.first) ;
1850            break ;
1851          }           
1852        }
1853
1854      } while (!listCouplerOut.empty() || !listCouplerIn.empty()) ;
1855
1856   }
1857   CATCH_DUMP_ATTR
1858
1859 
1860     //! Client side: Send infomation of active files (files are enabled to write out)
1861   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1862   TRY
1863   {
1864     int size = activeFiles.size();
1865
1866     // In a context, each type has a root definition, e.g: axis, domain, field.
1867     // Every object must be a child of one of these root definition. In this case
1868     // all new file objects created on server must be children of the root "file_definition"
1869     StdString fileDefRoot("file_definition");
1870     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1871
1872     for (int i = 0; i < size; ++i)
1873     {
1874       CFile* f = activeFiles[i];
1875       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1876       f->sendAllAttributesToServer(f->getContextClient());
1877       f->sendAddAllVariables(f->getContextClient());
1878     }
1879   }
1880   CATCH_DUMP_ATTR
1881
1882   //! Client side: Send information of active fields (ones are written onto files)
1883   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1884   TRY
1885   {
1886     int size = activeFiles.size();
1887     for (int i = 0; i < size; ++i)
1888     {
1889       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1890     }
1891   }
1892   CATCH_DUMP_ATTR
1893
1894 
1895   //! Client side: Prepare the timeseries by adding the necessary files
1896   void CContext::prepareTimeseries()
1897   TRY
1898   {
1899     const std::vector<CFile*> allFiles = CFile::getAll();
1900     for (size_t i = 0; i < allFiles.size(); i++)
1901     {
1902       CFile* file = allFiles[i];
1903
1904       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1905       for (size_t k = 0; k < vars.size(); k++)
1906       {
1907         CVariable* var = vars[k];
1908
1909         if (var->ts_target.isEmpty()
1910              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1911           fileVars.push_back(var);
1912
1913         if (!var->ts_target.isEmpty()
1914              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1915           fieldVars.push_back(var);
1916       }
1917
1918       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1919       {
1920         StdString fileNameStr("%file_name%") ;
1921         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1922         
1923         StdString fileName=file->getFileOutputName();
1924         size_t pos=tsPrefix.find(fileNameStr) ;
1925         while (pos!=std::string::npos)
1926         {
1927           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1928           pos=tsPrefix.find(fileNameStr) ;
1929         }
1930       
1931         const std::vector<CField*> allFields = file->getAllFields();
1932         for (size_t j = 0; j < allFields.size(); j++)
1933         {
1934           CField* field = allFields[j];
1935
1936           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1937           {
1938             CFile* tsFile = CFile::create();
1939             tsFile->duplicateAttributes(file);
1940
1941             // Add variables originating from file and targeted to timeserie file
1942             for (size_t k = 0; k < fileVars.size(); k++)
1943               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1944
1945           
1946             tsFile->name = tsPrefix + "_";
1947             if (!field->name.isEmpty())
1948               tsFile->name.get() += field->name;
1949             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1950               tsFile->name.get() += field->field_ref;
1951             else
1952               tsFile->name.get() += field->getId();
1953
1954             if (!field->ts_split_freq.isEmpty())
1955               tsFile->split_freq = field->ts_split_freq;
1956
1957             CField* tsField = tsFile->addField();
1958             tsField->field_ref = field->getId();
1959
1960             // Add variables originating from file and targeted to timeserie field
1961             for (size_t k = 0; k < fieldVars.size(); k++)
1962               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1963
1964             vars = field->getAllVariables();
1965             for (size_t k = 0; k < vars.size(); k++)
1966             {
1967               CVariable* var = vars[k];
1968
1969               // Add variables originating from field and targeted to timeserie field
1970               if (var->ts_target.isEmpty()
1971                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1972                 tsField->getVirtualVariableGroup()->addChild(var);
1973
1974               // Add variables originating from field and targeted to timeserie file
1975               if (!var->ts_target.isEmpty()
1976                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1977                 tsFile->getVirtualVariableGroup()->addChild(var);
1978             }
1979
1980             tsFile->solveFieldRefInheritance(true);
1981
1982             if (file->timeseries == CFile::timeseries_attr::exclusive)
1983               field->enabled = false;
1984           }
1985         }
1986
1987         // Finally disable the original file is need be
1988         if (file->timeseries == CFile::timeseries_attr::only)
1989          file->enabled = false;
1990       }
1991     }
1992   }
1993   CATCH_DUMP_ATTR
1994
1995 
1996   //! Client side: Send information of reference domain, axis and scalar of active fields
1997   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
1998   TRY
1999   {
2000     std::set<pair<StdString,CContextClient*>> domainIds, axisIds, scalarIds;
2001
2002     // Find all reference domain and axis of all active fields
2003     int numEnabledFiles = activeFiles.size();
2004     for (int i = 0; i < numEnabledFiles; ++i)
2005     {
2006       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
2007       int numEnabledFields = enabledFields.size();
2008       for (int j = 0; j < numEnabledFields; ++j)
2009       {
2010         CContextClient* contextClient=enabledFields[j]->getContextClient() ;
2011         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
2012         if ("" != prDomAxisScalarId[0]) domainIds.insert(make_pair(prDomAxisScalarId[0],contextClient));
2013         if ("" != prDomAxisScalarId[1]) axisIds.insert(make_pair(prDomAxisScalarId[1],contextClient));
2014         if ("" != prDomAxisScalarId[2]) scalarIds.insert(make_pair(prDomAxisScalarId[2],contextClient));
2015       }
2016     }
2017
2018     // Create all reference axis on server side
2019     std::set<StdString>::iterator itDom, itAxis, itScalar;
2020     std::set<StdString>::const_iterator itE;
2021
2022     StdString scalarDefRoot("scalar_definition");
2023     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
2024     
2025     for (auto itScalar = scalarIds.begin(); itScalar != scalarIds.end(); ++itScalar)
2026     {
2027       if (!itScalar->first.empty())
2028       {
2029         scalarPtr->sendCreateChild(itScalar->first,itScalar->second);
2030         CScalar::get(itScalar->first)->sendAllAttributesToServer(itScalar->second);
2031       }
2032     }
2033
2034     StdString axiDefRoot("axis_definition");
2035     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
2036     
2037     for (auto itAxis = axisIds.begin(); itAxis != axisIds.end(); ++itAxis)
2038     {
2039       if (!itAxis->first.empty())
2040       {
2041         axisPtr->sendCreateChild(itAxis->first, itAxis->second);
2042         CAxis::get(itAxis->first)->sendAllAttributesToServer(itAxis->second);
2043       }
2044     }
2045
2046     // Create all reference domains on server side
2047     StdString domDefRoot("domain_definition");
2048     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
2049     
2050     for (auto itDom = domainIds.begin(); itDom != domainIds.end(); ++itDom)
2051     {
2052       if (!itDom->first.empty()) {
2053          domPtr->sendCreateChild(itDom->first, itDom->second);
2054          CDomain::get(itDom->first)->sendAllAttributesToServer(itDom->second);
2055       }
2056     }
2057   }
2058   CATCH_DUMP_ATTR
2059
2060   void CContext::triggerLateFields(void)
2061   TRY
2062   {
2063    for(auto& field : fileInFields_) field->triggerLateField() ;
2064    for(auto& field : couplerInFields_) field->triggerLateField() ;
2065   }
2066   CATCH_DUMP_ATTR
2067
2068   //! Update calendar in each time step
2069   void CContext::updateCalendar(int step)
2070   TRY
2071   {
2072      int prevStep = calendar->getStep();
2073
2074      if (prevStep < step)
2075      {
2076        if (serviceType_==CServicesManager::CLIENT) // For now we only use server level 1 to read data
2077        {
2078          triggerLateFields();
2079        }
2080
2081        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
2082        calendar->update(step);
2083        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
2084  #ifdef XIOS_MEMTRACK_LIGHT
2085        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
2086  #endif
2087
2088        if (serviceType_==CServicesManager::CLIENT) // For now we only use server level 1 to read data
2089        {
2090          doPostTimestepOperationsForEnabledReadModeFiles();
2091          garbageCollector.invalidate(calendar->getCurrentDate());
2092        }
2093      }
2094      else if (prevStep == step)
2095        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
2096      else // if (prevStep > step)
2097        ERROR("void CContext::updateCalendar(int step)",
2098              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
2099   }
2100   CATCH_DUMP_ATTR
2101
2102   void CContext::initReadFiles(void)
2103   TRY
2104   {
2105      vector<CFile*>::const_iterator it;
2106
2107      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
2108      {
2109         (*it)->initRead();
2110      }
2111   }
2112   CATCH_DUMP_ATTR
2113
2114   //! Server side: Create header of netcdf file
2115   void CContext::createFileHeader(void)
2116   TRY
2117   {
2118      vector<CFile*>::const_iterator it;
2119
2120      //for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
2121      for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
2122      {
2123         (*it)->initWrite();
2124      }
2125   }
2126   CATCH_DUMP_ATTR
2127
2128   //! Get current context
2129   CContext* CContext::getCurrent(void)
2130   TRY
2131   {
2132     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
2133   }
2134   CATCH
2135
2136   /*!
2137   \brief Set context with an id be the current context
2138   \param [in] id identity of context to be set to current
2139   */
2140   void CContext::setCurrent(const string& id)
2141   TRY
2142   {
2143     CObjectFactory::SetCurrentContextId(id);
2144     CGroupFactory::SetCurrentContextId(id);
2145   }
2146   CATCH
2147
2148  /*!
2149  \brief Create a context with specific id
2150  \param [in] id identity of new context
2151  \return pointer to the new context or already-existed one with identity id
2152  */
2153  CContext* CContext::create(const StdString& id)
2154  TRY
2155  {
2156    CContext::setCurrent(id);
2157
2158    bool hasctxt = CContext::has(id);
2159    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
2160    getRoot();
2161    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
2162
2163#define DECLARE_NODE(Name_, name_) \
2164    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
2165#define DECLARE_NODE_PAR(Name_, name_)
2166#include "node_type.conf"
2167
2168    return (context);
2169  }
2170  CATCH
2171
2172 
2173  void CContext::sendFinalizeClient(CContextClient* contextClient, const string& contextClientId)
2174  TRY
2175  {
2176    CEventClient event(getType(),EVENT_ID_CONTEXT_FINALIZE_CLIENT);
2177    if (contextClient->isServerLeader())
2178    {
2179      CMessage msg;
2180      msg<<contextClientId ;
2181      const std::list<int>& ranks = contextClient->getRanksServerLeader();
2182      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
2183           event.push(*itRank,1,msg);
2184      contextClient->sendEvent(event);
2185    }
2186    else contextClient->sendEvent(event);
2187  }
2188  CATCH_DUMP_ATTR
2189
2190 
2191  void CContext::recvFinalizeClient(CEventServer& event)
2192  TRY
2193  {
2194    CBufferIn* buffer=event.subEvents.begin()->buffer;
2195    string id;
2196    *buffer>>id;
2197    get(id)->recvFinalizeClient(*buffer);
2198  }
2199  CATCH
2200
2201  void CContext::recvFinalizeClient(CBufferIn& buffer)
2202  TRY
2203  {
2204    countChildContextFinalized_++ ;
2205  }
2206  CATCH_DUMP_ATTR
2207
2208
2209
2210
2211 //! Client side: Send a message  announcing that context can receive grid definition from coupling
2212   void CContext::sendCouplerInReady(CContextClient* client)
2213   TRY
2214   {
2215      if (sendCouplerInReady_done_.count(client)!=0) return ;
2216      else sendCouplerInReady_done_.insert(client) ;
2217
2218      CEventClient event(getType(),EVENT_ID_COUPLER_IN_READY);
2219
2220      if (client->isServerLeader())
2221      {
2222        CMessage msg;
2223        msg<<this->getId();
2224        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2225        client->sendEvent(event);
2226      }
2227      else client->sendEvent(event);
2228   }
2229   CATCH_DUMP_ATTR
2230
2231   //! Server side: Receive a message announcing that context can send grid definition for context coupling
2232   void CContext::recvCouplerInReady(CEventServer& event)
2233   TRY
2234   {
2235      CBufferIn* buffer=event.subEvents.begin()->buffer;
2236      getCurrent()->recvCouplerInReady(*buffer);
2237   }
2238   CATCH
2239
2240   //! Server side: Receive a message announcing that context can send grid definition for context coupling
2241   void CContext::recvCouplerInReady(CBufferIn& buffer)
2242   TRY
2243   {
2244      string contextId ;
2245      buffer>>contextId;
2246      couplerInReady_.insert(getCouplerOutClient(contextId)) ;
2247   }
2248   CATCH_DUMP_ATTR
2249
2250
2251
2252
2253
2254 //! Client side: Send a message  announcing that a coupling context have done it closeDefinition, so data can be sent now.
2255   void CContext::sendCouplerInCloseDefinition(CContextClient* client)
2256   TRY
2257   {
2258      if (sendCouplerInCloseDefinition_done_.count(client)!=0) return ;
2259      else sendCouplerInCloseDefinition_done_.insert(client) ;
2260
2261      CEventClient event(getType(),EVENT_ID_COUPLER_IN_CLOSE_DEFINITION);
2262
2263      if (client->isServerLeader())
2264      {
2265        CMessage msg;
2266        msg<<this->getId();
2267        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2268        client->sendEvent(event);
2269      }
2270      else client->sendEvent(event);
2271   }
2272   CATCH_DUMP_ATTR
2273
2274   //! Server side: Receive a message announcing that a coupling context have done it closeDefinition, so data can be sent now.
2275   void CContext::recvCouplerInCloseDefinition(CEventServer& event)
2276   TRY
2277   {
2278      CBufferIn* buffer=event.subEvents.begin()->buffer;
2279      getCurrent()->recvCouplerInCloseDefinition(*buffer);
2280   }
2281   CATCH
2282
2283   //! Server side: Receive a message announcing that a coupling context have done it closeDefinition, so data can be sent now.
2284   void CContext::recvCouplerInCloseDefinition(CBufferIn& buffer)
2285   TRY
2286   {
2287      string contextId ;
2288      buffer>>contextId;
2289      couplerInCloseDefinition_.insert(getCouplerOutClient(contextId)) ;
2290   }
2291   CATCH_DUMP_ATTR
2292
2293
2294
2295
2296//! Client side: Send a message  announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2297   void CContext::sendCouplerInContextFinalized(CContextClient* client)
2298   TRY
2299   {
2300      if (sendCouplerInContextFinalized_done_.count(client)!=0) return ;
2301      else sendCouplerInContextFinalized_done_.insert(client) ;
2302
2303      CEventClient event(getType(),EVENT_ID_COUPLER_IN_CONTEXT_FINALIZED);
2304
2305      if (client->isServerLeader())
2306      {
2307        CMessage msg;
2308        msg<<this->getId();
2309        for (auto& rank : client->getRanksServerLeader()) event.push(rank,1,msg);
2310        client->sendEvent(event);
2311      }
2312      else client->sendEvent(event);
2313   }
2314   CATCH_DUMP_ATTR
2315
2316   //! Server side: Receive a message announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2317   void CContext::recvCouplerInContextFinalized(CEventServer& event)
2318   TRY
2319   {
2320      CBufferIn* buffer=event.subEvents.begin()->buffer;
2321      getCurrent()->recvCouplerInContextFinalized(*buffer);
2322   }
2323   CATCH
2324
2325   //! Server side: Receive a message announcing that a coupling context have done it contextFinalize, so it can also close it own context.
2326   void CContext::recvCouplerInContextFinalized(CBufferIn& buffer)
2327   TRY
2328   {
2329      string contextId ;
2330      buffer>>contextId;
2331      couplerInContextFinalized_.insert(getCouplerOutClient(contextId)) ;
2332   }
2333   CATCH_DUMP_ATTR
2334
2335
2336
2337
2338  /*!
2339  * \fn bool CContext::isFinalized(void)
2340  * Context is finalized if it received context post finalize event.
2341  */
2342  bool CContext::isFinalized(void)
2343  TRY
2344  {
2345    return finalized;
2346  }
2347  CATCH_DUMP_ATTR
2348  ///--------------------------------------------------------------
2349  StdString CContext::dumpClassAttributes(void)
2350  {
2351    StdString str;
2352    str.append("enabled files=\"");
2353    int size = this->enabledFiles.size();
2354    for (int i = 0; i < size; ++i)
2355    {
2356      str.append(enabledFiles[i]->getId());
2357      str.append(" ");
2358    }
2359    str.append("\"");
2360    return str;
2361  }
2362
2363} // namespace xios
Note: See TracBrowser for help on using the repository browser.