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

Last change on this file since 1665 was 1665, checked in by yushan, 2 years ago

MARK: branch merged with trunk @1660. Add option --omp to enable multithreading.

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