source: XIOS/dev/XIOS_DEV_CMIP6/src/node/context.cpp @ 1482

Last change on this file since 1482 was 1418, checked in by ymipsl, 6 years ago

Fix for workflow reentrance : missing check at context finalize.

YM

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