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

Last change on this file since 1390 was 1380, checked in by ymipsl, 6 years ago

Fix for previous commit (r1378) : forgotten argument for one eventLoop function
Attemping to solve a dead-lock rising at finalize :
Server 1 must be able receive buffer of on other context (ie from server2) when awaiting free buffer.

YM


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