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

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

Fixing a bug in context finalization. Now context finalization is done in two stages.
Tested on Cure with test_regular and test_xios2_cmip6.

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