source: XIOS/trunk/src/node/context.cpp @ 1542

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

Replacing Boost's unordered_map and shared_pointer by its STL counterparts.

Two notes for Curie:

  • one can see the content of unordered_map with ddt only if XIOS has been compiled with gnu
  • XIOS will not compile any more with pgi (all available versions use old STL which are not up to the c++11 norms)
  • 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.3 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
[1542]25  std::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   {
[1542]68      if (root.get()==NULL) root=std::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   */
[1542]78   std::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   */
[1542]89   void CContext::setCalendar(std::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            {
[1489]887              if (allFiles[i]->output_freq.isEmpty())
[1488]888              {
889                 ERROR("CContext::findEnabledFiles()",
890                     << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
891                     <<" \".")
892              }
[1158]893              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
894              {
895                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
896                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
897                    <<"\" is less than the time step. File will not be written."<<endl;
898              }
899              else
[300]900               enabledFiles.push_back(allFiles[i]);
[1158]901            }
[430]902         }
[1158]903         else
904         {
[1489]905           if (allFiles[i]->output_freq.isEmpty())
[1488]906           {
907              ERROR("CContext::findEnabledFiles()",
908                  << "Mandatory attribute output_freq must be defined for file \""<<allFiles[i]->getFileOutputName()
909                  <<" \".")
910           }
[1158]911           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
912           {
913             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
914                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
915                 <<"\" is less than the time step. File will not be written."<<endl;
916           }
917           else
918             enabledFiles.push_back(allFiles[i]); // otherwise true by default
919         }
[300]920
921      if (enabledFiles.size() == 0)
922         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
923               << getId() << "\" !");
[1021]924
[300]925   }
926
[1208]927   void CContext::distributeFiles(void)
928   {
[1349]929     bool distFileMemory=false ;
930     distFileMemory=CXios::getin<bool>("server2_dist_file_memory", distFileMemory);
931
932     if (distFileMemory) distributeFileOverMemoryBandwith() ;
933     else distributeFileOverBandwith() ;
934   }
935
936
937   void CContext::distributeFileOverBandwith(void)
938   {
[1215]939     double eps=std::numeric_limits<double>::epsilon()*10 ;
940     
[1208]941     // If primary server
942     if (hasServer && hasClient)
943     {
[1349]944       std::ofstream ofs(("distribute_file_"+getId()+".dat").c_str(), std::ofstream::out);
[1212]945       int nbPools = clientPrimServer.size();
946
[1208]947       // (1) Find all enabled files in write mode
[1232]948       // for (int i = 0; i < this->enabledFiles.size(); ++i)
949       // {
950       //   if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
951       //    enabledWriteModeFiles.push_back(enabledFiles[i]);
952       // }
[1208]953
954       // (2) Estimate the data volume for each file
955       int size = this->enabledWriteModeFiles.size();
[1215]956       std::vector<std::pair<double, CFile*> > dataSizeMap;
957       double dataPerPool = 0;
958       int nfield=0 ;
[1349]959       ofs<<size<<endl ;
[1208]960       for (size_t i = 0; i < size; ++i)
961       {
962         CFile* file = this->enabledWriteModeFiles[i];
[1349]963         ofs<<file->getId()<<endl ;
[1215]964         StdSize dataSize=0;
[1208]965         std::vector<CField*> enabledFields = file->getEnabledFields();
966         size_t numEnabledFields = enabledFields.size();
[1349]967         ofs<<numEnabledFields<<endl ;
968         for (size_t j = 0; j < numEnabledFields; ++j)
969         {
970           dataSize += enabledFields[j]->getGlobalWrittenSize() ;
971           ofs<<enabledFields[j]->grid->getId()<<endl ;
972           ofs<<enabledFields[j]->getGlobalWrittenSize()<<endl ;
973         }
[1215]974         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
975         double dataSizeSec= dataSize/ outFreqSec;
[1349]976         ofs<<dataSizeSec<<endl ;
[1215]977         nfield++ ;
978// add epsilon*nField to dataSizeSec in order to  preserve reproductive ordering when sorting
979         dataSizeMap.push_back(make_pair(dataSizeSec + dataSizeSec * eps * nfield , file));
980         dataPerPool += dataSizeSec;
[1208]981       }
[1212]982       dataPerPool /= nbPools;
[1208]983       std::sort(dataSizeMap.begin(), dataSizeMap.end());
984
[1212]985       // (3) Assign contextClient to each enabled file
[1215]986
987       std::multimap<double,int> poolDataSize ;
988// multimap is not garanty to preserve stable sorting in c++98 but it seems it does for c++11
989
990       int j;
991       double dataSize ;
992       for (j = 0 ; j < nbPools ; ++j) poolDataSize.insert(std::pair<double,int>(0.,j)) ; 
993             
[1212]994       for (int i = dataSizeMap.size()-1; i >= 0; --i)
[1208]995       {
[1215]996         dataSize=(*poolDataSize.begin()).first ;
997         j=(*poolDataSize.begin()).second ;
998         dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
999         dataSize+=dataSizeMap[i].first;
1000         poolDataSize.erase(poolDataSize.begin()) ;
1001         poolDataSize.insert(std::pair<double,int>(dataSize,j)) ; 
[1208]1002       }
[1212]1003
[1215]1004       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 ;
1005 
[1212]1006       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
[1232]1007       {
1008         enabledReadModeFiles[i]->setContextClient(client);         
1009       }
[1208]1010     }
1011     else
1012     {
1013       for (int i = 0; i < this->enabledFiles.size(); ++i)
1014         enabledFiles[i]->setContextClient(client);
1015     }
1016   }
1017
[1349]1018   void CContext::distributeFileOverMemoryBandwith(void)
1019   {
1020     // If primary server
1021     if (hasServer && hasClient)
1022     {
1023       int nbPools = clientPrimServer.size();
1024       double ratio=0.5 ;
1025       ratio=CXios::getin<double>("server2_dist_file_memory_ratio", ratio);
1026
1027       int nFiles = this->enabledWriteModeFiles.size();
1028       vector<SDistFile> files(nFiles);
1029       vector<SDistGrid> grids;
1030       map<string,int> gridMap ;
1031       string gridId; 
1032       int gridIndex=0 ;
1033
1034       for (size_t i = 0; i < nFiles; ++i)
1035       {
1036         StdSize dataSize=0;
1037         CFile* file = this->enabledWriteModeFiles[i];
1038         std::vector<CField*> enabledFields = file->getEnabledFields();
1039         size_t numEnabledFields = enabledFields.size();
1040
1041         files[i].id_=file->getId() ;
1042         files[i].nbGrids_=numEnabledFields;
1043         files[i].assignedGrid_ = new int[files[i].nbGrids_] ;
1044         
1045         for (size_t j = 0; j < numEnabledFields; ++j)
1046         {
1047           gridId=enabledFields[j]->grid->getId() ;
1048           if (gridMap.find(gridId)==gridMap.end())
1049           {
1050              gridMap[gridId]=gridIndex  ;
1051              SDistGrid newGrid; 
1052              grids.push_back(newGrid) ;
1053              gridIndex++ ;
1054           }
1055           files[i].assignedGrid_[j]=gridMap[gridId] ;
1056           grids[files[i].assignedGrid_[j]].size_=enabledFields[j]->getGlobalWrittenSize() ;
1057           dataSize += enabledFields[j]->getGlobalWrittenSize() ; // usefull
1058         }
1059         double outFreqSec = (Time)(calendar->getCurrentDate()+file->output_freq)-(Time)(calendar->getCurrentDate()) ;
1060         files[i].bandwith_= dataSize/ outFreqSec ;
1061       }
1062
1063       double bandwith=0 ;
1064       double memory=0 ;
1065   
1066       for(int i=0; i<nFiles; i++)  bandwith+=files[i].bandwith_ ;
1067       for(int i=0; i<nFiles; i++)  files[i].bandwith_ = files[i].bandwith_/bandwith * ratio ;
1068
1069       for(int i=0; i<grids.size(); i++)  memory+=grids[i].size_ ;
1070       for(int i=0; i<grids.size(); i++)  grids[i].size_ = grids[i].size_ / memory * (1.0-ratio) ;
1071       
1072       distributeFileOverServer2(nbPools, grids.size(), &grids[0], nFiles, &files[0]) ;
1073
1074       vector<double> memorySize(nbPools,0.) ;
1075       vector< set<int> > serverGrids(nbPools) ;
1076       vector<double> bandwithSize(nbPools,0.) ;
1077       
1078       for (size_t i = 0; i < nFiles; ++i)
1079       {
1080         bandwithSize[files[i].assignedServer_] += files[i].bandwith_* bandwith /ratio ;
1081         for(int j=0 ; j<files[i].nbGrids_;j++)
1082         {
1083           if (serverGrids[files[i].assignedServer_].find(files[i].assignedGrid_[j]) == serverGrids[files[i].assignedServer_].end())
1084           {
1085             memorySize[files[i].assignedServer_]+= grids[files[i].assignedGrid_[j]].size_ * memory / (1.0-ratio);
1086             serverGrids[files[i].assignedServer_].insert(files[i].assignedGrid_[j]) ;
1087           }
1088         }
1089         enabledWriteModeFiles[i]->setContextClient(clientPrimServer[files[i].assignedServer_]) ;
1090         delete [] files[i].assignedGrid_ ;
1091       }
1092
1093       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 ;
1094       for (int i = 0; i < nbPools; ++i) info(100)<<"Pool server level2 "<<i<<"   assigned grid memory "<<memorySize[i]*100/1024./1024.<<" Mb"<<endl ;
1095
1096
1097       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
1098       {
1099         enabledReadModeFiles[i]->setContextClient(client);         
1100       }
1101
1102   }
1103   else
1104   {
1105     for (int i = 0; i < this->enabledFiles.size(); ++i)
1106        enabledFiles[i]->setContextClient(client);
1107   }
1108}
1109
1110
1111
[1232]1112   /*!
1113      Find all files in write mode
1114   */
1115   void CContext::findEnabledWriteModeFiles(void)
1116   {
1117     int size = this->enabledFiles.size();
1118     for (int i = 0; i < size; ++i)
1119     {
1120       if (enabledFiles[i]->mode.isEmpty() || 
1121          (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
1122        enabledWriteModeFiles.push_back(enabledFiles[i]);
1123     }
1124   }
1125
1126   /*!
1127      Find all files in read mode
1128   */
[598]1129   void CContext::findEnabledReadModeFiles(void)
1130   {
1131     int size = this->enabledFiles.size();
1132     for (int i = 0; i < size; ++i)
1133     {
1134       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
1135        enabledReadModeFiles.push_back(enabledFiles[i]);
1136     }
1137   }
1138
[300]1139   void CContext::closeAllFile(void)
1140   {
[347]1141     std::vector<CFile*>::const_iterator
[300]1142            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
[509]1143
[300]1144     for (; it != end; it++)
1145     {
1146       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
1147       (*it)->close();
1148     }
1149   }
[509]1150
1151   /*!
1152   \brief Dispatch event received from client
1153      Whenever a message is received in buffer of server, it will be processed depending on
1154   its event type. A new event type should be added in the switch list to make sure
1155   it processed on server side.
1156   \param [in] event: Received message
1157   */
[300]1158   bool CContext::dispatchEvent(CEventServer& event)
1159   {
[509]1160
[549]1161      if (SuperClass::dispatchEvent(event)) return true;
[300]1162      else
1163      {
1164        switch(event.type)
1165        {
1166           case EVENT_ID_CLOSE_DEFINITION :
[549]1167             recvCloseDefinition(event);
1168             return true;
1169             break;
[584]1170           case EVENT_ID_UPDATE_CALENDAR:
[549]1171             recvUpdateCalendar(event);
1172             return true;
1173             break;
[300]1174           case EVENT_ID_CREATE_FILE_HEADER :
[549]1175             recvCreateFileHeader(event);
1176             return true;
1177             break;
[509]1178           case EVENT_ID_POST_PROCESS:
[549]1179             recvPostProcessing(event);
1180             return true;
[697]1181            case EVENT_ID_SEND_REGISTRY:
1182             recvRegistry(event);
1183             return true;
[1025]1184             break;
1185            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
1186             recvPostProcessingGlobalAttributes(event);
1187             return true;
1188             break;
1189            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
1190             recvProcessingGridOfEnabledFields(event);
1191             return true;
1192             break;
[300]1193           default :
1194             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
[549]1195                    <<"Unknown Event");
1196           return false;
[300]1197         }
1198      }
1199   }
[509]1200
1201   //! Client side: Send a message to server to make it close
[300]1202   void CContext::sendCloseDefinition(void)
1203   {
[987]1204     // Use correct context client to send message
[1030]1205     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1206     for (int i = 0; i < nbSrvPools; ++i)
[300]1207     {
[1009]1208       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1209       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
1210       if (contextClientTmp->isServerLeader())
1211       {
1212         CMessage msg;
1213         if (hasServer)
1214           msg<<this->getIdServer(i);
1215         else
1216           msg<<this->getIdServer();
1217         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1218         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1219           event.push(*itRank,1,msg);
1220         contextClientTmp->sendEvent(event);
1221       }
1222       else contextClientTmp->sendEvent(event);
[300]1223     }
1224   }
[509]1225
1226   //! Server side: Receive a message of client announcing a context close
[300]1227   void CContext::recvCloseDefinition(CEventServer& event)
1228   {
1229      CBufferIn* buffer=event.subEvents.begin()->buffer;
1230      string id;
[549]1231      *buffer>>id;
[509]1232      get(id)->closeDefinition();
[300]1233   }
[509]1234
1235   //! Client side: Send a message to update calendar in each time step
[300]1236   void CContext::sendUpdateCalendar(int step)
1237   {
[987]1238     // Use correct context client to send message
[1030]1239    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1240     for (int i = 0; i < nbSrvPools; ++i)
1241     {
1242       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1243       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
[987]1244
[1009]1245         if (contextClientTmp->isServerLeader())
1246         {
1247           CMessage msg;
1248           if (hasServer)
1249             msg<<this->getIdServer(i)<<step;
1250           else
1251             msg<<this->getIdServer()<<step;
1252           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1253           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1254             event.push(*itRank,1,msg);
1255           contextClientTmp->sendEvent(event);
1256         }
1257         else contextClientTmp->sendEvent(event);
1258     }
[300]1259   }
[509]1260
1261   //! Server side: Receive a message of client annoucing calendar update
[300]1262   void CContext::recvUpdateCalendar(CEventServer& event)
1263   {
1264      CBufferIn* buffer=event.subEvents.begin()->buffer;
1265      string id;
[549]1266      *buffer>>id;
1267      get(id)->recvUpdateCalendar(*buffer);
[300]1268   }
[509]1269
1270   //! Server side: Receive a message of client annoucing calendar update
[300]1271   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1272   {
[549]1273      int step;
1274      buffer>>step;
1275      updateCalendar(step);
[987]1276      if (hasClient && hasServer)
1277      {       
1278        sendUpdateCalendar(step);
1279      }
[300]1280   }
[509]1281
1282   //! Client side: Send a message to create header part of netcdf file
[300]1283   void CContext::sendCreateFileHeader(void)
1284   {
[987]1285     // Use correct context client to send message
[1030]1286     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1287     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1288     for (int i = 0; i < nbSrvPools; ++i)
1289     {
1290       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1291       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
[983]1292
[1009]1293       if (contextClientTmp->isServerLeader())
1294       {
1295         CMessage msg;
1296         if (hasServer)
1297           msg<<this->getIdServer(i);
1298         else
1299           msg<<this->getIdServer();
1300         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1301         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1302           event.push(*itRank,1,msg) ;
1303         contextClientTmp->sendEvent(event);
1304       }
1305       else contextClientTmp->sendEvent(event);
[300]1306     }
1307   }
[509]1308
1309   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1310   void CContext::recvCreateFileHeader(CEventServer& event)
1311   {
1312      CBufferIn* buffer=event.subEvents.begin()->buffer;
1313      string id;
[549]1314      *buffer>>id;
1315      get(id)->recvCreateFileHeader(*buffer);
[300]1316   }
[509]1317
1318   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1319   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1320   {
[987]1321      if (!hasClient && hasServer) 
1322        createFileHeader();
[300]1323   }
[509]1324
1325   //! Client side: Send a message to do some post processing on server
[1025]1326   void CContext::sendProcessingGridOfEnabledFields()
1327   {
1328      // Use correct context client to send message
[1030]1329     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]1330     for (int i = 0; i < nbSrvPools; ++i)
1331     {
1332       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1333       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
[1025]1334
[1027]1335       if (contextClientTmp->isServerLeader())
1336       {
1337         CMessage msg;
[1099]1338         if (hasServer)
1339           msg<<this->getIdServer(i);
1340         else
1341           msg<<this->getIdServer();
[1027]1342         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1343         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1344           event.push(*itRank,1,msg);
1345         contextClientTmp->sendEvent(event);
1346       }
1347       else contextClientTmp->sendEvent(event);
[1025]1348     }
1349   }
1350
1351   //! Server side: Receive a message to do some post processing
1352   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1353   {
1354      CBufferIn* buffer=event.subEvents.begin()->buffer;
1355      string id;
[1144]1356      *buffer>>id;     
[1025]1357   }
1358
1359   //! Client side: Send a message to do some post processing on server
[509]1360   void CContext::sendPostProcessing()
1361   {
[987]1362      // Use correct context client to send message
[1030]1363     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1364     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1365     for (int i = 0; i < nbSrvPools; ++i)
[509]1366     {
[1009]1367       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1368       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1369       if (contextClientTmp->isServerLeader())
1370       {
1371         CMessage msg;
1372         if (hasServer)
1373           msg<<this->getIdServer(i);
1374         else
1375           msg<<this->getIdServer();
1376         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1377         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[987]1378         event.push(*itRank,1,msg);
[1009]1379         contextClientTmp->sendEvent(event);
1380       }
1381       else contextClientTmp->sendEvent(event);
[509]1382     }
1383   }
1384
1385   //! Server side: Receive a message to do some post processing
1386   void CContext::recvPostProcessing(CEventServer& event)
1387   {
1388      CBufferIn* buffer=event.subEvents.begin()->buffer;
1389      string id;
1390      *buffer>>id;
1391      get(id)->recvPostProcessing(*buffer);
1392   }
1393
1394   //! Server side: Receive a message to do some post processing
1395   void CContext::recvPostProcessing(CBufferIn& buffer)
1396   {
[549]1397      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
[509]1398      postProcessing();
1399   }
1400
[511]1401   const StdString& CContext::getIdServer()
1402   {
1403      if (hasClient)
1404      {
1405        idServer_ = this->getId();
1406        idServer_ += "_server";
1407        return idServer_;
1408      }
1409      if (hasServer) return (this->getId());
1410   }
1411
[1009]1412   const StdString& CContext::getIdServer(const int i)
1413   {
1414     idServer_ = this->getId();
1415     idServer_ += "_server_";
[1542]1416     idServer_ += std::to_string(static_cast<unsigned long long>(i));
[1009]1417     return idServer_;
1418   }
1419
1420
[509]1421   /*!
1422   \brief Do some simple post processings after parsing xml file
1423      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1424   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1425   which will be written out into netcdf files, are processed
1426   */
1427   void CContext::postProcessing()
1428   {
1429     if (isPostProcessed) return;
1430
[549]1431      // Make sure the calendar was correctly created
1432      if (!calendar)
1433        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1434      else if (calendar->getTimeStep() == NoneDu)
1435        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
[550]1436      // Calendar first update to set the current date equals to the start date
1437      calendar->update(0);
[509]1438
1439      // Find all inheritance in xml structure
1440      this->solveAllInheritance();
1441
[992]1442//      ShowTree(info(10));
[983]1443
[676]1444      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1445      // Warning: This must be done after solving the inheritance and before the rest of post-processing
[1025]1446      checkAxisDomainsGridsEligibilityForCompressedOutput();     
[676]1447
[711]1448      // Check if some automatic time series should be generated
[1144]1449      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
[711]1450
[1025]1451      // The timeseries should only be prepared in client
1452      if (hasClient && !hasServer) prepareTimeseries();
1453
[509]1454      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
[1232]1455      findEnabledFiles();
1456      findEnabledWriteModeFiles();
1457      findEnabledReadModeFiles();
1458
[1025]1459      // For now, only read files with client and only one level server
[1232]1460      // if (hasClient && !hasServer) findEnabledReadModeFiles();     
[509]1461
[1232]1462      // Find all enabled fields of each file     
1463      findAllEnabledFieldsInFiles(this->enabledWriteModeFiles);
1464      findAllEnabledFieldsInFiles(this->enabledReadModeFiles);
1465
[1025]1466      // For now, only read files with client and only one level server
[1232]1467      // if (hasClient && !hasServer)
1468      //   findAllEnabledFieldsInFiles(this->enabledReadModeFiles);     
[509]1469
[1144]1470      if (hasClient && !hasServer)
1471      {
[1232]1472        initReadFiles();
1473        // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1474        this->readAttributesOfEnabledFieldsInReadModeFiles();
[1144]1475      }
1476
[823]1477      // Only search and rebuild all reference objects of enable fields, don't transform
[1099]1478      this->solveOnlyRefOfEnabledFields(false);
[823]1479
[1099]1480      // Search and rebuild all reference object of enabled fields, and transform
[1129]1481      this->solveAllRefOfEnabledFieldsAndTransform(false);
[1099]1482
[593]1483      // Find all fields with read access from the public API
[1025]1484      if (hasClient && !hasServer) findFieldsWithReadAccess();
[593]1485      // and solve the all reference for them
[1025]1486      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
[593]1487
[509]1488      isPostProcessed = true;
1489   }
1490
[917]1491   /*!
1492    * Compute the required buffer size to send the attributes (mostly those grid related).
1493    * \param maxEventSize [in/out] the size of the bigger event for each connected server
[1330]1494    * \param [in] contextClient
1495    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1496      This flag is only true for client and server-1 for communication with server-2
[917]1497    */
[1330]1498   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize,
1499                                                           CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
[509]1500   {
[1372]1501         // As calendar attributes are sent even if there are no active files or fields, maps are initialized according the size of calendar attributes
1502     std::map<int, StdSize> attributesSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
1503     maxEventSize = CCalendarWrapper::get(CCalendarWrapper::GetDefName())->getMinimumBufferSizeForAttributes(contextClient);
[731]1504
[1370]1505     std::vector<CFile*>& fileList = this->enabledFiles;
1506     size_t numEnabledFiles = fileList.size();
1507     for (size_t i = 0; i < numEnabledFiles; ++i)
[731]1508     {
[1370]1509//         CFile* file = this->enabledWriteModeFiles[i];
1510        CFile* file = fileList[i];
1511        std::vector<CField*> enabledFields = file->getEnabledFields();
1512        size_t numEnabledFields = enabledFields.size();
1513        for (size_t j = 0; j < numEnabledFields; ++j)
1514        {
1515          const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize(contextClient, bufferForWriting);
1516          std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1517          for (; it != itE; ++it)
1518          {
1519                     // If attributesSize[it->first] does not exist, it will be zero-initialized
1520                     // so we can use it safely without checking for its existence
1521             if (attributesSize[it->first] < it->second)
1522                           attributesSize[it->first] = it->second;
[917]1523
[1370]1524                     if (maxEventSize[it->first] < it->second)
1525                           maxEventSize[it->first] = it->second;
1526          }
1527        }
[731]1528     }
1529     return attributesSize;
1530   }
1531
[917]1532   /*!
1533    * Compute the required buffer size to send the fields data.
1534    * \param maxEventSize [in/out] the size of the bigger event for each connected server
[1330]1535    * \param [in] contextClient
1536    * \param [in] bufferForWriting True if buffers are used for sending data for writing
1537      This flag is only true for client and server-1 for communication with server-2
[917]1538    */
[1330]1539   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize,
1540                                                      CContextClient* contextClient, bool bufferForWriting /*= "false"*/)
[731]1541   {
[730]1542     std::map<int, StdSize> dataSize;
[509]1543
1544     // Find all reference domain and axis of all active fields
[1330]1545     std::vector<CFile*>& fileList = bufferForWriting ? this->enabledWriteModeFiles : this->enabledReadModeFiles;
1546     size_t numEnabledFiles = fileList.size();
[730]1547     for (size_t i = 0; i < numEnabledFiles; ++i)
[509]1548     {
[1330]1549//       CFile* file = this->enabledFiles[i];
1550       CFile* file = fileList[i];
[1193]1551       if (file->getContextClient() == contextClient)
[1184]1552       {
[1370]1553         std::vector<CField*> enabledFields = file->getEnabledFields();
1554         size_t numEnabledFields = enabledFields.size();
1555         for (size_t j = 0; j < numEnabledFields; ++j)
[509]1556         {
[1370]1557           // const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize(contextClient);
1558           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize(contextClient,bufferForWriting);
1559           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1560           for (; it != itE; ++it)
[509]1561           {
[1370]1562             // If dataSize[it->first] does not exist, it will be zero-initialized
1563             // so we can use it safely without checking for its existance
1564                 if (CXios::isOptPerformance)
1565               dataSize[it->first] += it->second;
1566             else if (dataSize[it->first] < it->second)
1567               dataSize[it->first] = it->second;
[917]1568
[1370]1569                 if (maxEventSize[it->first] < it->second)
1570               maxEventSize[it->first] = it->second;
[598]1571           }
[509]1572         }
1573       }
1574     }
[730]1575     return dataSize;
[509]1576   }
1577
1578   //! Client side: Send infomation of active files (files are enabled to write out)
[1232]1579   void CContext::sendEnabledFiles(const std::vector<CFile*>& activeFiles)
[509]1580   {
[1232]1581     int size = activeFiles.size();
[509]1582
1583     // In a context, each type has a root definition, e.g: axis, domain, field.
1584     // Every object must be a child of one of these root definition. In this case
1585     // all new file objects created on server must be children of the root "file_definition"
1586     StdString fileDefRoot("file_definition");
1587     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
[1158]1588
[509]1589     for (int i = 0; i < size; ++i)
1590     {
[1232]1591       CFile* f = activeFiles[i];
1592       cfgrpPtr->sendCreateChild(f->getId(),f->getContextClient());
1593       f->sendAllAttributesToServer(f->getContextClient());
1594       f->sendAddAllVariables(f->getContextClient());
[509]1595     }
1596   }
1597
1598   //! Client side: Send information of active fields (ones are written onto files)
[1232]1599   void CContext::sendEnabledFieldsInFiles(const std::vector<CFile*>& activeFiles)
[509]1600   {
[1232]1601     int size = activeFiles.size();
[509]1602     for (int i = 0; i < size; ++i)
1603     {
[1232]1604       activeFiles[i]->sendEnabledFields(activeFiles[i]->getContextClient());
[509]1605     }
1606   }
1607
[676]1608   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1609   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1610   {
1611     if (!hasClient) return;
1612
1613     const vector<CAxis*> allAxis = CAxis::getAll();
1614     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1615       (*it)->checkEligibilityForCompressedOutput();
1616
1617     const vector<CDomain*> allDomains = CDomain::getAll();
1618     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1619       (*it)->checkEligibilityForCompressedOutput();
1620
1621     const vector<CGrid*> allGrids = CGrid::getAll();
1622     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1623       (*it)->checkEligibilityForCompressedOutput();
1624   }
1625
[711]1626   //! Client side: Prepare the timeseries by adding the necessary files
1627   void CContext::prepareTimeseries()
1628   {
1629     if (!hasClient) return;
1630
1631     const std::vector<CFile*> allFiles = CFile::getAll();
1632     for (size_t i = 0; i < allFiles.size(); i++)
1633     {
1634       CFile* file = allFiles[i];
1635
[1158]1636       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1637       for (size_t k = 0; k < vars.size(); k++)
1638       {
1639         CVariable* var = vars[k];
1640
1641         if (var->ts_target.isEmpty()
1642              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1643           fileVars.push_back(var);
1644
1645         if (!var->ts_target.isEmpty()
1646              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1647           fieldVars.push_back(var);
1648       }
1649
[711]1650       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1651       {
[1158]1652         StdString fileNameStr("%file_name%") ;
1653         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1654         
1655         StdString fileName=file->getFileOutputName();
1656         size_t pos=tsPrefix.find(fileNameStr) ;
1657         while (pos!=std::string::npos)
1658         {
1659           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1660           pos=tsPrefix.find(fileNameStr) ;
1661         }
1662       
[711]1663         const std::vector<CField*> allFields = file->getAllFields();
1664         for (size_t j = 0; j < allFields.size(); j++)
1665         {
1666           CField* field = allFields[j];
1667
1668           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1669           {
1670             CFile* tsFile = CFile::create();
1671             tsFile->duplicateAttributes(file);
1672
[1158]1673             // Add variables originating from file and targeted to timeserie file
1674             for (size_t k = 0; k < fileVars.size(); k++)
1675               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1676
1677           
[711]1678             tsFile->name = tsPrefix + "_";
1679             if (!field->name.isEmpty())
1680               tsFile->name.get() += field->name;
1681             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1682               tsFile->name.get() += field->field_ref;
1683             else
1684               tsFile->name.get() += field->getId();
1685
1686             if (!field->ts_split_freq.isEmpty())
1687               tsFile->split_freq = field->ts_split_freq;
1688
1689             CField* tsField = tsFile->addField();
1690             tsField->field_ref = field->getId();
1691
[1158]1692             // Add variables originating from file and targeted to timeserie field
1693             for (size_t k = 0; k < fieldVars.size(); k++)
1694               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1695
1696             vars = field->getAllVariables();
1697             for (size_t k = 0; k < vars.size(); k++)
1698             {
1699               CVariable* var = vars[k];
1700
1701               // Add variables originating from field and targeted to timeserie field
1702               if (var->ts_target.isEmpty()
1703                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1704                 tsField->getVirtualVariableGroup()->addChild(var);
1705
1706               // Add variables originating from field and targeted to timeserie file
1707               if (!var->ts_target.isEmpty()
1708                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1709                 tsFile->getVirtualVariableGroup()->addChild(var);
1710             }
1711
[711]1712             tsFile->solveFieldRefInheritance(true);
1713
1714             if (file->timeseries == CFile::timeseries_attr::exclusive)
1715               field->enabled = false;
1716           }
1717         }
1718
1719         // Finally disable the original file is need be
1720         if (file->timeseries == CFile::timeseries_attr::only)
1721          file->enabled = false;
1722       }
1723     }
1724   }
1725
[509]1726   //! Client side: Send information of reference grid of active fields
[1232]1727   void CContext::sendRefGrid(const std::vector<CFile*>& activeFiles)
[509]1728   {
1729     std::set<StdString> gridIds;
[1232]1730     int sizeFile = activeFiles.size();
[509]1731     CFile* filePtr(NULL);
1732
1733     // Firstly, find all reference grids of all active fields
1734     for (int i = 0; i < sizeFile; ++i)
1735     {
[1232]1736       filePtr = activeFiles[i];
[509]1737       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1738       int sizeField = enabledFields.size();
1739       for (int numField = 0; numField < sizeField; ++numField)
1740       {
1741         if (0 != enabledFields[numField]->getRelGrid())
1742           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1743       }
1744     }
1745
1746     // Create all reference grids on server side
1747     StdString gridDefRoot("grid_definition");
1748     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1749     std::set<StdString>::const_iterator it, itE = gridIds.end();
1750     for (it = gridIds.begin(); it != itE; ++it)
1751     {
1752       gridPtr->sendCreateChild(*it);
1753       CGrid::get(*it)->sendAllAttributesToServer();
[540]1754       CGrid::get(*it)->sendAllDomains();
1755       CGrid::get(*it)->sendAllAxis();
[887]1756       CGrid::get(*it)->sendAllScalars();
[509]1757     }
1758   }
1759
[1232]1760   //! Client side: Send information of reference domain, axis and scalar of active fields
1761   void CContext::sendRefDomainsAxisScalars(const std::vector<CFile*>& activeFiles)
[569]1762   {
[887]1763     std::set<StdString> domainIds, axisIds, scalarIds;
[509]1764
[569]1765     // Find all reference domain and axis of all active fields
[1232]1766     int numEnabledFiles = activeFiles.size();
[569]1767     for (int i = 0; i < numEnabledFiles; ++i)
1768     {
[1232]1769       std::vector<CField*> enabledFields = activeFiles[i]->getEnabledFields();
[569]1770       int numEnabledFields = enabledFields.size();
1771       for (int j = 0; j < numEnabledFields; ++j)
1772       {
[887]1773         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1774         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1775         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1776         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
[569]1777       }
1778     }
1779
1780     // Create all reference axis on server side
[887]1781     std::set<StdString>::iterator itDom, itAxis, itScalar;
[569]1782     std::set<StdString>::const_iterator itE;
1783
[887]1784     StdString scalarDefRoot("scalar_definition");
1785     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1786     itE = scalarIds.end();
1787     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1788     {
1789       if (!itScalar->empty())
1790       {
1791         scalarPtr->sendCreateChild(*itScalar);
1792         CScalar::get(*itScalar)->sendAllAttributesToServer();
1793       }
1794     }
1795
[569]1796     StdString axiDefRoot("axis_definition");
1797     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1798     itE = axisIds.end();
1799     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1800     {
1801       if (!itAxis->empty())
1802       {
1803         axisPtr->sendCreateChild(*itAxis);
1804         CAxis::get(*itAxis)->sendAllAttributesToServer();
1805       }
1806     }
1807
1808     // Create all reference domains on server side
1809     StdString domDefRoot("domain_definition");
1810     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1811     itE = domainIds.end();
1812     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1813     {
1814       if (!itDom->empty()) {
1815          domPtr->sendCreateChild(*itDom);
1816          CDomain::get(*itDom)->sendAllAttributesToServer();
1817       }
1818     }
1819   }
1820
[509]1821   //! Update calendar in each time step
[300]1822   void CContext::updateCalendar(int step)
1823   {
[1357]1824      int prevStep = calendar->getStep();
1825
1826      if (prevStep < step)
[639]1827      {
[1358]1828        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1829        {
1830          doPreTimestepOperationsForEnabledReadModeFiles();
1831        }
1832
[1357]1833        info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1834        calendar->update(step);
1835        info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1836  #ifdef XIOS_MEMTRACK_LIGHT
1837        info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1838  #endif
1839
1840        if (hasClient && !hasServer) // For now we only use server level 1 to read data
1841        {
1842          doPostTimestepOperationsForEnabledReadModeFiles();
1843          garbageCollector.invalidate(calendar->getCurrentDate());
1844        }
[639]1845      }
[1357]1846      else if (prevStep == step)
1847        info(50) << "updateCalendar: already at step " << step << ", no operation done." << endl;
1848      else // if (prevStep > step)
1849        ERROR("void CContext::updateCalendar(int step)",
1850              << "Illegal calendar update: previous step was " << prevStep << ", new step " << step << "is in the past!")
[300]1851   }
[509]1852
[1232]1853   void CContext::initReadFiles(void)
1854   {
1855      vector<CFile*>::const_iterator it;
1856
1857      for (it=enabledReadModeFiles.begin(); it != enabledReadModeFiles.end(); it++)
1858      {
1859         (*it)->initRead();
1860      }
1861   }
1862
[509]1863   //! Server side: Create header of netcdf file
[1232]1864   void CContext::createFileHeader(void)
[300]1865   {
[549]1866      vector<CFile*>::const_iterator it;
[509]1867
[300]1868      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
[1232]1869      // for (it=enabledWriteModeFiles.begin(); it != enabledWriteModeFiles.end(); it++)
[300]1870      {
[1232]1871         (*it)->initWrite();
[300]1872      }
[509]1873   }
1874
1875   //! Get current context
[347]1876   CContext* CContext::getCurrent(void)
[300]1877   {
[549]1878     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
[300]1879   }
[509]1880
1881   /*!
1882   \brief Set context with an id be the current context
1883   \param [in] id identity of context to be set to current
1884   */
[346]1885   void CContext::setCurrent(const string& id)
1886   {
1887     CObjectFactory::SetCurrentContextId(id);
1888     CGroupFactory::SetCurrentContextId(id);
1889   }
[509]1890
1891  /*!
1892  \brief Create a context with specific id
1893  \param [in] id identity of new context
1894  \return pointer to the new context or already-existed one with identity id
1895  */
[347]1896  CContext* CContext::create(const StdString& id)
[346]1897  {
[549]1898    CContext::setCurrent(id);
[509]1899
[346]1900    bool hasctxt = CContext::has(id);
[347]1901    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
[549]1902    getRoot();
[347]1903    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
[346]1904
1905#define DECLARE_NODE(Name_, name_) \
1906    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1907#define DECLARE_NODE_PAR(Name_, name_)
1908#include "node_type.conf"
1909
1910    return (context);
1911  }
[697]1912
1913
1914     //! Server side: Receive a message to do some post processing
1915  void CContext::recvRegistry(CEventServer& event)
1916  {
1917    CBufferIn* buffer=event.subEvents.begin()->buffer;
1918    string id;
1919    *buffer>>id;
1920    get(id)->recvRegistry(*buffer);
1921  }
1922
1923  void CContext::recvRegistry(CBufferIn& buffer)
1924  {
1925    if (server->intraCommRank==0)
1926    {
1927      CRegistry registry(server->intraComm) ;
1928      registry.fromBuffer(buffer) ;
1929      registryOut->mergeRegistry(registry) ;
1930    }
1931  }
1932
1933  void CContext::sendRegistry(void)
[1158]1934  {
[697]1935    registryOut->hierarchicalGatherRegistry() ;
1936
[1009]1937    // Use correct context client to send message
[1030]1938    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1939    for (int i = 0; i < nbSrvPools; ++i)
1940    {
1941      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1942      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
[1021]1943        if (contextClientTmp->isServerLeader())
[1009]1944        {
1945           CMessage msg ;
1946           if (hasServer)
1947             msg<<this->getIdServer(i);
1948           else
1949             msg<<this->getIdServer();
1950           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
[1021]1951           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
[1009]1952           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1953             event.push(*itRank,1,msg);
1954           contextClientTmp->sendEvent(event);
1955         }
1956         else contextClientTmp->sendEvent(event);
1957    }
[697]1958  }
1959
[1130]1960  /*!
1961  * \fn bool CContext::isFinalized(void)
[1139]1962  * Context is finalized if it received context post finalize event.
[1130]1963  */
[1054]1964  bool CContext::isFinalized(void)
1965  {
[1139]1966    return finalized;
[1054]1967  }
1968
[335]1969} // namespace xios
Note: See TracBrowser for help on using the repository browser.