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

Last change on this file since 1487 was 1487, checked in by oabramkina, 6 years ago

Trunk: minor modifications for reading UGRID.

Using attribute nvertex defined by a user and not deduced from metadata of a file being read.
Taking into account the fact that the bounds attribute is not required by UGRID.

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