source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/context.cpp @ 2130

Last change on this file since 2130 was 2130, checked in by ymipsl, 3 years ago

New management of client-server buffers.

  • buffers can grow automatically in intialization phase
  • buffers is evaluated after the close context definition phase and fixed at optimal value.

YM

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