source: XIOS/dev/dev_olga/src/node/field.cpp @ 1166

Last change on this file since 1166 was 1166, checked in by mhnguyen, 7 years ago

Fixing a minor bug during merge.

Test
+) On Curie
+) test_client, test_complete work
+) Need to test more

  • 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: 48.8 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#include "file_server_writer_filter.hpp"
26
27namespace xios{
28
29   /// ////////////////////// Définitions ////////////////////// ///
30
31   CField::CField(void)
32      : CObjectTemplate<CField>(), CFieldAttributes()
33      , grid(), file()
34      , written(false)
35      , nstep(0), nstepMax(0)
36      , hasOutputFile(false)
37      , domAxisScalarIds_(vector<StdString>(3,""))
38      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
39      , useCompressedOutput(false)
40      , hasTimeInstant(false)
41      , hasTimeCentered(false)
42      , wasDataAlreadyReceivedFromServer(false)
43      , isEOF(false)
44   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
45
46   CField::CField(const StdString& id)
47      : CObjectTemplate<CField>(id), CFieldAttributes()
48      , grid(), file()
49      , written(false)
50      , nstep(0), nstepMax(0)
51      , hasOutputFile(false)
52      , domAxisScalarIds_(vector<StdString>(3,""))
53      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
54      , useCompressedOutput(false)
55      , hasTimeInstant(false)
56      , hasTimeCentered(false)
57      , wasDataAlreadyReceivedFromServer(false)
58      , isEOF(false)
59   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
60
61   CField::~CField(void)
62   {}
63
64  //----------------------------------------------------------------
65
66   void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
67   {
68      this->vVariableGroup = newVVariableGroup;
69   }
70
71   CVariableGroup* CField::getVirtualVariableGroup(void) const
72   {
73      return this->vVariableGroup;
74   }
75
76   std::vector<CVariable*> CField::getAllVariables(void) const
77   {
78      return this->vVariableGroup->getAllChildren();
79   }
80
81   void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
82   {
83      SuperClassAttribute::setAttributes(parent, apply);
84      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
85   }
86
87  //----------------------------------------------------------------
88
89  bool CField::dispatchEvent(CEventServer& event)
90  {
91    if (SuperClass::dispatchEvent(event)) return true;
92    else
93    {
94      switch(event.type)
95      {
96        case EVENT_ID_UPDATE_DATA :
97          recvUpdateData(event);
98          return true;
99          break;
100
101        case EVENT_ID_READ_DATA :
102          recvReadDataRequest(event);
103          return true;
104          break;
105
106        case EVENT_ID_READ_DATA_READY :
107          recvReadDataReady(event);
108          return true;
109          break;
110
111        case EVENT_ID_ADD_VARIABLE :
112          recvAddVariable(event);
113          return true;
114          break;
115
116        case EVENT_ID_ADD_VARIABLE_GROUP :
117          recvAddVariableGroup(event);
118          return true;
119          break;
120
121        default :
122          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
123          return false;
124      }
125    }
126  }
127
128  void CField::sendUpdateData(const CArray<double,1>& data)
129  {
130    CTimer::get("Field : send data").resume();
131
132    CContext* context = CContext::getCurrent();
133      CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
134
135      CEventClient event(getType(), EVENT_ID_UPDATE_DATA);
136
137      map<int, CArray<int,1> >::iterator it;
138      list<CMessage> list_msg;
139      list<CArray<double,1> > list_data;
140
141      if (!grid->doGridHaveDataDistributed())
142      {
143         if (client->isServerLeader())
144         {
145            for (it = grid->storeIndex_toSrv.begin(); it != grid->storeIndex_toSrv.end(); it++)
146            {
147              int rank = it->first;
148              CArray<int,1>& index = it->second;
149
150              list_msg.push_back(CMessage());
151              list_data.push_back(CArray<double,1>(index.numElements()));
152
153              CArray<double,1>& data_tmp = list_data.back();
154              for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
155
156              list_msg.back() << getId() << data_tmp;
157              event.push(rank, 1, list_msg.back());
158            }
159            client->sendEvent(event);
160         }
161         else client->sendEvent(event);
162      }
163      else
164      {
165        for (it = grid->storeIndex_toSrv.begin(); it != grid->storeIndex_toSrv.end(); it++)
166        {
167          int rank = it->first;
168          CArray<int,1>& index = it->second;
169
170          list_msg.push_back(CMessage());
171          list_data.push_back(CArray<double,1>(index.numElements()));
172
173          CArray<double,1>& data_tmp = list_data.back();
174          for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
175
176          list_msg.back() << getId() << data_tmp;
177          event.push(rank, grid->nbSenders[0][rank], list_msg.back());
178        }
179        client->sendEvent(event);
180      }   
181
182    CTimer::get("Field : send data").suspend();
183  }
184
185  void CField::recvUpdateData(CEventServer& event)
186  {
187    std::map<int,CBufferIn*> rankBuffers;
188
189    list<CEventServer::SSubEvent>::iterator it;
190    string fieldId;
191    CTimer::get("Field : recv data").resume();
192    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
193    {
194      int rank = it->rank;
195      CBufferIn* buffer = it->buffer;
196      *buffer >> fieldId;
197      rankBuffers[rank] = buffer;
198    }
199    get(fieldId)->recvUpdateData(rankBuffers);
200    CTimer::get("Field : recv data").suspend();
201  }
202
203  void  CField::recvUpdateData(std::map<int,CBufferIn*>& rankBuffers)
204  {
205    CContext* context = CContext::getCurrent();
206
207    size_t sizeData = 0;
208    if (0 == recvDataSrv.numElements())
209    {           
210      CArray<int,1>& storeClient = grid->storeIndex_client;
211
212      // Gather all data from different clients     
213      recvDataSrv.resize(storeClient.numElements());
214      recvFoperationSrv = boost::shared_ptr<func::CFunctor>(new func::CInstant(recvDataSrv));
215    }
216
217    CArray<double,1> recv_data_tmp(recvDataSrv.numElements());   
218    const CDate& currDate = context->getCalendar()->getCurrentDate();
219    const CDate opeDate   = last_operation_srv +freq_op + freq_operation_srv - freq_op;
220
221    if (opeDate <= currDate)
222    {
223      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); it != grid->outLocalIndexStoreOnClient.end(); ++it)
224      {
225        CArray<double,1> tmp;
226        CArray<size_t,1>& indexTmp = it->second;
227        *(rankBuffers[it->first]) >> tmp;
228        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
229        {
230          recv_data_tmp(indexTmp(idx)) = tmp(idx);
231        }     
232      }
233    }
234
235    this->setData(recv_data_tmp);
236  }
237
238  void CField::writeUpdateData(const CArray<double,1>& data)
239  {
240    CContext* context = CContext::getCurrent();
241
242    const CDate& currDate = context->getCalendar()->getCurrentDate();
243    const CDate opeDate      = last_operation_srv +freq_op + freq_operation_srv - freq_op;
244    const CDate writeDate    = last_Write_srv     + freq_write_srv;
245
246    if (opeDate <= currDate)
247    {
248      (*recvFoperationSrv)(data);
249      last_operation_srv = currDate;
250    }
251
252    if (writeDate < (currDate + freq_operation_srv))
253    {
254      recvFoperationSrv->final();
255      last_Write_srv = writeDate;
256      grid->computeWrittenIndex();
257      writeField();
258      lastlast_Write_srv = last_Write_srv;
259    }
260  }
261
262  void CField::writeField(void)
263  {
264    if (!getRelFile()->allDomainEmpty)
265    {
266      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
267      {
268        getRelFile()->checkWriteFile();
269        this->incrementNStep();
270        getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
271      }
272    }
273  }
274
275  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
276  {
277    CContext* context = CContext::getCurrent();
278    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
279
280
281    lastDataRequestedFromServer = tsDataRequested;
282
283    if (!isEOF) // No need to send the request if we already know we are at EOF
284    {
285      CEventClient event(getType(), EVENT_ID_READ_DATA);
286      if (client->isServerLeader())
287      {
288        CMessage msg;
289        msg << getId();
290        const std::list<int>& ranks = client->getRanksServerLeader();
291        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
292          event.push(*itRank, 1, msg);
293        client->sendEvent(event);
294      }
295      else client->sendEvent(event);
296    }
297    else
298      serverSourceFilter->signalEndOfStream(tsDataRequested);
299
300    return !isEOF;
301  }
302
303  /*!
304  Send request new data read from file if need be, that is the current data is out-of-date.
305  \return true if and only if some data was requested
306  */
307  bool CField::sendReadDataRequestIfNeeded(void)
308  {
309    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
310
311    bool dataRequested = false;
312
313    while (currentDate >= lastDataRequestedFromServer)
314    {
315      info(20) << "currentDate : " << currentDate << endl ;
316      info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
317      info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
318      info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
319
320      dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq);
321    }
322
323    return dataRequested;
324  }
325
326  void CField::recvReadDataRequest(CEventServer& event)
327  {
328    CBufferIn* buffer = event.subEvents.begin()->buffer;
329    StdString fieldId;
330    *buffer >> fieldId;
331    get(fieldId)->recvReadDataRequest();
332  }
333
334  void CField::recvReadDataRequest(void)
335  {
336    CContext* context = CContext::getCurrent();
337    CContextClient* client = context->client;
338
339    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
340    std::list<CMessage> msgs;
341
342    bool hasData = readField();
343
344    map<int, CArray<double,1> >::iterator it;
345    if (!grid->doGridHaveDataDistributed())
346    {
347       if (client->isServerLeader())
348       {
349          if (0 != recvDataSrv.numElements())
350          {           
351            const std::list<int>& ranks = client->getRanksServerLeader();
352            for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
353            {
354              msgs.push_back(CMessage());
355              CMessage& msg = msgs.back();
356              msg << getId();
357              if (hasData)
358                msg << getNStep() - 1 << recvDataSrv;
359              else
360                msg << int(-1);
361              event.push(*itRank, 1, msg);
362            }
363          }
364          client->sendEvent(event);
365       }
366       else
367       {
368          client->sendEvent(event);
369       }
370    }
371    else
372    {
373      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); 
374                                                  it != grid->outLocalIndexStoreOnClient.end(); ++it)
375      {
376        CArray<size_t,1>& indexTmp = it->second;
377        CArray<double,1> tmp(indexTmp.numElements());
378        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
379        {
380          tmp(idx) = recvDataSrv(indexTmp(idx));
381        } 
382
383        msgs.push_back(CMessage());
384        CMessage& msg = msgs.back();
385        msg << getId();
386        if (hasData)
387          msg << getNStep() - 1 << tmp;
388        else
389          msg << int(-1);
390        event.push(it->first, grid->nbReadSenders[0][it->first], msg);
391      }
392      client->sendEvent(event);
393    }
394  }
395
396  bool CField::readField(void)
397  {
398    grid->computeWrittenIndex();
399    if (!getRelFile()->allDomainEmpty)
400    {
401      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
402      {
403        if (0 == recvDataSrv.numElements())
404        {           
405          CArray<int,1>& storeClient = grid->storeIndex_client;         
406          recvDataSrv.resize(storeClient.numElements());         
407        }
408
409        getRelFile()->checkReadFile();
410        if (!nstepMax)
411        {
412          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
413        }
414
415        this->incrementNStep();
416
417        if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
418          return false;
419
420        getRelFile()->getDataInput()->readFieldData(CField::get(this));
421      }
422    }
423
424    return true;
425  }
426
427  void CField::recvReadDataReady(CEventServer& event)
428  {
429    string fieldId;
430    vector<int> ranks;
431    vector<CBufferIn*> buffers;
432
433    list<CEventServer::SSubEvent>::iterator it;
434    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
435    {
436      ranks.push_back(it->rank);
437      CBufferIn* buffer = it->buffer;
438      *buffer >> fieldId;
439      buffers.push_back(buffer);
440    }
441    get(fieldId)->recvReadDataReady(ranks, buffers);
442  }
443
444  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
445  {
446    CContext* context = CContext::getCurrent();
447    int record;
448    std::map<int, CArray<double,1> > data;
449
450    for (int i = 0; i < ranks.size(); i++)
451    {
452      int rank = ranks[i];
453      *buffers[i] >> record;
454      isEOF = (record == int(-1));
455
456      if (!isEOF)
457        *buffers[i] >> data[rank];
458      else
459        break;
460    }
461
462    if (wasDataAlreadyReceivedFromServer)
463      lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
464    else
465    {
466      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
467      wasDataAlreadyReceivedFromServer = true;
468    }
469
470    if (isEOF)
471      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
472    else
473      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
474  }
475
476   //----------------------------------------------------------------
477
478   void CField::setRelFile(CFile* _file)
479   {
480      this->file = _file;
481      hasOutputFile = true;
482   }
483
484   //----------------------------------------------------------------
485
486   StdString CField::GetName(void)    { return StdString("field"); }
487   StdString CField::GetDefName(void) { return CField::GetName(); }
488   ENodeType CField::GetType(void)    { return eField; }
489
490   //----------------------------------------------------------------
491
492   CGrid* CField::getRelGrid(void) const
493   {
494      return this->grid;
495   }
496
497   //----------------------------------------------------------------
498
499   CFile* CField::getRelFile(void) const
500   {
501      return this->file;
502   }
503
504   int CField::getNStep(void) const
505   {
506      return this->nstep;
507   }
508
509   func::CFunctor::ETimeType CField::getOperationTimeType() const
510   {
511     return operationTimeType;
512   }
513
514   //----------------------------------------------------------------
515
516   void CField::incrementNStep(void)
517   {
518      this->nstep++;
519   }
520
521   void CField::resetNStep(int nstep /*= 0*/)
522   {
523      this->nstep = nstep;
524   }
525
526   void CField::resetNStepMax(void)
527   {
528      this->nstepMax = 0;
529   }
530
531   //----------------------------------------------------------------
532
533   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
534   {
535      if (clientSourceFilter)
536        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
537      else if (storeFilter)
538        return true;
539      else if (instantDataFilter)
540        ERROR("bool CField::isActive(bool atCurrentTimestep)",
541              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
542
543      return false;
544   }
545
546   //----------------------------------------------------------------
547
548   bool CField::wasWritten() const
549   {
550     return written;
551   }
552
553   void CField::setWritten()
554   {
555     written = true;
556   }
557
558   //----------------------------------------------------------------
559
560   bool CField::getUseCompressedOutput() const
561   {
562     return useCompressedOutput;
563   }
564
565   void CField::setUseCompressedOutput()
566   {
567     useCompressedOutput = true;
568   }
569
570   //----------------------------------------------------------------
571
572   boost::shared_ptr<COutputPin> CField::getInstantDataFilter()
573   {
574     return instantDataFilter;
575   }
576
577   //----------------------------------------------------------------
578
579   /*!
580     Build up graph of grids which plays role of destination and source in grid transformation
581     This function should be called before \func solveGridReference()
582   */
583   void CField::buildGridTransformationGraph()
584   {
585     CContext* context = CContext::getCurrent();
586     if (context->hasClient && !context->hasServer)
587     {
588       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
589       {
590         grid->addTransGridSource(getDirectFieldReference()->grid);
591       }
592     }
593   }
594
595   /*!
596     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
597   */
598   void CField::generateNewTransformationGridDest()
599   {
600     CContext* context = CContext::getCurrent();
601     if (context->hasClient && !context->hasServer)
602     {
603       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
604       if (1 < gridSrcMap.size())
605       {
606         // Search for grid source
607         CGrid* gridSrc = grid;
608         CField* currField = this;
609         std::vector<CField*> hieraField;
610
611         while (currField->hasDirectFieldReference() && (gridSrc == grid))
612         {
613           hieraField.push_back(currField);
614           CField* tmp = currField->getDirectFieldReference();
615           currField = tmp;
616           gridSrc = currField->grid;
617         }
618
619         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
620         {
621           CGrid* gridTmp;
622           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
623           if (newGridDest.first)
624           {
625             StdString newIdGridDest = newGridDest.second;
626             if (!CGrid::has(newIdGridDest))
627             {
628                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
629                  << " Something wrong happened! Grid whose id " << newIdGridDest
630                  << "should exist ");
631             }
632             gridTmp = CGrid::get(newIdGridDest);
633           }
634           else
635           {
636             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
637             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
638
639             (gridSrcMap[gridSrc]).first = true;
640             (gridSrcMap[gridSrc]).second = newIdGridDest;
641           }
642
643           // Update all descendants
644           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
645           {
646             (*it)->grid = gridTmp;
647             (*it)->updateRef((*it)->grid);
648           }
649         }
650       }
651     }
652   }
653
654   void CField::updateRef(CGrid* grid)
655   {
656     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
657     else
658     {
659       std::vector<CAxis*> axisTmp = grid->getAxis();
660       std::vector<CDomain*> domainTmp = grid->getDomains();
661       if ((1<axisTmp.size()) || (1<domainTmp.size()))
662         ERROR("void CField::updateRef(CGrid* grid)",
663           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
664
665       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
666         ERROR("void CField::updateRef(CGrid* grid)",
667           << "Incoherent between available domain and domain_ref of field " << this->getId());
668       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
669         ERROR("void CField::updateRef(CGrid* grid)",
670           << "Incoherent between available axis and axis_ref of field " << this->getId());
671
672       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
673       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
674     }
675   }
676   
677   /*!
678     Solve reference of all enabled fields even the source fields .
679     In this step, we do transformations.
680   */
681   void CField::solveAllEnabledFieldsAndTransform()
682   {
683     CContext* context = CContext::getCurrent();
684     bool hasClient = context->hasClient;
685     bool hasServer = context->hasServer;
686
687     if (!isReferenceSolvedAndTransformed)
688     {
689        isReferenceSolvedAndTransformed = true;
690
691        if (hasClient && !hasServer)
692        {
693          solveRefInheritance(true);
694          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
695        }
696
697        if (hasServer)
698          solveServerOperation();
699
700        solveGridReference();
701
702        if (hasClient && !hasServer)
703       {
704         solveGenerateGrid();
705         buildGridTransformationGraph();
706       }
707
708       solveGridDomainAxisRef(false);
709
710       if (hasClient && !hasServer)
711       {
712         solveTransformedGrid();
713       }
714
715       solveGridDomainAxisRef(false);
716     }
717   }
718
719   void CField::checkGridOfEnabledFields()
720   {
721      solveCheckMaskIndex(false);
722   }
723
724   void CField::sendGridOfEnabledFields()
725   {
726      solveGridDomainAxisRef(true);
727      solveCheckMaskIndex(true);
728   }
729
730
731    void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
732   {
733     CContext* context = CContext::getCurrent();
734     if (!isReferenceSolved)
735     {
736        isReferenceSolved = true;
737
738        if (context->hasClient && !context->hasServer)
739        {
740          solveRefInheritance(true);
741          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
742        }
743
744        if (context->hasServer)
745          solveServerOperation();
746
747        solveGridReference();
748
749        if (context->hasClient && !context->hasServer)
750       {
751         solveGenerateGrid();
752         buildGridTransformationGraph();
753       }
754     }
755   }
756     
757   void CField::solveAllReferenceEnabledField(bool doSending2Server)
758   {
759     CContext* context = CContext::getCurrent();
760     solveOnlyReferenceEnabledField(doSending2Server);
761
762     if (!areAllReferenceSolved)
763     {
764        areAllReferenceSolved = true;
765       
766        if (context->hasClient && !context->hasServer)
767        {
768          solveRefInheritance(true);
769          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
770        }
771        else if (context->hasServer)
772          solveServerOperation();
773
774        solveGridReference();
775     }
776
777     solveGridDomainAxisRef(doSending2Server);
778
779     if (context->hasClient && !context->hasServer)
780     {
781       solveTransformedGrid();
782     }
783
784     solveCheckMaskIndex(doSending2Server);
785   }
786
787   std::map<int, StdSize> CField::getGridAttributesBufferSize()
788   {
789     return grid->getAttributesBufferSize();
790   }
791
792   std::vector<std::map<int, StdSize> > CField::getGridDataBufferSize()
793   {
794     return grid->getDataBufferSize(getId());
795   }
796
797   //----------------------------------------------------------------
798
799   void CField::solveServerOperation(void)
800   {
801      CContext* context = CContext::getCurrent();
802
803      if (!context->hasServer || !hasOutputFile) return;
804
805      if (freq_op.isEmpty())
806        freq_op.setValue(TimeStep);
807
808      if (freq_offset.isEmpty())
809        freq_offset.setValue(NoneDu);
810
811      freq_operation_srv = file->output_freq.getValue();
812      freq_write_srv     = file->output_freq.getValue();
813
814      lastlast_Write_srv = context->getCalendar()->getInitDate();
815      last_Write_srv     = context->getCalendar()->getInitDate();
816      last_operation_srv = context->getCalendar()->getInitDate();
817
818      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
819      last_operation_srv     = last_operation_srv - toffset;
820
821      if (operation.isEmpty())
822        ERROR("void CField::solveServerOperation(void)",
823              << "An operation must be defined for field \"" << getId() << "\".");
824
825      boost::shared_ptr<func::CFunctor> functor;
826      CArray<double, 1> dummyData;
827
828#define DECLARE_FUNCTOR(MType, mtype) \
829      if (operation.getValue().compare(#mtype) == 0) \
830      { \
831        functor.reset(new func::C##MType(dummyData)); \
832      }
833
834#include "functor_type.conf"
835
836      if (!functor)
837        ERROR("void CField::solveServerOperation(void)",
838              << "\"" << operation << "\" is not a valid operation.");
839
840      operationTimeType = functor->timeType();
841   }
842
843   //----------------------------------------------------------------
844
845   /*!
846    * Constructs the graph filter for the field, enabling or not the data output.
847    * This method should not be called more than once with enableOutput equal to true.
848    *
849    * \param gc the garbage collector to use when building the filter graph
850    * \param enableOutput must be true when the field data is to be
851    *                     read by the client or/and written to a file
852    */
853   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
854   {     
855    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
856     CContext* context = CContext::getCurrent();
857     bool hasWriterServer = context->hasServer && !context->hasClient;
858     bool hasIntermediateServer = context->hasServer && context->hasClient;
859
860     if (hasWriterServer)
861     {
862        if (!instantDataFilter)
863          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid));
864
865             // If the field data is to be read by the client or/and written to a file
866       if (enableOutput && !storeFilter && !fileWriterFilter)
867       {
868         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
869         {
870           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
871           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
872         }
873       }
874     }
875     else if (hasIntermediateServer)
876     {
877       if (!instantDataFilter)
878         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid));
879
880             // If the field data is to be read by the client or/and written to a file
881       if (enableOutput && !storeFilter && !fileWriterFilter)
882       {
883         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
884         {
885           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
886           instantDataFilter->connectOutput(fileWriterFilter, 0);
887         }
888       }
889     }
890     else
891     {
892       // Start by building a filter which can provide the field's instant data
893       if (!instantDataFilter)
894       {
895         // Check if we have an expression to parse
896         if (hasExpression())
897         {
898           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
899           boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
900
901           // Check if a spatial transformation is needed
902           if (!field_ref.isEmpty())
903           {
904             CGrid* gridRef = CField::get(field_ref)->grid;
905
906             if (grid && grid != gridRef && grid->hasTransform())
907             {
908               bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
909               double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
910               std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, hasMissingValue, defaultValue);
911
912               filter->connectOutput(filters.first, 0);
913               filter = filters.second;
914             }
915           }
916
917           instantDataFilter = filter;
918         }
919         // Check if we have a reference on another field
920         else if (!field_ref.isEmpty())
921           instantDataFilter = getFieldReference(gc);
922         // Check if the data is to be read from a file
923         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
924           instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,
925                                                                                                       freq_offset.isEmpty() ? NoneDu : freq_offset,
926                                                                                                       true));
927         else // The data might be passed from the model
928         {
929            bool ignoreMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
930            double defaultValue  = ignoreMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
931            instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
932                                                                                                        ignoreMissingValue, defaultValue));
933         }
934       }
935
936       // If the field data is to be read by the client or/and written to a file
937       if (enableOutput && !storeFilter && !fileWriterFilter)
938       {
939         if (!read_access.isEmpty() && read_access)
940         {
941           storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid));
942           instantDataFilter->connectOutput(storeFilter, 0);
943         }
944
945         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
946         {
947           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
948           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
949         }
950       }
951     }
952   }
953
954   /*!
955    * Returns the filter needed to handle the field reference.
956    * This method should only be called when building the filter graph corresponding to the field.
957    *
958    * \param gc the garbage collector to use
959    * \return the output pin corresponding to the field reference
960    */
961   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
962   {
963     if (instantDataFilter || field_ref.isEmpty())
964       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
965             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
966
967     CField* fieldRef = CField::get(field_ref);
968     fieldRef->buildFilterGraph(gc, false);
969
970     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
971     // Check if a spatial transformation is needed
972     if (grid && grid != fieldRef->grid && grid->hasTransform())
973     {       
974       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
975       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
976       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
977     }
978     else
979       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
980
981     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
982
983     return filters.second;
984   }
985
986   /*!
987    * Returns the filter needed to handle a self reference in the field's expression.
988    * If the needed filter does not exist, it is created, otherwise it is reused.
989    * This method should only be called when building the filter graph corresponding
990    * to the field's expression.
991    *
992    * \param gc the garbage collector to use
993    * \return the output pin corresponding to a self reference
994    */
995   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
996   {
997     if (instantDataFilter || !hasExpression())
998       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
999             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1000
1001     if (!selfReferenceFilter)
1002     {
1003       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1004       {
1005         if (!serverSourceFilter)
1006           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,
1007                                                                                   freq_offset.isEmpty() ? NoneDu : freq_offset,
1008                                                                                   true));
1009         selfReferenceFilter = serverSourceFilter;
1010       }
1011       else if (!field_ref.isEmpty())
1012       {
1013         CField* fieldRef = CField::get(field_ref);
1014         fieldRef->buildFilterGraph(gc, false);
1015         selfReferenceFilter = fieldRef->getInstantDataFilter();
1016       }
1017       else
1018       {
1019         if (!clientSourceFilter)
1020         {
1021           bool ignoreMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1022           double defaultValue  = ignoreMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0); 
1023           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
1024                                                                                   ignoreMissingValue, defaultValue));
1025         }
1026
1027         selfReferenceFilter = clientSourceFilter;
1028       }
1029     }
1030
1031     return selfReferenceFilter;
1032   }
1033
1034   /*!
1035    * Returns the temporal filter corresponding to the field's temporal operation
1036    * for the specified operation frequency. The filter is created if it does not
1037    * exist, otherwise it is reused.
1038    *
1039    * \param gc the garbage collector to use
1040    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1041    * \return the output pin corresponding to the requested temporal filter
1042    */
1043   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1044   {
1045     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1046
1047     if (it == temporalDataFilters.end())
1048     {
1049       if (operation.isEmpty())
1050         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1051               << "An operation must be defined for field \"" << getId() << "\".");
1052
1053       if (freq_op.isEmpty())
1054         freq_op.setValue(TimeStep);
1055       if (freq_offset.isEmpty())
1056         freq_offset.setValue(NoneDu);
1057
1058       const bool ignoreMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1059
1060       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1061                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1062                                                                             freq_op, freq_offset, outFreq,
1063                                                                             ignoreMissingValue, ignoreMissingValue ? default_value : 0.0));
1064       instantDataFilter->connectOutput(temporalFilter, 0);
1065
1066       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1067     }
1068
1069     return it->second;
1070   }
1071
1072  /*!
1073    * Returns the temporal filter corresponding to the field's temporal operation
1074    * for the specified operation frequency.
1075    *
1076    * \param gc the garbage collector to use
1077    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1078    * \return the output pin corresponding to the requested temporal filter
1079    */
1080   
1081   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1082   {
1083     if (instantDataFilter || !hasExpression())
1084       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1085             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1086
1087     if (!selfReferenceFilter) getSelfReference(gc) ;
1088
1089     if (serverSourceFilter || clientSourceFilter)
1090     {
1091       if (operation.isEmpty())
1092         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1093               << "An operation must be defined for field \"" << getId() << "\".");
1094
1095       if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
1096       if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
1097
1098       const bool ignoreMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1099
1100       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1101                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1102                                                                             freq_op, freq_offset, outFreq,
1103                                                                             ignoreMissingValue, ignoreMissingValue ? default_value : 0.0));
1104       selfReferenceFilter->connectOutput(temporalFilter, 0);
1105       return temporalFilter ;
1106     }
1107     else if (!field_ref.isEmpty())
1108     {
1109       CField* fieldRef = CField::get(field_ref);
1110       fieldRef->buildFilterGraph(gc, false); 
1111       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1112     }
1113  }
1114
1115   //----------------------------------------------------------------
1116/*
1117   void CField::fromBinary(StdIStream& is)
1118   {
1119      SuperClass::fromBinary(is);
1120#define CLEAR_ATT(name_)\
1121      SuperClassAttribute::operator[](#name_)->reset()
1122
1123         CLEAR_ATT(domain_ref);
1124         CLEAR_ATT(axis_ref);
1125#undef CLEAR_ATT
1126
1127   }
1128*/
1129   //----------------------------------------------------------------
1130
1131   void CField::solveGridReference(void)
1132   {
1133      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1134      {
1135        ERROR("CField::solveGridReference(void)",
1136              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1137      }
1138      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1139      {
1140        ERROR("CField::solveGridReference(void)",
1141              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1142              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1143      }
1144
1145      if (grid_ref.isEmpty())
1146      {
1147        std::vector<CDomain*> vecDom;
1148        std::vector<CAxis*> vecAxis;
1149        std::vector<CScalar*> vecScalar;
1150        std::vector<int> axisDomainOrderTmp;
1151       
1152        if (!domain_ref.isEmpty())
1153        {
1154          StdString tmp = domain_ref.getValue();
1155          if (CDomain::has(domain_ref))
1156          {
1157            vecDom.push_back(CDomain::get(domain_ref));
1158            axisDomainOrderTmp.push_back(2);
1159          }
1160          else
1161            ERROR("CField::solveGridReference(void)",
1162                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1163        }
1164
1165        if (!axis_ref.isEmpty())
1166        {
1167          if (CAxis::has(axis_ref))
1168          {
1169            vecAxis.push_back(CAxis::get(axis_ref));
1170            axisDomainOrderTmp.push_back(1);
1171          }
1172          else
1173            ERROR("CField::solveGridReference(void)",
1174                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1175        }
1176
1177        if (!scalar_ref.isEmpty())
1178        {
1179          if (CScalar::has(scalar_ref))
1180          {
1181            vecScalar.push_back(CScalar::get(scalar_ref));
1182            axisDomainOrderTmp.push_back(0);
1183          }
1184          else
1185            ERROR("CField::solveGridReference(void)",
1186                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1187        }
1188       
1189        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1190        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1191        {
1192          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1193        }
1194
1195        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1196        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1197        if (CGrid::has(gridId))
1198          this->grid = CGrid::get(gridId);
1199        else
1200          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1201      }
1202      else
1203      {
1204        if (CGrid::has(grid_ref))
1205          this->grid = CGrid::get(grid_ref);
1206        else
1207          ERROR("CField::solveGridReference(void)",
1208                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1209      }
1210   }
1211
1212   void CField::solveGridDomainAxisRef(bool checkAtt)
1213   {
1214     grid->solveDomainAxisRef(checkAtt);
1215   }
1216
1217   void CField::solveCheckMaskIndex(bool doSendingIndex)
1218   {
1219     grid->checkMaskIndex(doSendingIndex);
1220   }
1221
1222   void CField::solveTransformedGrid()
1223   {
1224     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1225     {
1226       std::vector<CGrid*> grids;
1227       // Source grid
1228       grids.push_back(getDirectFieldReference()->grid);
1229       // Intermediate grids
1230       if (!grid_path.isEmpty())
1231       {
1232         std::string gridId;
1233         size_t start = 0, end;
1234
1235         do
1236         {
1237           end = grid_path.getValue().find(',', start);
1238           if (end != std::string::npos)
1239           {
1240             gridId = grid_path.getValue().substr(start, end - start);
1241             start = end + 1;
1242           }
1243           else
1244             gridId = grid_path.getValue().substr(start);
1245
1246           if (!CGrid::has(gridId))
1247             ERROR("void CField::solveTransformedGrid()",
1248                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1249
1250           grids.push_back(CGrid::get(gridId));
1251         }
1252         while (end != std::string::npos);
1253       }
1254       // Destination grid
1255       grids.push_back(grid);
1256
1257       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1258       {
1259         CGrid *gridSrc  = grids[i];
1260         CGrid *gridDest = grids[i + 1];
1261         if (!gridDest->isTransformed())
1262           gridDest->transformGrid(gridSrc);
1263       }
1264     }
1265     else if (grid && grid->hasTransform() && !grid->isTransformed())
1266     {
1267       // Temporarily deactivate the self-transformation of grid
1268       //grid->transformGrid(grid);
1269     }
1270   }
1271
1272   void CField::solveGenerateGrid()
1273   {
1274     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1275       grid->completeGrid(getDirectFieldReference()->grid);
1276     else
1277       grid->completeGrid();
1278   }
1279
1280   void CField::solveGridDomainAxisBaseRef()
1281   {
1282     grid->solveDomainAxisRef(false);
1283     grid->solveDomainAxisBaseRef();
1284   }
1285
1286   ///-------------------------------------------------------------------
1287
1288   template <>
1289   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1290   {
1291      if (this->group_ref.isEmpty()) return;
1292      StdString gref = this->group_ref.getValue();
1293
1294      if (!CFieldGroup::has(gref))
1295         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1296               << "[ gref = " << gref << "]"
1297               << " invalid group name !");
1298
1299      CFieldGroup* group = CFieldGroup::get(gref);
1300      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1301
1302      std::vector<CField*> allChildren  = group->getAllChildren();
1303      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1304
1305      for (; it != end; it++)
1306      {
1307         CField* child = *it;
1308         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1309
1310      }
1311   }
1312
1313   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1314   {
1315     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1316   }
1317
1318   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1319   {
1320     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1321   }
1322
1323   void CField::outputField(CArray<double,1>& fieldOut)
1324   { 
1325      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1326      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1327      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1328      {
1329        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1330      }
1331   }
1332
1333   void CField::inputField(CArray<double,1>& fieldIn)
1334   {
1335      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1336      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1337      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1338      {
1339        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1340      }
1341
1342   }
1343
1344   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1345   {
1346      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1347      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1348      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1349      {
1350        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1351      }
1352   }
1353
1354   ///-------------------------------------------------------------------
1355
1356   void CField::parse(xml::CXMLNode& node)
1357   {
1358      SuperClass::parse(node);
1359      if (!node.getContent(this->content))
1360      {
1361        if (node.goToChildElement())
1362        {
1363          do
1364          {
1365            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1366          } while (node.goToNextElement());
1367          node.goToParentElement();
1368        }
1369      }
1370    }
1371
1372   /*!
1373     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1374   of a field. In some cases, only domain exists but axis doesn't
1375   \return pair of Domain and Axis id
1376   */
1377   const std::vector<StdString>& CField::getRefDomainAxisIds()
1378   {
1379     CGrid* cgPtr = getRelGrid();
1380     if (NULL != cgPtr)
1381     {
1382       std::vector<StdString>::iterator it;
1383       if (!domain_ref.isEmpty())
1384       {
1385         std::vector<StdString> domainList = cgPtr->getDomainList();
1386         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1387         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1388       }
1389
1390       if (!axis_ref.isEmpty())
1391       {
1392         std::vector<StdString> axisList = cgPtr->getAxisList();
1393         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1394         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1395       }
1396
1397       if (!scalar_ref.isEmpty())
1398       {
1399         std::vector<StdString> scalarList = cgPtr->getScalarList();
1400         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1401         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1402       }
1403     }
1404     return (domAxisScalarIds_);
1405   }
1406
1407   CVariable* CField::addVariable(const string& id)
1408   {
1409     return vVariableGroup->createChild(id);
1410   }
1411
1412   CVariableGroup* CField::addVariableGroup(const string& id)
1413   {
1414     return vVariableGroup->createChildGroup(id);
1415   }
1416
1417   void CField::sendAddAllVariables(CContextClient* client)
1418   {
1419     std::vector<CVariable*> allVar = getAllVariables();
1420     std::vector<CVariable*>::const_iterator it = allVar.begin();
1421     std::vector<CVariable*>::const_iterator itE = allVar.end();
1422
1423     for (; it != itE; ++it)
1424     {
1425       this->sendAddVariable((*it)->getId(), client);
1426       (*it)->sendAllAttributesToServer(client);
1427       (*it)->sendValue(client);
1428     }
1429   }
1430
1431   void CField::sendAddVariable(const string& id, CContextClient* client)
1432   {
1433      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1434   }
1435
1436   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1437   {
1438      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1439   }
1440
1441   void CField::recvAddVariable(CEventServer& event)
1442   {
1443
1444      CBufferIn* buffer = event.subEvents.begin()->buffer;
1445      string id;
1446      *buffer >> id;
1447      get(id)->recvAddVariable(*buffer);
1448   }
1449
1450   void CField::recvAddVariable(CBufferIn& buffer)
1451   {
1452      string id;
1453      buffer >> id;
1454      addVariable(id);
1455   }
1456
1457   void CField::recvAddVariableGroup(CEventServer& event)
1458   {
1459
1460      CBufferIn* buffer = event.subEvents.begin()->buffer;
1461      string id;
1462      *buffer >> id;
1463      get(id)->recvAddVariableGroup(*buffer);
1464   }
1465
1466   void CField::recvAddVariableGroup(CBufferIn& buffer)
1467   {
1468      string id;
1469      buffer >> id;
1470      addVariableGroup(id);
1471   }
1472
1473   /*!
1474    * Returns string arithmetic expression associated to the field.
1475    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1476    */
1477   const string& CField::getExpression(void)
1478   {
1479     if (!expr.isEmpty() && content.empty())
1480     {
1481       content = expr;
1482       expr.reset();
1483     }
1484
1485     return content;
1486   }
1487
1488   bool CField::hasExpression(void) const
1489   {
1490     return (!expr.isEmpty() || !content.empty());
1491   }
1492
1493
1494   DEFINE_REF_FUNC(Field,field)
1495} // namespace xios
Note: See TracBrowser for help on using the repository browser.