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

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

Improving buffer evaluation in the (rare) case of a context with no active fields.

  • 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.3 KB
Line 
1#include "context.hpp"
2#include "attribute_template.hpp"
3#include "object_template.hpp"
4#include "group_template.hpp"
5
6#include "calendar_type.hpp"
7#include "duration.hpp"
8
9#include "context_client.hpp"
10#include "context_server.hpp"
11#include "nc4_data_output.hpp"
12#include "node_type.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "timer.hpp"
17#include "memtrack.hpp"
18#include <limits>
19#include <fstream>
20#include "server.hpp"
21#include "distribute_file_server2.hpp"
22
23namespace xios {
24
25  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         // As calendar attributes are sent even if there are no active files or fields, maps are initialized according the size of calendar attributes
1485     std::map<int, StdSize> attributesSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1486     maxEventSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1487
1488     std::vector<CFile*>& fileList = this->enabledFiles;
1489     size_t numEnabledFiles = fileList.size();
1490     for (size_t i = 0; i < numEnabledFiles; ++i)
1491     {
1492//         CFile* file = this->enabledWriteModeFiles[i];
1493        CFile* file = fileList[i];
1494        std::vector<CField*> enabledFields = file->getEnabledFields();
1495        size_t numEnabledFields = enabledFields.size();
1496        for (size_t j = 0; j < numEnabledFields; ++j)
1497        {
1498          const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient, bufferForWriting);
1499          std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1500          for (; it != itE; ++it)
1501          {
1502                     // If attributesSize[it->first] does not exist, it will be zero-initialized
1503                     // so we can use it safely without checking for its existence
1504             if (attributesSize[it->first] < it->second)
1505                           attributesSize[it->first] = it->second;
1506
1507                     if (maxEventSize[it->first] < it->second)
1508                           maxEventSize[it->first] = it->second;
1509          }
1510        }
1511     }
1512     return attributesSize;
1513   }
1514
1515   /*!
1516    * Compute the required buffer size to send the fields data.
1517    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1518    * \param [in] contextClient
1519    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1520      This flag is only true for client and server-1 for communication with server-2
1521    */
1522   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize,
1523                                                      CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
1524   {
1525     std::map<int, StdSize> dataSize;
1526
1527     // Find all reference domain and axis of all active fields
1528     std::vector<CFile*>& fileList = bufferForWriting ? this->enabledWriteModeFiles : this->enabledReadModeFiles;
1529     size_t numEnabledFiles = fileList.size();
1530     for (size_t i = 0; i < numEnabledFiles; ++i)
1531     {
1532//       CFile* file = this->enabledFiles[i];
1533       CFile* file = fileList[i];
1534       if (file->getContextClient() == contextClient)
1535       {
1536         std::vector<CField*> enabledFields = file->getEnabledFields();
1537         size_t numEnabledFields = enabledFields.size();
1538         for (size_t j = 0; j < numEnabledFields; ++j)
1539         {
1540           // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1541           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient,bufferForWriting);
1542           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1543           for (; it != itE; ++it)
1544           {
1545             // If dataSize[it->first] does not exist, it will be zero-initialized
1546             // so we can use it safely without checking for its existance
1547                 if (CXios::isOptPerformance)
1548               dataSize[it->first] += it->second;
1549             else if (dataSize[it->first] < it->second)
1550               dataSize[it->first] = it->second;
1551
1552                 if (maxEventSize[it->first] < it->second)
1553               maxEventSize[it->first] = it->second;
1554           }
1555         }
1556       }
1557     }
1558     return dataSize;
1559   }
1560
1561   //! Client side: Send infomation of active files (files are enabled to write out)
1562   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
1563   {
1564     int size = activeFiles.size();
1565
1566     // In a context, each type has a root definition, e.g: axis, domain, field.
1567     // Every object must be a child of one of these root definition. In this case
1568     // all new file objects created on server must be children of the root "file_definition"
1569     StdString fileDefRoot("file_definition");
1570     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1571
1572     for (int i = 0; i < size; ++i)
1573     {
1574       CFile* f = activeFiles[i];
1575       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1576       f->sendAllAttributesToServer(f->getContextClient());
1577       f->sendAddAllVariables(f->getContextClient());
1578     }
1579   }
1580
1581   //! Client side: Send information of active fields (ones are written onto files)
1582   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
1583   {
1584     int size = activeFiles.size();
1585     for (int i = 0; i < size; ++i)
1586     {
1587       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
1588     }
1589   }
1590
1591   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1592   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1593   {
1594     if (!hasClient) return;
1595
1596     const vector<CAxis*> allAxis = CAxis::getAll();
1597     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1598       (*it)->checkEligibilityForCompressedOutput();
1599
1600     const vector<CDomain*> allDomains = CDomain::getAll();
1601     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1602       (*it)->checkEligibilityForCompressedOutput();
1603
1604     const vector<CGrid*> allGrids = CGrid::getAll();
1605     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1606       (*it)->checkEligibilityForCompressedOutput();
1607   }
1608
1609   //! Client side: Prepare the timeseries by adding the necessary files
1610   void CContext::prepareTimeseries()
1611   {
1612     if (!hasClient) return;
1613
1614     const std::vector<CFile*> allFiles = CFile::getAll();
1615     for (size_t i = 0; i < allFiles.size(); i++)
1616     {
1617       CFile* file = allFiles[i];
1618
1619       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1620       for (size_t k = 0; k < vars.size(); k++)
1621       {
1622         CVariable* var = vars[k];
1623
1624         if (var->ts_target.isEmpty()
1625              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1626           fileVars.push_back(var);
1627
1628         if (!var->ts_target.isEmpty()
1629              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1630           fieldVars.push_back(var);
1631       }
1632
1633       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1634       {
1635         StdString fileNameStr("%file_name%") ;
1636         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1637         
1638         StdString fileName=file->getFileOutputName();
1639         size_t pos=tsPrefix.find(fileNameStr) ;
1640         while (pos!=std::string::npos)
1641         {
1642           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1643           pos=tsPrefix.find(fileNameStr) ;
1644         }
1645       
1646         const std::vector<CField*> allFields = file->getAllFields();
1647         for (size_t j = 0; j < allFields.size(); j++)
1648         {
1649           CField* field = allFields[j];
1650
1651           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1652           {
1653             CFile* tsFile = CFile::create();
1654             tsFile->duplicateAttributes(file);
1655
1656             // Add variables originating from file and targeted to timeserie file
1657             for (size_t k = 0; k < fileVars.size(); k++)
1658               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1659
1660           
1661             tsFile->name = tsPrefix + "_";
1662             if (!field->name.isEmpty())
1663               tsFile->name.get() += field->name;
1664             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1665               tsFile->name.get() += field->field_ref;
1666             else
1667               tsFile->name.get() += field->getId();
1668
1669             if (!field->ts_split_freq.isEmpty())
1670               tsFile->split_freq = field->ts_split_freq;
1671
1672             CField* tsField = tsFile->addField();
1673             tsField->field_ref = field->getId();
1674
1675             // Add variables originating from file and targeted to timeserie field
1676             for (size_t k = 0; k < fieldVars.size(); k++)
1677               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1678
1679             vars = field->getAllVariables();
1680             for (size_t k = 0; k < vars.size(); k++)
1681             {
1682               CVariable* var = vars[k];
1683
1684               // Add variables originating from field and targeted to timeserie field
1685               if (var->ts_target.isEmpty()
1686                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1687                 tsField->getVirtualVariableGroup()->addChild(var);
1688
1689               // Add variables originating from field and targeted to timeserie file
1690               if (!var->ts_target.isEmpty()
1691                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1692                 tsFile->getVirtualVariableGroup()->addChild(var);
1693             }
1694
1695             tsFile->solveFieldRefInheritance(true);
1696
1697             if (file->timeseries == CFile::timeseries_attr::exclusive)
1698               field->enabled = false;
1699           }
1700         }
1701
1702         // Finally disable the original file is need be
1703         if (file->timeseries == CFile::timeseries_attr::only)
1704          file->enabled = false;
1705       }
1706     }
1707   }
1708
1709   //! Client side: Send information of reference grid of active fields
1710   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
1711   {
1712     std::set<StdString> gridIds;
1713     int sizeFile = activeFiles.size();
1714     CFile* filePtr(NULL);
1715
1716     // Firstly, find all reference grids of all active fields
1717     for (int i = 0; i < sizeFile; ++i)
1718     {
1719       filePtr = activeFiles[i];
1720       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1721       int sizeField = enabledFields.size();
1722       for (int numField = 0; numField < sizeField; ++numField)
1723       {
1724         if (0 != enabledFields[numField]->getRelGrid())
1725           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1726       }
1727     }
1728
1729     // Create all reference grids on server side
1730     StdString gridDefRoot("grid_definition");
1731     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1732     std::set<StdString>::const_iterator it, itE = gridIds.end();
1733     for (it = gridIds.begin(); it != itE; ++it)
1734     {
1735       gridPtr->sendCreateChild(*it);
1736       CGrid::get(*it)->sendAllAttributesToServer();
1737       CGrid::get(*it)->sendAllDomains();
1738       CGrid::get(*it)->sendAllAxis();
1739       CGrid::get(*it)->sendAllScalars();
1740     }
1741   }
1742
1743   //! Client side: Send information of reference domain, axis and scalar of active fields
1744   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
1745   {
1746     std::set<StdString> domainIds, axisIds, scalarIds;
1747
1748     // Find all reference domain and axis of all active fields
1749     int numEnabledFiles = activeFiles.size();
1750     for (int i = 0; i < numEnabledFiles; ++i)
1751     {
1752       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
1753       int numEnabledFields = enabledFields.size();
1754       for (int j = 0; j < numEnabledFields; ++j)
1755       {
1756         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1757         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1758         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1759         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1760       }
1761     }
1762
1763     // Create all reference axis on server side
1764     std::set<StdString>::iterator itDom, itAxis, itScalar;
1765     std::set<StdString>::const_iterator itE;
1766
1767     StdString scalarDefRoot("scalar_definition");
1768     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1769     itE = scalarIds.end();
1770     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1771     {
1772       if (!itScalar->empty())
1773       {
1774         scalarPtr->sendCreateChild(*itScalar);
1775         CScalar::get(*itScalar)->sendAllAttributesToServer();
1776       }
1777     }
1778
1779     StdString axiDefRoot("axis_definition");
1780     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1781     itE = axisIds.end();
1782     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1783     {
1784       if (!itAxis->empty())
1785       {
1786         axisPtr->sendCreateChild(*itAxis);
1787         CAxis::get(*itAxis)->sendAllAttributesToServer();
1788       }
1789     }
1790
1791     // Create all reference domains on server side
1792     StdString domDefRoot("domain_definition");
1793     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1794     itE = domainIds.end();
1795     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1796     {
1797       if (!itDom->empty()) {
1798          domPtr->sendCreateChild(*itDom);
1799          CDomain::get(*itDom)->sendAllAttributesToServer();
1800       }
1801     }
1802   }
1803
1804   //! Update calendar in each time step
1805   void CContext::updateCalendar(int step)
1806   {
1807      int prevStep = calendar->getStep();
1808
1809      if (prevStep < step)
1810      {
1811        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1812        {
1813          doPreTimestepOperationsForEnabledReadModeFiles();
1814        }
1815
1816        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1817        calendar->update(step);
1818        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1819  #ifdef XIOS_MEMTRACK_LIGHT
1820        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1821  #endif
1822
1823        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1824        {
1825          doPostTimestepOperationsForEnabledReadModeFiles();
1826          garbageCollector.invalidate(calendar->getCurrentDate());
1827        }
1828      }
1829      else if (prevStep == step)
1830        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
1831      else // if (prevStep > step)
1832        ERROR("void CContext::updateCalendar(int step)",
1833              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
1834   }
1835
1836   void CContext::initReadFiles(void)
1837   {
1838      vector<CFile*>::const_iterator it;
1839
1840      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
1841      {
1842         (*it)->initRead();
1843      }
1844   }
1845
1846   //! Server side: Create header of netcdf file
1847   void CContext::createFileHeader(void)
1848   {
1849      vector<CFile*>::const_iterator it;
1850
1851      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1852      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
1853      {
1854         (*it)->initWrite();
1855      }
1856   }
1857
1858   //! Get current context
1859   CContext* CContext::getCurrent(void)
1860   {
1861     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1862   }
1863
1864   /*!
1865   \brief Set context with an id be the current context
1866   \param [in] id identity of context to be set to current
1867   */
1868   void CContext::setCurrent(const string& id)
1869   {
1870     CObjectFactory::SetCurrentContextId(id);
1871     CGroupFactory::SetCurrentContextId(id);
1872   }
1873
1874  /*!
1875  \brief Create a context with specific id
1876  \param [in] id identity of new context
1877  \return pointer to the new context or already-existed one with identity id
1878  */
1879  CContext* CContext::create(const StdString& id)
1880  {
1881    CContext::setCurrent(id);
1882
1883    bool hasctxt = CContext::has(id);
1884    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1885    getRoot();
1886    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1887
1888#define DECLARE_NODE(Name_, name_) \
1889    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1890#define DECLARE_NODE_PAR(Name_, name_)
1891#include "node_type.conf"
1892
1893    return (context);
1894  }
1895
1896
1897     //! Server side: Receive a message to do some post processing
1898  void CContext::recvRegistry(CEventServer& event)
1899  {
1900    CBufferIn* buffer=event.subEvents.begin()->buffer;
1901    string id;
1902    *buffer>>id;
1903    get(id)->recvRegistry(*buffer);
1904  }
1905
1906  void CContext::recvRegistry(CBufferIn& buffer)
1907  {
1908    if (server->intraCommRank==0)
1909    {
1910      CRegistry registry(server->intraComm) ;
1911      registry.fromBuffer(buffer) ;
1912      registryOut->mergeRegistry(registry) ;
1913    }
1914  }
1915
1916  void CContext::sendRegistry(void)
1917  {
1918    registryOut->hierarchicalGatherRegistry() ;
1919
1920    // Use correct context client to send message
1921    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1922    for (int i = 0; i < nbSrvPools; ++i)
1923    {
1924      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1925      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1926        if (contextClientTmp->isServerLeader())
1927        {
1928           CMessage msg ;
1929           if (hasServer)
1930             msg<<this->getIdServer(i);
1931           else
1932             msg<<this->getIdServer();
1933           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1934           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1935           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1936             event.push(*itRank,1,msg);
1937           contextClientTmp->sendEvent(event);
1938         }
1939         else contextClientTmp->sendEvent(event);
1940    }
1941  }
1942
1943  /*!
1944  * \fn bool CContext::isFinalized(void)
1945  * Context is finalized if it received context post finalize event.
1946  */
1947  bool CContext::isFinalized(void)
1948  {
1949    return finalized;
1950  }
1951
1952} // namespace xios
Note: See TracBrowser for help on using the repository browser.