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

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

bug fixed in mpi_comm_split. Key needs to be specifify.

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