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

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

omp_dev

  • 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.2 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 = boost::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 = boost::shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective));
601      else data_in = boost::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        #pragma omp critical (_func)
649        {
650          this->data_in->readFieldAttributesValues(enabledFields[idx]);
651        }
652        // Fill attributes for base reference
653        enabledFields[idx]->solveGridDomainAxisBaseRef();
654     }
655
656     // Now everything is ok, close it
657     close();
658   }
659
660
661   /*!
662   \brief Parse xml file and write information into file object
663   \param [in] node xmld node corresponding in xml file
664   */
665   void CFile::parse(xml::CXMLNode & node)
666   {
667      SuperClass::parse(node);
668
669      if (node.goToChildElement())
670      {
671        do
672        {
673           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
674           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
675        } while (node.goToNextElement());
676        node.goToParentElement();
677      }
678
679   }
680   //----------------------------------------------------------------
681
682   /*!
683   \brief Represent a file in form of string with all its info
684   \return String
685   */
686   StdString CFile::toString(void) const
687   {
688      StdOStringStream oss;
689
690      oss << "<" << CFile::GetName() << " ";
691      if (this->hasId())
692         oss << " id=\"" << this->getId() << "\" ";
693      oss << SuperClassAttribute::toString() << ">" << std::endl;
694      if (this->getVirtualFieldGroup() != NULL)
695         oss << *this->getVirtualFieldGroup() << std::endl;
696      oss << "</" << CFile::GetName() << " >";
697      return (oss.str());
698   }
699
700   //----------------------------------------------------------------
701
702   /*!
703   \brief Find all inheritace among objects in a file.
704   \param [in] apply (true) write attributes of parent into ones of child if they are empty
705                     (false) write attributes of parent into a new container of child
706   \param [in] parent
707   */
708   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
709   {
710      SuperClassAttribute::setAttributes(parent,apply);
711      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
712      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
713   }
714
715   //----------------------------------------------------------------
716
717   /*!
718   \brief Resolve all reference of active fields.
719      In order to know exactly which data each active field has, a search for all its
720   reference to find its parents or/and its base reference object must be done. Moreover
721   during this search, there are some information that can only be sent to server AFTER
722   all information of active fields are created on server side, e.g: checking mask or index
723   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
724   */
725   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
726   {
727     int size = this->enabledFields.size();
728     for (int i = 0; i < size; ++i)
729     {
730       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
731//       this->enabledFields[i]->buildGridTransformationGraph();
732     }
733   }
734
735   void CFile::generateNewTransformationGridDest()
736   {
737     int size = this->enabledFields.size();
738     for (int i = 0; i < size; ++i)
739     {
740       this->enabledFields[i]->generateNewTransformationGridDest();
741     }
742   }
743
744   /*!
745   \brief Resolve all reference of active fields.
746      In order to know exactly which data each active field has, a search for all its
747   reference to find its parents or/and its base reference object must be done. Moreover
748   during this search, there are some information that can only be sent to server AFTER
749   all information of active fields are created on server side, e.g: checking mask or index
750   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
751   */
752   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
753   {
754     int size = this->enabledFields.size();
755     for (int i = 0; i < size; ++i)
756     {
757       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
758     }
759   }
760
761   /*!
762    * Constructs the filter graph for each active field.
763    *
764    * \param gc the garbage collector to use when building the filter graph
765    */
766   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
767   {
768     int size = this->enabledFields.size();
769     for (int i = 0; i < size; ++i)
770     {
771       this->enabledFields[i]->buildFilterGraph(gc, true);
772     }
773   }
774
775   /*!
776     Prefetching the data for enabled fields read from file.
777   */
778   void CFile::prefetchEnabledReadModeFields(void)
779   {
780     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
781       return;
782
783     int size = this->enabledFields.size();
784     for (int i = 0; i < size; ++i)
785       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
786   }
787
788   /*!
789     Do all post timestep operations for enabled fields in read mode:
790      - Prefetch the data read from file when needed
791      - Check that the data excepted from server has been received
792   */
793   void CFile::doPostTimestepOperationsForEnabledReadModeFields(void)
794   {
795     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
796       return;
797
798     int size = this->enabledFields.size();
799     for (int i = 0; i < size; ++i)
800     {
801       this->enabledFields[i]->checkForLateDataFromServer();
802       this->enabledFields[i]->sendReadDataRequestIfNeeded();
803     }
804   }
805
806   void CFile::solveFieldRefInheritance(bool apply)
807   {
808      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
809      std::vector<CField*> allF = this->getAllFields();
810      for (unsigned int i = 0; i < allF.size(); i++)
811         allF[i]->solveRefInheritance(apply);
812   }
813
814   //----------------------------------------------------------------
815
816   /*!
817   \brief Add a field into file.
818      A field is added into file and it will be written out if the file is enabled and
819   level of this field is smaller than level_output. A new field won't be created if one
820   with id has already existed
821   \param [in] id String identity of new field
822   \return Pointer to added (or already existed) field
823   */
824   CField* CFile::addField(const string& id)
825   {
826     return vFieldGroup->createChild(id);
827   }
828
829   /*!
830   \brief Add a field group into file.
831      A field group is added into file and it will play a role as parents for fields.
832   A new field group won't be created if one with id has already existed
833   \param [in] id String identity of new field group
834   \return Pointer to added (or already existed) field group
835   */
836   CFieldGroup* CFile::addFieldGroup(const string& id)
837   {
838     return vFieldGroup->createChildGroup(id);
839   }
840
841   /*!
842   \brief Add a variable into file.
843      A variable is added into file and if one with id has already existed, pointer to
844   it will be returned.
845      Variable as long as attributes are information container of file.
846   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
847   to fill in (extra) information for a file.
848   \param [in] id String identity of new variable
849   \return Pointer to added (or already existed) variable
850   */
851   CVariable* CFile::addVariable(const string& id)
852   {
853     return vVariableGroup->createChild(id);
854   }
855
856   /*!
857   \brief Add a variable group into file.
858      A variable group is added into file and it will play a role as parents for variables.
859   A new variable group won't be created if one with id has already existed
860   \param [in] id String identity of new variable group
861   \return Pointer to added (or already existed) variable group
862   */
863   CVariableGroup* CFile::addVariableGroup(const string& id)
864   {
865     return vVariableGroup->createChildGroup(id);
866   }
867
868   /*!
869   \brief Send a message to create a field on server side
870   \param[in] id String identity of field that will be created on server
871   */
872   void CFile::sendAddField(const string& id)
873   {
874    CContext* context = CContext::getCurrent();
875
876    if (! context->hasServer )
877    {
878       CContextClient* client = context->client;
879
880       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
881       if (client->isServerLeader())
882       {
883         CMessage msg;
884         msg << this->getId();
885         msg << id;
886         const std::list<int>& ranks = client->getRanksServerLeader();
887         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
888           event.push(*itRank,1,msg);
889         client->sendEvent(event);
890       }
891       else client->sendEvent(event);
892    }
893
894   }
895
896   /*!
897   \brief Send a message to create a field group on server side
898   \param[in] id String identity of field group that will be created on server
899   */
900   void CFile::sendAddFieldGroup(const string& id)
901   {
902    CContext* context = CContext::getCurrent();
903    if (! context->hasServer )
904    {
905       CContextClient* client = context->client;
906
907       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
908       if (client->isServerLeader())
909       {
910         CMessage msg;
911         msg << this->getId();
912         msg << id;
913         const std::list<int>& ranks = client->getRanksServerLeader();
914         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
915           event.push(*itRank,1,msg);
916         client->sendEvent(event);
917       }
918       else client->sendEvent(event);
919    }
920
921   }
922
923   /*!
924   \brief Receive a message annoucing the creation of a field on server side
925   \param[in] event Received event
926   */
927   void CFile::recvAddField(CEventServer& event)
928   {
929
930      CBufferIn* buffer = event.subEvents.begin()->buffer;
931      string id;
932      *buffer>>id;
933      get(id)->recvAddField(*buffer);
934   }
935
936   /*!
937   \brief Receive a message annoucing the creation of a field on server side
938   \param[in] buffer Buffer containing message
939   */
940   void CFile::recvAddField(CBufferIn& buffer)
941   {
942      string id;
943      buffer>>id;
944      addField(id);
945   }
946
947   /*!
948   \brief Receive a message annoucing the creation of a field group on server side
949   \param[in] event Received event
950   */
951   void CFile::recvAddFieldGroup(CEventServer& event)
952   {
953
954      CBufferIn* buffer = event.subEvents.begin()->buffer;
955      string id;
956      *buffer>>id;
957      get(id)->recvAddFieldGroup(*buffer);
958   }
959
960   /*!
961   \brief Receive a message annoucing the creation of a field group on server side
962   \param[in] buffer Buffer containing message
963   */
964   void CFile::recvAddFieldGroup(CBufferIn& buffer)
965   {
966      string id;
967      buffer>>id;
968      addFieldGroup(id);
969   }
970
971   /*!
972   \brief Send messages to duplicate all variables on server side
973      Because each variable has also its attributes. So first thing to do is replicate
974   all these attributes on server side. Because variable can have a value, the second thing
975   is to duplicate this value on server, too.
976   */
977   void CFile::sendAddAllVariables()
978   {
979     std::vector<CVariable*> allVar = getAllVariables();
980     std::vector<CVariable*>::const_iterator it = allVar.begin();
981     std::vector<CVariable*>::const_iterator itE = allVar.end();
982
983     for (; it != itE; ++it)
984     {
985       this->sendAddVariable((*it)->getId());
986       (*it)->sendAllAttributesToServer();
987       (*it)->sendValue();
988     }
989   }
990
991   /*!
992   \brief Send a message to create a variable on server side
993      A variable always belongs to a variable group
994   \param[in] id String identity of variable that will be created on server
995   */
996   void CFile::sendAddVariable(const string& id)
997   {
998    CContext* context = CContext::getCurrent();
999
1000    if (! context->hasServer )
1001    {
1002       CContextClient* client = context->client;
1003
1004       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
1005       if (client->isServerLeader())
1006       {
1007         CMessage msg;
1008         msg << this->getId();
1009         msg << id;
1010         const std::list<int>& ranks = client->getRanksServerLeader();
1011         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1012           event.push(*itRank,1,msg);
1013         client->sendEvent(event);
1014       }
1015       else client->sendEvent(event);
1016    }
1017
1018   }
1019
1020   /*!
1021   \brief Send a message to create a variable group on server side
1022   \param[in] id String identity of variable group that will be created on server
1023   */
1024   void CFile::sendAddVariableGroup(const string& id)
1025   {
1026    CContext* context = CContext::getCurrent();
1027    if (! context->hasServer )
1028    {
1029       CContextClient* client = context->client;
1030
1031       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
1032       if (client->isServerLeader())
1033       {
1034         CMessage msg;
1035         msg << this->getId();
1036         msg << id;
1037         const std::list<int>& ranks = client->getRanksServerLeader();
1038         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1039           event.push(*itRank,1,msg);
1040         client->sendEvent(event);
1041       }
1042       else client->sendEvent(event);
1043    }
1044
1045   }
1046
1047   /*!
1048   \brief Receive a message annoucing the creation of a variable on server side
1049   \param[in] event Received event
1050   */
1051   void CFile::recvAddVariable(CEventServer& event)
1052   {
1053
1054      CBufferIn* buffer = event.subEvents.begin()->buffer;
1055      string id;
1056      *buffer>>id;
1057      get(id)->recvAddVariable(*buffer);
1058   }
1059
1060   /*!
1061   \brief Receive a message annoucing the creation of a variable on server side
1062   \param[in] buffer Buffer containing message
1063   */
1064   void CFile::recvAddVariable(CBufferIn& buffer)
1065   {
1066      string id;
1067      buffer>>id;
1068      addVariable(id);
1069   }
1070
1071   /*!
1072   \brief Receive a message annoucing the creation of a variable group on server side
1073   \param[in] event Received event
1074   */
1075   void CFile::recvAddVariableGroup(CEventServer& event)
1076   {
1077
1078      CBufferIn* buffer = event.subEvents.begin()->buffer;
1079      string id;
1080      *buffer>>id;
1081      get(id)->recvAddVariableGroup(*buffer);
1082   }
1083
1084   /*!
1085   \brief Receive a message annoucing the creation of a variable group on server side
1086   \param[in] buffer Buffer containing message
1087   */
1088   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1089   {
1090      string id;
1091      buffer>>id;
1092      addVariableGroup(id);
1093   }
1094
1095   /*!
1096     \brief Sending all active (enabled) fields from client to server.
1097   Each field is identified uniquely by its string identity. Not only should we
1098   send the id to server but also we need to send ids of reference domain and reference axis.
1099   With these two id, it's easier to make reference to grid where all data should be written.
1100   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1101   */
1102   void CFile::sendEnabledFields()
1103   {
1104     size_t size = this->enabledFields.size();
1105     for (size_t i = 0; i < size; ++i)
1106     {
1107       CField* field = this->enabledFields[i];
1108       this->sendAddField(field->getId());
1109       field->checkAttributes();
1110       field->sendAllAttributesToServer();
1111       field->sendAddAllVariables();
1112     }
1113   }
1114
1115   /*!
1116   \brief Dispatch event received from client
1117      Whenever a message is received in buffer of server, it will be processed depending on
1118   its event type. A new event type should be added in the switch list to make sure
1119   it processed on server side.
1120   \param [in] event: Received message
1121   */
1122   bool CFile::dispatchEvent(CEventServer& event)
1123   {
1124      if (SuperClass::dispatchEvent(event)) return true;
1125      else
1126      {
1127        switch(event.type)
1128        {
1129           case EVENT_ID_ADD_FIELD :
1130             recvAddField(event);
1131             return true;
1132             break;
1133
1134           case EVENT_ID_ADD_FIELD_GROUP :
1135             recvAddFieldGroup(event);
1136             return true;
1137             break;
1138
1139            case EVENT_ID_ADD_VARIABLE :
1140             recvAddVariable(event);
1141             return true;
1142             break;
1143
1144           case EVENT_ID_ADD_VARIABLE_GROUP :
1145             recvAddVariableGroup(event);
1146             return true;
1147             break;
1148           default :
1149              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1150           return false;
1151        }
1152      }
1153   }
1154
1155
1156
1157
1158   ///---------------------------------------------------------------
1159
1160} // namespace xios
Note: See TracBrowser for help on using the repository browser.