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

Last change on this file since 1130 was 1130, checked in by oabramkina, 3 years ago

Two-level server: merging new grid functionalities and changes in the communication protocol (e.g. non-blocking context finalize, registries, oasis).

Tests on curie: test_client, test_complete, nemo (test_xios2_cmip6.exe).

To do: non-structured grid, check reading, possible bug in client/server initialization (?).

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