source: XIOS/dev/branch_openmp/src/node/file.cpp @ 1328

Last change on this file since 1328 was 1328, checked in by yushan, 6 years ago

dev_omp

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