source: XIOS/dev/dev_trunk_omp/src/node/context.cpp @ 1628

Last change on this file since 1628 was 1628, checked in by yushan, 5 years ago

bug fix (Nb of files less than Nb of servers)

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