source: XIOS/trunk/src/node/file.cpp @ 1098

Last change on this file since 1098 was 1098, checked in by ymipsl, 7 years ago

Enhancement : in file attribut ts_prefix, the substring "%file_name%", if found, is replaced by the file name.
Bug fix in append mode

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