source: XIOS/dev/dev_olga/src/node/file.cpp @ 1099

Last change on this file since 1099 was 1071, checked in by oabramkina, 7 years ago

dev: test for secondary servers added.

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