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

Last change on this file since 1848 was 1848, checked in by ymipsl, 4 years ago

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