source: XIOS/branchs/xios-2.5/src/node/context.cpp @ 2254

Last change on this file since 2254 was 2254, checked in by aclsce, 3 years ago

Enable the use of record_offset in case of reading and server level 2.

  • 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.5 KB
Line 
1#include "context.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "calendar_type.hpp"
7#include "duration.hpp"
8
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
12#include "node_type.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "timer.hpp"
17#include "memtrack.hpp"
18#include <limits>
19#include <fstream>
20#include "server.hpp"
21#include "distribute_file_server2.hpp"
22
23namespace xios {
24
25  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=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   boost::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(boost::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)) */ ; // WARNING remove freeing communicator !! --> deadlock raised, to be checked
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)) */;  // WARNING remove freeing communicator !! --> deadlock raised, to be checked
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)) */ ; // WARNING remove freeing communicator !! --> deadlock raised, to be checked
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      createFileHeader();
1322   }
1323
1324   //! Client side: Send a message to do some post processing on server
1325   void CContext::sendProcessingGridOfEnabledFields()
1326   {
1327      // Use correct context client to send message
1328     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1329     for (int i = 0; i < nbSrvPools; ++i)
1330     {
1331       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1332       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1333
1334       if (contextClientTmp->isServerLeader())
1335       {
1336         CMessage msg;
1337         if (hasServer)
1338           msg<<this->getIdServer(i);
1339         else
1340           msg<<this->getIdServer();
1341         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1342         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1343           event.push(*itRank,1,msg);
1344         contextClientTmp->sendEvent(event);
1345       }
1346       else contextClientTmp->sendEvent(event);
1347     }
1348   }
1349
1350   //! Server side: Receive a message to do some post processing
1351   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1352   {
1353      CBufferIn* buffer=event.subEvents.begin()->buffer;
1354      string id;
1355      *buffer>>id;     
1356   }
1357
1358   //! Client side: Send a message to do some post processing on server
1359   void CContext::sendPostProcessing()
1360   {
1361      // Use correct context client to send message
1362     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1363     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1364     for (int i = 0; i < nbSrvPools; ++i)
1365     {
1366       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1367       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1368       if (contextClientTmp->isServerLeader())
1369       {
1370         CMessage msg;
1371         if (hasServer)
1372           msg<<this->getIdServer(i);
1373         else
1374           msg<<this->getIdServer();
1375         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1376         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1377         event.push(*itRank,1,msg);
1378         contextClientTmp->sendEvent(event);
1379       }
1380       else contextClientTmp->sendEvent(event);
1381     }
1382   }
1383
1384   //! Server side: Receive a message to do some post processing
1385   void CContext::recvPostProcessing(CEventServer& event)
1386   {
1387      CBufferIn* buffer=event.subEvents.begin()->buffer;
1388      string id;
1389      *buffer>>id;
1390      get(id)->recvPostProcessing(*buffer);
1391   }
1392
1393   //! Server side: Receive a message to do some post processing
1394   void CContext::recvPostProcessing(CBufferIn& buffer)
1395   {
1396      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1397      postProcessing();
1398   }
1399
1400   const StdString& CContext::getIdServer()
1401   {
1402      if (hasClient)
1403      {
1404        idServer_ = this->getId();
1405        idServer_ += "_server";
1406        return idServer_;
1407      }
1408      if (hasServer) return (this->getId());
1409   }
1410
1411   const StdString& CContext::getIdServer(const int i)
1412   {
1413     idServer_ = this->getId();
1414     idServer_ += "_server_";
1415     idServer_ += boost::lexical_cast<string>(i);
1416     return idServer_;
1417   }
1418
1419
1420   /*!
1421   \brief Do some simple post processings after parsing xml file
1422      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1423   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1424   which will be written out into netcdf files, are processed
1425   */
1426   void CContext::postProcessing()
1427   {
1428     if (isPostProcessed) return;
1429
1430      // Make sure the calendar was correctly created
1431      if (!calendar)
1432        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1433      else if (calendar->getTimeStep() == NoneDu)
1434        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1435      // Calendar first update to set the current date equals to the start date
1436      calendar->update(0);
1437
1438      // Find all inheritance in xml structure
1439      this->solveAllInheritance();
1440
1441//      ShowTree(info(10));
1442
1443      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1444      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1445      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1446
1447      // Check if some automatic time series should be generated
1448      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1449
1450      // The timeseries should only be prepared in client
1451      if (hasClient && !hasServer) prepareTimeseries();
1452
1453      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1454      findEnabledFiles();
1455      findEnabledWriteModeFiles();
1456      findEnabledReadModeFiles();
1457
1458      // For now, only read files with client and only one level server
1459      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
1460
1461      // Find all enabled fields of each file     
1462      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1463      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1464
1465      // For now, only read files with client and only one level server
1466      // if (hasClient && !hasServer)
1467      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
1468
1469      if (hasClient && !hasServer)
1470      {
1471        initReadFiles();
1472        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1473        this->readAttributesOfEnabledFieldsInReadModeFiles();
1474      }
1475
1476      // Only search and rebuild all reference objects of enable fields, don't transform
1477      this->solveOnlyRefOfEnabledFields(false);
1478
1479      // Search and rebuild all reference object of enabled fields, and transform
1480      this->solveAllRefOfEnabledFieldsAndTransform(false);
1481
1482      // Find all fields with read access from the public API
1483      if (hasClient && !hasServer) findFieldsWithReadAccess();
1484      // and solve the all reference for them
1485      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1486
1487      isPostProcessed = true;
1488   }
1489
1490   /*!
1491    * Compute the required buffer size to send the attributes (mostly those grid related).
1492    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1493    * \param [in] contextClient
1494    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1495      This flag is only true for client and server-1 for communication with server-2
1496    */
1497   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize,
1498                                                           CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
1499   {
1500         // As calendar attributes are sent even if there are no active files or fields, maps are initialized according the size of calendar attributes
1501     std::map<int, StdSize> attributesSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1502     maxEventSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1503
1504     std::vector<CFile*>& fileList = this->enabledFiles;
1505     size_t numEnabledFiles = fileList.size();
1506     for (size_t i = 0; i < numEnabledFiles; ++i)
1507     {
1508//         CFile* file = this->enabledWriteModeFiles[i];
1509        CFile* file = fileList[i];
1510        std::vector<CField*> enabledFields = file->getEnabledFields();
1511        size_t numEnabledFields = enabledFields.size();
1512        for (size_t j = 0; j < numEnabledFields; ++j)
1513        {
1514          const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient, bufferForWriting);
1515          std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1516          for (; it != itE; ++it)
1517          {
1518                     // If attributesSize[it->first] does not exist, it will be zero-initialized
1519                     // so we can use it safely without checking for its existence
1520             if (attributesSize[it->first] < it->second)
1521                           attributesSize[it->first] = it->second;
1522
1523                     if (maxEventSize[it->first] < it->second)
1524                           maxEventSize[it->first] = it->second;
1525          }
1526        }
1527     }
1528     return attributesSize;
1529   }
1530
1531   /*!
1532    * Compute the required buffer size to send the fields data.
1533    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1534    * \param [in] contextClient
1535    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1536      This flag is only true for client and server-1 for communication with server-2
1537    */
1538   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize,
1539                                                      CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
1540   {
1541     std::map<int, StdSize> dataSize;
1542
1543     // Find all reference domain and axis of all active fields
1544     std::vector<CFile*>& fileList = bufferForWriting ? this->enabledWriteModeFiles : this->enabledReadModeFiles;
1545     size_t numEnabledFiles = fileList.size();
1546     for (size_t i = 0; i < numEnabledFiles; ++i)
1547     {
1548//       CFile* file = this->enabledFiles[i];
1549       CFile* file = fileList[i];
1550       if (file->getContextClient() == contextClient)
1551       {
1552         std::vector<CField*> enabledFields = file->getEnabledFields();
1553         size_t numEnabledFields = enabledFields.size();
1554         for (size_t j = 0; j < numEnabledFields; ++j)
1555         {
1556           // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1557           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient,bufferForWriting);
1558           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1559           for (; it != itE; ++it)
1560           {
1561             // If dataSize[it->first] does not exist, it will be zero-initialized
1562             // so we can use it safely without checking for its existance
1563                 if (CXios::isOptPerformance)
1564               dataSize[it->first] += it->second;
1565             else if (dataSize[it->first] < it->second)
1566               dataSize[it->first] = it->second;
1567
1568                 if (maxEventSize[it->first] < it->second)
1569               maxEventSize[it->first] = it->second;
1570           }
1571         }
1572       }
1573     }
1574     return dataSize;
1575   }
1576
1577   //! Client side: Send infomation of active files (files are enabled to write out)
1578   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1579   {
1580     int size = activeFiles.size();
1581
1582     // In a context, each type has a root definition, e.g: axis, domain, field.
1583     // Every object must be a child of one of these root definition. In this case
1584     // all new file objects created on server must be children of the root "file_definition"
1585     StdString fileDefRoot("file_definition");
1586     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1587
1588     for (int i = 0; i < size; ++i)
1589     {
1590       CFile* f = activeFiles[i];
1591       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1592       f->sendAllAttributesToServer(f->getContextClient());
1593       f->sendAddAllVariables(f->getContextClient());
1594     }
1595   }
1596
1597   //! Client side: Send information of active fields (ones are written onto files)
1598   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1599   {
1600     int size = activeFiles.size();
1601     for (int i = 0; i < size; ++i)
1602     {
1603       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1604     }
1605   }
1606
1607   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1608   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1609   {
1610     if (!hasClient) return;
1611
1612     const vector<CAxis*> allAxis = CAxis::getAll();
1613     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1614       (*it)->checkEligibilityForCompressedOutput();
1615
1616     const vector<CDomain*> allDomains = CDomain::getAll();
1617     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1618       (*it)->checkEligibilityForCompressedOutput();
1619
1620     const vector<CGrid*> allGrids = CGrid::getAll();
1621     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1622       (*it)->checkEligibilityForCompressedOutput();
1623   }
1624
1625   //! Client side: Prepare the timeseries by adding the necessary files
1626   void CContext::prepareTimeseries()
1627   {
1628     if (!hasClient) return;
1629
1630     const std::vector<CFile*> allFiles = CFile::getAll();
1631     for (size_t i = 0; i < allFiles.size(); i++)
1632     {
1633       CFile* file = allFiles[i];
1634
1635       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1636       for (size_t k = 0; k < vars.size(); k++)
1637       {
1638         CVariable* var = vars[k];
1639
1640         if (var->ts_target.isEmpty()
1641              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1642           fileVars.push_back(var);
1643
1644         if (!var->ts_target.isEmpty()
1645              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1646           fieldVars.push_back(var);
1647       }
1648
1649       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1650       {
1651         StdString fileNameStr("%file_name%") ;
1652         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1653         
1654         StdString fileName=file->getFileOutputName();
1655         size_t pos=tsPrefix.find(fileNameStr) ;
1656         while (pos!=std::string::npos)
1657         {
1658           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1659           pos=tsPrefix.find(fileNameStr) ;
1660         }
1661       
1662         const std::vector<CField*> allFields = file->getAllFields();
1663         for (size_t j = 0; j < allFields.size(); j++)
1664         {
1665           CField* field = allFields[j];
1666
1667           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1668           {
1669             CFile* tsFile = CFile::create();
1670             tsFile->duplicateAttributes(file);
1671
1672             // Add variables originating from file and targeted to timeserie file
1673             for (size_t k = 0; k < fileVars.size(); k++)
1674               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1675
1676           
1677             tsFile->name = tsPrefix + "_";
1678             if (!field->name.isEmpty())
1679               tsFile->name.get() += field->name;
1680             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1681               tsFile->name.get() += field->field_ref;
1682             else
1683               tsFile->name.get() += field->getId();
1684
1685             if (!field->ts_split_freq.isEmpty())
1686               tsFile->split_freq = field->ts_split_freq;
1687
1688             CField* tsField = tsFile->addField();
1689             tsField->field_ref = field->getId();
1690
1691             // Add variables originating from file and targeted to timeserie field
1692             for (size_t k = 0; k < fieldVars.size(); k++)
1693               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1694
1695             vars = field->getAllVariables();
1696             for (size_t k = 0; k < vars.size(); k++)
1697             {
1698               CVariable* var = vars[k];
1699
1700               // Add variables originating from field and targeted to timeserie field
1701               if (var->ts_target.isEmpty()
1702                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1703                 tsField->getVirtualVariableGroup()->addChild(var);
1704
1705               // Add variables originating from field and targeted to timeserie file
1706               if (!var->ts_target.isEmpty()
1707                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1708                 tsFile->getVirtualVariableGroup()->addChild(var);
1709             }
1710
1711             tsFile->solveFieldRefInheritance(true);
1712
1713             if (file->timeseries == CFile::timeseries_attr::exclusive)
1714               field->enabled = false;
1715           }
1716         }
1717
1718         // Finally disable the original file is need be
1719         if (file->timeseries == CFile::timeseries_attr::only)
1720          file->enabled = false;
1721       }
1722     }
1723   }
1724
1725   //! Client side: Send information of reference grid of active fields
1726   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
1727   {
1728     std::set<StdString> gridIds;
1729     int sizeFile = activeFiles.size();
1730     CFile* filePtr(NULL);
1731
1732     // Firstly, find all reference grids of all active fields
1733     for (int i = 0; i < sizeFile; ++i)
1734     {
1735       filePtr = activeFiles[i];
1736       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1737       int sizeField = enabledFields.size();
1738       for (int numField = 0; numField < sizeField; ++numField)
1739       {
1740         if (0 != enabledFields[numField]->getRelGrid())
1741           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1742       }
1743     }
1744
1745     // Create all reference grids on server side
1746     StdString gridDefRoot("grid_definition");
1747     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1748     std::set<StdString>::const_iterator it, itE = gridIds.end();
1749     for (it = gridIds.begin(); it != itE; ++it)
1750     {
1751       gridPtr->sendCreateChild(*it);
1752       CGrid::get(*it)->sendAllAttributesToServer();
1753       CGrid::get(*it)->sendAllDomains();
1754       CGrid::get(*it)->sendAllAxis();
1755       CGrid::get(*it)->sendAllScalars();
1756     }
1757   }
1758
1759   //! Client side: Send information of reference domain, axis and scalar of active fields
1760   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
1761   {
1762     std::set<StdString> domainIds, axisIds, scalarIds;
1763
1764     // Find all reference domain and axis of all active fields
1765     int numEnabledFiles = activeFiles.size();
1766     for (int i = 0; i < numEnabledFiles; ++i)
1767     {
1768       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
1769       int numEnabledFields = enabledFields.size();
1770       for (int j = 0; j < numEnabledFields; ++j)
1771       {
1772         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1773         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1774         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1775         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1776       }
1777     }
1778
1779     // Create all reference axis on server side
1780     std::set<StdString>::iterator itDom, itAxis, itScalar;
1781     std::set<StdString>::const_iterator itE;
1782
1783     StdString scalarDefRoot("scalar_definition");
1784     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1785     itE = scalarIds.end();
1786     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1787     {
1788       if (!itScalar->empty())
1789       {
1790         scalarPtr->sendCreateChild(*itScalar);
1791         CScalar::get(*itScalar)->sendAllAttributesToServer();
1792       }
1793     }
1794
1795     StdString axiDefRoot("axis_definition");
1796     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1797     itE = axisIds.end();
1798     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1799     {
1800       if (!itAxis->empty())
1801       {
1802         axisPtr->sendCreateChild(*itAxis);
1803         CAxis::get(*itAxis)->sendAllAttributesToServer();
1804       }
1805     }
1806
1807     // Create all reference domains on server side
1808     StdString domDefRoot("domain_definition");
1809     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1810     itE = domainIds.end();
1811     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1812     {
1813       if (!itDom->empty()) {
1814          domPtr->sendCreateChild(*itDom);
1815          CDomain::get(*itDom)->sendAllAttributesToServer();
1816       }
1817     }
1818   }
1819
1820   //! Update calendar in each time step
1821   void CContext::updateCalendar(int step)
1822   {
1823      int prevStep = calendar->getStep();
1824
1825      if (prevStep < step)
1826      {
1827        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1828        {
1829          doPreTimestepOperationsForEnabledReadModeFiles();
1830        }
1831
1832        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1833        calendar->update(step);
1834        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1835  #ifdef XIOS_MEMTRACK_LIGHT
1836        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1837  #endif
1838
1839        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1840        {
1841          doPostTimestepOperationsForEnabledReadModeFiles();
1842          garbageCollector.invalidate(calendar->getCurrentDate());
1843        }
1844      }
1845      else if (prevStep == step)
1846        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
1847      else // if (prevStep > step)
1848        ERROR("void CContext::updateCalendar(int step)",
1849              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
1850   }
1851
1852   void CContext::initReadFiles(void)
1853   {
1854      vector<CFile*>::const_iterator it;
1855
1856      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
1857      {
1858         (*it)->initRead();
1859      }
1860   }
1861
1862   //! Server side: Create header of netcdf file
1863   void CContext::createFileHeader(void)
1864   {
1865      vector<CFile*>::const_iterator it;
1866      if (!hasClient && hasServer) 
1867        for (it=enabledFiles.begin(); it != enabledFiles.end(); it++) (*it)->initWrite();
1868      else if (hasClient && hasServer)
1869        for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)  (*it)->initWrite();
1870   }
1871
1872   //! Get current context
1873   CContext* CContext::getCurrent(void)
1874   {
1875     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1876   }
1877
1878   /*!
1879   \brief Set context with an id be the current context
1880   \param [in] id identity of context to be set to current
1881   */
1882   void CContext::setCurrent(const string& id)
1883   {
1884     CObjectFactory::SetCurrentContextId(id);
1885     CGroupFactory::SetCurrentContextId(id);
1886   }
1887
1888  /*!
1889  \brief Create a context with specific id
1890  \param [in] id identity of new context
1891  \return pointer to the new context or already-existed one with identity id
1892  */
1893  CContext* CContext::create(const StdString& id)
1894  {
1895    CContext::setCurrent(id);
1896
1897    bool hasctxt = CContext::has(id);
1898    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1899    getRoot();
1900    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1901
1902#define DECLARE_NODE(Name_, name_) \
1903    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1904#define DECLARE_NODE_PAR(Name_, name_)
1905#include "node_type.conf"
1906
1907    return (context);
1908  }
1909
1910
1911     //! Server side: Receive a message to do some post processing
1912  void CContext::recvRegistry(CEventServer& event)
1913  {
1914    CBufferIn* buffer=event.subEvents.begin()->buffer;
1915    string id;
1916    *buffer>>id;
1917    get(id)->recvRegistry(*buffer);
1918  }
1919
1920  void CContext::recvRegistry(CBufferIn& buffer)
1921  {
1922    if (server->intraCommRank==0)
1923    {
1924      CRegistry registry(server->intraComm) ;
1925      registry.fromBuffer(buffer) ;
1926      registryOut->mergeRegistry(registry) ;
1927    }
1928  }
1929
1930  void CContext::sendRegistry(void)
1931  {
1932    registryOut->hierarchicalGatherRegistry() ;
1933
1934    // Use correct context client to send message
1935    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1936    for (int i = 0; i < nbSrvPools; ++i)
1937    {
1938      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1939      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1940        if (contextClientTmp->isServerLeader())
1941        {
1942           CMessage msg ;
1943           if (hasServer)
1944             msg<<this->getIdServer(i);
1945           else
1946             msg<<this->getIdServer();
1947           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1948           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1949           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1950             event.push(*itRank,1,msg);
1951           contextClientTmp->sendEvent(event);
1952         }
1953         else contextClientTmp->sendEvent(event);
1954    }
1955  }
1956
1957  /*!
1958  * \fn bool CContext::isFinalized(void)
1959  * Context is finalized if it received context post finalize event.
1960  */
1961  bool CContext::isFinalized(void)
1962  {
1963    return finalized;
1964  }
1965
1966} // namespace xios
Note: See TracBrowser for help on using the repository browser.