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

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

Two server levels: merging trunk r1200 (except for non-contiguous zoom) into dev. Tested on Curie. Todo: non-contiguous zoom.

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