diffpy.srfit 3.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. diffpy/__init__.py +15 -0
  2. diffpy/srfit/__init__.py +41 -0
  3. diffpy/srfit/equation/__init__.py +31 -0
  4. diffpy/srfit/equation/builder.py +702 -0
  5. diffpy/srfit/equation/equationmod.py +213 -0
  6. diffpy/srfit/equation/literals/__init__.py +71 -0
  7. diffpy/srfit/equation/literals/abcs.py +81 -0
  8. diffpy/srfit/equation/literals/argument.py +76 -0
  9. diffpy/srfit/equation/literals/literal.py +69 -0
  10. diffpy/srfit/equation/literals/operators.py +380 -0
  11. diffpy/srfit/equation/visitors/__init__.py +94 -0
  12. diffpy/srfit/equation/visitors/argfinder.py +62 -0
  13. diffpy/srfit/equation/visitors/printer.py +120 -0
  14. diffpy/srfit/equation/visitors/swapper.py +142 -0
  15. diffpy/srfit/equation/visitors/validator.py +113 -0
  16. diffpy/srfit/equation/visitors/visitor.py +62 -0
  17. diffpy/srfit/exceptions.py +29 -0
  18. diffpy/srfit/fitbase/__init__.py +53 -0
  19. diffpy/srfit/fitbase/calculator.py +110 -0
  20. diffpy/srfit/fitbase/configurable.py +57 -0
  21. diffpy/srfit/fitbase/constraint.py +117 -0
  22. diffpy/srfit/fitbase/fitcontribution.py +351 -0
  23. diffpy/srfit/fitbase/fithook.py +227 -0
  24. diffpy/srfit/fitbase/fitrecipe.py +826 -0
  25. diffpy/srfit/fitbase/fitresults.py +674 -0
  26. diffpy/srfit/fitbase/parameter.py +314 -0
  27. diffpy/srfit/fitbase/parameterset.py +110 -0
  28. diffpy/srfit/fitbase/profile.py +405 -0
  29. diffpy/srfit/fitbase/profilegenerator.py +168 -0
  30. diffpy/srfit/fitbase/profileparser.py +179 -0
  31. diffpy/srfit/fitbase/recipeorganizer.py +1074 -0
  32. diffpy/srfit/fitbase/restraint.py +117 -0
  33. diffpy/srfit/fitbase/simplerecipe.py +230 -0
  34. diffpy/srfit/fitbase/validatable.py +59 -0
  35. diffpy/srfit/interface/__init__.py +33 -0
  36. diffpy/srfit/interface/interface.py +180 -0
  37. diffpy/srfit/pdf/__init__.py +24 -0
  38. diffpy/srfit/pdf/basepdfgenerator.py +296 -0
  39. diffpy/srfit/pdf/characteristicfunctions.py +432 -0
  40. diffpy/srfit/pdf/debyepdfgenerator.py +115 -0
  41. diffpy/srfit/pdf/pdfcontribution.py +311 -0
  42. diffpy/srfit/pdf/pdfgenerator.py +77 -0
  43. diffpy/srfit/pdf/pdfparser.py +226 -0
  44. diffpy/srfit/sas/__init__.py +30 -0
  45. diffpy/srfit/sas/prcalculator.py +139 -0
  46. diffpy/srfit/sas/sasgenerator.py +70 -0
  47. diffpy/srfit/sas/sasimport.py +66 -0
  48. diffpy/srfit/sas/sasparameter.py +70 -0
  49. diffpy/srfit/sas/sasparser.py +133 -0
  50. diffpy/srfit/sas/sasprofile.py +94 -0
  51. diffpy/srfit/structure/__init__.py +60 -0
  52. diffpy/srfit/structure/basestructureparset.py +62 -0
  53. diffpy/srfit/structure/bvsrestraint.py +101 -0
  54. diffpy/srfit/structure/cctbxparset.py +292 -0
  55. diffpy/srfit/structure/diffpyparset.py +303 -0
  56. diffpy/srfit/structure/objcrystparset.py +1552 -0
  57. diffpy/srfit/structure/sgconstraints.py +761 -0
  58. diffpy/srfit/structure/srrealparset.py +92 -0
  59. diffpy/srfit/util/__init__.py +50 -0
  60. diffpy/srfit/util/argbinders.py +29 -0
  61. diffpy/srfit/util/inpututils.py +50 -0
  62. diffpy/srfit/util/nameutils.py +45 -0
  63. diffpy/srfit/util/observable.py +93 -0
  64. diffpy/srfit/util/tagmanager.py +150 -0
  65. diffpy/srfit/util/weakrefcallable.py +170 -0
  66. diffpy/srfit/version.py +26 -0
  67. diffpy_srfit-3.1.0.dist-info/METADATA +216 -0
  68. diffpy_srfit-3.1.0.dist-info/RECORD +73 -0
  69. diffpy_srfit-3.1.0.dist-info/WHEEL +5 -0
  70. diffpy_srfit-3.1.0.dist-info/licenses/AUTHORS.rst +10 -0
  71. diffpy_srfit-3.1.0.dist-info/licenses/LICENSE.rst +138 -0
  72. diffpy_srfit-3.1.0.dist-info/licenses/LICENSE_DANSE.rst +34 -0
  73. diffpy_srfit-3.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """Swapper for replacing a Literal in an equation with another Literals."""
16
+
17
+ __all__ = ["Swapper"]
18
+
19
+ from diffpy.srfit.equation.visitors.visitor import Visitor
20
+
21
+
22
+ class Swapper(Visitor):
23
+ """Swapper for swapping out one literal for another in a literal tree.
24
+
25
+ Note that this cannot swap out a root node of a literal tree. This case
26
+ must be tested for explicitly.
27
+
28
+ Attributes:
29
+ newlit -- The literal to be placed into the literal tree.
30
+ oldlit -- The literal to be replaced.
31
+ """
32
+
33
+ def __init__(self, oldlit, newlit):
34
+ """Initialize.
35
+
36
+ oldlit -- The literal to be replaced.
37
+ newlit -- The literal to be placed into the literal tree. See the
38
+ class for how the replacement takes place.
39
+ """
40
+
41
+ self.newlit = newlit
42
+ self.oldlit = oldlit
43
+
44
+ self._swap = False
45
+
46
+ return
47
+
48
+ def onArgument(self, arg):
49
+ """Process an Argument node.
50
+
51
+ Tell the parent to swap the old Argument with the replacement
52
+ Literal.
53
+ """
54
+
55
+ if arg is self.oldlit:
56
+ self._swap = True
57
+
58
+ return
59
+
60
+ def onOperator(self, op):
61
+ """Process an Operator node.
62
+
63
+ Tell the parent to swap the old Operator with the replacement
64
+ Literal.
65
+ """
66
+
67
+ # Check to see if we need to swap out this Operator. If so, then we
68
+ # don't need to traverse into its arguments.
69
+ if op is self.oldlit:
70
+ self._swap = True
71
+ return
72
+
73
+ # Now traverse into the arguments.
74
+ for literal in op.args:
75
+ literal.identify(self)
76
+
77
+ # If we've been told to swap out a literal, then we must do it in-place
78
+ # because the order of op.args matters.
79
+ if self._swap:
80
+
81
+ oldlit = self.oldlit
82
+ newlit = self.newlit
83
+
84
+ while oldlit in op.args:
85
+
86
+ # Record the index
87
+ idx = op.args.index(oldlit)
88
+ # Remove the literal
89
+ del op.args[idx]
90
+ # Remove op as an observer. A KeyError will be raised if we
91
+ # attempt to remove the same observer more than once, which
92
+ # might happen if the oldlit appears multiple times in op.args.
93
+ try:
94
+ oldlit.removeObserver(op._flush)
95
+ except KeyError:
96
+ pass
97
+
98
+ # Validate the new literal. If it fails, we need to restore the
99
+ # old one
100
+ try:
101
+ op._loopCheck(newlit)
102
+ except ValueError:
103
+ # Restore the old literal
104
+ op.args.insert(idx, oldlit)
105
+ oldlit.addObserver(op._flush)
106
+ raise
107
+
108
+ # If we got here, then go on with replacing the literal
109
+ op.args.insert(idx, newlit)
110
+ newlit.addObserver(op._flush)
111
+ op._flush(other=())
112
+
113
+ self._swap = False
114
+
115
+ return
116
+
117
+ def onEquation(self, eq):
118
+ """Process an Equation node.
119
+
120
+ This looks at the equation itself as well as the root.
121
+ """
122
+ if eq is self.oldlit:
123
+ self._swap = True
124
+ return
125
+
126
+ # If the newlit is the root, then swap that out and move on.
127
+ if eq.root is self.oldlit:
128
+ eq.setRoot(self.newlit)
129
+ return
130
+
131
+ # Now move into the equation. We have to do a _loopCheck to make sure
132
+ # that we won't have any loops in the equation.
133
+ eq._loopCheck(self.newlit)
134
+ eq.root.identify(self)
135
+
136
+ # Reset the root in case anything changed underneath.
137
+ eq.setRoot(eq.root)
138
+
139
+ return
140
+
141
+
142
+ # End of file
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """Validator visitor for validating a tree of Literals.
16
+
17
+ The Validator walks an equation tree composed of Literals and checks the
18
+ validity of each equation as much as possible without evaluating it. It
19
+ collects errors in a list.
20
+
21
+ The Validator checks that the input count of each Operator is equal to
22
+ the output count of its arguments. It also checks that each object has
23
+ the proper interface.
24
+ """
25
+
26
+ __all__ = ["Validator"]
27
+
28
+ from diffpy.srfit.equation.literals.abcs import ArgumentABC, OperatorABC
29
+ from diffpy.srfit.equation.visitors.visitor import Visitor
30
+
31
+ msg = "'%s' does not have the interface required by '%s'"
32
+
33
+
34
+ class Validator(Visitor):
35
+ """Validator error for checking validity of an equation tree.
36
+
37
+ Attributes:
38
+ errors -- List of strings describing errors.
39
+ _nin -- Variable for counting the number input arguments for an
40
+ operator.
41
+ """
42
+
43
+ def __init__(self):
44
+ """Initialize."""
45
+ self.reset()
46
+ return
47
+
48
+ def reset(self):
49
+ """Click the clicker and reset non-public data."""
50
+ self.errors = []
51
+ self._nin = 0
52
+ return
53
+
54
+ def onArgument(self, arg):
55
+ """Process an Argument node.
56
+
57
+ The Argument must be an instance of ArgumentABC from
58
+ diffpy.srfit.equation.literals.abcs
59
+ """
60
+ if not isinstance(arg, ArgumentABC):
61
+ m = msg % (arg, ArgumentABC.__name__)
62
+ self.errors.append(m)
63
+ self._nin = 1
64
+ return self.errors
65
+
66
+ def onOperator(self, op):
67
+ """Process an Operator node.
68
+
69
+ The Operator must be an instance of OperatorABC from
70
+ diffpy.srfit.equation.literals.abcs
71
+ """
72
+
73
+ if not isinstance(op, OperatorABC):
74
+ m = msg % (op, OperatorABC.__name__)
75
+ self.errors.append(m)
76
+
77
+ # Can only process single-valued functions
78
+ if op.nout != 1:
79
+ m = "'%s' is not single-valued (nout != 1)" % op
80
+ self.errors.append(m)
81
+ # Check name
82
+ if op.name is None:
83
+ m = "'%s' does not have a name" % op
84
+ self.errors.append(m)
85
+ # Check symbol
86
+ if op.symbol is None:
87
+ m = "'%s' does not have a symbol" % op
88
+ self.errors.append(m)
89
+ # Check operation without evaluating it
90
+ if op.operation is None:
91
+ m = "'%s' does not define and operation" % op
92
+ self.errors.append(m)
93
+
94
+ localnin = 0
95
+ for literal in op.args:
96
+ literal.identify(self)
97
+ # Count the nout of the arguments.
98
+ localnin += self._nin
99
+
100
+ # Check the input/output balance
101
+ if op.nin >= 0 and localnin != op.nin:
102
+ m = "'%s' requires %i inputs but receives %i" % (
103
+ op,
104
+ op.nin,
105
+ localnin,
106
+ )
107
+ self.errors.append(m)
108
+
109
+ self._nin = op.nout
110
+ return self.errors
111
+
112
+
113
+ # End of file
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """Base visitor class.
16
+
17
+ Visitors work with Literal trees to perform a specified action. They are
18
+ designed according to the visitor pattern (
19
+ http://en.wikipedia.org/wiki/Visitor_pattern).
20
+
21
+ Visitors work with the following Literal classes
22
+ (diffpy.srfit.equation.literals):
23
+ Argument
24
+ Operator
25
+
26
+ See the Visitor class for the required methods that each Visitor must overload.
27
+ """
28
+
29
+ __all__ = ["Visitor"]
30
+
31
+
32
+ class Visitor(object):
33
+ """Abstract class for all visitors to a Literal tree.
34
+
35
+ See implemented visitors for examples of use.
36
+ """
37
+
38
+ def onArgument(self, arg):
39
+ """Process an Argument node."""
40
+ return self._abstract("onArgument")
41
+
42
+ def onOperator(self, op):
43
+ """Process an Operator node."""
44
+ return self._abstract("onOperator")
45
+
46
+ def onEquation(self, eq):
47
+ """Process an Equation node.
48
+
49
+ Equations are specialized Operators. They don't need to be
50
+ specifically supported by a Visitor.
51
+ """
52
+ return self.onOperator(eq)
53
+
54
+ # throw an exception
55
+ def _abstract(self, method):
56
+ raise NotImplementedError(
57
+ "class '%s' should override method '%s'"
58
+ % (self.__class__.__name__, method)
59
+ )
60
+
61
+
62
+ # End of file
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit Complex Modeling Initiative
5
+ # (c) 2016 Brookhaven Science Associates,
6
+ # Brookhaven National Laboratory.
7
+ # All rights reserved.
8
+ #
9
+ # File coded by: Pavol Juhas
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """
16
+ Exceptions used for SrFit - specific errors.
17
+ """
18
+
19
+
20
+ class SrFitError(Exception):
21
+ """Generic error in SrFit expressions or recipe."""
22
+
23
+ pass
24
+
25
+
26
+ class ParseError(Exception):
27
+ """Exception used by ProfileParsers."""
28
+
29
+ pass
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """The base fitting classes for diffpy.srfit.
16
+
17
+ This package contains modules and subpackages that are used to define a
18
+ fit problem in SrFit. Unaltered, these classes will help set up a fit
19
+ problem that can be optimized within a fitting framework or with a
20
+ standalone optimizer. They provide the basic framework for defining a
21
+ forward calculator, and from that defining a fit problem with data,
22
+ constraints and restraints. The classes involved in this collaboration
23
+ can be tied to a fitting framework at various levels through
24
+ inheritance. One can create a fitting problem using the FitContribution,
25
+ Profile and FitRecipe classes.
26
+
27
+ Various code and design taken from Paul Kienzle's PARK package.
28
+ http://www.reflectometry.org/danse/park.html
29
+ """
30
+
31
+ __all__ = [
32
+ "Calculator",
33
+ "FitContribution",
34
+ "FitHook",
35
+ "FitRecipe",
36
+ "FitResults",
37
+ "initializeRecipe",
38
+ "PlotFitHook",
39
+ "Profile",
40
+ "ProfileGenerator",
41
+ "SimpleRecipe",
42
+ ]
43
+
44
+ from diffpy.srfit.fitbase.calculator import Calculator
45
+ from diffpy.srfit.fitbase.fitcontribution import FitContribution
46
+ from diffpy.srfit.fitbase.fithook import FitHook, PlotFitHook
47
+ from diffpy.srfit.fitbase.fitrecipe import FitRecipe
48
+ from diffpy.srfit.fitbase.fitresults import FitResults, initializeRecipe
49
+ from diffpy.srfit.fitbase.profile import Profile
50
+ from diffpy.srfit.fitbase.profilegenerator import ProfileGenerator
51
+ from diffpy.srfit.fitbase.simplerecipe import SimpleRecipe
52
+
53
+ # End of file
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """The Calculator for Parameter-aware functions.
16
+
17
+ Calculator is a functor class for producing a signal from embedded
18
+ Parameters. Calculators can store Parameters and ParameterSets,
19
+ Constraints and Restraints. Also, the __call__ function can be
20
+ overloaded to accept external arguments. Calculators are used to wrap
21
+ registered functions so that the function's Parameters are contained in
22
+ an object specific to the function. A custom Calculator can be added to
23
+ another RecipeOrganizer with the 'registerCalculator' method.
24
+ """
25
+
26
+ __all__ = ["Calculator"]
27
+
28
+ from diffpy.srfit.equation.literals.operators import Operator
29
+ from diffpy.srfit.fitbase.parameterset import ParameterSet
30
+
31
+
32
+ class Calculator(Operator, ParameterSet):
33
+ """Base class for calculators.
34
+
35
+ A Calculator organizes Parameters and has a __call__ method that can
36
+ calculate a generic signal.
37
+
38
+ Attributes
39
+ name -- A name for this organizer.
40
+ meta -- A dictionary of metadata needed by the calculator.
41
+ _calculators -- A managed dictionary of Calculators, indexed by name.
42
+ _constraints -- A set of constrained Parameters. Constraints can be
43
+ added using the 'constrain' methods.
44
+ _parameters -- A managed OrderedDict of contained Parameters.
45
+ _parsets -- A managed dictionary of ParameterSets.
46
+ _restraints -- A set of Restraints. Restraints can be added using the
47
+ 'restrain' or 'confine' methods.
48
+ _eqfactory -- A diffpy.srfit.equation.builder.EquationFactory
49
+ instance that is used create Equations from string.
50
+
51
+ Operator Attributes
52
+ args -- List of Literal arguments
53
+ nin -- Number of inputs (<1 means this is variable)
54
+ nout -- Number of outputs (1)
55
+ operation -- Function that performs the operation, self.__call__
56
+ symbol -- Same as name
57
+ _value -- The value of the Operator.
58
+ value -- Property for 'getValue'.
59
+
60
+ Properties
61
+ names -- Variable names (read only). See getNames.
62
+ values -- Variable values (read only). See getValues.
63
+ """
64
+
65
+ # define abstract attributes from the Operator base.
66
+
67
+ nin = -1
68
+ nout = 1
69
+
70
+ def __init__(self, name):
71
+ ParameterSet.__init__(self, name)
72
+ self.meta = {}
73
+
74
+ # Initialize Operator attributes
75
+ Operator.__init__(self, name)
76
+ return
77
+
78
+ @property
79
+ def symbol(self):
80
+ return self.name
81
+
82
+ # Overload me!
83
+ def __call__(self, *args):
84
+ """Calculate something.
85
+
86
+ This method must be overloaded. When overloading, you should
87
+ specify the arguments explicitly, otherwise the parameters must
88
+ be specified when adding the Calculator to a RecipeOrganizer.
89
+ """
90
+ return 0
91
+
92
+ def operation(self, *args):
93
+ self._value = self.__call__(*args)
94
+ return self._value
95
+
96
+ def _validate(self):
97
+ """Validate my state.
98
+
99
+ This performs ParameterSet validations. This does not validate
100
+ the operation, since this could be costly. The operation should
101
+ be validated with a containing equation.
102
+
103
+ Raises AttributeError if validation fails.
104
+ """
105
+ ParameterSet._validate(self)
106
+
107
+ return
108
+
109
+
110
+ # End class Calculator
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """Configurable class.
16
+
17
+ A Configurable has state of which a FitRecipe must be aware.
18
+ """
19
+
20
+ __all__ = ["Configurable"]
21
+
22
+
23
+ class Configurable(object):
24
+ """Configurable class.
25
+
26
+ A Configurable has state of which a FitRecipe must be aware.
27
+
28
+ Attributes
29
+ _configobjs -- Set of Configureables in a hierarchy or instances.
30
+ Messages get passed up the hierarchy to a FitReciple
31
+ via these objects.
32
+ """
33
+
34
+ def __init__(self):
35
+ self._configobjs = set()
36
+ return
37
+
38
+ def _updateConfiguration(self):
39
+ """Notify Configurables in hierarchy of configuration change."""
40
+ for obj in self._configobjs:
41
+ obj._updateConfiguration()
42
+ return
43
+
44
+ def _storeConfigurable(self, obj):
45
+ """Store a Configurable.
46
+
47
+ The passed obj is only stored if it is a a Configurable,
48
+ otherwise this method quietly exits.
49
+ """
50
+ if isinstance(obj, Configurable):
51
+ self._configobjs.add(obj)
52
+ return
53
+
54
+
55
+ # End class Configurable
56
+
57
+ # End of file
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env python
2
+ ##############################################################################
3
+ #
4
+ # diffpy.srfit by DANSE Diffraction group
5
+ # Simon J. L. Billinge
6
+ # (c) 2008 The Trustees of Columbia University
7
+ # in the City of New York. All rights reserved.
8
+ #
9
+ # File coded by: Chris Farrow
10
+ #
11
+ # See AUTHORS.txt for a list of people who contributed.
12
+ # See LICENSE_DANSE.txt for license information.
13
+ #
14
+ ##############################################################################
15
+ """Constraint class.
16
+
17
+ Constraints are used by a FitRecipe (and other RecipeOrganizers) to
18
+ organize constraint equations. They store a Parameter object and an
19
+ Equation object that is used to compute its value. The
20
+ Constraint.constrain method is used to create this association.
21
+ """
22
+
23
+ __all__ = ["Constraint"]
24
+
25
+ from diffpy.srfit.exceptions import SrFitError
26
+ from diffpy.srfit.fitbase.validatable import Validatable
27
+
28
+
29
+ class Constraint(Validatable):
30
+ """Constraint class.
31
+
32
+ Constraints are designed to be stored in only one place. (The holder of the
33
+ constraint owns it).
34
+
35
+ Attributes
36
+ par -- A Parameter that is the subject of the constraint.
37
+ eq -- An equation whose evaluation is used to set the value of the
38
+ constraint.
39
+ """
40
+
41
+ def __init__(self):
42
+ """Initialization."""
43
+ self.par = None
44
+ self.eq = None
45
+ return
46
+
47
+ def constrain(self, par, eq):
48
+ """Constrain a Parameter according to an Equation.
49
+
50
+ The parameter will be set constant once it is constrained. This
51
+ will keep it from being constrained multiple times.
52
+
53
+ Raises a ValueError if par is const.
54
+ """
55
+
56
+ if par.const:
57
+ raise ValueError("The parameter '%s' is constant" % par)
58
+
59
+ if par.constrained:
60
+ raise ValueError("The parameter '%s' is already constrained" % par)
61
+
62
+ par.constrained = True
63
+
64
+ self.par = par
65
+ self.eq = eq
66
+ self.update()
67
+ return
68
+
69
+ def unconstrain(self):
70
+ """Clear the constraint."""
71
+ self.par.constrained = False
72
+ self.par = None
73
+ self.eq = None
74
+ return
75
+
76
+ def update(self):
77
+ """Update the parameter according to the equation."""
78
+ # This will be evaluated quickly thanks to the Equation class.
79
+ val = self.eq()
80
+ # This will only change the Parameter if val is different from the
81
+ # currently stored value.
82
+ self.par.setValue(val)
83
+ return
84
+
85
+ def _validate(self):
86
+ """Validate my state.
87
+
88
+ This validates that par is not None. This validates eq.
89
+
90
+ Raises SrFitError if validation fails.
91
+ """
92
+ if self.par is None:
93
+ raise SrFitError("par is None")
94
+ if self.eq is None:
95
+ raise SrFitError("eq is None")
96
+ self.par._validate()
97
+ from diffpy.srfit.equation.visitors import validate
98
+
99
+ try:
100
+ validate(self.eq)
101
+ except ValueError as e:
102
+ raise SrFitError(e)
103
+
104
+ # Try to get the value of eq.
105
+ try:
106
+ val = self.eq()
107
+ self.par.setValue(val)
108
+ except TypeError:
109
+ raise SrFitError("eq cannot be evaluated")
110
+ finally:
111
+ if val is None:
112
+ raise SrFitError("eq evaluates to None")
113
+
114
+ return
115
+
116
+
117
+ # End of file