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

Last change on this file since 1349 was 1349, checked in by ymipsl, 7 years ago

New method to distribute file on server 2 : memory consumption of grids is now taking into account.
This new method can be activated using a specific variable from xios context :
<variable id="server2_dist_file_memory" type="bool">true_or_false</variable>

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