@@ -835,46 +835,33 @@ class UniformFiniteDifferencer(DerivativeEstimatorTemplate):
835
835
def __init__ (self , time_domain , scheme = "ord4" ):
836
836
"""Store the time domain and set the finite difference scheme."""
837
837
DerivativeEstimatorTemplate .__init__ (self , time_domain )
838
- self .scheme = scheme
839
838
840
- # Properties --------------------------------------------------------------
841
- @DerivativeEstimatorTemplate .time_domain .setter
842
- def time_domain (self , t ):
843
- """Set the time domain---ensuring it is uniform---and the time step."""
844
- if np .isscalar (t [0 ]):
845
- # Case 1: the time domain is a one-dimensional array.
846
- diffs = np .diff (t )
847
- if not np .allclose (diffs , diffs [0 ]):
848
- raise ValueError ("time domain must be uniformly spaced" )
849
- self .__dt = diffs [0 ]
850
- elif all (np .ndim (tt ) == 1 for tt in t ):
851
- # Case 2: there are several time domains (multiple trajectories).
852
- for tt in t :
853
- self .time_domain = tt # Check that each has uniform spacing.
854
- self .__dt = None
855
- else :
856
- raise ValueError ("time_domain should be a one-dimensional array" )
857
- DerivativeEstimatorTemplate .time_domain .fset (self , t )
839
+ # Check for uniform spacing.
840
+ diffs = np .diff (time_domain )
841
+ if not np .allclose (diffs , diffs [0 ]):
842
+ raise ValueError ("time domain must be uniformly spaced" )
843
+
844
+ # Set the finite difference scheme.
845
+ if not callable (scheme ):
846
+ if scheme not in self ._schemes :
847
+ raise ValueError (
848
+ f"invalid finite difference scheme '{ scheme } '"
849
+ )
850
+ scheme = self ._schemes [scheme ]
851
+ self .__scheme = scheme
858
852
853
+ # Properties --------------------------------------------------------------
859
854
@property
860
855
def dt (self ):
861
856
"""Time step."""
862
- return self .__dt
857
+ t = self .time_domain
858
+ return t [1 ] - t [0 ]
863
859
864
860
@property
865
861
def scheme (self ):
866
862
"""Finite difference engine."""
867
863
return self .__scheme
868
864
869
- @scheme .setter
870
- def scheme (self , f ):
871
- """Set the finite difference scheme."""
872
- if not callable (f ):
873
- if f not in self ._schemes :
874
- raise ValueError (f"invalid finite difference scheme '{ f } '" )
875
- f = self ._schemes [f ]
876
- self .__scheme = f
877
-
878
865
# Main routine ------------------------------------------------------------
879
866
def estimate (self , states , inputs = None ):
880
867
r"""Estimate the first time derivatives of the states using
@@ -900,19 +887,7 @@ def estimate(self, states, inputs=None):
900
887
Inputs corresponding to ``_states``, if applicable.
901
888
**Only returned** if ``inputs`` is provided.
902
889
"""
903
- if self .dt is None :
904
- raise RuntimeError ("dt is None" )
905
-
906
- if states .ndim != 2 :
907
- raise errors .DimensionalityError ("states must be two-dimensional" )
908
- if inputs is not None :
909
- if inputs .ndim == 1 :
910
- inputs = inputs .reshape ((1 , - 1 ))
911
- if inputs .shape [1 ] != states .shape [1 ]:
912
- raise errors .DimensionalityError (
913
- "states and inputs not aligned"
914
- )
915
-
890
+ states , inputs = self ._check_dimensions (states , inputs , False )
916
891
return self .scheme (states , self .dt , inputs )
917
892
918
893
@@ -933,26 +908,15 @@ class NonuniformFiniteDifferencer(DerivativeEstimatorTemplate):
933
908
934
909
def __init__ (self , time_domain ):
935
910
"""Set the time domain."""
936
- self .__check_uniformity = True
937
911
DerivativeEstimatorTemplate .__init__ (self , time_domain )
938
912
939
- # Properties --------------------------------------------------------------
940
- @DerivativeEstimatorTemplate .time_domain .setter
941
- def time_domain (self , t ):
942
- """Set the time domain. Raise a warning if it is uniform."""
943
- if np .isscalar (t [0 ]):
944
- # Case 1: the time domain is a one-dimensional array.
945
- if self .__check_uniformity and np .allclose (
946
- diffs := np .diff (t ), diffs [0 ]
947
- ):
948
- warnings .warn (
949
- "time_domain is uniformly spaced, consider using "
950
- "UniformFiniteDifferencer" ,
951
- errors .OpInfWarning ,
952
- )
953
- elif not all (np .ndim (tt ) == 1 for tt in t ): # OK if several domains.
954
- raise ValueError ("time_domain should be a one-dimensional array" )
955
- DerivativeEstimatorTemplate .time_domain .fset (self , t )
913
+ # Warn if time_domain in not uniform.
914
+ if np .allclose (diffs := np .diff (time_domain ), diffs [0 ]):
915
+ warnings .warn (
916
+ "time_domain is uniformly spaced, consider using "
917
+ "UniformFiniteDifferencer" ,
918
+ errors .OpInfWarning ,
919
+ )
956
920
957
921
# Main routine ------------------------------------------------------------
958
922
def estimate (self , states , inputs = None ):
@@ -976,20 +940,7 @@ def estimate(self, states, inputs=None):
976
940
Inputs corresponding to ``_states``, if applicable.
977
941
**Only returned** if ``inputs`` is provided.
978
942
"""
979
- # Check dimensions.
980
- if states .ndim != 2 :
981
- raise errors .DimensionalityError ("states must be two-dimensional" )
982
- if states .shape [- 1 ] != self .time_domain .size :
983
- raise errors .DimensionalityError (
984
- "states not aligned with time_domain"
985
- )
986
- if inputs is not None :
987
- if inputs .ndim == 1 :
988
- inputs = inputs .reshape ((1 , - 1 ))
989
- if inputs .shape [1 ] != self .time_domain .size :
990
- raise errors .DimensionalityError (
991
- "inputs not aligned with time_domain"
992
- )
943
+ states , inputs = self ._check_dimensions (states , inputs )
993
944
994
945
# Do the computation.
995
946
ddts = np .gradient (states , self .time_domain , edge_order = 2 , axis = - 1 )
@@ -998,29 +949,6 @@ def estimate(self, states, inputs=None):
998
949
return states , ddts , inputs
999
950
return states , ddts
1000
951
1001
- # Verification ------------------------------------------------------------
1002
- def verify (self , plot : bool = False ):
1003
- """Verify that :meth:`estimate()` is consistent in the sense that the
1004
- all outputs have the same number of columns and test the accuracy of
1005
- the results on a few test problems.
1006
-
1007
- Parameters
1008
- ----------
1009
- plot : bool
1010
- If ``True``, plot the relative errors of the derivative estimation
1011
- errors as a function of the time step.
1012
- If ``False`` (default), print a report of the relative errors.
1013
-
1014
- Returns
1015
- -------
1016
- errors : dict
1017
- Estimation errors for each test case.
1018
- Time steps are listed as ``errors[dts]``.
1019
- """
1020
- self .__check_uniformity = False
1021
- DerivativeEstimatorTemplate .verify (self , plot = plot )
1022
- self .__check_uniformity = True
1023
-
1024
952
1025
953
# Old API =====================================================================
1026
954
def ddt_uniform (states , dt , order = 2 ):
0 commit comments