source: XIOS/dev/branch_yushan/src/node/file.cpp @ 1037

Last change on this file since 1037 was 1037, checked in by yushan, 7 years ago

initialize the branch

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