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

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

Fixing bug on mask grid

+) Add mask_0d for scalar grid
+) Transmit grid's attributes (mask) from client and reconstruct them correctly on server
+) Rebuild data in the input of data flow on the server side

Test
+) On Curie
+) Simple test

  • 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.8 KB
Line 
1#include "field.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6
7#include "node_type.hpp"
8#include "calendar_util.hpp"
9#include "message.hpp"
10#include "xios_spl.hpp"
11#include "type.hpp"
12#include "timer.hpp"
13#include "context_client.hpp"
14#include "context_server.hpp"
15#include <set>
16#include "garbage_collector.hpp"
17#include "source_filter.hpp"
18#include "store_filter.hpp"
19#include "file_writer_filter.hpp"
20#include "pass_through_filter.hpp"
21#include "filter_expr_node.hpp"
22#include "lex_parser.hpp"
23#include "temporal_filter.hpp"
24#include "spatial_transform_filter.hpp"
25#include "file_server_writer_filter.hpp"
26
27namespace xios{
28
29   /// ////////////////////// Définitions ////////////////////// ///
30
31   CField::CField(void)
32      : CObjectTemplate<CField>(), CFieldAttributes()
33      , grid(), file()
34      , written(false)
35      , nstep(0), nstepMax(0)
36      , hasOutputFile(false)
37      , domAxisScalarIds_(vector<StdString>(3,""))
38      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
39      , useCompressedOutput(false)
40      , hasTimeInstant(false)
41      , hasTimeCentered(false)
42      , wasDataAlreadyReceivedFromServer(false)
43      , isEOF(false), 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,true));
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, true));
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, false, 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         if (!read_access.isEmpty() && read_access)
1027         {
1028           storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1029                                                                          detectMissingValues, defaultValue));
1030           instantDataFilter->connectOutput(storeFilter, 0);
1031         }
1032
1033         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1034         {
1035           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1036           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1037         }
1038       }
1039     }
1040   }
1041
1042   /*!
1043    * Returns the filter needed to handle the field reference.
1044    * This method should only be called when building the filter graph corresponding to the field.
1045    *
1046    * \param gc the garbage collector to use
1047    * \return the output pin corresponding to the field reference
1048    */
1049   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1050   {
1051     if (instantDataFilter || field_ref.isEmpty())
1052       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1053             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1054
1055     CField* fieldRef = CField::get(field_ref);
1056     fieldRef->buildFilterGraph(gc, false);
1057
1058     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
1059     // Check if a spatial transformation is needed
1060     if (grid && grid != fieldRef->grid && grid->hasTransform())
1061     {       
1062       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1063       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1064       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1065     }
1066     else
1067       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1068
1069     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1070
1071     return filters.second;
1072   }
1073
1074   /*!
1075    * Returns the filter needed to handle a self reference in the field's expression.
1076    * If the needed filter does not exist, it is created, otherwise it is reused.
1077    * This method should only be called when building the filter graph corresponding
1078    * to the field's expression.
1079    *
1080    * \param gc the garbage collector to use
1081    * \return the output pin corresponding to a self reference
1082    */
1083   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1084   {
1085     if (instantDataFilter || !hasExpression())
1086       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1087             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1088
1089     if (!selfReferenceFilter)
1090     {
1091       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1092       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1093
1094       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1095       {
1096         if (!serverSourceFilter)
1097           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true,
1098                                                                                   freq_offset.isEmpty() ? NoneDu : freq_offset,
1099                                                                                   true,
1100                                                                                   detectMissingValues, defaultValue));
1101
1102         selfReferenceFilter = serverSourceFilter;
1103       }
1104       else if (!field_ref.isEmpty())
1105       {
1106         CField* fieldRef = CField::get(field_ref);
1107         fieldRef->buildFilterGraph(gc, false);
1108         selfReferenceFilter = fieldRef->getInstantDataFilter();
1109       }
1110       else
1111       {
1112         if (!clientSourceFilter)
1113         {
1114           if (check_if_active.isEmpty()) check_if_active = false;
1115           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, NoneDu, false,
1116                                                                                   detectMissingValues, defaultValue));
1117         }
1118
1119         selfReferenceFilter = clientSourceFilter;
1120       }
1121     }
1122
1123     return selfReferenceFilter;
1124   }
1125
1126   /*!
1127    * Returns the temporal filter corresponding to the field's temporal operation
1128    * for the specified operation frequency. The filter is created if it does not
1129    * exist, otherwise it is reused.
1130    *
1131    * \param gc the garbage collector to use
1132    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1133    * \return the output pin corresponding to the requested temporal filter
1134    */
1135   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1136   {
1137     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1138
1139     if (it == temporalDataFilters.end())
1140     {
1141       if (operation.isEmpty())
1142         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1143               << "An operation must be defined for field \"" << getId() << "\".");
1144
1145       if (freq_op.isEmpty())
1146         freq_op.setValue(TimeStep);
1147       if (freq_offset.isEmpty())
1148         freq_offset.setValue(NoneDu);
1149
1150       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1151       
1152       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1153                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1154                                                                             freq_op, freq_offset, outFreq,
1155                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1156       instantDataFilter->connectOutput(temporalFilter, 0);
1157
1158       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1159     }
1160
1161     return it->second;
1162   }
1163
1164  /*!
1165    * Returns the temporal filter corresponding to the field's temporal operation
1166    * for the specified operation frequency.
1167    *
1168    * \param gc the garbage collector to use
1169    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1170    * \return the output pin corresponding to the requested temporal filter
1171    */
1172   
1173   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1174   {
1175     if (instantDataFilter || !hasExpression())
1176       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1177             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1178
1179     if (!selfReferenceFilter) getSelfReference(gc) ;
1180
1181     if (serverSourceFilter || clientSourceFilter)
1182     {
1183       if (operation.isEmpty())
1184         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1185               << "An operation must be defined for field \"" << getId() << "\".");
1186
1187       if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
1188       if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
1189
1190       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1191
1192       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1193                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1194                                                                             freq_op, freq_offset, outFreq,
1195                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1196       selfReferenceFilter->connectOutput(temporalFilter, 0);
1197       return temporalFilter ;
1198     }
1199     else if (!field_ref.isEmpty())
1200     {
1201       CField* fieldRef = CField::get(field_ref);
1202       fieldRef->buildFilterGraph(gc, false); 
1203       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1204     }
1205  }
1206
1207   //----------------------------------------------------------------
1208/*
1209   void CField::fromBinary(StdIStream& is)
1210   {
1211      SuperClass::fromBinary(is);
1212#define CLEAR_ATT(name_)\
1213      SuperClassAttribute::operator[](#name_)->reset()
1214
1215         CLEAR_ATT(domain_ref);
1216         CLEAR_ATT(axis_ref);
1217#undef CLEAR_ATT
1218
1219   }
1220*/
1221   //----------------------------------------------------------------
1222
1223   void CField::solveGridReference(void)
1224   {
1225      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1226      {
1227        ERROR("CField::solveGridReference(void)",
1228              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1229      }
1230      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1231      {
1232        ERROR("CField::solveGridReference(void)",
1233              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1234              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1235      }
1236
1237      if (grid_ref.isEmpty())
1238      {
1239        std::vector<CDomain*> vecDom;
1240        std::vector<CAxis*> vecAxis;
1241        std::vector<CScalar*> vecScalar;
1242        std::vector<int> axisDomainOrderTmp;
1243       
1244        if (!domain_ref.isEmpty())
1245        {
1246          StdString tmp = domain_ref.getValue();
1247          if (CDomain::has(domain_ref))
1248          {
1249            vecDom.push_back(CDomain::get(domain_ref));
1250            axisDomainOrderTmp.push_back(2);
1251          }
1252          else
1253            ERROR("CField::solveGridReference(void)",
1254                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1255        }
1256
1257        if (!axis_ref.isEmpty())
1258        {
1259          if (CAxis::has(axis_ref))
1260          {
1261            vecAxis.push_back(CAxis::get(axis_ref));
1262            axisDomainOrderTmp.push_back(1);
1263          }
1264          else
1265            ERROR("CField::solveGridReference(void)",
1266                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1267        }
1268
1269        if (!scalar_ref.isEmpty())
1270        {
1271          if (CScalar::has(scalar_ref))
1272          {
1273            vecScalar.push_back(CScalar::get(scalar_ref));
1274            axisDomainOrderTmp.push_back(0);
1275          }
1276          else
1277            ERROR("CField::solveGridReference(void)",
1278                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1279        }
1280       
1281        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1282        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1283        {
1284          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1285        }
1286
1287        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1288        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1289        if (CGrid::has(gridId))
1290          this->grid = CGrid::get(gridId);
1291        else
1292          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1293      }
1294      else
1295      {
1296        if (CGrid::has(grid_ref))
1297          this->grid = CGrid::get(grid_ref);
1298        else
1299          ERROR("CField::solveGridReference(void)",
1300                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1301      }
1302   }
1303
1304   void CField::solveGridDomainAxisRef(bool checkAtt)
1305   {
1306     grid->solveDomainAxisRef(checkAtt);
1307   }
1308
1309   void CField::solveCheckMaskIndex(bool doSendingIndex)
1310   {
1311     grid->checkMaskIndex(doSendingIndex);
1312   }
1313
1314   void CField::solveTransformedGrid()
1315   {
1316     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1317     {
1318       std::vector<CGrid*> grids;
1319       // Source grid
1320       grids.push_back(getDirectFieldReference()->grid);
1321       // Intermediate grids
1322       if (!grid_path.isEmpty())
1323       {
1324         std::string gridId;
1325         size_t start = 0, end;
1326
1327         do
1328         {
1329           end = grid_path.getValue().find(',', start);
1330           if (end != std::string::npos)
1331           {
1332             gridId = grid_path.getValue().substr(start, end - start);
1333             start = end + 1;
1334           }
1335           else
1336             gridId = grid_path.getValue().substr(start);
1337
1338           if (!CGrid::has(gridId))
1339             ERROR("void CField::solveTransformedGrid()",
1340                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1341
1342           grids.push_back(CGrid::get(gridId));
1343         }
1344         while (end != std::string::npos);
1345       }
1346       // Destination grid
1347       grids.push_back(grid);
1348
1349       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1350       {
1351         CGrid *gridSrc  = grids[i];
1352         CGrid *gridDest = grids[i + 1];
1353         if (!gridDest->isTransformed())
1354           gridDest->transformGrid(gridSrc);
1355       }
1356     }
1357     else if (grid && grid->hasTransform() && !grid->isTransformed())
1358     {
1359       // Temporarily deactivate the self-transformation of grid
1360       //grid->transformGrid(grid);
1361     }
1362   }
1363
1364   void CField::solveGenerateGrid()
1365   {
1366     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1367       grid->completeGrid(getDirectFieldReference()->grid);
1368     else
1369       grid->completeGrid();
1370   }
1371
1372   void CField::solveGridDomainAxisBaseRef()
1373   {
1374     grid->solveDomainAxisRef(false);
1375     grid->solveDomainAxisBaseRef();
1376   }
1377
1378   ///-------------------------------------------------------------------
1379
1380   template <>
1381   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1382   {
1383      if (this->group_ref.isEmpty()) return;
1384      StdString gref = this->group_ref.getValue();
1385
1386      if (!CFieldGroup::has(gref))
1387         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1388               << "[ gref = " << gref << "]"
1389               << " invalid group name !");
1390
1391      CFieldGroup* group = CFieldGroup::get(gref);
1392      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1393
1394      std::vector<CField*> allChildren  = group->getAllChildren();
1395      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1396
1397      for (; it != end; it++)
1398      {
1399         CField* child = *it;
1400         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1401
1402      }
1403   }
1404
1405   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1406   {
1407     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1408   }
1409
1410   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1411   {
1412     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1413   }
1414
1415   void CField::outputField(CArray<double,1>& fieldOut)
1416   { 
1417      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1418      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1419      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1420      {
1421        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1422      }
1423   }
1424
1425   void CField::inputField(CArray<double,1>& fieldIn)
1426   {
1427      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1428      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1429      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1430      {
1431        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1432      }
1433
1434   }
1435
1436   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1437   {
1438      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1439      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1440      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1441      {
1442        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1443      }
1444   }
1445
1446   ///-------------------------------------------------------------------
1447
1448   void CField::parse(xml::CXMLNode& node)
1449   {
1450      SuperClass::parse(node);
1451      if (!node.getContent(this->content))
1452      {
1453        if (node.goToChildElement())
1454        {
1455          do
1456          {
1457            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1458          } while (node.goToNextElement());
1459          node.goToParentElement();
1460        }
1461      }
1462    }
1463
1464   /*!
1465     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1466   of a field. In some cases, only domain exists but axis doesn't
1467   \return pair of Domain and Axis id
1468   */
1469   const std::vector<StdString>& CField::getRefDomainAxisIds()
1470   {
1471     CGrid* cgPtr = getRelGrid();
1472     if (NULL != cgPtr)
1473     {
1474       std::vector<StdString>::iterator it;
1475       if (!domain_ref.isEmpty())
1476       {
1477         std::vector<StdString> domainList = cgPtr->getDomainList();
1478         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1479         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1480       }
1481
1482       if (!axis_ref.isEmpty())
1483       {
1484         std::vector<StdString> axisList = cgPtr->getAxisList();
1485         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1486         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1487       }
1488
1489       if (!scalar_ref.isEmpty())
1490       {
1491         std::vector<StdString> scalarList = cgPtr->getScalarList();
1492         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1493         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1494       }
1495     }
1496     return (domAxisScalarIds_);
1497   }
1498
1499   CVariable* CField::addVariable(const string& id)
1500   {
1501     return vVariableGroup->createChild(id);
1502   }
1503
1504   CVariableGroup* CField::addVariableGroup(const string& id)
1505   {
1506     return vVariableGroup->createChildGroup(id);
1507   }
1508
1509   void CField::sendAddAllVariables(CContextClient* client)
1510   {
1511     std::vector<CVariable*> allVar = getAllVariables();
1512     std::vector<CVariable*>::const_iterator it = allVar.begin();
1513     std::vector<CVariable*>::const_iterator itE = allVar.end();
1514
1515     for (; it != itE; ++it)
1516     {
1517       this->sendAddVariable((*it)->getId(), client);
1518       (*it)->sendAllAttributesToServer(client);
1519       (*it)->sendValue(client);
1520     }
1521   }
1522
1523   void CField::sendAddVariable(const string& id, CContextClient* client)
1524   {
1525      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1526   }
1527
1528   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1529   {
1530      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1531   }
1532
1533   void CField::recvAddVariable(CEventServer& event)
1534   {
1535
1536      CBufferIn* buffer = event.subEvents.begin()->buffer;
1537      string id;
1538      *buffer >> id;
1539      get(id)->recvAddVariable(*buffer);
1540   }
1541
1542   void CField::recvAddVariable(CBufferIn& buffer)
1543   {
1544      string id;
1545      buffer >> id;
1546      addVariable(id);
1547   }
1548
1549   void CField::recvAddVariableGroup(CEventServer& event)
1550   {
1551
1552      CBufferIn* buffer = event.subEvents.begin()->buffer;
1553      string id;
1554      *buffer >> id;
1555      get(id)->recvAddVariableGroup(*buffer);
1556   }
1557
1558   void CField::recvAddVariableGroup(CBufferIn& buffer)
1559   {
1560      string id;
1561      buffer >> id;
1562      addVariableGroup(id);
1563   }
1564
1565   /*!
1566    * Returns string arithmetic expression associated to the field.
1567    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1568    */
1569   const string& CField::getExpression(void)
1570   {
1571     if (!expr.isEmpty() && content.empty())
1572     {
1573       content = expr;
1574       expr.reset();
1575     }
1576
1577     return content;
1578   }
1579
1580   bool CField::hasExpression(void) const
1581   {
1582     return (!expr.isEmpty() || !content.empty());
1583   }
1584
1585
1586   DEFINE_REF_FUNC(Field,field)
1587} // namespace xios
Note: See TracBrowser for help on using the repository browser.