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

Last change on this file since 1241 was 1241, checked in by ymipsl, 4 years ago

Fix problem on incoming data from client to server when you have so masking.
The source filter on server side try to compress data but the data are already compressed by client. So just make a flat copy and enter into workflow.

Now data compression is not called on server side.

YM

  • 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.7 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[client].begin(); it != grid->storeIndex_toSrv[client].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[client].begin(); it != grid->storeIndex_toSrv[client].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[client][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) << recvDataSrv;
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[client][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(MPI_IN_PLACE, &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::sendGridComponentOfEnabledFields()
800   {
801      solveGridDomainAxisRef(true);
802      // solveCheckMaskIndex(true);
803   }
804
805   void CField::sendGridOfEnabledFields()
806   {
807      // solveGridDomainAxisRef(true);
808      solveCheckMaskIndex(true);
809   }   
810
811   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
812   {
813     CContext* context = CContext::getCurrent();
814     if (!isReferenceSolved)
815     {
816        isReferenceSolved = true;
817
818        if (context->hasClient && !context->hasServer)
819        {
820          solveRefInheritance(true);
821          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
822        }
823
824        if (context->hasServer)
825          solveServerOperation();
826
827        solveGridReference();
828
829        if (context->hasClient && !context->hasServer)
830       {
831         solveGenerateGrid();
832         buildGridTransformationGraph();
833       }
834     }
835   }
836     
837   void CField::solveAllReferenceEnabledField(bool doSending2Server)
838   {
839     CContext* context = CContext::getCurrent();
840     solveOnlyReferenceEnabledField(doSending2Server);
841
842     if (!areAllReferenceSolved)
843     {
844        areAllReferenceSolved = true;
845       
846        if (context->hasClient && !context->hasServer)
847        {
848          solveRefInheritance(true);
849          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
850        }
851        else if (context->hasServer)
852          solveServerOperation();
853
854        solveGridReference();
855     }
856
857     solveGridDomainAxisRef(doSending2Server);
858
859     if (context->hasClient && !context->hasServer)
860     {
861       solveTransformedGrid();
862     }
863
864     solveCheckMaskIndex(doSending2Server);
865   }
866
867   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client)
868   {
869     return grid->getAttributesBufferSize(client);
870   }
871
872   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client)
873   {
874     return grid->getDataBufferSize(client, getId());
875   }
876
877   size_t CField::getGlobalWrittenSize()
878   {
879     return grid->getGlobalWrittenSize();
880   }
881
882   //----------------------------------------------------------------
883
884   void CField::solveServerOperation(void)
885   {
886      CContext* context = CContext::getCurrent();
887
888      if (!context->hasServer || !hasOutputFile) return;
889
890      if (freq_op.isEmpty())
891        freq_op.setValue(TimeStep);
892
893      if (freq_offset.isEmpty())
894        freq_offset.setValue(NoneDu);
895
896      freq_operation_srv = file->output_freq.getValue();
897      freq_write_srv     = file->output_freq.getValue();
898
899      lastlast_Write_srv = context->getCalendar()->getInitDate();
900      last_Write_srv     = context->getCalendar()->getInitDate();
901      last_operation_srv = context->getCalendar()->getInitDate();
902
903      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
904      last_operation_srv     = last_operation_srv - toffset;
905
906      if (operation.isEmpty())
907        ERROR("void CField::solveServerOperation(void)",
908              << "An operation must be defined for field \"" << getId() << "\".");
909
910      boost::shared_ptr<func::CFunctor> functor;
911      CArray<double, 1> dummyData;
912
913#define DECLARE_FUNCTOR(MType, mtype) \
914      if (operation.getValue().compare(#mtype) == 0) \
915      { \
916        functor.reset(new func::C##MType(dummyData)); \
917      }
918
919#include "functor_type.conf"
920
921      if (!functor)
922        ERROR("void CField::solveServerOperation(void)",
923              << "\"" << operation << "\" is not a valid operation.");
924
925      operationTimeType = functor->timeType();
926   }
927
928   //----------------------------------------------------------------
929
930   /*!
931    * Constructs the graph filter for the field, enabling or not the data output.
932    * This method should not be called more than once with enableOutput equal to true.
933    *
934    * \param gc the garbage collector to use when building the filter graph
935    * \param enableOutput must be true when the field data is to be
936    *                     read by the client or/and written to a file
937    */
938   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
939   {     
940    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
941
942     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
943     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
944
945     CContext* context = CContext::getCurrent();
946     bool hasWriterServer = context->hasServer && !context->hasClient;
947     bool hasIntermediateServer = context->hasServer && context->hasClient;
948
949     if (hasWriterServer)
950     {
951        if (!instantDataFilter)
952          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,false));
953
954             // If the field data is to be read by the client or/and written to a file
955       if (enableOutput && !storeFilter && !fileWriterFilter)
956       {
957         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
958         {
959           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
960           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
961         }
962       }
963     }
964     else if (hasIntermediateServer)
965     {
966       if (!instantDataFilter)
967         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false));
968
969             // If the field data is to be read by the client or/and written to a file
970       if (enableOutput && !storeFilter && !fileWriterFilter)
971       {
972         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
973         {
974           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
975           instantDataFilter->connectOutput(fileWriterFilter, 0);
976         }
977       }
978     }
979     else
980     {
981       // Start by building a filter which can provide the field's instant data
982       if (!instantDataFilter)
983       {
984         // Check if we have an expression to parse
985         if (hasExpression())
986         {
987           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
988           boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
989
990           // Check if a spatial transformation is needed
991           if (!field_ref.isEmpty())
992           {
993             CGrid* gridRef = CField::get(field_ref)->grid;
994
995             if (grid && grid != gridRef && grid->hasTransform())
996             {
997                 std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
998
999               filter->connectOutput(filters.first, 0);
1000               filter = filters.second;
1001             }
1002           }
1003
1004           instantDataFilter = filter;
1005         }
1006         // Check if we have a reference on another field
1007         else if (!field_ref.isEmpty())
1008           instantDataFilter = getFieldReference(gc);
1009         // Check if the data is to be read from a file
1010         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1011           instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true,
1012                                                                                                       freq_offset.isEmpty() ? NoneDu : freq_offset,
1013                                                                                                       true,
1014                                                                                                       detectMissingValues, defaultValue));
1015         else // The data might be passed from the model
1016         {
1017            if (check_if_active.isEmpty()) check_if_active = false; 
1018            instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, NoneDu, false,
1019                                                                                                        detectMissingValues, defaultValue));
1020         }
1021       }
1022
1023       // If the field data is to be read by the client or/and written to a file
1024       if (enableOutput && !storeFilter && !fileWriterFilter)
1025       {
1026         storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1027                                                                        detectMissingValues, defaultValue));
1028         instantDataFilter->connectOutput(storeFilter, 0);
1029       }
1030
1031       if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1032       {
1033         fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1034         getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1035       }
1036     }
1037   }
1038
1039   /*!
1040    * Returns the filter needed to handle the field reference.
1041    * This method should only be called when building the filter graph corresponding to the field.
1042    *
1043    * \param gc the garbage collector to use
1044    * \return the output pin corresponding to the field reference
1045    */
1046   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1047   {
1048     if (instantDataFilter || field_ref.isEmpty())
1049       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1050             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1051
1052     CField* fieldRef = CField::get(field_ref);
1053     fieldRef->buildFilterGraph(gc, false);
1054
1055     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
1056     // Check if a spatial transformation is needed
1057     if (grid && grid != fieldRef->grid && grid->hasTransform())
1058     {       
1059       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1060       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1061       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1062     }
1063     else
1064       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1065
1066     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1067
1068     return filters.second;
1069   }
1070
1071   /*!
1072    * Returns the filter needed to handle a self reference in the field's expression.
1073    * If the needed filter does not exist, it is created, otherwise it is reused.
1074    * This method should only be called when building the filter graph corresponding
1075    * to the field's expression.
1076    *
1077    * \param gc the garbage collector to use
1078    * \return the output pin corresponding to a self reference
1079    */
1080   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1081   {
1082     if (instantDataFilter || !hasExpression())
1083       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1084             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1085
1086     if (!selfReferenceFilter)
1087     {
1088       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1089       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1090
1091       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1092       {
1093         if (!serverSourceFilter)
1094           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true,
1095                                                                                   freq_offset.isEmpty() ? NoneDu : freq_offset,
1096                                                                                   true,
1097                                                                                   detectMissingValues, defaultValue));
1098
1099         selfReferenceFilter = serverSourceFilter;
1100       }
1101       else if (!field_ref.isEmpty())
1102       {
1103         CField* fieldRef = CField::get(field_ref);
1104         fieldRef->buildFilterGraph(gc, false);
1105         selfReferenceFilter = fieldRef->getInstantDataFilter();
1106       }
1107       else
1108       {
1109         if (!clientSourceFilter)
1110         {
1111           if (check_if_active.isEmpty()) check_if_active = false;
1112           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, NoneDu, false,
1113                                                                                   detectMissingValues, defaultValue));
1114         }
1115
1116         selfReferenceFilter = clientSourceFilter;
1117       }
1118     }
1119
1120     return selfReferenceFilter;
1121   }
1122
1123   /*!
1124    * Returns the temporal filter corresponding to the field's temporal operation
1125    * for the specified operation frequency. The filter is created if it does not
1126    * exist, otherwise it is reused.
1127    *
1128    * \param gc the garbage collector to use
1129    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1130    * \return the output pin corresponding to the requested temporal filter
1131    */
1132   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1133   {
1134     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1135
1136     if (it == temporalDataFilters.end())
1137     {
1138       if (operation.isEmpty())
1139         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1140               << "An operation must be defined for field \"" << getId() << "\".");
1141
1142       if (freq_op.isEmpty())
1143         freq_op.setValue(TimeStep);
1144       if (freq_offset.isEmpty())
1145         freq_offset.setValue(NoneDu);
1146
1147       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1148       
1149       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1150                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1151                                                                             freq_op, freq_offset, outFreq,
1152                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1153       instantDataFilter->connectOutput(temporalFilter, 0);
1154
1155       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1156     }
1157
1158     return it->second;
1159   }
1160
1161  /*!
1162    * Returns the temporal filter corresponding to the field's temporal operation
1163    * for the specified operation frequency.
1164    *
1165    * \param gc the garbage collector to use
1166    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1167    * \return the output pin corresponding to the requested temporal filter
1168    */
1169   
1170   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1171   {
1172     if (instantDataFilter || !hasExpression())
1173       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1174             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1175
1176     if (!selfReferenceFilter) getSelfReference(gc) ;
1177
1178     if (serverSourceFilter || clientSourceFilter)
1179     {
1180       if (operation.isEmpty())
1181         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1182               << "An operation must be defined for field \"" << getId() << "\".");
1183
1184       if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
1185       if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
1186
1187       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1188
1189       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1190                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1191                                                                             freq_op, freq_offset, outFreq,
1192                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1193       selfReferenceFilter->connectOutput(temporalFilter, 0);
1194       return temporalFilter ;
1195     }
1196     else if (!field_ref.isEmpty())
1197     {
1198       CField* fieldRef = CField::get(field_ref);
1199       fieldRef->buildFilterGraph(gc, false); 
1200       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1201     }
1202  }
1203
1204   //----------------------------------------------------------------
1205/*
1206   void CField::fromBinary(StdIStream& is)
1207   {
1208      SuperClass::fromBinary(is);
1209#define CLEAR_ATT(name_)\
1210      SuperClassAttribute::operator[](#name_)->reset()
1211
1212         CLEAR_ATT(domain_ref);
1213         CLEAR_ATT(axis_ref);
1214#undef CLEAR_ATT
1215
1216   }
1217*/
1218   //----------------------------------------------------------------
1219
1220   void CField::solveGridReference(void)
1221   {
1222      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1223      {
1224        ERROR("CField::solveGridReference(void)",
1225              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1226      }
1227      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1228      {
1229        ERROR("CField::solveGridReference(void)",
1230              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1231              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1232      }
1233
1234      if (grid_ref.isEmpty())
1235      {
1236        std::vector<CDomain*> vecDom;
1237        std::vector<CAxis*> vecAxis;
1238        std::vector<CScalar*> vecScalar;
1239        std::vector<int> axisDomainOrderTmp;
1240       
1241        if (!domain_ref.isEmpty())
1242        {
1243          StdString tmp = domain_ref.getValue();
1244          if (CDomain::has(domain_ref))
1245          {
1246            vecDom.push_back(CDomain::get(domain_ref));
1247            axisDomainOrderTmp.push_back(2);
1248          }
1249          else
1250            ERROR("CField::solveGridReference(void)",
1251                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1252        }
1253
1254        if (!axis_ref.isEmpty())
1255        {
1256          if (CAxis::has(axis_ref))
1257          {
1258            vecAxis.push_back(CAxis::get(axis_ref));
1259            axisDomainOrderTmp.push_back(1);
1260          }
1261          else
1262            ERROR("CField::solveGridReference(void)",
1263                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1264        }
1265
1266        if (!scalar_ref.isEmpty())
1267        {
1268          if (CScalar::has(scalar_ref))
1269          {
1270            vecScalar.push_back(CScalar::get(scalar_ref));
1271            axisDomainOrderTmp.push_back(0);
1272          }
1273          else
1274            ERROR("CField::solveGridReference(void)",
1275                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1276        }
1277       
1278        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1279        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1280        {
1281          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1282        }
1283
1284        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1285        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1286        if (CGrid::has(gridId))
1287          this->grid = CGrid::get(gridId);
1288        else
1289          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1290      }
1291      else
1292      {
1293        if (CGrid::has(grid_ref))
1294          this->grid = CGrid::get(grid_ref);
1295        else
1296          ERROR("CField::solveGridReference(void)",
1297                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1298      }
1299   }
1300
1301   void CField::solveGridDomainAxisRef(bool checkAtt)
1302   {
1303     grid->solveDomainAxisRef(checkAtt);
1304   }
1305
1306   void CField::solveCheckMaskIndex(bool doSendingIndex)
1307   {
1308     grid->checkMaskIndex(doSendingIndex);
1309   }
1310
1311   void CField::solveTransformedGrid()
1312   {
1313     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1314     {
1315       std::vector<CGrid*> grids;
1316       // Source grid
1317       grids.push_back(getDirectFieldReference()->grid);
1318       // Intermediate grids
1319       if (!grid_path.isEmpty())
1320       {
1321         std::string gridId;
1322         size_t start = 0, end;
1323
1324         do
1325         {
1326           end = grid_path.getValue().find(',', start);
1327           if (end != std::string::npos)
1328           {
1329             gridId = grid_path.getValue().substr(start, end - start);
1330             start = end + 1;
1331           }
1332           else
1333             gridId = grid_path.getValue().substr(start);
1334
1335           if (!CGrid::has(gridId))
1336             ERROR("void CField::solveTransformedGrid()",
1337                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1338
1339           grids.push_back(CGrid::get(gridId));
1340         }
1341         while (end != std::string::npos);
1342       }
1343       // Destination grid
1344       grids.push_back(grid);
1345
1346       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1347       {
1348         CGrid *gridSrc  = grids[i];
1349         CGrid *gridDest = grids[i + 1];
1350         if (!gridDest->isTransformed())
1351           gridDest->transformGrid(gridSrc);
1352       }
1353     }
1354     else if (grid && grid->hasTransform() && !grid->isTransformed())
1355     {
1356       // Temporarily deactivate the self-transformation of grid
1357       //grid->transformGrid(grid);
1358     }
1359   }
1360
1361   void CField::solveGenerateGrid()
1362   {
1363     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1364       grid->completeGrid(getDirectFieldReference()->grid);
1365     else
1366       grid->completeGrid();
1367   }
1368
1369   void CField::solveGridDomainAxisBaseRef()
1370   {
1371     grid->solveDomainAxisRef(false);
1372     grid->solveDomainAxisBaseRef();
1373   }
1374
1375   ///-------------------------------------------------------------------
1376
1377   template <>
1378   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1379   {
1380      if (this->group_ref.isEmpty()) return;
1381      StdString gref = this->group_ref.getValue();
1382
1383      if (!CFieldGroup::has(gref))
1384         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1385               << "[ gref = " << gref << "]"
1386               << " invalid group name !");
1387
1388      CFieldGroup* group = CFieldGroup::get(gref);
1389      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1390
1391      std::vector<CField*> allChildren  = group->getAllChildren();
1392      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1393
1394      for (; it != end; it++)
1395      {
1396         CField* child = *it;
1397         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1398
1399      }
1400   }
1401
1402   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1403   {
1404     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1405   }
1406
1407   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1408   {
1409     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1410   }
1411
1412   void CField::outputField(CArray<double,1>& fieldOut)
1413   { 
1414      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1415      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1416      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1417      {
1418        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1419      }
1420   }
1421
1422   void CField::inputField(CArray<double,1>& fieldIn)
1423   {
1424      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1425      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1426      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1427      {
1428        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1429      }
1430
1431   }
1432
1433   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1434   {
1435      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1436      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1437      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1438      {
1439        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1440      }
1441   }
1442
1443   ///-------------------------------------------------------------------
1444
1445   void CField::parse(xml::CXMLNode& node)
1446   {
1447      SuperClass::parse(node);
1448      if (!node.getContent(this->content))
1449      {
1450        if (node.goToChildElement())
1451        {
1452          do
1453          {
1454            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1455          } while (node.goToNextElement());
1456          node.goToParentElement();
1457        }
1458      }
1459    }
1460
1461   /*!
1462     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1463   of a field. In some cases, only domain exists but axis doesn't
1464   \return pair of Domain and Axis id
1465   */
1466   const std::vector<StdString>& CField::getRefDomainAxisIds()
1467   {
1468     CGrid* cgPtr = getRelGrid();
1469     if (NULL != cgPtr)
1470     {
1471       std::vector<StdString>::iterator it;
1472       if (!domain_ref.isEmpty())
1473       {
1474         std::vector<StdString> domainList = cgPtr->getDomainList();
1475         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1476         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1477       }
1478
1479       if (!axis_ref.isEmpty())
1480       {
1481         std::vector<StdString> axisList = cgPtr->getAxisList();
1482         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1483         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1484       }
1485
1486       if (!scalar_ref.isEmpty())
1487       {
1488         std::vector<StdString> scalarList = cgPtr->getScalarList();
1489         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1490         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1491       }
1492     }
1493     return (domAxisScalarIds_);
1494   }
1495
1496   CVariable* CField::addVariable(const string& id)
1497   {
1498     return vVariableGroup->createChild(id);
1499   }
1500
1501   CVariableGroup* CField::addVariableGroup(const string& id)
1502   {
1503     return vVariableGroup->createChildGroup(id);
1504   }
1505
1506   void CField::sendAddAllVariables(CContextClient* client)
1507   {
1508     std::vector<CVariable*> allVar = getAllVariables();
1509     std::vector<CVariable*>::const_iterator it = allVar.begin();
1510     std::vector<CVariable*>::const_iterator itE = allVar.end();
1511
1512     for (; it != itE; ++it)
1513     {
1514       this->sendAddVariable((*it)->getId(), client);
1515       (*it)->sendAllAttributesToServer(client);
1516       (*it)->sendValue(client);
1517     }
1518   }
1519
1520   void CField::sendAddVariable(const string& id, CContextClient* client)
1521   {
1522      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1523   }
1524
1525   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1526   {
1527      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1528   }
1529
1530   void CField::recvAddVariable(CEventServer& event)
1531   {
1532
1533      CBufferIn* buffer = event.subEvents.begin()->buffer;
1534      string id;
1535      *buffer >> id;
1536      get(id)->recvAddVariable(*buffer);
1537   }
1538
1539   void CField::recvAddVariable(CBufferIn& buffer)
1540   {
1541      string id;
1542      buffer >> id;
1543      addVariable(id);
1544   }
1545
1546   void CField::recvAddVariableGroup(CEventServer& event)
1547   {
1548
1549      CBufferIn* buffer = event.subEvents.begin()->buffer;
1550      string id;
1551      *buffer >> id;
1552      get(id)->recvAddVariableGroup(*buffer);
1553   }
1554
1555   void CField::recvAddVariableGroup(CBufferIn& buffer)
1556   {
1557      string id;
1558      buffer >> id;
1559      addVariableGroup(id);
1560   }
1561
1562   /*!
1563    * Returns string arithmetic expression associated to the field.
1564    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1565    */
1566   const string& CField::getExpression(void)
1567   {
1568     if (!expr.isEmpty() && content.empty())
1569     {
1570       content = expr;
1571       expr.reset();
1572     }
1573
1574     return content;
1575   }
1576
1577   bool CField::hasExpression(void) const
1578   {
1579     return (!expr.isEmpty() || !content.empty());
1580   }
1581
1582
1583   DEFINE_REF_FUNC(Field,field)
1584} // namespace xios
Note: See TracBrowser for help on using the repository browser.