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

Last change on this file since 1099 was 1099, checked in by mhnguyen, 7 years ago

Updating 2-level server

+) Make some changes in the way data rebuilt on each level of server
+) Make some changes in the order of functions call during close context to make sure that each server receives the global indexes before calculating index to send to next level
+) Modify some functions to make sure data sent to the correct server pool

Test
+) On Curie
+) Only test_client

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