source: XIOS/dev/dev_olga/src/node/field.cpp @ 1654

Last change on this file since 1654 was 1654, checked in by oabramkina, 3 years ago

Corrections for workflow visualization.

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