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

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

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