source: XIOS/trunk/src/node/field.cpp @ 1768

Last change on this file since 1768 was 1768, checked in by yushan, 5 years ago

trunk : bug fix for workflowgraph

  • 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: 68.6 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#include "workflow_graph.hpp"
27
28namespace xios{
29
30   /// ////////////////////// Définitions ////////////////////// ///
31
32   CField::CField(void)
33      : CObjectTemplate<CField>(), CFieldAttributes()
34      , grid(), file()
35      , written(false)
36      , nstep(0), nstepMax(0)
37      , hasOutputFile(false)
38      , domAxisScalarIds_(vector<StdString>(3,""))
39      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
40      , isGridChecked(false)
41      , useCompressedOutput(false)
42      , hasTimeInstant(false)
43      , hasTimeCentered(false)
44      , wasDataRequestedFromServer(false)
45      , wasDataAlreadyReceivedFromServer(false)
46      , mustAutoTrigger(false)
47      , isEOF(false), nstepMaxRead(false)
48   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); 
49     field_graph_start = -2;
50     field_graph_end = -2;
51   }
52
53   CField::CField(const StdString& id)
54      : CObjectTemplate<CField>(id), CFieldAttributes()
55      , grid(), file()
56      , written(false)
57      , nstep(0), nstepMax(0)
58      , hasOutputFile(false)
59      , domAxisScalarIds_(vector<StdString>(3,""))
60      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
61      , isGridChecked(false)
62      , useCompressedOutput(false)
63      , hasTimeInstant(false)
64      , hasTimeCentered(false)
65      , wasDataRequestedFromServer(false)
66      , wasDataAlreadyReceivedFromServer(false)
67      , mustAutoTrigger(false)
68      , isEOF(false), nstepMaxRead(false)
69   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); 
70     field_graph_start = -2;
71     field_graph_end = -2;
72   }
73
74
75   CField::~CField(void)
76   {}
77
78  //----------------------------------------------------------------
79
80   void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
81   TRY
82   {
83      this->vVariableGroup = newVVariableGroup;
84   }
85   CATCH
86
87   CVariableGroup* CField::getVirtualVariableGroup(void) const
88   TRY
89   {
90      return this->vVariableGroup;
91   }
92   CATCH
93
94   std::vector<CVariable*> CField::getAllVariables(void) const
95   TRY
96   {
97      return this->vVariableGroup->getAllChildren();
98   }
99   CATCH
100
101   void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
102   TRY
103   {
104      SuperClassAttribute::setAttributes(parent, apply);
105      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
106   }
107   CATCH_DUMP_ATTR
108
109  //----------------------------------------------------------------
110
111  bool CField::dispatchEvent(CEventServer& event)
112  TRY
113  {
114    if (SuperClass::dispatchEvent(event)) return true;
115    else
116    {
117      switch(event.type)
118      {
119        case EVENT_ID_UPDATE_DATA :
120          recvUpdateData(event);
121          return true;
122          break;
123
124        case EVENT_ID_READ_DATA :
125          recvReadDataRequest(event);
126          return true;
127          break;
128
129        case EVENT_ID_READ_DATA_READY :
130          recvReadDataReady(event);
131          return true;
132          break;
133
134        case EVENT_ID_ADD_VARIABLE :
135          recvAddVariable(event);
136          return true;
137          break;
138
139        case EVENT_ID_ADD_VARIABLE_GROUP :
140          recvAddVariableGroup(event);
141          return true;
142          break;
143
144        default :
145          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
146          return false;
147      }
148    }
149  }
150  CATCH
151
152  void CField::sendUpdateData(const CArray<double,1>& data)
153  TRY
154  {
155    CTimer::get("Field : send data").resume();
156
157    CContext* context = CContext::getCurrent();
158    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
159    int receiverSize = client->serverSize;
160
161    CEventClient event(getType(), EVENT_ID_UPDATE_DATA);
162
163    map<int, CArray<int,1> >::iterator it;
164    list<CMessage> list_msg;
165    list<CArray<double,1> > list_data;
166
167    if (!grid->doGridHaveDataDistributed(client))
168    {
169       if (client->isServerLeader())
170       {
171          for (it = grid->storeIndex_toSrv[client].begin(); it != grid->storeIndex_toSrv[client].end(); it++)
172          {
173            int rank = it->first;
174            CArray<int,1>& index = it->second;
175
176            list_msg.push_back(CMessage());
177            list_data.push_back(CArray<double,1>(index.numElements()));
178
179            CArray<double,1>& data_tmp = list_data.back();
180            for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
181
182            list_msg.back() << getId() << data_tmp;
183            event.push(rank, 1, list_msg.back());
184          }
185          client->sendEvent(event);
186        }
187      else client->sendEvent(event);
188    }
189    else
190    {
191      for (it = grid->storeIndex_toSrv[client].begin(); it != grid->storeIndex_toSrv[client].end(); it++)
192      {
193        int rank = it->first;
194        CArray<int,1>& index = it->second;
195
196        list_msg.push_back(CMessage());
197        list_data.push_back(CArray<double,1>(index.numElements()));
198
199        CArray<double,1>& data_tmp = list_data.back();
200        for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
201
202        list_msg.back() << getId() << data_tmp;
203        event.push(rank, grid->nbSenders[receiverSize][rank], list_msg.back());
204      }
205      client->sendEvent(event);
206    }
207
208    CTimer::get("Field : send data").suspend();
209  }
210  CATCH_DUMP_ATTR
211
212  void CField::recvUpdateData(CEventServer& event)
213  TRY
214  {
215    std::map<int,CBufferIn*> rankBuffers;
216
217    list<CEventServer::SSubEvent>::iterator it;
218    string fieldId;
219    CTimer::get("Field : recv data").resume();
220    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
221    {
222      int rank = it->rank;
223      CBufferIn* buffer = it->buffer;
224      *buffer >> fieldId;
225      rankBuffers[rank] = buffer;
226    }
227    get(fieldId)->recvUpdateData(rankBuffers);
228    CTimer::get("Field : recv data").suspend();
229  }
230  CATCH
231
232  void  CField::recvUpdateData(std::map<int,CBufferIn*>& rankBuffers)
233  TRY
234  {
235    CContext* context = CContext::getCurrent();
236
237    size_t sizeData = 0;
238    if (0 == recvDataSrv.numElements())
239    {           
240      CArray<int,1>& storeClient = grid->storeIndex_client;
241
242      // Gather all data from different clients     
243      recvDataSrv.resize(storeClient.numElements());
244      recvFoperationSrv = std::shared_ptr<func::CFunctor>(new func::CInstant(recvDataSrv));
245    }
246
247    CArray<double,1> recv_data_tmp(recvDataSrv.numElements());   
248    const CDate& currDate = context->getCalendar()->getCurrentDate();
249    CDuration offsetAllButMonth (freq_offset.getValue().year, 0 , freq_offset.getValue().day,
250                                   freq_offset.getValue().hour, freq_offset.getValue().minute,
251                                   freq_offset.getValue().second, freq_offset.getValue().timestep);
252    const CDate opeDate   = (last_operation_srv - offsetAllButMonth + context->getCalendar()->getTimeStep())
253                              + freq_op + freq_operation_srv - freq_op - context->getCalendar()->getTimeStep() + offsetAllButMonth;
254
255    if (opeDate <= currDate)
256    {
257      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); it != grid->outLocalIndexStoreOnClient.end(); ++it)
258      {
259        CArray<double,1> tmp;
260        CArray<size_t,1>& indexTmp = it->second;
261        *(rankBuffers[it->first]) >> tmp;
262        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
263        {
264          recv_data_tmp(indexTmp(idx)) = tmp(idx);
265        }     
266      }
267    }
268
269    this->setData(recv_data_tmp);
270    // delete incomming flux for server only
271    recvFoperationSrv.reset() ;
272    recvDataSrv.reset() ;
273  }
274  CATCH_DUMP_ATTR
275
276  void CField::writeUpdateData(const CArray<double,1>& data)
277  TRY
278  {
279    CContext* context = CContext::getCurrent();
280
281    const CDate& currDate = context->getCalendar()->getCurrentDate();
282    CDuration offsetAllButMonth (freq_offset.getValue().year, 0 , freq_offset.getValue().day,
283                                   freq_offset.getValue().hour, freq_offset.getValue().minute,
284                                   freq_offset.getValue().second, freq_offset.getValue().timestep);
285    const CDate opeDate   = (last_operation_srv - offsetAllButMonth + context->getCalendar()->getTimeStep())
286                              + freq_op + freq_operation_srv - freq_op - context->getCalendar()->getTimeStep() + offsetAllButMonth;
287    const CDate writeDate = last_Write_srv + freq_write_srv;
288
289    if (opeDate <= currDate)
290    {
291      (*recvFoperationSrv)(data);
292      last_operation_srv = currDate;
293    }
294
295    if (writeDate < (currDate + freq_operation_srv))
296    {
297      recvFoperationSrv->final();
298      last_Write_srv = writeDate;
299      grid->computeWrittenIndex();
300      writeField();
301      lastlast_Write_srv = last_Write_srv;
302    }
303  }
304  CATCH_DUMP_ATTR
305
306  void CField::writeField(void)
307  TRY
308  {
309    if (!getRelFile()->isEmptyZone())
310    {
311      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
312      {
313        getRelFile()->checkWriteFile();
314        this->incrementNStep();
315        getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
316      }
317    }
318  }
319  CATCH_DUMP_ATTR
320
321  /*
322    Send a request for reading data.
323    Client sends a request to server for demanding server to read data and send back to it.
324    For now, this function is called only by client
325    In the future, it can be called by level-1 servers
326    \param [in] tsDataRequested timestamp when the call is made
327  */
328  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
329  TRY
330  {
331    CContext* context = CContext::getCurrent();
332    // CContextClient* client = context->client;
333
334    // This code is for future: If we want to read file with level-2 servers
335    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
336
337    lastDataRequestedFromServer = tsDataRequested;
338
339    // No need to send the request if we are sure that we are already at EOF
340    if (!isEOF || context->getCalendar()->getCurrentDate() <= dateEOF)
341    {
342      CEventClient event(getType(), EVENT_ID_READ_DATA);
343      if (client->isServerLeader())
344      {
345        CMessage msg;
346        msg << getId();
347        const std::list<int>& ranks = client->getRanksServerLeader();
348        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
349          event.push(*itRank, 1, msg);
350        client->sendEvent(event);
351      }
352      else client->sendEvent(event);
353    }
354    else
355      serverSourceFilter->signalEndOfStream(tsDataRequested);
356
357    wasDataRequestedFromServer = true;
358
359    return !isEOF;
360  }
361  CATCH_DUMP_ATTR
362
363  /*!
364  Send request new data read from file if need be, that is the current data is out-of-date.
365  \return true if and only if some data was requested
366  */
367  bool CField::sendReadDataRequestIfNeeded(void)
368  TRY
369  {
370    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
371
372    bool dataRequested = false;
373
374    while (currentDate >= lastDataRequestedFromServer)
375    {
376      info(20) << "currentDate : " << currentDate << endl ;
377      info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
378      info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
379      info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
380
381      dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq);
382    }
383
384    return dataRequested;
385  }
386  CATCH_DUMP_ATTR
387
388  void CField::recvReadDataRequest(CEventServer& event)
389  TRY
390  {
391    CBufferIn* buffer = event.subEvents.begin()->buffer;
392    StdString fieldId;
393    *buffer >> fieldId;
394    get(fieldId)->recvReadDataRequest();
395  }
396  CATCH
397
398  /*!
399    Receive data request sent from client and process it
400    Every time server receives this request, it will try to read data and sent read data back to client
401    At the moment, this function is called by server level 1
402    In the future, this should (only) be done by the last level servers.
403  */
404  void CField::recvReadDataRequest(void)
405  TRY
406  {
407    CContext* context = CContext::getCurrent();
408    CContextClient* client = context->client;
409
410    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
411    std::list<CMessage> msgs;
412
413    EReadField hasData = readField();
414
415    map<int, CArray<double,1> >::iterator it;
416    if (!grid->doGridHaveDataDistributed(client))
417    {
418       if (client->isServerLeader())
419       {
420          if (0 != recvDataSrv.numElements())
421          {           
422            const std::list<int>& ranks = client->getRanksServerLeader();
423            for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
424            {
425              msgs.push_back(CMessage());
426              CMessage& msg = msgs.back();
427              msg << getId();
428              switch (hasData)
429              {
430                case RF_DATA:
431                  msg << getNStep() - 1 << recvDataSrv;
432                  break;
433                case RF_NODATA:
434                  msg << int(-2) << recvDataSrv;
435                  break;
436                case RF_EOF:                 
437                default:
438                  msg << int(-1);
439                  break;
440              }
441
442              event.push(*itRank, 1, msg);
443            }
444          }
445          client->sendEvent(event);
446       }
447       else
448       {
449          client->sendEvent(event);
450       }
451    }
452    else
453    {
454      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); 
455                                                  it != grid->outLocalIndexStoreOnClient.end(); ++it)
456      {
457        CArray<size_t,1>& indexTmp = it->second;
458        CArray<double,1> tmp(indexTmp.numElements());
459        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
460        {
461          tmp(idx) = recvDataSrv(indexTmp(idx));
462        } 
463
464        msgs.push_back(CMessage());
465        CMessage& msg = msgs.back();
466        msg << getId();
467        switch (hasData)
468        {
469          case RF_DATA:
470            msg << getNStep() - 1 << tmp;
471            break;
472          case RF_NODATA:
473            msg << int(-2) << tmp;
474            break;
475          case RF_EOF:                 
476          default:
477            msg << int(-1);
478            break;
479        }
480
481        event.push(it->first, grid->nbReadSenders[client][it->first], msg);
482      }
483      client->sendEvent(event);
484    }
485  }
486  CATCH_DUMP_ATTR
487
488  /*!
489    Read field from a file.
490    A field is read with the distribution of data on the server side
491    \return State of field can be read from a file
492  */
493  CField::EReadField CField::readField(void)
494  TRY
495  {
496    CContext* context = CContext::getCurrent();
497    grid->computeWrittenIndex();
498    getRelFile()->initRead();
499    EReadField readState = RF_DATA;
500
501    if (!getRelFile()->isEmptyZone())
502    {     
503      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)     
504      {
505        if (0 == recvDataSrv.numElements())
506        {           
507          CArray<int,1>& storeClient = grid->storeIndex_client;         
508          recvDataSrv.resize(storeClient.numElements());         
509        }
510       
511        getRelFile()->checkReadFile();
512
513        if (!nstepMax)
514        {
515          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
516        }
517
518        this->incrementNStep();
519
520        if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
521          readState = RF_EOF;
522
523        if (RF_EOF != readState)
524          getRelFile()->getDataInput()->readFieldData(CField::get(this));
525      }
526    }
527    else
528    {
529      this->incrementNStep();
530      if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
531        readState = RF_EOF;
532      else
533        readState = RF_NODATA;
534
535      if (!nstepMaxRead) // This can be a bug if we try to read field from zero time record
536        readState = RF_NODATA;
537    }
538
539    if (!nstepMaxRead)
540    {
541       MPI_Allreduce(MPI_IN_PLACE, &nstepMax, 1, MPI_INT, MPI_MAX, context->server->intraComm);
542       nstepMaxRead = true;
543    }
544
545    return readState;
546  }
547  CATCH_DUMP_ATTR
548
549  /*
550    Receive read data from server.
551    At the moment, this function is called in the client side.
552    In the future, this function can be called hiearachically (server n-1, server n -2, ..., client)
553    \param event event containing read data
554  */
555  void CField::recvReadDataReady(CEventServer& event)
556  TRY
557  {
558    string fieldId;
559    vector<int> ranks;
560    vector<CBufferIn*> buffers;
561
562    list<CEventServer::SSubEvent>::iterator it;
563    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
564    {
565      ranks.push_back(it->rank);
566      CBufferIn* buffer = it->buffer;
567      *buffer >> fieldId;
568      buffers.push_back(buffer);
569    }
570    get(fieldId)->recvReadDataReady(ranks, buffers);
571  }
572  CATCH
573
574  /*!
575    Receive read data from server
576    \param [in] ranks Ranks of sending processes
577    \param [in] buffers buffers containing read data
578  */
579  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
580  TRY
581  {
582    CContext* context = CContext::getCurrent();
583    std::map<int, CArray<double,1> > data;
584    const bool wasEOF = isEOF;
585
586    for (int i = 0; i < ranks.size(); i++)
587    {
588      int rank = ranks[i];
589      int record;
590      *buffers[i] >> record;
591      isEOF = (record == int(-1));
592
593      if (!isEOF)
594        *buffers[i] >> data[rank];
595      else
596        break;
597    }
598
599    if (wasDataAlreadyReceivedFromServer)
600      lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
601    else
602    {
603      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
604      wasDataAlreadyReceivedFromServer = true;
605    }
606
607    if (isEOF)
608    {
609      if (!wasEOF)
610        dateEOF = lastDataReceivedFromServer;
611
612      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
613    }
614    else
615      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
616  }
617  CATCH_DUMP_ATTR
618
619  void CField::checkForLateDataFromServer(void)
620  TRY
621  {
622    CContext* context = CContext::getCurrent();
623    const CDate& currentDate = context->getCalendar()->getCurrentDate();
624
625    // Check if data previously requested has been received as expected
626    if (wasDataRequestedFromServer && !isEOF)
627    {
628      CTimer timer("CField::checkForLateDataFromServer");
629
630      bool isDataLate;
631      do
632      {
633        const CDate nextDataDue = wasDataAlreadyReceivedFromServer ? (lastDataReceivedFromServer + file->output_freq) : context->getCalendar()->getInitDate();
634        isDataLate = (nextDataDue <= currentDate);
635
636        if (isDataLate)
637        {
638          timer.resume();
639
640          context->checkBuffersAndListen();
641
642          timer.suspend();
643        }
644      }
645      while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout);
646
647      if (isDataLate)
648        ERROR("void CField::checkForLateDataFromServer(void)",
649              << "Late data at timestep = " << currentDate);
650    }
651  }
652  CATCH_DUMP_ATTR
653
654  void CField::checkIfMustAutoTrigger(void)
655  TRY
656  {
657    mustAutoTrigger = serverSourceFilter ? serverSourceFilter->mustAutoTrigger() : false;
658  }
659  CATCH_DUMP_ATTR
660
661  void CField::autoTriggerIfNeeded(void)
662  TRY
663  {
664    if (mustAutoTrigger)
665      serverSourceFilter->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
666  }
667  CATCH_DUMP_ATTR
668
669   //----------------------------------------------------------------
670
671   void CField::setRelFile(CFile* _file)
672   TRY
673   {
674      this->file = _file;
675      hasOutputFile = true;
676   }
677   CATCH_DUMP_ATTR
678
679   //----------------------------------------------------------------
680
681   StdString CField::GetName(void)    { return StdString("field"); }
682   StdString CField::GetDefName(void) { return CField::GetName(); }
683   ENodeType CField::GetType(void)    { return eField; }
684
685   //----------------------------------------------------------------
686
687   CGrid* CField::getRelGrid(void) const
688   TRY
689   {
690      return this->grid;
691   }
692   CATCH
693
694   //----------------------------------------------------------------
695
696   CFile* CField::getRelFile(void) const
697   TRY
698   {
699      return this->file;
700   }
701   CATCH
702
703   int CField::getNStep(void) const
704   TRY
705   {
706      return this->nstep;
707   }
708   CATCH
709
710   func::CFunctor::ETimeType CField::getOperationTimeType() const
711   TRY
712   {
713     return operationTimeType;
714   }
715   CATCH
716
717   //----------------------------------------------------------------
718
719   void CField::incrementNStep(void)
720   TRY
721   {
722      this->nstep++;
723   }
724   CATCH_DUMP_ATTR
725
726   void CField::resetNStep(int nstep /*= 0*/)
727   TRY
728   {
729      this->nstep = nstep;
730   }
731   CATCH_DUMP_ATTR
732
733   void CField::resetNStepMax(void)
734   TRY
735   {
736      this->nstepMax = 0;
737      nstepMaxRead = false;
738   }
739   CATCH_DUMP_ATTR
740
741   //----------------------------------------------------------------
742
743   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
744   TRY
745   {
746      if (clientSourceFilter)
747        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
748      else if (storeFilter)
749        return true;
750      else if (instantDataFilter)
751        ERROR("bool CField::isActive(bool atCurrentTimestep)",
752              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
753
754      return false;
755   }
756   CATCH
757
758   //----------------------------------------------------------------
759
760   bool CField::wasWritten() const
761   TRY
762   {
763     return written;
764   }
765   CATCH
766
767   void CField::setWritten()
768   TRY
769   {
770     written = true;
771   }
772   CATCH_DUMP_ATTR
773
774   //----------------------------------------------------------------
775
776   bool CField::getUseCompressedOutput() const
777   TRY
778   {
779     return useCompressedOutput;
780   }
781   CATCH
782
783   void CField::setUseCompressedOutput()
784   TRY
785   {
786     useCompressedOutput = true;
787   }
788   CATCH_DUMP_ATTR
789
790   //----------------------------------------------------------------
791
792   std::shared_ptr<COutputPin> CField::getInstantDataFilter()
793   TRY
794   {
795     return instantDataFilter;
796   }
797   CATCH_DUMP_ATTR
798
799   //----------------------------------------------------------------
800
801   /*!
802     Build up graph of grids which plays role of destination and source in grid transformation
803     This function should be called before \func solveGridReference()
804   */
805   void CField::buildGridTransformationGraph()
806   TRY
807   {
808     CContext* context = CContext::getCurrent();
809     if (context->hasClient && !context->hasServer)
810     {
811       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
812       {
813         grid->addTransGridSource(getDirectFieldReference()->grid);
814       }
815     }
816   }
817   CATCH_DUMP_ATTR
818
819   /*!
820     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
821   */
822   void CField::generateNewTransformationGridDest()
823   TRY
824   {
825     CContext* context = CContext::getCurrent();
826     if (context->hasClient && !context->hasServer)
827     {
828       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
829       if (1 < gridSrcMap.size())
830       {
831         // Search for grid source
832         CGrid* gridSrc = grid;
833         CField* currField = this;
834         std::vector<CField*> hieraField;
835
836         while (currField->hasDirectFieldReference() && (gridSrc == grid))
837         {
838           hieraField.push_back(currField);
839           CField* tmp = currField->getDirectFieldReference();
840           currField = tmp;
841           gridSrc = currField->grid;
842         }
843
844         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
845         {
846           CGrid* gridTmp;
847           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
848           if (newGridDest.first)
849           {
850             StdString newIdGridDest = newGridDest.second;
851             if (!CGrid::has(newIdGridDest))
852             {
853                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
854                  << " Something wrong happened! Grid whose id " << newIdGridDest
855                  << "should exist ");
856             }
857             gridTmp = CGrid::get(newIdGridDest);
858           }
859           else
860           {
861             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
862             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
863
864             (gridSrcMap[gridSrc]).first = true;
865             (gridSrcMap[gridSrc]).second = newIdGridDest;
866           }
867
868           // Update all descendants
869           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
870           {
871             (*it)->grid = gridTmp;
872             (*it)->updateRef((*it)->grid);
873           }
874         }
875       }
876     }
877   }
878   CATCH_DUMP_ATTR
879
880   void CField::updateRef(CGrid* grid)
881   TRY
882   {
883     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
884     else
885     {
886       std::vector<CAxis*> axisTmp = grid->getAxis();
887       std::vector<CDomain*> domainTmp = grid->getDomains();
888       if ((1<axisTmp.size()) || (1<domainTmp.size()))
889         ERROR("void CField::updateRef(CGrid* grid)",
890           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
891
892       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
893         ERROR("void CField::updateRef(CGrid* grid)",
894           << "Incoherent between available domain and domain_ref of field " << this->getId());
895       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
896         ERROR("void CField::updateRef(CGrid* grid)",
897           << "Incoherent between available axis and axis_ref of field " << this->getId());
898
899       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
900       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
901     }
902   }
903   CATCH_DUMP_ATTR
904   
905   /*!
906     Solve reference of all enabled fields even the source fields .
907     In this step, we do transformations.
908   */
909   void CField::solveAllEnabledFieldsAndTransform()
910   TRY
911   {
912     CContext* context = CContext::getCurrent();
913     bool hasClient = context->hasClient;
914     bool hasServer = context->hasServer;
915
916     if (!isReferenceSolvedAndTransformed)
917     {
918        isReferenceSolvedAndTransformed = true;
919
920        if (hasClient && !hasServer)
921        {
922          solveRefInheritance(true);
923          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
924        }
925
926        if (hasServer)
927          solveServerOperation();
928
929        solveGridReference();
930
931        if (hasClient && !hasServer)
932       {
933         solveGenerateGrid();
934         buildGridTransformationGraph();
935       }
936
937       solveGridDomainAxisRef(false);
938
939       if (hasClient && !hasServer)
940       {
941         solveTransformedGrid();
942       }
943
944       solveGridDomainAxisRef(false);
945     }
946   }
947   CATCH_DUMP_ATTR
948
949   void CField::checkGridOfEnabledFields()
950   TRY
951   {
952     if (!isGridChecked)
953     {
954       isGridChecked = true;
955       solveCheckMaskIndex(false);
956     }
957   }
958   CATCH_DUMP_ATTR
959
960   void CField::sendGridComponentOfEnabledFields()
961   TRY
962   {
963      solveGridDomainAxisRef(true);
964      // solveCheckMaskIndex(true);
965   }
966   CATCH_DUMP_ATTR
967
968   void CField::sendGridOfEnabledFields()
969   TRY
970   {
971      // solveGridDomainAxisRef(true);
972      solveCheckMaskIndex(true);
973   }   
974   CATCH_DUMP_ATTR
975
976   void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
977   TRY
978   {
979     CContext* context = CContext::getCurrent();
980     if (!isReferenceSolved)
981     {
982        isReferenceSolved = true;
983
984        if (context->hasClient && !context->hasServer)
985        {
986          solveRefInheritance(true);
987          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
988        }
989
990        if (context->hasServer)
991          solveServerOperation();
992
993        solveGridReference();
994        grid->solveDomainAxisRefInheritance(true); // make it again to solve grid reading from file
995
996        if (context->hasClient && !context->hasServer)
997       {
998         solveGenerateGrid();
999         buildGridTransformationGraph();
1000       }
1001     }
1002   }
1003   CATCH_DUMP_ATTR
1004
1005   void CField::solveAllReferenceEnabledField(bool doSending2Server)
1006   TRY
1007   {
1008     CContext* context = CContext::getCurrent();
1009     solveOnlyReferenceEnabledField(doSending2Server);
1010
1011     if (!areAllReferenceSolved)
1012     {
1013        areAllReferenceSolved = true;
1014       
1015        if (context->hasClient && !context->hasServer)
1016        {
1017          solveRefInheritance(true);
1018          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
1019        }
1020        else if (context->hasServer)
1021          solveServerOperation();
1022
1023        solveGridReference();
1024     }
1025
1026     solveGridDomainAxisRef(doSending2Server);
1027
1028     if (context->hasClient && !context->hasServer)
1029     {
1030       solveTransformedGrid();
1031     }
1032
1033     solveCheckMaskIndex(doSending2Server);
1034   }
1035   CATCH_DUMP_ATTR
1036
1037   std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
1038   TRY
1039   {
1040     return grid->getAttributesBufferSize(client, bufferForWriting);
1041   }
1042   CATCH_DUMP_ATTR
1043
1044   std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
1045   TRY
1046   {
1047     return grid->getDataBufferSize(client, getId(), bufferForWriting);
1048   }
1049   CATCH_DUMP_ATTR
1050
1051   size_t CField::getGlobalWrittenSize()
1052   TRY
1053   {
1054     return grid->getGlobalWrittenSize();
1055   }
1056   CATCH_DUMP_ATTR
1057
1058   //----------------------------------------------------------------
1059
1060   void CField::solveServerOperation(void)
1061   TRY
1062   {
1063      CContext* context = CContext::getCurrent();
1064
1065      if (!context->hasServer || !hasOutputFile) return;
1066
1067      if (freq_op.isEmpty())
1068        freq_op.setValue(TimeStep);
1069
1070      if (freq_offset.isEmpty())
1071        freq_offset.setValue(NoneDu);
1072
1073      freq_operation_srv = file->output_freq.getValue();
1074      freq_write_srv     = file->output_freq.getValue();
1075
1076      lastlast_Write_srv = context->getCalendar()->getInitDate();
1077      last_Write_srv     = context->getCalendar()->getInitDate();
1078      last_operation_srv = context->getCalendar()->getInitDate();
1079
1080      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
1081      last_operation_srv     = last_operation_srv - toffset;
1082
1083      if (operation.isEmpty())
1084        ERROR("void CField::solveServerOperation(void)",
1085              << "An operation must be defined for field \"" << getId() << "\".");
1086
1087      std::shared_ptr<func::CFunctor> functor;
1088      CArray<double, 1> dummyData;
1089
1090#define DECLARE_FUNCTOR(MType, mtype) \
1091      if (operation.getValue().compare(#mtype) == 0) \
1092      { \
1093        functor.reset(new func::C##MType(dummyData)); \
1094      }
1095
1096#include "functor_type.conf"
1097
1098      if (!functor)
1099        ERROR("void CField::solveServerOperation(void)",
1100              << "\"" << operation << "\" is not a valid operation.");
1101
1102      operationTimeType = functor->timeType();
1103   }
1104   CATCH_DUMP_ATTR
1105
1106   //----------------------------------------------------------------
1107
1108   /*!
1109    * Constructs the graph filter for the field, enabling or not the data output.
1110    * This method should not be called more than once with enableOutput equal to true.
1111    *
1112    * \param gc the garbage collector to use when building the filter graph
1113    * \param enableOutput must be true when the field data is to be
1114    *                     read by the client or/and written to a file
1115    */
1116   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput, Time start_graph, Time end_graph)
1117   TRY
1118   {     
1119     if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
1120     if (!isGridChecked) checkGridOfEnabledFields();
1121
1122     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1123     
1124     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1125
1126     
1127     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1128
1129     CContext* context = CContext::getCurrent();
1130     
1131     Time filter_start;
1132     if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1133     else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1134     else filter_start = -1;
1135
1136     Time filter_end;
1137     if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1138     else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1139     else filter_end = -1;
1140
1141     if(this->field_graph_start==-2) this->field_graph_start = filter_start;
1142     if(this->field_graph_end==-2) this->field_graph_end = filter_end;         // init
1143
1144     // if(CXios::isClient) std::cout<<"****************** buildFilterGraph : field_id = "<<this->getId()<<" BEFORE: this->field_graph_start = "<<this->field_graph_start<<" this->field_graph_end = "<<this->field_graph_end<<std::endl;
1145
1146     if(start_graph == -1)
1147     {
1148       //nothing
1149       // if(CXios::isClient) std::cout<<"buildFilterGraph field_id = "<<this->getId()<<" case1: this->field_graph_start = "<<this->field_graph_start<<std::endl;
1150     }
1151     else //if(start_graph != -1)
1152     {
1153       if(this->field_graph_start == -1) this->field_graph_start = start_graph;
1154       else this->field_graph_start = min(this->field_graph_start, start_graph);
1155
1156       // if(CXios::isClient) std::cout<<"buildFilterGraph field_id = "<<this->getId()<<" case2: this->field_graph_start = "<<this->field_graph_start<<std::endl;
1157     }
1158
1159
1160     if(end_graph == -1)
1161     {
1162       //nothing
1163       // if(CXios::isClient) std::cout<<"buildFilterGraph field_id = "<<this->getId()<<" case1: this->field_graph_end = "<<this->field_graph_end<<std::endl;
1164     }
1165     else
1166     {
1167       if(this->field_graph_end == -1) this->field_graph_end = end_graph;
1168       else this->field_graph_end = max(this->field_graph_end, end_graph);
1169
1170       // if(CXios::isClient) std::cout<<"buildFilterGraph field_id = "<<this->getId()<<" case2: this->field_graph_end = "<<this->field_graph_end<<std::endl;
1171     }
1172   
1173
1174     filter_start = this->field_graph_start;
1175     filter_end = this->field_graph_end;
1176
1177
1178     // if(CXios::isClient) std::cout<<"****************** buildFilterGraph : field_id = "<<this->getId()<<" AFTER: this->field_graph_start = "<<this->field_graph_start<<" this->field_graph_end = "<<this->field_graph_end<<std::endl;
1179     
1180
1181     
1182     
1183
1184     bool hasWriterServer = context->hasServer && !context->hasClient;
1185     bool hasIntermediateServer = context->hasServer && context->hasClient;
1186
1187     if (hasWriterServer)
1188     {
1189        if (!instantDataFilter)
1190          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false));
1191
1192
1193       // If the field data is to be read by the client or/and written to a file
1194       if (enableOutput && !storeFilter && !fileWriterFilter)
1195       {
1196         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1197         {
1198           fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1199           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1200         }
1201       }
1202     }
1203     else if (hasIntermediateServer)
1204     {
1205       if (!instantDataFilter)
1206         instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, false));
1207
1208             // If the field data is to be read by the client or/and written to a file
1209       if (enableOutput && !storeFilter && !fileWriterFilter)
1210       {
1211         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1212         {
1213           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1214           instantDataFilter->connectOutput(fileWriterFilter, 0);
1215         }
1216       }
1217     }
1218     else
1219     {
1220       // Start by building a filter which can provide the field's instant data
1221       if (!instantDataFilter)
1222       {
1223         // Check if we have an expression to parse
1224         if (hasExpression())
1225         {
1226           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1227           std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this, filter_start, filter_end);
1228
1229           // Check if a spatial transformation is needed
1230           if (!field_ref.isEmpty())
1231           {
1232             CGrid* gridRef = CField::get(field_ref)->grid;
1233
1234             if (grid && grid != gridRef && grid->hasTransform())
1235             {
1236               std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue);
1237
1238               filter->connectOutput(filters.first, 0);
1239               filter = filters.second;
1240             }
1241           }
1242
1243           instantDataFilter = filter;
1244           instantDataFilter->field = this;
1245           filter->tag = buildWorkflowGraph;
1246           
1247           filter->start_graph = filter_start;
1248           filter->end_graph = filter_end;
1249
1250           for(int i=0; i<filter->parent_filters.size(); i++)
1251           {
1252             filter->tag = filter->tag || filter->parent_filters[i]->tag;
1253           }
1254         }
1255         // Check if we have a reference on another field
1256         else if (!field_ref.isEmpty())
1257         {
1258           instantDataFilter = getFieldReference(gc, filter_start, filter_end);
1259           instantDataFilter->tag = buildWorkflowGraph;
1260           instantDataFilter->start_graph = filter_start;
1261           instantDataFilter->end_graph = filter_end;
1262         }
1263         // Check if the data is to be read from a file
1264         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1265         {
1266           checkTimeAttributes();
1267           instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1268                                                                                                       detectMissingValues, defaultValue));
1269           instantDataFilter->tag = buildWorkflowGraph;
1270           instantDataFilter->start_graph = filter_start;
1271           instantDataFilter->end_graph = filter_end;
1272           instantDataFilter->field = this;
1273
1274         }
1275         else // The data might be passed from the model
1276         {
1277            if (check_if_active.isEmpty()) check_if_active = false; 
1278            instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, true, NoneDu, false,
1279                                                                                                      detectMissingValues, defaultValue)); 
1280            instantDataFilter->tag = buildWorkflowGraph;
1281            instantDataFilter->start_graph = filter_start;
1282            instantDataFilter->end_graph = filter_end;
1283            instantDataFilter->field = this;
1284            // if(CXios::isClient) std::cout<<"***********************buildFilterGraph init source filter : field_id = "<<this->getId()<<" sourcefilter->start_graph = "<<clientSourceFilter->start_graph<<" sourcefilter->end_graph = "<<clientSourceFilter->end_graph<<std::endl;
1285         }
1286       }
1287
1288       // If the field data is to be read by the client or/and written to a file
1289       if (enableOutput && !storeFilter && !fileWriterFilter)
1290       {
1291         if (!read_access.isEmpty() && read_access)
1292         {
1293           storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1294                                                                          detectMissingValues, defaultValue));
1295           instantDataFilter->connectOutput(storeFilter, 0);
1296
1297           storeFilter->tag = (instantDataFilter->tag || buildWorkflowGraph);
1298           instantDataFilter->start_graph = filter_start;
1299           instantDataFilter->end_graph = filter_end;
1300
1301           instantDataFilter->setParentFiltersTag();
1302           storeFilter->start_graph = filter_start;
1303           storeFilter->end_graph = filter_end;
1304           storeFilter->field = this;
1305           storeFilter->distance = instantDataFilter->distance+1;
1306         }
1307
1308         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1309         {
1310           fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1311           getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1312           
1313           fileWriterFilter->tag = (getTemporalDataFilter(gc, file->output_freq)->tag || buildWorkflowGraph);
1314           getTemporalDataFilter(gc, file->output_freq)->start_graph = filter_start;
1315           getTemporalDataFilter(gc, file->output_freq)->end_graph = filter_end;
1316           getTemporalDataFilter(gc, file->output_freq)->tag = buildWorkflowGraph;
1317           getTemporalDataFilter(gc, file->output_freq)->setParentFiltersTag();
1318           fileWriterFilter->start_graph = filter_start;
1319           fileWriterFilter->end_graph = filter_end;
1320           fileWriterFilter->distance = getTemporalDataFilter(gc, file->output_freq)->distance+1;
1321
1322           // std::cout<<"CFileWriterFilter filter start = "<<filter_start<<" end = "<<filter_end<<" field = "<<this->getId()<<std::endl;
1323
1324         }
1325       }
1326     }
1327   }
1328   CATCH_DUMP_ATTR
1329
1330   /*!
1331    * Returns the filter needed to handle the field reference.
1332    * This method should only be called when building the filter graph corresponding to the field.
1333    *
1334    * \param gc the garbage collector to use
1335    * \return the output pin corresponding to the field reference
1336    */
1337   std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc, Time start_graph, Time end_graph)
1338   TRY
1339   {
1340     if (instantDataFilter || field_ref.isEmpty())
1341       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1342             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1343
1344     CField* fieldRef = CField::get(field_ref);
1345     fieldRef->buildFilterGraph(gc, false, start_graph, end_graph);
1346     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1347
1348     CContext* context = CContext::getCurrent();
1349
1350     Time filter_start;
1351     if(!build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = context->calendar->getInitDate()+build_workflow_graph_start;
1352     else if(build_workflow_graph_start.isEmpty() && buildWorkflowGraph) filter_start = 0;
1353     else filter_start = -1;
1354
1355     Time filter_end;
1356     if(!build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = context->calendar->getInitDate()+build_workflow_graph_end;
1357     else if(build_workflow_graph_end.isEmpty() && buildWorkflowGraph) filter_end = 9223372036854775807;
1358     else filter_end = -1;
1359
1360     if(this->field_graph_start==-2) this->field_graph_start = filter_start;
1361     if(this->field_graph_end==-2) this->field_graph_end = filter_end;         // init
1362
1363     // if(CXios::isClient) std::cout<<"getFieldReference field_id = "<<this->getId()<<" BEFORE: this->field_graph_start = "<<this->field_graph_start<<" this->field_graph_end = "<<this->field_graph_end<<std::endl;
1364
1365     if(start_graph == -1)
1366     {
1367       //nothing
1368       // if(CXios::isClient) std::cout<<"getFieldReference field_id = "<<this->getId()<<" case1: this->field_graph_start = "<<this->field_graph_start<<std::endl;
1369     }
1370     else //if(start_graph != -1)
1371     {
1372       if(this->field_graph_start == -1) this->field_graph_start = start_graph;
1373       else this->field_graph_start = min(this->field_graph_start, start_graph);
1374
1375       // if(CXios::isClient) std::cout<<"getFieldReference field_id = "<<this->getId()<<" case2: this->field_graph_start = "<<this->field_graph_start<<std::endl;
1376     }
1377
1378     if(end_graph == -1)
1379     {
1380       //nothing
1381       // if(CXios::isClient) std::cout<<"getFieldReference field_id = "<<this->getId()<<" case1: this->field_graph_end = "<<this->field_graph_end<<std::endl;
1382     }
1383     else
1384     {
1385       if(this->field_graph_end == -1) this->field_graph_end = end_graph;
1386       else this->field_graph_end = max(this->field_graph_end, end_graph);
1387
1388       // if(CXios::isClient) std::cout<<"getFieldReference field_id = "<<this->getId()<<" case2: this->field_graph_end = "<<this->field_graph_end<<std::endl;
1389     }
1390
1391     filter_start = this->field_graph_start;
1392     filter_end = this->field_graph_end;
1393
1394     // if(CXios::isClient) std::cout<<"getFieldReference field_id = "<<this->getId()<<" AFTER: this->field_graph_start = "<<this->field_graph_start<<" this->field_graph_end = "<<this->field_graph_end<<std::endl;
1395
1396
1397     std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1398     // Check if a spatial transformation is needed
1399     if (grid && grid != fieldRef->grid && grid->hasTransform())
1400     {       
1401       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1402       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1403       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1404
1405       fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1406
1407     
1408
1409       filters.second->parent_filters.resize(1);
1410       filters.second->parent_filters[0]= fieldRef->getInstantDataFilter();
1411
1412       filters.second->tag = (buildWorkflowGraph || filters.second->parent_filters[0]->tag);
1413       
1414       filters.second->start_graph = filter_start;
1415       filters.second->end_graph = filter_end;
1416       filters.second->field = this;
1417       
1418     }
1419     else
1420     {
1421       filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1422
1423       fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1424     
1425
1426       filters.second->parent_filters.resize(1);
1427       filters.second->parent_filters[0]= fieldRef->getInstantDataFilter();
1428
1429       filters.second->tag = (buildWorkflowGraph || filters.second->parent_filters[0]->tag);
1430
1431       filters.second->start_graph = filter_start;
1432       filters.second->end_graph = filter_end;
1433       filters.second->field = this;
1434
1435     }
1436
1437     return filters.second;
1438   }
1439   CATCH_DUMP_ATTR
1440
1441   /*!
1442    * Returns the filter needed to handle a self reference in the field's expression.
1443    * If the needed filter does not exist, it is created, otherwise it is reused.
1444    * This method should only be called when building the filter graph corresponding
1445    * to the field's expression.
1446    *
1447    * \param gc the garbage collector to use
1448    * \return the output pin corresponding to a self reference
1449    */
1450   std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc, Time start_graph, Time end_graph)
1451   TRY
1452   {
1453     //if(CXios::isClient) std::cout<<"getSelfReference field_id = "<<this->getId()<<" start_graph = "<<start_graph<<" end_graph = "<<end_graph<<std::endl;
1454
1455     if (instantDataFilter || !hasExpression())
1456       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1457             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1458     
1459     bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1460
1461     if (!selfReferenceFilter)
1462     {
1463       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1464       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1465
1466       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1467       {
1468         if (!serverSourceFilter)
1469         {
1470           checkTimeAttributes();
1471           serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1472                                                                                   detectMissingValues, defaultValue));
1473         }
1474
1475         selfReferenceFilter = serverSourceFilter;
1476       }
1477       else if (!field_ref.isEmpty())
1478       {
1479         CField* fieldRef = CField::get(field_ref);
1480         fieldRef->buildFilterGraph(gc, false);
1481         selfReferenceFilter = fieldRef->getInstantDataFilter();
1482       }
1483       else
1484       {
1485         if (!clientSourceFilter)
1486         {
1487           if (check_if_active.isEmpty()) check_if_active = false;
1488           clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, true, NoneDu, false,
1489                                                                                   detectMissingValues, defaultValue));
1490         }
1491
1492         selfReferenceFilter = clientSourceFilter;
1493       }
1494     }
1495
1496     selfReferenceFilter->tag = buildWorkflowGraph;
1497     selfReferenceFilter->field = this;
1498     return selfReferenceFilter;
1499   }
1500   CATCH_DUMP_ATTR
1501
1502   /*!
1503    * Returns the temporal filter corresponding to the field's temporal operation
1504    * for the specified operation frequency. The filter is created if it does not
1505    * exist, otherwise it is reused.
1506    *
1507    * \param gc the garbage collector to use
1508    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1509    * \return the output pin corresponding to the requested temporal filter
1510    */
1511   std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1512   TRY
1513   {
1514     std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1515     const bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1516
1517     CContext* context = CContext::getCurrent();
1518
1519
1520     if (it == temporalDataFilters.end())
1521     {
1522       if (operation.isEmpty())
1523         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1524               << "An operation must be defined for field \"" << getId() << "\".");
1525
1526       checkTimeAttributes(&outFreq);
1527
1528       const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1529       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1530                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1531                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1532
1533       instantDataFilter->connectOutput(temporalFilter, 0);
1534       //temporalFilter->tag = buildWorkflowGraph;
1535       
1536       temporalFilter->parent_filters.resize(1);
1537       temporalFilter->parent_filters[0] = instantDataFilter;
1538       
1539
1540       //if(temporalFilter->parent_filters[0]->tag) temporalFilter->tag=true;
1541       temporalFilter->tag = temporalFilter->parent_filters[0]->tag;
1542       temporalFilter->start_graph = temporalFilter->parent_filters[0]->start_graph;
1543       temporalFilter->end_graph = temporalFilter->parent_filters[0]->end_graph;
1544
1545       // temporalFilter->start_graph = filter_start;
1546       // temporalFilter->end_graph = filter_end;
1547       temporalFilter->field = this;
1548
1549       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1550     }
1551
1552     return it->second;
1553   }
1554   CATCH_DUMP_ATTR
1555
1556  /*!
1557    * Returns the temporal filter corresponding to the field's temporal operation
1558    * for the specified operation frequency.
1559    *
1560    * \param gc the garbage collector to use
1561    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1562    * \return the output pin corresponding to the requested temporal filter
1563    */
1564   
1565   std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1566   TRY
1567   {
1568     if (instantDataFilter || !hasExpression())
1569       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1570             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1571
1572     if (!selfReferenceFilter) getSelfReference(gc) ;
1573
1574     if (serverSourceFilter || clientSourceFilter)
1575     {
1576       if (operation.isEmpty())
1577         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1578               << "An operation must be defined for field \"" << getId() << "\".");
1579
1580       checkTimeAttributes(&outFreq);
1581
1582       const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1583       bool buildWorkflowGraph = (!build_workflow_graph.isEmpty() && build_workflow_graph == true);
1584       std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1585                                                                           CContext::getCurrent()->getCalendar()->getInitDate(),
1586                                                                           freq_op, freq_offset, outFreq, detectMissingValues));
1587
1588       selfReferenceFilter->connectOutput(temporalFilter, 0);
1589       temporalFilter->tag = buildWorkflowGraph;
1590       temporalFilter->field = this;
1591
1592       return temporalFilter ;
1593     }
1594     else if (!field_ref.isEmpty())
1595     {
1596       CField* fieldRef = CField::get(field_ref);
1597       fieldRef->buildFilterGraph(gc, false); 
1598       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1599     }
1600  }
1601   CATCH_DUMP_ATTR
1602
1603   //----------------------------------------------------------------
1604/*
1605   void CField::fromBinary(StdIStream& is)
1606   {
1607      SuperClass::fromBinary(is);
1608#define CLEAR_ATT(name_)\
1609      SuperClassAttribute::operator[](#name_)->reset()
1610
1611         CLEAR_ATT(domain_ref);
1612         CLEAR_ATT(axis_ref);
1613#undef CLEAR_ATT
1614
1615   }
1616*/
1617   //----------------------------------------------------------------
1618
1619   void CField::solveGridReference(void)
1620   TRY
1621   {
1622      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1623      {
1624        ERROR("CField::solveGridReference(void)",
1625              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1626      }
1627      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1628      {
1629        ERROR("CField::solveGridReference(void)",
1630              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1631              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1632      }
1633
1634      if (grid_ref.isEmpty())
1635      {
1636        std::vector<CDomain*> vecDom;
1637        std::vector<CAxis*> vecAxis;
1638        std::vector<CScalar*> vecScalar;
1639        std::vector<int> axisDomainOrderTmp;
1640
1641        std::vector<CDomain*> vecDomRef;
1642        std::vector<CAxis*> vecAxisRef;
1643        std::vector<CScalar*> vecScalarRef;
1644
1645       
1646        if (!domain_ref.isEmpty())
1647        {
1648          StdString tmp = domain_ref.getValue();
1649          if (CDomain::has(domain_ref))
1650          {
1651            vecDom.push_back(CDomain::get(domain_ref));
1652            vecDomRef.push_back(CDomain::createDomain());
1653            vecDomRef.back()->domain_ref=domain_ref;
1654            axisDomainOrderTmp.push_back(2);
1655          }
1656          else  ERROR("CField::solveGridReference(void)",
1657                      << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1658        }
1659
1660        if (!axis_ref.isEmpty())
1661        {
1662          if (CAxis::has(axis_ref))
1663          {
1664            vecAxis.push_back(CAxis::get(axis_ref));
1665            vecAxisRef.push_back(CAxis::createAxis());
1666            vecAxisRef.back()->axis_ref=axis_ref;
1667            axisDomainOrderTmp.push_back(1);
1668          }
1669          else  ERROR("CField::solveGridReference(void)",
1670                      << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1671        }
1672
1673        if (!scalar_ref.isEmpty())
1674        {
1675          if (CScalar::has(scalar_ref))
1676          {
1677            vecScalar.push_back(CScalar::get(scalar_ref));
1678            vecScalarRef.push_back(CScalar::createScalar());
1679            vecScalarRef.back()->scalar_ref=scalar_ref;
1680            axisDomainOrderTmp.push_back(0);
1681          }
1682          else ERROR("CField::solveGridReference(void)",
1683                     << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1684        }
1685       
1686        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1687        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1688        {
1689          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1690        }
1691
1692        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1693        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1694        if (CGrid::has(gridId)) this->grid = CGrid::get(gridId);
1695        else  this->grid = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1696      }
1697      else
1698      {
1699        if (CGrid::has(grid_ref)) this->grid = CGrid::get(grid_ref);
1700        else  ERROR("CField::solveGridReference(void)",
1701                     << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1702      }
1703   }
1704   CATCH_DUMP_ATTR
1705
1706   void CField::solveGridDomainAxisRef(bool checkAtt)
1707   TRY
1708   {
1709     grid->solveDomainAxisRef(checkAtt);
1710   }
1711   CATCH_DUMP_ATTR
1712
1713   void CField::solveCheckMaskIndex(bool doSendingIndex)
1714   TRY
1715   {
1716     grid->checkMaskIndex(doSendingIndex);
1717   }
1718   CATCH_DUMP_ATTR
1719
1720   void CField::solveTransformedGrid()
1721   TRY
1722   {
1723     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1724     {
1725       std::vector<CGrid*> grids;
1726       // Source grid
1727       grids.push_back(getDirectFieldReference()->grid);
1728       // Intermediate grids
1729       if (!grid_path.isEmpty())
1730       {
1731         std::string gridId;
1732         size_t start = 0, end;
1733
1734         do
1735         {
1736           end = grid_path.getValue().find(',', start);
1737           if (end != std::string::npos)
1738           {
1739             gridId = grid_path.getValue().substr(start, end - start);
1740             start = end + 1;
1741           }
1742           else
1743             gridId = grid_path.getValue().substr(start);
1744
1745           if (!CGrid::has(gridId))
1746             ERROR("void CField::solveTransformedGrid()",
1747                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1748
1749           grids.push_back(CGrid::get(gridId));
1750         }
1751         while (end != std::string::npos);
1752       }
1753       // Destination grid
1754       grids.push_back(grid);
1755
1756       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1757       {
1758         CGrid *gridSrc  = grids[i];
1759         CGrid *gridDest = grids[i + 1];
1760         if (!gridDest->isTransformed())
1761           gridDest->transformGrid(gridSrc);
1762       }
1763     }
1764     else if (grid && grid->hasTransform() && !grid->isTransformed())
1765     {
1766       // Temporarily deactivate the self-transformation of grid
1767       // grid->transformGrid(grid);
1768     }
1769   }
1770   CATCH_DUMP_ATTR
1771
1772   void CField::solveGenerateGrid()
1773   TRY
1774   {
1775     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1776       grid->completeGrid(getDirectFieldReference()->grid);
1777     else
1778       grid->completeGrid();
1779   }
1780   CATCH_DUMP_ATTR
1781
1782   void CField::solveGridDomainAxisBaseRef()
1783   TRY
1784   {
1785     grid->solveDomainAxisRef(false);
1786     grid->solveDomainAxisBaseRef();
1787   }
1788   CATCH_DUMP_ATTR
1789
1790   ///-------------------------------------------------------------------
1791
1792   template <>
1793   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1794   TRY
1795   {
1796      if (this->group_ref.isEmpty()) return;
1797      StdString gref = this->group_ref.getValue();
1798
1799      if (!CFieldGroup::has(gref))
1800         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1801               << "[ gref = " << gref << "]"
1802               << " invalid group name !");
1803
1804      CFieldGroup* group = CFieldGroup::get(gref);
1805      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1806      owner->setAttributes(group); // inherite of attributes of group reference
1807     
1808      std::vector<CField*> allChildren  = group->getAllChildren();
1809      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1810
1811      for (; it != end; it++)
1812      {
1813         CField* child = *it;
1814         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1815
1816      }
1817   }
1818   CATCH_DUMP_ATTR
1819
1820   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1821   TRY
1822   {
1823     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1824   }
1825   CATCH_DUMP_ATTR
1826
1827   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1828   TRY
1829   {
1830     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1831   }
1832   CATCH_DUMP_ATTR
1833
1834   void CField::outputField(CArray<double,1>& fieldOut)
1835   TRY
1836   { 
1837      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1838      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1839      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1840      {
1841        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1842      }
1843   }
1844   CATCH_DUMP_ATTR
1845
1846   void CField::inputField(CArray<double,1>& fieldIn)
1847   TRY
1848   {
1849      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1850      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1851      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1852      {
1853        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1854      }
1855   }
1856   CATCH_DUMP_ATTR
1857
1858   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1859   TRY
1860   {
1861      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1862      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1863      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1864      {
1865        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1866      }
1867   }
1868   CATCH_DUMP_ATTR
1869
1870   ///-------------------------------------------------------------------
1871
1872   void CField::parse(xml::CXMLNode& node)
1873   TRY
1874   {
1875      string newContent ;
1876      SuperClass::parse(node);
1877      if (node.goToChildElement())
1878      {
1879        do
1880        {
1881          if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1882          else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1883        } while (node.goToNextElement());
1884        node.goToParentElement();
1885      }
1886      if (node.getContent(newContent)) content=newContent ;
1887    }
1888   CATCH_DUMP_ATTR
1889
1890   /*!
1891     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1892   of a field. In some cases, only domain exists but axis doesn't
1893   \return pair of Domain and Axis id
1894   */
1895   const std::vector<StdString>& CField::getRefDomainAxisIds()
1896   TRY
1897   {
1898     CGrid* cgPtr = getRelGrid();
1899     if (NULL != cgPtr)
1900     {
1901       std::vector<StdString>::iterator it;
1902       if (!domain_ref.isEmpty())
1903       {
1904         std::vector<StdString> domainList = cgPtr->getDomainList();
1905         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1906         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1907       }
1908
1909       if (!axis_ref.isEmpty())
1910       {
1911         std::vector<StdString> axisList = cgPtr->getAxisList();
1912         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1913         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1914       }
1915
1916       if (!scalar_ref.isEmpty())
1917       {
1918         std::vector<StdString> scalarList = cgPtr->getScalarList();
1919         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1920         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1921       }
1922     }
1923     return (domAxisScalarIds_);
1924   }
1925   CATCH_DUMP_ATTR
1926
1927   CVariable* CField::addVariable(const string& id)
1928   TRY
1929   {
1930     return vVariableGroup->createChild(id);
1931   }
1932   CATCH
1933
1934   CVariableGroup* CField::addVariableGroup(const string& id)
1935   TRY
1936   {
1937     return vVariableGroup->createChildGroup(id);
1938   }
1939   CATCH
1940
1941   void CField::setContextClient(CContextClient* contextClient)
1942   TRY
1943   {
1944     CContext* context = CContext::getCurrent();
1945     client = contextClient;
1946     if (context->hasClient)
1947     {
1948       // A grid is sent by a client (both for read or write) or by primary server (write only)
1949       if (context->hasServer)
1950       {
1951         if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1952           grid->setContextClient(contextClient);
1953       }
1954       else
1955           grid->setContextClient(contextClient);
1956     }
1957   }
1958   CATCH_DUMP_ATTR
1959
1960   CContextClient* CField::getContextClient()
1961   TRY
1962   {
1963     return client;
1964   }
1965   CATCH
1966
1967   void CField::sendAddAllVariables(CContextClient* client)
1968   TRY
1969   {
1970     std::vector<CVariable*> allVar = getAllVariables();
1971     std::vector<CVariable*>::const_iterator it = allVar.begin();
1972     std::vector<CVariable*>::const_iterator itE = allVar.end();
1973
1974     for (; it != itE; ++it)
1975     {
1976       this->sendAddVariable((*it)->getId(), client);
1977       (*it)->sendAllAttributesToServer(client);
1978       (*it)->sendValue(client);
1979     }
1980   }
1981   CATCH_DUMP_ATTR
1982
1983   /*!
1984    * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
1985    * must be sent to server and not domain_ref/axis_ref/scalar_ref.
1986    */
1987   
1988   void CField::sendAllAttributesToServer(CContextClient* client)
1989   TRY
1990   {
1991     if (grid_ref.isEmpty())
1992     {
1993       grid_ref=grid->getId() ;
1994       SuperClass::sendAllAttributesToServer(client) ;
1995       grid_ref.reset();
1996     }
1997     else SuperClass::sendAllAttributesToServer(client) ;
1998   }
1999   CATCH_DUMP_ATTR
2000   
2001   void CField::sendAddVariable(const string& id, CContextClient* client)
2002   TRY
2003   {
2004      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
2005   }
2006   CATCH_DUMP_ATTR
2007
2008   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
2009   TRY
2010   {
2011      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
2012   }
2013   CATCH_DUMP_ATTR
2014
2015   void CField::recvAddVariable(CEventServer& event)
2016   TRY
2017   {
2018
2019      CBufferIn* buffer = event.subEvents.begin()->buffer;
2020      string id;
2021      *buffer >> id;
2022      get(id)->recvAddVariable(*buffer);
2023   }
2024   CATCH
2025
2026   void CField::recvAddVariable(CBufferIn& buffer)
2027   TRY
2028   {
2029      string id;
2030      buffer >> id;
2031      addVariable(id);
2032   }
2033   CATCH_DUMP_ATTR
2034
2035   void CField::recvAddVariableGroup(CEventServer& event)
2036   TRY
2037   {
2038
2039      CBufferIn* buffer = event.subEvents.begin()->buffer;
2040      string id;
2041      *buffer >> id;
2042      get(id)->recvAddVariableGroup(*buffer);
2043   }
2044   CATCH
2045
2046   void CField::recvAddVariableGroup(CBufferIn& buffer)
2047   TRY
2048   {
2049      string id;
2050      buffer >> id;
2051      addVariableGroup(id);
2052   }
2053   CATCH_DUMP_ATTR
2054
2055   /*!
2056    * Check on freq_off and freq_op attributes.
2057    */
2058   void CField::checkTimeAttributes(CDuration* freqOp)
2059   TRY
2060   {
2061     bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
2062     bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
2063     if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
2064       ERROR("void CField::checkTimeAttributes(void)",
2065             << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
2066             << "Currently only \"instant\" is supported for fields read from file.")
2067
2068     if (freq_op.isEmpty())
2069     {
2070       if (operation.getValue() == "instant")
2071       {
2072         if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
2073         else freq_op=*freqOp ;
2074       }
2075       else
2076         freq_op.setValue(TimeStep);
2077     }
2078     if (freq_offset.isEmpty())
2079       freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
2080   }
2081   CATCH_DUMP_ATTR
2082
2083   /*!
2084    * Returns string arithmetic expression associated to the field.
2085    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
2086    */
2087   const string& CField::getExpression(void)
2088   TRY
2089   {
2090     if (!expr.isEmpty() && content.empty())
2091     {
2092       content = expr;
2093       expr.reset();
2094     }
2095
2096     return content;
2097   }
2098   CATCH_DUMP_ATTR
2099
2100   bool CField::hasExpression(void) const
2101   TRY
2102   {
2103     return (!expr.isEmpty() || !content.empty());
2104   }
2105   CATCH
2106
2107   bool CField::hasGridMask(void) const
2108   TRY
2109   {
2110     return (this->grid->hasMask());
2111   }
2112   CATCH
2113
2114   DEFINE_REF_FUNC(Field,field)
2115} // namespace xios
Note: See TracBrowser for help on using the repository browser.