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

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

Reverse partially commit 2438 : the integration of environment variables in XML soures inclusion (not XIOS_IODEF_PATH).

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