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

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

Updating two-level server.
Each client now can play the role of server: It can forward data to other clients or write data like a server.
Each client must combine all data received from other client(s) before forward them or write them on files

+) Correct some bugs of exchange data_index in domain and axis
+) Reorder some functions in context.cpp to make sure that all necessary attributes are available before computing index
+) Add the mapping index for client to write data.

Test
+) On Curie
+) test_client and test_complete
+) Mode:

  • Only one level: Correct
  • Two levels: Work if using ddt (bug)

+) Only zoom is tested but other transformations should work
+) No reading test

  • 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    this->buildFilterGraphOfEnabledFields();
577   
578    if (hasClient && !hasServer)
579    {
580      buildFilterGraphOfFieldsWithReadAccess();     
581    }
582
583    // if (hasClient) this->solveAllRefOfEnabledFields(true);   
584    checkGridEnabledFields();
585    // sendGridEnabledFields();
586
587    if (hasClient) this->sendProcessingGridOfEnabledFields();
588    if (hasClient) this->sendCloseDefinition();
589
590    // Nettoyage de l'arborescence
591    if (hasClient) CleanTree(); // Only on client side??
592
593    if (hasClient)
594    {
595      sendCreateFileHeader();
596      if (!hasServer) startPrefetchingOfEnabledReadModeFiles();
597    }
598   }
599
600   void CContext::findAllEnabledFields(void)
601   {
602     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
603     (void)this->enabledFiles[i]->getEnabledFields();
604   }
605
606   void CContext::findAllEnabledFieldsInReadModeFiles(void)
607   {
608     for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
609     (void)this->enabledReadModeFiles[i]->getEnabledFields();
610   }
611
612   void CContext::readAttributesOfEnabledFieldsInReadModeFiles()
613   {
614      for (unsigned int i = 0; i < this->enabledReadModeFiles.size(); ++i)
615        (void)this->enabledReadModeFiles[i]->readAttributesOfEnabledFieldsInReadMode();
616   }
617
618   void CContext::solveAllEnabledFields()
619   {
620     int size = this->enabledFiles.size();
621     for (int i = 0; i < size; ++i)
622     {
623       this->enabledFiles[i]->solveOnlyRefOfEnabledFields(false);
624       // this->enabledFiles[i]->solveAllReferenceEnabledField(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
667   void CContext::solveAllRefOfEnabledFieldsAndTransform(bool sendToServer)
668   {
669     int size = this->enabledFiles.size();
670     for (int i = 0; i < size; ++i)
671     {
672       this->enabledFiles[i]->solveAllRefOfEnabledFieldsAndTransform(sendToServer);
673     }
674   }
675
676   void CContext::buildFilterGraphOfEnabledFields()
677   {
678     int size = this->enabledFiles.size();
679     for (int i = 0; i < size; ++i)
680     {
681       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
682     }
683   }
684
685   void CContext::startPrefetchingOfEnabledReadModeFiles()
686   {
687     int size = enabledReadModeFiles.size();
688     for (int i = 0; i < size; ++i)
689     {
690        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
691     }
692   }
693
694   void CContext::checkPrefetchingOfEnabledReadModeFiles()
695   {
696     int size = enabledReadModeFiles.size();
697     for (int i = 0; i < size; ++i)
698     {
699        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
700     }
701   }
702
703  void CContext::findFieldsWithReadAccess(void)
704  {
705    fieldsWithReadAccess.clear();
706    const vector<CField*> allFields = CField::getAll();
707    for (size_t i = 0; i < allFields.size(); ++i)
708    {
709      CField* field = allFields[i];
710
711      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
712        field->read_access = true;
713      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
714        fieldsWithReadAccess.push_back(field);
715    }
716  }
717
718  void CContext::solveAllRefOfFieldsWithReadAccess()
719  {
720    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
721      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
722  }
723
724  void CContext::buildFilterGraphOfFieldsWithReadAccess()
725  {
726    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
727      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
728  }
729
730   void CContext::solveAllInheritance(bool apply)
731   {
732     // Résolution des héritages descendants (càd des héritages de groupes)
733     // pour chacun des contextes.
734      solveDescInheritance(apply);
735
736     // Résolution des héritages par référence au niveau des fichiers.
737      const vector<CFile*> allFiles=CFile::getAll();
738      const vector<CGrid*> allGrids= CGrid::getAll();
739
740      if (hasClient && !hasServer)
741      //if (hasClient)
742      {
743        for (unsigned int i = 0; i < allFiles.size(); i++)
744          allFiles[i]->solveFieldRefInheritance(apply);
745      }
746
747      unsigned int vecSize = allGrids.size();
748      unsigned int i = 0;
749      for (i = 0; i < vecSize; ++i)
750        allGrids[i]->solveDomainAxisRefInheritance(apply);
751
752   }
753
754   void CContext::findEnabledFiles(void)
755   {
756      const std::vector<CFile*> allFiles = CFile::getAll();
757
758      for (unsigned int i = 0; i < allFiles.size(); i++)
759         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
760         {
761            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
762               enabledFiles.push_back(allFiles[i]);
763         }
764         else enabledFiles.push_back(allFiles[i]); // otherwise true by default
765
766
767      if (enabledFiles.size() == 0)
768         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
769               << getId() << "\" !");
770
771      // Assigning contextClient to each enabled file
772      if (hasClient)
773      {
774        for (int i = 0; i < enabledFiles.size(); ++i)
775        {
776          if (hasServer)
777          {
778            int srvId = i % clientPrimServer.size();
779            enabledFiles[i]->setContextClient(clientPrimServer[srvId]);
780          }
781          else
782            enabledFiles[i]->setContextClient(client);
783        }
784      }
785   }
786
787   void CContext::findEnabledReadModeFiles(void)
788   {
789     int size = this->enabledFiles.size();
790     for (int i = 0; i < size; ++i)
791     {
792       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
793        enabledReadModeFiles.push_back(enabledFiles[i]);
794     }
795   }
796
797   void CContext::closeAllFile(void)
798   {
799     std::vector<CFile*>::const_iterator
800            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
801
802     for (; it != end; it++)
803     {
804       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
805       (*it)->close();
806     }
807   }
808
809   /*!
810   \brief Dispatch event received from client
811      Whenever a message is received in buffer of server, it will be processed depending on
812   its event type. A new event type should be added in the switch list to make sure
813   it processed on server side.
814   \param [in] event: Received message
815   */
816   bool CContext::dispatchEvent(CEventServer& event)
817   {
818
819      if (SuperClass::dispatchEvent(event)) return true;
820      else
821      {
822        switch(event.type)
823        {
824           case EVENT_ID_CLOSE_DEFINITION :
825             recvCloseDefinition(event);
826             return true;
827             break;
828           case EVENT_ID_UPDATE_CALENDAR:
829             recvUpdateCalendar(event);
830             return true;
831             break;
832           case EVENT_ID_CREATE_FILE_HEADER :
833             recvCreateFileHeader(event);
834             return true;
835             break;
836           case EVENT_ID_POST_PROCESS:
837             recvPostProcessing(event);
838             return true;
839            case EVENT_ID_SEND_REGISTRY:
840             recvRegistry(event);
841             return true;
842             break;
843            case EVENT_ID_POST_PROCESS_GLOBAL_ATTRIBUTES:
844             recvPostProcessingGlobalAttributes(event);
845             return true;
846             break;
847            case EVENT_ID_PROCESS_GRID_ENABLED_FIELDS:
848             recvProcessingGridOfEnabledFields(event);
849             return true;
850             break;
851           default :
852             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
853                    <<"Unknown Event");
854           return false;
855         }
856      }
857   }
858
859//   // Only send close definition from process having hasClient
860//   void CContext::sendCloseDefinitionToServer(void)
861//   {
862//     CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
863//   }
864
865   //! Client side: Send a message to server to make it close
866   void CContext::sendCloseDefinition(void)
867   {
868     // Use correct context client to send message
869     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
870     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
871     for (int i = 0; i < nbSrvPools; ++i)
872     {
873       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
874       CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
875       if (contextClientTmp->isServerLeader())
876       {
877         CMessage msg;
878         if (hasServer)
879           msg<<this->getIdServer(i);
880         else
881           msg<<this->getIdServer();
882         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
883         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
884           event.push(*itRank,1,msg);
885         contextClientTmp->sendEvent(event);
886       }
887       else contextClientTmp->sendEvent(event);
888     }
889   }
890
891   //! Server side: Receive a message of client announcing a context close
892   void CContext::recvCloseDefinition(CEventServer& event)
893   {
894      CBufferIn* buffer=event.subEvents.begin()->buffer;
895      string id;
896      *buffer>>id;
897      get(id)->closeDefinition();
898   }
899
900   //! Client side: Send a message to update calendar in each time step
901   void CContext::sendUpdateCalendar(int step)
902   {
903     // Use correct context client to send message
904//     CContextClient* contextClientTmp = (0 != clientPrimServer) ? clientPrimServer : client;
905     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
906    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
907     for (int i = 0; i < nbSrvPools; ++i)
908     {
909       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
910       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
911
912         if (contextClientTmp->isServerLeader())
913         {
914           CMessage msg;
915           if (hasServer)
916             msg<<this->getIdServer(i)<<step;
917           else
918             msg<<this->getIdServer()<<step;
919           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
920           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
921             event.push(*itRank,1,msg);
922           contextClientTmp->sendEvent(event);
923         }
924         else contextClientTmp->sendEvent(event);
925     }
926   }
927
928   //! Server side: Receive a message of client annoucing calendar update
929   void CContext::recvUpdateCalendar(CEventServer& event)
930   {
931      CBufferIn* buffer=event.subEvents.begin()->buffer;
932      string id;
933      *buffer>>id;
934      get(id)->recvUpdateCalendar(*buffer);
935   }
936
937   //! Server side: Receive a message of client annoucing calendar update
938   void CContext::recvUpdateCalendar(CBufferIn& buffer)
939   {
940      int step;
941      buffer>>step;
942      updateCalendar(step);
943      if (hasClient && hasServer)
944      {       
945        sendUpdateCalendar(step);
946      }
947   }
948
949   //! Client side: Send a message to create header part of netcdf file
950   void CContext::sendCreateFileHeader(void)
951   {
952     // Use correct context client to send message
953     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
954     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
955     for (int i = 0; i < nbSrvPools; ++i)
956     {
957       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
958       CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
959
960       if (contextClientTmp->isServerLeader())
961       {
962         CMessage msg;
963         if (hasServer)
964           msg<<this->getIdServer(i);
965         else
966           msg<<this->getIdServer();
967         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
968         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
969           event.push(*itRank,1,msg) ;
970         contextClientTmp->sendEvent(event);
971       }
972       else contextClientTmp->sendEvent(event);
973     }
974   }
975
976   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
977   void CContext::recvCreateFileHeader(CEventServer& event)
978   {
979      CBufferIn* buffer=event.subEvents.begin()->buffer;
980      string id;
981      *buffer>>id;
982      get(id)->recvCreateFileHeader(*buffer);
983   }
984
985   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
986   void CContext::recvCreateFileHeader(CBufferIn& buffer)
987   {
988     // The creation of header file should be delegated to server2, for now
989      // if (hasClient && hasServer)
990      // {       
991      //   sendCreateFileHeader();
992      // }
993     
994      if (!hasClient && hasServer) 
995        createFileHeader();
996   }
997
998   //! Client side: Send a message to do some post processing on server
999   void CContext::sendProcessingGridOfEnabledFields()
1000   {
1001      // Use correct context client to send message
1002     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1003     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1004     for (int i = 0; i < nbSrvPools; ++i)
1005     {
1006       CContextClient* contextClientTmp = (0 != clientPrimServer.size()) ? clientPrimServer[i] : client;
1007       CEventClient event(getType(),EVENT_ID_PROCESS_GRID_ENABLED_FIELDS);
1008
1009       if (contextClientTmp->isServerLeader())
1010       {
1011         CMessage msg;
1012         if (hasServer)
1013           msg<<this->getIdServer(i);
1014         else
1015           msg<<this->getIdServer();
1016         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1017         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1018           event.push(*itRank,1,msg);
1019         contextClientTmp->sendEvent(event);
1020       }
1021       else contextClientTmp->sendEvent(event);
1022     }
1023   }
1024
1025   //! Server side: Receive a message to do some post processing
1026   void CContext::recvProcessingGridOfEnabledFields(CEventServer& event)
1027   {
1028      CBufferIn* buffer=event.subEvents.begin()->buffer;
1029      string id;
1030      *buffer>>id;
1031      //get(id)->solveOnlyRefOfEnabledFields(false);
1032   }
1033
1034   //! Client side: Send a message to do some post processing on server
1035   void CContext::sendPostProcessing()
1036   {
1037      // Use correct context client to send message
1038     // int nbSrvPools = (hasServer) ? clientPrimServer.size() : 1;
1039     int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1040     for (int i = 0; i < nbSrvPools; ++i)
1041     {
1042       CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1043       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
1044       if (contextClientTmp->isServerLeader())
1045       {
1046         CMessage msg;
1047         if (hasServer)
1048           msg<<this->getIdServer(i);
1049         else
1050           msg<<this->getIdServer();
1051         const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1052         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1053         event.push(*itRank,1,msg);
1054         contextClientTmp->sendEvent(event);
1055       }
1056       else contextClientTmp->sendEvent(event);
1057     }
1058   }
1059
1060   //! Server side: Receive a message to do some post processing
1061   void CContext::recvPostProcessing(CEventServer& event)
1062   {
1063      CBufferIn* buffer=event.subEvents.begin()->buffer;
1064      string id;
1065      *buffer>>id;
1066      get(id)->recvPostProcessing(*buffer);
1067   }
1068
1069   //! Server side: Receive a message to do some post processing
1070   void CContext::recvPostProcessing(CBufferIn& buffer)
1071   {
1072      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
1073      postProcessing();
1074   }
1075
1076   const StdString& CContext::getIdServer()
1077   {
1078      if (hasClient)
1079      {
1080        idServer_ = this->getId();
1081        idServer_ += "_server";
1082        return idServer_;
1083      }
1084      if (hasServer) return (this->getId());
1085   }
1086
1087   const StdString& CContext::getIdServer(const int i)
1088   {
1089     idServer_ = this->getId();
1090     idServer_ += "_server_";
1091     idServer_ += boost::lexical_cast<string>(i);
1092     return idServer_;
1093   }
1094
1095
1096   /*!
1097   \brief Do some simple post processings after parsing xml file
1098      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
1099   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
1100   which will be written out into netcdf files, are processed
1101   */
1102   void CContext::postProcessing()
1103   {
1104     if (isPostProcessed) return;
1105
1106      // Make sure the calendar was correctly created
1107      if (!calendar)
1108        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
1109      else if (calendar->getTimeStep() == NoneDu)
1110        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
1111      // Calendar first update to set the current date equals to the start date
1112      calendar->update(0);
1113
1114      // Find all inheritance in xml structure
1115      this->solveAllInheritance();
1116
1117//      ShowTree(info(10));
1118
1119      // Check if some axis, domains or grids are eligible to for compressed indexed output.
1120      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1121      checkAxisDomainsGridsEligibilityForCompressedOutput();     
1122
1123      // Check if some automatic time series should be generated
1124      // Warning: This must be done after solving the inheritance and before the rest of post-processing
1125      // prepareTimeseries();
1126
1127      // The timeseries should only be prepared in client
1128      if (hasClient && !hasServer) prepareTimeseries();
1129
1130      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
1131      this->findEnabledFiles();
1132      // this->findEnabledReadModeFiles();
1133      // For now, only read files with client and only one level server
1134      if (hasClient && !hasServer) this->findEnabledReadModeFiles();
1135
1136
1137      // Find all enabled fields of each file
1138      this->findAllEnabledFields();
1139      // this->findAllEnabledFieldsInReadModeFiles();
1140      // For now, only read files with client and only one level server
1141      if (hasClient && !hasServer) this->findAllEnabledFieldsInReadModeFiles();
1142
1143//     if (hasClient)
1144     if (hasClient && !hasServer)
1145     {
1146      // Try to read attributes of fields in file then fill in corresponding grid (or domain, axis)
1147      this->readAttributesOfEnabledFieldsInReadModeFiles();
1148     }
1149
1150      // // Only search and rebuild all reference objects of enable fields, don't transform
1151      // this->solveOnlyRefOfEnabledFields(false);
1152
1153      // // Search and rebuild all reference object of enabled fields
1154      // this->solveAllRefOfEnabledFields(false);
1155
1156      // // Find all fields with read access from the public API
1157      // findFieldsWithReadAccess();
1158      // // and solve the all reference for them
1159      // solveAllRefOfFieldsWithReadAccess();
1160
1161      // Only search and rebuild all reference objects of enable fields, don't transform
1162      this->solveOnlyRefOfEnabledFields(false);
1163
1164      // Search and rebuild all reference object of enabled fields, and transform
1165      // this->solveAllEnabledFields
1166      this->solveAllRefOfEnabledFieldsAndTransform(false);
1167      // // Check grid and calculate its distribution
1168      // if (hasClient) checkGridEnabledFields();
1169
1170      // Find all fields with read access from the public API
1171      if (hasClient && !hasServer) findFieldsWithReadAccess();
1172      // and solve the all reference for them
1173      if (hasClient && !hasServer) solveAllRefOfFieldsWithReadAccess();
1174
1175      isPostProcessed = true;
1176   }
1177
1178   /*!
1179    * Compute the required buffer size to send the attributes (mostly those grid related).
1180    *
1181    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1182    */
1183   std::map<int, StdSize> CContext::getAttributesBufferSize(std::map<int, StdSize>& maxEventSize)
1184   {
1185     std::map<int, StdSize> attributesSize;
1186
1187     if (hasClient)
1188     {
1189       size_t numEnabledFiles = this->enabledFiles.size();
1190       for (size_t i = 0; i < numEnabledFiles; ++i)
1191       {
1192         CFile* file = this->enabledFiles[i];
1193
1194         std::vector<CField*> enabledFields = file->getEnabledFields();
1195         size_t numEnabledFields = enabledFields.size();
1196         for (size_t j = 0; j < numEnabledFields; ++j)
1197         {
1198           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
1199           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
1200           for (; it != itE; ++it)
1201           {
1202             // If attributesSize[it->first] does not exist, it will be zero-initialized
1203             // so we can use it safely without checking for its existance
1204             if (attributesSize[it->first] < it->second)
1205               attributesSize[it->first] = it->second;
1206
1207             if (maxEventSize[it->first] < it->second)
1208               maxEventSize[it->first] = it->second;
1209           }
1210         }
1211       }
1212     }
1213
1214     return attributesSize;
1215   }
1216
1217   /*!
1218    * Compute the required buffer size to send the fields data.
1219    *
1220    * \param maxEventSize [in/out] the size of the bigger event for each connected server
1221    */
1222   std::map<int, StdSize> CContext::getDataBufferSize(std::map<int, StdSize>& maxEventSize)
1223   {
1224     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
1225
1226     std::map<int, StdSize> dataSize;
1227
1228     // Find all reference domain and axis of all active fields
1229     size_t numEnabledFiles = this->enabledFiles.size();
1230     for (size_t i = 0; i < numEnabledFiles; ++i)
1231     {
1232       CFile* file = this->enabledFiles[i];
1233       CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
1234
1235       if (fileMode == mode)
1236       {
1237         std::vector<CField*> enabledFields = file->getEnabledFields();
1238         size_t numEnabledFields = enabledFields.size();
1239         for (size_t j = 0; j < numEnabledFields; ++j)
1240         {
1241           const std::vector<std::map<int, StdSize> > mapSize = enabledFields[j]->getGridDataBufferSize();
1242           for (size_t c = 0; c < mapSize.size(); ++c)
1243           {
1244             std::map<int, StdSize>::const_iterator it = mapSize[c].begin(), itE = mapSize[c].end();
1245             for (; it != itE; ++it)
1246             {
1247               // If dataSize[it->first] does not exist, it will be zero-initialized
1248               // so we can use it safely without checking for its existance
1249               if (CXios::isOptPerformance)
1250                 dataSize[it->first] += it->second;
1251               else if (dataSize[it->first] < it->second)
1252                 dataSize[it->first] = it->second;
1253
1254               if (maxEventSize[it->first] < it->second)
1255                 maxEventSize[it->first] = it->second;
1256             }
1257           }
1258         }
1259       }
1260     }
1261
1262     return dataSize;
1263   }
1264
1265   //! Client side: Send infomation of active files (files are enabled to write out)
1266   void CContext::sendEnabledFiles()
1267   {
1268     int size = this->enabledFiles.size();
1269
1270     // In a context, each type has a root definition, e.g: axis, domain, field.
1271     // Every object must be a child of one of these root definition. In this case
1272     // all new file objects created on server must be children of the root "file_definition"
1273     StdString fileDefRoot("file_definition");
1274     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
1275     for (int i = 0; i < size; ++i)
1276     {
1277       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId(),enabledFiles[i]->getContextClient());
1278       this->enabledFiles[i]->sendAllAttributesToServer(enabledFiles[i]->getContextClient());
1279       this->enabledFiles[i]->sendAddAllVariables(enabledFiles[i]->getContextClient());
1280     }
1281   }
1282
1283   //! Client side: Send information of active fields (ones are written onto files)
1284   void CContext::sendEnabledFields()
1285   {
1286     int size = this->enabledFiles.size();
1287     for (int i = 0; i < size; ++i)
1288     {
1289       this->enabledFiles[i]->sendEnabledFields(enabledFiles[i]->getContextClient());
1290     }
1291   }
1292
1293   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
1294   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
1295   {
1296     if (!hasClient) return;
1297
1298     const vector<CAxis*> allAxis = CAxis::getAll();
1299     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
1300       (*it)->checkEligibilityForCompressedOutput();
1301
1302     const vector<CDomain*> allDomains = CDomain::getAll();
1303     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
1304       (*it)->checkEligibilityForCompressedOutput();
1305
1306     const vector<CGrid*> allGrids = CGrid::getAll();
1307     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
1308       (*it)->checkEligibilityForCompressedOutput();
1309   }
1310
1311   //! Client side: Prepare the timeseries by adding the necessary files
1312   void CContext::prepareTimeseries()
1313   {
1314     if (!hasClient) return;
1315
1316     const std::vector<CFile*> allFiles = CFile::getAll();
1317     for (size_t i = 0; i < allFiles.size(); i++)
1318     {
1319       CFile* file = allFiles[i];
1320
1321       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
1322       {
1323         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : file->getFileOutputName();
1324
1325         const std::vector<CField*> allFields = file->getAllFields();
1326         for (size_t j = 0; j < allFields.size(); j++)
1327         {
1328           CField* field = allFields[j];
1329
1330           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
1331           {
1332             CFile* tsFile = CFile::create();
1333             tsFile->duplicateAttributes(file);
1334             tsFile->setVirtualVariableGroup(file->getVirtualVariableGroup());
1335
1336             tsFile->name = tsPrefix + "_";
1337             if (!field->name.isEmpty())
1338               tsFile->name.get() += field->name;
1339             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
1340               tsFile->name.get() += field->field_ref;
1341             else
1342               tsFile->name.get() += field->getId();
1343
1344             if (!field->ts_split_freq.isEmpty())
1345               tsFile->split_freq = field->ts_split_freq;
1346
1347             CField* tsField = tsFile->addField();
1348             tsField->field_ref = field->getId();
1349             tsField->setVirtualVariableGroup(field->getVirtualVariableGroup());
1350
1351             tsFile->solveFieldRefInheritance(true);
1352
1353             if (file->timeseries == CFile::timeseries_attr::exclusive)
1354               field->enabled = false;
1355           }
1356         }
1357
1358         // Finally disable the original file is need be
1359         if (file->timeseries == CFile::timeseries_attr::only)
1360          file->enabled = false;
1361       }
1362     }
1363   }
1364
1365   //! Client side: Send information of reference grid of active fields
1366   void CContext::sendRefGrid()
1367   {
1368     std::set<StdString> gridIds;
1369     int sizeFile = this->enabledFiles.size();
1370     CFile* filePtr(NULL);
1371
1372     // Firstly, find all reference grids of all active fields
1373     for (int i = 0; i < sizeFile; ++i)
1374     {
1375       filePtr = this->enabledFiles[i];
1376       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
1377       int sizeField = enabledFields.size();
1378       for (int numField = 0; numField < sizeField; ++numField)
1379       {
1380         if (0 != enabledFields[numField]->getRelGrid())
1381           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
1382       }
1383     }
1384
1385     // Create all reference grids on server side
1386     StdString gridDefRoot("grid_definition");
1387     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
1388     std::set<StdString>::const_iterator it, itE = gridIds.end();
1389     for (it = gridIds.begin(); it != itE; ++it)
1390     {
1391       gridPtr->sendCreateChild(*it);
1392       CGrid::get(*it)->sendAllAttributesToServer();
1393       CGrid::get(*it)->sendAllDomains();
1394       CGrid::get(*it)->sendAllAxis();
1395       CGrid::get(*it)->sendAllScalars();
1396     }
1397   }
1398
1399
1400   //! Client side: Send information of reference domain and axis of active fields
1401   void CContext::sendRefDomainsAxis()
1402   {
1403     std::set<StdString> domainIds, axisIds, scalarIds;
1404
1405     // Find all reference domain and axis of all active fields
1406     int numEnabledFiles = this->enabledFiles.size();
1407     for (int i = 0; i < numEnabledFiles; ++i)
1408     {
1409       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1410       int numEnabledFields = enabledFields.size();
1411       for (int j = 0; j < numEnabledFields; ++j)
1412       {
1413         const std::vector<StdString>& prDomAxisScalarId = enabledFields[j]->getRefDomainAxisIds();
1414         if ("" != prDomAxisScalarId[0]) domainIds.insert(prDomAxisScalarId[0]);
1415         if ("" != prDomAxisScalarId[1]) axisIds.insert(prDomAxisScalarId[1]);
1416         if ("" != prDomAxisScalarId[2]) scalarIds.insert(prDomAxisScalarId[2]);
1417       }
1418     }
1419
1420     // Create all reference axis on server side
1421     std::set<StdString>::iterator itDom, itAxis, itScalar;
1422     std::set<StdString>::const_iterator itE;
1423
1424     StdString scalarDefRoot("scalar_definition");
1425     CScalarGroup* scalarPtr = CScalarGroup::get(scalarDefRoot);
1426     itE = scalarIds.end();
1427     for (itScalar = scalarIds.begin(); itScalar != itE; ++itScalar)
1428     {
1429       if (!itScalar->empty())
1430       {
1431         scalarPtr->sendCreateChild(*itScalar);
1432         CScalar::get(*itScalar)->sendAllAttributesToServer();
1433       }
1434     }
1435
1436     StdString axiDefRoot("axis_definition");
1437     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1438     itE = axisIds.end();
1439     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1440     {
1441       if (!itAxis->empty())
1442       {
1443         axisPtr->sendCreateChild(*itAxis);
1444         CAxis::get(*itAxis)->sendAllAttributesToServer();
1445       }
1446     }
1447
1448     // Create all reference domains on server side
1449     StdString domDefRoot("domain_definition");
1450     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1451     itE = domainIds.end();
1452     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1453     {
1454       if (!itDom->empty()) {
1455          domPtr->sendCreateChild(*itDom);
1456          CDomain::get(*itDom)->sendAllAttributesToServer();
1457       }
1458     }
1459   }
1460
1461   //! Update calendar in each time step
1462   void CContext::updateCalendar(int step)
1463   {
1464      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1465      calendar->update(step);
1466      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1467
1468      if (hasClient)
1469      {
1470        checkPrefetchingOfEnabledReadModeFiles();
1471        garbageCollector.invalidate(calendar->getCurrentDate());
1472      }
1473   }
1474
1475   //! Server side: Create header of netcdf file
1476   void CContext::createFileHeader(void )
1477   {
1478      vector<CFile*>::const_iterator it;
1479
1480      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1481      {
1482         (*it)->initFile();
1483      }
1484   }
1485
1486   //! Get current context
1487   CContext* CContext::getCurrent(void)
1488   {
1489     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1490   }
1491
1492   /*!
1493   \brief Set context with an id be the current context
1494   \param [in] id identity of context to be set to current
1495   */
1496   void CContext::setCurrent(const string& id)
1497   {
1498     CObjectFactory::SetCurrentContextId(id);
1499     CGroupFactory::SetCurrentContextId(id);
1500   }
1501
1502  /*!
1503  \brief Create a context with specific id
1504  \param [in] id identity of new context
1505  \return pointer to the new context or already-existed one with identity id
1506  */
1507  CContext* CContext::create(const StdString& id)
1508  {
1509    CContext::setCurrent(id);
1510
1511    bool hasctxt = CContext::has(id);
1512    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1513    getRoot();
1514    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1515
1516#define DECLARE_NODE(Name_, name_) \
1517    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1518#define DECLARE_NODE_PAR(Name_, name_)
1519#include "node_type.conf"
1520
1521    return (context);
1522  }
1523
1524
1525     //! Server side: Receive a message to do some post processing
1526  void CContext::recvRegistry(CEventServer& event)
1527  {
1528    CBufferIn* buffer=event.subEvents.begin()->buffer;
1529    string id;
1530    *buffer>>id;
1531    get(id)->recvRegistry(*buffer);
1532  }
1533
1534  void CContext::recvRegistry(CBufferIn& buffer)
1535  {
1536    if (server->intraCommRank==0)
1537    {
1538      CRegistry registry(server->intraComm) ;
1539      registry.fromBuffer(buffer) ;
1540      registryOut->mergeRegistry(registry) ;
1541    }
1542  }
1543
1544  void CContext::sendRegistry(void)
1545  {   
1546    registryOut->hierarchicalGatherRegistry() ;
1547
1548    // Use correct context client to send message
1549    int nbSrvPools = (this->hasServer) ? (this->hasClient ? this->clientPrimServer.size() : 0) : 1;
1550    for (int i = 0; i < nbSrvPools; ++i)
1551    {
1552      CContextClient* contextClientTmp = (hasServer) ? clientPrimServer[i] : client;
1553      CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1554        if (contextClientTmp->isServerLeader())
1555        {
1556           CMessage msg ;
1557           if (hasServer)
1558             msg<<this->getIdServer(i);
1559           else
1560             msg<<this->getIdServer();
1561           if (contextClientTmp->clientRank==0) msg<<*registryOut ;
1562           const std::list<int>& ranks = contextClientTmp->getRanksServerLeader();
1563           for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1564             event.push(*itRank,1,msg);
1565           contextClientTmp->sendEvent(event);
1566         }
1567         else contextClientTmp->sendEvent(event);
1568    }
1569  }
1570
1571  bool CContext::isFinalized(void)
1572  {
1573    return finalized;
1574  }
1575
1576} // namespace xios
Note: See TracBrowser for help on using the repository browser.