source: XIOS/dev/branch_yushan_merged/src/node/file.cpp @ 1172

Last change on this file since 1172 was 1172, checked in by yushan, 7 years ago

save dev. need to unify the file type when using EP

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