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

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

trunk : bug fix for workflowgraph

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