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

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

branch merged with trunk @1155

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