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

Last change on this file since 681 was 676, checked in by rlacroix, 9 years ago

Add support for indexed output.

If the new field attribute "indexed_output" is set to true and a mask is defined (either at grid, domain or axis level), the indexed data will be outputed instead of the full data with missing values.

See http://cfconventions.org/Data/cf-conventions/cf-conventions-1.5/build/cf-conventions.html#compression-by-gathering for more information.

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