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

Last change on this file since 2426 was 2426, checked in by jderouillat, 19 months ago

Clean MemCheckcer?, add memory consumption accumulators in main XIOS interfaces for clients, and in the NetCDF interface for servers.

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