source: XIOS/dev/dev_olga/src/node/file.cpp @ 1136

Last change on this file since 1136 was 1136, checked in by mhnguyen, 7 years ago

Reading for two-level server

+) Update reading with the changes of grid distribution
+) Correct a minor bug on modification grid mask
+) Do some code cleaning

Test
+) On Curie
+) Work in both mode: classical and two-level
+) Push some *.nc for test_remap

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