source: XIOS/dev/XIOS_DEV_CMIP6/src/node/field.cpp @ 1215

Last change on this file since 1215 was 1215, checked in by ymipsl, 7 years ago

Distribute files on servers 2 -> Ok test_dcmip2

YM

  • Property copyright set to
    Software name : XIOS (Xml I/O Server)
    http://forge.ipsl.jussieu.fr/ioserver
    Creation date : January 2009
    Licence : CeCCIL version2
    see license file in root directory : Licence_CeCILL_V2-en.txt
    or http://www.cecill.info/licences/Licence_CeCILL_V2-en.html
    Holder : CEA/LSCE (Laboratoire des Sciences du CLimat et de l'Environnement)
    CNRS/IPSL (Institut Pierre Simon Laplace)
    Project Manager : Yann Meurdesoif
    yann.meurdesoif@cea.fr
  • Property svn:executable set to *
File size: 49.1 KB
Line 
1#include "field.hpp"
2
3#include "attribute_template.hpp"
4#include "object_template.hpp"
5#include "group_template.hpp"
6
7#include "node_type.hpp"
8#include "calendar_util.hpp"
9#include "message.hpp"
10#include "xios_spl.hpp"
11#include "type.hpp"
12#include "timer.hpp"
13#include "context_client.hpp"
14#include "context_server.hpp"
15#include <set>
16#include "garbage_collector.hpp"
17#include "source_filter.hpp"
18#include "store_filter.hpp"
19#include "file_writer_filter.hpp"
20#include "pass_through_filter.hpp"
21#include "filter_expr_node.hpp"
22#include "lex_parser.hpp"
23#include "temporal_filter.hpp"
24#include "spatial_transform_filter.hpp"
25#include "file_server_writer_filter.hpp"
26
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      , useCompressedOutput(false)
40      , hasTimeInstant(false)
41      , hasTimeCentered(false)
42      , wasDataAlreadyReceivedFromServer(false)
43      , isEOF(false)
44   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
45
46   CField::CField(const StdString& id)
47      : CObjectTemplate<CField>(id), CFieldAttributes()
48      , grid(), file()
49      , written(false)
50      , nstep(0), nstepMax(0)
51      , hasOutputFile(false)
52      , domAxisScalarIds_(vector<StdString>(3,""))
53      , areAllReferenceSolved(false), isReferenceSolved(false), isReferenceSolvedAndTransformed(false)
54      , useCompressedOutput(false)
55      , hasTimeInstant(false)
56      , hasTimeCentered(false)
57      , wasDataAlreadyReceivedFromServer(false)
58      , isEOF(false)
59   { setVirtualVariableGroup(CVariableGroup::create(getId() + "_virtual_variable_group")); }
60
61   CField::~CField(void)
62   {}
63
64  //----------------------------------------------------------------
65
66   void CField::setVirtualVariableGroup(CVariableGroup* newVVariableGroup)
67   {
68      this->vVariableGroup = newVVariableGroup;
69   }
70
71   CVariableGroup* CField::getVirtualVariableGroup(void) const
72   {
73      return this->vVariableGroup;
74   }
75
76   std::vector<CVariable*> CField::getAllVariables(void) const
77   {
78      return this->vVariableGroup->getAllChildren();
79   }
80
81   void CField::solveDescInheritance(bool apply, const CAttributeMap* const parent)
82   {
83      SuperClassAttribute::setAttributes(parent, apply);
84      this->getVirtualVariableGroup()->solveDescInheritance(apply, NULL);
85   }
86
87  //----------------------------------------------------------------
88
89  bool CField::dispatchEvent(CEventServer& event)
90  {
91    if (SuperClass::dispatchEvent(event)) return true;
92    else
93    {
94      switch(event.type)
95      {
96        case EVENT_ID_UPDATE_DATA :
97          recvUpdateData(event);
98          return true;
99          break;
100
101        case EVENT_ID_READ_DATA :
102          recvReadDataRequest(event);
103          return true;
104          break;
105
106        case EVENT_ID_READ_DATA_READY :
107          recvReadDataReady(event);
108          return true;
109          break;
110
111        case EVENT_ID_ADD_VARIABLE :
112          recvAddVariable(event);
113          return true;
114          break;
115
116        case EVENT_ID_ADD_VARIABLE_GROUP :
117          recvAddVariableGroup(event);
118          return true;
119          break;
120
121        default :
122          ERROR("bool CField::dispatchEvent(CEventServer& event)", << "Unknown Event");
123          return false;
124      }
125    }
126  }
127
128  void CField::sendUpdateData(const CArray<double,1>& data)
129  {
130    CTimer::get("Field : send data").resume();
131
132    CContext* context = CContext::getCurrent();
133    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
134
135    CEventClient event(getType(), EVENT_ID_UPDATE_DATA);
136
137    map<int, CArray<int,1> >::iterator it;
138    list<CMessage> list_msg;
139    list<CArray<double,1> > list_data;
140
141    if (!grid->doGridHaveDataDistributed())
142    {
143       if (client->isServerLeader())
144       {
145          for (it = grid->storeIndex_toSrv.begin(); it != grid->storeIndex_toSrv.end(); it++)
146          {
147            int rank = it->first;
148            CArray<int,1>& index = it->second;
149
150            list_msg.push_back(CMessage());
151            list_data.push_back(CArray<double,1>(index.numElements()));
152
153            CArray<double,1>& data_tmp = list_data.back();
154            for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
155
156            list_msg.back() << getId() << data_tmp;
157            event.push(rank, 1, list_msg.back());
158          }
159          client->sendEvent(event);
160        }
161      else client->sendEvent(event);
162    }
163    else
164    {
165      for (it = grid->storeIndex_toSrv.begin(); it != grid->storeIndex_toSrv.end(); it++)
166      {
167        int rank = it->first;
168        CArray<int,1>& index = it->second;
169
170        list_msg.push_back(CMessage());
171        list_data.push_back(CArray<double,1>(index.numElements()));
172
173        CArray<double,1>& data_tmp = list_data.back();
174        for (int n = 0; n < data_tmp.numElements(); n++) data_tmp(n) = data(index(n));
175
176        list_msg.back() << getId() << data_tmp;
177        event.push(rank, grid->nbSenders[0][rank], list_msg.back());
178      }
179      client->sendEvent(event);
180    }
181
182    CTimer::get("Field : send data").suspend();
183  }
184
185  void CField::recvUpdateData(CEventServer& event)
186  {
187    std::map<int,CBufferIn*> rankBuffers;
188
189    list<CEventServer::SSubEvent>::iterator it;
190    string fieldId;
191    CTimer::get("Field : recv data").resume();
192    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
193    {
194      int rank = it->rank;
195      CBufferIn* buffer = it->buffer;
196      *buffer >> fieldId;
197      rankBuffers[rank] = buffer;
198    }
199    get(fieldId)->recvUpdateData(rankBuffers);
200    CTimer::get("Field : recv data").suspend();
201  }
202
203  void  CField::recvUpdateData(std::map<int,CBufferIn*>& rankBuffers)
204  {
205    CContext* context = CContext::getCurrent();
206
207    size_t sizeData = 0;
208    if (0 == recvDataSrv.numElements())
209    {           
210      CArray<int,1>& storeClient = grid->storeIndex_client;
211
212      // Gather all data from different clients     
213      recvDataSrv.resize(storeClient.numElements());
214      recvFoperationSrv = boost::shared_ptr<func::CFunctor>(new func::CInstant(recvDataSrv));
215    }
216
217    CArray<double,1> recv_data_tmp(recvDataSrv.numElements());   
218    const CDate& currDate = context->getCalendar()->getCurrentDate();
219    const CDate opeDate   = last_operation_srv +freq_op + freq_operation_srv - freq_op;
220
221    if (opeDate <= currDate)
222    {
223      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); it != grid->outLocalIndexStoreOnClient.end(); ++it)
224      {
225        CArray<double,1> tmp;
226        CArray<size_t,1>& indexTmp = it->second;
227        *(rankBuffers[it->first]) >> tmp;
228        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
229        {
230          recv_data_tmp(indexTmp(idx)) = tmp(idx);
231        }     
232      }
233    }
234
235    this->setData(recv_data_tmp);
236  }
237
238  void CField::writeUpdateData(const CArray<double,1>& data)
239  {
240    CContext* context = CContext::getCurrent();
241
242    const CDate& currDate = context->getCalendar()->getCurrentDate();
243    const CDate opeDate      = last_operation_srv +freq_op + freq_operation_srv - freq_op;
244    const CDate writeDate    = last_Write_srv     + freq_write_srv;
245
246    if (opeDate <= currDate)
247    {
248      (*recvFoperationSrv)(data);
249      last_operation_srv = currDate;
250    }
251
252    if (writeDate < (currDate + freq_operation_srv))
253    {
254      recvFoperationSrv->final();
255      last_Write_srv = writeDate;
256      grid->computeWrittenIndex();
257      writeField();
258      lastlast_Write_srv = last_Write_srv;
259    }
260  }
261
262  void CField::writeField(void)
263  {
264    if (!getRelFile()->allDomainEmpty)
265    {
266      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
267      {
268        getRelFile()->checkWriteFile();
269        this->incrementNStep();
270        getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
271      }
272    }
273  }
274
275  bool CField::sendReadDataRequest(const CDate& tsDataRequested)
276  {
277    CContext* context = CContext::getCurrent();
278//    CContextClient* client = context->client;
279    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
280
281    lastDataRequestedFromServer = tsDataRequested;
282
283    if (!isEOF) // No need to send the request if we already know we are at EOF
284    {
285      CEventClient event(getType(), EVENT_ID_READ_DATA);
286      if (client->isServerLeader())
287      {
288        CMessage msg;
289        msg << getId();
290        const std::list<int>& ranks = client->getRanksServerLeader();
291        for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
292          event.push(*itRank, 1, msg);
293        client->sendEvent(event);
294      }
295      else client->sendEvent(event);
296    }
297    else
298      serverSourceFilter->signalEndOfStream(tsDataRequested);
299
300    return !isEOF;
301  }
302
303  /*!
304  Send request new data read from file if need be, that is the current data is out-of-date.
305  \return true if and only if some data was requested
306  */
307  bool CField::sendReadDataRequestIfNeeded(void)
308  {
309    const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
310
311    bool dataRequested = false;
312
313    while (currentDate >= lastDataRequestedFromServer)
314    {
315      info(20) << "currentDate : " << currentDate << endl ;
316      info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
317      info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
318      info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
319
320      dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq);
321    }
322
323    return dataRequested;
324  }
325
326  void CField::recvReadDataRequest(CEventServer& event)
327  {
328    CBufferIn* buffer = event.subEvents.begin()->buffer;
329    StdString fieldId;
330    *buffer >> fieldId;
331    get(fieldId)->recvReadDataRequest();
332  }
333
334  void CField::recvReadDataRequest(void)
335  {
336    CContext* context = CContext::getCurrent();
337    CContextClient* client = context->client;
338//    CContextClient* client = (!context->hasServer) ? context->client : this->file->getContextClient();
339
340    CEventClient event(getType(), EVENT_ID_READ_DATA_READY);
341    std::list<CMessage> msgs;
342
343    bool hasData = readField();
344
345    map<int, CArray<double,1> >::iterator it;
346    if (!grid->doGridHaveDataDistributed())
347    {
348       if (client->isServerLeader())
349       {
350          if (0 != recvDataSrv.numElements())
351          {           
352            const std::list<int>& ranks = client->getRanksServerLeader();
353            for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
354            {
355              msgs.push_back(CMessage());
356              CMessage& msg = msgs.back();
357              msg << getId();
358              if (hasData)
359                msg << getNStep() - 1 << recvDataSrv;
360              else
361                msg << int(-1);
362              event.push(*itRank, 1, msg);
363            }
364          }
365          client->sendEvent(event);
366       }
367       else
368       {
369          client->sendEvent(event);
370       }
371    }
372    else
373    {
374      for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin(); 
375                                                  it != grid->outLocalIndexStoreOnClient.end(); ++it)
376      {
377        CArray<size_t,1>& indexTmp = it->second;
378        CArray<double,1> tmp(indexTmp.numElements());
379        for (int idx = 0; idx < indexTmp.numElements(); ++idx)
380        {
381          tmp(idx) = recvDataSrv(indexTmp(idx));
382        } 
383
384        msgs.push_back(CMessage());
385        CMessage& msg = msgs.back();
386        msg << getId();
387        if (hasData)
388          msg << getNStep() - 1 << tmp;
389        else
390          msg << int(-1);
391        event.push(it->first, grid->nbReadSenders[0][it->first], msg);
392      }
393      client->sendEvent(event);
394    }
395  }
396
397  bool CField::readField(void)
398  {
399    grid->computeWrittenIndex();
400    if (!getRelFile()->allDomainEmpty)
401    {
402      if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
403      {
404        if (0 == recvDataSrv.numElements())
405        {           
406          CArray<int,1>& storeClient = grid->storeIndex_client;         
407          recvDataSrv.resize(storeClient.numElements());         
408        }
409
410        getRelFile()->checkReadFile();
411        if (!nstepMax)
412        {
413          nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
414        }
415
416        this->incrementNStep();
417
418        if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
419          return false;
420
421        getRelFile()->getDataInput()->readFieldData(CField::get(this));
422      }
423    }
424
425    return true;
426  }
427
428  void CField::recvReadDataReady(CEventServer& event)
429  {
430    string fieldId;
431    vector<int> ranks;
432    vector<CBufferIn*> buffers;
433
434    list<CEventServer::SSubEvent>::iterator it;
435    for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
436    {
437      ranks.push_back(it->rank);
438      CBufferIn* buffer = it->buffer;
439      *buffer >> fieldId;
440      buffers.push_back(buffer);
441    }
442    get(fieldId)->recvReadDataReady(ranks, buffers);
443  }
444
445  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
446  {
447    CContext* context = CContext::getCurrent();
448    int record;
449    std::map<int, CArray<double,1> > data;
450
451    for (int i = 0; i < ranks.size(); i++)
452    {
453      int rank = ranks[i];
454      *buffers[i] >> record;
455      isEOF = (record == int(-1));
456
457      if (!isEOF)
458        *buffers[i] >> data[rank];
459      else
460        break;
461    }
462
463    if (wasDataAlreadyReceivedFromServer)
464      lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
465    else
466    {
467      lastDataReceivedFromServer = context->getCalendar()->getInitDate();
468      wasDataAlreadyReceivedFromServer = true;
469    }
470
471    if (isEOF)
472      serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
473    else
474      serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
475  }
476
477   //----------------------------------------------------------------
478
479   void CField::setRelFile(CFile* _file)
480   {
481      this->file = _file;
482      hasOutputFile = true;
483   }
484
485   //----------------------------------------------------------------
486
487   StdString CField::GetName(void)    { return StdString("field"); }
488   StdString CField::GetDefName(void) { return CField::GetName(); }
489   ENodeType CField::GetType(void)    { return eField; }
490
491   //----------------------------------------------------------------
492
493   CGrid* CField::getRelGrid(void) const
494   {
495      return this->grid;
496   }
497
498   //----------------------------------------------------------------
499
500   CFile* CField::getRelFile(void) const
501   {
502      return this->file;
503   }
504
505   int CField::getNStep(void) const
506   {
507      return this->nstep;
508   }
509
510   func::CFunctor::ETimeType CField::getOperationTimeType() const
511   {
512     return operationTimeType;
513   }
514
515   //----------------------------------------------------------------
516
517   void CField::incrementNStep(void)
518   {
519      this->nstep++;
520   }
521
522   void CField::resetNStep(int nstep /*= 0*/)
523   {
524      this->nstep = nstep;
525   }
526
527   void CField::resetNStepMax(void)
528   {
529      this->nstepMax = 0;
530   }
531
532   //----------------------------------------------------------------
533
534   bool CField::isActive(bool atCurrentTimestep /*= false*/) const
535   {
536      if (clientSourceFilter)
537        return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
538      else if (storeFilter)
539        return true;
540      else if (instantDataFilter)
541        ERROR("bool CField::isActive(bool atCurrentTimestep)",
542              << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
543
544      return false;
545   }
546
547   //----------------------------------------------------------------
548
549   bool CField::wasWritten() const
550   {
551     return written;
552   }
553
554   void CField::setWritten()
555   {
556     written = true;
557   }
558
559   //----------------------------------------------------------------
560
561   bool CField::getUseCompressedOutput() const
562   {
563     return useCompressedOutput;
564   }
565
566   void CField::setUseCompressedOutput()
567   {
568     useCompressedOutput = true;
569   }
570
571   //----------------------------------------------------------------
572
573   boost::shared_ptr<COutputPin> CField::getInstantDataFilter()
574   {
575     return instantDataFilter;
576   }
577
578   //----------------------------------------------------------------
579
580   /*!
581     Build up graph of grids which plays role of destination and source in grid transformation
582     This function should be called before \func solveGridReference()
583   */
584   void CField::buildGridTransformationGraph()
585   {
586     CContext* context = CContext::getCurrent();
587     if (context->hasClient && !context->hasServer)
588     {
589       if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
590       {
591         grid->addTransGridSource(getDirectFieldReference()->grid);
592       }
593     }
594   }
595
596   /*!
597     Generate a new grid destination if there are more than one grid source pointing to a same grid destination
598   */
599   void CField::generateNewTransformationGridDest()
600   {
601     CContext* context = CContext::getCurrent();
602     if (context->hasClient && !context->hasServer)
603     {
604       std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
605       if (1 < gridSrcMap.size())
606       {
607         // Search for grid source
608         CGrid* gridSrc = grid;
609         CField* currField = this;
610         std::vector<CField*> hieraField;
611
612         while (currField->hasDirectFieldReference() && (gridSrc == grid))
613         {
614           hieraField.push_back(currField);
615           CField* tmp = currField->getDirectFieldReference();
616           currField = tmp;
617           gridSrc = currField->grid;
618         }
619
620         if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
621         {
622           CGrid* gridTmp;
623           std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
624           if (newGridDest.first)
625           {
626             StdString newIdGridDest = newGridDest.second;
627             if (!CGrid::has(newIdGridDest))
628             {
629                ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
630                  << " Something wrong happened! Grid whose id " << newIdGridDest
631                  << "should exist ");
632             }
633             gridTmp = CGrid::get(newIdGridDest);
634           }
635           else
636           {
637             StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
638             gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
639
640             (gridSrcMap[gridSrc]).first = true;
641             (gridSrcMap[gridSrc]).second = newIdGridDest;
642           }
643
644           // Update all descendants
645           for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
646           {
647             (*it)->grid = gridTmp;
648             (*it)->updateRef((*it)->grid);
649           }
650         }
651       }
652     }
653   }
654
655   void CField::updateRef(CGrid* grid)
656   {
657     if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
658     else
659     {
660       std::vector<CAxis*> axisTmp = grid->getAxis();
661       std::vector<CDomain*> domainTmp = grid->getDomains();
662       if ((1<axisTmp.size()) || (1<domainTmp.size()))
663         ERROR("void CField::updateRef(CGrid* grid)",
664           << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
665
666       if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
667         ERROR("void CField::updateRef(CGrid* grid)",
668           << "Incoherent between available domain and domain_ref of field " << this->getId());
669       if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
670         ERROR("void CField::updateRef(CGrid* grid)",
671           << "Incoherent between available axis and axis_ref of field " << this->getId());
672
673       if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
674       if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
675     }
676   }
677   
678   /*!
679     Solve reference of all enabled fields even the source fields .
680     In this step, we do transformations.
681   */
682   void CField::solveAllEnabledFieldsAndTransform()
683   {
684     CContext* context = CContext::getCurrent();
685     bool hasClient = context->hasClient;
686     bool hasServer = context->hasServer;
687
688     if (!isReferenceSolvedAndTransformed)
689     {
690        isReferenceSolvedAndTransformed = true;
691
692        if (hasClient && !hasServer)
693        {
694          solveRefInheritance(true);
695          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
696        }
697
698        if (hasServer)
699          solveServerOperation();
700
701        solveGridReference();
702
703        if (hasClient && !hasServer)
704       {
705         solveGenerateGrid();
706         buildGridTransformationGraph();
707       }
708
709       solveGridDomainAxisRef(false);
710
711       if (hasClient && !hasServer)
712       {
713         solveTransformedGrid();
714       }
715
716       solveGridDomainAxisRef(false);
717     }
718   }
719
720   void CField::checkGridOfEnabledFields()
721   {
722      solveCheckMaskIndex(false);
723   }
724
725   void CField::sendGridOfEnabledFields()
726   {
727      solveGridDomainAxisRef(true);
728      solveCheckMaskIndex(true);
729   }
730
731
732    void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
733   {
734     CContext* context = CContext::getCurrent();
735     if (!isReferenceSolved)
736     {
737        isReferenceSolved = true;
738
739        if (context->hasClient && !context->hasServer)
740        {
741          solveRefInheritance(true);
742          if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
743        }
744
745        if (context->hasServer)
746          solveServerOperation();
747
748        solveGridReference();
749
750        if (context->hasClient && !context->hasServer)
751       {
752         solveGenerateGrid();
753         buildGridTransformationGraph();
754       }
755     }
756   }
757     
758   void CField::solveAllReferenceEnabledField(bool doSending2Server)
759   {
760     CContext* context = CContext::getCurrent();
761     solveOnlyReferenceEnabledField(doSending2Server);
762
763     if (!areAllReferenceSolved)
764     {
765        areAllReferenceSolved = true;
766       
767        if (context->hasClient && !context->hasServer)
768        {
769          solveRefInheritance(true);
770          if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
771        }
772        else if (context->hasServer)
773          solveServerOperation();
774
775        solveGridReference();
776     }
777
778     solveGridDomainAxisRef(doSending2Server);
779
780     if (context->hasClient && !context->hasServer)
781     {
782       solveTransformedGrid();
783     }
784
785     solveCheckMaskIndex(doSending2Server);
786   }
787
788   std::map<int, StdSize> CField::getGridAttributesBufferSize()
789   {
790     return grid->getAttributesBufferSize();
791   }
792
793   std::vector<std::map<int, StdSize> > CField::getGridDataBufferSize()
794   {
795     return grid->getDataBufferSize(getId());
796   }
797
798   size_t CField::getGlobalWrittenSize()
799   {
800     return grid->getGlobalWrittenSize();
801   }
802
803   //----------------------------------------------------------------
804
805   void CField::solveServerOperation(void)
806   {
807      CContext* context = CContext::getCurrent();
808
809      if (!context->hasServer || !hasOutputFile) return;
810
811      if (freq_op.isEmpty())
812        freq_op.setValue(TimeStep);
813
814      if (freq_offset.isEmpty())
815        freq_offset.setValue(NoneDu);
816
817      freq_operation_srv = file->output_freq.getValue();
818      freq_write_srv     = file->output_freq.getValue();
819
820      lastlast_Write_srv = context->getCalendar()->getInitDate();
821      last_Write_srv     = context->getCalendar()->getInitDate();
822      last_operation_srv = context->getCalendar()->getInitDate();
823
824      const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
825      last_operation_srv     = last_operation_srv - toffset;
826
827      if (operation.isEmpty())
828        ERROR("void CField::solveServerOperation(void)",
829              << "An operation must be defined for field \"" << getId() << "\".");
830
831      boost::shared_ptr<func::CFunctor> functor;
832      CArray<double, 1> dummyData;
833
834#define DECLARE_FUNCTOR(MType, mtype) \
835      if (operation.getValue().compare(#mtype) == 0) \
836      { \
837        functor.reset(new func::C##MType(dummyData)); \
838      }
839
840#include "functor_type.conf"
841
842      if (!functor)
843        ERROR("void CField::solveServerOperation(void)",
844              << "\"" << operation << "\" is not a valid operation.");
845
846      operationTimeType = functor->timeType();
847   }
848
849   //----------------------------------------------------------------
850
851   /*!
852    * Constructs the graph filter for the field, enabling or not the data output.
853    * This method should not be called more than once with enableOutput equal to true.
854    *
855    * \param gc the garbage collector to use when building the filter graph
856    * \param enableOutput must be true when the field data is to be
857    *                     read by the client or/and written to a file
858    */
859   void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
860   {     
861    if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
862
863     const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
864     const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
865
866     CContext* context = CContext::getCurrent();
867     bool hasWriterServer = context->hasServer && !context->hasClient;
868     bool hasIntermediateServer = context->hasServer && context->hasClient;
869
870     if (hasWriterServer)
871     {
872        if (!instantDataFilter)
873          instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid));
874
875             // If the field data is to be read by the client or/and written to a file
876       if (enableOutput && !storeFilter && !fileWriterFilter)
877       {
878         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
879         {
880           fileServerWriterFilter = boost::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
881           instantDataFilter->connectOutput(fileServerWriterFilter, 0);
882         }
883       }
884     }
885     else if (hasIntermediateServer)
886     {
887       if (!instantDataFilter)
888         instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid));
889
890             // If the field data is to be read by the client or/and written to a file
891       if (enableOutput && !storeFilter && !fileWriterFilter)
892       {
893         if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
894         {
895           fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
896           instantDataFilter->connectOutput(fileWriterFilter, 0);
897         }
898       }
899     }
900     else
901     {
902       // Start by building a filter which can provide the field's instant data
903       if (!instantDataFilter)
904       {
905         // Check if we have an expression to parse
906         if (hasExpression())
907         {
908           boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
909           boost::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
910
911           // Check if a spatial transformation is needed
912           if (!field_ref.isEmpty())
913           {
914             CGrid* gridRef = CField::get(field_ref)->grid;
915
916             if (grid && grid != gridRef && grid->hasTransform())
917             {
918                 std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue); 
919
920               filter->connectOutput(filters.first, 0);
921               filter = filters.second;
922             }
923           }
924
925           instantDataFilter = filter;
926         }
927         // Check if we have a reference on another field
928         else if (!field_ref.isEmpty())
929           instantDataFilter = getFieldReference(gc);
930         // Check if the data is to be read from a file
931         else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
932           instantDataFilter = serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,
933                                                                                                       freq_offset.isEmpty() ? NoneDu : freq_offset,
934                                                                                                       true,
935                                                                                                       detectMissingValues, defaultValue));
936         else // The data might be passed from the model
937         {
938            if (check_if_active.isEmpty()) check_if_active = false; 
939            instantDataFilter = clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
940                                                                                                        detectMissingValues, defaultValue));
941         }
942       }
943
944       // If the field data is to be read by the client or/and written to a file
945       if (enableOutput && !storeFilter && !fileWriterFilter)
946       {
947         storeFilter = boost::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
948                                                                        detectMissingValues, defaultValue));
949         instantDataFilter->connectOutput(storeFilter, 0);
950       }
951
952       if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
953       {
954         fileWriterFilter = boost::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
955         getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
956       }
957     }
958   }
959
960   /*!
961    * Returns the filter needed to handle the field reference.
962    * This method should only be called when building the filter graph corresponding to the field.
963    *
964    * \param gc the garbage collector to use
965    * \return the output pin corresponding to the field reference
966    */
967   boost::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
968   {
969     if (instantDataFilter || field_ref.isEmpty())
970       ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
971             "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
972
973     CField* fieldRef = CField::get(field_ref);
974     fieldRef->buildFilterGraph(gc, false);
975
976     std::pair<boost::shared_ptr<CFilter>, boost::shared_ptr<CFilter> > filters;
977     // Check if a spatial transformation is needed
978     if (grid && grid != fieldRef->grid && grid->hasTransform())
979     {       
980       bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
981       double defaultValue  = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);                               
982       filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
983     }
984     else
985       filters.first = filters.second = boost::shared_ptr<CFilter>(new CPassThroughFilter(gc));
986
987     fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
988
989     return filters.second;
990   }
991
992   /*!
993    * Returns the filter needed to handle a self reference in the field's expression.
994    * If the needed filter does not exist, it is created, otherwise it is reused.
995    * This method should only be called when building the filter graph corresponding
996    * to the field's expression.
997    *
998    * \param gc the garbage collector to use
999    * \return the output pin corresponding to a self reference
1000    */
1001   boost::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1002   {
1003     if (instantDataFilter || !hasExpression())
1004       ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1005             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1006
1007     if (!selfReferenceFilter)
1008     {
1009       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1010       const double defaultValue  = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1011
1012       if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1013       {
1014         if (!serverSourceFilter)
1015           serverSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid,
1016                                                                                   freq_offset.isEmpty() ? NoneDu : freq_offset,
1017                                                                                   true,
1018                                                                                   detectMissingValues, defaultValue));
1019
1020         selfReferenceFilter = serverSourceFilter;
1021       }
1022       else if (!field_ref.isEmpty())
1023       {
1024         CField* fieldRef = CField::get(field_ref);
1025         fieldRef->buildFilterGraph(gc, false);
1026         selfReferenceFilter = fieldRef->getInstantDataFilter();
1027       }
1028       else
1029       {
1030         if (!clientSourceFilter)
1031         {
1032           if (check_if_active.isEmpty()) check_if_active = false;
1033           clientSourceFilter = boost::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, NoneDu, false,
1034                                                                                   detectMissingValues, defaultValue));
1035         }
1036
1037         selfReferenceFilter = clientSourceFilter;
1038       }
1039     }
1040
1041     return selfReferenceFilter;
1042   }
1043
1044   /*!
1045    * Returns the temporal filter corresponding to the field's temporal operation
1046    * for the specified operation frequency. The filter is created if it does not
1047    * exist, otherwise it is reused.
1048    *
1049    * \param gc the garbage collector to use
1050    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1051    * \return the output pin corresponding to the requested temporal filter
1052    */
1053   boost::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1054   {
1055     std::map<CDuration, boost::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1056
1057     if (it == temporalDataFilters.end())
1058     {
1059       if (operation.isEmpty())
1060         ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1061               << "An operation must be defined for field \"" << getId() << "\".");
1062
1063       if (freq_op.isEmpty())
1064         freq_op.setValue(TimeStep);
1065       if (freq_offset.isEmpty())
1066         freq_offset.setValue(NoneDu);
1067
1068       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1069       
1070       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1071                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1072                                                                             freq_op, freq_offset, outFreq,
1073                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1074       instantDataFilter->connectOutput(temporalFilter, 0);
1075
1076       it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1077     }
1078
1079     return it->second;
1080   }
1081
1082  /*!
1083    * Returns the temporal filter corresponding to the field's temporal operation
1084    * for the specified operation frequency.
1085    *
1086    * \param gc the garbage collector to use
1087    * \param outFreq the operation frequency, i.e. the frequency at which the output data will be computed
1088    * \return the output pin corresponding to the requested temporal filter
1089    */
1090   
1091   boost::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1092   {
1093     if (instantDataFilter || !hasExpression())
1094       ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1095             "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1096
1097     if (!selfReferenceFilter) getSelfReference(gc) ;
1098
1099     if (serverSourceFilter || clientSourceFilter)
1100     {
1101       if (operation.isEmpty())
1102         ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1103               << "An operation must be defined for field \"" << getId() << "\".");
1104
1105       if (freq_op.isEmpty()) freq_op.setValue(TimeStep);
1106       if (freq_offset.isEmpty()) freq_offset.setValue(NoneDu);
1107
1108       const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1109
1110       boost::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1111                                                                             CContext::getCurrent()->getCalendar()->getInitDate(),
1112                                                                             freq_op, freq_offset, outFreq,
1113                                                                             detectMissingValues, detectMissingValues ? default_value : 0.0));
1114       selfReferenceFilter->connectOutput(temporalFilter, 0);
1115       return temporalFilter ;
1116     }
1117     else if (!field_ref.isEmpty())
1118     {
1119       CField* fieldRef = CField::get(field_ref);
1120       fieldRef->buildFilterGraph(gc, false); 
1121       return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1122     }
1123  }
1124
1125   //----------------------------------------------------------------
1126/*
1127   void CField::fromBinary(StdIStream& is)
1128   {
1129      SuperClass::fromBinary(is);
1130#define CLEAR_ATT(name_)\
1131      SuperClassAttribute::operator[](#name_)->reset()
1132
1133         CLEAR_ATT(domain_ref);
1134         CLEAR_ATT(axis_ref);
1135#undef CLEAR_ATT
1136
1137   }
1138*/
1139   //----------------------------------------------------------------
1140
1141   void CField::solveGridReference(void)
1142   {
1143      if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1144      {
1145        ERROR("CField::solveGridReference(void)",
1146              << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1147      }
1148      else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1149      {
1150        ERROR("CField::solveGridReference(void)",
1151              << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1152              << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1153      }
1154
1155      if (grid_ref.isEmpty())
1156      {
1157        std::vector<CDomain*> vecDom;
1158        std::vector<CAxis*> vecAxis;
1159        std::vector<CScalar*> vecScalar;
1160        std::vector<int> axisDomainOrderTmp;
1161       
1162        if (!domain_ref.isEmpty())
1163        {
1164          StdString tmp = domain_ref.getValue();
1165          if (CDomain::has(domain_ref))
1166          {
1167            vecDom.push_back(CDomain::get(domain_ref));
1168            axisDomainOrderTmp.push_back(2);
1169          }
1170          else
1171            ERROR("CField::solveGridReference(void)",
1172                  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1173        }
1174
1175        if (!axis_ref.isEmpty())
1176        {
1177          if (CAxis::has(axis_ref))
1178          {
1179            vecAxis.push_back(CAxis::get(axis_ref));
1180            axisDomainOrderTmp.push_back(1);
1181          }
1182          else
1183            ERROR("CField::solveGridReference(void)",
1184                  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1185        }
1186
1187        if (!scalar_ref.isEmpty())
1188        {
1189          if (CScalar::has(scalar_ref))
1190          {
1191            vecScalar.push_back(CScalar::get(scalar_ref));
1192            axisDomainOrderTmp.push_back(0);
1193          }
1194          else
1195            ERROR("CField::solveGridReference(void)",
1196                  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1197        }
1198       
1199        CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1200        for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1201        {
1202          axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1203        }
1204
1205        // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1206        StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1207        if (CGrid::has(gridId))
1208          this->grid = CGrid::get(gridId);
1209        else
1210          this->grid = CGrid::createGrid(gridId, vecDom, vecAxis, vecScalar,axisDomainOrder);
1211      }
1212      else
1213      {
1214        if (CGrid::has(grid_ref))
1215          this->grid = CGrid::get(grid_ref);
1216        else
1217          ERROR("CField::solveGridReference(void)",
1218                << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1219      }
1220   }
1221
1222   void CField::solveGridDomainAxisRef(bool checkAtt)
1223   {
1224     grid->solveDomainAxisRef(checkAtt);
1225   }
1226
1227   void CField::solveCheckMaskIndex(bool doSendingIndex)
1228   {
1229     grid->checkMaskIndex(doSendingIndex);
1230   }
1231
1232   void CField::solveTransformedGrid()
1233   {
1234     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1235     {
1236       std::vector<CGrid*> grids;
1237       // Source grid
1238       grids.push_back(getDirectFieldReference()->grid);
1239       // Intermediate grids
1240       if (!grid_path.isEmpty())
1241       {
1242         std::string gridId;
1243         size_t start = 0, end;
1244
1245         do
1246         {
1247           end = grid_path.getValue().find(',', start);
1248           if (end != std::string::npos)
1249           {
1250             gridId = grid_path.getValue().substr(start, end - start);
1251             start = end + 1;
1252           }
1253           else
1254             gridId = grid_path.getValue().substr(start);
1255
1256           if (!CGrid::has(gridId))
1257             ERROR("void CField::solveTransformedGrid()",
1258                   << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1259
1260           grids.push_back(CGrid::get(gridId));
1261         }
1262         while (end != std::string::npos);
1263       }
1264       // Destination grid
1265       grids.push_back(grid);
1266
1267       for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1268       {
1269         CGrid *gridSrc  = grids[i];
1270         CGrid *gridDest = grids[i + 1];
1271         if (!gridDest->isTransformed())
1272           gridDest->transformGrid(gridSrc);
1273       }
1274     }
1275     else if (grid && grid->hasTransform() && !grid->isTransformed())
1276     {
1277       // Temporarily deactivate the self-transformation of grid
1278       //grid->transformGrid(grid);
1279     }
1280   }
1281
1282   void CField::solveGenerateGrid()
1283   {
1284     if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1285       grid->completeGrid(getDirectFieldReference()->grid);
1286     else
1287       grid->completeGrid();
1288   }
1289
1290   void CField::solveGridDomainAxisBaseRef()
1291   {
1292     grid->solveDomainAxisRef(false);
1293     grid->solveDomainAxisBaseRef();
1294   }
1295
1296   ///-------------------------------------------------------------------
1297
1298   template <>
1299   void CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)
1300   {
1301      if (this->group_ref.isEmpty()) return;
1302      StdString gref = this->group_ref.getValue();
1303
1304      if (!CFieldGroup::has(gref))
1305         ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1306               << "[ gref = " << gref << "]"
1307               << " invalid group name !");
1308
1309      CFieldGroup* group = CFieldGroup::get(gref);
1310      CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1311
1312      std::vector<CField*> allChildren  = group->getAllChildren();
1313      std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1314
1315      for (; it != end; it++)
1316      {
1317         CField* child = *it;
1318         if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1319
1320      }
1321   }
1322
1323   void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1324   {
1325     recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1326   }
1327
1328   void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1329   {
1330     recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1331   }
1332
1333   void CField::outputField(CArray<double,1>& fieldOut)
1334   { 
1335      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1336      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1337      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1338      {
1339        fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1340      }
1341   }
1342
1343   void CField::inputField(CArray<double,1>& fieldIn)
1344   {
1345      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1346      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1347      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1348      {
1349        recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1350      }
1351
1352   }
1353
1354   void CField::outputCompressedField(CArray<double,1>& fieldOut)
1355   {
1356      CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1357      CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1358      for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1359      {
1360        fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1361      }
1362   }
1363
1364   ///-------------------------------------------------------------------
1365
1366   void CField::parse(xml::CXMLNode& node)
1367   {
1368      SuperClass::parse(node);
1369      if (!node.getContent(this->content))
1370      {
1371        if (node.goToChildElement())
1372        {
1373          do
1374          {
1375            if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1376          } while (node.goToNextElement());
1377          node.goToParentElement();
1378        }
1379      }
1380    }
1381
1382   /*!
1383     This function retrieves Id of corresponding domain_ref and axis_ref (if any)
1384   of a field. In some cases, only domain exists but axis doesn't
1385   \return pair of Domain and Axis id
1386   */
1387   const std::vector<StdString>& CField::getRefDomainAxisIds()
1388   {
1389     CGrid* cgPtr = getRelGrid();
1390     if (NULL != cgPtr)
1391     {
1392       std::vector<StdString>::iterator it;
1393       if (!domain_ref.isEmpty())
1394       {
1395         std::vector<StdString> domainList = cgPtr->getDomainList();
1396         it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1397         if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1398       }
1399
1400       if (!axis_ref.isEmpty())
1401       {
1402         std::vector<StdString> axisList = cgPtr->getAxisList();
1403         it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1404         if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1405       }
1406
1407       if (!scalar_ref.isEmpty())
1408       {
1409         std::vector<StdString> scalarList = cgPtr->getScalarList();
1410         it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1411         if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1412       }
1413     }
1414     return (domAxisScalarIds_);
1415   }
1416
1417   CVariable* CField::addVariable(const string& id)
1418   {
1419     return vVariableGroup->createChild(id);
1420   }
1421
1422   CVariableGroup* CField::addVariableGroup(const string& id)
1423   {
1424     return vVariableGroup->createChildGroup(id);
1425   }
1426
1427   void CField::sendAddAllVariables(CContextClient* client)
1428   {
1429     std::vector<CVariable*> allVar = getAllVariables();
1430     std::vector<CVariable*>::const_iterator it = allVar.begin();
1431     std::vector<CVariable*>::const_iterator itE = allVar.end();
1432
1433     for (; it != itE; ++it)
1434     {
1435       this->sendAddVariable((*it)->getId(), client);
1436       (*it)->sendAllAttributesToServer(client);
1437       (*it)->sendValue(client);
1438     }
1439   }
1440
1441   void CField::sendAddVariable(const string& id, CContextClient* client)
1442   {
1443      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1444   }
1445
1446   void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1447   {
1448      sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1449   }
1450
1451   void CField::recvAddVariable(CEventServer& event)
1452   {
1453
1454      CBufferIn* buffer = event.subEvents.begin()->buffer;
1455      string id;
1456      *buffer >> id;
1457      get(id)->recvAddVariable(*buffer);
1458   }
1459
1460   void CField::recvAddVariable(CBufferIn& buffer)
1461   {
1462      string id;
1463      buffer >> id;
1464      addVariable(id);
1465   }
1466
1467   void CField::recvAddVariableGroup(CEventServer& event)
1468   {
1469
1470      CBufferIn* buffer = event.subEvents.begin()->buffer;
1471      string id;
1472      *buffer >> id;
1473      get(id)->recvAddVariableGroup(*buffer);
1474   }
1475
1476   void CField::recvAddVariableGroup(CBufferIn& buffer)
1477   {
1478      string id;
1479      buffer >> id;
1480      addVariableGroup(id);
1481   }
1482
1483   /*!
1484    * Returns string arithmetic expression associated to the field.
1485    * \return if content is defined return content string, otherwise, if "expr" attribute is defined, return expr string.
1486    */
1487   const string& CField::getExpression(void)
1488   {
1489     if (!expr.isEmpty() && content.empty())
1490     {
1491       content = expr;
1492       expr.reset();
1493     }
1494
1495     return content;
1496   }
1497
1498   bool CField::hasExpression(void) const
1499   {
1500     return (!expr.isEmpty() || !content.empty());
1501   }
1502
1503
1504   DEFINE_REF_FUNC(Field,field)
1505} // namespace xios
Note: See TracBrowser for help on using the repository browser.