source: XIOS/trunk/src/node/context.cpp @ 1542

Last change on this file since 1542 was 1542, checked in by oabramkina, 6 years ago

Replacing Boost's unordered_map and shared_pointer by its STL counterparts.

Two notes for Curie:

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