source: XIOS/dev/dev_trunk_omp/src/node/field.cpp @ 1670

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

MARK: branch merged with trunk @1663. Generate one static graph for each output file

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