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

Last change on this file since 876 was 876, checked in by ymipsl, 5 years ago

Remove some debug output

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