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

Last change on this file since 1153 was 1153, checked in by yushan, 5 years ago

save modif

  • 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.5 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                                                              static_cast< ::MPI_Comm >(fileComm.mpi_comm), 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      #ifdef _usingEP
581      if(omp_get_num_threads() != 1 ) multifile = true;
582      #endif
583
584      if (isOpen) data_out->closeFile();
585      if (time_counter_name.isEmpty()) data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), static_cast< ::MPI_Comm >(fileComm.mpi_comm), multifile, isCollective));
586      else data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), static_cast< ::MPI_Comm >(fileComm.mpi_comm), multifile, isCollective, time_counter_name));
587      isOpen = true;
588    }
589  }
590
591   //! Close file
592   void CFile::close(void)
593   {
594     if (!allDomainEmpty)
595       if (isOpen)
596       {
597         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
598          this->data_out->closeFile();
599         else
600          this->data_in->closeFile();
601       }
602      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
603   }
604   //----------------------------------------------------------------
605
606   void CFile::readAttributesOfEnabledFieldsInReadMode()
607   {
608     if (enabledFields.empty()) return;
609
610     // Just check file and try to open it
611     CContext* context = CContext::getCurrent();
612     CContextClient* client=context->client;
613
614     // It would probably be better to call initFile() somehow
615     
616     MPI_Comm_dup(client->intraComm, &fileComm);
617     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
618
619     //#pragma omp critical (_readAttributesOfEnabledFieldsInReadMode_)
620     //{
621     checkFile(); // calls nc_open
622
623     for (int idx = 0; idx < enabledFields.size(); ++idx)
624     {
625        // First of all, find out which domain and axis associated with this field
626        enabledFields[idx]->solveGridReference();
627
628        // Read attributes of domain and axis from this file
629        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
630
631        // Now complete domain and axis associated with this field
632        enabledFields[idx]->solveGenerateGrid();
633
634        // Read necessary value from file
635        #pragma omp critical (_func)
636        {
637          //checkFile();
638          this->data_in->readFieldAttributesValues(enabledFields[idx]);
639          //close();
640        }
641       
642        // Fill attributes for base reference
643        enabledFields[idx]->solveGridDomainAxisBaseRef();
644     }
645
646     // Now everything is ok, close it
647     close();
648     //}
649     
650     //if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
651     
652   }
653
654
655   /*!
656   \brief Parse xml file and write information into file object
657   \param [in] node xmld node corresponding in xml file
658   */
659   void CFile::parse(xml::CXMLNode & node)
660   {
661      SuperClass::parse(node);
662
663      if (node.goToChildElement())
664      {
665        do
666        {
667           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
668           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
669        } while (node.goToNextElement());
670        node.goToParentElement();
671      }
672
673   }
674   //----------------------------------------------------------------
675
676   /*!
677   \brief Represent a file in form of string with all its info
678   \return String
679   */
680   StdString CFile::toString(void) const
681   {
682      StdOStringStream oss;
683
684      oss << "<" << CFile::GetName() << " ";
685      if (this->hasId())
686         oss << " id=\"" << this->getId() << "\" ";
687      oss << SuperClassAttribute::toString() << ">" << std::endl;
688      if (this->getVirtualFieldGroup() != NULL)
689         oss << *this->getVirtualFieldGroup() << std::endl;
690      oss << "</" << CFile::GetName() << " >";
691      return (oss.str());
692   }
693
694   //----------------------------------------------------------------
695
696   /*!
697   \brief Find all inheritace among objects in a file.
698   \param [in] apply (true) write attributes of parent into ones of child if they are empty
699                     (false) write attributes of parent into a new container of child
700   \param [in] parent
701   */
702   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
703   {
704      SuperClassAttribute::setAttributes(parent,apply);
705      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
706      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
707   }
708
709   //----------------------------------------------------------------
710
711   /*!
712   \brief Resolve all reference of active fields.
713      In order to know exactly which data each active field has, a search for all its
714   reference to find its parents or/and its base reference object must be done. Moreover
715   during this search, there are some information that can only be sent to server AFTER
716   all information of active fields are created on server side, e.g: checking mask or index
717   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
718   */
719   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
720   {
721     int size = this->enabledFields.size();
722     for (int i = 0; i < size; ++i)
723     {
724       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
725//       this->enabledFields[i]->buildGridTransformationGraph();
726     }
727   }
728
729   void CFile::generateNewTransformationGridDest()
730   {
731     int size = this->enabledFields.size();
732     for (int i = 0; i < size; ++i)
733     {
734       this->enabledFields[i]->generateNewTransformationGridDest();
735     }
736   }
737
738   /*!
739   \brief Resolve all reference of active fields.
740      In order to know exactly which data each active field has, a search for all its
741   reference to find its parents or/and its base reference object must be done. Moreover
742   during this search, there are some information that can only be sent to server AFTER
743   all information of active fields are created on server side, e.g: checking mask or index
744   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
745   */
746   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
747   {
748     int size = this->enabledFields.size();
749     for (int i = 0; i < size; ++i)
750     {
751       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
752     }
753   }
754
755   /*!
756    * Constructs the filter graph for each active field.
757    *
758    * \param gc the garbage collector to use when building the filter graph
759    */
760   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
761   {
762     int size = this->enabledFields.size();
763     for (int i = 0; i < size; ++i)
764     {
765       this->enabledFields[i]->buildFilterGraph(gc, true);
766     }
767   }
768
769   /*!
770     Prefetching the data for enabled fields read from file.
771   */
772   void CFile::prefetchEnabledReadModeFields(void)
773   {
774     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
775       return;
776
777     int size = this->enabledFields.size();
778     for (int i = 0; i < size; ++i)
779       this->enabledFields[i]->sendReadDataRequest(CContext::getCurrent()->getCalendar()->getCurrentDate());
780   }
781
782   /*!
783     Prefetching the data for enabled fields read from file whose data is out-of-date.
784   */
785   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
786   {
787     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
788       return;
789
790     int size = this->enabledFields.size();
791     for (int i = 0; i < size; ++i)
792       this->enabledFields[i]->sendReadDataRequestIfNeeded();
793   }
794
795   void CFile::solveFieldRefInheritance(bool apply)
796   {
797      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
798      std::vector<CField*> allF = this->getAllFields();
799      for (unsigned int i = 0; i < allF.size(); i++)
800         allF[i]->solveRefInheritance(apply);
801   }
802
803   //----------------------------------------------------------------
804
805   /*!
806   \brief Add a field into file.
807      A field is added into file and it will be written out if the file is enabled and
808   level of this field is smaller than level_output. A new field won't be created if one
809   with id has already existed
810   \param [in] id String identity of new field
811   \return Pointer to added (or already existed) field
812   */
813   CField* CFile::addField(const string& id)
814   {
815     return vFieldGroup->createChild(id);
816   }
817
818   /*!
819   \brief Add a field group into file.
820      A field group is added into file and it will play a role as parents for fields.
821   A new field group won't be created if one with id has already existed
822   \param [in] id String identity of new field group
823   \return Pointer to added (or already existed) field group
824   */
825   CFieldGroup* CFile::addFieldGroup(const string& id)
826   {
827     return vFieldGroup->createChildGroup(id);
828   }
829
830   /*!
831   \brief Add a variable into file.
832      A variable is added into file and if one with id has already existed, pointer to
833   it will be returned.
834      Variable as long as attributes are information container of file.
835   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
836   to fill in (extra) information for a file.
837   \param [in] id String identity of new variable
838   \return Pointer to added (or already existed) variable
839   */
840   CVariable* CFile::addVariable(const string& id)
841   {
842     return vVariableGroup->createChild(id);
843   }
844
845   /*!
846   \brief Add a variable group into file.
847      A variable group is added into file and it will play a role as parents for variables.
848   A new variable group won't be created if one with id has already existed
849   \param [in] id String identity of new variable group
850   \return Pointer to added (or already existed) variable group
851   */
852   CVariableGroup* CFile::addVariableGroup(const string& id)
853   {
854     return vVariableGroup->createChildGroup(id);
855   }
856
857   /*!
858   \brief Send a message to create a field on server side
859   \param[in] id String identity of field that will be created on server
860   */
861   void CFile::sendAddField(const string& id)
862   {
863    CContext* context = CContext::getCurrent();
864
865    if (! context->hasServer )
866    {
867       CContextClient* client = context->client;
868
869       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
870       if (client->isServerLeader())
871       {
872         CMessage msg;
873         msg << this->getId();
874         msg << id;
875         const std::list<int>& ranks = client->getRanksServerLeader();
876         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
877           event.push(*itRank,1,msg);
878         client->sendEvent(event);
879       }
880       else client->sendEvent(event);
881    }
882
883   }
884
885   /*!
886   \brief Send a message to create a field group on server side
887   \param[in] id String identity of field group that will be created on server
888   */
889   void CFile::sendAddFieldGroup(const string& id)
890   {
891    CContext* context = CContext::getCurrent();
892    if (! context->hasServer )
893    {
894       CContextClient* client = context->client;
895
896       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
897       if (client->isServerLeader())
898       {
899         CMessage msg;
900         msg << this->getId();
901         msg << id;
902         const std::list<int>& ranks = client->getRanksServerLeader();
903         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
904           event.push(*itRank,1,msg);
905         client->sendEvent(event);
906       }
907       else client->sendEvent(event);
908    }
909
910   }
911
912   /*!
913   \brief Receive a message annoucing the creation of a field on server side
914   \param[in] event Received event
915   */
916   void CFile::recvAddField(CEventServer& event)
917   {
918
919      CBufferIn* buffer = event.subEvents.begin()->buffer;
920      string id;
921      *buffer>>id;
922      get(id)->recvAddField(*buffer);
923   }
924
925   /*!
926   \brief Receive a message annoucing the creation of a field on server side
927   \param[in] buffer Buffer containing message
928   */
929   void CFile::recvAddField(CBufferIn& buffer)
930   {
931      string id;
932      buffer>>id;
933      addField(id);
934   }
935
936   /*!
937   \brief Receive a message annoucing the creation of a field group on server side
938   \param[in] event Received event
939   */
940   void CFile::recvAddFieldGroup(CEventServer& event)
941   {
942
943      CBufferIn* buffer = event.subEvents.begin()->buffer;
944      string id;
945      *buffer>>id;
946      get(id)->recvAddFieldGroup(*buffer);
947   }
948
949   /*!
950   \brief Receive a message annoucing the creation of a field group on server side
951   \param[in] buffer Buffer containing message
952   */
953   void CFile::recvAddFieldGroup(CBufferIn& buffer)
954   {
955      string id;
956      buffer>>id;
957      addFieldGroup(id);
958   }
959
960   /*!
961   \brief Send messages to duplicate all variables on server side
962      Because each variable has also its attributes. So first thing to do is replicate
963   all these attributes on server side. Because variable can have a value, the second thing
964   is to duplicate this value on server, too.
965   */
966   void CFile::sendAddAllVariables()
967   {
968     std::vector<CVariable*> allVar = getAllVariables();
969     std::vector<CVariable*>::const_iterator it = allVar.begin();
970     std::vector<CVariable*>::const_iterator itE = allVar.end();
971
972     for (; it != itE; ++it)
973     {
974       this->sendAddVariable((*it)->getId());
975       (*it)->sendAllAttributesToServer();
976       (*it)->sendValue();
977     }
978   }
979
980   /*!
981   \brief Send a message to create a variable on server side
982      A variable always belongs to a variable group
983   \param[in] id String identity of variable that will be created on server
984   */
985   void CFile::sendAddVariable(const string& id)
986   {
987    CContext* context = CContext::getCurrent();
988
989    if (! context->hasServer )
990    {
991       CContextClient* client = context->client;
992
993       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
994       if (client->isServerLeader())
995       {
996         CMessage msg;
997         msg << this->getId();
998         msg << id;
999         const std::list<int>& ranks = client->getRanksServerLeader();
1000         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1001           event.push(*itRank,1,msg);
1002         client->sendEvent(event);
1003       }
1004       else client->sendEvent(event);
1005    }
1006
1007   }
1008
1009   /*!
1010   \brief Send a message to create a variable group on server side
1011   \param[in] id String identity of variable group that will be created on server
1012   */
1013   void CFile::sendAddVariableGroup(const string& id)
1014   {
1015    CContext* context = CContext::getCurrent();
1016    if (! context->hasServer )
1017    {
1018       CContextClient* client = context->client;
1019
1020       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
1021       if (client->isServerLeader())
1022       {
1023         CMessage msg;
1024         msg << this->getId();
1025         msg << id;
1026         const std::list<int>& ranks = client->getRanksServerLeader();
1027         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1028           event.push(*itRank,1,msg);
1029         client->sendEvent(event);
1030       }
1031       else client->sendEvent(event);
1032    }
1033
1034   }
1035
1036   /*!
1037   \brief Receive a message annoucing the creation of a variable on server side
1038   \param[in] event Received event
1039   */
1040   void CFile::recvAddVariable(CEventServer& event)
1041   {
1042
1043      CBufferIn* buffer = event.subEvents.begin()->buffer;
1044      string id;
1045      *buffer>>id;
1046      get(id)->recvAddVariable(*buffer);
1047   }
1048
1049   /*!
1050   \brief Receive a message annoucing the creation of a variable on server side
1051   \param[in] buffer Buffer containing message
1052   */
1053   void CFile::recvAddVariable(CBufferIn& buffer)
1054   {
1055      string id;
1056      buffer>>id;
1057      addVariable(id);
1058   }
1059
1060   /*!
1061   \brief Receive a message annoucing the creation of a variable group on server side
1062   \param[in] event Received event
1063   */
1064   void CFile::recvAddVariableGroup(CEventServer& event)
1065   {
1066
1067      CBufferIn* buffer = event.subEvents.begin()->buffer;
1068      string id;
1069      *buffer>>id;
1070      get(id)->recvAddVariableGroup(*buffer);
1071   }
1072
1073   /*!
1074   \brief Receive a message annoucing the creation of a variable group on server side
1075   \param[in] buffer Buffer containing message
1076   */
1077   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1078   {
1079      string id;
1080      buffer>>id;
1081      addVariableGroup(id);
1082   }
1083
1084   /*!
1085     \brief Sending all active (enabled) fields from client to server.
1086   Each field is identified uniquely by its string identity. Not only should we
1087   send the id to server but also we need to send ids of reference domain and reference axis.
1088   With these two id, it's easier to make reference to grid where all data should be written.
1089   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1090   */
1091   void CFile::sendEnabledFields()
1092   {
1093     size_t size = this->enabledFields.size();
1094     for (size_t i = 0; i < size; ++i)
1095     {
1096       CField* field = this->enabledFields[i];
1097       this->sendAddField(field->getId());
1098       field->sendAllAttributesToServer();
1099       field->sendAddAllVariables();
1100     }
1101   }
1102
1103   /*!
1104   \brief Dispatch event received from client
1105      Whenever a message is received in buffer of server, it will be processed depending on
1106   its event type. A new event type should be added in the switch list to make sure
1107   it processed on server side.
1108   \param [in] event: Received message
1109   */
1110   bool CFile::dispatchEvent(CEventServer& event)
1111   {
1112      if (SuperClass::dispatchEvent(event)) return true;
1113      else
1114      {
1115        switch(event.type)
1116        {
1117           case EVENT_ID_ADD_FIELD :
1118             recvAddField(event);
1119             return true;
1120             break;
1121
1122           case EVENT_ID_ADD_FIELD_GROUP :
1123             recvAddFieldGroup(event);
1124             return true;
1125             break;
1126
1127            case EVENT_ID_ADD_VARIABLE :
1128             recvAddVariable(event);
1129             return true;
1130             break;
1131
1132           case EVENT_ID_ADD_VARIABLE_GROUP :
1133             recvAddVariableGroup(event);
1134             return true;
1135             break;
1136           default :
1137              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1138           return false;
1139        }
1140      }
1141   }
1142
1143
1144
1145
1146   ///---------------------------------------------------------------
1147
1148} // namespace xios
Note: See TracBrowser for help on using the repository browser.