source: XIOS/trunk/src/node/file.cpp @ 1046

Last change on this file since 1046 was 1046, checked in by ymipsl, 7 years ago
  • Add 2 new file attributes to parameter timestamp : time_stamp_name and time_stamp_format.

Default value :
time_stamp_name="timestamp"
time_stamp_format="%Y-%b-%d %H:%M:%S %Z"

  • timestamp is now given in UTC time

YM

  • 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: 36.3 KB
Line 
1#include "file.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "object_factory.hpp"
7#include "context.hpp"
8#include "context_server.hpp"
9#include "nc4_data_output.hpp"
10#include "nc4_data_input.hpp"
11#include "calendar_util.hpp"
12#include "date.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "context_client.hpp"
17#include "mpi.hpp"
18
19namespace xios {
20
21   /// ////////////////////// Dfinitions ////////////////////// ///
22
23   CFile::CFile(void)
24      : CObjectTemplate<CFile>(), CFileAttributes()
25      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
26      , allDomainEmpty(false), isOpen(false)
27   {
28     setVirtualFieldGroup(CFieldGroup::create(getId() + "_virtual_field_group"));
29     setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group"));
30   }
31
32   CFile::CFile(const StdString & id)
33      : CObjectTemplate<CFile>(id), CFileAttributes()
34      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
35      , allDomainEmpty(false), isOpen(false)
36    {
37      setVirtualFieldGroup(CFieldGroup::create(getId() + "_virtual_field_group"));
38      setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group"));
39    }
40
41   CFile::~CFile(void)
42   { /* Ne rien faire de plus */ }
43
44   ///---------------------------------------------------------------
45  //! Get name of file
46   StdString CFile::GetName(void)   { return (StdString("file")); }
47   StdString CFile::GetDefName(void){ return (CFile::GetName()); }
48   ENodeType CFile::GetType(void)   { return (eFile); }
49
50   //----------------------------------------------------------------
51
52   const StdString& CFile::getFileOutputName(void) const
53   {
54     return name.isEmpty() ? getId() : name;
55   }
56
57   //----------------------------------------------------------------
58   /*!
59   \brief Get data writer object.
60   Each enabled file in xml represents a physical netcdf file.
61   This function allows to access the data writer object.
62   \return data writer object.
63   */
64   boost::shared_ptr<CDataOutput> CFile::getDataOutput(void) const
65   {
66      return data_out;
67   }
68
69   /*!
70   \brief Get data reader object.
71   Each enabled file in xml represents a physical netcdf file.
72   This function allows to access the data reader object.
73   \return data reader object.
74   */
75   boost::shared_ptr<CDataInput> CFile::getDataInput(void) const
76   {
77      return data_in;
78   }
79
80   /*!
81   \brief Get virtual field group
82      In each file, there always exists a field group which is the ancestor of all
83   fields in the file. This is considered be virtual because it is created automatically during
84   file initialization and it normally doesn't appear on xml file
85   \return Pointer to field group
86   */
87   CFieldGroup* CFile::getVirtualFieldGroup(void) const
88   {
89      return (this->vFieldGroup);
90   }
91
92   /*!
93   \brief Get virtual variable group
94      In each file, there always exists a variable group which is the ancestor of all
95   variable in the file. This is considered be virtual because it is created automatically during
96   file initialization and it normally doesn't appear on xml file
97   \return Pointer to variable group
98   */
99   CVariableGroup* CFile::getVirtualVariableGroup(void) const
100   {
101      return (this->vVariableGroup);
102   }
103
104   //! Get all fields of a file
105   std::vector<CField*> CFile::getAllFields(void) const
106   {
107      return (this->vFieldGroup->getAllChildren());
108   }
109
110   //! Get all variables of a file
111   std::vector<CVariable*> CFile::getAllVariables(void) const
112   {
113      return (this->vVariableGroup->getAllChildren());
114   }
115
116   //----------------------------------------------------------------
117   /*!
118   \brief Get all enabled fields of file
119      A field is considered to be enabled if it fullfil these conditions: it is enabled, inside a enabled file
120   and its own level is not larger than file output level.
121   \param [in] default_outputlevel default value output level of file
122   \param [in] default_level default value level of field
123   \param [in] default_enabled flag determine by default if field is enabled
124   \return Vector of pointers of enabled fields
125   */
126   std::vector<CField*> CFile::getEnabledFields(int default_outputlevel,
127                                                int default_level,
128                                                bool default_enabled)
129   {
130      if (!this->enabledFields.empty())
131         return (this->enabledFields);
132
133      const int _outputlevel =
134         (!output_level.isEmpty()) ? output_level.getValue() : default_outputlevel;
135      std::vector<CField*>::iterator it;
136      this->enabledFields = this->getAllFields();
137
138      std::vector<CField*> newEnabledFields;
139
140      for ( it = this->enabledFields.begin(); it != this->enabledFields.end(); it++ )
141      {
142         if (!(*it)->enabled.isEmpty()) // Si l'attribut 'enabled' est dfini ...
143         {
144            if (! (*it)->enabled.getValue()) continue;
145//            { it--; this->enabledFields.erase(it+1); continue; }
146         }
147         else // Si l'attribut 'enabled' n'est pas dfini ...
148         {
149            if (!default_enabled) continue;
150//            { it--; this->enabledFields.erase(it+1); continue; }
151         }
152
153         if (!(*it)->level.isEmpty()) // Si l'attribut 'level' est dfini ...
154         {
155            if ((*it)->level.getValue() > _outputlevel) continue;
156//            { it--; this->enabledFields.erase(it+1); continue; }
157         }
158         else // Si l'attribut 'level' n'est pas dfini ...
159         {
160            if (default_level > _outputlevel) continue;
161//            { it--; this->enabledFields.erase(it+1); continue; }
162         }
163
164//         CField* field_tmp=(*it).get();
165//         shared_ptr<CField> sptfield=*it;
166//         field_tmp->refObject.push_back(sptfield);
167         newEnabledFields.push_back(*it);
168         // Le champ est finalement actif, on y ajoute sa propre reference.
169//         (*it)->refObject.push_back(*it);
170         // Le champ est finalement actif, on y ajoute la rfrence au champ de base.
171         (*it)->setRelFile(CFile::get(this));
172      }
173      enabledFields = newEnabledFields;
174
175      return (this->enabledFields);
176   }
177
178   //----------------------------------------------------------------
179   //! Change virtual field group to a new one
180   void CFile::setVirtualFieldGroup(CFieldGroup* newVFieldGroup)
181   {
182      this->vFieldGroup = newVFieldGroup;
183   }
184
185   //! Change virtual variable group to new one
186   void CFile::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
187   {
188      this->vVariableGroup = newVVariableGroup;
189   }
190
191   //----------------------------------------------------------------
192   bool CFile::isSyncTime(void)
193   {
194     CContext* context = CContext::getCurrent();
195     const CDate& currentDate = context->calendar->getCurrentDate();
196     if (!sync_freq.isEmpty())
197     {
198       if (lastSync + sync_freq.getValue() < currentDate)
199       {
200         lastSync = currentDate;
201         return true;
202        }
203      }
204      return false;
205    }
206
207   //! Initialize a file in order to write into it
208   void CFile::initFile(void)
209   {
210      CContext* context = CContext::getCurrent();
211      const CDate& currentDate = context->calendar->getCurrentDate();
212      CContextServer* server = context->server;
213
214      lastSync  = currentDate;
215      lastSplit = currentDate;
216      if (!split_freq.isEmpty())
217      {
218        if (context->registryIn->foundKey("splitStart") && context->registryIn->foundKey("splitEnd"))
219        {
220          CDate savedSplitStart(*context->getCalendar()), savedSplitEnd(*context->getCalendar());
221          context->registryIn->getKey("splitStart", savedSplitStart);
222          context->registryIn->getKey("splitEnd",   savedSplitEnd);
223
224          if (savedSplitStart <= lastSplit && lastSplit <= savedSplitEnd)
225            lastSplit = savedSplitStart;
226        }
227      }
228      isOpen = false;
229
230      allDomainEmpty = true;
231
232//      if (!record_offset.isEmpty() && record_offset < 0)
233//        ERROR("void CFile::initFile(void)",
234//              "Invalid 'record_offset', this attribute cannot be negative.");
235      const int recordOffset = record_offset.isEmpty() ? 0 : record_offset;
236
237      // set<CAxis*> setAxis;
238      // set<CDomain*> setDomains;
239      set<StdString> setAxis;
240      set<StdString> setDomains;
241     
242      std::vector<CField*>::iterator it, end = this->enabledFields.end();
243      for (it = this->enabledFields.begin(); it != end; it++)
244      {
245         CField* field = *it;
246         allDomainEmpty &= !field->grid->doGridHaveDataToWrite();
247         std::vector<CAxis*> vecAxis = field->grid->getAxis();
248         for (size_t i = 0; i < vecAxis.size(); ++i)
249            setAxis.insert(vecAxis[i]->getAxisOutputName());
250            // setAxis.insert(vecAxis[i]);
251         std::vector<CDomain*> vecDomains = field->grid->getDomains();
252         for (size_t i = 0; i < vecDomains.size(); ++i)
253            setDomains.insert(vecDomains[i]->getDomainOutputName());
254            // setDomains.insert(vecDomains[i]);
255
256         field->resetNStep(recordOffset);
257      }
258      nbAxis = setAxis.size();
259      nbDomains = setDomains.size();
260
261      // create sub communicator for file
262      int color = allDomainEmpty ? 0 : 1;
263      MPI_Comm_split(server->intraComm, color, server->intraCommRank, &fileComm);
264      if (allDomainEmpty) MPI_Comm_free(&fileComm);
265
266      // if (time_counter.isEmpty()) time_counter.setValue(time_counter_attr::centered);
267      if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
268    }
269
270    //! Verify state of a file
271    void CFile::checkFile(void)
272    {
273      if (mode.isEmpty() || mode.getValue() == mode_attr::write)
274      {
275        if (!isOpen) createHeader();
276        checkSync();
277      }
278      else
279      {
280        if (!isOpen) openInReadMode();
281      }
282      checkSplit();
283    }
284
285    /*!
286    \brief Verify if synchronisation should be done
287        If syn option is enabled, syn frequence and current time will be used to
288    calculate the moment to syn file(s)
289    \return True if it is the moment to synchronize file, otherwise false
290    */
291   bool CFile::checkSync(void)
292   {
293     CContext* context = CContext::getCurrent();
294     const CDate& currentDate = context->calendar->getCurrentDate();
295     if (!sync_freq.isEmpty())
296     {
297       if (lastSync + sync_freq.getValue() <= currentDate)
298       {
299         lastSync = currentDate;
300         data_out->syncFile();
301         return true;
302        }
303      }
304      return false;
305    }
306
307    /*!
308    \brief Verify if splitting should be done
309        If split option is enabled, split frequence and current time will be used to
310    calculate the moment to split file
311    \return True if it is the moment to split file, otherwise false
312    */
313    bool CFile::checkSplit(void)
314    {
315      CContext* context = CContext::getCurrent();
316      const CDate& currentDate = context->calendar->getCurrentDate();
317      if (!split_freq.isEmpty())
318      {
319        if (currentDate > lastSplit + split_freq.getValue())
320        {
321          lastSplit = lastSplit + split_freq.getValue();
322          std::vector<CField*>::iterator it, end = this->enabledFields.end();
323          for (it = this->enabledFields.begin(); it != end; it++)
324          {
325            (*it)->resetNStep();
326            (*it)->resetNStepMax();
327          }
328          if (mode.isEmpty() || mode.getValue() == mode_attr::write)
329            createHeader();
330          else
331            openInReadMode();
332          return true;
333        }
334      }
335      return false;
336    }
337
338   /*!
339   \brief Create header of netcdf file
340   There are some information to fill in header of each netcdf.
341   */
342   void CFile::createHeader(void)
343   {
344      CContext* context = CContext::getCurrent();
345      CContextServer* server = context->server;
346
347      if (!allDomainEmpty)
348      {
349         StdString filename = getFileOutputName();
350         if (!name_suffix.isEmpty()) filename+=name_suffix.getValue();
351
352// determine splitting format in the file name  : firstPart%start_date%middlePart%end_date%lastPart
353
354         std::string strStartDate="%start_date%" ;
355         std::string strEndDate="%end_date%" ;
356
357         std::string firstPart ;
358         std::string middlePart ;
359         std::string lastPart ;
360         size_t pos1, pos2 ;
361         bool hasStartDate=false ;
362         bool hasEndDate=false ;
363         bool hasSplit = (!split_freq.isEmpty());
364                 
365         pos1=filename.find(strStartDate) ;
366         if (pos1!=std::string::npos)
367         {
368           firstPart=filename.substr(0,pos1) ;
369           pos1+=strStartDate.size() ;
370           hasStartDate=true ;
371         }
372         else pos1=0 ;
373
374         pos2=filename.find(strEndDate,pos1) ;
375         if (pos2!=std::string::npos)
376         {
377           middlePart=filename.substr(pos1,pos2-pos1) ;           
378           pos2+=strEndDate.size() ;
379           lastPart=filename.substr(pos2,filename.size()-pos2) ;
380           hasEndDate=true ;
381         }
382         else middlePart=filename.substr(pos1,filename.size()) ;
383
384         if (!hasStartDate && !hasEndDate)
385         {
386           hasStartDate=true ;
387           hasEndDate=true;
388           firstPart=middlePart ;
389           if (hasSplit) firstPart +="_";
390           middlePart="-" ;
391         }
392   
393         StdOStringStream oss;
394
395         if (!split_freq.isEmpty())
396         {
397           CDate splitEnd = lastSplit + split_freq - 1 * Second;
398
399           string splitFormat;
400           if (split_freq_format.isEmpty())
401           {
402             if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
403             else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
404             else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
405             else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
406             else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
407             else splitFormat = "%y";
408           }
409           else splitFormat = split_freq_format;
410
411           oss << firstPart ;
412           if (hasStartDate) oss << lastSplit.getStr(splitFormat) ;
413           oss << middlePart ;
414           if (hasEndDate) oss << splitEnd.getStr(splitFormat);
415           oss << lastPart ;
416
417           context->registryOut->setKey("splitStart", lastSplit);
418           context->registryOut->setKey("splitEnd",   splitEnd);
419         }
420         else oss<<firstPart<<lastPart ;
421
422        bool append = !this->append.isEmpty() && this->append.getValue();
423
424         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
425         bool useCFConvention = convention.isEmpty() || convention == convention_attr::CF;
426
427         bool multifile = true;
428         if (!type.isEmpty())
429         {
430           if (type == type_attr::one_file) multifile = false;
431           else if (type == type_attr::multiple_file) multifile = true;
432
433         }
434#ifndef USING_NETCDF_PAR
435         if (!multifile)
436         {
437            info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
438            multifile = true;
439          }
440#endif
441         if (multifile)
442         {
443            int commSize, commRank;
444            MPI_Comm_size(fileComm, &commSize);
445            MPI_Comm_rank(fileComm, &commRank);
446
447            if (server->intraCommSize > 1)
448            {
449              oss << "_" ;
450              int width=0; int n = commSize-1;
451              while (n != 0) { n = n / 10; width++;}
452              if (!min_digits.isEmpty())
453                if (width < min_digits) width = min_digits;
454              oss.width(width);
455              oss.fill('0');
456              oss << right << commRank;
457            }
458         }
459         oss << ".nc";
460
461         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
462
463         if (isOpen) data_out->closeFile();
464
465        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(this, oss.str(), append, useClassicFormat, useCFConvention,
466                                                              fileComm, multifile, isCollective, time_counter_name));
467        isOpen = true;
468
469        data_out->writeFile(CFile::get(this));
470
471        // Do not recreate the file structure if opening an existing file
472        if (!data_out->IsInAppendMode())
473        {
474          std::vector<CField*>::iterator it, end = this->enabledFields.end();
475          for (it = this->enabledFields.begin(); it != end; it++)
476          {
477            CField* field = *it;
478            this->data_out->writeFieldGrid(field);
479          }
480          this->data_out->writeTimeDimension();
481
482          for (it = this->enabledFields.begin(); it != end; it++)
483          {
484            CField* field = *it;
485            this->data_out->writeField(field);
486          }
487
488          vector<CVariable*> listVars = getAllVariables();
489          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
490            this->data_out->writeAttribute(*it);
491
492          this->data_out->definition_end();
493        }
494      }
495   }
496
497  /*!
498  \brief Open an existing NetCDF file in read-only mode
499  */
500  void CFile::openInReadMode(void)
501  {
502    CContext* context = CContext::getCurrent();
503    CContextServer* server = context->server;
504
505    if (!allDomainEmpty)
506    {
507      StdString filename = getFileOutputName();
508      StdOStringStream oss;
509      oss << filename;
510      if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
511
512      if (!split_freq.isEmpty())
513      {
514        string splitFormat;
515        if (split_freq_format.isEmpty())
516        {
517          if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
518          else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
519          else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
520          else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
521          else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
522          else splitFormat = "%y";
523        }
524        else splitFormat = split_freq_format;
525        oss << "_" << lastSplit.getStr(splitFormat)
526        << "-" << (lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
527      }
528
529      bool multifile = true;
530      if (!type.isEmpty())
531      {
532        if (type == type_attr::one_file) multifile = false;
533        else if (type == type_attr::multiple_file) multifile = true;
534      }
535  #ifndef USING_NETCDF_PAR
536      if (!multifile)
537      {
538        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
539        multifile = true;
540      }
541  #endif
542      if (multifile)
543      {
544        int commSize, commRank;
545        MPI_Comm_size(fileComm, &commSize);
546        MPI_Comm_rank(fileComm, &commRank);
547
548        if (server->intraCommSize > 1)
549        {
550          oss << "_";
551          int width = 0, n = commSize - 1;
552          while (n != 0) { n = n / 10; width++; }
553          if (!min_digits.isEmpty() && width < min_digits)
554            width = min_digits;
555          oss.width(width);
556          oss.fill('0');
557          oss << right << commRank;
558        }
559      }
560      oss << ".nc";
561
562      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
563
564      if (isOpen) data_out->closeFile();
565      if (time_counter_name.isEmpty()) data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective));
566      else data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective, time_counter_name));
567      isOpen = true;
568    }
569  }
570
571   //! Close file
572   void CFile::close(void)
573   {
574     if (!allDomainEmpty)
575       if (isOpen)
576       {
577         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
578          this->data_out->closeFile();
579         else
580          this->data_in->closeFile();
581       }
582      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
583   }
584   //----------------------------------------------------------------
585
586   void CFile::readAttributesOfEnabledFieldsInReadMode()
587   {
588     if (enabledFields.empty()) return;
589
590     // Just check file and try to open it
591     CContext* context = CContext::getCurrent();
592     CContextClient* client=context->client;
593
594     // It would probably be better to call initFile() somehow
595     MPI_Comm_dup(client->intraComm, &fileComm);
596     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
597
598     checkFile();
599
600     for (int idx = 0; idx < enabledFields.size(); ++idx)
601     {
602        // First of all, find out which domain and axis associated with this field
603        enabledFields[idx]->solveGridReference();
604
605        // Read attributes of domain and axis from this file
606        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
607
608        // Now complete domain and axis associated with this field
609        enabledFields[idx]->solveGenerateGrid();
610
611        // Read necessary value from file
612        this->data_in->readFieldAttributesValues(enabledFields[idx]);
613
614        // Fill attributes for base reference
615        enabledFields[idx]->solveGridDomainAxisBaseRef();
616     }
617
618     // Now everything is ok, close it
619     close();
620   }
621
622
623   /*!
624   \brief Parse xml file and write information into file object
625   \param [in] node xmld node corresponding in xml file
626   */
627   void CFile::parse(xml::CXMLNode & node)
628   {
629      SuperClass::parse(node);
630
631      if (node.goToChildElement())
632      {
633        do
634        {
635           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
636           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
637        } while (node.goToNextElement());
638        node.goToParentElement();
639      }
640
641   }
642   //----------------------------------------------------------------
643
644   /*!
645   \brief Represent a file in form of string with all its info
646   \return String
647   */
648   StdString CFile::toString(void) const
649   {
650      StdOStringStream oss;
651
652      oss << "<" << CFile::GetName() << " ";
653      if (this->hasId())
654         oss << " id=\"" << this->getId() << "\" ";
655      oss << SuperClassAttribute::toString() << ">" << std::endl;
656      if (this->getVirtualFieldGroup() != NULL)
657         oss << *this->getVirtualFieldGroup() << std::endl;
658      oss << "</" << CFile::GetName() << " >";
659      return (oss.str());
660   }
661
662   //----------------------------------------------------------------
663
664   /*!
665   \brief Find all inheritace among objects in a file.
666   \param [in] apply (true) write attributes of parent into ones of child if they are empty
667                     (false) write attributes of parent into a new container of child
668   \param [in] parent
669   */
670   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
671   {
672      SuperClassAttribute::setAttributes(parent,apply);
673      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
674      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
675   }
676
677   //----------------------------------------------------------------
678
679   /*!
680   \brief Resolve all reference of active fields.
681      In order to know exactly which data each active field has, a search for all its
682   reference to find its parents or/and its base reference object must be done. Moreover
683   during this search, there are some information that can only be sent to server AFTER
684   all information of active fields are created on server side, e.g: checking mask or index
685   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
686   */
687   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
688   {
689     int size = this->enabledFields.size();
690     for (int i = 0; i < size; ++i)
691     {
692       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
693//       this->enabledFields[i]->buildGridTransformationGraph();
694     }
695   }
696
697   void CFile::generateNewTransformationGridDest()
698   {
699     int size = this->enabledFields.size();
700     for (int i = 0; i < size; ++i)
701     {
702       this->enabledFields[i]->generateNewTransformationGridDest();
703     }
704   }
705
706   /*!
707   \brief Resolve all reference of active fields.
708      In order to know exactly which data each active field has, a search for all its
709   reference to find its parents or/and its base reference object must be done. Moreover
710   during this search, there are some information that can only be sent to server AFTER
711   all information of active fields are created on server side, e.g: checking mask or index
712   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
713   */
714   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
715   {
716     int size = this->enabledFields.size();
717     for (int i = 0; i < size; ++i)
718     {
719       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
720     }
721   }
722
723   /*!
724    * Constructs the filter graph for each active field.
725    *
726    * \param gc the garbage collector to use when building the filter graph
727    */
728   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
729   {
730     int size = this->enabledFields.size();
731     for (int i = 0; i < size; ++i)
732     {
733       this->enabledFields[i]->buildFilterGraph(gc, true);
734     }
735   }
736
737   /*!
738     Prefetching the data for enabled fields read from file.
739   */
740   void CFile::prefetchEnabledReadModeFields(void)
741   {
742     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
743       return;
744
745     int size = this->enabledFields.size();
746     for (int i = 0; i < size; ++i)
747       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
748   }
749
750   /*!
751     Prefetching the data for enabled fields read from file whose data is out-of-date.
752   */
753   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
754   {
755     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
756       return;
757
758     int size = this->enabledFields.size();
759     for (int i = 0; i < size; ++i)
760       this->enabledFields[i]->sendReadDataRequestIfNeeded();
761   }
762
763   void CFile::solveFieldRefInheritance(bool apply)
764   {
765      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
766      std::vector<CField*> allF = this->getAllFields();
767      for (unsigned int i = 0; i < allF.size(); i++)
768         allF[i]->solveRefInheritance(apply);
769   }
770
771   //----------------------------------------------------------------
772
773   /*!
774   \brief Add a field into file.
775      A field is added into file and it will be written out if the file is enabled and
776   level of this field is smaller than level_output. A new field won't be created if one
777   with id has already existed
778   \param [in] id String identity of new field
779   \return Pointer to added (or already existed) field
780   */
781   CField* CFile::addField(const string& id)
782   {
783     return vFieldGroup->createChild(id);
784   }
785
786   /*!
787   \brief Add a field group into file.
788      A field group is added into file and it will play a role as parents for fields.
789   A new field group won't be created if one with id has already existed
790   \param [in] id String identity of new field group
791   \return Pointer to added (or already existed) field group
792   */
793   CFieldGroup* CFile::addFieldGroup(const string& id)
794   {
795     return vFieldGroup->createChildGroup(id);
796   }
797
798   /*!
799   \brief Add a variable into file.
800      A variable is added into file and if one with id has already existed, pointer to
801   it will be returned.
802      Variable as long as attributes are information container of file.
803   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
804   to fill in (extra) information for a file.
805   \param [in] id String identity of new variable
806   \return Pointer to added (or already existed) variable
807   */
808   CVariable* CFile::addVariable(const string& id)
809   {
810     return vVariableGroup->createChild(id);
811   }
812
813   /*!
814   \brief Add a variable group into file.
815      A variable group is added into file and it will play a role as parents for variables.
816   A new variable group won't be created if one with id has already existed
817   \param [in] id String identity of new variable group
818   \return Pointer to added (or already existed) variable group
819   */
820   CVariableGroup* CFile::addVariableGroup(const string& id)
821   {
822     return vVariableGroup->createChildGroup(id);
823   }
824
825   /*!
826   \brief Send a message to create a field on server side
827   \param[in] id String identity of field that will be created on server
828   */
829   void CFile::sendAddField(const string& id)
830   {
831    CContext* context = CContext::getCurrent();
832
833    if (! context->hasServer )
834    {
835       CContextClient* client = context->client;
836
837       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
838       if (client->isServerLeader())
839       {
840         CMessage msg;
841         msg << this->getId();
842         msg << id;
843         const std::list<int>& ranks = client->getRanksServerLeader();
844         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
845           event.push(*itRank,1,msg);
846         client->sendEvent(event);
847       }
848       else client->sendEvent(event);
849    }
850
851   }
852
853   /*!
854   \brief Send a message to create a field group on server side
855   \param[in] id String identity of field group that will be created on server
856   */
857   void CFile::sendAddFieldGroup(const string& id)
858   {
859    CContext* context = CContext::getCurrent();
860    if (! context->hasServer )
861    {
862       CContextClient* client = context->client;
863
864       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
865       if (client->isServerLeader())
866       {
867         CMessage msg;
868         msg << this->getId();
869         msg << id;
870         const std::list<int>& ranks = client->getRanksServerLeader();
871         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
872           event.push(*itRank,1,msg);
873         client->sendEvent(event);
874       }
875       else client->sendEvent(event);
876    }
877
878   }
879
880   /*!
881   \brief Receive a message annoucing the creation of a field on server side
882   \param[in] event Received event
883   */
884   void CFile::recvAddField(CEventServer& event)
885   {
886
887      CBufferIn* buffer = event.subEvents.begin()->buffer;
888      string id;
889      *buffer>>id;
890      get(id)->recvAddField(*buffer);
891   }
892
893   /*!
894   \brief Receive a message annoucing the creation of a field on server side
895   \param[in] buffer Buffer containing message
896   */
897   void CFile::recvAddField(CBufferIn& buffer)
898   {
899      string id;
900      buffer>>id;
901      addField(id);
902   }
903
904   /*!
905   \brief Receive a message annoucing the creation of a field group on server side
906   \param[in] event Received event
907   */
908   void CFile::recvAddFieldGroup(CEventServer& event)
909   {
910
911      CBufferIn* buffer = event.subEvents.begin()->buffer;
912      string id;
913      *buffer>>id;
914      get(id)->recvAddFieldGroup(*buffer);
915   }
916
917   /*!
918   \brief Receive a message annoucing the creation of a field group on server side
919   \param[in] buffer Buffer containing message
920   */
921   void CFile::recvAddFieldGroup(CBufferIn& buffer)
922   {
923      string id;
924      buffer>>id;
925      addFieldGroup(id);
926   }
927
928   /*!
929   \brief Send messages to duplicate all variables on server side
930      Because each variable has also its attributes. So first thing to do is replicate
931   all these attributes on server side. Because variable can have a value, the second thing
932   is to duplicate this value on server, too.
933   */
934   void CFile::sendAddAllVariables()
935   {
936     std::vector<CVariable*> allVar = getAllVariables();
937     std::vector<CVariable*>::const_iterator it = allVar.begin();
938     std::vector<CVariable*>::const_iterator itE = allVar.end();
939
940     for (; it != itE; ++it)
941     {
942       this->sendAddVariable((*it)->getId());
943       (*it)->sendAllAttributesToServer();
944       (*it)->sendValue();
945     }
946   }
947
948   /*!
949   \brief Send a message to create a variable on server side
950      A variable always belongs to a variable group
951   \param[in] id String identity of variable that will be created on server
952   */
953   void CFile::sendAddVariable(const string& id)
954   {
955    CContext* context = CContext::getCurrent();
956
957    if (! context->hasServer )
958    {
959       CContextClient* client = context->client;
960
961       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
962       if (client->isServerLeader())
963       {
964         CMessage msg;
965         msg << this->getId();
966         msg << id;
967         const std::list<int>& ranks = client->getRanksServerLeader();
968         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
969           event.push(*itRank,1,msg);
970         client->sendEvent(event);
971       }
972       else client->sendEvent(event);
973    }
974
975   }
976
977   /*!
978   \brief Send a message to create a variable group on server side
979   \param[in] id String identity of variable group that will be created on server
980   */
981   void CFile::sendAddVariableGroup(const string& id)
982   {
983    CContext* context = CContext::getCurrent();
984    if (! context->hasServer )
985    {
986       CContextClient* client = context->client;
987
988       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
989       if (client->isServerLeader())
990       {
991         CMessage msg;
992         msg << this->getId();
993         msg << id;
994         const std::list<int>& ranks = client->getRanksServerLeader();
995         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
996           event.push(*itRank,1,msg);
997         client->sendEvent(event);
998       }
999       else client->sendEvent(event);
1000    }
1001
1002   }
1003
1004   /*!
1005   \brief Receive a message annoucing the creation of a variable on server side
1006   \param[in] event Received event
1007   */
1008   void CFile::recvAddVariable(CEventServer& event)
1009   {
1010
1011      CBufferIn* buffer = event.subEvents.begin()->buffer;
1012      string id;
1013      *buffer>>id;
1014      get(id)->recvAddVariable(*buffer);
1015   }
1016
1017   /*!
1018   \brief Receive a message annoucing the creation of a variable on server side
1019   \param[in] buffer Buffer containing message
1020   */
1021   void CFile::recvAddVariable(CBufferIn& buffer)
1022   {
1023      string id;
1024      buffer>>id;
1025      addVariable(id);
1026   }
1027
1028   /*!
1029   \brief Receive a message annoucing the creation of a variable group on server side
1030   \param[in] event Received event
1031   */
1032   void CFile::recvAddVariableGroup(CEventServer& event)
1033   {
1034
1035      CBufferIn* buffer = event.subEvents.begin()->buffer;
1036      string id;
1037      *buffer>>id;
1038      get(id)->recvAddVariableGroup(*buffer);
1039   }
1040
1041   /*!
1042   \brief Receive a message annoucing the creation of a variable group on server side
1043   \param[in] buffer Buffer containing message
1044   */
1045   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1046   {
1047      string id;
1048      buffer>>id;
1049      addVariableGroup(id);
1050   }
1051
1052   /*!
1053     \brief Sending all active (enabled) fields from client to server.
1054   Each field is identified uniquely by its string identity. Not only should we
1055   send the id to server but also we need to send ids of reference domain and reference axis.
1056   With these two id, it's easier to make reference to grid where all data should be written.
1057   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1058   */
1059   void CFile::sendEnabledFields()
1060   {
1061     size_t size = this->enabledFields.size();
1062     for (size_t i = 0; i < size; ++i)
1063     {
1064       CField* field = this->enabledFields[i];
1065       this->sendAddField(field->getId());
1066       field->sendAllAttributesToServer();
1067       field->sendAddAllVariables();
1068     }
1069   }
1070
1071   /*!
1072   \brief Dispatch event received from client
1073      Whenever a message is received in buffer of server, it will be processed depending on
1074   its event type. A new event type should be added in the switch list to make sure
1075   it processed on server side.
1076   \param [in] event: Received message
1077   */
1078   bool CFile::dispatchEvent(CEventServer& event)
1079   {
1080      if (SuperClass::dispatchEvent(event)) return true;
1081      else
1082      {
1083        switch(event.type)
1084        {
1085           case EVENT_ID_ADD_FIELD :
1086             recvAddField(event);
1087             return true;
1088             break;
1089
1090           case EVENT_ID_ADD_FIELD_GROUP :
1091             recvAddFieldGroup(event);
1092             return true;
1093             break;
1094
1095            case EVENT_ID_ADD_VARIABLE :
1096             recvAddVariable(event);
1097             return true;
1098             break;
1099
1100           case EVENT_ID_ADD_VARIABLE_GROUP :
1101             recvAddVariableGroup(event);
1102             return true;
1103             break;
1104           default :
1105              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1106           return false;
1107        }
1108      }
1109   }
1110
1111
1112
1113
1114   ///---------------------------------------------------------------
1115
1116} // namespace xios
Note: See TracBrowser for help on using the repository browser.