source: XIOS/dev/dev_trunk_omp/src/node/field.cpp @ 1689

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

dev for graph. up to date with trunk at r1684

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