source: XIOS/dev/dev_olga/src/node/file.cpp @ 1025

Last change on this file since 1025 was 1025, checked in by mhnguyen, 7 years ago

Merging working version of coupler

+) Add some changes of domain and axis: Retransfer the atttributes in a generic ways for each level of client (or server)
+) Remove some spoiled files from the previous commits

Test
+) No test

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