source: XIOS/trunk/src/node/field.cpp @ 676

Last change on this file since 676 was 676, checked in by rlacroix, 6 years ago

Add support for indexed output.

If the new field attribute "indexed_output" is set to true and a mask is defined (either at grid, domain or axis level), the indexed data will be outputed instead of the full data with missing values.

See http://cfconventions.org/Data/cf-conventions/cf-conventions-1.5/build/cf-conventions.html#compression-by-gathering for more information.

  • 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
  • Property svn:executable set to *
File size: 31.0 KB
Line 
1#include "field.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6
7#include "node_type.hpp"
8#include "calendar_util.hpp"
9#include "message.hpp"
10#include "xios_spl.hpp"
11#include "type.hpp"
12#include "timer.hpp"
13#include "context_client.hpp"
14#include "context_server.hpp"
15#include <set>
16#include "garbage_collector.hpp"
17#include "source_filter.hpp"
18#include "store_filter.hpp"
19#include "file_writer_filter.hpp"
20#include "pass_through_filter.hpp"
21#include "filter_expr_node.hpp"
22#include "lex_parser.hpp"
23#include "temporal_filter.hpp"
24#include "spatial_transform_filter.hpp"
25
26namespace xios{
27
28   /// ////////////////////// Définitions ////////////////////// ///
29
30   CField::CField(void)
31      : CObjectTemplate<CField>(), CFieldAttributes()
32      , refObject(), baseRefObject()
33      , grid(), file()
34      , nstep(0), nstepMax(0)
35      , hasOutputFile(false)
36      , domAxisIds_("", ""), areAllReferenceSolved(false)
37      , useCompressedOutput(false)
38      , isReadDataRequestPending(false)
39   { setVirtualVariableGroup(); }
40
41   CField::CField(const StdString& id)
42      : CObjectTemplate<CField>(id), CFieldAttributes()
43      , refObject(), baseRefObject()
44      , grid(), file()
45      , nstep(0), nstepMax(0)
46      , hasOutputFile(false)
47      , domAxisIds_("", ""), areAllReferenceSolved(false)
48      , useCompressedOutput(false)
49      , isReadDataRequestPending(false)
50   { setVirtualVariableGroup(); }
51
52   CField::~CField(void)
53   {}
54
55  //----------------------------------------------------------------
56
57   void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
58   {
59      this->vVariableGroup = newVVariableGroup;
60   }
61
62   void CField::setVirtualVariableGroup(void)
63   {
64      this->setVirtualVariableGroup(CVariableGroup::create());
65   }
66
67   CVariableGroup* CField::getVirtualVariableGroup(void) const
68   {
69      return this->vVariableGroup;
70   }
71
72
73   std::vector<CVariable*> CField::getAllVariables(void) const
74   {
75      return this->vVariableGroup->getAllChildren();
76   }
77
78   void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
79   {
80      SuperClassAttribute::setAttributes(parent, apply);
81      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
82   }
83
84  //----------------------------------------------------------------
85
86  bool CField::dispatchEvent(CEventServer& event)
87  {
88    if (SuperClass::dispatchEvent(event)) return true;
89    else
90    {
91      switch(event.type)
92      {
93        case EVENT_ID_UPDATE_DATA :
94          recvUpdateData(event);
95          return true;
96          break;
97
98        case EVENT_ID_READ_DATA :
99          recvReadDataRequest(event);
100          return true;
101          break;
102
103        case EVENT_ID_READ_DATA_READY :
104          recvReadDataReady(event);
105          return true;
106          break;
107
108        case EVENT_ID_ADD_VARIABLE :
109          recvAddVariable(event);
110          return true;
111          break;
112
113        case EVENT_ID_ADD_VARIABLE_GROUP :
114          recvAddVariableGroup(event);
115          return true;
116          break;
117
118        default :
119          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
120          return false;
121      }
122    }
123  }
124
125  void CField::sendUpdateData(const CArray<double,1>& data)
126  {
127    CTimer::get("XIOS Send Data").resume();
128
129    CContext* context = CContext::getCurrent();
130    CContextClient* client = context->client;
131
132    CEventClient event(getType(), EVENT_ID_UPDATE_DATA);
133
134    map<int, CArray<int,1> >::iterator it;
135    list<CMessage> list_msg;
136    list<CArray<double,1> > list_data;
137
138    if (!grid->doGridHaveDataDistributed())
139    {
140       if (0 == client->clientRank)
141       {
142          for (it = grid->storeIndex_toSrv.begin(); it != grid->storeIndex_toSrv.end(); it++)
143          {
144            int rank = it->first;
145            CArray<int,1>& index = it->second;
146
147            list_msg.push_back(CMessage());
148            list_data.push_back(CArray<double,1>(index.numElements()));
149
150            CArray<double,1>& data_tmp = list_data.back();
151            for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
152
153            list_msg.back() << getId() << data_tmp;
154            event.push(rank, 1, list_msg.back());
155          }
156          client->sendEvent(event);
157       } else client->sendEvent(event);
158    }
159    else
160    {
161      for (it = grid->storeIndex_toSrv.begin(); it != grid->storeIndex_toSrv.end(); it++)
162      {
163        int rank = it->first;
164        CArray<int,1>& index = it->second;
165
166        list_msg.push_back(CMessage());
167        list_data.push_back(CArray<double,1>(index.numElements()));
168
169        CArray<double,1>& data_tmp = list_data.back();
170        for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
171
172        list_msg.back() << getId() << data_tmp;
173        event.push(rank, grid->nbSenders[rank], list_msg.back());
174      }
175      client->sendEvent(event);
176    }
177   
178    CTimer::get("XIOS Send Data").suspend();
179  }
180
181  void CField::recvUpdateData(CEventServer& event)
182  {
183    vector<int> ranks;
184    vector<CBufferIn*> buffers;
185
186    list<CEventServer::SSubEvent>::iterator it;
187    string fieldId;
188
189    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
190    {
191      int rank = it->rank;
192      CBufferIn* buffer = it->buffer;
193      *buffer >> fieldId;
194      ranks.push_back(rank);
195      buffers.push_back(buffer);
196    }
197    get(fieldId)->recvUpdateData(ranks,buffers);
198  }
199
200  void  CField::recvUpdateData(vector<int>& ranks, vector<CBufferIn*>& buffers)
201  {
202    if (data_srv.empty())
203    {
204      for (map<int, CArray<size_t, 1> >::iterator it = grid->outIndexFromClient.begin(); it != grid->outIndexFromClient.end(); ++it)
205      {
206        int rank = it->first;
207        data_srv.insert(std::make_pair(rank, CArray<double,1>(it->second.numElements())));
208        foperation_srv.insert(pair<int,boost::shared_ptr<func::CFunctor> >(rank,boost::shared_ptr<func::CFunctor>(new func::CInstant(data_srv[rank]))));
209      }
210    }
211
212    CContext* context = CContext::getCurrent();
213    const CDate& currDate = context->getCalendar()->getCurrentDate();
214    const CDate opeDate      = last_operation_srv + freq_operation_srv;
215    const CDate writeDate    = last_Write_srv     + freq_write_srv;
216
217    if (opeDate <= currDate)
218    {
219      for (int n = 0; n < ranks.size(); n++)
220      {
221        CArray<double,1> data_tmp;
222        *buffers[n] >> data_tmp;
223        (*foperation_srv[ranks[n]])(data_tmp);
224      }
225      last_operation_srv = currDate;
226    }
227
228    if (writeDate < (currDate + freq_operation_srv))
229    {
230      for (int n = 0; n < ranks.size(); n++)
231      {
232        this->foperation_srv[ranks[n]]->final();
233      }
234
235      last_Write_srv = writeDate;
236      writeField();
237      lastlast_Write_srv = last_Write_srv;
238    }
239  }
240
241  void CField::writeField(void)
242  {
243    if (!getRelFile()->allDomainEmpty)
244    {
245      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
246      {
247        getRelFile()->checkFile();
248        this->incrementNStep();
249        getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
250      }
251    }
252  }
253
254  void CField::sendReadDataRequest(void)
255  {
256    CContext* context = CContext::getCurrent();
257    CContextClient* client = context->client;
258
259    CEventClient event(getType(), EVENT_ID_READ_DATA);
260    if (client->isServerLeader())
261    {
262      CMessage msg;
263      msg << getId();
264      const std::list<int>& ranks = client->getRanksServerLeader();
265      for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
266        event.push(*itRank, 1, msg);
267      client->sendEvent(event);
268    }
269    else client->sendEvent(event);
270
271    lastDataRequestedFromServer = context->getCalendar()->getCurrentDate();
272    isReadDataRequestPending = true;
273  }
274
275  /*!
276  Send request new data read from file if need be, that is the current data is out-of-date.
277  \return true if and only if some data was requested
278  */
279  bool CField::sendReadDataRequestIfNeeded(void)
280  {
281    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
282
283    bool requestData = (currentDate >= lastDataRequestedFromServer + file->output_freq.getValue());
284
285    if (requestData)
286      sendReadDataRequest();
287
288    return requestData;
289  }
290
291  void CField::recvReadDataRequest(CEventServer& event)
292  {
293    CBufferIn* buffer = event.subEvents.begin()->buffer;
294    StdString fieldId;
295    *buffer >> fieldId;
296    get(fieldId)->recvReadDataRequest();
297  }
298
299  void CField::recvReadDataRequest(void)
300  {
301    CContext* context = CContext::getCurrent();
302    CContextClient* client = context->client;
303
304    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
305    std::list<CMessage> msgs;
306
307    bool hasData = readField();
308
309    map<int, CArray<double,1> >::iterator it;
310    for (it = data_srv.begin(); it != data_srv.end(); it++)
311    {
312      msgs.push_back(CMessage());
313      CMessage& msg = msgs.back();
314      msg << getId();
315      if (hasData)
316        msg << getNStep() - 1 << it->second;
317      else
318        msg << size_t(-1);
319      event.push(it->first, grid->nbSenders[it->first], msg);
320    }
321    client->sendEvent(event);
322  }
323
324  bool CField::readField(void)
325  {
326    if (!getRelFile()->allDomainEmpty)
327    {
328      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
329      {
330        if (data_srv.empty())
331        {
332          for (map<int, CArray<size_t, 1> >::iterator it = grid->outIndexFromClient.begin(); it != grid->outIndexFromClient.end(); ++it)
333            data_srv.insert(std::make_pair(it->first, CArray<double,1>(it->second.numElements())));
334        }
335
336        getRelFile()->checkFile();
337        this->incrementNStep();
338
339        if (!nstepMax)
340        {
341          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
342        }
343
344        if (getNStep() > nstepMax)
345          return false;
346
347        getRelFile()->getDataInput()->readFieldData(CField::get(this));
348      }
349    }
350
351    return true;
352  }
353
354  void CField::recvReadDataReady(CEventServer& event)
355  {
356    string fieldId;
357    vector<int> ranks;
358    vector<CBufferIn*> buffers;
359
360    list<CEventServer::SSubEvent>::iterator it;
361    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
362    {
363      ranks.push_back(it->rank);
364      CBufferIn* buffer = it->buffer;
365      *buffer >> fieldId;
366      buffers.push_back(buffer);
367    }
368    get(fieldId)->recvReadDataReady(ranks, buffers);
369  }
370
371  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
372  {
373    CContext* context = CContext::getCurrent();
374    StdSize record;
375    std::map<int, CArray<double,1> > data;
376
377    bool isEOF = false;
378
379    for (int i = 0; i < ranks.size(); i++)
380    {
381      int rank = ranks[i];
382      *buffers[i] >> record;
383      isEOF = (record == size_t(-1));
384
385      if (!isEOF)
386        *buffers[i] >> data[rank];
387      else
388        break;
389    }
390
391    if (isEOF)
392      serverSourceFilter->signalEndOfStream(lastDataRequestedFromServer);
393    else
394      serverSourceFilter->streamDataFromServer(lastDataRequestedFromServer, data);
395
396    isReadDataRequestPending = false;
397  }
398
399   //----------------------------------------------------------------
400
401   void CField::setRelFile(CFile* _file)
402   {
403      this->file = _file;
404      hasOutputFile = true;
405   }
406
407   //----------------------------------------------------------------
408
409   StdString CField::GetName(void)    { return StdString("field"); }
410   StdString CField::GetDefName(void) { return CField::GetName(); }
411   ENodeType CField::GetType(void)    { return eField; }
412
413   //----------------------------------------------------------------
414
415   CGrid* CField::getRelGrid(void) const
416   {
417      return this->grid;
418   }
419
420   //----------------------------------------------------------------
421
422   CFile* CField::getRelFile(void) const
423   {
424      return this->file;
425   }
426
427   StdSize CField::getNStep(void) const
428   {
429      return this->nstep;
430   }
431
432   func::CFunctor::ETimeType CField::getOperationTimeType() const
433   {
434     return operationTimeType;
435   }
436
437   //----------------------------------------------------------------
438
439   void CField::incrementNStep(void)
440   {
441      this->nstep++;
442   }
443
444   void CField::resetNStep(void)
445   {
446      this->nstep = 0;
447   }
448
449   void CField::resetNStepMax(void)
450   {
451      this->nstepMax = 0;
452   }
453
454   //----------------------------------------------------------------
455
456   bool CField::isActive(void) const
457   {
458      return !this->refObject.empty();
459   }
460
461   //----------------------------------------------------------------
462
463   bool CField::getUseCompressedOutput() const
464   {
465     return useCompressedOutput;
466   }
467
468   void CField::setUseCompressedOutput()
469   {
470     useCompressedOutput = true;
471   }
472
473   //----------------------------------------------------------------
474
475   boost::shared_ptr<COutputPin> CField::getInstantDataFilter()
476   {
477     return instantDataFilter;
478   }
479
480   //----------------------------------------------------------------
481
482   void CField::solveAllReferenceEnabledField(bool doSending2Sever)
483   {
484     CContext* context = CContext::getCurrent();
485     if (!areAllReferenceSolved)
486     {
487        areAllReferenceSolved = true;
488
489        if (context->hasClient)
490        {
491          solveRefInheritance(true);
492          solveBaseReference();
493          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
494        }
495        else if (context->hasServer)
496          solveServerOperation();
497
498        solveGridReference();
499     }
500     solveGridDomainAxisRef(doSending2Sever);
501     if (context->hasClient)
502     {
503       solveTransformedGrid();
504     }
505     solveCheckMaskIndex(doSending2Sever);
506   }
507
508   std::map<int, StdSize> CField::getGridDataSize()
509   {
510     return grid->getConnectedServerDataSize();
511   }
512
513   //----------------------------------------------------------------
514
515   void CField::solveServerOperation(void)
516   {
517      CContext* context = CContext::getCurrent();
518
519      if (!context->hasServer || !hasOutputFile) return;
520
521      if (freq_op.isEmpty())
522        freq_op.setValue(TimeStep);
523
524      if (freq_offset.isEmpty())
525        freq_offset.setValue(NoneDu);
526
527      freq_operation_srv = file->output_freq.getValue();
528      freq_write_srv     = file->output_freq.getValue();
529
530      lastlast_Write_srv = context->getCalendar()->getInitDate();
531      last_Write_srv     = context->getCalendar()->getInitDate();
532      last_operation_srv = context->getCalendar()->getInitDate();
533
534      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
535      last_operation_srv     = last_operation_srv - toffset;
536
537      if (operation.isEmpty())
538        ERROR("void CField::solveServerOperation(void)",
539              << "An operation must be defined for field \"" << getId() << "\".");
540
541      boost::shared_ptr<func::CFunctor> functor;
542      CArray<double, 1> dummyData;
543
544#define DECLARE_FUNCTOR(MType, mtype) \
545      if (operation.getValue().compare(#mtype) == 0) \
546      { \
547        functor.reset(new func::C##MType(dummyData)); \
548      }
549
550#include "functor_type.conf"
551
552      if (!functor)
553        ERROR("void CField::solveServerOperation(void)",
554              << "\"" << operation << "\" is not a valid operation.");
555
556      operationTimeType = functor->timeType();
557   }
558
559   //----------------------------------------------------------------
560
561   /*!
562    * Constructs the graph filter for the field, enabling or not the data output.
563    * This method should not be called more than once with enableOutput equal to true.
564    *
565    * \param gc the garbage collector to use when building the filter graph
566    * \param enableOutput must be true when the field data is to be
567    *                     read by the client or/and written to a file
568    */
569   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
570   {
571     if (!areAllReferenceSolved) solveAllReferenceEnabledField(false);
572
573     // Start by building a filter which can provide the field's instant data
574     if (!instantDataFilter)
575     {
576       // Check if we have an expression to parse
577       if (!content.empty())
578       {
579         boost::scoped_ptr<IFilterExprNode> expr(parseExpr(content + '\0'));
580         instantDataFilter = expr->reduce(gc, *this);
581       }
582       // Check if we have a reference on another field
583       else if (!field_ref.isEmpty())
584       {
585         CField* fieldRef = CField::get(field_ref);
586         fieldRef->buildFilterGraph(gc, false);
587
588         std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
589         // Check if a spatial transformation is needed
590         if (!grid_ref.isEmpty() && !fieldRef->grid_ref.isEmpty() && grid_ref.getValue() != fieldRef->grid_ref.getValue())
591           filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid);
592         else
593           filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
594
595         fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
596         instantDataFilter = filters.second;
597       }
598       // Check if the data is to be read from a file
599       else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
600         instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(grid));
601       else // The data might be passed from the model
602         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(grid));
603     }
604
605     // If the field data is to be read by the client or/and written to a file
606     if (enableOutput && !storeFilter && !fileWriterFilter)
607     {
608       if (!read_access.isEmpty() && read_access.getValue())
609       {
610         storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid));
611         instantDataFilter->connectOutput(storeFilter, 0);
612       }
613
614       if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
615       {
616         fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
617         getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
618       }
619     }
620   }
621
622   /*!
623    * Returns the source filter to handle a self reference in the field's expression.
624    * If the needed source filter does not exist, it is created, otherwise it is reused.
625    * This method should only be called when building the filter graph corresponding
626    * to the field's expression.
627    *
628    * \param gc the garbage collector to use
629    * \return the output pin corresponding to a self reference
630    */
631   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
632   {
633     if (instantDataFilter || content.empty())
634       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
635             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
636
637     if (!clientSourceFilter)
638       clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(grid));
639
640     return clientSourceFilter;
641   }
642
643   /*!
644    * Returns the temporal filter corresponding to the field's temporal operation
645    * for the specified operation frequency. The filter is created if it does not
646    * exist, otherwise it is reused.
647    *
648    * \param gc the garbage collector to use
649    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
650    * \return the output pin corresponding to the requested temporal filter
651    */
652   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
653   {
654     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
655
656     if (it == temporalDataFilters.end())
657     {
658       if (operation.isEmpty())
659         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
660               << "An operation must be defined for field \"" << getId() << "\".");
661
662       if (freq_op.isEmpty())
663         freq_op.setValue(TimeStep);
664       if (freq_offset.isEmpty())
665         freq_offset.setValue(NoneDu);
666
667       const bool ignoreMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
668
669       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
670                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
671                                                                             freq_op, freq_offset, outFreq,
672                                                                             ignoreMissingValue, ignoreMissingValue ? default_value : 0.0));
673       instantDataFilter->connectOutput(temporalFilter, 0);
674
675       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
676     }
677
678     return it->second;
679   }
680
681   //----------------------------------------------------------------
682/*
683   void CField::fromBinary(StdIStream& is)
684   {
685      SuperClass::fromBinary(is);
686#define CLEAR_ATT(name_)\
687      SuperClassAttribute::operator[](#name_)->reset()
688
689         CLEAR_ATT(domain_ref);
690         CLEAR_ATT(axis_ref);
691#undef CLEAR_ATT
692
693   }
694*/
695   //----------------------------------------------------------------
696
697   void CField::solveGridReference(void)
698   {
699      CDomain* domain;
700      CAxis* axis;
701      std::vector<CDomain*> vecDom;
702      std::vector<CAxis*> vecAxis;
703      std::vector<std::string> domList, axisList;
704
705      if (!domain_ref.isEmpty())
706      {
707         if (CDomain::has(domain_ref.getValue()))
708         {
709           domain = CDomain::get(domain_ref.getValue());
710           vecDom.push_back(domain);
711         }
712         else
713            ERROR("CField::solveGridReference(void)",
714                  << "Reference to the domain \'"
715                  << domain_ref.getValue() << "\' is wrong");
716      }
717
718      if (!axis_ref.isEmpty())
719      {
720         if (CAxis::has(axis_ref.getValue()))
721         {
722           axis = CAxis::get(axis_ref.getValue());
723           vecAxis.push_back(axis);
724         }
725         else
726            ERROR("CField::solveGridReference(void)",
727                  << "Reference to the axis \'"
728                  << axis_ref.getValue() <<"\' is wrong");
729      }
730
731      if (!grid_ref.isEmpty())
732      {
733         if (CGrid::has(grid_ref.getValue()))
734         {
735           this->grid = CGrid::get(grid_ref.getValue());
736           domList = grid->getDomainList();
737           axisList = grid->getAxisList();
738           if (domList.empty() && axisList.empty())
739           {
740             this->grid = CGrid::createGrid(vecDom, vecAxis);
741           }
742         }
743         else
744            ERROR("CField::solveGridReference(void)",
745                  << "Reference to the grid \'"
746                  << grid_ref.getValue() << "\' is wrong");
747      }
748      else
749      {
750         this->grid = CGrid::createGrid(vecDom, vecAxis);
751      }
752
753      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty())
754      {
755            ERROR("CField::solveGridReference(void)",
756                  << "At least one dimension must be defined for this field.");
757      }
758   }
759
760   void CField::solveGridDomainAxisRef(bool checkAtt)
761   {
762     grid->solveDomainAxisRef(checkAtt);
763   }
764
765   void CField::solveCheckMaskIndex(bool doSendingIndex)
766   {
767     grid->checkMaskIndex(doSendingIndex);
768   }
769
770   void CField::solveTransformedGrid()
771   {
772     if (!grid_ref.isEmpty() && hasDirectFieldReference() && !getDirectFieldReference()->grid_ref.isEmpty()
773         && grid_ref.getValue() != getDirectFieldReference()->grid_ref.getValue() && !grid->isTransformed())
774       grid->transformGrid(getDirectFieldReference()->grid);
775   }
776
777   ///-------------------------------------------------------------------
778
779   template <>
780   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
781   {
782      if (this->group_ref.isEmpty()) return;
783      StdString gref = this->group_ref.getValue();
784
785      if (!CFieldGroup::has(gref))
786         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
787               << "[ gref = " << gref << "]"
788               << " invalid group name !");
789
790      CFieldGroup* group = CFieldGroup::get(gref);
791      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
792
793      std::vector<CField*> allChildren  = group->getAllChildren();
794      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
795
796      for (; it != end; it++)
797      {
798         CField* child = *it;
799         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
800
801      }
802   }
803
804   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
805   {
806     map<int, CArray<double,1> >::iterator it;
807     for (it = data_srv.begin(); it != data_srv.end(); it++) it->second = (it->second - addOffset) / scaleFactor;
808   }
809
810   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
811   {
812     map<int, CArray<double,1> >::iterator it;
813     for (it = data_srv.begin(); it != data_srv.end(); it++) it->second = it->second * scaleFactor + addOffset;
814   }
815
816   void CField::outputField(CArray<double,3>& fieldOut)
817   {
818      map<int, CArray<double,1> >::iterator it;
819      for (it = data_srv.begin(); it != data_srv.end(); it++)
820      {
821        grid->outputField(it->first, it->second, fieldOut.dataFirst());
822      }
823   }
824
825   void CField::outputField(CArray<double,2>& fieldOut)
826   {
827      map<int, CArray<double,1> >::iterator it;
828      for(it=data_srv.begin();it!=data_srv.end();it++)
829      {
830         grid->outputField(it->first, it->second, fieldOut.dataFirst());
831      }
832   }
833
834   void CField::outputField(CArray<double,1>& fieldOut)
835   {
836      map<int, CArray<double,1> >::iterator it;
837
838      for (it = data_srv.begin(); it != data_srv.end(); it++)
839      {
840         grid->outputField(it->first, it->second, fieldOut.dataFirst());
841      }
842   }
843
844   void CField::inputField(CArray<double,3>& fieldOut)
845   {
846      map<int, CArray<double,1> >::iterator it;
847      for (it = data_srv.begin(); it != data_srv.end(); it++)
848      {
849        grid->inputField(it->first, fieldOut.dataFirst(), it->second);
850      }
851   }
852
853   void CField::inputField(CArray<double,2>& fieldOut)
854   {
855      map<int, CArray<double,1> >::iterator it;
856      for(it = data_srv.begin(); it != data_srv.end(); it++)
857      {
858         grid->inputField(it->first, fieldOut.dataFirst(), it->second);
859      }
860   }
861
862   void CField::inputField(CArray<double,1>& fieldOut)
863   {
864      map<int, CArray<double,1> >::iterator it;
865      for (it = data_srv.begin(); it != data_srv.end(); it++)
866      {
867         grid->inputField(it->first, fieldOut.dataFirst(), it->second);
868      }
869   }
870
871   void CField::outputCompressedField(CArray<double,1>& fieldOut)
872   {
873      map<int, CArray<double,1> >::iterator it;
874
875      for (it = data_srv.begin(); it != data_srv.end(); it++)
876      {
877         grid->outputCompressedField(it->first, it->second, fieldOut.dataFirst());
878      }
879   }
880
881   ///-------------------------------------------------------------------
882
883   void CField::parse(xml::CXMLNode& node)
884   {
885      SuperClass::parse(node);
886      if (!node.getContent(this->content))
887      {
888        if (node.goToChildElement())
889        {
890          do
891          {
892            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
893          } while (node.goToNextElement());
894          node.goToParentElement();
895        }
896      }
897    }
898
899   /*!
900     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
901   of a field. In some cases, only domain exists but axis doesn't
902   \return pair of Domain and Axis id
903   */
904   const std::pair<StdString,StdString>& CField::getRefDomainAxisIds()
905   {
906     CGrid* cgPtr = getRelGrid();
907     if (NULL != cgPtr)
908     {
909       std::vector<StdString>::iterator it;
910       if (!domain_ref.isEmpty())
911       {
912         std::vector<StdString> domainList = cgPtr->getDomainList();
913         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
914         if (domainList.end() != it) domAxisIds_.first = *it;
915       }
916
917       if (!axis_ref.isEmpty())
918       {
919         std::vector<StdString> axisList = cgPtr->getAxisList();
920         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
921         if (axisList.end() != it) domAxisIds_.second = *it;
922       }
923     }
924     return (domAxisIds_);
925   }
926
927   CVariable* CField::addVariable(const string& id)
928   {
929     return vVariableGroup->createChild(id);
930   }
931
932   CVariableGroup* CField::addVariableGroup(const string& id)
933   {
934     return vVariableGroup->createChildGroup(id);
935   }
936
937   void CField::sendAddAllVariables()
938   {
939     if (!getAllVariables().empty())
940     {
941       // Firstly, it's necessary to add virtual variable group
942       sendAddVariableGroup(getVirtualVariableGroup()->getId());
943
944       // Okie, now we can add to this variable group
945       std::vector<CVariable*> allVar = getAllVariables();
946       std::vector<CVariable*>::const_iterator it = allVar.begin();
947       std::vector<CVariable*>::const_iterator itE = allVar.end();
948
949       for (; it != itE; ++it)
950       {
951         this->sendAddVariable((*it)->getId());
952         (*it)->sendAllAttributesToServer();
953         (*it)->sendValue();
954       }
955     }
956   }
957
958   void CField::sendAddVariable(const string& id)
959   {
960    CContext* context = CContext::getCurrent();
961
962    if (!context->hasServer)
963    {
964       CContextClient* client = context->client;
965
966       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE);
967       if (client->isServerLeader())
968       {
969         CMessage msg;
970         msg << this->getId();
971         msg << id;
972         const std::list<int>& ranks = client->getRanksServerLeader();
973         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
974           event.push(*itRank,1,msg);
975         client->sendEvent(event);
976       }
977       else client->sendEvent(event);
978    }
979   }
980
981   void CField::sendAddVariableGroup(const string& id)
982   {
983    CContext* context = CContext::getCurrent();
984    if (!context->hasServer)
985    {
986       CContextClient* client = context->client;
987
988       CEventClient event(this->getType(),EVENT_ID_ADD_VARIABLE_GROUP);
989       if (client->isServerLeader())
990       {
991         CMessage msg;
992         msg << this->getId();
993         msg << id;
994         const std::list<int>& ranks = client->getRanksServerLeader();
995         for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
996           event.push(*itRank,1,msg);
997         client->sendEvent(event);
998       }
999       else client->sendEvent(event);
1000    }
1001   }
1002
1003   void CField::recvAddVariable(CEventServer& event)
1004   {
1005
1006      CBufferIn* buffer = event.subEvents.begin()->buffer;
1007      string id;
1008      *buffer >> id;
1009      get(id)->recvAddVariable(*buffer);
1010   }
1011
1012   void CField::recvAddVariable(CBufferIn& buffer)
1013   {
1014      string id;
1015      buffer >> id;
1016      addVariable(id);
1017   }
1018
1019   void CField::recvAddVariableGroup(CEventServer& event)
1020   {
1021
1022      CBufferIn* buffer = event.subEvents.begin()->buffer;
1023      string id;
1024      *buffer >> id;
1025      get(id)->recvAddVariableGroup(*buffer);
1026   }
1027
1028   void CField::recvAddVariableGroup(CBufferIn& buffer)
1029   {
1030      string id;
1031      buffer >> id;
1032      addVariableGroup(id);
1033   }
1034
1035   DEFINE_REF_FUNC(Field,field)
1036} // namespace xios
Note: See TracBrowser for help on using the repository browser.