source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/file.cpp @ 2002

Last change on this file since 2002 was 2002, checked in by ymipsl, 3 years ago

Some cleaning of old transformation dead code

YM

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