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

Last change on this file since 1180 was 1180, checked in by oabramkina, 4 years ago

Two server levels:
(1) oasis works now with two server levels
(2) corrected assignment of processes between two server levels in case of non-contiguous processes
(3) corrected a bug during context finalization.

  • 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
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()
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);
303     std::map<int, StdSize> dataBufferSize = getDataBufferSize(maxEventSize);
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 (client->isServerLeader())
322     {
323       const std::list<int>& ranks = client->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     client->setBufferSize(bufferSize, maxEventSize);
328
329     // If it is primary server pool, also set buffer for clientPrimServer.
330     if (hasClient && hasServer)
331     {
332       for (int i = 0; i < clientPrimServer.size(); ++i)
333       {
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);
341       }
342     }
343   }
344
345   //! Verify whether a context is initialized
346   bool CContext::isInitialized(void)
347   {
348     return hasClient;
349   }
350
351   void CContext::initServer(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtClient /*= 0*/)
352   {
353     hasServer=true;
354     server = new CContextServer(this,intraComm,interComm);
355
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()) ;
362
363     MPI_Comm intraCommClient, interCommClient;
364     if (cxtClient) // Attached mode
365     {
366       intraCommClient = intraComm;
367       interCommClient = interComm;
368     }
369     else
370     {
371       MPI_Comm_dup(intraComm, &intraCommClient);
372       comms.push_back(intraCommClient);
373       MPI_Comm_dup(interComm, &interCommClient);
374       comms.push_back(interCommClient);
375     }
376     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
377   }
378
379   //! Try to send the buffers and receive possible answers
380  bool CContext::checkBuffersAndListen(void)
381  {
382    bool clientReady, serverFinished;
383
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    {
396      if (!finalized)
397        client->checkBuffers();
398      bool serverFinished = true;
399      if (!finalized)
400        serverFinished = server->eventLoop();
401      bool serverPrimFinished = true;
402      for (int i = 0; i < clientPrimServer.size(); ++i)
403      {
404        if (!finalized)
405          clientPrimServer[i]->checkBuffers();
406        if (!finalized)
407          serverPrimFinished *= serverPrimServer[i]->eventLoop();
408      }
409      return ( serverFinished && serverPrimFinished);
410    }
411
412    else if (CServer::serverLevel == 2)
413    {
414      client->checkBuffers();
415      return server->eventLoop();
416    }
417  }
418
419   //! Terminate a context
420   void CContext::finalize(void)
421   {
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
429     // (3) send post finalize to its server
430     if (CXios::isClient)
431     {
432       // Make sure that client (model) enters the loop only once
433       if (countChildCtx_ < 1)
434       {
435         ++countChildCtx_;
436
437         client->finalize();
438         while (client->havePendingRequests())
439            client->checkBuffers();
440
441         while (!server->hasFinished())
442           server->eventLoop();
443
444         if (CXios::isServer) // Mode attache
445           postFinalize();
446         else                  // Mode server
447           client->postFinalize();
448
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)
456         for (int i = 0; i < clientPrimServer.size(); ++i)
457           clientPrimServer[i]->finalize();
458
459       // (Last) context finalized message received
460       // Close files, gather registries, send context finalize to its parent context
461       if (countChildCtx_ == clientPrimServer.size())
462         client->finalize();
463
464       ++countChildCtx_;
465     }
466   }
467
468   /*!
469   * \fn void CContext::postFinalize(void)
470   * Close files, gather registries, and make deallocations.
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   {
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
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
500     //! Deallocate client buffers
501     client->releaseBuffers();
502     for (int i = 0; i < clientPrimServer.size(); ++i)
503       clientPrimServer[i]->releaseBuffers();
504
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
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   }
519
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
528   void CContext::postProcessingGlobalAttributes()
529   {
530     if (allProcessed) return; 
531     
532     // After xml is parsed, there are some more works with post processing
533     postProcessing();
534
535     // Check grid and calculate its distribution
536     checkGridEnabledFields();   
537
538     setClientServerBuffer();
539
540     if (hasClient)
541     {
542      // Send all attributes of current context to server
543      this->sendAllAttributesToServer();
544
545      // Send all attributes of current calendar
546      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
547
548      // We have enough information to send to server
549      // First of all, send all enabled files
550      sendEnabledFiles();
551
552      // Then, send all enabled fields
553      sendEnabledFields();
554
555      // At last, we have all info of domain and axis, then send them
556       sendRefDomainsAxis();
557
558       // After that, send all grid (if any)
559       sendRefGrid();
560
561       // We have a xml tree on the server side and now, it should be also processed
562       sendPostProcessing();
563
564       sendGridEnabledFields();       
565     }
566     allProcessed = true;
567   }
568
569   void CContext::sendPostProcessingGlobalAttributes()
570   {
571      // Use correct context client to send message
572     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
573    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
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);
578
579       if (contextClientTmp->isServerLeader())
580       {
581         CMessage msg;
582         if (hasServer)
583           msg<<this->getIdServer(i);
584         else
585           msg<<this->getIdServer();
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);
592     }
593   }
594
595   void CContext::recvPostProcessingGlobalAttributes(CEventServer& event)
596   {
597      CBufferIn* buffer=event.subEvents.begin()->buffer;
598      string id;
599      *buffer>>id;
600      get(id)->recvPostProcessingGlobalAttributes(*buffer);
601   }
602
603   void CContext::recvPostProcessingGlobalAttributes(CBufferIn& buffer)
604   {     
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   {
619    CTimer::get("Context : close definition").resume() ;
620    postProcessingGlobalAttributes();
621
622    if (hasClient) sendPostProcessingGlobalAttributes();
623
624    // There are some processings that should be done after all of above. For example: check mask or index
625    this->buildFilterGraphOfEnabledFields();
626   
627     if (hasClient && !hasServer)
628    {
629      buildFilterGraphOfFieldsWithReadAccess();
630    }
631   
632    checkGridEnabledFields();   
633
634    if (hasClient) this->sendProcessingGridOfEnabledFields();
635    if (hasClient) this->sendCloseDefinition();
636
637    // Nettoyage de l'arborescence
638    if (hasClient) CleanTree(); // Only on client side??
639
640    if (hasClient)
641    {
642      sendCreateFileHeader();
643      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
644    }
645    CTimer::get("Context : close definition").suspend() ;
646   }
647
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
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
666   void CContext::sendGridEnabledFields()
667   {
668     int size = this->enabledFiles.size();
669     for (int i = 0; i < size; ++i)
670     {       
671       this->enabledFiles[i]->sendGridOfEnabledFields();
672     }
673   }
674
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   }
683
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
698   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
699   {
700     int size = this->enabledFiles.size();
701     for (int i = 0; i < size; ++i)
702     {
703       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
704     }
705   }
706
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
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
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      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);
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
755  void CContext::buildFilterGraphOfFieldsWithReadAccess()
756  {
757    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
758      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
759  }
760
761   void CContext::solveAllInheritance(bool apply)
762   {
763     // Résolution des héritages descendants (càd des héritages de groupes)
764     // pour chacun des contextes.
765      solveDescInheritance(apply);
766
767     // Résolution des héritages par référence au niveau des fichiers.
768      const vector<CFile*> allFiles=CFile::getAll();
769      const vector<CGrid*> allGrids= CGrid::getAll();
770
771      if (hasClient && !hasServer)
772      //if (hasClient)
773      {
774        for (unsigned int i = 0; i < allFiles.size(); i++)
775          allFiles[i]->solveFieldRefInheritance(apply);
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
783   }
784
785   void CContext::findEnabledFiles(void)
786   {
787      const std::vector<CFile*> allFiles = CFile::getAll();
788      const CDate& initDate = calendar->getInitDate();
789
790      for (unsigned int i = 0; i < allFiles.size(); i++)
791         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
792         {
793            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
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
802               enabledFiles.push_back(allFiles[i]);
803            }
804         }
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         }
816
817      if (enabledFiles.size() == 0)
818         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
819               << getId() << "\" !");
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      }
835   }
836
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
847   void CContext::closeAllFile(void)
848   {
849     std::vector<CFile*>::const_iterator
850            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
851
852     for (; it != end; it++)
853     {
854       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
855       (*it)->close();
856     }
857   }
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   */
866   bool CContext::dispatchEvent(CEventServer& event)
867   {
868
869      if (SuperClass::dispatchEvent(event)) return true;
870      else
871      {
872        switch(event.type)
873        {
874           case EVENT_ID_CLOSE_DEFINITION :
875             recvCloseDefinition(event);
876             return true;
877             break;
878           case EVENT_ID_UPDATE_CALENDAR:
879             recvUpdateCalendar(event);
880             return true;
881             break;
882           case EVENT_ID_CREATE_FILE_HEADER :
883             recvCreateFileHeader(event);
884             return true;
885             break;
886           case EVENT_ID_POST_PROCESS:
887             recvPostProcessing(event);
888             return true;
889            case EVENT_ID_SEND_REGISTRY:
890             recvRegistry(event);
891             return true;
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;
901           default :
902             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
903                    <<"Unknown Event");
904           return false;
905         }
906      }
907   }
908
909   //! Client side: Send a message to server to make it close
910   void CContext::sendCloseDefinition(void)
911   {
912     // Use correct context client to send message
913     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
914     for (int i = 0; i < nbSrvPools; ++i)
915     {
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);
931     }
932   }
933
934   //! Server side: Receive a message of client announcing a context close
935   void CContext::recvCloseDefinition(CEventServer& event)
936   {
937      CBufferIn* buffer=event.subEvents.begin()->buffer;
938      string id;
939      *buffer>>id;
940      get(id)->closeDefinition();
941   }
942
943   //! Client side: Send a message to update calendar in each time step
944   void CContext::sendUpdateCalendar(int step)
945   {
946     // Use correct context client to send message
947    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
948     for (int i = 0; i < nbSrvPools; ++i)
949     {
950       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
951       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
952
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     }
967   }
968
969   //! Server side: Receive a message of client annoucing calendar update
970   void CContext::recvUpdateCalendar(CEventServer& event)
971   {
972      CBufferIn* buffer=event.subEvents.begin()->buffer;
973      string id;
974      *buffer>>id;
975      get(id)->recvUpdateCalendar(*buffer);
976   }
977
978   //! Server side: Receive a message of client annoucing calendar update
979   void CContext::recvUpdateCalendar(CBufferIn& buffer)
980   {
981      int step;
982      buffer>>step;
983      updateCalendar(step);
984      if (hasClient && hasServer)
985      {       
986        sendUpdateCalendar(step);
987      }
988   }
989
990   //! Client side: Send a message to create header part of netcdf file
991   void CContext::sendCreateFileHeader(void)
992   {
993     // Use correct context client to send message
994     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
995     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
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);
1000
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);
1014     }
1015   }
1016
1017   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1018   void CContext::recvCreateFileHeader(CEventServer& event)
1019   {
1020      CBufferIn* buffer=event.subEvents.begin()->buffer;
1021      string id;
1022      *buffer>>id;
1023      get(id)->recvCreateFileHeader(*buffer);
1024   }
1025
1026   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
1027   void CContext::recvCreateFileHeader(CBufferIn& buffer)
1028   {
1029      if (!hasClient && hasServer) 
1030        createFileHeader();
1031   }
1032
1033   //! Client side: Send a message to do some post processing on server
1034   void CContext::sendProcessingGridOfEnabledFields()
1035   {
1036      // Use correct context client to send message
1037     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
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);
1042
1043       if (contextClientTmp->isServerLeader())
1044       {
1045         CMessage msg;
1046         if (hasServer)
1047           msg<<this->getIdServer(i);
1048         else
1049           msg<<this->getIdServer();
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);
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;
1064      *buffer>>id;     
1065   }
1066
1067   //! Client side: Send a message to do some post processing on server
1068   void CContext::sendPostProcessing()
1069   {
1070      // Use correct context client to send message
1071     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1072     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1073     for (int i = 0; i < nbSrvPools; ++i)
1074     {
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)
1086         event.push(*itRank,1,msg);
1087         contextClientTmp->sendEvent(event);
1088       }
1089       else contextClientTmp->sendEvent(event);
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   {
1105      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1106      postProcessing();
1107   }
1108
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
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
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
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() << "!\"")
1144      // Calendar first update to set the current date equals to the start date
1145      calendar->update(0);
1146
1147      // Find all inheritance in xml structure
1148      this->solveAllInheritance();
1149
1150//      ShowTree(info(10));
1151
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
1154      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1155
1156      // Check if some automatic time series should be generated
1157      // Warning: This must be done after solving the inheritance and before the rest of post-processing     
1158
1159      // The timeseries should only be prepared in client
1160      if (hasClient && !hasServer) prepareTimeseries();
1161
1162      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1163      this->findEnabledFiles();
1164     
1165      // For now, only read files with client and only one level server
1166      if (hasClient && !hasServer) this->findEnabledReadModeFiles();
1167
1168      // Find all enabled fields of each file
1169      this->findAllEnabledFields();
1170      // For now, only read files with client and only one level server
1171      if (hasClient && !hasServer) this->findAllEnabledFieldsInReadModeFiles();
1172
1173
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
1180      // Only search and rebuild all reference objects of enable fields, don't transform
1181      this->solveOnlyRefOfEnabledFields(false);
1182
1183      // Search and rebuild all reference object of enabled fields, and transform
1184      this->solveAllRefOfEnabledFieldsAndTransform(false);
1185
1186      // Find all fields with read access from the public API
1187      if (hasClient && !hasServer) findFieldsWithReadAccess();
1188      // and solve the all reference for them
1189      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1190
1191      isPostProcessed = true;
1192   }
1193
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)
1200   {
1201     std::map<int, StdSize> attributesSize;
1202
1203     if (hasClient)
1204     {
1205       size_t numEnabledFiles = this->enabledFiles.size();
1206       for (size_t i = 0; i < numEnabledFiles; ++i)
1207       {
1208         CFile* file = this->enabledFiles[i];
1209
1210         std::vector<CField*> enabledFields = file->getEnabledFields();
1211         size_t numEnabledFields = enabledFields.size();
1212         for (size_t j = 0; j < numEnabledFields; ++j)
1213         {
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;
1222
1223             if (maxEventSize[it->first] < it->second)
1224               maxEventSize[it->first] = it->second;
1225           }
1226         }
1227       }
1228     }
1229
1230     return attributesSize;
1231   }
1232
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)
1239   {
1240     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
1241
1242     std::map<int, StdSize> dataSize;
1243
1244     // Find all reference domain and axis of all active fields
1245     size_t numEnabledFiles = this->enabledFiles.size();
1246     for (size_t i = 0; i < numEnabledFiles; ++i)
1247     {
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)
1252       {
1253         std::vector<CField*> enabledFields = file->getEnabledFields();
1254         size_t numEnabledFields = enabledFields.size();
1255         for (size_t j = 0; j < numEnabledFields; ++j)
1256         {
1257           const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
1258           for (size_t c = 0; c < mapSize.size(); ++c)
1259           {
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;
1269
1270               if (maxEventSize[it->first] < it->second)
1271                 maxEventSize[it->first] = it->second;
1272             }
1273           }
1274         }
1275       }
1276     }
1277
1278     return dataSize;
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);
1291
1292     for (int i = 0; i < size; ++i)
1293     {
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());
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     {
1306       this->enabledFiles[i]->sendEnabledFields(enabledFiles[i]->getContextClient());
1307     }
1308   }
1309
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
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
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
1352       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1353       {
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       
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
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           
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
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
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
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();
1456       CGrid::get(*it)->sendAllDomains();
1457       CGrid::get(*it)->sendAllAxis();
1458       CGrid::get(*it)->sendAllScalars();
1459     }
1460   }
1461
1462
1463   //! Client side: Send information of reference domain and axis of active fields
1464   void CContext::sendRefDomainsAxis()
1465   {
1466     std::set<StdString> domainIds, axisIds, scalarIds;
1467
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       {
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]);
1480       }
1481     }
1482
1483     // Create all reference axis on server side
1484     std::set<StdString>::iterator itDom, itAxis, itScalar;
1485     std::set<StdString>::const_iterator itE;
1486
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
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
1524   //! Update calendar in each time step
1525   void CContext::updateCalendar(int step)
1526   {
1527      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1528      calendar->update(step);
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
1533      if (hasClient)
1534      {
1535        checkPrefetchingOfEnabledReadModeFiles();
1536        garbageCollector.invalidate(calendar->getCurrentDate());
1537      }
1538   }
1539
1540   //! Server side: Create header of netcdf file
1541   void CContext::createFileHeader(void )
1542   {
1543      vector<CFile*>::const_iterator it;
1544
1545      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1546      {
1547         (*it)->initFile();
1548      }
1549   }
1550
1551   //! Get current context
1552   CContext* CContext::getCurrent(void)
1553   {
1554     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1555   }
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   */
1561   void CContext::setCurrent(const string& id)
1562   {
1563     CObjectFactory::SetCurrentContextId(id);
1564     CGroupFactory::SetCurrentContextId(id);
1565   }
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  */
1572  CContext* CContext::create(const StdString& id)
1573  {
1574    CContext::setCurrent(id);
1575
1576    bool hasctxt = CContext::has(id);
1577    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1578    getRoot();
1579    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
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  }
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)
1610  {
1611    registryOut->hierarchicalGatherRegistry() ;
1612
1613    // Use correct context client to send message
1614    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
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);
1619        if (contextClientTmp->isServerLeader())
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 ;
1627           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
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    }
1634  }
1635
1636  /*!
1637  * \fn bool CContext::isFinalized(void)
1638  * Context is finalized if it received context post finalize event.
1639  */
1640  bool CContext::isFinalized(void)
1641  {
1642    return finalized;
1643  }
1644
1645} // namespace xios
Note: See TracBrowser for help on using the repository browser.