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

Last change on this file since 2405 was 2405, checked in by ymipsl, 21 months ago

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