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

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

XIOS coupling branch
Adopt infrastructure based on filter for reading data on server side and sending it to the client, in a similar way on what is done for other case.

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