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

Last change on this file since 952 was 952, checked in by ymipsl, 5 years ago
  • Attribut record_offset accept now negative value.
  • Field are not output in files until nstep > 0.

YM

  • 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: 36.5 KB
Line 
1#include "file.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6#include "object_factory.hpp"
7#include "context.hpp"
8#include "context_server.hpp"
9#include "nc4_data_output.hpp"
10#include "nc4_data_input.hpp"
11#include "calendar_util.hpp"
12#include "date.hpp"
13#include "message.hpp"
14#include "type.hpp"
15#include "xios_spl.hpp"
16#include "context_client.hpp"
17#include "mpi.hpp"
18
19namespace xios {
20
21   /// ////////////////////// Dfinitions ////////////////////// ///
22
23   CFile::CFile(void)
24      : CObjectTemplate<CFile>(), CFileAttributes()
25      , vFieldGroup(), data_out(), enabledFields(), fileComm(MPI_COMM_NULL)
26      , allDomainEmpty(false), isOpen(false)
27   {
28     setVirtualFieldGroup();
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 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   //! 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 int 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         if (!name_suffix.isEmpty()) filename+=name_suffix.getValue();
360
361// determine splitting format in the file name  : firstPart%start_date%middlePart%end_date%lastPart
362
363         std::string strStartDate="%start_date%" ;
364         std::string strEndDate="%end_date%" ;
365
366         std::string firstPart ;
367         std::string middlePart ;
368         std::string lastPart ;
369         size_t pos1, pos2 ;
370         bool hasStartDate=false ;
371         bool hasEndDate=false ;
372         bool hasSplit = (!split_freq.isEmpty());
373                 
374         pos1=filename.find(strStartDate) ;
375         if (pos1!=std::string::npos)
376         {
377           firstPart=filename.substr(0,pos1) ;
378           pos1+=strStartDate.size() ;
379           hasStartDate=true ;
380         }
381         else pos1=0 ;
382
383         pos2=filename.find(strEndDate,pos1) ;
384         if (pos2!=std::string::npos)
385         {
386           middlePart=filename.substr(pos1,pos2-pos1) ;
387           cout<<pos2<<endl ;
388           pos2+=strEndDate.size() ;
389           lastPart=filename.substr(pos2,filename.size()-pos2) ;
390           hasEndDate=true ;
391         }
392         else middlePart=filename.substr(pos1,filename.size()) ;
393
394         if (!hasStartDate && !hasEndDate)
395         {
396           hasStartDate=true ;
397           hasEndDate=true;
398           firstPart=middlePart ;
399           if (hasSplit) firstPart +="_";
400           middlePart="-" ;
401         }
402   
403         StdOStringStream oss;
404
405         if (!split_freq.isEmpty())
406         {
407           CDate splitEnd = lastSplit + split_freq - 1 * Second;
408
409           string splitFormat;
410           if (split_freq_format.isEmpty())
411           {
412             if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
413             else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
414             else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
415             else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
416             else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
417             else splitFormat = "%y";
418           }
419           else splitFormat = split_freq_format;
420
421           oss << firstPart ;
422           if (hasStartDate) oss << lastSplit.getStr(splitFormat) ;
423           oss << middlePart ;
424           if (hasEndDate) oss << splitEnd.getStr(splitFormat);
425           oss << lastPart ;
426
427           context->registryOut->setKey("splitStart", lastSplit);
428           context->registryOut->setKey("splitEnd",   splitEnd);
429         }
430         else oss<<firstPart<<lastPart ;
431
432        bool append = !this->append.isEmpty() && this->append.getValue();
433
434         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
435         bool useCFConvention = convention.isEmpty() || convention == convention_attr::CF;
436
437         bool multifile = true;
438         if (!type.isEmpty())
439         {
440           if (type == type_attr::one_file) multifile = false;
441           else if (type == type_attr::multiple_file) multifile = true;
442
443         }
444#ifndef USING_NETCDF_PAR
445         if (!multifile)
446         {
447            info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
448            multifile = true;
449          }
450#endif
451         if (multifile)
452         {
453            int commSize, commRank;
454            MPI_Comm_size(fileComm, &commSize);
455            MPI_Comm_rank(fileComm, &commRank);
456
457            if (server->intraCommSize > 1)
458            {
459              oss << "_" ;
460              int width=0; int n = commSize-1;
461              while (n != 0) { n = n / 10; width++;}
462              if (!min_digits.isEmpty())
463                if (width < min_digits) width = min_digits;
464              oss.width(width);
465              oss.fill('0');
466              oss << right << commRank;
467            }
468         }
469         oss << ".nc";
470
471         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
472
473         if (isOpen) data_out->closeFile();
474
475        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), append, useClassicFormat, useCFConvention,
476                                                              fileComm, multifile, isCollective, time_counter_name));
477        isOpen = true;
478
479        data_out->writeFile(CFile::get(this));
480
481        // Do not recreate the file structure if opening an existing file
482        if (!data_out->IsInAppendMode())
483        {
484          std::vector<CField*>::iterator it, end = this->enabledFields.end();
485          for (it = this->enabledFields.begin(); it != end; it++)
486          {
487            CField* field = *it;
488            this->data_out->writeFieldGrid(field);
489          }
490          this->data_out->writeTimeDimension();
491
492          for (it = this->enabledFields.begin(); it != end; it++)
493          {
494            CField* field = *it;
495            this->data_out->writeField(field);
496          }
497
498          vector<CVariable*> listVars = getAllVariables();
499          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
500            this->data_out->writeAttribute(*it);
501
502          this->data_out->definition_end();
503        }
504      }
505   }
506
507  /*!
508  \brief Open an existing NetCDF file in read-only mode
509  */
510  void CFile::openInReadMode(void)
511  {
512    CContext* context = CContext::getCurrent();
513    CContextServer* server = context->server;
514
515    if (!allDomainEmpty)
516    {
517      StdString filename = getFileOutputName();
518      StdOStringStream oss;
519      oss << filename;
520      if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
521
522      if (!split_freq.isEmpty())
523      {
524        string splitFormat;
525        if (split_freq_format.isEmpty())
526        {
527          if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
528          else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
529          else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
530          else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
531          else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
532          else splitFormat = "%y";
533        }
534        else splitFormat = split_freq_format;
535        oss << "_" << lastSplit.getStr(splitFormat)
536        << "-" << (lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
537      }
538
539      bool multifile = true;
540      if (!type.isEmpty())
541      {
542        if (type == type_attr::one_file) multifile = false;
543        else if (type == type_attr::multiple_file) multifile = true;
544      }
545  #ifndef USING_NETCDF_PAR
546      if (!multifile)
547      {
548        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
549        multifile = true;
550      }
551  #endif
552      if (multifile)
553      {
554        int commSize, commRank;
555        MPI_Comm_size(fileComm, &commSize);
556        MPI_Comm_rank(fileComm, &commRank);
557
558        if (server->intraCommSize > 1)
559        {
560          oss << "_";
561          int width = 0, n = commSize - 1;
562          while (n != 0) { n = n / 10; width++; }
563          if (!min_digits.isEmpty() && width < min_digits)
564            width = min_digits;
565          oss.width(width);
566          oss.fill('0');
567          oss << right << commRank;
568        }
569      }
570      oss << ".nc";
571
572      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
573
574      if (isOpen) data_out->closeFile();
575      if (time_counter_name.isEmpty()) data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective));
576      else data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective, time_counter_name));
577      isOpen = true;
578    }
579  }
580
581   //! Close file
582   void CFile::close(void)
583   {
584     if (!allDomainEmpty)
585       if (isOpen)
586       {
587         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
588          this->data_out->closeFile();
589         else
590          this->data_in->closeFile();
591       }
592      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
593   }
594   //----------------------------------------------------------------
595
596   void CFile::readAttributesOfEnabledFieldsInReadMode()
597   {
598     if (enabledFields.empty()) return;
599
600     // Just check file and try to open it
601     CContext* context = CContext::getCurrent();
602     CContextClient* client=context->client;
603
604     // It would probably be better to call initFile() somehow
605     MPI_Comm_dup(client->intraComm, &fileComm);
606     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
607
608     checkFile();
609
610     for (int idx = 0; idx < enabledFields.size(); ++idx)
611     {
612        // First of all, find out which domain and axis associated with this field
613        enabledFields[idx]->solveGridReference();
614
615        // Read attributes of domain and axis from this file
616        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
617
618        // Now complete domain and axis associated with this field
619        enabledFields[idx]->solveGenerateGrid();
620
621        // Read necessary value from file
622        this->data_in->readFieldAttributesValues(enabledFields[idx]);
623
624        // Fill attributes for base reference
625        enabledFields[idx]->solveGridDomainAxisBaseRef();
626     }
627
628     // Now everything is ok, close it
629     close();
630   }
631
632
633   /*!
634   \brief Parse xml file and write information into file object
635   \param [in] node xmld node corresponding in xml file
636   */
637   void CFile::parse(xml::CXMLNode & node)
638   {
639      SuperClass::parse(node);
640
641      if (node.goToChildElement())
642      {
643        do
644        {
645           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
646           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
647        } while (node.goToNextElement());
648        node.goToParentElement();
649      }
650
651   }
652   //----------------------------------------------------------------
653
654   /*!
655   \brief Represent a file in form of string with all its info
656   \return String
657   */
658   StdString CFile::toString(void) const
659   {
660      StdOStringStream oss;
661
662      oss << "<" << CFile::GetName() << " ";
663      if (this->hasId())
664         oss << " id=\"" << this->getId() << "\" ";
665      oss << SuperClassAttribute::toString() << ">" << std::endl;
666      if (this->getVirtualFieldGroup() != NULL)
667         oss << *this->getVirtualFieldGroup() << std::endl;
668      oss << "</" << CFile::GetName() << " >";
669      return (oss.str());
670   }
671
672   //----------------------------------------------------------------
673
674   /*!
675   \brief Find all inheritace among objects in a file.
676   \param [in] apply (true) write attributes of parent into ones of child if they are empty
677                     (false) write attributes of parent into a new container of child
678   \param [in] parent
679   */
680   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
681   {
682      SuperClassAttribute::setAttributes(parent,apply);
683      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
684      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
685   }
686
687   //----------------------------------------------------------------
688
689   /*!
690   \brief Resolve all reference of active fields.
691      In order to know exactly which data each active field has, a search for all its
692   reference to find its parents or/and its base reference object must be done. Moreover
693   during this search, there are some information that can only be sent to server AFTER
694   all information of active fields are created on server side, e.g: checking mask or index
695   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
696   */
697   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
698   {
699     int size = this->enabledFields.size();
700     for (int i = 0; i < size; ++i)
701     {
702       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
703//       this->enabledFields[i]->buildGridTransformationGraph();
704     }
705   }
706
707   void CFile::generateNewTransformationGridDest()
708   {
709     int size = this->enabledFields.size();
710     for (int i = 0; i < size; ++i)
711     {
712       this->enabledFields[i]->generateNewTransformationGridDest();
713     }
714   }
715
716   /*!
717   \brief Resolve all reference of active fields.
718      In order to know exactly which data each active field has, a search for all its
719   reference to find its parents or/and its base reference object must be done. Moreover
720   during this search, there are some information that can only be sent to server AFTER
721   all information of active fields are created on server side, e.g: checking mask or index
722   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
723   */
724   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
725   {
726     int size = this->enabledFields.size();
727     for (int i = 0; i < size; ++i)
728     {
729       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
730     }
731   }
732
733   /*!
734    * Constructs the filter graph for each active field.
735    *
736    * \param gc the garbage collector to use when building the filter graph
737    */
738   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
739   {
740     int size = this->enabledFields.size();
741     for (int i = 0; i < size; ++i)
742     {
743       this->enabledFields[i]->buildFilterGraph(gc, true);
744     }
745   }
746
747   /*!
748     Prefetching the data for enabled fields read from file.
749   */
750   void CFile::prefetchEnabledReadModeFields(void)
751   {
752     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
753       return;
754
755     int size = this->enabledFields.size();
756     for (int i = 0; i < size; ++i)
757       this->enabledFields[i]->sendReadDataRequest();
758   }
759
760   /*!
761     Prefetching the data for enabled fields read from file whose data is out-of-date.
762   */
763   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
764   {
765     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
766       return;
767
768     int size = this->enabledFields.size();
769     for (int i = 0; i < size; ++i)
770       this->enabledFields[i]->sendReadDataRequestIfNeeded();
771   }
772
773   void CFile::solveFieldRefInheritance(bool apply)
774   {
775      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
776      std::vector<CField*> allF = this->getAllFields();
777      for (unsigned int i = 0; i < allF.size(); i++)
778         allF[i]->solveRefInheritance(apply);
779   }
780
781   //----------------------------------------------------------------
782
783   /*!
784   \brief Add a field into file.
785      A field is added into file and it will be written out if the file is enabled and
786   level of this field is smaller than level_output. A new field won't be created if one
787   with id has already existed
788   \param [in] id String identity of new field
789   \return Pointer to added (or already existed) field
790   */
791   CField* CFile::addField(const string& id)
792   {
793     return vFieldGroup->createChild(id);
794   }
795
796   /*!
797   \brief Add a field group into file.
798      A field group is added into file and it will play a role as parents for fields.
799   A new field group won't be created if one with id has already existed
800   \param [in] id String identity of new field group
801   \return Pointer to added (or already existed) field group
802   */
803   CFieldGroup* CFile::addFieldGroup(const string& id)
804   {
805     return vFieldGroup->createChildGroup(id);
806   }
807
808   /*!
809   \brief Add a variable into file.
810      A variable is added into file and if one with id has already existed, pointer to
811   it will be returned.
812      Variable as long as attributes are information container of file.
813   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
814   to fill in (extra) information for a file.
815   \param [in] id String identity of new variable
816   \return Pointer to added (or already existed) variable
817   */
818   CVariable* CFile::addVariable(const string& id)
819   {
820     return vVariableGroup->createChild(id);
821   }
822
823   /*!
824   \brief Add a variable group into file.
825      A variable group is added into file and it will play a role as parents for variables.
826   A new variable group won't be created if one with id has already existed
827   \param [in] id String identity of new variable group
828   \return Pointer to added (or already existed) variable group
829   */
830   CVariableGroup* CFile::addVariableGroup(const string& id)
831   {
832     return vVariableGroup->createChildGroup(id);
833   }
834
835   /*!
836   \brief Send a message to create a field on server side
837   \param[in] id String identity of field that will be created on server
838   */
839   void CFile::sendAddField(const string& id)
840   {
841    CContext* context = CContext::getCurrent();
842
843    if (! context->hasServer )
844    {
845       CContextClient* client = context->client;
846
847       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
848       if (client->isServerLeader())
849       {
850         CMessage msg;
851         msg << this->getId();
852         msg << id;
853         const std::list<int>& ranks = client->getRanksServerLeader();
854         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
855           event.push(*itRank,1,msg);
856         client->sendEvent(event);
857       }
858       else client->sendEvent(event);
859    }
860
861   }
862
863   /*!
864   \brief Send a message to create a field group on server side
865   \param[in] id String identity of field group that will be created on server
866   */
867   void CFile::sendAddFieldGroup(const string& id)
868   {
869    CContext* context = CContext::getCurrent();
870    if (! context->hasServer )
871    {
872       CContextClient* client = context->client;
873
874       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
875       if (client->isServerLeader())
876       {
877         CMessage msg;
878         msg << this->getId();
879         msg << id;
880         const std::list<int>& ranks = client->getRanksServerLeader();
881         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
882           event.push(*itRank,1,msg);
883         client->sendEvent(event);
884       }
885       else client->sendEvent(event);
886    }
887
888   }
889
890   /*!
891   \brief Receive a message annoucing the creation of a field on server side
892   \param[in] event Received event
893   */
894   void CFile::recvAddField(CEventServer& event)
895   {
896
897      CBufferIn* buffer = event.subEvents.begin()->buffer;
898      string id;
899      *buffer>>id;
900      get(id)->recvAddField(*buffer);
901   }
902
903   /*!
904   \brief Receive a message annoucing the creation of a field on server side
905   \param[in] buffer Buffer containing message
906   */
907   void CFile::recvAddField(CBufferIn& buffer)
908   {
909      string id;
910      buffer>>id;
911      addField(id);
912   }
913
914   /*!
915   \brief Receive a message annoucing the creation of a field group on server side
916   \param[in] event Received event
917   */
918   void CFile::recvAddFieldGroup(CEventServer& event)
919   {
920
921      CBufferIn* buffer = event.subEvents.begin()->buffer;
922      string id;
923      *buffer>>id;
924      get(id)->recvAddFieldGroup(*buffer);
925   }
926
927   /*!
928   \brief Receive a message annoucing the creation of a field group on server side
929   \param[in] buffer Buffer containing message
930   */
931   void CFile::recvAddFieldGroup(CBufferIn& buffer)
932   {
933      string id;
934      buffer>>id;
935      addFieldGroup(id);
936   }
937
938   /*!
939   \brief Send messages to duplicate all variables on server side
940      Because each variable has also its attributes. So first thing to do is replicate
941   all these attributes on server side. Because variable can have a value, the second thing
942   is to duplicate this value on server, too.
943   */
944   void CFile::sendAddAllVariables()
945   {
946     if (!getAllVariables().empty())
947     {
948       // Firstly, it's necessary to add virtual variable group
949       sendAddVariableGroup(getVirtualVariableGroup()->getId());
950
951       // Okie, now we can add to this variable group
952       std::vector<CVariable*> allVar = getAllVariables();
953       std::vector<CVariable*>::const_iterator it = allVar.begin();
954       std::vector<CVariable*>::const_iterator itE = allVar.end();
955
956       for (; it != itE; ++it)
957       {
958         this->sendAddVariable((*it)->getId());
959         (*it)->sendAllAttributesToServer();
960         (*it)->sendValue();
961       }
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.