source: XIOS/trunk/src/node/context.cpp @ 773

Last change on this file since 773 was 773, checked in by rlacroix, 6 years ago

File/Variable?: Add an helper function to get the output name.

  • 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: 37.2 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
18namespace xios {
19
20  shared_ptr<CContextGroup> CContext::root;
21
22   /// ////////////////////// Définitions ////////////////////// ///
23
24   CContext::CContext(void)
25      : CObjectTemplate<CContext>(), CContextAttributes()
26      , calendar(), hasClient(false), hasServer(false), isPostProcessed(false), finalized(false)
27      , idServer_(), client(0), server(0)
28   { /* Ne rien faire de plus */ }
29
30   CContext::CContext(const StdString & id)
31      : CObjectTemplate<CContext>(id), CContextAttributes()
32      , calendar(), hasClient(false), hasServer(false), isPostProcessed(false), finalized(false)
33      , idServer_(), client(0), server(0)
34   { /* Ne rien faire de plus */ }
35
36   CContext::~CContext(void)
37   {
38     delete client;
39     delete server;
40   }
41
42   //----------------------------------------------------------------
43   //! Get name of context
44   StdString CContext::GetName(void)   { return (StdString("context")); }
45   StdString CContext::GetDefName(void){ return (CContext::GetName()); }
46   ENodeType CContext::GetType(void)   { return (eContext); }
47
48   //----------------------------------------------------------------
49
50   /*!
51   \brief Get context group (context root)
52   \return Context root
53   */
54   CContextGroup* CContext::getRoot(void)
55   {
56      if (root.get()==NULL) root=shared_ptr<CContextGroup>(new CContextGroup(xml::CXMLNode::GetRootName()));
57      return root.get();
58   }
59
60   //----------------------------------------------------------------
61
62   /*!
63   \brief Get calendar of a context
64   \return Calendar
65   */
66   boost::shared_ptr<CCalendar> CContext::getCalendar(void) const
67   {
68      return (this->calendar);
69   }
70
71   //----------------------------------------------------------------
72
73   /*!
74   \brief Set a context with a calendar
75   \param[in] newCalendar new calendar
76   */
77   void CContext::setCalendar(boost::shared_ptr<CCalendar> newCalendar)
78   {
79      this->calendar = newCalendar;
80   }
81
82   //----------------------------------------------------------------
83   /*!
84   \brief Parse xml file and write information into context object
85   \param [in] node xmld node corresponding in xml file
86   */
87   void CContext::parse(xml::CXMLNode & node)
88   {
89      CContext::SuperClass::parse(node);
90
91      // PARSING POUR GESTION DES ENFANTS
92      xml::THashAttributes attributes = node.getAttributes();
93
94      if (attributes.end() != attributes.find("src"))
95      {
96         StdIFStream ifs ( attributes["src"].c_str() , StdIFStream::in );
97         if ( (ifs.rdstate() & std::ifstream::failbit ) != 0 )
98            ERROR("void CContext::parse(xml::CXMLNode & node)",
99                  <<endl<< "Can not open <"<<attributes["src"].c_str()<<"> file" );
100         if (!ifs.good())
101            ERROR("CContext::parse(xml::CXMLNode & node)",
102                  << "[ filename = " << attributes["src"] << " ] Bad xml stream !");
103         xml::CXMLParser::ParseInclude(ifs, attributes["src"], *this);
104      }
105
106      if (node.getElementName().compare(CContext::GetName()))
107         DEBUG("Le noeud is wrong defined but will be considered as a context !");
108
109      if (!(node.goToChildElement()))
110      {
111         DEBUG("Le context ne contient pas d'enfant !");
112      }
113      else
114      {
115         do { // Parcours des contextes pour traitement.
116
117            StdString name = node.getElementName();
118            attributes.clear();
119            attributes = node.getAttributes();
120
121            if (attributes.end() != attributes.find("id"))
122            {
123              DEBUG(<< "Definition node has an id,"
124                    << "it will not be taking account !");
125            }
126
127#define DECLARE_NODE(Name_, name_)    \
128   if (name.compare(C##Name_##Definition::GetDefName()) == 0) \
129   { C##Name_##Definition::create(C##Name_##Definition::GetDefName()) -> parse(node); continue; }
130#define DECLARE_NODE_PAR(Name_, name_)
131#include "node_type.conf"
132
133            DEBUG(<< "The element \'"     << name
134                  << "\' in the context \'" << CContext::getCurrent()->getId()
135                  << "\' is not a definition !");
136
137         } while (node.goToNextElement());
138
139         node.goToParentElement(); // Retour au parent
140      }
141   }
142
143   //----------------------------------------------------------------
144   //! Show tree structure of context
145   void CContext::ShowTree(StdOStream & out)
146   {
147      StdString currentContextId = CContext::getCurrent() -> getId();
148      std::vector<CContext*> def_vector =
149         CContext::getRoot()->getChildList();
150      std::vector<CContext*>::iterator
151         it = def_vector.begin(), end = def_vector.end();
152
153      out << "<? xml version=\"1.0\" ?>" << std::endl;
154      out << "<"  << xml::CXMLNode::GetRootName() << " >" << std::endl;
155
156      for (; it != end; it++)
157      {
158         CContext* context = *it;
159         CContext::setCurrent(context->getId());
160         out << *context << std::endl;
161      }
162
163      out << "</" << xml::CXMLNode::GetRootName() << " >" << std::endl;
164      CContext::setCurrent(currentContextId);
165   }
166
167
168   //----------------------------------------------------------------
169
170   //! Convert context object into string (to print)
171   StdString CContext::toString(void) const
172   {
173      StdOStringStream oss;
174      oss << "<" << CContext::GetName()
175          << " id=\"" << this->getId() << "\" "
176          << SuperClassAttribute::toString() << ">" << std::endl;
177      if (!this->hasChild())
178      {
179         //oss << "<!-- No definition -->" << std::endl; // fait planter l'incrémentation
180      }
181      else
182      {
183
184#define DECLARE_NODE(Name_, name_)    \
185   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
186   oss << * C##Name_##Definition::get(C##Name_##Definition::GetDefName()) << std::endl;
187#define DECLARE_NODE_PAR(Name_, name_)
188#include "node_type.conf"
189
190      }
191
192      oss << "</" << CContext::GetName() << " >";
193
194      return (oss.str());
195   }
196
197   //----------------------------------------------------------------
198
199   /*!
200   \brief Find all inheritace among objects in a context.
201   \param [in] apply (true) write attributes of parent into ones of child if they are empty
202                     (false) write attributes of parent into a new container of child
203   \param [in] parent unused
204   */
205   void CContext::solveDescInheritance(bool apply, const CAttributeMap * const UNUSED(parent))
206   {
207#define DECLARE_NODE(Name_, name_)    \
208   if (C##Name_##Definition::has(C##Name_##Definition::GetDefName())) \
209     C##Name_##Definition::get(C##Name_##Definition::GetDefName())->solveDescInheritance(apply);
210#define DECLARE_NODE_PAR(Name_, name_)
211#include "node_type.conf"
212   }
213
214   //----------------------------------------------------------------
215
216   //! Verify if all root definition in the context have child.
217   bool CContext::hasChild(void) const
218   {
219      return (
220#define DECLARE_NODE(Name_, name_)    \
221   C##Name_##Definition::has(C##Name_##Definition::GetDefName())   ||
222#define DECLARE_NODE_PAR(Name_, name_)
223#include "node_type.conf"
224      false);
225}
226
227   //----------------------------------------------------------------
228
229   void CContext::CleanTree(void)
230   {
231#define DECLARE_NODE(Name_, name_) C##Name_##Definition::ClearAllAttributes();
232#define DECLARE_NODE_PAR(Name_, name_)
233#include "node_type.conf"
234   }
235   ///---------------------------------------------------------------
236
237   //! Initialize client side
238   void CContext::initClient(MPI_Comm intraComm, MPI_Comm interComm, CContext* cxtServer /*= 0*/)
239   {
240     hasClient=true;
241     client = new CContextClient(this,intraComm, interComm, cxtServer);
242     registryIn=new CRegistry(intraComm);
243     registryIn->setPath(getId()) ;
244     if (client->clientRank==0) registryIn->fromFile("xios_registry.bin") ;
245     registryIn->bcastRegistry() ;
246
247     registryOut=new CRegistry(intraComm) ;
248     registryOut->setPath(getId()) ;
249
250     MPI_Comm intraCommServer, interCommServer;
251     if (cxtServer) // Attached mode
252     {
253       intraCommServer = intraComm;
254       interCommServer = interComm;
255     }
256     else
257     {
258       MPI_Comm_dup(intraComm, &intraCommServer);
259       comms.push_back(intraCommServer);
260       MPI_Comm_dup(interComm, &interCommServer);
261       comms.push_back(interCommServer);
262     }
263     server = new CContextServer(this,intraCommServer,interCommServer);
264   }
265
266   void CContext::setClientServerBuffer()
267   {
268     size_t minBufferSize = CXios::minBufferSize;
269#define DECLARE_NODE(Name_, name_)    \
270     if (minBufferSize < sizeof(C##Name_##Definition)) minBufferSize = sizeof(C##Name_##Definition);
271#define DECLARE_NODE_PAR(Name_, name_)
272#include "node_type.conf"
273#undef DECLARE_NODE
274#undef DECLARE_NODE_PAR
275
276     std::map<int, StdSize> bufferSize = getAttributesBufferSize();
277     std::map<int, StdSize>::iterator it, ite = bufferSize.end();
278     for (it = bufferSize.begin(); it != ite; ++it)
279       if (it->second < minBufferSize) it->second = minBufferSize;
280
281     std::map<int, StdSize> dataBufferSize = getDataBufferSize();
282     ite = dataBufferSize.end();
283     for (it = dataBufferSize.begin(); it != ite; ++it)
284       if (it->second > bufferSize[it->first]) bufferSize[it->first] = it->second;
285
286     if (client->isServerLeader())
287     {
288       const std::list<int>& ranks = client->getRanksServerLeader();
289       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
290         if (!bufferSize.count(*itRank)) bufferSize[*itRank] = minBufferSize;
291     }
292
293     if (!bufferSize.empty())
294       client->setBufferSize(bufferSize);
295   }
296
297   //! Verify whether a context is initialized
298   bool CContext::isInitialized(void)
299   {
300     return hasClient;
301   }
302
303   //! Initialize server
304   void CContext::initServer(MPI_Comm intraComm,MPI_Comm interComm, CContext* cxtClient /*= 0*/)
305   {
306     hasServer=true;
307     server = new CContextServer(this,intraComm,interComm);
308
309     registryIn=new CRegistry(intraComm);
310     registryIn->setPath(getId()) ;
311     if (server->intraCommRank==0) registryIn->fromFile("xios_registry.bin") ;
312     registryIn->bcastRegistry() ;
313     registryOut=new CRegistry(intraComm) ;
314     registryOut->setPath(getId()) ;
315 
316     MPI_Comm intraCommClient, interCommClient;
317     if (cxtClient) // Attached mode
318     {
319       intraCommClient = intraComm;
320       interCommClient = interComm;
321     }
322     else
323     {
324       MPI_Comm_dup(intraComm, &intraCommClient);
325       comms.push_back(intraCommClient);
326       MPI_Comm_dup(interComm, &interCommClient);
327       comms.push_back(interCommClient);
328     }
329     client = new CContextClient(this,intraCommClient,interCommClient, cxtClient);
330   }
331
332   //! Server side: Put server into a loop in order to listen message from client
333   bool CContext::eventLoop(void)
334   {
335     return server->eventLoop();
336   }
337
338   //! Try to send the buffers and receive possible answers
339   bool CContext::checkBuffersAndListen(void)
340   {
341     client->checkBuffers();
342     return server->eventLoop();
343   }
344
345   //! Terminate a context
346   void CContext::finalize(void)
347   {
348      if (!finalized)
349      {
350        finalized = true;
351        if (hasClient) sendRegistry() ;
352        client->finalize();
353        while (!server->hasFinished())
354        {
355          server->eventLoop();
356        }
357
358        if (hasServer)
359        {
360          closeAllFile();
361          registryOut->hierarchicalGatherRegistry() ;
362          if (server->intraCommRank==0) CXios::globalRegistry->mergeRegistry(*registryOut) ;
363        }
364       
365        for (std::list<MPI_Comm>::iterator it = comms.begin(); it != comms.end(); ++it)
366          MPI_Comm_free(&(*it));
367        comms.clear();
368      }
369   }
370
371   /*!
372   \brief Close all the context defintion and do processing data
373      After everything is well defined on client side, they will be processed and sent to server
374   From the version 2.0, sever and client work no more on the same database. Moreover, client(s) will send
375   all necessary information to server, from which each server can build its own database.
376   Because the role of server is to write out field data on a specific netcdf file,
377   the only information that it needs is the enabled files
378   and the active fields (fields will be written onto active files)
379   */
380   void CContext::closeDefinition(void)
381   {
382     // There is nothing client need to send to server
383     if (hasClient)
384     {
385       // After xml is parsed, there are some more works with post processing
386       postProcessing();
387     }
388     setClientServerBuffer();
389
390     if (hasClient && !hasServer)
391     {
392      // Send all attributes of current context to server
393      this->sendAllAttributesToServer();
394
395      // Send all attributes of current calendar
396      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->sendAllAttributesToServer();
397
398      // We have enough information to send to server
399      // First of all, send all enabled files
400       sendEnabledFiles();
401
402      // Then, send all enabled fields
403       sendEnabledFields();
404
405      // At last, we have all info of domain and axis, then send them
406       sendRefDomainsAxis();
407
408      // After that, send all grid (if any)
409       sendRefGrid();
410    }
411
412    // We have a xml tree on the server side and now, it should be also processed
413    if (hasClient && !hasServer) sendPostProcessing();
414
415    // There are some processings that should be done after all of above. For example: check mask or index
416    if (hasClient)
417    {
418      this->buildFilterGraphOfEnabledFields();
419      buildFilterGraphOfFieldsWithReadAccess();
420      this->solveAllRefOfEnabledFields(true);
421    }
422
423    // Now tell server that it can process all messages from client
424    if (hasClient && !hasServer) this->sendCloseDefinition();
425
426    // Nettoyage de l'arborescence
427    if (hasClient && !hasServer) CleanTree(); // Only on client side??
428
429    if (hasClient)
430    {
431      sendCreateFileHeader();
432
433      startPrefetchingOfEnabledReadModeFiles();
434    }
435   }
436
437   void CContext::findAllEnabledFields(void)
438   {
439     for (unsigned int i = 0; i < this->enabledFiles.size(); i++)
440     (void)this->enabledFiles[i]->getEnabledFields();
441   }
442
443   void CContext::solveAllRefOfEnabledFields(bool sendToServer)
444   {
445     int size = this->enabledFiles.size();
446     for (int i = 0; i < size; ++i)
447     {
448       this->enabledFiles[i]->solveAllRefOfEnabledFields(sendToServer);
449     }
450   }
451
452   void CContext::buildFilterGraphOfEnabledFields()
453   {
454     int size = this->enabledFiles.size();
455     for (int i = 0; i < size; ++i)
456     {
457       this->enabledFiles[i]->buildFilterGraphOfEnabledFields(garbageCollector);
458     }
459   }
460
461   void CContext::startPrefetchingOfEnabledReadModeFiles()
462   {
463     int size = enabledReadModeFiles.size();
464     for (int i = 0; i < size; ++i)
465     {
466        enabledReadModeFiles[i]->prefetchEnabledReadModeFields();
467     }
468   }
469
470   void CContext::checkPrefetchingOfEnabledReadModeFiles()
471   {
472     int size = enabledReadModeFiles.size();
473     for (int i = 0; i < size; ++i)
474     {
475        enabledReadModeFiles[i]->prefetchEnabledReadModeFieldsIfNeeded();
476     }
477   }
478
479  void CContext::findFieldsWithReadAccess(void)
480  {
481    fieldsWithReadAccess.clear();
482    const vector<CField*> allFields = CField::getAll();
483    for (size_t i = 0; i < allFields.size(); ++i)
484    {
485      CField* field = allFields[i];
486
487      if (field->file && !field->file->mode.isEmpty() && field->file->mode == CFile::mode_attr::read)
488        field->read_access = true;
489      else if (!field->read_access.isEmpty() && field->read_access && (field->enabled.isEmpty() || field->enabled))
490        fieldsWithReadAccess.push_back(field);
491    }
492  }
493
494  void CContext::solveAllRefOfFieldsWithReadAccess()
495  {
496    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
497      fieldsWithReadAccess[i]->solveAllReferenceEnabledField(false);
498  }
499
500  void CContext::buildFilterGraphOfFieldsWithReadAccess()
501  {
502    for (size_t i = 0; i < fieldsWithReadAccess.size(); ++i)
503      fieldsWithReadAccess[i]->buildFilterGraph(garbageCollector, true);
504  }
505
506   void CContext::solveAllInheritance(bool apply)
507   {
508     // Résolution des héritages descendants (càd des héritages de groupes)
509     // pour chacun des contextes.
510      solveDescInheritance(apply);
511
512     // Résolution des héritages par référence au niveau des fichiers.
513      const vector<CFile*> allFiles=CFile::getAll();
514      const vector<CGrid*> allGrids= CGrid::getAll();
515
516     //if (hasClient && !hasServer)
517      if (hasClient)
518      {
519        for (unsigned int i = 0; i < allFiles.size(); i++)
520          allFiles[i]->solveFieldRefInheritance(apply);
521      }
522
523      unsigned int vecSize = allGrids.size();
524      unsigned int i = 0;
525      for (i = 0; i < vecSize; ++i)
526        allGrids[i]->solveDomainAxisRefInheritance(apply);
527
528   }
529
530   void CContext::findEnabledFiles(void)
531   {
532      const std::vector<CFile*> allFiles = CFile::getAll();
533
534      for (unsigned int i = 0; i < allFiles.size(); i++)
535         if (!allFiles[i]->enabled.isEmpty()) // Si l'attribut 'enabled' est défini.
536         {
537            if (allFiles[i]->enabled.getValue()) // Si l'attribut 'enabled' est fixé à vrai.
538               enabledFiles.push_back(allFiles[i]);
539         }
540         else enabledFiles.push_back(allFiles[i]); // otherwise true by default
541
542
543      if (enabledFiles.size() == 0)
544         DEBUG(<<"Aucun fichier ne va être sorti dans le contexte nommé \""
545               << getId() << "\" !");
546   }
547
548   void CContext::findEnabledReadModeFiles(void)
549   {
550     int size = this->enabledFiles.size();
551     for (int i = 0; i < size; ++i)
552     {
553       if (!enabledFiles[i]->mode.isEmpty() && enabledFiles[i]->mode.getValue() == CFile::mode_attr::read)
554        enabledReadModeFiles.push_back(enabledFiles[i]);
555     }
556   }
557
558   void CContext::closeAllFile(void)
559   {
560     std::vector<CFile*>::const_iterator
561            it = this->enabledFiles.begin(), end = this->enabledFiles.end();
562
563     for (; it != end; it++)
564     {
565       info(30)<<"Closing File : "<<(*it)->getId()<<endl;
566       (*it)->close();
567     }
568   }
569
570   /*!
571   \brief Dispatch event received from client
572      Whenever a message is received in buffer of server, it will be processed depending on
573   its event type. A new event type should be added in the switch list to make sure
574   it processed on server side.
575   \param [in] event: Received message
576   */
577   bool CContext::dispatchEvent(CEventServer& event)
578   {
579
580      if (SuperClass::dispatchEvent(event)) return true;
581      else
582      {
583        switch(event.type)
584        {
585           case EVENT_ID_CLOSE_DEFINITION :
586             recvCloseDefinition(event);
587             return true;
588             break;
589           case EVENT_ID_UPDATE_CALENDAR:
590             recvUpdateCalendar(event);
591             return true;
592             break;
593           case EVENT_ID_CREATE_FILE_HEADER :
594             recvCreateFileHeader(event);
595             return true;
596             break;
597           case EVENT_ID_POST_PROCESS:
598             recvPostProcessing(event);
599             return true;
600            case EVENT_ID_SEND_REGISTRY:
601             recvRegistry(event);
602             return true;
603            break;
604
605           default :
606             ERROR("bool CContext::dispatchEvent(CEventServer& event)",
607                    <<"Unknown Event");
608           return false;
609         }
610      }
611   }
612
613   //! Client side: Send a message to server to make it close
614   void CContext::sendCloseDefinition(void)
615   {
616     CEventClient event(getType(),EVENT_ID_CLOSE_DEFINITION);
617     if (client->isServerLeader())
618     {
619       CMessage msg;
620       msg<<this->getIdServer();
621       const std::list<int>& ranks = client->getRanksServerLeader();
622       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
623         event.push(*itRank,1,msg);
624       client->sendEvent(event);
625     }
626     else client->sendEvent(event);
627   }
628
629   //! Server side: Receive a message of client announcing a context close
630   void CContext::recvCloseDefinition(CEventServer& event)
631   {
632
633      CBufferIn* buffer=event.subEvents.begin()->buffer;
634      string id;
635      *buffer>>id;
636      get(id)->closeDefinition();
637   }
638
639   //! Client side: Send a message to update calendar in each time step
640   void CContext::sendUpdateCalendar(int step)
641   {
642     if (!hasServer)
643     {
644       CEventClient event(getType(),EVENT_ID_UPDATE_CALENDAR);
645       if (client->isServerLeader())
646       {
647         CMessage msg;
648         msg<<this->getIdServer()<<step;
649         const std::list<int>& ranks = client->getRanksServerLeader();
650         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
651           event.push(*itRank,1,msg);
652         client->sendEvent(event);
653       }
654       else client->sendEvent(event);
655     }
656   }
657
658   //! Server side: Receive a message of client annoucing calendar update
659   void CContext::recvUpdateCalendar(CEventServer& event)
660   {
661      CBufferIn* buffer=event.subEvents.begin()->buffer;
662      string id;
663      *buffer>>id;
664      get(id)->recvUpdateCalendar(*buffer);
665   }
666
667   //! Server side: Receive a message of client annoucing calendar update
668   void CContext::recvUpdateCalendar(CBufferIn& buffer)
669   {
670      int step;
671      buffer>>step;
672      updateCalendar(step);
673   }
674
675   //! Client side: Send a message to create header part of netcdf file
676   void CContext::sendCreateFileHeader(void)
677   {
678     CEventClient event(getType(),EVENT_ID_CREATE_FILE_HEADER);
679     if (client->isServerLeader())
680     {
681       CMessage msg;
682       msg<<this->getIdServer();
683       const std::list<int>& ranks = client->getRanksServerLeader();
684       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
685         event.push(*itRank,1,msg) ;
686       client->sendEvent(event);
687     }
688     else client->sendEvent(event);
689   }
690
691   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
692   void CContext::recvCreateFileHeader(CEventServer& event)
693   {
694      CBufferIn* buffer=event.subEvents.begin()->buffer;
695      string id;
696      *buffer>>id;
697      get(id)->recvCreateFileHeader(*buffer);
698   }
699
700   //! Server side: Receive a message of client annoucing the creation of header part of netcdf file
701   void CContext::recvCreateFileHeader(CBufferIn& buffer)
702   {
703      createFileHeader();
704   }
705
706   //! Client side: Send a message to do some post processing on server
707   void CContext::sendPostProcessing()
708   {
709     if (!hasServer)
710     {
711       CEventClient event(getType(),EVENT_ID_POST_PROCESS);
712       if (client->isServerLeader())
713       {
714         CMessage msg;
715         msg<<this->getIdServer();
716         const std::list<int>& ranks = client->getRanksServerLeader();
717         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
718           event.push(*itRank,1,msg);
719         client->sendEvent(event);
720       }
721       else client->sendEvent(event);
722     }
723   }
724
725   //! Server side: Receive a message to do some post processing
726   void CContext::recvPostProcessing(CEventServer& event)
727   {
728      CBufferIn* buffer=event.subEvents.begin()->buffer;
729      string id;
730      *buffer>>id;
731      get(id)->recvPostProcessing(*buffer);
732   }
733
734   //! Server side: Receive a message to do some post processing
735   void CContext::recvPostProcessing(CBufferIn& buffer)
736   {
737      CCalendarWrapper::get(CCalendarWrapper::GetDefName())->createCalendar();
738      postProcessing();
739   }
740
741   const StdString& CContext::getIdServer()
742   {
743      if (hasClient)
744      {
745        idServer_ = this->getId();
746        idServer_ += "_server";
747        return idServer_;
748      }
749      if (hasServer) return (this->getId());
750   }
751
752   /*!
753   \brief Do some simple post processings after parsing xml file
754      After the xml file (iodef.xml) is parsed, it is necessary to build all relations among
755   created object, e.g: inhertance among fields, domain, axis. After that, all fiels as well as their parents (reference fields),
756   which will be written out into netcdf files, are processed
757   */
758   void CContext::postProcessing()
759   {
760     if (isPostProcessed) return;
761
762      // Make sure the calendar was correctly created
763      if (!calendar)
764        ERROR("CContext::postProcessing()", << "A calendar must be defined for the context \"" << getId() << "!\"")
765      else if (calendar->getTimeStep() == NoneDu)
766        ERROR("CContext::postProcessing()", << "A timestep must be defined for the context \"" << getId() << "!\"")
767      // Calendar first update to set the current date equals to the start date
768      calendar->update(0);
769
770      // Find all inheritance in xml structure
771      this->solveAllInheritance();
772
773      // Check if some axis, domains or grids are eligible to for compressed indexed output.
774      // Warning: This must be done after solving the inheritance and before the rest of post-processing
775      checkAxisDomainsGridsEligibilityForCompressedOutput();
776
777      // Check if some automatic time series should be generated
778      // Warning: This must be done after solving the inheritance and before the rest of post-processing
779      prepareTimeseries();
780
781      //Initialisation du vecteur 'enabledFiles' contenant la liste des fichiers à sortir.
782      this->findEnabledFiles();
783      this->findEnabledReadModeFiles();
784
785      // Find all enabled fields of each file
786      this->findAllEnabledFields();
787
788      // Search and rebuild all reference object of enabled fields
789      this->solveAllRefOfEnabledFields(false);
790
791      // Find all fields with read access from the public API
792      findFieldsWithReadAccess();
793      // and solve the all reference for them
794      solveAllRefOfFieldsWithReadAccess();
795
796      isPostProcessed = true;
797   }
798
799   std::map<int, StdSize> CContext::getAttributesBufferSize()
800   {
801     std::map<int, StdSize> attributesSize;
802
803     size_t numEnabledFiles = this->enabledFiles.size();
804     for (size_t i = 0; i < numEnabledFiles; ++i)
805     {
806       CFile* file = this->enabledFiles[i];
807
808       std::vector<CField*> enabledFields = file->getEnabledFields();
809       size_t numEnabledFields = enabledFields.size();
810       for (size_t j = 0; j < numEnabledFields; ++j)
811       {
812         const std::map<int, StdSize> mapSize = enabledFields[j]->getGridAttributesBufferSize();
813         std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
814         for (; it != itE; ++it)
815         {
816           // If attributesSize[it->first] does not exist, it will be zero-initialized
817           // so we can use it safely without checking for its existance
818           if (attributesSize[it->first] < it->second)
819             attributesSize[it->first] = it->second;
820         }
821       }
822     }
823
824     return attributesSize;
825   }
826
827   std::map<int, StdSize> CContext::getDataBufferSize()
828   {
829     CFile::mode_attr::t_enum mode = hasClient ? CFile::mode_attr::write : CFile::mode_attr::read;
830
831     std::map<int, StdSize> dataSize;
832
833     // Find all reference domain and axis of all active fields
834     size_t numEnabledFiles = this->enabledFiles.size();
835     for (size_t i = 0; i < numEnabledFiles; ++i)
836     {
837       CFile* file = this->enabledFiles[i];
838       CFile::mode_attr::t_enum fileMode = file->mode.isEmpty() ? CFile::mode_attr::write : file->mode.getValue();
839
840       if (fileMode == mode)
841       {
842         std::vector<CField*> enabledFields = file->getEnabledFields();
843         size_t numEnabledFields = enabledFields.size();
844         for (size_t j = 0; j < numEnabledFields; ++j)
845         {
846           const std::map<int, StdSize> mapSize = enabledFields[j]->getGridDataBufferSize();
847           std::map<int, StdSize>::const_iterator it = mapSize.begin(), itE = mapSize.end();
848           for (; it != itE; ++it)
849           {
850             // If dataSize[it->first] does not exist, it will be zero-initialized
851             // so we can use it safely without checking for its existance
852             if (CXios::isOptPerformance)
853               dataSize[it->first] += it->second;
854             else if (dataSize[it->first] < it->second)
855               dataSize[it->first] = it->second;
856           }
857         }
858       }
859     }
860
861     return dataSize;
862   }
863
864   //! Client side: Send infomation of active files (files are enabled to write out)
865   void CContext::sendEnabledFiles()
866   {
867     int size = this->enabledFiles.size();
868
869     // In a context, each type has a root definition, e.g: axis, domain, field.
870     // Every object must be a child of one of these root definition. In this case
871     // all new file objects created on server must be children of the root "file_definition"
872     StdString fileDefRoot("file_definition");
873     CFileGroup* cfgrpPtr = CFileGroup::get(fileDefRoot);
874
875     for (int i = 0; i < size; ++i)
876     {
877       cfgrpPtr->sendCreateChild(this->enabledFiles[i]->getId());
878       this->enabledFiles[i]->sendAllAttributesToServer();
879       this->enabledFiles[i]->sendAddAllVariables();
880     }
881   }
882
883   //! Client side: Send information of active fields (ones are written onto files)
884   void CContext::sendEnabledFields()
885   {
886     int size = this->enabledFiles.size();
887     for (int i = 0; i < size; ++i)
888     {
889       this->enabledFiles[i]->sendEnabledFields();
890     }
891   }
892
893   //! Client side: Check if the defined axis, domains and grids are eligible for compressed indexed output
894   void CContext::checkAxisDomainsGridsEligibilityForCompressedOutput()
895   {
896     if (!hasClient) return;
897
898     const vector<CAxis*> allAxis = CAxis::getAll();
899     for (vector<CAxis*>::const_iterator it = allAxis.begin(); it != allAxis.end(); it++)
900       (*it)->checkEligibilityForCompressedOutput();
901
902     const vector<CDomain*> allDomains = CDomain::getAll();
903     for (vector<CDomain*>::const_iterator it = allDomains.begin(); it != allDomains.end(); it++)
904       (*it)->checkEligibilityForCompressedOutput();
905
906     const vector<CGrid*> allGrids = CGrid::getAll();
907     for (vector<CGrid*>::const_iterator it = allGrids.begin(); it != allGrids.end(); it++)
908       (*it)->checkEligibilityForCompressedOutput();
909   }
910
911   //! Client side: Prepare the timeseries by adding the necessary files
912   void CContext::prepareTimeseries()
913   {
914     if (!hasClient) return;
915
916     const std::vector<CFile*> allFiles = CFile::getAll();
917     for (size_t i = 0; i < allFiles.size(); i++)
918     {
919       CFile* file = allFiles[i];
920
921       if (!file->timeseries.isEmpty() && file->timeseries != CFile::timeseries_attr::none)
922       {
923         StdString tsPrefix = !file->ts_prefix.isEmpty() ? file->ts_prefix : file->getFileOutputName();
924
925         const std::vector<CField*> allFields = file->getAllFields();
926         for (size_t j = 0; j < allFields.size(); j++)
927         {
928           CField* field = allFields[j];
929
930           if (!field->ts_enabled.isEmpty() && field->ts_enabled)
931           {
932             CFile* tsFile = CFile::create();
933             tsFile->duplicateAttributes(file);
934
935             tsFile->name = tsPrefix + "_";
936             if (!field->name.isEmpty())
937               tsFile->name.get() += field->name;
938             else if (field->hasDirectFieldReference()) // We cannot use getBaseFieldReference() just yet
939               tsFile->name.get() += field->field_ref;
940             else
941               tsFile->name.get() += field->getId();
942
943             if (!field->ts_split_freq.isEmpty())
944               tsFile->split_freq = field->ts_split_freq;
945
946             CField* tsField = tsFile->addField();
947             tsField->field_ref = field->getId();
948
949             tsFile->solveFieldRefInheritance(true);
950
951             if (file->timeseries == CFile::timeseries_attr::exclusive)
952               field->enabled = false;
953           }
954         }
955
956         // Finally disable the original file is need be
957         if (file->timeseries == CFile::timeseries_attr::only)
958          file->enabled = false;
959       }
960     }
961   }
962
963   //! Client side: Send information of reference grid of active fields
964   void CContext::sendRefGrid()
965   {
966     std::set<StdString> gridIds;
967     int sizeFile = this->enabledFiles.size();
968     CFile* filePtr(NULL);
969
970     // Firstly, find all reference grids of all active fields
971     for (int i = 0; i < sizeFile; ++i)
972     {
973       filePtr = this->enabledFiles[i];
974       std::vector<CField*> enabledFields = filePtr->getEnabledFields();
975       int sizeField = enabledFields.size();
976       for (int numField = 0; numField < sizeField; ++numField)
977       {
978         if (0 != enabledFields[numField]->getRelGrid())
979           gridIds.insert(CGrid::get(enabledFields[numField]->getRelGrid())->getId());
980       }
981     }
982
983     // Create all reference grids on server side
984     StdString gridDefRoot("grid_definition");
985     CGridGroup* gridPtr = CGridGroup::get(gridDefRoot);
986     std::set<StdString>::const_iterator it, itE = gridIds.end();
987     for (it = gridIds.begin(); it != itE; ++it)
988     {
989       gridPtr->sendCreateChild(*it);
990       CGrid::get(*it)->sendAllAttributesToServer();
991       CGrid::get(*it)->sendAllDomains();
992       CGrid::get(*it)->sendAllAxis();
993     }
994   }
995
996
997   //! Client side: Send information of reference domain and axis of active fields
998   void CContext::sendRefDomainsAxis()
999   {
1000     std::set<StdString> domainIds;
1001     std::set<StdString> axisIds;
1002
1003     // Find all reference domain and axis of all active fields
1004     int numEnabledFiles = this->enabledFiles.size();
1005     for (int i = 0; i < numEnabledFiles; ++i)
1006     {
1007       std::vector<CField*> enabledFields = this->enabledFiles[i]->getEnabledFields();
1008       int numEnabledFields = enabledFields.size();
1009       for (int j = 0; j < numEnabledFields; ++j)
1010       {
1011         const std::pair<StdString, StdString>& prDomAxisId = enabledFields[j]->getRefDomainAxisIds();
1012         if ("" != prDomAxisId.first) domainIds.insert(prDomAxisId.first);
1013         if ("" != prDomAxisId.second) axisIds.insert(prDomAxisId.second);
1014       }
1015     }
1016
1017     // Create all reference axis on server side
1018     std::set<StdString>::iterator itDom, itAxis;
1019     std::set<StdString>::const_iterator itE;
1020
1021     StdString axiDefRoot("axis_definition");
1022     CAxisGroup* axisPtr = CAxisGroup::get(axiDefRoot);
1023     itE = axisIds.end();
1024     for (itAxis = axisIds.begin(); itAxis != itE; ++itAxis)
1025     {
1026       if (!itAxis->empty())
1027       {
1028         axisPtr->sendCreateChild(*itAxis);
1029         CAxis::get(*itAxis)->sendAllAttributesToServer();
1030       }
1031     }
1032
1033     // Create all reference domains on server side
1034     StdString domDefRoot("domain_definition");
1035     CDomainGroup* domPtr = CDomainGroup::get(domDefRoot);
1036     itE = domainIds.end();
1037     for (itDom = domainIds.begin(); itDom != itE; ++itDom)
1038     {
1039       if (!itDom->empty()) {
1040          domPtr->sendCreateChild(*itDom);
1041          CDomain::get(*itDom)->sendAllAttributesToServer();
1042       }
1043     }
1044   }
1045
1046   //! Update calendar in each time step
1047   void CContext::updateCalendar(int step)
1048   {
1049      info(50) << "updateCalendar : before : " << calendar->getCurrentDate() << endl;
1050      calendar->update(step);
1051      info(50) << "updateCalendar : after : " << calendar->getCurrentDate() << endl;
1052
1053      if (hasClient)
1054      {
1055        checkPrefetchingOfEnabledReadModeFiles();
1056        garbageCollector.invalidate(calendar->getCurrentDate());
1057      }
1058   }
1059
1060   //! Server side: Create header of netcdf file
1061   void CContext::createFileHeader(void )
1062   {
1063      vector<CFile*>::const_iterator it;
1064
1065      for (it=enabledFiles.begin(); it != enabledFiles.end(); it++)
1066      {
1067         (*it)->initFile();
1068      }
1069   }
1070
1071   //! Get current context
1072   CContext* CContext::getCurrent(void)
1073   {
1074     return CObjectFactory::GetObject<CContext>(CObjectFactory::GetCurrentContextId()).get();
1075   }
1076
1077   /*!
1078   \brief Set context with an id be the current context
1079   \param [in] id identity of context to be set to current
1080   */
1081   void CContext::setCurrent(const string& id)
1082   {
1083     CObjectFactory::SetCurrentContextId(id);
1084     CGroupFactory::SetCurrentContextId(id);
1085   }
1086
1087  /*!
1088  \brief Create a context with specific id
1089  \param [in] id identity of new context
1090  \return pointer to the new context or already-existed one with identity id
1091  */
1092  CContext* CContext::create(const StdString& id)
1093  {
1094    CContext::setCurrent(id);
1095
1096    bool hasctxt = CContext::has(id);
1097    CContext* context = CObjectFactory::CreateObject<CContext>(id).get();
1098    getRoot();
1099    if (!hasctxt) CGroupFactory::AddChild(root, context->getShared());
1100
1101#define DECLARE_NODE(Name_, name_) \
1102    C##Name_##Definition::create(C##Name_##Definition::GetDefName());
1103#define DECLARE_NODE_PAR(Name_, name_)
1104#include "node_type.conf"
1105
1106    return (context);
1107  }
1108
1109
1110
1111     //! Server side: Receive a message to do some post processing
1112  void CContext::recvRegistry(CEventServer& event)
1113  {
1114    CBufferIn* buffer=event.subEvents.begin()->buffer;
1115    string id;
1116    *buffer>>id;
1117    get(id)->recvRegistry(*buffer);
1118  }
1119
1120  void CContext::recvRegistry(CBufferIn& buffer)
1121  {
1122    if (server->intraCommRank==0)
1123    {
1124      CRegistry registry(server->intraComm) ;
1125      registry.fromBuffer(buffer) ;
1126      registryOut->mergeRegistry(registry) ;
1127    }
1128  }
1129
1130  void CContext::sendRegistry(void)
1131  {
1132    registryOut->hierarchicalGatherRegistry() ;
1133
1134    CEventClient event(CContext::GetType(), CContext::EVENT_ID_SEND_REGISTRY);
1135    if (client->isServerLeader())
1136    {
1137       CMessage msg ;
1138       msg<<this->getIdServer();
1139       if (client->clientRank==0) msg<<*registryOut ;
1140       const std::list<int>& ranks = client->getRanksServerLeader();
1141       for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1142         event.push(*itRank,1,msg);
1143       client->sendEvent(event);
1144     }
1145     else client->sendEvent(event);
1146  }
1147
1148} // namespace xios
Note: See TracBrowser for help on using the repository browser.