Version: 8.3.0
CalciumCouplingPolicy.hxx
Go to the documentation of this file.
1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 
23 // File : CalciumCouplingPolicy.hxx
24 // Author : Eric Fayolle (EDF)
25 // Module : KERNEL
26 // Id : $Id$
27 //
28 #ifndef __CALCIUM_COUPLING_POLICY__
29 #define __CALCIUM_COUPLING_POLICY__
30 
31 #include <vector>
32 #include <map>
33 
34 #include "DisplayPair.hxx"
35 #include "CouplingPolicy.hxx"
36 #include "AdjacentFunctor.hxx"
37 #include <boost/lambda/lambda.hpp>
38 #include <boost/utility/enable_if.hpp>
39 #include <boost/type_traits/is_arithmetic.hpp>
40 #include "CalciumTypes.hxx"
41 #include "CalciumException.hxx"
42 
43 //#define MYDEBUG
44 
46 
47 
48 public:
49 
50  template <typename T_TIME, typename T_TAG > class InternalDataIdContainer;
51  template <typename T_TIME, typename T_TAG > friend class InternalDataIdContainer;
52  template <typename DataManipulator,
53  class EnableIf > friend class BoundedDataIdProcessor;
54  template <typename DataManipulator > friend class EraseDataIdProcessor;
55  template <typename DataManipulator > friend class EraseDataIdBeforeOrAfterTagProcessor;
56  template <typename DataManipulator > friend class DisconnectProcessor;
57 
63 
64 private:
65 
67  size_t _storageLevel;
71  double _alpha;
72  double _deltaT;
74 
75 public:
77 
80 
81  void setStorageLevel (size_t storageLevel);
82  size_t getStorageLevel () const;
83 
86 
87  void setAlpha(double alpha);
88  double getAlpha() const ;
89 
90  void setDeltaT(double deltaT );
91  double getDeltaT() const ;
92 
97 
98  // Classe DataId rassemblant les paramètres de la méthode PORT::put
99  // qui identifient l'instance d'une donnée pour Calcium
100  // Rem : Le DataId doit pouvoir être une key dans une map stl
101  typedef double TimeType;
102  typedef long TagType;
103  typedef std::pair< TimeType , TagType > DataId;
105  typedef std::vector< DataId >::iterator iterator;
106 
107  template <typename T_TIME, typename T_TAG >
109 
110  inline TimeType getTime(const DataId &dataId) const { return dataId.first;}
111  inline TagType getTag (const DataId &dataId) const { return dataId.second;}
112 
113  template <typename DataManipulator,
114  class EnableIf = void > struct BoundedDataIdProcessor;
115  //template <typename DataManipulator> struct BoundedDataIdProcessor;
116  template <typename DataManipulator> struct EraseDataIdProcessor;
117  template <typename DataManipulator> struct EraseDataIdBeforeOrAfterTagProcessor;
118  template <typename DataManipulator> struct DisconnectProcessor;
119 
120  // Renvoie isEqual si le dataId attendu est trouvé dans storedDataIds :
121  // - l'itérateur wDataIt1 pointe alors sur ce dataId
122  // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et
123  // que la politique de couplage gére ce cas de figure
124  // - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
125  // Le container doit être associatif
126  template < typename AssocContainer >
127  bool isDataIdConveniant( AssocContainer & storedDatas,
128  const typename AssocContainer::key_type & expectedDataId,
129  bool & isEqual, bool & isBounded,
130  typename AssocContainer::iterator & wDataIt1) const;
131 
133 
134  void disconnect(bool provideLastGivenValue);
135 
136 }; //Fin de CalciumCouplingPolicy
137 
138 
139 
140 //************* DEFINITION DES METHODES ET OBJETS TEMPLATES *************//
141 
142 
143 
144 // Définition du container de DataId pour répondre au concept
145 // de mode de couplage
146 template <typename T_TIME, typename T_TAG >
147 struct CalciumCouplingPolicy::InternalDataIdContainer : public std::vector< std::pair< T_TIME,T_TAG> > {
148  typedef std::vector < DataId > DataIdVect;
149 
151  const CalciumCouplingPolicy & policy
152  ):std::vector< std::pair< T_TIME,T_TAG> >() {
153  // Ignore les paramètres qui ne sont pas en rapport avec le type de dépendance
154  switch (policy._dependencyType) {
156  this->push_back(DataId(dataId.first,0));
157  break;
159  this->push_back(DataId(0,dataId.second));
160  break;
161  default:
162  throw(CalciumException(CalciumTypes::CPIT,LOC("The dependency type must be set by setDependencyType before calling DataIdContainer contructor")));
163  break;
164  }
165  };
166 };
167 
168 
169 template <typename DataManipulator, class EnableIf >
171  BoundedDataIdProcessor(const CouplingPolicy & couplingPolicy) {};
172  template < typename Iterator, typename DataId >
173  void inline apply(typename iterator_t<Iterator>::value_type & data,
174  const DataId & dataId,
175  const Iterator & it1) const {
176  typedef typename iterator_t<Iterator>::value_type value_type;
177 #ifdef MYDEBUG
178  std::cout << "-------- Calcium Generic BoundedDataIdProcessor.apply() called " << std::endl;
179 #endif
180 
181  }
182 };
183 
184 
185 template <typename DataManipulator >
187  DataManipulator,
188  typename boost::enable_if< boost::is_float< typename DataManipulator::InnerType> >::type > {
189 
191 
193  _couplingPolicy(couplingPolicy) {};
194 
195  // Méthode implémentant l'interpolation temporelle
196  template < typename MapIterator >
197  void inline apply (typename iterator_t<MapIterator>::value_type & data,
198  const DataId & dataId, const MapIterator & it1) const {
199 
200  typedef typename iterator_t<MapIterator>::value_type value_type;
201  typedef typename DataManipulator::InnerType InnerType;
202  typedef typename DataManipulator::Type Type;
203 
204  MapIterator it2=it1; ++it2;
205  size_t dataSize1 = DataManipulator::size(it1->second);
206 #ifdef MYDEBUG
207  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Taille de donnée dataId1 : " << dataSize1 << std::endl;
208 #endif
209 
210  // Gérer dans calcium la limite de la taille du buffer donnée par
211  // l'utilisateur.
212  size_t dataSize2 = DataManipulator::size(it2->second);
213 #ifdef MYDEBUG
214  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Taille de donnée dataId2 : " << dataSize2 << std::endl;
215 #endif
216 
217  size_t dataSize = std::min< size_t >( dataSize1, dataSize2 );
218  DataId dataId2 = it2->first;
219  DataId dataId1 = it1->first;
220  TimeType t2 = dataId2.first;
221  TimeType t1 = dataId1.first;
222 #ifdef MYDEBUG
223  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t1 : " << t1 << std::endl;
224  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t2 : " << t2 << std::endl;
225 #endif
226  TimeType t = dataId.first;
227 #ifdef MYDEBUG
228  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t : " << t << std::endl;
229 #endif
230  TimeType timeDiff = t2-t1;
231 #ifdef MYDEBUG
232  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de timeDiff : " << timeDiff << std::endl;
233 #endif
234  TimeType coeff = (t2-t)/timeDiff;
235 #ifdef MYDEBUG
236  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de coeff : " << coeff << std::endl;
237 #endif
238 
239  InnerType const * const InIt1 = DataManipulator::getPointer(it1->second);
240 #ifdef MYDEBUG
241  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Données à t1 : " << std::endl;
242  std::copy(InIt1,InIt1+dataSize1,std::ostream_iterator<InnerType>(std::cout," "));
243  std::cout << std::endl;
244 #endif
245  InnerType const * const InIt2 = DataManipulator::getPointer(it2->second);
246 #ifdef MYDEBUG
247  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Données à t2 : " << std::endl;
248  std::copy(InIt2,InIt2+dataSize2,std::ostream_iterator<InnerType>(std::cout," "));
249  std::cout << std::endl;
250 #endif
251  Type dataOut = DataManipulator::create(dataSize);
252  InnerType * const OutIt = DataManipulator::getPointer(dataOut);
253 
254 #ifdef MYDEBUG
255  std::cerr << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : interpolationSchem : " << _couplingPolicy._interpolationSchem << std::endl;
256  std::cerr << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : alpha : " << _couplingPolicy._alpha << std::endl;
257  std::cerr << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : datecalschem : " << _couplingPolicy._dateCalSchem << std::endl;
258  std::cerr << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : storageLevel : " << _couplingPolicy._storageLevel << std::endl;
259 #endif
260  if ( timeDiff == 0.0 || _couplingPolicy._interpolationSchem == CalciumTypes::L0_SCHEM ) {
261  std::copy(InIt1,InIt1+dataSize,OutIt);
262  } else {
263 
264  boost::lambda::placeholder1_type _1;
265  boost::lambda::placeholder2_type _2;
266  // OLD: REM : Pour des buffers de type int
267  // OLD: le compilo indiquera warning: converting to `long int' from `Double'
268  std::transform(InIt1,InIt1+dataSize,InIt2,OutIt,
269  ( _1 - _2 ) * coeff + _2 );
270 // for(size_t i =0; i < dataSize3; ++i) {
271 // OutIt[i]=(InIt1[i] - InIt2[i]) * coeff + InIt2[i];
272 // }
273 
274  }
275 #ifdef MYDEBUG
276  std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Données calculées à t : " << std::endl;
277  std::copy(OutIt,OutIt+dataSize,std::ostream_iterator<InnerType>(std::cout," "));
278  std::cout << std::endl;
279 #endif
280  data = dataOut;
281 
282  }
283 };
284 
285 // Renvoie isEqual si le dataId attendu est trouvé dans storedDataIds :
286 // - l'itérateur wDataIt1 pointe alors sur ce dataId
287 // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et
288 // que la politique de couplage gére ce cas de figure
289 // - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
290 // Le container doit être associatif
291 template < typename AssocContainer >
292 bool CalciumCouplingPolicy::isDataIdConveniant( AssocContainer & storedDatas, const typename AssocContainer::key_type & expectedDataId,
293  bool & isEqual, bool & isBounded, typename AssocContainer::iterator & wDataIt1) const {
294 
295  // Rem : le type key_type == DataId
296  typedef typename AssocContainer::key_type key_type;
297  AdjacentFunctor< key_type > af(expectedDataId);
299  {
300 #ifdef MYDEBUG
301  std::cout << "-------- time expected : " << expectedDataId.first << std::endl;
302  std::cout << "-------- time expected corrected : " << expectedDataId.first*(1.0-_deltaT) << std::endl;
303 #endif
304  af.setMaxValue(key_type(expectedDataId.first*(1.0-_deltaT),0));
305  }
306  isBounded = false;
307 
308  // Rem 1 :
309  // L'algo adjacent_find ne peut être utilisé avec l'AdjacentPredicate
310  // - si la table contient un seul élément l'algorithme adjacent_find retourne end()
311  // que se soit l'élément attendu ou non
312  // - si la table contient deux éléments dont le dernier est celui recherché
313  // l'algorithme adjacent_find retourne end() aussi
314  // d'ou la necessité d'effectuer un find avant ou d'écrire un algorithme ad hoc
315 
316  // Rem 2 :
317  //
318  // L'algo find_if ne peut être utilisé car il recopie l'AdjacentFunctor
319  // qui ne peut alors pas mémoriser ses états précédents
320  //
321 
322  // Un codage en reverse serait plus efficace
323  typename AssocContainer::iterator prev = storedDatas.begin();
324  typename AssocContainer::iterator current = prev;
325  while ( (current != storedDatas.end()) && !af(current->first) )
326  {
327 #ifdef MYDEBUG
328  std::cerr << "------- stored time : " << current->first << std::endl;
329 #endif
330  // if ( af(current->first) ) break;
331  prev = current++;
332  }
333 
334  isEqual = af.isEqual();
335 
336  // On considère qu'il n'est pas possible d'encadrer en dépendance itérative,
337  // on se veut pas calculer d'interpolation.
338  if ( _dependencyType == CalciumTypes::TIME_DEPENDENCY) isBounded = af.isBounded();
339 
340  if ( isEqual ) wDataIt1 = current;
341  else
342  if (isBounded) wDataIt1 = prev;
343  else
344  wDataIt1 = storedDatas.end();
345 
346 #ifdef MYDEBUG
347  std::cout << "-------- isDataIdConvenient : isEqual : " << isEqual << " , isBounded " << isBounded << std::endl;
348 #endif
349 
350  return isEqual || isBounded;
351 }
352 
353 //Remove DataId before or after a given time or tag
354 template < typename DataManipulator >
356 {
358 
360  _couplingPolicy(couplingPolicy) {};
361 
362  template < typename Container,typename TimeType,typename TagType >
363  void apply(Container & storedDatas, TimeType time, TagType tag, bool before) const
364  {
365  typedef typename Container::iterator iterator;
366  typedef typename Container::reverse_iterator riterator;
367 
369  {
370  if(before)
371  {
372  iterator it=storedDatas.begin();
373  while(it != storedDatas.end() && it->first.first <= time)
374  {
375  DataManipulator::delete_data(it->second);
376  storedDatas.erase(it);
377  it=storedDatas.begin();
378  }
379  }
380  else
381  {
382  riterator it=storedDatas.rbegin();
383  while(it != storedDatas.rend() && it->first.first >= time)
384  {
385  DataManipulator::delete_data(it->second);
386  storedDatas.erase(it->first);
387  it=storedDatas.rbegin();
388  }
389  }
390  }
391  else
392  {
393  if(before)
394  {
395  iterator it=storedDatas.begin();
396  while(it != storedDatas.end() && it->first.second <= tag)
397  {
398  DataManipulator::delete_data(it->second);
399  storedDatas.erase(it);
400  it=storedDatas.begin();
401  }
402  }
403  else
404  {
405  riterator it=storedDatas.rbegin();
406  while(it != storedDatas.rend() && it->first.second >= tag)
407  {
408  DataManipulator::delete_data(it->second);
409  storedDatas.erase(it->first);
410  it=storedDatas.rbegin();
411  }
412  }
413  }
414  }
415 };
416 
417 // TODO :PAS ENCORE TESTE AVEC UN NIVEAU POSITIONNE
418 // Supprime les DataId et les données associées
419 // du container associatif quand le nombre
420 // de données stockées dépasse le niveau CALCIUM.
421 // Cette méthode est appelée de GenericPort::get et GenericPort::next
422 // TODO : Elle devrait également être appelée dans GenericPort::Put
423 // mais il faut étudier les interactions avec GenericPort::Get et GenericPort::next
424 template < typename DataManipulator >
426 
428 
430  _couplingPolicy(couplingPolicy) {};
431 
432  template < typename Container >
433  void apply(Container & storedDatas,
434  typename Container::iterator & wDataIt1 ) const {
435 
436  typedef typename Container::key_type key_type;
437  typedef typename Container::value_type value_type;
438  typedef typename Container::iterator iterator;
439 
440 #ifdef MYDEBUG
441  std::cout << "-------- CalciumCouplingPolicy::eraseDataId, storedDatasSize : " << storedDatas.size() << std::endl;
442 #endif
443 
445 
446  size_t storedDatasSize = storedDatas.size();
447  long s = storedDatasSize - _couplingPolicy._storageLevel;
448  if (s > 0 ) {
449  size_t dist=distance(storedDatas.begin(),wDataIt1);
450  for (int i=0; i<s; ++i) {
451  //no bug if removed : DataManipulator::delete_data((*storedDatas.begin()).second);
452  DataManipulator::delete_data((*storedDatas.begin()).second);
453  storedDatas.erase(storedDatas.begin());
454  }
455  // Si l'itérateur pointait sur une valeur que l'on vient de supprimer
456  if (dist < s ) {
457  throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "StorageLevel management "
459  " has just removed the data to send")));
460  }
461  }
462 #ifdef MYDEBUG
463  std::cout << "-------- CalciumCouplingPolicy::eraseDataId, new storedDatasSize : " << storedDatas.size() << std::endl;
464 #endif
465  return;
466 
467  }
468 };
469 
470 
471 // Lorsque cette méthode est appelée depuis GenericPort::Get
472 // l'expectedDataId n'a pas été trouvé et n'est pas non plus
473 // encadré (en mode temporel).
474 // Si apply n'effectue pas de traitement particulier la méthode renvoie false
475 // Si le port a déjà reçu une directive de deconnexion STOP une exception est levée
476 // Si le port a déjà reçu une directive de deconnexion CONTINUE,
477 // on donne la dernière valeur connu et on renvoie true.
478 template < typename DataManipulator >
480 
482 
484  _couplingPolicy(couplingPolicy) {};
485 
486  template < typename Container, typename DataId >
487  bool apply(Container & storedDatas,
488  const DataId & expectedDataId,
489  typename Container::iterator & wDataIt1 ) const {
490 
491  typedef typename Container::key_type key_type;
492  typedef typename Container::value_type value_type;
493  typedef typename Container::iterator iterator;
494 
495  // Pas de traitement particulier a effectuer
496 #ifdef MYDEBUG
497  std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK1 ("<< _couplingPolicy._disconnectDirective<<") --------" << std::endl;
498 #endif
500 
501 #ifdef MYDEBUG
502  std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK2 --------" << std::endl;
503 #endif
504 
505  // TODO : Ds GenericPort::next il faut convertir en CPSTOPSEQ
507  throw(CalciumException(CalciumTypes::CPINARRET,LOC(OSS()<< "CP_ARRET directive"
508  << " interrupts all further data reading")));
509 #ifdef MYDEBUG
510  std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK3 --------" << std::endl;
511 #endif
512 
513 
514  // S'il n'y a plus de données indique que l'on a pas pu effectuer de traitement
515  // TODO : Dans la gestion des niveaux il faut peut être interdire un niveau == 0
516  if ( storedDatas.empty() )
517  throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "CP_CONT directive"
518  << " is active but no data is available.")));
519 
520  // expectedDataId n'a ni été trouvé dans storedDataIds ni encadré mais il se peut
521  // qu'en mode itératif il ne soit pas plus grand que le plus grand DataId stocké auquel
522  // cas on doit renvoyer une expection car on n'est plus connecté et on ne pourra jamais
523  // fournir de données pour ce dataId.
524 #ifdef MYDEBUG
525  std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK4 " << expectedDataId <<" --------" << std::endl;
526 #endif
527 
528  // >= expectedDataId
529  iterator it1 = storedDatas.lower_bound(expectedDataId);
530 #ifdef MYDEBUG
531  std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK5 " << std::endl;
532  for (iterator it=storedDatas.begin();it!=storedDatas.end();++it)
533  std::cout <<" "<<(*it).first ;
534  std::cout <<std::endl;
535 #endif
536 
537  // TODO : Il faut en fait renvoyer le plus proche cf IT ou DT
538  if (it1 == storedDatas.end())
539  throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "CP_CONT directive"
540  << " is active but the requested dataId is less or equal to the last one received.")));
541 
542 #ifdef MYDEBUG
543  std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK6 " << std::endl;
544 #endif
545 
546  wDataIt1 = storedDatas.end();
547  --wDataIt1;
548 #ifdef MYDEBUG
549  std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor, CP_CONT : " << (*wDataIt1).first << std::endl;
550 #endif
551 
552  return true;
553  }
554 };
555 
556 #endif