1 // Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File : CalciumCouplingPolicy.hxx
24 // Author : Eric Fayolle (EDF)
28 #ifndef __CALCIUM_COUPLING_POLICY__
29 #define __CALCIUM_COUPLING_POLICY__
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"
45 class CalciumCouplingPolicy : public CouplingPolicy {
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;
58 typedef CalciumTypes::DependencyType DependencyType;
59 typedef CalciumTypes::DateCalSchem DateCalSchem;
60 typedef CalciumTypes::InterpolationSchem InterpolationSchem;
61 typedef CalciumTypes::ExtrapolationSchem ExtrapolationSchem;
62 typedef CalciumTypes::DisconnectDirective DisconnectDirective;
66 DependencyType _dependencyType;
68 DateCalSchem _dateCalSchem;
69 InterpolationSchem _interpolationSchem;
70 ExtrapolationSchem _extrapolationSchem;
73 DisconnectDirective _disconnectDirective;
76 CalciumCouplingPolicy();
78 void setDependencyType (DependencyType dependencyType);
79 DependencyType getDependencyType () const;
81 void setStorageLevel (size_t storageLevel);
82 size_t getStorageLevel () const;
84 void setDateCalSchem (DateCalSchem dateCalSchem);
85 DateCalSchem getDateCalSchem () const;
87 void setAlpha(double alpha);
88 double getAlpha() const ;
90 void setDeltaT(double deltaT );
91 double getDeltaT() const ;
93 void setInterpolationSchem (InterpolationSchem interpolationSchem);
94 void setExtrapolationSchem (ExtrapolationSchem extrapolationSchem);
95 InterpolationSchem getInterpolationSchem () const ;
96 ExtrapolationSchem getExtrapolationSchem () const ;
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;
104 typedef InternalDataIdContainer < TimeType , TagType > DataIdContainer;
105 typedef std::vector< DataId >::iterator iterator;
107 template <typename T_TIME, typename T_TAG >
108 struct InternalDataIdContainer;
110 inline TimeType getTime(const DataId &dataId) const { return dataId.first;}
111 inline TagType getTag (const DataId &dataId) const { return dataId.second;}
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;
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;
132 TimeType getEffectiveTime(TimeType ti, TimeType tf);
134 void disconnect(bool provideLastGivenValue);
136 }; //Fin de CalciumCouplingPolicy
140 //************* DEFINITION DES METHODES ET OBJETS TEMPLATES *************//
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;
150 InternalDataIdContainer(const DataId & dataId,
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) {
155 case CalciumTypes::TIME_DEPENDENCY:
156 this->push_back(DataId(dataId.first,0));
158 case CalciumTypes::ITERATION_DEPENDENCY:
159 this->push_back(DataId(0,dataId.second));
162 throw(CalciumException(CalciumTypes::CPIT,LOC("The dependency type must be set by setDependencyType before calling DataIdContainer contructor")));
169 template <typename DataManipulator, class EnableIf >
170 struct CalciumCouplingPolicy::BoundedDataIdProcessor{
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;
178 std::cout << "-------- Calcium Generic BoundedDataIdProcessor.apply() called " << std::endl;
185 template <typename DataManipulator >
186 struct CalciumCouplingPolicy::BoundedDataIdProcessor<
188 typename boost::enable_if< boost::is_float< typename DataManipulator::InnerType> >::type > {
190 const CalciumCouplingPolicy & _couplingPolicy;
192 BoundedDataIdProcessor(const CalciumCouplingPolicy &couplingPolicy):
193 _couplingPolicy(couplingPolicy) {};
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 {
200 typedef typename iterator_t<MapIterator>::value_type value_type;
201 typedef typename DataManipulator::InnerType InnerType;
202 typedef typename DataManipulator::Type Type;
204 MapIterator it2=it1; ++it2;
205 size_t dataSize1 = DataManipulator::size(it1->second);
207 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Taille de donnée dataId1 : " << dataSize1 << std::endl;
210 // Gérer dans calcium la limite de la taille du buffer donnée par
212 size_t dataSize2 = DataManipulator::size(it2->second);
214 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Taille de donnée dataId2 : " << dataSize2 << std::endl;
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;
223 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t1 : " << t1 << std::endl;
224 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t2 : " << t2 << std::endl;
226 TimeType t = dataId.first;
228 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de t : " << t << std::endl;
230 TimeType timeDiff = t2-t1;
232 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de timeDiff : " << timeDiff << std::endl;
234 TimeType coeff = (t2-t)/timeDiff;
236 std::cout << "-------- CalciumCouplingPolicy::BoundedDataIdProcessor : Valeur de coeff : " << coeff << std::endl;
239 InnerType const * const InIt1 = DataManipulator::getPointer(it1->second);
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;
245 InnerType const * const InIt2 = DataManipulator::getPointer(it2->second);
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;
251 Type dataOut = DataManipulator::create(dataSize);
252 InnerType * const OutIt = DataManipulator::getPointer(dataOut);
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;
260 if ( timeDiff == 0.0 || _couplingPolicy._interpolationSchem == CalciumTypes::L0_SCHEM ) {
261 std::copy(InIt1,InIt1+dataSize,OutIt);
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];
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;
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 {
295 // Rem : le type key_type == DataId
296 typedef typename AssocContainer::key_type key_type;
297 AdjacentFunctor< key_type > af(expectedDataId);
298 if ( _dependencyType == CalciumTypes::TIME_DEPENDENCY )
301 std::cout << "-------- time expected : " << expectedDataId.first << std::endl;
302 std::cout << "-------- time expected corrected : " << expectedDataId.first*(1.0-_deltaT) << std::endl;
304 af.setMaxValue(key_type(expectedDataId.first*(1.0-_deltaT),0));
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
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
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) )
328 std::cerr << "------- stored time : " << current->first << std::endl;
330 // if ( af(current->first) ) break;
334 isEqual = af.isEqual();
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();
340 if ( isEqual ) wDataIt1 = current;
342 if (isBounded) wDataIt1 = prev;
344 wDataIt1 = storedDatas.end();
347 std::cout << "-------- isDataIdConvenient : isEqual : " << isEqual << " , isBounded " << isBounded << std::endl;
350 return isEqual || isBounded;
353 //Remove DataId before or after a given time or tag
354 template < typename DataManipulator >
355 struct CalciumCouplingPolicy::EraseDataIdBeforeOrAfterTagProcessor
357 CalciumCouplingPolicy &_couplingPolicy;
359 EraseDataIdBeforeOrAfterTagProcessor(CalciumCouplingPolicy &couplingPolicy):
360 _couplingPolicy(couplingPolicy) {};
362 template < typename Container,typename TimeType,typename TagType >
363 void apply(Container & storedDatas, TimeType time, TagType tag, bool before) const
365 typedef typename Container::iterator iterator;
366 typedef typename Container::reverse_iterator riterator;
368 if(_couplingPolicy._dependencyType == CalciumTypes::TIME_DEPENDENCY)
372 iterator it=storedDatas.begin();
373 while(it != storedDatas.end() && it->first.first <= time)
375 DataManipulator::delete_data(it->second);
376 storedDatas.erase(it);
377 it=storedDatas.begin();
382 riterator it=storedDatas.rbegin();
383 while(it != storedDatas.rend() && it->first.first >= time)
385 DataManipulator::delete_data(it->second);
386 storedDatas.erase(it->first);
387 it=storedDatas.rbegin();
395 iterator it=storedDatas.begin();
396 while(it != storedDatas.end() && it->first.second <= tag)
398 DataManipulator::delete_data(it->second);
399 storedDatas.erase(it);
400 it=storedDatas.begin();
405 riterator it=storedDatas.rbegin();
406 while(it != storedDatas.rend() && it->first.second >= tag)
408 DataManipulator::delete_data(it->second);
409 storedDatas.erase(it->first);
410 it=storedDatas.rbegin();
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 >
425 struct CalciumCouplingPolicy::EraseDataIdProcessor {
427 CalciumCouplingPolicy &_couplingPolicy;
429 EraseDataIdProcessor(CalciumCouplingPolicy &couplingPolicy):
430 _couplingPolicy(couplingPolicy) {};
432 template < typename Container >
433 void apply(Container & storedDatas,
434 typename Container::iterator & wDataIt1 ) const {
436 typedef typename Container::key_type key_type;
437 typedef typename Container::value_type value_type;
438 typedef typename Container::iterator iterator;
441 std::cout << "-------- CalciumCouplingPolicy::eraseDataId, storedDatasSize : " << storedDatas.size() << std::endl;
444 if ( _couplingPolicy._storageLevel == (size_t)CalciumTypes::UNLIMITED_STORAGE_LEVEL ) return;
446 size_t storedDatasSize = storedDatas.size();
447 long s = storedDatasSize - _couplingPolicy._storageLevel;
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());
455 // Si l'itérateur pointait sur une valeur que l'on vient de supprimer
456 if (dist < (size_t)s ) {
457 throw(CalciumException(CalciumTypes::CPNTNULL,LOC(OSS()<< "StorageLevel management "
458 << _couplingPolicy._storageLevel <<
459 " has just removed the data to send")));
463 std::cout << "-------- CalciumCouplingPolicy::eraseDataId, new storedDatasSize : " << storedDatas.size() << std::endl;
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 >
479 struct CalciumCouplingPolicy::DisconnectProcessor {
481 const CalciumCouplingPolicy & _couplingPolicy;
483 DisconnectProcessor(const CalciumCouplingPolicy & couplingPolicy):
484 _couplingPolicy(couplingPolicy) {};
486 template < typename Container, typename DataId >
487 bool apply(Container & storedDatas,
488 const DataId & expectedDataId,
489 typename Container::iterator & wDataIt1 ) const {
491 typedef typename Container::key_type key_type;
492 typedef typename Container::value_type value_type;
493 typedef typename Container::iterator iterator;
495 // Pas de traitement particulier a effectuer
497 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK1 ("<< _couplingPolicy._disconnectDirective<<") --------" << std::endl;
499 if ( (_couplingPolicy._disconnectDirective) == (CalciumTypes::UNDEFINED_DIRECTIVE) ) return false;
502 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK2 --------" << std::endl;
505 // TODO : Ds GenericPort::next il faut convertir en CPSTOPSEQ
506 if ( _couplingPolicy._disconnectDirective == CalciumTypes::CP_ARRET )
507 throw(CalciumException(CalciumTypes::CPINARRET,LOC(OSS()<< "CP_ARRET directive"
508 << " interrupts all further data reading")));
510 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK3 --------" << std::endl;
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.")));
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.
525 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK4 " << expectedDataId <<" --------" << std::endl;
529 iterator it1 = storedDatas.lower_bound(expectedDataId);
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;
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.")));
543 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor MARK6 " << std::endl;
546 wDataIt1 = storedDatas.end();
549 std::cout << "-------- CalciumCouplingPolicy::DisconnectProcessor, CP_CONT : " << (*wDataIt1).first << std::endl;