source: XIOS/dev/dev_ym/XIOS_ONE_SIDED/src/node/context.cpp @ 1554

Last change on this file since 1554 was 1554, checked in by ymipsl, 6 years ago
  • Remove temporary buffered event
  • Some cleaning

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