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

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

Two server levels: simplifying context finalization.
Send of context finalization is blocking now on all server types.

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