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

Last change on this file since 823 was 823, checked in by mhnguyen, 8 years ago

Implementing grid destination clone in case of two grid source

+) Clone attributes of grid destination as well as its transformation
+) Clean some redundant codes

Test
+) All tests pass

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