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

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

Coupling Branch.
Implementing a coupler scheduler, to impose order for intercommunicator creation between several coupling context.
Two way coupling is now working.

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