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

Last change on this file since 1358 was 1358, checked in by rlacroix, 6 years ago

Support reentrant workflows and workflows with temporal integration for fields read from files.

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