source: XIOS/dev/branch_openmp/src/node/file.cpp @ 1338

Last change on this file since 1338 was 1338, checked in by yushan, 6 years ago

dev_omp

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