source: XIOS/dev/XIOS_DEV_CMIP6/src/node/field.cpp @ 1211

Last change on this file since 1211 was 1201, checked in by oabramkina, 7 years ago

Two server levels: merging trunk r1200 (except for non-contiguous zoom) into dev. Tested on Curie. Todo: non-contiguous zoom.

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