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

Last change on this file since 1213 was 1212, checked in by oabramkina, 7 years ago

File dibution among secondary servers done in a more flexible way. Tested.

  • 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: 58.9 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"
[219]18
[992]19#include "server.hpp"
[697]20
[335]21namespace xios {
[509]22
[549]23  shared_ptr<CContextGroup> CContext::root;
[509]24
[219]25   /// ////////////////////// Définitions ////////////////////// ///
26
27   CContext::CContext(void)
28      : CObjectTemplate<CContext>(), CContextAttributes()
[983]29      , calendar(), hasClient(false), hasServer(false)
[1139]30      , isPostProcessed(false), finalized(false)
[1009]31      , idServer_(), client(0), server(0)
[1130]32      , allProcessed(false), countChildCtx_(0)
[219]33   { /* Ne rien faire de plus */ }
34
35   CContext::CContext(const StdString & id)
36      : CObjectTemplate<CContext>(id), CContextAttributes()
[983]37      , calendar(), hasClient(false), hasServer(false)
[1139]38      , isPostProcessed(false), finalized(false)
[1009]39      , idServer_(), client(0), server(0)
[1130]40      , allProcessed(false), countChildCtx_(0)
[219]41   { /* Ne rien faire de plus */ }
42
43   CContext::~CContext(void)
[509]44   {
[597]45     delete client;
46     delete server;
[1071]47     for (std::vector<CContextClient*>::iterator it = clientPrimServer.begin(); it != clientPrimServer.end(); it++)  delete *it;
48     for (std::vector<CContextServer*>::iterator it = serverPrimServer.begin(); it != serverPrimServer.end(); it++)  delete *it;
[1139]49
[300]50   }
[219]51
52   //----------------------------------------------------------------
[509]53   //! Get name of context
[219]54   StdString CContext::GetName(void)   { return (StdString("context")); }
55   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
56   ENodeType CContext::GetType(void)   { return (eContext); }
57
58   //----------------------------------------------------------------
[640]59
[509]60   /*!
61   \brief Get context group (context root)
62   \return Context root
63   */
[347]64   CContextGroup* CContext::getRoot(void)
[509]65   {
[549]66      if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
[509]67      return root.get();
[219]68   }
69
[640]70   //----------------------------------------------------------------
[509]71
72   /*!
73   \brief Get calendar of a context
74   \return Calendar
75   */
[343]76   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
[219]77   {
78      return (this->calendar);
79   }
[509]80
[219]81   //----------------------------------------------------------------
[640]82
[509]83   /*!
84   \brief Set a context with a calendar
85   \param[in] newCalendar new calendar
86   */
[343]87   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
[219]88   {
89      this->calendar = newCalendar;
90   }
[509]91
[219]92   //----------------------------------------------------------------
[509]93   /*!
94   \brief Parse xml file and write information into context object
95   \param [in] node xmld node corresponding in xml file
96   */
[219]97   void CContext::parse(xml::CXMLNode & node)
98   {
99      CContext::SuperClass::parse(node);
100
101      // PARSING POUR GESTION DES ENFANTS
[278]102      xml::THashAttributes attributes = node.getAttributes();
[219]103
[278]104      if (attributes.end() != attributes.find("src"))
105      {
106         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
[462]107         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
108            ERROR("void CContext::parse(xml::CXMLNode & node)",
109                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
[278]110         if (!ifs.good())
111            ERROR("CContext::parse(xml::CXMLNode & node)",
112                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
[462]113         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
[278]114      }
115
[219]116      if (node.getElementName().compare(CContext::GetName()))
[421]117         DEBUG("Le noeud is wrong defined but will be considered as a context !");
[219]118
119      if (!(node.goToChildElement()))
120      {
121         DEBUG("Le context ne contient pas d'enfant !");
122      }
123      else
124      {
125         do { // Parcours des contextes pour traitement.
126
127            StdString name = node.getElementName();
128            attributes.clear();
129            attributes = node.getAttributes();
130
131            if (attributes.end() != attributes.find("id"))
[509]132            {
133              DEBUG(<< "Definition node has an id,"
134                    << "it will not be taking account !");
135            }
[219]136
137#define DECLARE_NODE(Name_, name_)    \
138   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
[549]139   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
[219]140#define DECLARE_NODE_PAR(Name_, name_)
141#include "node_type.conf"
[286]142
[421]143            DEBUG(<< "The element \'"     << name
144                  << "\' in the context \'" << CContext::getCurrent()->getId()
145                  << "\' is not a definition !");
[219]146
147         } while (node.goToNextElement());
148
149         node.goToParentElement(); // Retour au parent
150      }
151   }
152
153   //----------------------------------------------------------------
[509]154   //! Show tree structure of context
[219]155   void CContext::ShowTree(StdOStream & out)
156   {
[549]157      StdString currentContextId = CContext::getCurrent() -> getId();
[347]158      std::vector<CContext*> def_vector =
[346]159         CContext::getRoot()->getChildList();
[347]160      std::vector<CContext*>::iterator
[219]161         it = def_vector.begin(), end = def_vector.end();
162
163      out << "<? xml version=\"1.0\" ?>" << std::endl;
164      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
[509]165
[219]166      for (; it != end; it++)
167      {
[509]168         CContext* context = *it;
169         CContext::setCurrent(context->getId());
[219]170         out << *context << std::endl;
171      }
[509]172
[219]173      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
[509]174      CContext::setCurrent(currentContextId);
[219]175   }
[346]176
[509]177
[219]178   //----------------------------------------------------------------
179
[509]180   //! Convert context object into string (to print)
[219]181   StdString CContext::toString(void) const
182   {
183      StdOStringStream oss;
184      oss << "<" << CContext::GetName()
185          << " id=\"" << this->getId() << "\" "
186          << SuperClassAttribute::toString() << ">" << std::endl;
187      if (!this->hasChild())
188      {
189         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
190      }
191      else
192      {
193
194#define DECLARE_NODE(Name_, name_)    \
[346]195   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
196   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
[219]197#define DECLARE_NODE_PAR(Name_, name_)
198#include "node_type.conf"
199
200      }
201
202      oss << "</" << CContext::GetName() << " >";
203
204      return (oss.str());
205   }
206
207   //----------------------------------------------------------------
208
[509]209   /*!
210   \brief Find all inheritace among objects in a context.
211   \param [in] apply (true) write attributes of parent into ones of child if they are empty
212                     (false) write attributes of parent into a new container of child
213   \param [in] parent unused
214   */
[445]215   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
[219]216   {
217#define DECLARE_NODE(Name_, name_)    \
[354]218   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
[445]219     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
[219]220#define DECLARE_NODE_PAR(Name_, name_)
221#include "node_type.conf"
222   }
223
224   //----------------------------------------------------------------
225
[509]226   //! Verify if all root definition in the context have child.
[219]227   bool CContext::hasChild(void) const
228   {
229      return (
230#define DECLARE_NODE(Name_, name_)    \
[346]231   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
[219]232#define DECLARE_NODE_PAR(Name_, name_)
233#include "node_type.conf"
234      false);
235}
236
237   //----------------------------------------------------------------
238
239   void CContext::CleanTree(void)
240   {
[549]241#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
[219]242#define DECLARE_NODE_PAR(Name_, name_)
243#include "node_type.conf"
244   }
245   ///---------------------------------------------------------------
[509]246
247   //! Initialize client side
[597]248   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtServer /*= 0*/)
[300]249   {
[983]250
251     hasClient = true;
[1071]252     MPI_Comm intraCommServer, interCommServer;
[1054]253
[1021]254     if (CServer::serverLevel != 1)
[1071]255      // initClient is called by client
[983]256     {
257       client = new CContextClient(this, intraComm, interComm, cxtServer);
[1054]258       if (cxtServer) // Attached mode
259       {
260         intraCommServer = intraComm;
261         interCommServer = interComm;
262       }
263       else
264       {
[1071]265         MPI_Comm_dup(intraComm, &intraCommServer);
266         comms.push_back(intraCommServer);
267         MPI_Comm_dup(interComm, &interCommServer);
268         comms.push_back(interCommServer);
[1054]269       }
[1071]270       registryIn=new CRegistry(intraComm);
271       registryIn->setPath(getId()) ;
272       if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
273       registryIn->bcastRegistry() ;
274       registryOut=new CRegistry(intraComm) ;
275       registryOut->setPath(getId()) ;
276
277       server = new CContextServer(this, intraCommServer, interCommServer);
[983]278     }
[1021]279     else
[1054]280     // initClient is called by primary server
[983]281     {
[1009]282       clientPrimServer.push_back(new CContextClient(this, intraComm, interComm));
[1071]283       MPI_Comm_dup(intraComm, &intraCommServer);
284       comms.push_back(intraCommServer);
285       MPI_Comm_dup(interComm, &interCommServer);
286       comms.push_back(interCommServer);
287       serverPrimServer.push_back(new CContextServer(this, intraCommServer, interCommServer));
[983]288     }
[509]289   }
[219]290
[1184]291   void CContext::setClientServerBuffer(CContextClient* contextClient)
[509]292   {
[1201]293      // Estimated minimum event size for small events (10 is an arbitrary constant just for safety)
294      const size_t minEventSize = CEventClient::headerSize + getIdServer().size() + 10 * sizeof(int);
295
296      // Ensure there is at least some room for 20 of such events in the buffers
297      size_t minBufferSize = std::max(CXios::minBufferSize, 20 * minEventSize);
298
[583]299#define DECLARE_NODE(Name_, name_)    \
[731]300     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
[583]301#define DECLARE_NODE_PAR(Name_, name_)
302#include "node_type.conf"
[719]303#undef DECLARE_NODE
304#undef DECLARE_NODE_PAR
305
[1201]306     // Compute the buffer sizes needed to send the attributes and data corresponding to fields
[917]307     std::map<int, StdSize> maxEventSize;
[1184]308     std::map<int, StdSize> bufferSize = getAttributesBufferSize(maxEventSize, contextClient);
309     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize, contextClient);
[729]310
[909]311     std::map<int, StdSize>::iterator it, ite = dataBufferSize.end();
[731]312     for (it = dataBufferSize.begin(); it != ite; ++it)
313       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
314
[1201]315     // Apply the buffer size factor and check that we are above the minimum buffer size
[909]316     ite = bufferSize.end();
317     for (it = bufferSize.begin(); it != ite; ++it)
318     {
319       it->second *= CXios::bufferSizeFactor;
320       if (it->second < minBufferSize) it->second = minBufferSize;
321     }
322
[1201]323     // Leaders will have to send some control events so ensure there is some room for those in the buffers
[1184]324     if (contextClient->isServerLeader())
[598]325     {
[1184]326       const std::list<int>& ranks = contextClient->getRanksServerLeader();
[729]327       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[1201]328       {
329         if (!bufferSize.count(*itRank))
330         {
331           bufferSize[*itRank] = minBufferSize;
332           maxEventSize[*itRank] = minEventSize;
333         }
334       }
[598]335     }
[1184]336     contextClient->setBufferSize(bufferSize, maxEventSize);
[584]337
[509]338   }
339
340   //! Verify whether a context is initialized
[461]341   bool CContext::isInitialized(void)
342   {
[549]343     return hasClient;
[461]344   }
[509]345
[983]346   void CContext::initServer(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtClient /*= 0*/)
[300]347   {
[549]348     hasServer=true;
349     server = new CContextServer(this,intraComm,interComm);
[697]350
[1071]351     registryIn=new CRegistry(intraComm);
352     registryIn->setPath(getId()) ;
353     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
354     registryIn->bcastRegistry() ;
355     registryOut=new CRegistry(intraComm) ;
356     registryOut->setPath(getId()) ;
[775]357
[597]358     MPI_Comm intraCommClient, interCommClient;
359     if (cxtClient) // Attached mode
360     {
361       intraCommClient = intraComm;
362       interCommClient = interComm;
363     }
364     else
365     {
[1071]366       MPI_Comm_dup(intraComm, &intraCommClient);
367       comms.push_back(intraCommClient);
368       MPI_Comm_dup(interComm, &interCommClient);
369       comms.push_back(interCommClient);
[597]370     }
[1158]371     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
[509]372   }
[300]373
[597]374   //! Try to send the buffers and receive possible answers
[1130]375  bool CContext::checkBuffersAndListen(void)
376  {
377    bool clientReady, serverFinished;
[1054]378
[1130]379    // Only classical servers are non-blocking
380    if (CServer::serverLevel == 0)
381    {
382      client->checkBuffers();
383      bool hasTmpBufferedEvent = client->hasTemporarilyBufferedEvent();
384      if (hasTmpBufferedEvent)
385        hasTmpBufferedEvent = !client->sendTemporarilyBufferedEvent();
386      // Don't process events if there is a temporarily buffered event
387      return server->eventLoop(!hasTmpBufferedEvent);
388    }
389    else if (CServer::serverLevel == 1)
390    {
[1139]391      if (!finalized)
392        client->checkBuffers();
393      bool serverFinished = true;
394      if (!finalized)
395        serverFinished = server->eventLoop();
[1130]396      bool serverPrimFinished = true;
397      for (int i = 0; i < clientPrimServer.size(); ++i)
398      {
[1139]399        if (!finalized)
400          clientPrimServer[i]->checkBuffers();
401        if (!finalized)
402          serverPrimFinished *= serverPrimServer[i]->eventLoop();
[1130]403      }
404      return ( serverFinished && serverPrimFinished);
405    }
[1054]406
[1130]407    else if (CServer::serverLevel == 2)
408    {
409      client->checkBuffers();
410      return server->eventLoop();
411    }
412  }
[1054]413
[509]414   //! Terminate a context
[300]415   void CContext::finalize(void)
416   {
[1130]417     // Send registry upon calling the function the first time
418     if (countChildCtx_ == 0)
419       if (hasClient) sendRegistry() ;
420
421     // Client:
422     // (1) blocking send context finalize to its server
423     // (2) blocking receive context finalize from its server
[1194]424     // (3) some memory deallocations
[1130]425     if (CXios::isClient)
[1009]426     {
[1130]427       // Make sure that client (model) enters the loop only once
428       if (countChildCtx_ < 1)
429       {
430         ++countChildCtx_;
[983]431
[1130]432         client->finalize();
433         while (client->havePendingRequests())
434            client->checkBuffers();
[1054]435
[1130]436         while (!server->hasFinished())
437           server->eventLoop();
[1139]438
[1194]439         if (hasServer) // Mode attache
440         {
441           closeAllFile();
442           registryOut->hierarchicalGatherRegistry() ;
443           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
444         }
[1139]445
[1194]446         //! Deallocate client buffers
447         client->releaseBuffers();
448
449         //! Free internally allocated communicators
450         for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
451           MPI_Comm_free(&(*it));
452         comms.clear();
453
454         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
[1130]455       }
456     }
457     else if (CXios::isServer)
458     {
[1194]459       // First context finalize message received from a model
460       // Send context finalize to its child contexts (if any)
[1130]461       if (countChildCtx_ == 0)
[1009]462         for (int i = 0; i < clientPrimServer.size(); ++i)
463           clientPrimServer[i]->finalize();
[983]464
[1139]465       // (Last) context finalized message received
[1130]466       if (countChildCtx_ == clientPrimServer.size())
[1194]467       {
468         // Blocking send of context finalize message to its client (e.g. primary server or model)
[1130]469         client->finalize();
[1194]470         bool bufferReleased;
471         do
472         {
473           client->checkBuffers();
474           bufferReleased = !client->havePendingRequests();
475         } while (!bufferReleased);
476         finalized = true;
[983]477
[1194]478         if (hasServer && !hasClient)
479         {
480           closeAllFile();
481           registryOut->hierarchicalGatherRegistry() ;
482           if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
483         }
[1077]484
[1194]485         //! Deallocate client buffers
486         client->releaseBuffers();
487         for (int i = 0; i < clientPrimServer.size(); ++i)
488           clientPrimServer[i]->releaseBuffers();
[1139]489
[1194]490         //! Free internally allocated communicators
491         for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
492           MPI_Comm_free(&(*it));
493         comms.clear();
494
495         info(20)<<"CContext: Context <"<<getId()<<"> is finalized."<<endl;
[1139]496       }
497
[1194]498       ++countChildCtx_;
[1130]499     }
500   }
501
[1071]502   //! Free internally allocated communicators
503   void CContext::freeComms(void)
504   {
505     for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
506       MPI_Comm_free(&(*it));
507     comms.clear();
508   }
[509]509
[1130]510   //! Deallocate buffers allocated by clientContexts
511   void CContext::releaseClientBuffers(void)
512   {
513     client->releaseBuffers();
514     for (int i = 0; i < clientPrimServer.size(); ++i)
515       clientPrimServer[i]->releaseBuffers();
516   }
517
[1025]518   void CContext::postProcessingGlobalAttributes()
[300]519   {
[1144]520     if (allProcessed) return; 
[1025]521     
[1144]522     // After xml is parsed, there are some more works with post processing
523     postProcessing();
[983]524
[1144]525     // Check grid and calculate its distribution
526     checkGridEnabledFields();   
[1099]527
[1208]528     // Distribute files between secondary servers according to the data size
529     distributeFiles();
530
[1194]531     // Buffer for primary server for connection to client will be allocated by default (to min size)
532     if (CServer::serverLevel != 1)
533       setClientServerBuffer(client);
[1184]534     if (hasServer)
535       for (int i = 0; i < clientPrimServer.size(); ++i)
536         setClientServerBuffer(clientPrimServer[i]);
[300]537
[1184]538
[983]539     if (hasClient)
[510]540     {
[509]541      // Send all attributes of current context to server
542      this->sendAllAttributesToServer();
[459]543
[549]544      // Send all attributes of current calendar
545      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
546
[509]547      // We have enough information to send to server
[1021]548      // First of all, send all enabled files
549      sendEnabledFiles();
[509]550
[1021]551      // Then, send all enabled fields
552      sendEnabledFields();
553
[540]554      // At last, we have all info of domain and axis, then send them
[569]555       sendRefDomainsAxis();
[1021]556
557       // After that, send all grid (if any)
[1130]558       sendRefGrid();
[1021]559
[983]560       // We have a xml tree on the server side and now, it should be also processed
561       sendPostProcessing();
[1144]562
[1099]563       sendGridEnabledFields();       
[983]564     }
[1025]565     allProcessed = true;
566   }
[983]567
[1025]568   void CContext::sendPostProcessingGlobalAttributes()
569   {
[1027]570      // Use correct context client to send message
[1030]571     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
572    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]573     for (int i = 0; i < nbSrvPools; ++i)
574     {
575       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
576       CEventClient event(getType(),EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES);
[987]577
[1027]578       if (contextClientTmp->isServerLeader())
579       {
580         CMessage msg;
[1099]581         if (hasServer)
582           msg<<this->getIdServer(i);
583         else
584           msg<<this->getIdServer();
[1027]585         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
586         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
587           event.push(*itRank,1,msg);
588         contextClientTmp->sendEvent(event);
589       }
590       else contextClientTmp->sendEvent(event);
[1025]591     }
592   }
593
594   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
595   {
596      CBufferIn* buffer=event.subEvents.begin()->buffer;
597      string id;
598      *buffer>>id;
[1099]599      get(id)->recvPostProcessingGlobalAttributes(*buffer);
[1025]600   }
601
602   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
[1144]603   {     
[1025]604      postProcessingGlobalAttributes();
605   }
606
607   /*!
608   \brief Close all the context defintion and do processing data
609      After everything is well defined on client side, they will be processed and sent to server
610   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
611   all necessary information to server, from which each server can build its own database.
612   Because the role of server is to write out field data on a specific netcdf file,
613   the only information that it needs is the enabled files
614   and the active fields (fields will be written onto active files)
615   */
616   void CContext::closeDefinition(void)
617   {
[1158]618    CTimer::get("Context : close definition").resume() ;
[1025]619    postProcessingGlobalAttributes();
[983]620
[1130]621    if (hasClient) sendPostProcessingGlobalAttributes();
622
623    // There are some processings that should be done after all of above. For example: check mask or index
[1025]624    this->buildFilterGraphOfEnabledFields();
625   
[1130]626     if (hasClient && !hasServer)
[509]627    {
[1130]628      buildFilterGraphOfFieldsWithReadAccess();
[509]629    }
[1144]630   
631    checkGridEnabledFields();   
[509]632
[1025]633    if (hasClient) this->sendProcessingGridOfEnabledFields();
[1077]634    if (hasClient) this->sendCloseDefinition();
[510]635
[584]636    // Nettoyage de l'arborescence
[983]637    if (hasClient) CleanTree(); // Only on client side??
[510]638
[598]639    if (hasClient)
640    {
641      sendCreateFileHeader();
[983]642      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
[598]643    }
[1158]644    CTimer::get("Context : close definition").suspend() ;
[300]645   }
[509]646
[300]647   void CContext::findAllEnabledFields(void)
648   {
649     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
650     (void)this->enabledFiles[i]->getEnabledFields();
651   }
652
[775]653   void CContext::findAllEnabledFieldsInReadModeFiles(void)
654   {
655     for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
656     (void)this->enabledReadModeFiles[i]->getEnabledFields();
657   }
658
659   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
660   {
661      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
662        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
663   }
664
[1099]665   void CContext::sendGridEnabledFields()
[1025]666   {
667     int size = this->enabledFiles.size();
668     for (int i = 0; i < size; ++i)
[1099]669     {       
[1025]670       this->enabledFiles[i]->sendGridOfEnabledFields();
671     }
672   }
673
[1099]674   void CContext::checkGridEnabledFields()
675   {
676     int size = this->enabledFiles.size();
677     for (int i = 0; i < size; ++i)
678     {
679       this->enabledFiles[i]->checkGridOfEnabledFields();       
680     }
681   }
[1025]682
[823]683   void CContext::solveOnlyRefOfEnabledFields(bool sendToServer)
684   {
685     int size = this->enabledFiles.size();
686     for (int i = 0; i < size; ++i)
687     {
688       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(sendToServer);
689     }
690
691     for (int i = 0; i < size; ++i)
692     {
693       this->enabledFiles[i]->generateNewTransformationGridDest();
694     }
695   }
696
[1129]697   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
[300]698   {
[509]699     int size = this->enabledFiles.size();
700     for (int i = 0; i < size; ++i)
701     {
[1129]702       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
[509]703     }
[300]704   }
705
[640]706   void CContext::buildFilterGraphOfEnabledFields()
707   {
708     int size = this->enabledFiles.size();
709     for (int i = 0; i < size; ++i)
710     {
711       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
712     }
713   }
714
[598]715   void CContext::startPrefetchingOfEnabledReadModeFiles()
716   {
717     int size = enabledReadModeFiles.size();
718     for (int i = 0; i < size; ++i)
719     {
720        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
721     }
722   }
723
724   void CContext::checkPrefetchingOfEnabledReadModeFiles()
725   {
726     int size = enabledReadModeFiles.size();
727     for (int i = 0; i < size; ++i)
728     {
729        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
730     }
731   }
732
[593]733  void CContext::findFieldsWithReadAccess(void)
734  {
735    fieldsWithReadAccess.clear();
736    const vector<CField*> allFields = CField::getAll();
737    for (size_t i = 0; i < allFields.size(); ++i)
738    {
[740]739      CField* field = allFields[i];
740
741      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
742        field->read_access = true;
743      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
744        fieldsWithReadAccess.push_back(field);
[593]745    }
746  }
747
748  void CContext::solveAllRefOfFieldsWithReadAccess()
749  {
750    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
751      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
752  }
753
[640]754  void CContext::buildFilterGraphOfFieldsWithReadAccess()
755  {
756    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
757      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
758  }
759
[445]760   void CContext::solveAllInheritance(bool apply)
[300]761   {
762     // Résolution des héritages descendants (càd des héritages de groupes)
763     // pour chacun des contextes.
[445]764      solveDescInheritance(apply);
[300]765
766     // Résolution des héritages par référence au niveau des fichiers.
[549]767      const vector<CFile*> allFiles=CFile::getAll();
[540]768      const vector<CGrid*> allGrids= CGrid::getAll();
[300]769
[983]770      if (hasClient && !hasServer)
771      //if (hasClient)
[540]772      {
[510]773        for (unsigned int i = 0; i < allFiles.size(); i++)
774          allFiles[i]->solveFieldRefInheritance(apply);
[540]775      }
776
777      unsigned int vecSize = allGrids.size();
778      unsigned int i = 0;
779      for (i = 0; i < vecSize; ++i)
780        allGrids[i]->solveDomainAxisRefInheritance(apply);
781
[300]782   }
783
784   void CContext::findEnabledFiles(void)
785   {
[347]786      const std::vector<CFile*> allFiles = CFile::getAll();
[1158]787      const CDate& initDate = calendar->getInitDate();
[300]788
789      for (unsigned int i = 0; i < allFiles.size(); i++)
790         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
[430]791         {
[300]792            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
[1158]793            {
794              if ((initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
795              {
796                error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
797                    << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
798                    <<"\" is less than the time step. File will not be written."<<endl;
799              }
800              else
[300]801               enabledFiles.push_back(allFiles[i]);
[1158]802            }
[430]803         }
[1158]804         else
805         {
806           if ( (initDate + allFiles[i]->output_freq.getValue()) < (initDate + this->getCalendar()->getTimeStep()))
807           {
808             error(0)<<"WARNING: void CContext::findEnabledFiles()"<<endl
809                 << "Output frequency in file \""<<allFiles[i]->getFileOutputName()
810                 <<"\" is less than the time step. File will not be written."<<endl;
811           }
812           else
813             enabledFiles.push_back(allFiles[i]); // otherwise true by default
814         }
[300]815
816      if (enabledFiles.size() == 0)
817         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
818               << getId() << "\" !");
[1021]819
[300]820   }
821
[1208]822   void CContext::distributeFiles(void)
823   {
824     // If primary server
825     if (hasServer && hasClient)
826     {
[1212]827       int nbPools = clientPrimServer.size();
828
[1208]829       // (1) Find all enabled files in write mode
830       for (int i = 0; i < this->enabledFiles.size(); ++i)
831       {
832         if (enabledFiles[i]->mode.isEmpty() || (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::write ))
833          enabledWriteModeFiles.push_back(enabledFiles[i]);
834       }
835
836       // (2) Estimate the data volume for each file
837       int size = this->enabledWriteModeFiles.size();
838       std::vector<std::pair<StdSize, CFile*> > dataSizeMap;
[1212]839       StdSize dataPerPool = 0;
[1208]840       for (size_t i = 0; i < size; ++i)
841       {
842         CFile* file = this->enabledWriteModeFiles[i];
843         StdSize dataSize;
844         std::vector<CField*> enabledFields = file->getEnabledFields();
845         size_t numEnabledFields = enabledFields.size();
846         for (size_t j = 0; j < numEnabledFields; ++j)
847         {
848           const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
849           for (size_t c = 0; c < mapSize.size(); ++c)
850           {
851             std::map<int, StdSize>::const_iterator it = mapSize[c].begin(), itE = mapSize[c].end();
852             for (; it != itE; ++it)
853             {
854               dataSize += it->second;
855             }
856           }
857         }
858         CDuration outFreq = file->output_freq.getValue();
859         if (outFreq.timestep != 0.0)
860         {
861           outFreq = calendar->getTimeStep();
862         }
863         double outFreqSec = outFreq.second + 60.*(outFreq.minute + 60.*(outFreq.hour + 24.*(outFreq.day + outFreq.year*365.25) ) );
864         dataSize /= outFreqSec;
865         dataSizeMap.push_back(make_pair(dataSize,file));
[1212]866         dataPerPool += dataSize;
[1208]867       }
[1212]868       dataPerPool /= nbPools;
[1208]869       std::sort(dataSizeMap.begin(), dataSizeMap.end());
870
[1212]871       // (3) Assign contextClient to each enabled file
872       std::vector<StdSize> poolData(nbPools);
873       int lazyPool = 0;
874       for (int i = dataSizeMap.size()-1; i >= 0; --i)
[1208]875       {
[1212]876         bool contextSet = false;
877         for (int j = 0; j < nbPools; ++j)
[1208]878         {
[1212]879           if (!contextSet)
880           {
881             if (dataSizeMap[i].first + poolData[j] < dataPerPool)
882             {
883               dataSizeMap[i].second->setContextClient(clientPrimServer[j]);
884               poolData[j] += dataSizeMap[i].first;
885               contextSet = true;
886             }
887           }
888           if (poolData[j] < poolData[lazyPool])
889             lazyPool = j;
[1208]890         }
[1212]891         if (!contextSet)
[1208]892         {
[1212]893           dataSizeMap[i].second->setContextClient(clientPrimServer[lazyPool]);
894           poolData[lazyPool] += dataSizeMap[i].first;
[1208]895         }
896       }
[1212]897
898       for (int i = 0; i < this->enabledReadModeFiles.size(); ++i)
899         enabledReadModeFiles[i]->setContextClient(client);
[1208]900     }
901     else
902     {
903       for (int i = 0; i < this->enabledFiles.size(); ++i)
904         enabledFiles[i]->setContextClient(client);
905     }
906   }
907
[598]908   void CContext::findEnabledReadModeFiles(void)
909   {
910     int size = this->enabledFiles.size();
911     for (int i = 0; i < size; ++i)
912     {
913       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
914        enabledReadModeFiles.push_back(enabledFiles[i]);
915     }
916   }
917
[300]918   void CContext::closeAllFile(void)
919   {
[347]920     std::vector<CFile*>::const_iterator
[300]921            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
[509]922
[300]923     for (; it != end; it++)
924     {
925       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
926       (*it)->close();
927     }
928   }
[509]929
930   /*!
931   \brief Dispatch event received from client
932      Whenever a message is received in buffer of server, it will be processed depending on
933   its event type. A new event type should be added in the switch list to make sure
934   it processed on server side.
935   \param [in] event: Received message
936   */
[300]937   bool CContext::dispatchEvent(CEventServer& event)
938   {
[509]939
[549]940      if (SuperClass::dispatchEvent(event)) return true;
[300]941      else
942      {
943        switch(event.type)
944        {
945           case EVENT_ID_CLOSE_DEFINITION :
[549]946             recvCloseDefinition(event);
947             return true;
948             break;
[584]949           case EVENT_ID_UPDATE_CALENDAR:
[549]950             recvUpdateCalendar(event);
951             return true;
952             break;
[300]953           case EVENT_ID_CREATE_FILE_HEADER :
[549]954             recvCreateFileHeader(event);
955             return true;
956             break;
[509]957           case EVENT_ID_POST_PROCESS:
[549]958             recvPostProcessing(event);
959             return true;
[697]960            case EVENT_ID_SEND_REGISTRY:
961             recvRegistry(event);
962             return true;
[1025]963             break;
964            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
965             recvPostProcessingGlobalAttributes(event);
966             return true;
967             break;
968            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
969             recvProcessingGridOfEnabledFields(event);
970             return true;
971             break;
[300]972           default :
973             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
[549]974                    <<"Unknown Event");
975           return false;
[300]976         }
977      }
978   }
[509]979
980   //! Client side: Send a message to server to make it close
[300]981   void CContext::sendCloseDefinition(void)
982   {
[987]983     // Use correct context client to send message
[1030]984     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]985     for (int i = 0; i < nbSrvPools; ++i)
[300]986     {
[1009]987       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
988       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
989       if (contextClientTmp->isServerLeader())
990       {
991         CMessage msg;
992         if (hasServer)
993           msg<<this->getIdServer(i);
994         else
995           msg<<this->getIdServer();
996         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
997         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
998           event.push(*itRank,1,msg);
999         contextClientTmp->sendEvent(event);
1000       }
1001       else contextClientTmp->sendEvent(event);
[300]1002     }
1003   }
[509]1004
1005   //! Server side: Receive a message of client announcing a context close
[300]1006   void CContext::recvCloseDefinition(CEventServer& event)
1007   {
1008      CBufferIn* buffer=event.subEvents.begin()->buffer;
1009      string id;
[549]1010      *buffer>>id;
[509]1011      get(id)->closeDefinition();
[300]1012   }
[509]1013
1014   //! Client side: Send a message to update calendar in each time step
[300]1015   void CContext::sendUpdateCalendar(int step)
1016   {
[987]1017     // Use correct context client to send message
[1030]1018    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1019     for (int i = 0; i < nbSrvPools; ++i)
1020     {
1021       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1022       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
[987]1023
[1009]1024         if (contextClientTmp->isServerLeader())
1025         {
1026           CMessage msg;
1027           if (hasServer)
1028             msg<<this->getIdServer(i)<<step;
1029           else
1030             msg<<this->getIdServer()<<step;
1031           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1032           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1033             event.push(*itRank,1,msg);
1034           contextClientTmp->sendEvent(event);
1035         }
1036         else contextClientTmp->sendEvent(event);
1037     }
[300]1038   }
[509]1039
1040   //! Server side: Receive a message of client annoucing calendar update
[300]1041   void CContext::recvUpdateCalendar(CEventServer& event)
1042   {
1043      CBufferIn* buffer=event.subEvents.begin()->buffer;
1044      string id;
[549]1045      *buffer>>id;
1046      get(id)->recvUpdateCalendar(*buffer);
[300]1047   }
[509]1048
1049   //! Server side: Receive a message of client annoucing calendar update
[300]1050   void CContext::recvUpdateCalendar(CBufferIn& buffer)
1051   {
[549]1052      int step;
1053      buffer>>step;
1054      updateCalendar(step);
[987]1055      if (hasClient && hasServer)
1056      {       
1057        sendUpdateCalendar(step);
1058      }
[300]1059   }
[509]1060
1061   //! Client side: Send a message to create header part of netcdf file
[300]1062   void CContext::sendCreateFileHeader(void)
1063   {
[987]1064     // Use correct context client to send message
[1030]1065     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1066     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1067     for (int i = 0; i < nbSrvPools; ++i)
1068     {
1069       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1070       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
[983]1071
[1009]1072       if (contextClientTmp->isServerLeader())
1073       {
1074         CMessage msg;
1075         if (hasServer)
1076           msg<<this->getIdServer(i);
1077         else
1078           msg<<this->getIdServer();
1079         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1080         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1081           event.push(*itRank,1,msg) ;
1082         contextClientTmp->sendEvent(event);
1083       }
1084       else contextClientTmp->sendEvent(event);
[300]1085     }
1086   }
[509]1087
1088   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1089   void CContext::recvCreateFileHeader(CEventServer& event)
1090   {
1091      CBufferIn* buffer=event.subEvents.begin()->buffer;
1092      string id;
[549]1093      *buffer>>id;
1094      get(id)->recvCreateFileHeader(*buffer);
[300]1095   }
[509]1096
1097   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
[300]1098   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1099   {
[987]1100      if (!hasClient && hasServer) 
1101        createFileHeader();
[300]1102   }
[509]1103
1104   //! Client side: Send a message to do some post processing on server
[1025]1105   void CContext::sendProcessingGridOfEnabledFields()
1106   {
1107      // Use correct context client to send message
[1030]1108     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1027]1109     for (int i = 0; i < nbSrvPools; ++i)
1110     {
1111       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1112       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
[1025]1113
[1027]1114       if (contextClientTmp->isServerLeader())
1115       {
1116         CMessage msg;
[1099]1117         if (hasServer)
1118           msg<<this->getIdServer(i);
1119         else
1120           msg<<this->getIdServer();
[1027]1121         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1122         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1123           event.push(*itRank,1,msg);
1124         contextClientTmp->sendEvent(event);
1125       }
1126       else contextClientTmp->sendEvent(event);
[1025]1127     }
1128   }
1129
1130   //! Server side: Receive a message to do some post processing
1131   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1132   {
1133      CBufferIn* buffer=event.subEvents.begin()->buffer;
1134      string id;
[1144]1135      *buffer>>id;     
[1025]1136   }
1137
1138   //! Client side: Send a message to do some post processing on server
[509]1139   void CContext::sendPostProcessing()
1140   {
[987]1141      // Use correct context client to send message
[1030]1142     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1143     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1144     for (int i = 0; i < nbSrvPools; ++i)
[509]1145     {
[1009]1146       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1147       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1148       if (contextClientTmp->isServerLeader())
1149       {
1150         CMessage msg;
1151         if (hasServer)
1152           msg<<this->getIdServer(i);
1153         else
1154           msg<<this->getIdServer();
1155         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1156         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
[987]1157         event.push(*itRank,1,msg);
[1009]1158         contextClientTmp->sendEvent(event);
1159       }
1160       else contextClientTmp->sendEvent(event);
[509]1161     }
1162   }
1163
1164   //! Server side: Receive a message to do some post processing
1165   void CContext::recvPostProcessing(CEventServer& event)
1166   {
1167      CBufferIn* buffer=event.subEvents.begin()->buffer;
1168      string id;
1169      *buffer>>id;
1170      get(id)->recvPostProcessing(*buffer);
1171   }
1172
1173   //! Server side: Receive a message to do some post processing
1174   void CContext::recvPostProcessing(CBufferIn& buffer)
1175   {
[549]1176      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
[509]1177      postProcessing();
1178   }
1179
[511]1180   const StdString& CContext::getIdServer()
1181   {
1182      if (hasClient)
1183      {
1184        idServer_ = this->getId();
1185        idServer_ += "_server";
1186        return idServer_;
1187      }
1188      if (hasServer) return (this->getId());
1189   }
1190
[1009]1191   const StdString& CContext::getIdServer(const int i)
1192   {
1193     idServer_ = this->getId();
1194     idServer_ += "_server_";
1195     idServer_ += boost::lexical_cast<string>(i);
1196     return idServer_;
1197   }
1198
1199
[509]1200   /*!
1201   \brief Do some simple post processings after parsing xml file
1202      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1203   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1204   which will be written out into netcdf files, are processed
1205   */
1206   void CContext::postProcessing()
1207   {
1208     if (isPostProcessed) return;
1209
[549]1210      // Make sure the calendar was correctly created
1211      if (!calendar)
1212        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1213      else if (calendar->getTimeStep() == NoneDu)
1214        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
[550]1215      // Calendar first update to set the current date equals to the start date
1216      calendar->update(0);
[509]1217
1218      // Find all inheritance in xml structure
1219      this->solveAllInheritance();
1220
[992]1221//      ShowTree(info(10));
[983]1222
[676]1223      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1224      // Warning: This must be done after solving the inheritance and before the rest of post-processing
[1025]1225      checkAxisDomainsGridsEligibilityForCompressedOutput();     
[676]1226
[711]1227      // Check if some automatic time series should be generated
[1144]1228      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
[711]1229
[1025]1230      // The timeseries should only be prepared in client
1231      if (hasClient && !hasServer) prepareTimeseries();
1232
[509]1233      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1234      this->findEnabledFiles();
[1144]1235     
[1025]1236      // For now, only read files with client and only one level server
1237      if (hasClient && !hasServer) this->findEnabledReadModeFiles();
[509]1238
1239      // Find all enabled fields of each file
1240      this->findAllEnabledFields();
[1025]1241      // For now, only read files with client and only one level server
1242      if (hasClient && !hasServer) this->findAllEnabledFieldsInReadModeFiles();
[509]1243
[823]1244
[1144]1245      if (hasClient && !hasServer)
1246      {
1247       // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1248       this->readAttributesOfEnabledFieldsInReadModeFiles();
1249      }
1250
[823]1251      // Only search and rebuild all reference objects of enable fields, don't transform
[1099]1252      this->solveOnlyRefOfEnabledFields(false);
[823]1253
[1099]1254      // Search and rebuild all reference object of enabled fields, and transform
[1129]1255      this->solveAllRefOfEnabledFieldsAndTransform(false);
[1099]1256
[593]1257      // Find all fields with read access from the public API
[1025]1258      if (hasClient && !hasServer) findFieldsWithReadAccess();
[593]1259      // and solve the all reference for them
[1025]1260      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
[593]1261
[509]1262      isPostProcessed = true;
1263   }
1264
[917]1265   /*!
1266    * Compute the required buffer size to send the attributes (mostly those grid related).
1267    *
1268    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1269    */
[1184]1270   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
[509]1271   {
[731]1272     std::map<int, StdSize> attributesSize;
1273
[908]1274     if (hasClient)
[731]1275     {
[908]1276       size_t numEnabledFiles = this->enabledFiles.size();
1277       for (size_t i = 0; i < numEnabledFiles; ++i)
1278       {
1279         CFile* file = this->enabledFiles[i];
[1188]1280//         if (file->getContextClient() == contextClient)
[731]1281         {
[1184]1282           std::vector<CField*> enabledFields = file->getEnabledFields();
1283           size_t numEnabledFields = enabledFields.size();
1284           for (size_t j = 0; j < numEnabledFields; ++j)
[908]1285           {
[1184]1286             const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
1287             std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1288             for (; it != itE; ++it)
1289             {
1290               // If attributesSize[it->first] does not exist, it will be zero-initialized
1291               // so we can use it safely without checking for its existance
1292               if (attributesSize[it->first] < it->second)
1293                 attributesSize[it->first] = it->second;
[917]1294
[1184]1295               if (maxEventSize[it->first] < it->second)
1296                 maxEventSize[it->first] = it->second;
1297             }
[908]1298           }
[731]1299         }
1300       }
1301     }
1302
1303     return attributesSize;
1304   }
1305
[917]1306   /*!
1307    * Compute the required buffer size to send the fields data.
1308    *
1309    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1310    */
[1184]1311   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize, CContextClient* contextClient)
[731]1312   {
[598]1313     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
1314
[730]1315     std::map<int, StdSize> dataSize;
[509]1316
1317     // Find all reference domain and axis of all active fields
[730]1318     size_t numEnabledFiles = this->enabledFiles.size();
1319     for (size_t i = 0; i < numEnabledFiles; ++i)
[509]1320     {
[598]1321       CFile* file = this->enabledFiles[i];
[1193]1322       if (file->getContextClient() == contextClient)
[1184]1323       {
1324         CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
[598]1325
[1184]1326         if (fileMode == mode)
[509]1327         {
[1184]1328           std::vector<CField*> enabledFields = file->getEnabledFields();
1329           size_t numEnabledFields = enabledFields.size();
1330           for (size_t j = 0; j < numEnabledFields; ++j)
[509]1331           {
[1184]1332             const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
1333             for (size_t c = 0; c < mapSize.size(); ++c)
[1099]1334             {
[1184]1335               std::map<int, StdSize>::const_iterator it = mapSize[c].begin(), itE = mapSize[c].end();
1336               for (; it != itE; ++it)
1337               {
1338                 // If dataSize[it->first] does not exist, it will be zero-initialized
1339                 // so we can use it safely without checking for its existance
1340                 if (CXios::isOptPerformance)
1341                   dataSize[it->first] += it->second;
1342                 else if (dataSize[it->first] < it->second)
1343                   dataSize[it->first] = it->second;
[917]1344
[1184]1345                 if (maxEventSize[it->first] < it->second)
1346                   maxEventSize[it->first] = it->second;
1347               }
[1099]1348             }
[598]1349           }
[509]1350         }
1351       }
1352     }
1353
[730]1354     return dataSize;
[509]1355   }
1356
1357   //! Client side: Send infomation of active files (files are enabled to write out)
1358   void CContext::sendEnabledFiles()
1359   {
1360     int size = this->enabledFiles.size();
1361
1362     // In a context, each type has a root definition, e.g: axis, domain, field.
1363     // Every object must be a child of one of these root definition. In this case
1364     // all new file objects created on server must be children of the root "file_definition"
1365     StdString fileDefRoot("file_definition");
1366     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
[1158]1367
[509]1368     for (int i = 0; i < size; ++i)
1369     {
[1021]1370       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId(),enabledFiles[i]->getContextClient());
1371       this->enabledFiles[i]->sendAllAttributesToServer(enabledFiles[i]->getContextClient());
1372       this->enabledFiles[i]->sendAddAllVariables(enabledFiles[i]->getContextClient());
[509]1373     }
1374   }
1375
1376   //! Client side: Send information of active fields (ones are written onto files)
1377   void CContext::sendEnabledFields()
1378   {
1379     int size = this->enabledFiles.size();
1380     for (int i = 0; i < size; ++i)
1381     {
[1021]1382       this->enabledFiles[i]->sendEnabledFields(enabledFiles[i]->getContextClient());
[509]1383     }
1384   }
1385
[676]1386   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1387   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1388   {
1389     if (!hasClient) return;
1390
1391     const vector<CAxis*> allAxis = CAxis::getAll();
1392     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1393       (*it)->checkEligibilityForCompressedOutput();
1394
1395     const vector<CDomain*> allDomains = CDomain::getAll();
1396     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1397       (*it)->checkEligibilityForCompressedOutput();
1398
1399     const vector<CGrid*> allGrids = CGrid::getAll();
1400     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1401       (*it)->checkEligibilityForCompressedOutput();
1402   }
1403
[711]1404   //! Client side: Prepare the timeseries by adding the necessary files
1405   void CContext::prepareTimeseries()
1406   {
1407     if (!hasClient) return;
1408
1409     const std::vector<CFile*> allFiles = CFile::getAll();
1410     for (size_t i = 0; i < allFiles.size(); i++)
1411     {
1412       CFile* file = allFiles[i];
1413
[1158]1414       std::vector<CVariable*> fileVars, fieldVars, vars = file->getAllVariables();
1415       for (size_t k = 0; k < vars.size(); k++)
1416       {
1417         CVariable* var = vars[k];
1418
1419         if (var->ts_target.isEmpty()
1420              || var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both)
1421           fileVars.push_back(var);
1422
1423         if (!var->ts_target.isEmpty()
1424              && (var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both))
1425           fieldVars.push_back(var);
1426       }
1427
[711]1428       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1429       {
[1158]1430         StdString fileNameStr("%file_name%") ;
1431         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : fileNameStr ;
1432         
1433         StdString fileName=file->getFileOutputName();
1434         size_t pos=tsPrefix.find(fileNameStr) ;
1435         while (pos!=std::string::npos)
1436         {
1437           tsPrefix=tsPrefix.replace(pos,fileNameStr.size(),fileName) ;
1438           pos=tsPrefix.find(fileNameStr) ;
1439         }
1440       
[711]1441         const std::vector<CField*> allFields = file->getAllFields();
1442         for (size_t j = 0; j < allFields.size(); j++)
1443         {
1444           CField* field = allFields[j];
1445
1446           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1447           {
1448             CFile* tsFile = CFile::create();
1449             tsFile->duplicateAttributes(file);
1450
[1158]1451             // Add variables originating from file and targeted to timeserie file
1452             for (size_t k = 0; k < fileVars.size(); k++)
1453               tsFile->getVirtualVariableGroup()->addChild(fileVars[k]);
1454
1455           
[711]1456             tsFile->name = tsPrefix + "_";
1457             if (!field->name.isEmpty())
1458               tsFile->name.get() += field->name;
1459             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1460               tsFile->name.get() += field->field_ref;
1461             else
1462               tsFile->name.get() += field->getId();
1463
1464             if (!field->ts_split_freq.isEmpty())
1465               tsFile->split_freq = field->ts_split_freq;
1466
1467             CField* tsField = tsFile->addField();
1468             tsField->field_ref = field->getId();
1469
[1158]1470             // Add variables originating from file and targeted to timeserie field
1471             for (size_t k = 0; k < fieldVars.size(); k++)
1472               tsField->getVirtualVariableGroup()->addChild(fieldVars[k]);
1473
1474             vars = field->getAllVariables();
1475             for (size_t k = 0; k < vars.size(); k++)
1476             {
1477               CVariable* var = vars[k];
1478
1479               // Add variables originating from field and targeted to timeserie field
1480               if (var->ts_target.isEmpty()
1481                    || var->ts_target == CVariable::ts_target_attr::field || var->ts_target == CVariable::ts_target_attr::both)
1482                 tsField->getVirtualVariableGroup()->addChild(var);
1483
1484               // Add variables originating from field and targeted to timeserie file
1485               if (!var->ts_target.isEmpty()
1486                    && (var->ts_target == CVariable::ts_target_attr::file || var->ts_target == CVariable::ts_target_attr::both))
1487                 tsFile->getVirtualVariableGroup()->addChild(var);
1488             }
1489
[711]1490             tsFile->solveFieldRefInheritance(true);
1491
1492             if (file->timeseries == CFile::timeseries_attr::exclusive)
1493               field->enabled = false;
1494           }
1495         }
1496
1497         // Finally disable the original file is need be
1498         if (file->timeseries == CFile::timeseries_attr::only)
1499          file->enabled = false;
1500       }
1501     }
1502   }
1503
[509]1504   //! Client side: Send information of reference grid of active fields
1505   void CContext::sendRefGrid()
1506   {
1507     std::set<StdString> gridIds;
1508     int sizeFile = this->enabledFiles.size();
1509     CFile* filePtr(NULL);
1510
1511     // Firstly, find all reference grids of all active fields
1512     for (int i = 0; i < sizeFile; ++i)
1513     {
1514       filePtr = this->enabledFiles[i];
1515       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1516       int sizeField = enabledFields.size();
1517       for (int numField = 0; numField < sizeField; ++numField)
1518       {
1519         if (0 != enabledFields[numField]->getRelGrid())
1520           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1521       }
1522     }
1523
1524     // Create all reference grids on server side
1525     StdString gridDefRoot("grid_definition");
1526     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1527     std::set<StdString>::const_iterator it, itE = gridIds.end();
1528     for (it = gridIds.begin(); it != itE; ++it)
1529     {
1530       gridPtr->sendCreateChild(*it);
1531       CGrid::get(*it)->sendAllAttributesToServer();
[540]1532       CGrid::get(*it)->sendAllDomains();
1533       CGrid::get(*it)->sendAllAxis();
[887]1534       CGrid::get(*it)->sendAllScalars();
[509]1535     }
1536   }
1537
1538
1539   //! Client side: Send information of reference domain and axis of active fields
[569]1540   void CContext::sendRefDomainsAxis()
1541   {
[887]1542     std::set<StdString> domainIds, axisIds, scalarIds;
[509]1543
[569]1544     // Find all reference domain and axis of all active fields
1545     int numEnabledFiles = this->enabledFiles.size();
1546     for (int i = 0; i < numEnabledFiles; ++i)
1547     {
1548       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1549       int numEnabledFields = enabledFields.size();
1550       for (int j = 0; j < numEnabledFields; ++j)
1551       {
[887]1552         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1553         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1554         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1555         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
[569]1556       }
1557     }
1558
1559     // Create all reference axis on server side
[887]1560     std::set<StdString>::iterator itDom, itAxis, itScalar;
[569]1561     std::set<StdString>::const_iterator itE;
1562
[887]1563     StdString scalarDefRoot("scalar_definition");
1564     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1565     itE = scalarIds.end();
1566     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1567     {
1568       if (!itScalar->empty())
1569       {
1570         scalarPtr->sendCreateChild(*itScalar);
1571         CScalar::get(*itScalar)->sendAllAttributesToServer();
1572       }
1573     }
1574
[569]1575     StdString axiDefRoot("axis_definition");
1576     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1577     itE = axisIds.end();
1578     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1579     {
1580       if (!itAxis->empty())
1581       {
1582         axisPtr->sendCreateChild(*itAxis);
1583         CAxis::get(*itAxis)->sendAllAttributesToServer();
1584       }
1585     }
1586
1587     // Create all reference domains on server side
1588     StdString domDefRoot("domain_definition");
1589     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1590     itE = domainIds.end();
1591     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1592     {
1593       if (!itDom->empty()) {
1594          domPtr->sendCreateChild(*itDom);
1595          CDomain::get(*itDom)->sendAllAttributesToServer();
1596       }
1597     }
1598   }
1599
[509]1600   //! Update calendar in each time step
[300]1601   void CContext::updateCalendar(int step)
1602   {
[1158]1603      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
[549]1604      calendar->update(step);
[1158]1605      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1606#ifdef XIOS_MEMTRACK_LIGHT
1607      info(50) << " Current memory used by XIOS : "<<  MemTrack::getCurrentMemorySize()*1.0/(1024*1024)<<" Mbyte, at timestep "<<step<<" of context "<<this->getId()<<endl ;
1608#endif
[639]1609      if (hasClient)
1610      {
[806]1611        checkPrefetchingOfEnabledReadModeFiles();
[639]1612        garbageCollector.invalidate(calendar->getCurrentDate());
1613      }
[300]1614   }
[509]1615
1616   //! Server side: Create header of netcdf file
[300]1617   void CContext::createFileHeader(void )
1618   {
[549]1619      vector<CFile*>::const_iterator it;
[509]1620
[300]1621      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1622      {
[321]1623         (*it)->initFile();
[300]1624      }
[509]1625   }
1626
1627   //! Get current context
[347]1628   CContext* CContext::getCurrent(void)
[300]1629   {
[549]1630     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
[300]1631   }
[509]1632
1633   /*!
1634   \brief Set context with an id be the current context
1635   \param [in] id identity of context to be set to current
1636   */
[346]1637   void CContext::setCurrent(const string& id)
1638   {
1639     CObjectFactory::SetCurrentContextId(id);
1640     CGroupFactory::SetCurrentContextId(id);
1641   }
[509]1642
1643  /*!
1644  \brief Create a context with specific id
1645  \param [in] id identity of new context
1646  \return pointer to the new context or already-existed one with identity id
1647  */
[347]1648  CContext* CContext::create(const StdString& id)
[346]1649  {
[549]1650    CContext::setCurrent(id);
[509]1651
[346]1652    bool hasctxt = CContext::has(id);
[347]1653    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
[549]1654    getRoot();
[347]1655    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
[346]1656
1657#define DECLARE_NODE(Name_, name_) \
1658    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1659#define DECLARE_NODE_PAR(Name_, name_)
1660#include "node_type.conf"
1661
1662    return (context);
1663  }
[697]1664
1665
1666     //! Server side: Receive a message to do some post processing
1667  void CContext::recvRegistry(CEventServer& event)
1668  {
1669    CBufferIn* buffer=event.subEvents.begin()->buffer;
1670    string id;
1671    *buffer>>id;
1672    get(id)->recvRegistry(*buffer);
1673  }
1674
1675  void CContext::recvRegistry(CBufferIn& buffer)
1676  {
1677    if (server->intraCommRank==0)
1678    {
1679      CRegistry registry(server->intraComm) ;
1680      registry.fromBuffer(buffer) ;
1681      registryOut->mergeRegistry(registry) ;
1682    }
1683  }
1684
1685  void CContext::sendRegistry(void)
[1158]1686  {
[697]1687    registryOut->hierarchicalGatherRegistry() ;
1688
[1009]1689    // Use correct context client to send message
[1030]1690    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
[1009]1691    for (int i = 0; i < nbSrvPools; ++i)
1692    {
1693      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1694      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
[1021]1695        if (contextClientTmp->isServerLeader())
[1009]1696        {
1697           CMessage msg ;
1698           if (hasServer)
1699             msg<<this->getIdServer(i);
1700           else
1701             msg<<this->getIdServer();
1702           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
[1021]1703           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
[1009]1704           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1705             event.push(*itRank,1,msg);
1706           contextClientTmp->sendEvent(event);
1707         }
1708         else contextClientTmp->sendEvent(event);
1709    }
[697]1710  }
1711
[1130]1712  /*!
1713  * \fn bool CContext::isFinalized(void)
[1139]1714  * Context is finalized if it received context post finalize event.
[1130]1715  */
[1054]1716  bool CContext::isFinalized(void)
1717  {
[1139]1718    return finalized;
[1054]1719  }
1720
[335]1721} // namespace xios
Note: See TracBrowser for help on using the repository browser.