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

Last change on this file since 895 was 878, checked in by oabramkina, 8 years ago

Sequential version for UGRID norms. File attribute "convention" has been added with two possible values "CF" and "UGRID". The default value is "CF".

  • 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.4 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 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         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                 
373         pos1=filename.find(strStartDate) ;
374         if (pos1!=std::string::npos)
375         {
376           firstPart=filename.substr(0,pos1) ;
377           pos1+=strStartDate.size() ;
378           hasStartDate=true ;
379         }
380         else pos1=0 ;
381
382         pos2=filename.find(strEndDate,pos1) ;
383         if (pos2!=std::string::npos)
384         {
385           middlePart=filename.substr(pos1,pos2-pos1) ;
386           cout<<pos2<<endl ;
387           pos2+=strEndDate.size() ;
388           lastPart=filename.substr(pos2,filename.size()-pos2) ;
389           hasEndDate=true ;
390         }
391         else middlePart=filename.substr(pos1,filename.size()) ;
392
393         if (!hasStartDate && !hasEndDate)
394         {
395           hasStartDate=true ;
396           hasEndDate=true;
397           firstPart=middlePart ;
398           middlePart="-" ;
399         }
400//   
401         StdOStringStream oss;
402
403         if (!split_freq.isEmpty())
404         {
405           CDate splitEnd = lastSplit + split_freq - 1 * Second;
406
407           string splitFormat;
408           if (split_freq_format.isEmpty())
409           {
410             if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
411             else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
412             else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
413             else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
414             else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
415             else splitFormat = "%y";
416           }
417           else splitFormat = split_freq_format;
418
419           oss << firstPart ;
420           if (hasStartDate) oss << lastSplit.getStr(splitFormat) ;
421           oss << middlePart ;
422           if (hasEndDate) oss << splitEnd.getStr(splitFormat);
423           oss << lastPart ;
424
425           context->registryOut->setKey("splitStart", lastSplit);
426           context->registryOut->setKey("splitEnd",   splitEnd);
427         }
428         else oss<<firstPart<<lastPart ;
429
430        bool append = !this->append.isEmpty() && this->append.getValue();
431
432         bool useClassicFormat = !format.isEmpty() && format == format_attr::netcdf4_classic;
433         bool useCFConvention = convention.isEmpty() || convention == convention_attr::CF;
434
435         bool multifile = true;
436         if (!type.isEmpty())
437         {
438           if (type == type_attr::one_file) multifile = false;
439           else if (type == type_attr::multiple_file) multifile = true;
440
441         }
442#ifndef USING_NETCDF_PAR
443         if (!multifile)
444         {
445            info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
446            multifile = true;
447          }
448#endif
449         if (multifile)
450         {
451            int commSize, commRank;
452            MPI_Comm_size(fileComm, &commSize);
453            MPI_Comm_rank(fileComm, &commRank);
454
455            if (server->intraCommSize > 1)
456            {
457              oss << "_" ;
458              int width=0; int n = commSize-1;
459              while (n != 0) { n = n / 10; width++;}
460              if (!min_digits.isEmpty())
461                if (width < min_digits) width = min_digits;
462              oss.width(width);
463              oss.fill('0');
464              oss << right << commRank;
465            }
466         }
467         oss << ".nc";
468
469         bool isCollective = par_access.isEmpty() ||  par_access == par_access_attr::collective;
470
471         if (isOpen) data_out->closeFile();
472
473        data_out = shared_ptr<CDataOutput>(new CNc4DataOutput(oss.str(), append, useClassicFormat, useCFConvention,
474                                                              fileComm, multifile, isCollective, time_counter_name));
475        isOpen = true;
476
477        data_out->writeFile(CFile::get(this));
478
479        // Do not recreate the file structure if opening an existing file
480        if (!data_out->IsInAppendMode())
481        {
482          std::vector<CField*>::iterator it, end = this->enabledFields.end();
483          for (it = this->enabledFields.begin(); it != end; it++)
484          {
485            CField* field = *it;
486            this->data_out->writeFieldGrid(field);
487          }
488          this->data_out->writeTimeDimension();
489
490          for (it = this->enabledFields.begin(); it != end; it++)
491          {
492            CField* field = *it;
493            this->data_out->writeField(field);
494          }
495
496          vector<CVariable*> listVars = getAllVariables();
497          for (vector<CVariable*>::iterator it = listVars.begin(); it != listVars.end(); it++)
498            this->data_out->writeAttribute(*it);
499
500          this->data_out->definition_end();
501        }
502      }
503   }
504
505  /*!
506  \brief Open an existing NetCDF file in read-only mode
507  */
508  void CFile::openInReadMode(void)
509  {
510    CContext* context = CContext::getCurrent();
511    CContextServer* server = context->server;
512
513    if (!allDomainEmpty)
514    {
515      StdString filename = getFileOutputName();
516      StdOStringStream oss;
517      oss << filename;
518      if (!name_suffix.isEmpty()) oss << name_suffix.getValue();
519
520      if (!split_freq.isEmpty())
521      {
522        string splitFormat;
523        if (split_freq_format.isEmpty())
524        {
525          if (split_freq.getValue().second != 0) splitFormat = "%y%mo%d%h%mi%s";
526          else if (split_freq.getValue().minute != 0) splitFormat = "%y%mo%d%h%mi";
527          else if (split_freq.getValue().hour != 0) splitFormat = "%y%mo%d%h";
528          else if (split_freq.getValue().day != 0) splitFormat = "%y%mo%d";
529          else if (split_freq.getValue().month != 0) splitFormat = "%y%mo";
530          else splitFormat = "%y";
531        }
532        else splitFormat = split_freq_format;
533        oss << "_" << lastSplit.getStr(splitFormat)
534        << "-" << (lastSplit + split_freq.getValue() - 1 * Second).getStr(splitFormat);
535      }
536
537      bool multifile = true;
538      if (!type.isEmpty())
539      {
540        if (type == type_attr::one_file) multifile = false;
541        else if (type == type_attr::multiple_file) multifile = true;
542      }
543  #ifndef USING_NETCDF_PAR
544      if (!multifile)
545      {
546        info(0) << "!!! Warning -> Using non parallel version of netcdf, switching in multiple_file mode for file : " << filename << " ..." << endl;
547        multifile = true;
548      }
549  #endif
550      if (multifile)
551      {
552        int commSize, commRank;
553        MPI_Comm_size(fileComm, &commSize);
554        MPI_Comm_rank(fileComm, &commRank);
555
556        if (server->intraCommSize > 1)
557        {
558          oss << "_";
559          int width = 0, n = commSize - 1;
560          while (n != 0) { n = n / 10; width++; }
561          if (!min_digits.isEmpty() && width < min_digits)
562            width = min_digits;
563          oss.width(width);
564          oss.fill('0');
565          oss << right << commRank;
566        }
567      }
568      oss << ".nc";
569
570      bool isCollective = par_access.isEmpty() || par_access == par_access_attr::collective;
571
572      if (isOpen) data_out->closeFile();
573      if (time_counter_name.isEmpty()) data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective));
574      else data_in = shared_ptr<CDataInput>(new CNc4DataInput(oss.str(), fileComm, multifile, isCollective, time_counter_name));
575      isOpen = true;
576    }
577  }
578
579   //! Close file
580   void CFile::close(void)
581   {
582     if (!allDomainEmpty)
583       if (isOpen)
584       {
585         if (mode.isEmpty() || mode.getValue() == mode_attr::write)
586          this->data_out->closeFile();
587         else
588          this->data_in->closeFile();
589       }
590      if (fileComm != MPI_COMM_NULL) MPI_Comm_free(&fileComm);
591   }
592   //----------------------------------------------------------------
593
594   void CFile::readAttributesOfEnabledFieldsInReadMode()
595   {
596     if (enabledFields.empty()) return;
597
598     // Just check file and try to open it
599     CContext* context = CContext::getCurrent();
600     CContextClient* client=context->client;
601
602     // It would probably be better to call initFile() somehow
603     MPI_Comm_dup(client->intraComm, &fileComm);
604     if (time_counter_name.isEmpty()) time_counter_name = "time_counter";
605
606     checkFile();
607
608     for (int idx = 0; idx < enabledFields.size(); ++idx)
609     {
610        // First of all, find out which domain and axis associated with this field
611        enabledFields[idx]->solveGridReference();
612
613        // Read attributes of domain and axis from this file
614        this->data_in->readFieldAttributesMetaData(enabledFields[idx]);
615
616        // Now complete domain and axis associated with this field
617        enabledFields[idx]->solveGenerateGrid();
618
619        // Read necessary value from file
620        this->data_in->readFieldAttributesValues(enabledFields[idx]);
621
622        // Fill attributes for base reference
623        enabledFields[idx]->solveGridDomainAxisBaseRef();
624     }
625
626     // Now everything is ok, close it
627     close();
628   }
629
630
631   /*!
632   \brief Parse xml file and write information into file object
633   \param [in] node xmld node corresponding in xml file
634   */
635   void CFile::parse(xml::CXMLNode & node)
636   {
637      SuperClass::parse(node);
638
639      if (node.goToChildElement())
640      {
641        do
642        {
643           if (node.getElementName()=="field" || node.getElementName()=="field_group") this->getVirtualFieldGroup()->parseChild(node);
644           else if (node.getElementName()=="variable" || node.getElementName()=="variable_group") this->getVirtualVariableGroup()->parseChild(node);
645        } while (node.goToNextElement());
646        node.goToParentElement();
647      }
648
649   }
650   //----------------------------------------------------------------
651
652   /*!
653   \brief Represent a file in form of string with all its info
654   \return String
655   */
656   StdString CFile::toString(void) const
657   {
658      StdOStringStream oss;
659
660      oss << "<" << CFile::GetName() << " ";
661      if (this->hasId())
662         oss << " id=\"" << this->getId() << "\" ";
663      oss << SuperClassAttribute::toString() << ">" << std::endl;
664      if (this->getVirtualFieldGroup() != NULL)
665         oss << *this->getVirtualFieldGroup() << std::endl;
666      oss << "</" << CFile::GetName() << " >";
667      return (oss.str());
668   }
669
670   //----------------------------------------------------------------
671
672   /*!
673   \brief Find all inheritace among objects in a file.
674   \param [in] apply (true) write attributes of parent into ones of child if they are empty
675                     (false) write attributes of parent into a new container of child
676   \param [in] parent
677   */
678   void CFile::solveDescInheritance(bool apply, const CAttributeMap * const parent)
679   {
680      SuperClassAttribute::setAttributes(parent,apply);
681      this->getVirtualFieldGroup()->solveDescInheritance(apply, NULL);
682      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
683   }
684
685   //----------------------------------------------------------------
686
687   /*!
688   \brief Resolve all reference of active fields.
689      In order to know exactly which data each active field has, a search for all its
690   reference to find its parents or/and its base reference object must be done. Moreover
691   during this search, there are some information that can only be sent to server AFTER
692   all information of active fields are created on server side, e.g: checking mask or index
693   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
694   */
695   void CFile::solveOnlyRefOfEnabledFields(bool sendToServer)
696   {
697     int size = this->enabledFields.size();
698     for (int i = 0; i < size; ++i)
699     {
700       this->enabledFields[i]->solveOnlyReferenceEnabledField(sendToServer);
701//       this->enabledFields[i]->buildGridTransformationGraph();
702     }
703   }
704
705   void CFile::generateNewTransformationGridDest()
706   {
707     int size = this->enabledFields.size();
708     for (int i = 0; i < size; ++i)
709     {
710       this->enabledFields[i]->generateNewTransformationGridDest();
711     }
712   }
713
714   /*!
715   \brief Resolve all reference of active fields.
716      In order to know exactly which data each active field has, a search for all its
717   reference to find its parents or/and its base reference object must be done. Moreover
718   during this search, there are some information that can only be sent to server AFTER
719   all information of active fields are created on server side, e.g: checking mask or index
720   \param [in] sendToServer: Send all info to server (true) or only a part of it (false)
721   */
722   void CFile::solveAllRefOfEnabledFields(bool sendToServer)
723   {
724     int size = this->enabledFields.size();
725     for (int i = 0; i < size; ++i)
726     {
727       this->enabledFields[i]->solveAllReferenceEnabledField(sendToServer);
728     }
729   }
730
731   /*!
732    * Constructs the filter graph for each active field.
733    *
734    * \param gc the garbage collector to use when building the filter graph
735    */
736   void CFile::buildFilterGraphOfEnabledFields(CGarbageCollector& gc)
737   {
738     int size = this->enabledFields.size();
739     for (int i = 0; i < size; ++i)
740     {
741       this->enabledFields[i]->buildFilterGraph(gc, true);
742     }
743   }
744
745   /*!
746     Prefetching the data for enabled fields read from file.
747   */
748   void CFile::prefetchEnabledReadModeFields(void)
749   {
750     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
751       return;
752
753     int size = this->enabledFields.size();
754     for (int i = 0; i < size; ++i)
755       this->enabledFields[i]->sendReadDataRequest();
756   }
757
758   /*!
759     Prefetching the data for enabled fields read from file whose data is out-of-date.
760   */
761   void CFile::prefetchEnabledReadModeFieldsIfNeeded(void)
762   {
763     if (mode.isEmpty() || mode.getValue() != mode_attr::read)
764       return;
765
766     int size = this->enabledFields.size();
767     for (int i = 0; i < size; ++i)
768       this->enabledFields[i]->sendReadDataRequestIfNeeded();
769   }
770
771   void CFile::solveFieldRefInheritance(bool apply)
772   {
773      // Rsolution des hritages par rfrence de chacun des champs contenus dans le fichier.
774      std::vector<CField*> allF = this->getAllFields();
775      for (unsigned int i = 0; i < allF.size(); i++)
776         allF[i]->solveRefInheritance(apply);
777   }
778
779   //----------------------------------------------------------------
780
781   /*!
782   \brief Add a field into file.
783      A field is added into file and it will be written out if the file is enabled and
784   level of this field is smaller than level_output. A new field won't be created if one
785   with id has already existed
786   \param [in] id String identity of new field
787   \return Pointer to added (or already existed) field
788   */
789   CField* CFile::addField(const string& id)
790   {
791     return vFieldGroup->createChild(id);
792   }
793
794   /*!
795   \brief Add a field group into file.
796      A field group is added into file and it will play a role as parents for fields.
797   A new field group won't be created if one with id has already existed
798   \param [in] id String identity of new field group
799   \return Pointer to added (or already existed) field group
800   */
801   CFieldGroup* CFile::addFieldGroup(const string& id)
802   {
803     return vFieldGroup->createChildGroup(id);
804   }
805
806   /*!
807   \brief Add a variable into file.
808      A variable is added into file and if one with id has already existed, pointer to
809   it will be returned.
810      Variable as long as attributes are information container of file.
811   However, whereas attributes are "fixed" information, variables provides a more flexible way to user
812   to fill in (extra) information for a file.
813   \param [in] id String identity of new variable
814   \return Pointer to added (or already existed) variable
815   */
816   CVariable* CFile::addVariable(const string& id)
817   {
818     return vVariableGroup->createChild(id);
819   }
820
821   /*!
822   \brief Add a variable group into file.
823      A variable group is added into file and it will play a role as parents for variables.
824   A new variable group won't be created if one with id has already existed
825   \param [in] id String identity of new variable group
826   \return Pointer to added (or already existed) variable group
827   */
828   CVariableGroup* CFile::addVariableGroup(const string& id)
829   {
830     return vVariableGroup->createChildGroup(id);
831   }
832
833   /*!
834   \brief Send a message to create a field on server side
835   \param[in] id String identity of field that will be created on server
836   */
837   void CFile::sendAddField(const string& id)
838   {
839    CContext* context = CContext::getCurrent();
840
841    if (! context->hasServer )
842    {
843       CContextClient* client = context->client;
844
845       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD);
846       if (client->isServerLeader())
847       {
848         CMessage msg;
849         msg << this->getId();
850         msg << id;
851         const std::list<int>& ranks = client->getRanksServerLeader();
852         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
853           event.push(*itRank,1,msg);
854         client->sendEvent(event);
855       }
856       else client->sendEvent(event);
857    }
858
859   }
860
861   /*!
862   \brief Send a message to create a field group on server side
863   \param[in] id String identity of field group that will be created on server
864   */
865   void CFile::sendAddFieldGroup(const string& id)
866   {
867    CContext* context = CContext::getCurrent();
868    if (! context->hasServer )
869    {
870       CContextClient* client = context->client;
871
872       CEventClient event(this->getType(),EVENT_ID_ADD_FIELD_GROUP);
873       if (client->isServerLeader())
874       {
875         CMessage msg;
876         msg << this->getId();
877         msg << id;
878         const std::list<int>& ranks = client->getRanksServerLeader();
879         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
880           event.push(*itRank,1,msg);
881         client->sendEvent(event);
882       }
883       else client->sendEvent(event);
884    }
885
886   }
887
888   /*!
889   \brief Receive a message annoucing the creation of a field on server side
890   \param[in] event Received event
891   */
892   void CFile::recvAddField(CEventServer& event)
893   {
894
895      CBufferIn* buffer = event.subEvents.begin()->buffer;
896      string id;
897      *buffer>>id;
898      get(id)->recvAddField(*buffer);
899   }
900
901   /*!
902   \brief Receive a message annoucing the creation of a field on server side
903   \param[in] buffer Buffer containing message
904   */
905   void CFile::recvAddField(CBufferIn& buffer)
906   {
907      string id;
908      buffer>>id;
909      addField(id);
910   }
911
912   /*!
913   \brief Receive a message annoucing the creation of a field group on server side
914   \param[in] event Received event
915   */
916   void CFile::recvAddFieldGroup(CEventServer& event)
917   {
918
919      CBufferIn* buffer = event.subEvents.begin()->buffer;
920      string id;
921      *buffer>>id;
922      get(id)->recvAddFieldGroup(*buffer);
923   }
924
925   /*!
926   \brief Receive a message annoucing the creation of a field group on server side
927   \param[in] buffer Buffer containing message
928   */
929   void CFile::recvAddFieldGroup(CBufferIn& buffer)
930   {
931      string id;
932      buffer>>id;
933      addFieldGroup(id);
934   }
935
936   /*!
937   \brief Send messages to duplicate all variables on server side
938      Because each variable has also its attributes. So first thing to do is replicate
939   all these attributes on server side. Because variable can have a value, the second thing
940   is to duplicate this value on server, too.
941   */
942   void CFile::sendAddAllVariables()
943   {
944     if (!getAllVariables().empty())
945     {
946       // Firstly, it's necessary to add virtual variable group
947       sendAddVariableGroup(getVirtualVariableGroup()->getId());
948
949       // Okie, now we can add to this variable group
950       std::vector<CVariable*> allVar = getAllVariables();
951       std::vector<CVariable*>::const_iterator it = allVar.begin();
952       std::vector<CVariable*>::const_iterator itE = allVar.end();
953
954       for (; it != itE; ++it)
955       {
956         this->sendAddVariable((*it)->getId());
957         (*it)->sendAllAttributesToServer();
958         (*it)->sendValue();
959       }
960     }
961   }
962
963   /*!
964   \brief Send a message to create a variable on server side
965      A variable always belongs to a variable group
966   \param[in] id String identity of variable that will be created on server
967   */
968   void CFile::sendAddVariable(const string& id)
969   {
970    CContext* context = CContext::getCurrent();
971
972    if (! context->hasServer )
973    {
974       CContextClient* client = context->client;
975
976       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
977       if (client->isServerLeader())
978       {
979         CMessage msg;
980         msg << this->getId();
981         msg << id;
982         const std::list<int>& ranks = client->getRanksServerLeader();
983         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
984           event.push(*itRank,1,msg);
985         client->sendEvent(event);
986       }
987       else client->sendEvent(event);
988    }
989
990   }
991
992   /*!
993   \brief Send a message to create a variable group on server side
994   \param[in] id String identity of variable group that will be created on server
995   */
996   void CFile::sendAddVariableGroup(const string& id)
997   {
998    CContext* context = CContext::getCurrent();
999    if (! context->hasServer )
1000    {
1001       CContextClient* client = context->client;
1002
1003       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
1004       if (client->isServerLeader())
1005       {
1006         CMessage msg;
1007         msg << this->getId();
1008         msg << id;
1009         const std::list<int>& ranks = client->getRanksServerLeader();
1010         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
1011           event.push(*itRank,1,msg);
1012         client->sendEvent(event);
1013       }
1014       else client->sendEvent(event);
1015    }
1016
1017   }
1018
1019   /*!
1020   \brief Receive a message annoucing the creation of a variable on server side
1021   \param[in] event Received event
1022   */
1023   void CFile::recvAddVariable(CEventServer& event)
1024   {
1025
1026      CBufferIn* buffer = event.subEvents.begin()->buffer;
1027      string id;
1028      *buffer>>id;
1029      get(id)->recvAddVariable(*buffer);
1030   }
1031
1032   /*!
1033   \brief Receive a message annoucing the creation of a variable on server side
1034   \param[in] buffer Buffer containing message
1035   */
1036   void CFile::recvAddVariable(CBufferIn& buffer)
1037   {
1038      string id;
1039      buffer>>id;
1040      addVariable(id);
1041   }
1042
1043   /*!
1044   \brief Receive a message annoucing the creation of a variable group on server side
1045   \param[in] event Received event
1046   */
1047   void CFile::recvAddVariableGroup(CEventServer& event)
1048   {
1049
1050      CBufferIn* buffer = event.subEvents.begin()->buffer;
1051      string id;
1052      *buffer>>id;
1053      get(id)->recvAddVariableGroup(*buffer);
1054   }
1055
1056   /*!
1057   \brief Receive a message annoucing the creation of a variable group on server side
1058   \param[in] buffer Buffer containing message
1059   */
1060   void CFile::recvAddVariableGroup(CBufferIn& buffer)
1061   {
1062      string id;
1063      buffer>>id;
1064      addVariableGroup(id);
1065   }
1066
1067   /*!
1068     \brief Sending all active (enabled) fields from client to server.
1069   Each field is identified uniquely by its string identity. Not only should we
1070   send the id to server but also we need to send ids of reference domain and reference axis.
1071   With these two id, it's easier to make reference to grid where all data should be written.
1072   Remark: This function must be called AFTER all active (enabled) files have been created on the server side
1073   */
1074   void CFile::sendEnabledFields()
1075   {
1076     size_t size = this->enabledFields.size();
1077     for (size_t i = 0; i < size; ++i)
1078     {
1079       CField* field = this->enabledFields[i];
1080       this->sendAddField(field->getId());
1081       field->sendAllAttributesToServer();
1082       field->sendAddAllVariables();
1083     }
1084   }
1085
1086   /*!
1087   \brief Dispatch event received from client
1088      Whenever a message is received in buffer of server, it will be processed depending on
1089   its event type. A new event type should be added in the switch list to make sure
1090   it processed on server side.
1091   \param [in] event: Received message
1092   */
1093   bool CFile::dispatchEvent(CEventServer& event)
1094   {
1095      if (SuperClass::dispatchEvent(event)) return true;
1096      else
1097      {
1098        switch(event.type)
1099        {
1100           case EVENT_ID_ADD_FIELD :
1101             recvAddField(event);
1102             return true;
1103             break;
1104
1105           case EVENT_ID_ADD_FIELD_GROUP :
1106             recvAddFieldGroup(event);
1107             return true;
1108             break;
1109
1110            case EVENT_ID_ADD_VARIABLE :
1111             recvAddVariable(event);
1112             return true;
1113             break;
1114
1115           case EVENT_ID_ADD_VARIABLE_GROUP :
1116             recvAddVariableGroup(event);
1117             return true;
1118             break;
1119           default :
1120              ERROR("bool CFile::dispatchEvent(CEventServer& event)", << "Unknown Event");
1121           return false;
1122        }
1123      }
1124   }
1125
1126
1127
1128
1129   ///---------------------------------------------------------------
1130
1131} // namespace xios
Note: See TracBrowser for help on using the repository browser.