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

Last change on this file since 1853 was 1853, checked in by ymipsl, 21 months ago

Coupling branch : replace hasServer and hasClient combination by the name of correct service : CLIENT, GATHERER or OUT_SERVER.

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