source: XIOS/dev/dev_ym/XIOS_COUPLING/src/node/field.cpp @ 1872

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

Some update on XIOS_COUPLING branch...

YM

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