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

Last change on this file since 2410 was 2410, checked in by jderouillat, 21 months ago

Fix for attached mode in the new service management

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