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

Last change on this file since 1784 was 1784, checked in by ymipsl, 4 years ago
  • Preparing coupling functionalities.
  • Make some cleaner things

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