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

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

branch merged with trunk @1200

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