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

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

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