source: XIOS/dev/dev_olga/src/node/context.cpp @ 1178

Last change on this file since 1178 was 1158, checked in by oabramkina, 7 years ago

Two server levels: merging with trunk r1137.
There are bugs.

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