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

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

Add a new user defined calendar type.

A new calendar type "user_defined" is now available. This allows the users to create a custom calendar that we can configured to be suitable for planets other than the Earth.

An user defined calendar is always defined by two mandatory attributes:

  • day_length: the duration of a day, in seconds
  • and either:
    • month_length: an array containing the duration of each month, in days (the number of elements in the array is the number of months in a year)
    • or year_length: the duration of a year, in seconds (in that case, the calendar does not have months).

If the calendar has months (i.e. month_length attribute is set) and only in that case, it is possible to define leap years in order to compensate for the duration of an astronomical year not being a multiple of the day length. The leap years are defined by two mandatory attributes:

  • leap_year_month: the month to which the extra day will be added in case of leap year, expressed as an integer number in the range [1, numberOfMonths]
  • and leap_year_drift: the fraction of a day representing the yearly drift between the calendar year and the astronomical year, expressed as a real number in the range [0, 1).

Optionally, one can define the leap_year_drift_offset attribute to set the original drift at the beginning of the time origin's year, again expressed as a real number in the range [0, 1). If leap_year_drift_offset + leap_year_drift is greater or equal to 1, then the first year will be a leap year.

For example, the following configuration creates a Gregorian-like calendar:

<calendar type="user_defined" start_date="2012-03-01 15:00:00" time_origin="2012-02-28 15:00:00 + 1d" day_length="86400" month_lengths="(1, 12) [31 28 31 30 31 30 31 31 30 31 30 31]" leap_year_month="2" leap_year_drift="0.25" leap_year_drift_offset="0.75" />

Note that dates attributes must be written differently in the configuration file when using an user defined calendar without months:

  • if the year length is greater than the day length, the input format is year-day hh:min:sec instead of year-month-day hh:min:sec
  • if the day length is greater or equal to the year length, the input format is year hh:min:sec.

In all cases, it is still possible to use the date + duration notation to build a date (with both the date and duration parts being optional).

The Fortran interface has been updated accordingly so that xios_define_calendar can accept the new attributes necessary to define custom calendars.

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