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

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

Fix for workflow reentrance : missing check at context finalize.

YM

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