XIOS  1.0
Xml I/O Server
 Tout Classes Espaces de nommage Fichiers Fonctions Variables Définitions de type Énumérations Valeurs énumérées Amis Macros
field.cpp
Aller à la documentation de ce fichier.
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"
26 
27 namespace xios{
28 
30 
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 
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 
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  }
100 
101  //----------------------------------------------------------------
102 
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 
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  }
203 
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  }
267 
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  }
297 
299  TRY
300  {
301  if (!getRelFile()->isEmptyZone())
302  {
303  if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
304  {
306  this->incrementNStep();
307  getRelFile()->getDataOutput()->writeFieldData(CField::get(this));
308  }
309  }
310  }
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  }
354 
360  TRY
361  {
362  const CDate& currentDate = CContext::getCurrent()->getCalendar()->getCurrentDate();
363 
364  bool dataRequested = false;
365 
366  while (currentDate >= lastDataRequestedFromServer)
367  {
368  info(20) << "currentDate : " << currentDate << endl ;
369  info(20) << "lastDataRequestedFromServer : " << lastDataRequestedFromServer << endl ;
370  info(20) << "file->output_freq.getValue() : " << file->output_freq.getValue() << endl ;
371  info(20) << "lastDataRequestedFromServer + file->output_freq.getValue() : " << lastDataRequestedFromServer + file->output_freq << endl ;
372 
373  dataRequested |= sendReadDataRequest(lastDataRequestedFromServer + file->output_freq);
374  }
375 
376  return dataRequested;
377  }
379 
381  TRY
382  {
383  CBufferIn* buffer = event.subEvents.begin()->buffer;
384  StdString fieldId;
385  *buffer >> fieldId;
386  get(fieldId)->recvReadDataRequest();
387  }
388  CATCH
389 
397  TRY
398  {
399  CContext* context = CContext::getCurrent();
400  CContextClient* client = context->client;
401 
403  std::list<CMessage> msgs;
404 
405  EReadField hasData = readField();
406 
407  map<int, CArray<double,1> >::iterator it;
408  if (!grid->doGridHaveDataDistributed(client))
409  {
410  if (client->isServerLeader())
411  {
412  if (0 != recvDataSrv.numElements())
413  {
414  const std::list<int>& ranks = client->getRanksServerLeader();
415  for (std::list<int>::const_iterator itRank = ranks.begin(), itRankEnd = ranks.end(); itRank != itRankEnd; ++itRank)
416  {
417  msgs.push_back(CMessage());
418  CMessage& msg = msgs.back();
419  msg << getId();
420  switch (hasData)
421  {
422  case RF_DATA:
423  msg << getNStep() - 1 << recvDataSrv;
424  break;
425  case RF_NODATA:
426  msg << int(-2) << recvDataSrv;
427  break;
428  case RF_EOF:
429  default:
430  msg << int(-1);
431  break;
432  }
433 
434  event.push(*itRank, 1, msg);
435  }
436  }
437  client->sendEvent(event);
438  }
439  else
440  {
441  client->sendEvent(event);
442  }
443  }
444  else
445  {
446  for (map<int, CArray<size_t, 1> >::iterator it = grid->outLocalIndexStoreOnClient.begin();
447  it != grid->outLocalIndexStoreOnClient.end(); ++it)
448  {
449  CArray<size_t,1>& indexTmp = it->second;
450  CArray<double,1> tmp(indexTmp.numElements());
451  for (int idx = 0; idx < indexTmp.numElements(); ++idx)
452  {
453  tmp(idx) = recvDataSrv(indexTmp(idx));
454  }
455 
456  msgs.push_back(CMessage());
457  CMessage& msg = msgs.back();
458  msg << getId();
459  switch (hasData)
460  {
461  case RF_DATA:
462  msg << getNStep() - 1 << tmp;
463  break;
464  case RF_NODATA:
465  msg << int(-2) << tmp;
466  break;
467  case RF_EOF:
468  default:
469  msg << int(-1);
470  break;
471  }
472 
473  event.push(it->first, grid->nbReadSenders[client][it->first], msg);
474  }
475  client->sendEvent(event);
476  }
477  }
479 
486  TRY
487  {
488  CContext* context = CContext::getCurrent();
490  getRelFile()->initRead();
491  EReadField readState = RF_DATA;
492 
493  if (!getRelFile()->isEmptyZone())
494  {
495  if (grid->doGridHaveDataToWrite() || getRelFile()->type == CFile::type_attr::one_file)
496  {
497  if (0 == recvDataSrv.numElements())
498  {
499  CArray<int,1>& storeClient = grid->storeIndex_client;
500  recvDataSrv.resize(storeClient.numElements());
501  }
502 
504 
505  if (!nstepMax)
506  {
507  nstepMax = getRelFile()->getDataInput()->getFieldNbRecords(CField::get(this));
508  }
509 
510  this->incrementNStep();
511 
512  if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
513  readState = RF_EOF;
514 
515  if (RF_EOF != readState)
516  getRelFile()->getDataInput()->readFieldData(CField::get(this));
517  }
518  }
519  else
520  {
521  this->incrementNStep();
522  if (getNStep() > nstepMax && (getRelFile()->cyclic.isEmpty() || !getRelFile()->cyclic) )
523  readState = RF_EOF;
524  else
525  readState = RF_NODATA;
526 
527  if (!nstepMaxRead) // This can be a bug if we try to read field from zero time record
528  readState = RF_NODATA;
529  }
530 
531  if (!nstepMaxRead)
532  {
533  MPI_Allreduce(MPI_IN_PLACE, &nstepMax, 1, MPI_INT, MPI_MAX, context->server->intraComm);
534  nstepMaxRead = true;
535  }
536 
537  return readState;
538  }
540 
541  /*
542  Receive read data from server.
543  At the moment, this function is called in the client side.
544  In the future, this function can be called hiearachically (server n-1, server n -2, ..., client)
545  \param event event containing read data
546  */
548  TRY
549  {
550  string fieldId;
551  vector<int> ranks;
552  vector<CBufferIn*> buffers;
553 
554  list<CEventServer::SSubEvent>::iterator it;
555  for (it = event.subEvents.begin(); it != event.subEvents.end(); ++it)
556  {
557  ranks.push_back(it->rank);
558  CBufferIn* buffer = it->buffer;
559  *buffer >> fieldId;
560  buffers.push_back(buffer);
561  }
562  get(fieldId)->recvReadDataReady(ranks, buffers);
563  }
564  CATCH
565 
571  void CField::recvReadDataReady(vector<int> ranks, vector<CBufferIn*> buffers)
572  TRY
573  {
574  CContext* context = CContext::getCurrent();
575  std::map<int, CArray<double,1> > data;
576  const bool wasEOF = isEOF;
577 
578  for (int i = 0; i < ranks.size(); i++)
579  {
580  int rank = ranks[i];
581  int record;
582  *buffers[i] >> record;
583  isEOF = (record == int(-1));
584 
585  if (!isEOF)
586  *buffers[i] >> data[rank];
587  else
588  break;
589  }
590 
591  if (wasDataAlreadyReceivedFromServer)
592  lastDataReceivedFromServer = lastDataReceivedFromServer + file->output_freq;
593  else
594  {
595  lastDataReceivedFromServer = context->getCalendar()->getInitDate();
596  wasDataAlreadyReceivedFromServer = true;
597  }
598 
599  if (isEOF)
600  {
601  if (!wasEOF)
602  dateEOF = lastDataReceivedFromServer;
603 
604  serverSourceFilter->signalEndOfStream(lastDataReceivedFromServer);
605  }
606  else
607  serverSourceFilter->streamDataFromServer(lastDataReceivedFromServer, data);
608  }
610 
612  TRY
613  {
614  CContext* context = CContext::getCurrent();
615  const CDate& currentDate = context->getCalendar()->getCurrentDate();
616 
617  // Check if data previously requested has been received as expected
619  {
620  CTimer timer("CField::checkForLateDataFromServer");
621 
622  bool isDataLate;
623  do
624  {
625  const CDate nextDataDue = wasDataAlreadyReceivedFromServer ? (lastDataReceivedFromServer + file->output_freq) : context->getCalendar()->getInitDate();
626  isDataLate = (nextDataDue <= currentDate);
627 
628  if (isDataLate)
629  {
630  timer.resume();
631 
632  context->checkBuffersAndListen();
633 
634  timer.suspend();
635  }
636  }
637  while (isDataLate && timer.getCumulatedTime() < CXios::recvFieldTimeout);
638 
639  if (isDataLate)
640  ERROR("void CField::checkForLateDataFromServer(void)",
641  << "Late data at timestep = " << currentDate);
642  }
643  }
645 
647  TRY
648  {
649  mustAutoTrigger = serverSourceFilter ? serverSourceFilter->mustAutoTrigger() : false;
650  }
652 
654  TRY
655  {
656  if (mustAutoTrigger)
657  serverSourceFilter->trigger(CContext::getCurrent()->getCalendar()->getCurrentDate());
658  }
660 
661  //----------------------------------------------------------------
662 
664  TRY
665  {
666  this->file = _file;
667  hasOutputFile = true;
668  }
670 
671  //----------------------------------------------------------------
672 
673  StdString CField::GetName(void) { return StdString("field"); }
675  ENodeType CField::GetType(void) { return eField; }
676 
677  //----------------------------------------------------------------
678 
680  TRY
681  {
682  return this->grid;
683  }
684  CATCH
685 
686  //----------------------------------------------------------------
687 
689  TRY
690  {
691  return this->file;
692  }
693  CATCH
694 
695  int CField::getNStep(void) const
696  TRY
697  {
698  return this->nstep;
699  }
700  CATCH
701 
703  TRY
704  {
705  return operationTimeType;
706  }
707  CATCH
708 
709  //----------------------------------------------------------------
710 
712  TRY
713  {
714  this->nstep++;
715  }
717 
718  void CField::resetNStep(int nstep /*= 0*/)
719  TRY
720  {
721  this->nstep = nstep;
722  }
724 
726  TRY
727  {
728  this->nstepMax = 0;
729  nstepMaxRead = false;
730  }
732 
733  //----------------------------------------------------------------
734 
735  bool CField::isActive(bool atCurrentTimestep /*= false*/) const
736  TRY
737  {
738  if (clientSourceFilter)
739  return atCurrentTimestep ? clientSourceFilter->isDataExpected(CContext::getCurrent()->getCalendar()->getCurrentDate()) : true;
740  else if (storeFilter)
741  return true;
742  else if (instantDataFilter)
743  ERROR("bool CField::isActive(bool atCurrentTimestep)",
744  << "Impossible to check if field [ id = " << getId() << " ] is active as it cannot be used to receive nor send data.");
745 
746  return false;
747  }
748  CATCH
749 
750  //----------------------------------------------------------------
751 
752  bool CField::wasWritten() const
753  TRY
754  {
755  return written;
756  }
757  CATCH
758 
760  TRY
761  {
762  written = true;
763  }
765 
766  //----------------------------------------------------------------
767 
769  TRY
770  {
771  return useCompressedOutput;
772  }
773  CATCH
774 
776  TRY
777  {
778  useCompressedOutput = true;
779  }
781 
782  //----------------------------------------------------------------
783 
784  std::shared_ptr<COutputPin> CField::getInstantDataFilter()
785  TRY
786  {
787  return instantDataFilter;
788  }
790 
791  //----------------------------------------------------------------
792 
798  TRY
799  {
800  CContext* context = CContext::getCurrent();
801  if (context->hasClient && !context->hasServer)
802  {
803  if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
804  {
805  grid->addTransGridSource(getDirectFieldReference()->grid);
806  }
807  }
808  }
810 
815  TRY
816  {
817  CContext* context = CContext::getCurrent();
818  if (context->hasClient && !context->hasServer)
819  {
820  std::map<CGrid*,std::pair<bool,StdString> >& gridSrcMap = grid->getTransGridSource();
821  if (1 < gridSrcMap.size())
822  {
823  // Search for grid source
824  CGrid* gridSrc = grid;
825  CField* currField = this;
826  std::vector<CField*> hieraField;
827 
828  while (currField->hasDirectFieldReference() && (gridSrc == grid))
829  {
830  hieraField.push_back(currField);
831  CField* tmp = currField->getDirectFieldReference();
832  currField = tmp;
833  gridSrc = currField->grid;
834  }
835 
836  if (gridSrcMap.end() != gridSrcMap.find(gridSrc))
837  {
838  CGrid* gridTmp;
839  std::pair<bool,StdString> newGridDest = gridSrcMap[gridSrc];
840  if (newGridDest.first)
841  {
842  StdString newIdGridDest = newGridDest.second;
843  if (!CGrid::has(newIdGridDest))
844  {
845  ERROR("CGrid* CGrid::generateNewTransformationGridDest()",
846  << " Something wrong happened! Grid whose id " << newIdGridDest
847  << "should exist ");
848  }
849  gridTmp = CGrid::get(newIdGridDest);
850  }
851  else
852  {
853  StdString newIdGridDest = CGrid::generateId(gridSrc, grid);
854  gridTmp = CGrid::cloneGrid(newIdGridDest, grid);
855 
856  (gridSrcMap[gridSrc]).first = true;
857  (gridSrcMap[gridSrc]).second = newIdGridDest;
858  }
859 
860  // Update all descendants
861  for (std::vector<CField*>::iterator it = hieraField.begin(); it != hieraField.end(); ++it)
862  {
863  (*it)->grid = gridTmp;
864  (*it)->updateRef((*it)->grid);
865  }
866  }
867  }
868  }
869  }
871 
873  TRY
874  {
875  if (!grid_ref.isEmpty()) grid_ref.setValue(grid->getId());
876  else
877  {
878  std::vector<CAxis*> axisTmp = grid->getAxis();
879  std::vector<CDomain*> domainTmp = grid->getDomains();
880  if ((1<axisTmp.size()) || (1<domainTmp.size()))
881  ERROR("void CField::updateRef(CGrid* grid)",
882  << "More than one domain or axis is available for domain_ref/axis_ref of field " << this->getId());
883 
884  if ((!domain_ref.isEmpty()) && (domainTmp.empty()))
885  ERROR("void CField::updateRef(CGrid* grid)",
886  << "Incoherent between available domain and domain_ref of field " << this->getId());
887  if ((!axis_ref.isEmpty()) && (axisTmp.empty()))
888  ERROR("void CField::updateRef(CGrid* grid)",
889  << "Incoherent between available axis and axis_ref of field " << this->getId());
890 
891  if (!domain_ref.isEmpty()) domain_ref.setValue(domainTmp[0]->getId());
892  if (!axis_ref.isEmpty()) axis_ref.setValue(axisTmp[0]->getId());
893  }
894  }
896 
902  TRY
903  {
904  CContext* context = CContext::getCurrent();
905  bool hasClient = context->hasClient;
906  bool hasServer = context->hasServer;
907 
909  {
911 
912  if (hasClient && !hasServer)
913  {
914  solveRefInheritance(true);
915  if (hasDirectFieldReference()) getDirectFieldReference()->solveAllEnabledFieldsAndTransform();
916  }
917 
918  if (hasServer)
920 
922 
923  if (hasClient && !hasServer)
924  {
927  }
928 
929  solveGridDomainAxisRef(false);
930 
931  if (hasClient && !hasServer)
932  {
934  }
935 
936  solveGridDomainAxisRef(false);
937  }
938  }
940 
942  TRY
943  {
944  if (!isGridChecked)
945  {
946  isGridChecked = true;
947  solveCheckMaskIndex(false);
948  }
949  }
951 
953  TRY
954  {
956  // solveCheckMaskIndex(true);
957  }
959 
961  TRY
962  {
963  // solveGridDomainAxisRef(true);
964  solveCheckMaskIndex(true);
965  }
967 
968  void CField::solveOnlyReferenceEnabledField(bool doSending2Server)
969  TRY
970  {
971  CContext* context = CContext::getCurrent();
972  if (!isReferenceSolved)
973  {
974  isReferenceSolved = true;
975 
976  if (context->hasClient && !context->hasServer)
977  {
978  solveRefInheritance(true);
979  if (hasDirectFieldReference()) getDirectFieldReference()->solveOnlyReferenceEnabledField(false);
980  }
981 
982  if (context->hasServer)
983  solveServerOperation();
984 
985  solveGridReference();
986  grid->solveDomainAxisRefInheritance(true); // make it again to solve grid reading from file
987 
988  if (context->hasClient && !context->hasServer)
989  {
990  solveGenerateGrid();
991  buildGridTransformationGraph();
992  }
993  }
994  }
996 
997  void CField::solveAllReferenceEnabledField(bool doSending2Server)
998  TRY
999  {
1000  CContext* context = CContext::getCurrent();
1001  solveOnlyReferenceEnabledField(doSending2Server);
1002 
1003  if (!areAllReferenceSolved)
1004  {
1005  areAllReferenceSolved = true;
1006 
1007  if (context->hasClient && !context->hasServer)
1008  {
1009  solveRefInheritance(true);
1010  if (hasDirectFieldReference()) getDirectFieldReference()->solveAllReferenceEnabledField(false);
1011  }
1012  else if (context->hasServer)
1013  solveServerOperation();
1014 
1015  solveGridReference();
1016  }
1017 
1018  solveGridDomainAxisRef(doSending2Server);
1019 
1020  if (context->hasClient && !context->hasServer)
1021  {
1022  solveTransformedGrid();
1023  }
1024 
1025  solveCheckMaskIndex(doSending2Server);
1026  }
1028 
1029  std::map<int, StdSize> CField::getGridAttributesBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
1030  TRY
1031  {
1032  return grid->getAttributesBufferSize(client, bufferForWriting);
1033  }
1035 
1036  std::map<int, StdSize> CField::getGridDataBufferSize(CContextClient* client, bool bufferForWriting /*= "false"*/)
1037  TRY
1038  {
1039  return grid->getDataBufferSize(client, getId(), bufferForWriting);
1040  }
1042 
1044  TRY
1045  {
1046  return grid->getGlobalWrittenSize();
1047  }
1049 
1050  //----------------------------------------------------------------
1051 
1053  TRY
1054  {
1055  CContext* context = CContext::getCurrent();
1056 
1057  if (!context->hasServer || !hasOutputFile) return;
1058 
1059  if (freq_op.isEmpty())
1060  freq_op.setValue(TimeStep);
1061 
1062  if (freq_offset.isEmpty())
1063  freq_offset.setValue(NoneDu);
1064 
1065  freq_operation_srv = file->output_freq.getValue();
1066  freq_write_srv = file->output_freq.getValue();
1067 
1068  lastlast_Write_srv = context->getCalendar()->getInitDate();
1069  last_Write_srv = context->getCalendar()->getInitDate();
1070  last_operation_srv = context->getCalendar()->getInitDate();
1071 
1072  const CDuration toffset = freq_operation_srv - freq_offset.getValue() - context->getCalendar()->getTimeStep();
1074 
1075  if (operation.isEmpty())
1076  ERROR("void CField::solveServerOperation(void)",
1077  << "An operation must be defined for field \"" << getId() << "\".");
1078 
1079  std::shared_ptr<func::CFunctor> functor;
1080  CArray<double, 1> dummyData;
1081 
1082 #define DECLARE_FUNCTOR(MType, mtype) \
1083  if (operation.getValue().compare(#mtype) == 0) \
1084  { \
1085  functor.reset(new func::C##MType(dummyData)); \
1086  }
1087 
1088 #include "functor_type.conf"
1089 
1090  if (!functor)
1091  ERROR("void CField::solveServerOperation(void)",
1092  << "\"" << operation << "\" is not a valid operation.");
1093 
1094  operationTimeType = functor->timeType();
1095  }
1097 
1098  //----------------------------------------------------------------
1099 
1108  void CField::buildFilterGraph(CGarbageCollector& gc, bool enableOutput)
1109  TRY
1110  {
1111  if (!isReferenceSolvedAndTransformed) solveAllEnabledFieldsAndTransform();
1112  if (!isGridChecked) checkGridOfEnabledFields();
1113 
1114  const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1115  const double defaultValue = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1116 
1117  CContext* context = CContext::getCurrent();
1118  bool hasWriterServer = context->hasServer && !context->hasClient;
1119  bool hasIntermediateServer = context->hasServer && context->hasClient;
1120 
1121  if (hasWriterServer)
1122  {
1123  if (!instantDataFilter)
1124  instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false));
1125 
1126 
1127  // If the field data is to be read by the client or/and written to a file
1128  if (enableOutput && !storeFilter && !fileWriterFilter)
1129  {
1130  if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1131  {
1132  fileServerWriterFilter = std::shared_ptr<CFileServerWriterFilter>(new CFileServerWriterFilter(gc, this));
1133  instantDataFilter->connectOutput(fileServerWriterFilter, 0);
1134  }
1135  }
1136  }
1137  else if (hasIntermediateServer)
1138  {
1139  if (!instantDataFilter)
1140  instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, false));
1141 
1142  // If the field data is to be read by the client or/and written to a file
1143  if (enableOutput && !storeFilter && !fileWriterFilter)
1144  {
1145  if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1146  {
1147  fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1148  instantDataFilter->connectOutput(fileWriterFilter, 0);
1149  }
1150  }
1151  }
1152  else
1153  {
1154  // Start by building a filter which can provide the field's instant data
1155  if (!instantDataFilter)
1156  {
1157  // Check if we have an expression to parse
1158  if (hasExpression())
1159  {
1160  boost::scoped_ptr<IFilterExprNode> expr(parseExpr(getExpression() + '\0'));
1161  std::shared_ptr<COutputPin> filter = expr->reduce(gc, *this);
1162 
1163  // Check if a spatial transformation is needed
1164  if (!field_ref.isEmpty())
1165  {
1166  CGrid* gridRef = CField::get(field_ref)->grid;
1167 
1168  if (grid && grid != gridRef && grid->hasTransform())
1169  {
1170  std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters = CSpatialTransformFilter::buildFilterGraph(gc, gridRef, grid, detectMissingValues, defaultValue);
1171 
1172  filter->connectOutput(filters.first, 0);
1173  filter = filters.second;
1174  }
1175  }
1176 
1177  instantDataFilter = filter;
1178  }
1179  // Check if we have a reference on another field
1180  else if (!field_ref.isEmpty())
1181  instantDataFilter = getFieldReference(gc);
1182  // Check if the data is to be read from a file
1183  else if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1184  {
1185  checkTimeAttributes();
1186  instantDataFilter = serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1187  detectMissingValues, defaultValue));
1188  }
1189  else // The data might be passed from the model
1190  {
1191  if (check_if_active.isEmpty()) check_if_active = false;
1192  instantDataFilter = clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, false, true, NoneDu, false,
1193  detectMissingValues, defaultValue));
1194  }
1195  }
1196 
1197  // If the field data is to be read by the client or/and written to a file
1198  if (enableOutput && !storeFilter && !fileWriterFilter)
1199  {
1200  if (!read_access.isEmpty() && read_access)
1201  {
1202  storeFilter = std::shared_ptr<CStoreFilter>(new CStoreFilter(gc, CContext::getCurrent(), grid,
1203  detectMissingValues, defaultValue));
1204  instantDataFilter->connectOutput(storeFilter, 0);
1205  }
1206 
1207  if (file && (file->mode.isEmpty() || file->mode == CFile::mode_attr::write))
1208  {
1209  fileWriterFilter = std::shared_ptr<CFileWriterFilter>(new CFileWriterFilter(gc, this));
1210  getTemporalDataFilter(gc, file->output_freq)->connectOutput(fileWriterFilter, 0);
1211  }
1212  }
1213  }
1214  }
1216 
1224  std::shared_ptr<COutputPin> CField::getFieldReference(CGarbageCollector& gc)
1225  TRY
1226  {
1227  if (instantDataFilter || field_ref.isEmpty())
1228  ERROR("COutputPin* CField::getFieldReference(CGarbageCollector& gc)",
1229  "Impossible to get the field reference for a field which has already been parsed or which does not have a field_ref.");
1230 
1231  CField* fieldRef = CField::get(field_ref);
1232  fieldRef->buildFilterGraph(gc, false);
1233 
1234  std::pair<std::shared_ptr<CFilter>, std::shared_ptr<CFilter> > filters;
1235  // Check if a spatial transformation is needed
1236  if (grid && grid != fieldRef->grid && grid->hasTransform())
1237  {
1238  bool hasMissingValue = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1239  double defaultValue = hasMissingValue ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1240  filters = CSpatialTransformFilter::buildFilterGraph(gc, fieldRef->grid, grid, hasMissingValue, defaultValue);
1241  }
1242  else
1243  filters.first = filters.second = std::shared_ptr<CFilter>(new CPassThroughFilter(gc));
1244 
1245  fieldRef->getInstantDataFilter()->connectOutput(filters.first, 0);
1246 
1247  return filters.second;
1248  }
1250 
1260  std::shared_ptr<COutputPin> CField::getSelfReference(CGarbageCollector& gc)
1261  TRY
1262  {
1263  if (instantDataFilter || !hasExpression())
1264  ERROR("COutputPin* CField::getSelfReference(CGarbageCollector& gc)",
1265  "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1266 
1267  if (!selfReferenceFilter)
1268  {
1269  const bool detectMissingValues = (!detect_missing_value.isEmpty() && !default_value.isEmpty() && detect_missing_value == true);
1270  const double defaultValue = detectMissingValues ? default_value : (!default_value.isEmpty() ? default_value : 0.0);
1271 
1272  if (file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read)
1273  {
1274  if (!serverSourceFilter)
1275  {
1276  checkTimeAttributes();
1277  serverSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, false, freq_offset, true,
1278  detectMissingValues, defaultValue));
1279  }
1280 
1281  selfReferenceFilter = serverSourceFilter;
1282  }
1283  else if (!field_ref.isEmpty())
1284  {
1285  CField* fieldRef = CField::get(field_ref);
1286  fieldRef->buildFilterGraph(gc, false);
1287  selfReferenceFilter = fieldRef->getInstantDataFilter();
1288  }
1289  else
1290  {
1291  if (!clientSourceFilter)
1292  {
1293  if (check_if_active.isEmpty()) check_if_active = false;
1294  clientSourceFilter = std::shared_ptr<CSourceFilter>(new CSourceFilter(gc, grid, true, true, NoneDu, false,
1295  detectMissingValues, defaultValue));
1296  }
1297 
1298  selfReferenceFilter = clientSourceFilter;
1299  }
1300  }
1301 
1302  return selfReferenceFilter;
1303  }
1305 
1315  std::shared_ptr<COutputPin> CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1316  TRY
1317  {
1318  std::map<CDuration, std::shared_ptr<COutputPin> >::iterator it = temporalDataFilters.find(outFreq);
1319 
1320  if (it == temporalDataFilters.end())
1321  {
1322  if (operation.isEmpty())
1323  ERROR("void CField::getTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1324  << "An operation must be defined for field \"" << getId() << "\".");
1325 
1326  checkTimeAttributes(&outFreq);
1327 
1328  const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1329  std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1330  CContext::getCurrent()->getCalendar()->getInitDate(),
1331  freq_op, freq_offset, outFreq, detectMissingValues));
1332 
1333  instantDataFilter->connectOutput(temporalFilter, 0);
1334 
1335  it = temporalDataFilters.insert(std::make_pair(outFreq, temporalFilter)).first;
1336  }
1337 
1338  return it->second;
1339  }
1341 
1351  std::shared_ptr<COutputPin> CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)
1352  TRY
1353  {
1354  if (instantDataFilter || !hasExpression())
1355  ERROR("COutputPin* CField::getSelfTemporalDataFilter(CGarbageCollector& gc)",
1356  "Impossible to add a self reference to a field which has already been parsed or which does not have an expression.");
1357 
1358  if (!selfReferenceFilter) getSelfReference(gc) ;
1359 
1360  if (serverSourceFilter || clientSourceFilter)
1361  {
1362  if (operation.isEmpty())
1363  ERROR("void CField::getSelfTemporalDataFilter(CGarbageCollector& gc, CDuration outFreq)",
1364  << "An operation must be defined for field \"" << getId() << "\".");
1365 
1366  checkTimeAttributes(&outFreq);
1367 
1368  const bool detectMissingValues = (!detect_missing_value.isEmpty() && detect_missing_value == true);
1369  std::shared_ptr<CTemporalFilter> temporalFilter(new CTemporalFilter(gc, operation,
1370  CContext::getCurrent()->getCalendar()->getInitDate(),
1371  freq_op, freq_offset, outFreq, detectMissingValues));
1372 
1373  selfReferenceFilter->connectOutput(temporalFilter, 0);
1374  return temporalFilter ;
1375  }
1376  else if (!field_ref.isEmpty())
1377  {
1378  CField* fieldRef = CField::get(field_ref);
1379  fieldRef->buildFilterGraph(gc, false);
1380  return fieldRef->getTemporalDataFilter(gc, outFreq) ;
1381  }
1382  }
1384 
1385  //----------------------------------------------------------------
1386 /*
1387  void CField::fromBinary(StdIStream& is)
1388  {
1389  SuperClass::fromBinary(is);
1390 #define CLEAR_ATT(name_)\
1391  SuperClassAttribute::operator[](#name_)->reset()
1392 
1393  CLEAR_ATT(domain_ref);
1394  CLEAR_ATT(axis_ref);
1395 #undef CLEAR_ATT
1396 
1397  }
1398 */
1399  //----------------------------------------------------------------
1400 
1402  TRY
1403  {
1404  if (grid_ref.isEmpty() && domain_ref.isEmpty() && axis_ref.isEmpty() && scalar_ref.isEmpty())
1405  {
1406  ERROR("CField::solveGridReference(void)",
1407  << "A grid must be defined for field '" << getFieldOutputName() << "' .");
1408  }
1409  else if (!grid_ref.isEmpty() && (!domain_ref.isEmpty() || !axis_ref.isEmpty() || !scalar_ref.isEmpty()))
1410  {
1411  ERROR("CField::solveGridReference(void)",
1412  << "Field '" << getFieldOutputName() << "' has both a grid and a domain/axis/scalar." << std::endl
1413  << "Please define either 'grid_ref' or 'domain_ref'/'axis_ref'/'scalar_ref'.");
1414  }
1415 
1416  if (grid_ref.isEmpty())
1417  {
1418  std::vector<CDomain*> vecDom;
1419  std::vector<CAxis*> vecAxis;
1420  std::vector<CScalar*> vecScalar;
1421  std::vector<int> axisDomainOrderTmp;
1422 
1423  std::vector<CDomain*> vecDomRef;
1424  std::vector<CAxis*> vecAxisRef;
1425  std::vector<CScalar*> vecScalarRef;
1426 
1427 
1428  if (!domain_ref.isEmpty())
1429  {
1430  StdString tmp = domain_ref.getValue();
1431  if (CDomain::has(domain_ref))
1432  {
1433  vecDom.push_back(CDomain::get(domain_ref));
1434  vecDomRef.push_back(CDomain::createDomain());
1435  vecDomRef.back()->domain_ref=domain_ref;
1436  axisDomainOrderTmp.push_back(2);
1437  }
1438  else ERROR("CField::solveGridReference(void)",
1439  << "Invalid reference to domain '" << domain_ref.getValue() << "'.");
1440  }
1441 
1442  if (!axis_ref.isEmpty())
1443  {
1444  if (CAxis::has(axis_ref))
1445  {
1446  vecAxis.push_back(CAxis::get(axis_ref));
1447  vecAxisRef.push_back(CAxis::createAxis());
1448  vecAxisRef.back()->axis_ref=axis_ref;
1449  axisDomainOrderTmp.push_back(1);
1450  }
1451  else ERROR("CField::solveGridReference(void)",
1452  << "Invalid reference to axis '" << axis_ref.getValue() << "'.");
1453  }
1454 
1455  if (!scalar_ref.isEmpty())
1456  {
1457  if (CScalar::has(scalar_ref))
1458  {
1459  vecScalar.push_back(CScalar::get(scalar_ref));
1460  vecScalarRef.push_back(CScalar::createScalar());
1461  vecScalarRef.back()->scalar_ref=scalar_ref;
1462  axisDomainOrderTmp.push_back(0);
1463  }
1464  else ERROR("CField::solveGridReference(void)",
1465  << "Invalid reference to scalar '" << scalar_ref.getValue() << "'.");
1466  }
1467 
1468  CArray<int,1> axisDomainOrder(axisDomainOrderTmp.size());
1469  for (int idx = 0; idx < axisDomainOrderTmp.size(); ++idx)
1470  {
1471  axisDomainOrder(idx) = axisDomainOrderTmp[idx];
1472  }
1473 
1474  // Warning: the gridId shouldn't be set as the grid_ref since it could be inherited
1475  StdString gridId = CGrid::generateId(vecDom, vecAxis, vecScalar,axisDomainOrder);
1476  if (CGrid::has(gridId)) this->grid = CGrid::get(gridId);
1477  else this->grid = CGrid::createGrid(gridId, vecDomRef, vecAxisRef, vecScalarRef,axisDomainOrder);
1478  }
1479  else
1480  {
1481  if (CGrid::has(grid_ref)) this->grid = CGrid::get(grid_ref);
1482  else ERROR("CField::solveGridReference(void)",
1483  << "Invalid reference to grid '" << grid_ref.getValue() << "'.");
1484  }
1485  }
1487 
1489  TRY
1490  {
1491  grid->solveDomainAxisRef(checkAtt);
1492  }
1494 
1495  void CField::solveCheckMaskIndex(bool doSendingIndex)
1496  TRY
1497  {
1498  grid->checkMaskIndex(doSendingIndex);
1499  }
1501 
1503  TRY
1504  {
1505  if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1506  {
1507  std::vector<CGrid*> grids;
1508  // Source grid
1509  grids.push_back(getDirectFieldReference()->grid);
1510  // Intermediate grids
1511  if (!grid_path.isEmpty())
1512  {
1513  std::string gridId;
1514  size_t start = 0, end;
1515 
1516  do
1517  {
1518  end = grid_path.getValue().find(',', start);
1519  if (end != std::string::npos)
1520  {
1521  gridId = grid_path.getValue().substr(start, end - start);
1522  start = end + 1;
1523  }
1524  else
1525  gridId = grid_path.getValue().substr(start);
1526 
1527  if (!CGrid::has(gridId))
1528  ERROR("void CField::solveTransformedGrid()",
1529  << "Invalid grid_path, the grid '" << gridId << "' does not exist.");
1530 
1531  grids.push_back(CGrid::get(gridId));
1532  }
1533  while (end != std::string::npos);
1534  }
1535  // Destination grid
1536  grids.push_back(grid);
1537 
1538  for (size_t i = 0, count = grids.size() - 1; i < count; ++i)
1539  {
1540  CGrid *gridSrc = grids[i];
1541  CGrid *gridDest = grids[i + 1];
1542  if (!gridDest->isTransformed())
1543  gridDest->transformGrid(gridSrc);
1544  }
1545  }
1546  else if (grid && grid->hasTransform() && !grid->isTransformed())
1547  {
1548  // Temporarily deactivate the self-transformation of grid
1549  // grid->transformGrid(grid);
1550  }
1551  }
1553 
1555  TRY
1556  {
1557  if (grid && !grid->isTransformed() && hasDirectFieldReference() && grid != getDirectFieldReference()->grid)
1558  grid->completeGrid(getDirectFieldReference()->grid);
1559  else
1560  grid->completeGrid();
1561  }
1563 
1565  TRY
1566  {
1567  grid->solveDomainAxisRef(false);
1569  }
1571 
1573 
1574  template <>
1576  TRY
1577  {
1578  if (this->group_ref.isEmpty()) return;
1579  StdString gref = this->group_ref.getValue();
1580 
1581  if (!CFieldGroup::has(gref))
1582  ERROR("CGroupTemplate<CField, CFieldGroup, CFieldAttributes>::solveRefInheritance(void)",
1583  << "[ gref = " << gref << "]"
1584  << " invalid group name !");
1585 
1586  CFieldGroup* group = CFieldGroup::get(gref);
1587  CFieldGroup* owner = CFieldGroup::get(boost::polymorphic_downcast<CFieldGroup*>(this));
1588  owner->setAttributes(group); // inherite of attributes of group reference
1589 
1590  std::vector<CField*> allChildren = group->getAllChildren();
1591  std::vector<CField*>::iterator it = allChildren.begin(), end = allChildren.end();
1592 
1593  for (; it != end; it++)
1594  {
1595  CField* child = *it;
1596  if (child->hasId()) owner->createChild()->field_ref.setValue(child->getId());
1597 
1598  }
1599  }
1601 
1602  void CField::scaleFactorAddOffset(double scaleFactor, double addOffset)
1603  TRY
1604  {
1605  recvDataSrv = (recvDataSrv - addOffset) / scaleFactor;
1606  }
1608 
1609  void CField::invertScaleFactorAddOffset(double scaleFactor, double addOffset)
1610  TRY
1611  {
1612  recvDataSrv = recvDataSrv * scaleFactor + addOffset;
1613  }
1615 
1617  TRY
1618  {
1619  CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1620  CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1621  for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1622  {
1623  fieldOut(outIndexServer(idx)) = recvDataSrv(outIndexClient(idx));
1624  }
1625  }
1627 
1629  TRY
1630  {
1631  CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1632  CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1633  for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1634  {
1635  recvDataSrv(outIndexClient(idx)) = fieldIn(outIndexServer(idx));
1636  }
1637  }
1639 
1641  TRY
1642  {
1643  CArray<size_t,1>& outIndexClient = grid->localIndexToWriteOnClient;
1644  CArray<size_t,1>& outIndexServer = grid->localIndexToWriteOnServer;
1645  for (size_t idx = 0; idx < outIndexServer.numElements(); ++idx)
1646  {
1647  fieldOut((idx)) = recvDataSrv(outIndexClient(idx));
1648  }
1649  }
1651 
1653 
1655  TRY
1656  {
1657  string newContent ;
1658  SuperClass::parse(node);
1659  if (node.goToChildElement())
1660  {
1661  do
1662  {
1663  if (node.getElementName() == "variable" || node.getElementName() == "variable_group") this->getVirtualVariableGroup()->parseChild(node);
1664  else if (node.getElementName() == "expr") if (node.getContent(newContent)) content+=newContent ;
1665  } while (node.goToNextElement());
1666  node.goToParentElement();
1667  }
1668  if (node.getContent(newContent)) content=newContent ;
1669  }
1671 
1677  const std::vector<StdString>& CField::getRefDomainAxisIds()
1678  TRY
1679  {
1680  CGrid* cgPtr = getRelGrid();
1681  if (NULL != cgPtr)
1682  {
1683  std::vector<StdString>::iterator it;
1684  if (!domain_ref.isEmpty())
1685  {
1686  std::vector<StdString> domainList = cgPtr->getDomainList();
1687  it = std::find(domainList.begin(), domainList.end(), domain_ref.getValue());
1688  if (domainList.end() != it) domAxisScalarIds_[0] = *it;
1689  }
1690 
1691  if (!axis_ref.isEmpty())
1692  {
1693  std::vector<StdString> axisList = cgPtr->getAxisList();
1694  it = std::find(axisList.begin(), axisList.end(), axis_ref.getValue());
1695  if (axisList.end() != it) domAxisScalarIds_[1] = *it;
1696  }
1697 
1698  if (!scalar_ref.isEmpty())
1699  {
1700  std::vector<StdString> scalarList = cgPtr->getScalarList();
1701  it = std::find(scalarList.begin(), scalarList.end(), scalar_ref.getValue());
1702  if (scalarList.end() != it) domAxisScalarIds_[2] = *it;
1703  }
1704  }
1705  return (domAxisScalarIds_);
1706  }
1708 
1709  CVariable* CField::addVariable(const string& id)
1710  TRY
1711  {
1712  return vVariableGroup->createChild(id);
1713  }
1714  CATCH
1715 
1716  CVariableGroup* CField::addVariableGroup(const string& id)
1717  TRY
1718  {
1719  return vVariableGroup->createChildGroup(id);
1720  }
1721  CATCH
1722 
1724  TRY
1725  {
1726  CContext* context = CContext::getCurrent();
1727  client = contextClient;
1728  if (context->hasClient)
1729  {
1730  // A grid is sent by a client (both for read or write) or by primary server (write only)
1731  if (context->hasServer)
1732  {
1733  if (file->mode.isEmpty() || (!file->mode.isEmpty() && file->mode == CFile::mode_attr::write))
1734  grid->setContextClient(contextClient);
1735  }
1736  else
1737  grid->setContextClient(contextClient);
1738  }
1739  }
1741 
1743  TRY
1744  {
1745  return client;
1746  }
1747  CATCH
1748 
1750  TRY
1751  {
1752  std::vector<CVariable*> allVar = getAllVariables();
1753  std::vector<CVariable*>::const_iterator it = allVar.begin();
1754  std::vector<CVariable*>::const_iterator itE = allVar.end();
1755 
1756  for (; it != itE; ++it)
1757  {
1758  this->sendAddVariable((*it)->getId(), client);
1759  (*it)->sendAllAttributesToServer(client);
1760  (*it)->sendValue(client);
1761  }
1762  }
1764 
1771  TRY
1772  {
1773  if (grid_ref.isEmpty())
1774  {
1775  grid_ref=grid->getId() ;
1776  SuperClass::sendAllAttributesToServer(client) ;
1777  grid_ref.reset();
1778  }
1779  else SuperClass::sendAllAttributesToServer(client) ;
1780  }
1782 
1783  void CField::sendAddVariable(const string& id, CContextClient* client)
1784  TRY
1785  {
1786  sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE, client);
1787  }
1789 
1790  void CField::sendAddVariableGroup(const string& id, CContextClient* client)
1791  TRY
1792  {
1793  sendAddItem(id, (int)EVENT_ID_ADD_VARIABLE_GROUP, client);
1794  }
1796 
1798  TRY
1799  {
1800 
1801  CBufferIn* buffer = event.subEvents.begin()->buffer;
1802  string id;
1803  *buffer >> id;
1804  get(id)->recvAddVariable(*buffer);
1805  }
1806  CATCH
1807 
1809  TRY
1810  {
1811  string id;
1812  buffer >> id;
1813  addVariable(id);
1814  }
1816 
1818  TRY
1819  {
1820 
1821  CBufferIn* buffer = event.subEvents.begin()->buffer;
1822  string id;
1823  *buffer >> id;
1824  get(id)->recvAddVariableGroup(*buffer);
1825  }
1826  CATCH
1827 
1829  TRY
1830  {
1831  string id;
1832  buffer >> id;
1833  addVariableGroup(id);
1834  }
1836 
1841  TRY
1842  {
1843  bool isFieldRead = file && !file->mode.isEmpty() && file->mode == CFile::mode_attr::read;
1844  bool isFieldWrite = file && ( file->mode.isEmpty() || file->mode == CFile::mode_attr::write);
1845  if (isFieldRead && !(operation.getValue() == "instant" || operation.getValue() == "once") )
1846  ERROR("void CField::checkTimeAttributes(void)",
1847  << "Unsupported operation for field '" << getFieldOutputName() << "'." << std::endl
1848  << "Currently only \"instant\" is supported for fields read from file.")
1849 
1850  if (freq_op.isEmpty())
1851  {
1852  if (operation.getValue() == "instant")
1853  {
1854  if (isFieldRead || isFieldWrite) freq_op.setValue(file->output_freq.getValue());
1855  else freq_op=*freqOp ;
1856  }
1857  else
1858  freq_op.setValue(TimeStep);
1859  }
1860  if (freq_offset.isEmpty())
1861  freq_offset.setValue(isFieldRead ? NoneDu : (freq_op.getValue() - TimeStep));
1862  }
1864 
1869  const string& CField::getExpression(void)
1870  TRY
1871  {
1872  if (!expr.isEmpty() && content.empty())
1873  {
1874  content = expr;
1875  expr.reset();
1876  }
1877 
1878  return content;
1879  }
1881 
1882  bool CField::hasExpression(void) const
1883  TRY
1884  {
1885  return (!expr.isEmpty() || !content.empty());
1886  }
1887  CATCH
1888 
1889  bool CField::hasGridMask(void) const
1890  TRY
1891  {
1892  return (this->grid->hasMask());
1893  }
1894  CATCH
1895 
1896  DEFINE_REF_FUNC(Field,field)
1897 } // namespace xios
#define CATCH_DUMP_ATTR
Definition: exception.hpp:156
std::map< int, StdSize > getGridAttributesBufferSize(CContextClient *client, bool bufferForWriting=false)
Definition: field.cpp:1029
void solveTransformedGrid()
Definition: field.cpp:1502
A simple pass-through filter with one input slot.
void checkWriteFile(void)
Definition: file.cpp:319
void buildFilterGraph(CGarbageCollector &gc, bool enableOutput)
Constructs the graph filter for the field, enabling or not the data output.
Definition: field.cpp:1108
bool hasOutputFile
Definition: field.hpp:111
void sendEvent(CEventClient &event)
In case of attached mode, the current context must be reset to context for client.
std::shared_ptr< CDataOutput > getDataOutput(void) const
Get data writer object.
Definition: file.cpp:68
#define DEFINE_REF_FUNC(type, name_)
static ENodeType GetType(void)
Definition: field.cpp:675
void inputField(CArray< double, 3 > &fieldOut)
void autoTriggerIfNeeded(void)
Definition: field.cpp:653
int count
Definition: tracer.cpp:26
const CDuration TimeStep(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)
Definition: duration.hpp:47
void solveDomainAxisRef(bool areAttributesChecked)
Definition: grid.cpp:276
CFile * getRelFile(void) const
Definition: field.cpp:688
CLog info("info")
Definition: log.hpp:55
EReadField readField(void)
Read field from a file.
Definition: field.cpp:485
A generic temporal filter with one input slot wrapping any type of temporal operation.
CDuration freq_operation_srv
Definition: field.hpp:220
std::shared_ptr< COutputPin > getTemporalDataFilter(CGarbageCollector &gc, CDuration outFreq)
Returns the temporal filter corresponding to the field&#39;s temporal operation for the specified operati...
Definition: field.cpp:1315
void outputField(CArray< double, 3 > &fieldOut)
bool mustAutoTrigger
Definition: field.hpp:228
void parse(xml::CXMLNode &node)
Definition: field.cpp:1654
static bool has(const string &id)
#define TRY
Definition: exception.hpp:154
std::shared_ptr< COutputPin > getFieldReference(CGarbageCollector &gc)
Returns the filter needed to handle the field reference.
Definition: field.cpp:1224
void setRelFile(CFile *_file)
Mutateur ///.
Definition: field.cpp:663
static CAxis * createAxis()
Definition: axis.cpp:261
std::shared_ptr< CCalendar > getCalendar(void) const
Accesseurs ///.
Definition: context.cpp:81
double getCumulatedTime(void)
Definition: timer.cpp:49
CContextServer * server
Concrete context server.
Definition: context.hpp:250
IFilterExprNode * parseExpr(const std::string &strExpr)
bool written
Definition: field.hpp:222
static void recvReadDataReady(CEventServer &event)
Definition: field.cpp:547
void solveOnlyReferenceEnabledField(bool doSending2Server)
Definition: field.cpp:968
const CDuration NoneDu(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
Definition: duration.hpp:47
bool useCompressedOutput
Definition: field.hpp:239
std::shared_ptr< COutputPin > getInstantDataFilter()
Definition: field.cpp:784
void outputCompressedField(CArray< double, 1 > &fieldOut)
Definition: field.cpp:1640
A terminal filter which transmits the packets it receives to a field for writting in a file...
void completeGrid(CGrid *transformGridSrc=0)
Complete all the necessary (and lacking) attributes of a grid This function is similar to gridTransfo...
Definition: grid.cpp:2324
void checkReadFile(void)
Definition: file.cpp:345
static StdString GetName(void)
Accesseurs statiques ///.
Definition: field.cpp:673
CField(void)
Constructeurs ///.
Definition: field.cpp:31
static double recvFieldTimeout
Time to wait for data before issuing an error when receiving a field.
Definition: cxios.hpp:56
std::map< CContextClient *, std::map< int, int > > nbReadSenders
Definition: grid.hpp:217
void suspend(void)
Definition: timer.cpp:23
static CGrid * cloneGrid(const StdString &idNewGrid, CGrid *gridSrc)
Definition: grid.cpp:1184
std::string StdString
Definition: xios_spl.hpp:48
const std::list< int > & getRanksServerLeader(void) const
Get leading server in the group of connected server.
#define xios(arg)
const StdString & getId(void) const
Accesseurs ///.
Definition: object.cpp:26
void setWritten()
Definition: field.cpp:759
CVariableGroup * addVariableGroup(const string &id="")
Definition: field.cpp:1716
void setContextClient(CContextClient *newContextClient)
Definition: field.cpp:1723
CGrid * getRelGrid(void) const
Accesseurs ///.
Definition: field.cpp:679
A terminal filter which stores all the packets it receives.
////////////////////// Déclarations ////////////////////// ///
void invertScaleFactorAddOffset(double scaleFactor, double addOffset)
Definition: field.cpp:1609
bool doGridHaveDataToWrite()
Verify whether one server need to write data There are some cases on which one server has nodata to w...
Definition: grid.cpp:1937
void generateNewTransformationGridDest()
Generate a new grid destination if there are more than one grid source pointing to a same grid destin...
Definition: field.cpp:814
void computeWrittenIndex()
Compute the index to for write data into a file.
Definition: grid.cpp:623
void solveDomainAxisBaseRef()
Definition: grid.cpp:292
void solveGenerateGrid()
Definition: field.cpp:1554
A terminal filter which writes the packets it receives in a file.
virtual void solveDescInheritance(bool apply, const CAttributeMap *const parent=0)
Traitements ///.
Definition: field.cpp:93
void setUseCompressedOutput()
Definition: field.cpp:775
std::map< int, StdSize > getGridDataBufferSize(CContextClient *client, bool bufferForWriting=false)
Definition: field.cpp:1036
void solveServerOperation(void)
Definition: field.cpp:1052
void solveAllReferenceEnabledField(bool doSending2Server)
Definition: field.cpp:997
virtual ~CField(void)
Destructeur ///.
Definition: field.cpp:67
bool sendReadDataRequestIfNeeded(void)
Send request new data read from file if need be, that is the current data is out-of-date.
Definition: field.cpp:359
void solveGridDomainAxisBaseRef()
Definition: field.cpp:1564
static StdString GetDefName(void)
Definition: field.cpp:674
bool isTransformed()
Definition: grid.cpp:2284
void checkIfMustAutoTrigger(void)
Definition: field.cpp:646
CDate lastDataRequestedFromServer
Definition: field.hpp:226
static void recvUpdateData(CEventServer &event)
Definition: field.cpp:204
void sendAddAllVariables(CContextClient *client)
Definition: field.cpp:1749
vector< CVariable * > getAllVariables(void) const
Definition: field.cpp:86
void resetNStepMax()
Definition: field.cpp:725
bool hasTransform()
Definition: grid.cpp:2389
void sendGridComponentOfEnabledFields()
Definition: field.cpp:952
CATCH CScalarAlgorithmReduceScalar::CScalarAlgorithmReduceScalar(CScalar *scalarDestination, CScalar *scalarSource, CReduceScalarToScalar *algo ERROR)("CScalarAlgorithmReduceScalar::CScalarAlgorithmReduceScalar(CScalar* scalarDestination, CScalar* scalarSource, CReduceScalarToScalar* algo)",<< "Operation must be defined."<< "Scalar source "<< scalarSource->getId()<< std::endl<< "Scalar destination "<< scalarDestination->getId())
std::shared_ptr< COutputPin > getSelfReference(CGarbageCollector &gc)
Returns the filter needed to handle a self reference in the field&#39;s expression.
Definition: field.cpp:1260
A context can be both on client and on server side.
std::vector< StdString > getScalarList()
Get list of id of scalar.
Definition: grid.cpp:2642
////////////////////// Déclarations ////////////////////// ///
void writeUpdateData(const CArray< double, 1 > &data)
Definition: field.cpp:268
void push(int rank, int nbSender, CMessage &msg)
CFile * file
Definition: field.hpp:218
void checkForLateDataFromServer(void)
Definition: field.cpp:611
CContextClient * getContextClient()
Definition: field.cpp:1742
void setVirtualVariableGroup(CVariableGroup *newVVariableGroup)
Definition: field.cpp:72
CDuration freq_write_srv
Definition: field.hpp:220
CDate last_Write_srv
Definition: field.hpp:225
int getNStep(void) const
Definition: field.cpp:695
std::map< CGrid *, std::pair< bool, StdString > > & getTransGridSource()
Definition: grid.cpp:2313
std::shared_ptr< COutputPin > instantDataFilter
The output pin of the filter providing the instant data for the field.
Definition: field.hpp:262
void writeField(void)
Definition: field.cpp:298
const std::vector< StdString > & getRefDomainAxisIds()
This function retrieves Id of corresponding domain_ref and axis_ref (if any) of a field...
Definition: field.cpp:1677
void sendGridOfEnabledFields()
Definition: field.cpp:960
void sendUpdateData(const CArray< double, 1 > &data)
Definition: field.cpp:144
bool hasGridMask(void) const
Definition: field.cpp:1889
void solveGridReference(void)
Traitements ///.
Definition: field.cpp:1401
static bool dispatchEvent(CEventServer &event)
Definition: field.cpp:103
map< int, CArray< size_t, 1 > > outLocalIndexStoreOnClient
Definition: grid.hpp:235
bool wasDataRequestedFromServer
Definition: field.hpp:227
bool hasMask(void) const
Definition: grid.cpp:366
string content
Definition: field.hpp:236
void initRead(void)
Initialize a file in order to write into it.
Definition: file.cpp:280
int serverSize
Size of server group.
bool wasWritten() const
Definition: field.cpp:752
CGrid * grid
Definition: field.hpp:217
bool wasDataAlreadyReceivedFromServer
Definition: field.hpp:227
static const xios::CCalendar & getCalendar(const std::string &idFunc)
Definition: icdate.cpp:23
bool sendReadDataRequest(const CDate &tsDataRequested)
Definition: field.cpp:320
bool nstepMaxRead
Definition: field.hpp:255
static CGrid * createGrid(CDomain *domain)
Instanciateurs Statiques ///.
Definition: grid.cpp:1101
CArray< double, 1 > recvDataSrv
Definition: field.hpp:233
int nstepMax
Definition: field.hpp:223
bool hasId(void) const
Tests ///.
Definition: object.cpp:41
void resize(int extent)
Definition: array_new.hpp:320
void buildGridTransformationGraph()
Build up graph of grids which plays role of destination and source in grid transformation This functi...
Definition: field.cpp:797
void resume(void)
Definition: timer.cpp:33
CArray< int, 1 > storeIndex_client
Definition: grid.hpp:208
void checkTimeAttributes(CDuration *freqOp=NULL)
Vérifications ///.
Definition: field.cpp:1840
CContextClient * client
Definition: field.hpp:249
static StdString generateId(const std::vector< CDomain * > &domains, const std::vector< CAxis * > &axis, const std::vector< CScalar * > &scalars, const CArray< int, 1 > &axisDomainOrder=CArray< int, 1 >())
Definition: grid.cpp:1227
void checkGridOfEnabledFields()
Definition: field.cpp:941
CVariableGroup * vVariableGroup
Propriétés privées ///.
Definition: field.hpp:215
void transformGrid(CGrid *transformGridSrc)
Definition: grid.cpp:2360
bool isReferenceSolvedAndTransformed
Definition: field.hpp:253
////////////////////// Déclarations ////////////////////// ///
Definition: instant.hpp:13
void resetNStep(int nstep=0)
Definition: field.cpp:718
enum xios::_node_type ENodeType
////////////////////// Définitions ////////////////////// ///
static std::pair< std::shared_ptr< CSpatialTransformFilter >, std::shared_ptr< CSpatialTransformFilter > > buildFilterGraph(CGarbageCollector &gc, CGrid *srcGrid, CGrid *destGrid, bool hasMissingValue, double defaultValue)
Builds the filter graph needed to transform the specified source grid into the specified destination ...
void scaleFactorAddOffset(double scaleFactor, double addOffset)
Definition: field.cpp:1602
CDate lastlast_Write_srv
Definition: field.hpp:225
void incrementNStep(void)
Definition: field.cpp:711
void sendAddVariable(const string &id, CContextClient *client)
Definition: field.cpp:1783
static CTimer & get(std::string name)
Definition: timer.cpp:54
void addTransGridSource(CGrid *gridSrc)
Definition: grid.cpp:2305
CDate lastDataReceivedFromServer
Definition: field.hpp:226
void updateRef(CGrid *grid)
Definition: field.cpp:872
bool hasExpression(void) const
Definition: field.cpp:1882
func::CFunctor::ETimeType getOperationTimeType() const
Definition: field.cpp:702
CVariable * addVariable(const string &id="")
Definition: field.cpp:1709
void recvReadDataRequest(void)
Receive data request sent from client and process it Every time server receives this request...
Definition: field.cpp:396
static void recvAddVariable(CEventServer &event)
Definition: field.cpp:1797
const string & getExpression(void)
Returns string arithmetic expression associated to the field.
Definition: field.cpp:1869
std::vector< StdString > domAxisScalarIds_
Definition: field.hpp:238
void solveAllEnabledFieldsAndTransform()
Solve reference of all enabled fields even the source fields .
Definition: field.cpp:901
bool doGridHaveDataDistributed(CContextClient *client=0)
Definition: grid.cpp:2004
A basic garbage collector which ensures no old packets linger in the filter graph.
#define CATCH
Definition: exception.hpp:155
std::vector< StdString > getAxisList()
Get list of id of axis.
Definition: grid.cpp:2630
std::shared_ptr< COutputPin > getSelfTemporalDataFilter(CGarbageCollector &gc, CDuration outFreq)
Returns the temporal filter corresponding to the field&#39;s temporal operation for the specified operati...
Definition: field.cpp:1351
ENodeType getType(void) const
Accesseurs ///.
func::CFunctor::ETimeType operationTimeType
The type of operation attached to the field.
Definition: field.hpp:259
static CScalar * createScalar()
Definition: scalar.cpp:43
A source filter is the entry point of the data in the graph of filters.
std::shared_ptr< CSourceFilter > serverSourceFilter
The source filter for data provided by the server.
Definition: field.hpp:270
void sendAddVariableGroup(const string &id, CContextClient *client)
Definition: field.cpp:1790
bool getUseCompressedOutput() const
Definition: field.cpp:768
bool isEOF
Definition: field.hpp:224
CDate last_operation_srv
Definition: field.hpp:225
void solveCheckMaskIndex(bool doSendingIndex)
Definition: field.cpp:1495
bool checkBuffersAndListen(bool enableEventsProcessing=true)
Try to send the buffers and receive possible answers.
Definition: context.cpp:422
std::vector< StdString > getDomainList()
Get list of id of domains.
Definition: grid.cpp:2618
bool isGridChecked
Definition: field.hpp:254
CVariableGroup * getVirtualVariableGroup(void) const
Definition: field.cpp:79
static void recvAddVariableGroup(CEventServer &event)
Definition: field.cpp:1817
bool isActive(bool atCurrentTimestep=false) const
Definition: field.cpp:735
static CContext * getCurrent(void)
Get current context.
Definition: context.cpp:2018
CContextClient * client
Concrete contex client.
Definition: context.hpp:251
bool isServerLeader(void) const
Check if client connects to leading server.
std::shared_ptr< CDataInput > getDataInput(void) const
Get data reader object.
Definition: file.cpp:81
static CDomain * createDomain()
Definition: domain.cpp:66
size_t getGlobalWrittenSize(void)
Definition: grid.cpp:191
size_t getGlobalWrittenSize(void)
Definition: field.cpp:1043
void solveGridDomainAxisRef(bool checkAtt)
Definition: field.cpp:1488