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

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

Fixing a bug on writting axis label

+) Axis label is correctly processed before being written
+) Do some code cleaning and add some comments

Test
+) On Curie
+) OK

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