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

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

Two server levels: correcting buffer allocations on client side of primary server. The buffer size is calculated according to the number of files sent to each secondary server.

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