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

Last change on this file since 1871 was 1871, 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: 69.2 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    , file()
36    , written(false)
37    , nstep(0), nstepMax(0)
38    , hasOutputFile(false)
39    , domAxisScalarIds_(vector<StdString>(3,""))
40    , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
41    , isGridChecked(false)
42    , useCompressedOutput(false)
43    , hasTimeInstant(false)
44    , hasTimeCentered(false)
45    , wasDataRequestedFromServer(false)
46    , wasDataAlreadyReceivedFromServer(false)
47    , mustAutoTrigger(false)
48    , isEOF(false), nstepMaxRead(false)
49  { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
50
51  CField::CField(const StdString& id)
52    : CObjectTemplate<CField>(id), CFieldAttributes()
53    , file()
54    , written(false)
55    , nstep(0), nstepMax(0)
56    , hasOutputFile(false)
57    , domAxisScalarIds_(vector<StdString>(3,""))
58    , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
59    , isGridChecked(false)
60    , useCompressedOutput(false)
61    , hasTimeInstant(false)
62    , hasTimeCentered(false)
63    , wasDataRequestedFromServer(false)
64    , wasDataAlreadyReceivedFromServer(false)
65    , mustAutoTrigger(false)
66    , isEOF(false), nstepMaxRead(false)
67  { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
68
69  CField::~CField(void)
70  {}
71
72  //----------------------------------------------------------------
73
74  void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
75  TRY
76  {
77    this->vVariableGroup = newVVariableGroup;
78  }
79  CATCH
80
81  CVariableGroup* CField::getVirtualVariableGroup(void) const
82  TRY
83  {
84     return this->vVariableGroup;
85  }
86  CATCH
87
88  std::vector<CVariable*> CField::getAllVariables(void) const
89  TRY
90  {
91    return this->vVariableGroup->getAllChildren();
92  }
93  CATCH
94
95  void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
96  TRY
97  {
98    SuperClassAttribute::setAttributes(parent, apply);
99    this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
100  }
101  CATCH_DUMP_ATTR
102
103  //----------------------------------------------------------------
104
105  bool CField::dispatchEvent(CEventServer& event)
106  TRY
107  {
108    if (SuperClass::dispatchEvent(event)) return true;
109    else
110    {
111      switch(event.type)
112      {
113        case EVENT_ID_UPDATE_DATA :
114          recvUpdateData(event);
115          return true;
116          break;
117
118        case EVENT_ID_READ_DATA :
119          recvReadDataRequest(event);
120          return true;
121          break;
122
123        case EVENT_ID_READ_DATA_READY :
124          recvReadDataReady(event);
125          return true;
126          break;
127
128        case EVENT_ID_ADD_VARIABLE :
129          recvAddVariable(event);
130          return true;
131          break;
132
133        case EVENT_ID_ADD_VARIABLE_GROUP :
134          recvAddVariableGroup(event);
135          return true;
136          break;
137
138        default :
139          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
140          return false;
141      }
142    }
143  }
144  CATCH
145
146  void CField::sendUpdateData(const CArray<double,1>& data, CContextClient* client)
147  TRY
148  {
149    CTimer::get("Field : send data").resume();
150    int receiverSize = client->serverSize;
151
152    CEventClient event(getType(), EVENT_ID_UPDATE_DATA);
153
154    map<int, CArray<int,1> >::iterator it;
155    list<CMessage> list_msg;
156    list<CArray<double,1> > list_data;
157
158    if (!grid_->doGridHaveDataDistributed(client))
159    {
160       if (client->isServerLeader())
161       {
162          for (it = grid_->storeIndex_toSrv_[client].begin(); it != grid_->storeIndex_toSrv_[client].end(); it++)
163          {
164            int rank = it->first;
165            CArray<int,1>& index = it->second;
166
167            list_msg.push_back(CMessage());
168            list_data.push_back(CArray<double,1>(index.numElements()));
169
170            CArray<double,1>& data_tmp = list_data.back();
171            for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
172
173            list_msg.back() << getId() << data_tmp;
174            event.push(rank, 1, list_msg.back());
175          }
176          client->sendEvent(event);
177        }
178      else client->sendEvent(event);
179    }
180    else
181    {
182      for (it = grid_->storeIndex_toSrv_[client].begin(); it != grid_->storeIndex_toSrv_[client].end(); it++)
183      {
184        int rank = it->first;
185        CArray<int,1>& index = it->second;
186
187        list_msg.push_back(CMessage());
188        list_data.push_back(CArray<double,1>(index.numElements()));
189
190        CArray<double,1>& data_tmp = list_data.back();
191        for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
192
193        list_msg.back() << getId() << data_tmp;
194        event.push(rank, grid_->nbSenders_[receiverSize][rank], list_msg.back());
195      }
196      client->sendEvent(event);
197    }
198
199    CTimer::get("Field : send data").suspend();
200  }
201  CATCH_DUMP_ATTR
202
203  void CField::recvUpdateData(CEventServer& event)
204  TRY
205  {
206    std::map<int,CBufferIn*> rankBuffers;
207
208    list<CEventServer::SSubEvent>::iterator it;
209    string fieldId;
210    CTimer::get("Field : recv data").resume();
211    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
212    {
213      int rank = it->rank;
214      CBufferIn* buffer = it->buffer;
215      *buffer >> fieldId;
216      rankBuffers[rank] = buffer;
217    }
218    get(fieldId)->recvUpdateData(rankBuffers);
219    CTimer::get("Field : recv data").suspend();
220  }
221  CATCH
222
223  void  CField::recvUpdateData(std::map<int,CBufferIn*>& rankBuffers)
224  TRY
225  {
226    CContext* context = CContext::getCurrent();
227
228    size_t sizeData = 0;
229    if (0 == recvDataSrv.numElements())
230    {           
231      CArray<int,1>& storeClient = grid_->getStoreIndex_client();
232
233      // Gather all data from different clients     
234      recvDataSrv.resize(storeClient.numElements());
235      recvFoperationSrv = std::shared_ptr<func::CFunctor>(new func::CInstant(recvDataSrv));
236    }
237
238    CArray<double,1> recv_data_tmp(recvDataSrv.numElements());   
239    const CDate& currDate = context->getCalendar()->getCurrentDate();
240    CDuration offsetAllButMonth (freq_offset.getValue().year, 0 , freq_offset.getValue().day,
241                                 freq_offset.getValue().hour, freq_offset.getValue().minute,
242                                 freq_offset.getValue().second, freq_offset.getValue().timestep);
243    const CDate opeDate   = (last_operation_srv - offsetAllButMonth + context->getCalendar()->getTimeStep())
244                             + freq_op + freq_operation_srv - freq_op - context->getCalendar()->getTimeStep() + offsetAllButMonth;
245
246    if (opeDate <= currDate)
247    {
248      auto& outLocalIndexStoreOnClient = grid_-> getOutLocalIndexStoreOnClient() ;
249      for (auto it = outLocalIndexStoreOnClient.begin(); it != outLocalIndexStoreOnClient.end(); ++it)
250      {
251        CArray<double,1> tmp;
252        CArray<size_t,1>& indexTmp = it->second;
253        *(rankBuffers[it->first]) >> tmp;
254        for (int idx = 0; idx < indexTmp.numElements(); ++idx) recv_data_tmp(indexTmp(idx)) = tmp(idx);
255      }
256    }
257
258    this->setData(recv_data_tmp);
259    // delete incomming flux for server only
260    recvFoperationSrv.reset() ;
261    recvDataSrv.reset() ;
262  }
263  CATCH_DUMP_ATTR
264
265  void CField::writeUpdateData(const CArray<double,1>& data)
266  TRY
267  {
268    CContext* context = CContext::getCurrent();
269
270    const CDate& currDate = context->getCalendar()->getCurrentDate();
271    CDuration offsetAllButMonth (freq_offset.getValue().year, 0 , freq_offset.getValue().day,
272                                   freq_offset.getValue().hour, freq_offset.getValue().minute,
273                                   freq_offset.getValue().second, freq_offset.getValue().timestep);
274    const CDate opeDate   = (last_operation_srv - offsetAllButMonth + context->getCalendar()->getTimeStep())
275                              + freq_op + freq_operation_srv - freq_op - context->getCalendar()->getTimeStep() + offsetAllButMonth;
276    const CDate writeDate = last_Write_srv + freq_write_srv;
277
278    if (opeDate <= currDate)
279    {
280      (*recvFoperationSrv)(data);
281      last_operation_srv = currDate;
282    }
283
284    if (writeDate < (currDate + freq_operation_srv))
285    {
286      recvFoperationSrv->final();
287      last_Write_srv = writeDate;
288      grid_->computeWrittenIndex();
289      writeField();
290      lastlast_Write_srv = last_Write_srv;
291    }
292  }
293  CATCH_DUMP_ATTR
294
295  void CField::writeField(void)
296  TRY
297  {
298    if (!getRelFile()->isEmptyZone())
299    {
300      if (grid_->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
301      {
302        getRelFile()->checkWriteFile();
303        this->incrementNStep();
304        getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
305      }
306    }
307  }
308  CATCH_DUMP_ATTR
309
310  /*
311    Send a request for reading data.
312    Client sends a request to server for demanding server to read data and send back to it.
313    For now, this function is called only by client
314    In the future, it can be called by level-1 servers
315    \param [in] tsDataRequested timestamp when the call is made
316  */
317  bool CField::sendReadDataRequest(const CDate& tsDataRequested, CContextClient* client)
318  TRY
319  {
320    CContext* context = CContext::getCurrent();
321
322    lastDataRequestedFromServer = tsDataRequested;
323
324    // No need to send the request if we are sure that we are already at EOF
325    if (!isEOF || context->getCalendar()->getCurrentDate() <= dateEOF)
326    {
327      CEventClient event(getType(), EVENT_ID_READ_DATA);
328      if (client->isServerLeader())
329      {
330        CMessage msg;
331        msg << getId();
332        const std::list<int>& ranks = client->getRanksServerLeader();
333        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
334          event.push(*itRank, 1, msg);
335        client->sendEvent(event);
336      }
337      else client->sendEvent(event);
338    }
339    else serverSourceFilter->signalEndOfStream(tsDataRequested);
340
341    wasDataRequestedFromServer = true;
342
343    return !isEOF;
344  }
345  CATCH_DUMP_ATTR
346
347  /*!
348  Send request new data read from file if need be, that is the current data is out-of-date.
349  \return true if and only if some data was requested
350  */
351  bool CField::sendReadDataRequestIfNeeded(void)
352  TRY
353  {
354    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
355
356    bool dataRequested = false;
357
358    while (currentDate >= lastDataRequestedFromServer)
359    {
360      info(20) << "currentDate : " << currentDate << endl ;
361      info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
362      info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
363      info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
364
365      dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq, file->getContextClient());
366    }
367
368    return dataRequested;
369  }
370  CATCH_DUMP_ATTR
371
372  void CField::recvReadDataRequest(CEventServer& event)
373  TRY
374  {
375    CBufferIn* buffer = event.subEvents.begin()->buffer;
376    StdString fieldId;
377    *buffer >> fieldId;
378    get(fieldId)->recvReadDataRequest(event.getContextServer());
379  }
380  CATCH
381
382  /*!
383    Receive data request sent from client and process it
384    Every time server receives this request, it will try to read data and sent read data back to client
385    At the moment, this function is called by server level 1
386    In the future, this should (only) be done by the last level servers.
387  */
388  void CField::recvReadDataRequest(CContextServer* server)
389  TRY
390  {
391    CContextClient* client = server->getAssociatedClient() ;
392    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
393    std::list<CMessage> msgs;
394
395    EReadField hasData = readField();
396
397    map<int, CArray<double,1> >::iterator it;
398    if (!grid_->doGridHaveDataDistributed(client))
399    {
400       if (client->isServerLeader())
401       {
402          if (0 != recvDataSrv.numElements())
403          {           
404            const std::list<int>& ranks = client->getRanksServerLeader();
405            for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
406            {
407              msgs.push_back(CMessage());
408              CMessage& msg = msgs.back();
409              msg << getId();
410              switch (hasData)
411              {
412                case RF_DATA:
413                  msg << getNStep() - 1 << recvDataSrv;
414                  break;
415                case RF_NODATA:
416                  msg << int(-2) << recvDataSrv;
417                  break;
418                case RF_EOF:                 
419                default:
420                  msg << int(-1);
421                  break;
422              }
423
424              event.push(*itRank, 1, msg);
425            }
426          }
427          client->sendEvent(event);
428       }
429       else
430       {
431          client->sendEvent(event);
432       }
433    }
434    else
435    {
436      auto& outLocalIndexStoreOnClient = grid_-> getOutLocalIndexStoreOnClient() ;
437      for (auto it = outLocalIndexStoreOnClient.begin(); it != outLocalIndexStoreOnClient.end(); ++it)
438      {
439        CArray<size_t,1>& indexTmp = it->second;
440        CArray<double,1> tmp(indexTmp.numElements());
441        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
442        {
443          tmp(idx) = recvDataSrv(indexTmp(idx));
444        } 
445
446        msgs.push_back(CMessage());
447        CMessage& msg = msgs.back();
448        msg << getId();
449        switch (hasData)
450        {
451          case RF_DATA:
452            msg << getNStep() - 1 << tmp;
453            break;
454          case RF_NODATA:
455            msg << int(-2) << tmp;
456            break;
457          case RF_EOF:                 
458          default:
459            msg << int(-1);
460            break;
461        }
462
463        event.push(it->first, grid_->nbReadSenders_[client][it->first], msg);
464      }
465      client->sendEvent(event);
466    }
467  }
468  CATCH_DUMP_ATTR
469
470  /*!
471    Read field from a file.
472    A field is read with the distribution of data on the server side
473    \return State of field can be read from a file
474  */
475  CField::EReadField CField::readField(void)
476  TRY
477  {
478    CContext* context = CContext::getCurrent();
479    grid_->computeWrittenIndex();
480    getRelFile()->initRead();
481    EReadField readState = RF_DATA;
482
483    if (!getRelFile()->isEmptyZone())
484    {     
485      if (grid_->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)     
486      {
487        if (0 == recvDataSrv.numElements())
488        {           
489          CArray<int,1>& storeClient = grid_->getStoreIndex_client();         
490          recvDataSrv.resize(storeClient.numElements());         
491        }
492       
493        getRelFile()->checkReadFile();
494
495        if (!nstepMax)
496        {
497          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
498        }
499
500        this->incrementNStep();
501
502        if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
503          readState = RF_EOF;
504
505        if (RF_EOF != readState)
506          getRelFile()->getDataInput()->readFieldData(CField::get(this));
507      }
508    }
509    else
510    {
511      this->incrementNStep();
512      if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
513        readState = RF_EOF;
514      else
515        readState = RF_NODATA;
516
517      if (!nstepMaxRead) // This can be a bug if we try to read field from zero time record
518        readState = RF_NODATA;
519    }
520
521    if (!nstepMaxRead)
522    {
523       MPI_Allreduce(MPI_IN_PLACE, &nstepMax, 1, MPI_INT, MPI_MAX, context->intraComm_);
524       nstepMaxRead = true;
525    }
526
527    return readState;
528  }
529  CATCH_DUMP_ATTR
530
531  /*
532    Receive read data from server.
533    At the moment, this function is called in the client side.
534    In the future, this function can be called hiearachically (server n-1, server n -2, ..., client)
535    \param event event containing read data
536  */
537  void CField::recvReadDataReady(CEventServer& event)
538  TRY
539  {
540    string fieldId;
541    vector<int> ranks;
542    vector<CBufferIn*> buffers;
543
544    list<CEventServer::SSubEvent>::iterator it;
545    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
546    {
547      ranks.push_back(it->rank);
548      CBufferIn* buffer = it->buffer;
549      *buffer >> fieldId;
550      buffers.push_back(buffer);
551    }
552    get(fieldId)->recvReadDataReady(ranks, buffers);
553  }
554  CATCH
555
556  /*!
557    Receive read data from server
558    \param [in] ranks Ranks of sending processes
559    \param [in] buffers buffers containing read data
560  */
561  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
562  TRY
563  {
564    CContext* context = CContext::getCurrent();
565    std::map<int, CArray<double,1> > data;
566    const bool wasEOF = isEOF;
567
568    for (int i = 0; i < ranks.size(); i++)
569    {
570      int rank = ranks[i];
571      int record;
572      *buffers[i] >> record;
573      isEOF = (record == int(-1));
574
575      if (!isEOF)
576        *buffers[i] >> data[rank];
577      else
578        break;
579    }
580
581    if (wasDataAlreadyReceivedFromServer)
582      lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
583    else
584    {
585      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
586      wasDataAlreadyReceivedFromServer = true;
587    }
588
589    if (isEOF)
590    {
591      if (!wasEOF)
592        dateEOF = lastDataReceivedFromServer;
593
594      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
595    }
596    else
597      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
598  }
599  CATCH_DUMP_ATTR
600
601  void CField::checkForLateDataFromServer(void)
602  TRY
603  {
604    CContext* context = CContext::getCurrent();
605    const CDate& currentDate = context->getCalendar()->getCurrentDate();
606
607    // Check if data previously requested has been received as expected
608    if (wasDataRequestedFromServer && !isEOF)
609    {
610      CTimer timer("CField::checkForLateDataFromServer");
611      timer.resume();
612      traceOff() ;
613      timer.suspend();
614     
615      bool isDataLate;
616      do
617      {
618        const CDate nextDataDue = wasDataAlreadyReceivedFromServer ? (lastDataReceivedFromServer + file->output_freq) : context->getCalendar()->getInitDate();
619        isDataLate = (nextDataDue <= currentDate);
620
621        if (isDataLate)
622        {
623          timer.resume();
624
625//ym          context->checkBuffersAndListen();
626//ym            context->eventLoop();
627          context->globalEventLoop();
628
629          timer.suspend();
630        }
631      }
632      while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout);
633      timer.resume();
634      traceOn() ;
635      timer.suspend() ;
636
637
638      if (isDataLate)
639        ERROR("void CField::checkForLateDataFromServer(void)",
640              << "Late data at timestep = " << currentDate);
641    }
642  }
643  CATCH_DUMP_ATTR
644
645  void CField::checkIfMustAutoTrigger(void)
646  TRY
647  {
648    mustAutoTrigger = serverSourceFilter ? serverSourceFilter->mustAutoTrigger() : false;
649  }
650  CATCH_DUMP_ATTR
651
652  void CField::autoTriggerIfNeeded(void)
653  TRY
654  {
655    if (mustAutoTrigger)
656      serverSourceFilter->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
657  }
658  CATCH_DUMP_ATTR
659
660  //----------------------------------------------------------------
661
662  void CField::setRelFile(CFile* _file)
663  TRY
664  {
665    this->file = _file;
666    hasOutputFile = true;
667  }
668  CATCH_DUMP_ATTR
669
670  //----------------------------------------------------------------
671
672  StdString CField::GetName(void)    { return StdString("field"); }
673  StdString CField::GetDefName(void) { return CField::GetName(); }
674  ENodeType CField::GetType(void)    { return eField; }
675
676  //----------------------------------------------------------------
677
678  CGrid* CField::getRelGrid(void) const
679  TRY
680  {
681    return this->grid_;
682  }
683  CATCH
684
685  //----------------------------------------------------------------
686
687  CFile* CField::getRelFile(void) const
688  TRY
689  {
690    return this->file;
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 (context->getServiceType()==CServicesManager::CLIENT || !hasOutputFile) return;
1101
1102    if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
1103
1104    if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
1105
1106    freq_operation_srv = file->output_freq.getValue();
1107    freq_write_srv     = file->output_freq.getValue();
1108
1109    lastlast_Write_srv = context->getCalendar()->getInitDate();
1110    last_Write_srv     = context->getCalendar()->getInitDate();
1111    last_operation_srv = context->getCalendar()->getInitDate();
1112
1113    const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
1114    last_operation_srv     = last_operation_srv - toffset;
1115
1116    if (operation.isEmpty())
1117      ERROR("void CField::solveServerOperation(void)",
1118            << "An operation must be defined for field \"" << getId() << "\".");
1119
1120    std::shared_ptr<func::CFunctor> functor;
1121    CArray<double, 1> dummyData;
1122
1123#define DECLARE_FUNCTOR(MType, mtype) \
1124    if (operation.getValue().compare(#mtype) == 0) \
1125    { \
1126      functor.reset(new func::C##MType(dummyData)); \
1127    }
1128
1129#include "functor_type.conf"
1130
1131    if (!functor)
1132      ERROR("void CField::solveServerOperation(void)",
1133            << "\"" << operation << "\" is not a valid operation.");
1134
1135    operationTimeType = functor->timeType();
1136  }
1137  CATCH_DUMP_ATTR
1138
1139 //----------------------------------------------------------------
1140
1141  bool CField::buildWorkflowGraph(CGarbageCollector& gc)
1142  {
1143    if (buildWorkflowGraphDone_) return true ;
1144    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1145    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1146
1147    if (!inputFilter) inputFilter = std::shared_ptr<CPassThroughFilter>(new CPassThroughFilter(gc)); 
1148     
1149    if (hasDirectFieldReference())
1150    {
1151      CField* fieldRef = getDirectFieldReference();
1152      bool ret=fieldRef->buildWorkflowGraph(gc); 
1153      if (!ret) return false ; // workflow graph cannot be built at this stage
1154    }
1155
1156    // Check if we have an expression to parse
1157    std::shared_ptr<COutputPin> filterExpr ;
1158    if (hasExpression())
1159    {
1160      boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1161      filterExpr = expr->reduce(gc, *this);
1162      if (!filterExpr) return false ; // workflow graph cannot be built at this stage
1163    }
1164   
1165    // now construct grid and check if element are enabled
1166    solveGridReference() ; // grid_ is now defined
1167   
1168    // prepare transformation. Need to know before if workflow of auxillary field can be built
1169    if (hasDirectFieldReference())
1170    {
1171      auto gridPath=getGridPath() ;
1172      gridPath.push_back(grid_) ;
1173
1174      CGrid* gridSrc=getDirectFieldReference()->getGrid() ;
1175      for(auto grid : gridPath)
1176      {
1177        if (!grid->checkIfCompleted()) return false ;
1178        grid->solveElementsRefInheritance() ;
1179        grid_->completeGrid(gridSrc); // grid generation, to be checked
1180        grid->prepareTransformGrid(gridSrc) ; // prepare the grid tranformation
1181        for(auto fieldId : grid->getAuxInputTransformGrid()) // try to build workflow graph for auxillary field tranformation
1182          if (!CField::get(fieldId)->buildWorkflowGraph(gc)) return false ;
1183        gridSrc=grid ;
1184      }
1185     
1186      std::shared_ptr<COutputPin> lastFilter ;
1187      if (filterExpr) lastFilter=filterExpr ;
1188      else lastFilter = inputFilter ;
1189     
1190      gridSrc=getDirectFieldReference()->getGrid() ;
1191      for(auto grid : gridPath) 
1192      {
1193        grid->makeTransformGrid() ; // make the grid transformation
1194        if (grid->hasTransform()) 
1195        {
1196          std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridSrc, grid, detectMissingValues, defaultValue); 
1197          lastFilter->connectOutput(filters.first, 0);
1198          lastFilter = filters.second;
1199          gridSrc=grid ;
1200        }
1201      }
1202      instantDataFilter = lastFilter ;
1203     
1204      // connect the input Filter to the reference
1205      getDirectFieldReference()->getInstantDataFilter()->connectOutput(inputFilter,0);
1206    }
1207    else 
1208    {
1209      if (!grid_->checkIfCompleted()) return false ;
1210     
1211      if (hasFileIn()) // input file, attemp to read the grid from file
1212      {
1213         // must be checked
1214         fileIn_->initRead() ;
1215         fileIn_->checkReadFile();
1216         grid_->solveElementsRefInheritance() ;
1217         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesMetaData(this);
1218         grid_->completeGrid(); // grid generation, to be checked
1219         if (fileIn_->isClientSide()) fileIn_->readFieldAttributesValues(this);
1220         grid_->checkElementsAttributes() ;
1221         grid_->solveDomainAxisBaseRef();
1222         // probably in future tag grid incomplete if coming from a reading
1223         instantDataFilter=inputFilter ;
1224      } 
1225      else 
1226      {
1227        setModelIn() ; // no reference, the field is potentially a source field from model
1228
1229        grid_->solveElementsRefInheritance() ;
1230        grid_->completeGrid(); // grid generation, to be checked
1231        grid_->checkElementsAttributes() ;
1232        instantDataFilter=inputFilter ;
1233      }
1234    }
1235   
1236    buildWorkflowGraphDone_ = true ;
1237    workflowEnabled_ = true ;
1238    return true ;
1239  }
1240   
1241  /*!
1242   * Connect field to filter to send data to server. A temporal filter is inserted before accordingly to the
1243   * output frequency of the file
1244   * \param gc the garbage collector to use when building the filter graph
1245   */
1246  void CField::connectToFileServer(CGarbageCollector& gc)
1247  {
1248    // insert temporal filter before sending to files
1249    fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, client));
1250    // insert temporal filter before sending to files
1251    getTemporalDataFilter(gc, fileOut_->output_freq)->connectOutput(fileWriterFilter, 0);
1252  } 
1253
1254  /*!
1255   * Compute grid index needed to send grid and data to server
1256   */
1257  void CField::computeGridIndexToFileServer(void)
1258  {
1259    grid_->computeGridIndexToFileServer(client) ;
1260  }
1261
1262  /*!
1263   * Connect field to a source filter to receive data from model.
1264   */
1265  void CField::connectToModelInput(CGarbageCollector& gc)
1266  {
1267    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1268    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1269
1270    if (check_if_active.isEmpty()) check_if_active = false; 
1271    clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, true, NoneDu, false, detectMissingValues, defaultValue));
1272    clientSourceFilter -> connectOutput(inputFilter,0) ;
1273  } 
1274 
1275  /*!
1276   * Connect field to a source filter to receive data from a client (on server side).
1277   */
1278  void CField::connectToClientInput(CGarbageCollector& gc)
1279  {
1280    clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc,  grid_, false, false));
1281    clientSourceFilter -> connectOutput(inputFilter,0) ;
1282  } 
1283
1284
1285  /*!
1286   * Connect field to a source filter to receive data from a server (on client side).
1287   */
1288  void CField::connectToServerInput(CGarbageCollector& gc)
1289  {
1290    serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc,  grid_, false, false));
1291    serverSourceFilter -> connectOutput(inputFilter,0) ;
1292  } 
1293
1294  /*!
1295   * Connect field to a file writer filter to write data in file (on server side).
1296   */
1297  void CField::connectToFileWriter(CGarbageCollector& gc)
1298  {
1299    fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1300    instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1301  } 
1302 
1303
1304  /*!
1305   * Connect field to a store filter to output data to model on client Side
1306   */
1307  void CField::connectToModelOutput(CGarbageCollector& gc)
1308  {
1309    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1310    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1311
1312    storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid_, detectMissingValues, defaultValue));
1313    instantDataFilter->connectOutput(storeFilter, 0);
1314  }
1315
1316  /*!
1317   * Transform the grid_path attribut into vector of grid.
1318   * \return the vector CGrid* containing the list of grid path for tranformation
1319   */ 
1320  vector<CGrid*> CField::getGridPath(void)
1321  {
1322    std::vector<CGrid*> gridPath;
1323
1324    if (hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1325    {
1326      if (!grid_path.isEmpty())
1327      {
1328        std::string gridId;
1329        size_t start = 0, end;
1330
1331        do
1332        {
1333          end = grid_path.getValue().find(',', start);
1334          if (end != std::string::npos)
1335          {
1336            gridId = grid_path.getValue().substr(start, end - start);
1337            start = end + 1;
1338          }
1339          else gridId = grid_path.getValue().substr(start);
1340
1341          if (!CGrid::has(gridId))
1342            ERROR("void CField::solveTransformedGrid()",
1343               << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1344
1345          gridPath.push_back(CGrid::get(gridId));
1346        }
1347        while (end != std::string::npos);
1348      }
1349    }
1350    return gridPath ;
1351  }
1352
1353  /*!
1354   * Constructs the graph filter for the field, enabling or not the data output.
1355   * This method should not be called more than once with enableOutput equal to true.
1356   *
1357   * \param gc the garbage collector to use when building the filter graph
1358   * \param enableOutput must be true when the field data is to be
1359   *                     read by the client or/and written to a file
1360   */
1361   // ym obselete : to be removed later....
1362  void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
1363  TRY
1364  {     
1365    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
1366    if (!isGridChecked) checkGridOfEnabledFields();
1367
1368    const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1369    const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1370
1371    CContext* context = CContext::getCurrent();
1372    bool hasWriterServer = context->getServiceType()==CServicesManager::OUT_SERVER ;
1373    bool hasIntermediateServer = context->getServiceType()==CServicesManager::GATHERER ;
1374
1375    if (hasWriterServer)
1376    {
1377      if (!instantDataFilter)
1378        instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false));
1379
1380
1381      // If the field data is to be read by the client or/and written to a file
1382      if (enableOutput && !storeFilter && !fileWriterFilter)
1383      {
1384        if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1385        {
1386          fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1387          instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1388        }
1389      }
1390    }
1391    else if (hasIntermediateServer)
1392    {
1393      if (!instantDataFilter)
1394        instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, false));
1395
1396      // If the field data is to be read by the client or/and written to a file
1397      if (enableOutput && !storeFilter && !fileWriterFilter)
1398      {
1399        if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1400        {
1401          fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, file->getContextClient()));
1402          instantDataFilter->connectOutput(fileWriterFilter, 0);
1403        }
1404      }
1405    }
1406    else
1407    {
1408      // Start by building a filter which can provide the field's instant data
1409      if (!instantDataFilter)
1410      {
1411        // Check if we have an expression to parse
1412        if (hasExpression())
1413        {
1414          boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1415          std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
1416
1417          // Check if a spatial transformation is needed
1418          if (!field_ref.isEmpty())
1419          {
1420            CGrid* gridRef = CField::get(field_ref)->grid_;
1421            if (grid_ && grid_ != gridRef && grid_->hasTransform())
1422            {
1423                std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid_, detectMissingValues, defaultValue); 
1424
1425              filter->connectOutput(filters.first, 0);
1426              filter = filters.second;
1427            }
1428          }
1429
1430          instantDataFilter = filter;
1431        }
1432        // Check if we have a reference on another field
1433        else if (!field_ref.isEmpty()) instantDataFilter = getFieldReference(gc);
1434        // Check if the data is to be read from a file
1435        else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1436        {
1437          checkTimeAttributes();
1438          instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
1439                                                                                                       detectMissingValues, defaultValue));
1440        }
1441        else // The data might be passed from the model
1442        {
1443          if (check_if_active.isEmpty()) check_if_active = false; 
1444          instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, false, true, NoneDu, false,
1445                                                                                                      detectMissingValues, defaultValue));
1446        }
1447      }
1448
1449      // If the field data is to be read by the client or/and written to a file
1450      if (enableOutput && !storeFilter && !fileWriterFilter)
1451      {
1452        if (!read_access.isEmpty() && read_access)
1453        {
1454          storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid_,
1455                                                                          detectMissingValues, defaultValue));
1456          instantDataFilter->connectOutput(storeFilter, 0);
1457        }
1458
1459        if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1460        {
1461          fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this, file->getContextClient()));
1462          getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1463        }
1464      }
1465    }
1466  }
1467  CATCH_DUMP_ATTR
1468
1469  /*!
1470   * Returns the filter needed to handle the field reference.
1471   * This method should only be called when building the filter graph corresponding to the field.
1472   *
1473   * \param gc the garbage collector to use
1474   * \return the output pin corresponding to the field reference
1475   */
1476  std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1477  TRY
1478  {
1479    if (instantDataFilter || field_ref.isEmpty())
1480      ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1481            "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1482
1483    CField* fieldRef = CField::get(field_ref);
1484    fieldRef->buildFilterGraph(gc, false);
1485
1486    std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1487    // Check if a spatial transformation is needed
1488    if (grid_ && grid_ != fieldRef->grid_ && grid_->hasTransform())
1489    {       
1490      bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1491      double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
1492      filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid_, grid_, hasMissingValue, defaultValue);
1493    }
1494    else
1495      filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1496
1497    fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1498
1499    return filters.second;
1500  }
1501  CATCH_DUMP_ATTR
1502
1503  /*!
1504   * Returns the filter needed to handle a self reference in the field's expression.
1505   * If the needed filter does not exist, it is created, otherwise it is reused.
1506   * This method should only be called when building the filter graph corresponding
1507   * to the field's expression.
1508   *
1509   * \param gc the garbage collector to use
1510   * \return the output pin corresponding to a self reference
1511   */
1512
1513/* old version
1514  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1515  TRY
1516  {
1517    if (instantDataFilter || !hasExpression())
1518      ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1519            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1520
1521    if (!selfReferenceFilter)
1522    {
1523      const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1524      const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1525
1526      if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1527      {
1528        if (!serverSourceFilter)
1529        {
1530          checkTimeAttributes();
1531          serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, false, freq_offset, true,
1532                                                              detectMissingValues, defaultValue));
1533         }
1534
1535        selfReferenceFilter = serverSourceFilter;
1536      }
1537      else if (!field_ref.isEmpty())
1538      {
1539        CField* fieldRef = CField::get(field_ref);
1540        fieldRef->buildFilterGraph(gc, false);
1541        selfReferenceFilter = fieldRef->getInstantDataFilter();
1542      }
1543      else
1544      {
1545        if (!clientSourceFilter)
1546        {
1547          if (check_if_active.isEmpty()) check_if_active = false;
1548          clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid_, true, true, NoneDu, false,
1549                                                                                detectMissingValues, defaultValue));
1550        }
1551
1552        selfReferenceFilter = clientSourceFilter;
1553      }
1554    }
1555
1556    return selfReferenceFilter;
1557  }
1558  CATCH_DUMP_ATTR
1559*/
1560  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1561  TRY
1562  {
1563    return inputFilter ;
1564  } 
1565  CATCH_DUMP_ATTR
1566
1567  /*!
1568   * Returns the temporal filter corresponding to the field's temporal operation
1569   * for the specified operation frequency. The filter is created if it does not
1570   * exist, otherwise it is reused.
1571   *
1572   * \param gc the garbage collector to use
1573   * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1574   * \return the output pin corresponding to the requested temporal filter
1575   */
1576  std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1577  TRY
1578  {
1579    std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1580
1581    if (it == temporalDataFilters.end())
1582    {
1583      if (operation.isEmpty())
1584        ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1585              << "An operation must be defined for field \"" << getId() << "\".");
1586
1587      checkTimeAttributes(&outFreq);
1588
1589      const bool detectMissingValues = (!detect_missing_value.isEmpty()  && detect_missing_value == true);
1590      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1591                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1592                                                                             freq_op, freq_offset, outFreq, detectMissingValues));
1593
1594      instantDataFilter->connectOutput(temporalFilter, 0);
1595
1596      it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1597    }
1598
1599    return it->second;
1600  }
1601  CATCH_DUMP_ATTR
1602
1603  /*!
1604    * Returns the temporal filter corresponding to the field's temporal operation
1605    * for the specified operation frequency.
1606    *
1607    * \param gc the garbage collector to use
1608    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1609    * \return the output pin corresponding to the requested temporal filter
1610    */
1611
1612  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1613  TRY
1614  {
1615    if (instantDataFilter || !hasExpression())
1616      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1617            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1618   
1619    if (selfTemporalDataFilter) return selfTemporalDataFilter;
1620
1621    if (hasDirectFieldReference())
1622    {
1623      CField* fieldRef=getDirectFieldReference();
1624      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1625    }
1626    else
1627    {
1628      if (selfTemporalDataFilter) return selfTemporalDataFilter ;
1629
1630      if (operation.isEmpty())
1631        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1632              << "An operation must be defined for field \"" << getId() << "\".");
1633
1634      checkTimeAttributes(&outFreq); //bof
1635
1636      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1637      selfTemporalDataFilter = std::shared_ptr<CTemporalFilter>(new CTemporalFilter(gc, operation,
1638                                                                CContext::getCurrent()->getCalendar()->getInitDate(),
1639                                                                freq_op, freq_offset, outFreq, detectMissingValues));
1640
1641      inputFilter->connectOutput(selfTemporalDataFilter, 0);
1642      return selfTemporalDataFilter ;
1643    }
1644  }
1645  CATCH_DUMP_ATTR
1646
1647/* old version   
1648  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1649  TRY
1650  {
1651    if (instantDataFilter || !hasExpression())
1652      ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1653            "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1654
1655    if (!selfReferenceFilter) getSelfReference(gc) ;
1656
1657    if (serverSourceFilter || clientSourceFilter)
1658    {
1659      if (operation.isEmpty())
1660        ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1661              << "An operation must be defined for field \"" << getId() << "\".");
1662
1663      checkTimeAttributes(&outFreq);
1664
1665      const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1666      std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1667                                                                          CContext::getCurrent()->getCalendar()->getInitDate(),
1668                                                                          freq_op, freq_offset, outFreq, detectMissingValues));
1669
1670      selfReferenceFilter->connectOutput(temporalFilter, 0);
1671      return temporalFilter ;
1672    }
1673    else if (!field_ref.isEmpty())
1674    {
1675      CField* fieldRef = CField::get(field_ref);
1676      fieldRef->buildFilterGraph(gc, false);
1677      return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1678    }
1679  }
1680  CATCH_DUMP_ATTR
1681*/
1682
1683  //----------------------------------------------------------------
1684/*
1685   void CField::fromBinary(StdIStream& is)
1686   {
1687      SuperClass::fromBinary(is);
1688#define CLEAR_ATT(name_)\
1689      SuperClassAttribute::operator[](#name_)->reset()
1690
1691         CLEAR_ATT(domain_ref);
1692         CLEAR_ATT(axis_ref);
1693#undef CLEAR_ATT
1694
1695   }
1696*/
1697   //----------------------------------------------------------------
1698
1699  void CField::solveGridReference(void)
1700  TRY
1701  {
1702    if (grid_!=nullptr) return ; // already done
1703
1704    if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1705    {
1706      ERROR("CField::solveGridReference(void)",
1707            << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1708    }
1709    else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1710    {
1711      ERROR("CField::solveGridReference(void)",
1712            << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1713            << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1714    }
1715
1716    if (grid_ref.isEmpty())
1717    {
1718      std::vector<CDomain*> vecDom;
1719      std::vector<CAxis*> vecAxis;
1720      std::vector<CScalar*> vecScalar;
1721      std::vector<int> axisDomainOrderTmp;
1722
1723      std::vector<CDomain*> vecDomRef;
1724      std::vector<CAxis*> vecAxisRef;
1725      std::vector<CScalar*> vecScalarRef;
1726       
1727      if (!domain_ref.isEmpty())
1728      {
1729        StdString tmp = domain_ref.getValue();
1730        if (CDomain::has(domain_ref))
1731        {
1732          vecDom.push_back(CDomain::get(domain_ref));
1733          vecDomRef.push_back(CDomain::createDomain());
1734          vecDomRef.back()->domain_ref=domain_ref;
1735          axisDomainOrderTmp.push_back(2);
1736        }
1737        else  ERROR("CField::solveGridReference(void)",
1738                    << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1739      }
1740
1741      if (!axis_ref.isEmpty())
1742      {
1743        if (CAxis::has(axis_ref))
1744        {
1745          vecAxis.push_back(CAxis::get(axis_ref));
1746          vecAxisRef.push_back(CAxis::createAxis());
1747          vecAxisRef.back()->axis_ref=axis_ref;
1748          axisDomainOrderTmp.push_back(1);
1749        }
1750        else  ERROR("CField::solveGridReference(void)",
1751                    << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1752      }
1753
1754      if (!scalar_ref.isEmpty())
1755      {
1756        if (CScalar::has(scalar_ref))
1757        {
1758          vecScalar.push_back(CScalar::get(scalar_ref));
1759          vecScalarRef.push_back(CScalar::createScalar());
1760          vecScalarRef.back()->scalar_ref=scalar_ref;
1761          axisDomainOrderTmp.push_back(0);
1762        }
1763        else ERROR("CField::solveGridReference(void)",
1764                   << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1765      }
1766       
1767      CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1768      for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1769      {
1770        axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1771      }
1772
1773      // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1774      StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1775      if (CGrid::has(gridId)) this->grid_ = CGrid::get(gridId);
1776      else  this->grid_ = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1777    }
1778    else
1779    {
1780      if (CGrid::has(grid_ref)) this->grid_ = CGrid::get(grid_ref);
1781      else  ERROR("CField::solveGridReference(void)",
1782                   << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1783    }
1784  }
1785  CATCH_DUMP_ATTR
1786
1787  void CField::solveGridDomainAxisRef(bool checkAtt)
1788  TRY
1789  {
1790    grid_->solveDomainAxisRef(checkAtt);
1791  }
1792  CATCH_DUMP_ATTR
1793
1794  void CField::solveCheckMaskIndex(bool doSendingIndex)
1795  TRY
1796  {
1797    grid_->checkMaskIndex(doSendingIndex);
1798  }
1799  CATCH_DUMP_ATTR
1800
1801  void CField::solveTransformedGrid()
1802  TRY
1803  {
1804    if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1805    {
1806      std::vector<CGrid*> grids;
1807      // Source grid
1808      grids.push_back(getDirectFieldReference()->grid_);
1809      auto gridPath = getGridPath() ;
1810      grids.insert(grids.begin(), gridPath.begin(), gridPath.end());
1811
1812      for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1813      {
1814        CGrid *gridSrc  = grids[i];
1815        CGrid *gridDest = grids[i + 1];
1816        if (!gridDest->isTransformed()) gridDest->transformGrid(gridSrc);
1817      }
1818    }
1819    else if (grid_ && grid_->hasTransform() && !grid_->isTransformed())
1820    {
1821      // Temporarily deactivate the self-transformation of grid
1822      // grid_->transformGrid(grid_);
1823    }
1824  }
1825  CATCH_DUMP_ATTR
1826
1827  void CField::solveGenerateGrid()
1828  TRY
1829  {
1830    if (grid_ && !grid_->isTransformed() && hasDirectFieldReference() && grid_ != getDirectFieldReference()->grid_)
1831      grid_->completeGrid(getDirectFieldReference()->grid_);
1832    else grid_->completeGrid();
1833  }
1834  CATCH_DUMP_ATTR
1835
1836  void CField::solveGridDomainAxisBaseRef()
1837  TRY
1838  {
1839    grid_->solveDomainAxisRef(false);
1840    grid_->solveDomainAxisBaseRef();
1841  }
1842  CATCH_DUMP_ATTR
1843
1844  ///-------------------------------------------------------------------
1845
1846  template <>
1847  void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1848  TRY
1849  {
1850    if (this->group_ref.isEmpty()) return;
1851    StdString gref = this->group_ref.getValue();
1852
1853    if (!CFieldGroup::has(gref))
1854      ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1855         << "[ gref = " << gref << "]"
1856         << " invalid group name !");
1857
1858    CFieldGroup* group = CFieldGroup::get(gref);
1859    CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1860    owner->setAttributes(group); // inherite of attributes of group reference
1861     
1862    std::vector<CField*> allChildren  = group->getAllChildren();
1863    std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1864
1865    for (; it != end; it++)
1866    {
1867      CField* child = *it;
1868     if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1869    }
1870  }
1871  CATCH_DUMP_ATTR
1872
1873  void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1874  TRY
1875  {
1876    recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1877  }
1878  CATCH_DUMP_ATTR
1879
1880  void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1881  TRY
1882  {
1883    recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1884  }
1885  CATCH_DUMP_ATTR
1886
1887  void CField::outputField(CArray<double,1>& fieldOut)
1888  TRY
1889  { 
1890    CArray<size_t,1>& outIndexClient = grid_->localIndexToWriteOnClient_;
1891    CArray<size_t,1>& outIndexServer = grid_->localIndexToWriteOnServer_;
1892    for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1893    {
1894      fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1895    }
1896  }
1897  CATCH_DUMP_ATTR
1898
1899  void CField::inputField(CArray<double,1>& fieldIn)
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      recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1907    }
1908  }
1909  CATCH_DUMP_ATTR
1910
1911 void CField::outputCompressedField(CArray<double,1>& fieldOut)
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      fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1919    }
1920  }
1921  CATCH_DUMP_ATTR
1922
1923  ///-------------------------------------------------------------------
1924
1925  void CField::parse(xml::CXMLNode& node)
1926  TRY
1927  {
1928    string newContent ;
1929    SuperClass::parse(node);
1930    if (node.goToChildElement())
1931    {
1932      do
1933      {
1934        if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1935        else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1936      } while (node.goToNextElement());
1937      node.goToParentElement();
1938    }
1939    if (node.getContent(newContent)) content=newContent ;
1940  }
1941  CATCH_DUMP_ATTR
1942
1943 /*!
1944   This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1945   of a field. In some cases, only domain exists but axis doesn't
1946   \return pair of Domain and Axis id
1947  */
1948  const std::vector<StdString>& CField::getRefDomainAxisIds()
1949  TRY
1950  {
1951    CGrid* cgPtr = getRelGrid();
1952    if (NULL != cgPtr)
1953    {
1954      std::vector<StdString>::iterator it;
1955      if (!domain_ref.isEmpty())
1956      {
1957        std::vector<StdString> domainList = cgPtr->getDomainList();
1958        it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1959        if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1960      }
1961
1962      if (!axis_ref.isEmpty())
1963      {
1964        std::vector<StdString> axisList = cgPtr->getAxisList();
1965        it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1966        if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1967      }
1968
1969      if (!scalar_ref.isEmpty())
1970      {
1971        std::vector<StdString> scalarList = cgPtr->getScalarList();
1972        it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1973        if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1974      }
1975    }
1976    return (domAxisScalarIds_);
1977  }
1978  CATCH_DUMP_ATTR
1979
1980  CVariable* CField::addVariable(const string& id)
1981  TRY
1982  {
1983    return vVariableGroup->createChild(id);
1984  }
1985  CATCH
1986
1987  CVariableGroup* CField::addVariableGroup(const string& id)
1988  TRY
1989  {
1990    return vVariableGroup->createChildGroup(id);
1991  }
1992  CATCH
1993
1994  void CField::setContextClient(CContextClient* contextClient)
1995  TRY
1996  {
1997    CContext* context = CContext::getCurrent();
1998    client = contextClient;
1999 
2000    // A grid is sent by a client (both for read or write) or by primary server (write only)
2001    if (context->getServiceType()==CServicesManager::GATHERER)
2002    {
2003      if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
2004        grid_->setContextClient(contextClient);
2005    }
2006    else if (context->getServiceType()==CServicesManager::CLIENT)
2007      grid_->setContextClient(contextClient);
2008  }
2009  CATCH_DUMP_ATTR
2010
2011  CContextClient* CField::getContextClient()
2012  TRY
2013  {
2014    return client;
2015  }
2016  CATCH
2017
2018 
2019  void CField::sendFieldToFileServer(void)
2020  {
2021    CContext::getCurrent()->sendContextToFileServer(client);
2022    fileOut_->sendFileToFileServer(client);
2023    grid_->sendGridToFileServer(client);
2024    this->sendAllAttributesToServer(client);
2025    this->sendAddAllVariables(client);
2026  }
2027
2028  void CField::sendAddAllVariables(CContextClient* client)
2029  TRY
2030  {
2031    std::vector<CVariable*> allVar = getAllVariables();
2032    std::vector<CVariable*>::const_iterator it = allVar.begin();
2033    std::vector<CVariable*>::const_iterator itE = allVar.end();
2034
2035    for (; it != itE; ++it)
2036    {
2037      this->sendAddVariable((*it)->getId(), client);
2038      (*it)->sendAllAttributesToServer(client);
2039      (*it)->sendValue(client);
2040    }
2041  }
2042  CATCH_DUMP_ATTR
2043
2044  /*!
2045   * Send all Attributes to server. This method is overloaded, since only grid_ref attribute
2046   * must be sent to server and not domain_ref/axis_ref/scalar_ref.
2047   */
2048   
2049  void CField::sendAllAttributesToServer(CContextClient* client)
2050  TRY
2051  {
2052    if (grid_ref.isEmpty())
2053    {
2054      grid_ref=grid_->getId() ;
2055      SuperClass::sendAllAttributesToServer(client) ;
2056      domain_ref.reset() ;
2057      axis_ref.reset() ;
2058      scalar_ref.reset() ;
2059      grid_ref.reset();
2060    }
2061    else SuperClass::sendAllAttributesToServer(client) ;
2062  }
2063  CATCH_DUMP_ATTR
2064   
2065  void CField::sendAddVariable(const string& id, CContextClient* client)
2066  TRY
2067  {
2068    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
2069  }
2070  CATCH_DUMP_ATTR
2071
2072  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
2073  TRY
2074  {
2075    sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
2076  }
2077  CATCH_DUMP_ATTR
2078
2079  void CField::recvAddVariable(CEventServer& event)
2080  TRY
2081  {
2082    CBufferIn* buffer = event.subEvents.begin()->buffer;
2083    string id;
2084    *buffer >> id;
2085    get(id)->recvAddVariable(*buffer);
2086  }
2087  CATCH
2088
2089  void CField::recvAddVariable(CBufferIn& buffer)
2090  TRY
2091  {
2092    string id;
2093    buffer >> id;
2094    addVariable(id);
2095  }
2096  CATCH_DUMP_ATTR
2097
2098  void CField::recvAddVariableGroup(CEventServer& event)
2099  TRY
2100  {
2101    CBufferIn* buffer = event.subEvents.begin()->buffer;
2102    string id;
2103    *buffer >> id;
2104    get(id)->recvAddVariableGroup(*buffer);
2105  }
2106  CATCH
2107
2108  void CField::recvAddVariableGroup(CBufferIn& buffer)
2109  TRY
2110  {
2111    string id;
2112    buffer >> id;
2113    addVariableGroup(id);
2114  }
2115  CATCH_DUMP_ATTR
2116
2117  /*!
2118   * Check on freq_off and freq_op attributes.
2119   */
2120  void CField::checkTimeAttributes(CDuration* freqOp)
2121  TRY
2122  {
2123    bool isFieldRead  = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
2124    bool isFieldWrite = file && ( file->mode.isEmpty() ||  file->mode == CFile::mode_attr::write);
2125    if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )     
2126      ERROR("void CField::checkTimeAttributes(void)",
2127         << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
2128         << "Currently only \"instant\" is supported for fields read from file.")
2129
2130    if (freq_op.isEmpty())
2131    {
2132      if (operation.getValue() == "instant")
2133      {
2134        if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
2135        else freq_op=*freqOp ;
2136      }
2137      else freq_op.setValue(TimeStep);
2138    }
2139    if (freq_offset.isEmpty()) freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
2140  }
2141  CATCH_DUMP_ATTR
2142
2143  /*!
2144   * Returns string arithmetic expression associated to the field.
2145   * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
2146   */
2147  const string& CField::getExpression(void)
2148  TRY
2149  {
2150    if (!expr.isEmpty() && content.empty())
2151    {
2152      content = expr;
2153      expr.reset();
2154    }
2155
2156    return content;
2157  }
2158  CATCH_DUMP_ATTR
2159
2160  bool CField::hasExpression(void) const
2161  TRY
2162  {
2163    return (!expr.isEmpty() || !content.empty());
2164  }
2165  CATCH
2166
2167  bool CField::hasGridMask(void) const
2168  TRY
2169  {
2170    return (this->grid_->hasMask());
2171  }
2172  CATCH
2173
2174  DEFINE_REF_FUNC(Field,field)
2175} // namespace xios
Note: See TracBrowser for help on using the repository browser.