import escape as esc
esc.require("0.9.8")
Loading material database from /home/dkor/Data/Development/workspace_escape/escape-core/python/src/escape/scattering/../data/mdb/materials.db
Parameters¶
Parameter_obj object is a major building block of ESCAPE library. It performs a link between created models and optimizer, which performs optimization of the parameters for the best match between modeled and experimental data. In order to create a parameter object one should use a special factory function par, which has the following arguments:
1. name - parameter name
1. value - default value
2. userlim - limits of the parameter value
3. scale - multiplicator for parameter value
4. limscale - scale for automatic limits
5. units - units of parameter
6. fixed - set to True if you would like to fix value of the parameter
Below few examples of parameter creation are given.
p1 = esc.par("parameter 1", value=1.5, userlim=[0, 5])
p2 = esc.par("parameter 2", value=2.0, scale=1e-6, userlim=[0, 5])
p3 = esc.par("parameter 3", value=400.0, userlim=[0, 500])
p1, p2, p3
(parameter_obj(name='parameter 1', value=1.5, min=0.0, max=5.0, fixed=False, units=''), parameter_obj(name='parameter 2', value=2e-06, min=0.0, max=4.9999999999999996e-06, fixed=False, units=''), parameter_obj(name='parameter 3', value=400.0, min=0.0, max=500.0, fixed=False, units=''))
How to assign a value¶
There are two ways to assign parameter value:
1. by assigning to *value* property
2. by calling *force_value* method
If you try to set value outside given boundaries a warning will be generated. The force value method forces the value setting and changes boundaries.
p1.value = 3
print(p1)
# assigned value cannot be out of users or physical boundaries causing warning
p1.value = 10
print(p1)
parameter_obj(name='parameter 1', value=3.0, min=0.0, max=5.0, fixed=False, units='') parameter_obj(name='parameter 1', value=5.0, min=0.0, max=5.0, fixed=False, units='')
/tmp/ipykernel_58086/4167545963.py:4: WrongValueWarning: Parameter didn't reach user value, check limits p1.value = 10
p1.force_value(10)
print(p1)
parameter_obj(name='parameter 1', value=10.0, min=5.0, max=15.0, fixed=False, units='')
Expressions¶
Another useful feature of parameters is that they support arithmetic operators and mathematical functions. This feature allows the user to define parameters dependencies. New parameters will observe such dependencies and certainly will be not optimized during fit. The following mathematical functions are supported: sin, cos, tan, sinh, cosh, tanh, exp, sqrt, log, log10, pow, min, max, erf
p4 = esc.sin((p1 - p2) * (p1 + p2) / p1)
print(p4.value)
print(p4.independent)
-0.5440211108890345 False
p5 = esc.min(p1, p3)
print("p1=", p1.value, "p3=", p3.value, "p5=", p5.value)
p1= 10.0 p3= 400.0 p5= 10.0
As you have probably noticed par factory function returns an object of type parameter_obj. Class parameter_obj has a static method convert which is responsible for conversion from int and float types to parameters. In every method which requires parameter as an input, you can, if necessary, provide a float value. The value provided by the user will be converted to parameter_obj with constant value. This parameter is considered as dependent and will be ignored by the optimizer.
Conditional parameters¶
Conditional parameter is the parameter which, depending on condition result, true or false, returns a value of either the first parameter or the second one, respectively. Below is an example of conditional parameter. Conditional parameters can be used everywhere where parameter is required as an input.
p10 = esc.par("P10", 10)
p11 = esc.par("P11", 8)
p12 = esc.par("P12", 1)
p13 = esc.par("P13", 5)
cp = esc.conditional(p11 < p10, p12, p13)
cp.value
1.0
p11.value = 12
cp.value
5.0
Constraint parameters¶
Parameters in ESCAPE can be constrained using logical conditions. Constraints are used to restrict parameter values based on mathematical expressions involving other parameters.
For example, if we have parameters A and B, we can add constraints like:
- A + B > 10
- A > 0 & B > 0
- A^2 + B^2 > 100
Constraints are added to parameterized objects using the constrain() method. An object can have multiple constraints.
When constraints are violated, the paramerized object becomes infeasible (is_feasible property becomes False). This is useful for optimization problems where we want to ensure parameters stay within valid ranges.
Constraints are inherited by child functors - if functor f has a constraint and we create f2 = f + d, then f2 will inherit f's constraints.
The constraints can use all logical operators:
- Greater than (>)
- Less than (<)
- Equal to (==)
- Not equal to (!=)
- Greater than or equal to (>=)
- Less than or equal to (<=)
- AND (&)
- OR (|)
- NOT (~)
# Create parameters with boundaries
a = esc.par("A", "10+-30")
b = esc.par("B", "20+-40")
# Create variables
x = esc.var("X")
y = esc.var("Y")
# Create a functor with parameters
f = a * x**2 + b * y**2
# Add constraints: a^2 + b^2 > 100 AND a > 0 AND b > 0
c = (a**2 + b**2 > 100) & (a > 0) & (b > 0)
f.constrain(c)
print("Initial values: a =", a.value, ", b =", b.value)
print("Functor is feasible:", f.is_feasible)
# Change parameter values to make it infeasible
a.value = -10 # Violates a > 0
print("\nAfter setting a = -10:")
print("Functor is feasible:", f.is_feasible)
# Try another infeasible case
a.value = 10
b.value = -20 # Violates b > 0
print("\nAfter setting a = 10, b = -20:")
print("Functor is feasible:", f.is_feasible)
# Try values that violate a^2 + b^2 > 100
a.value = 1
b.value = 2
print("\nAfter setting a = 1, b = 2:")
print("Functor is feasible:", f.is_feasible)
# Set values back to feasible region
a.value = 10
b.value = 20
print("\nAfter setting a = 10, b = 20:")
print("Functor is feasible:", f.is_feasible)
Initial values: a = 10.0 , b = 20.0 Functor is feasible: True After setting a = -10: Functor is feasible: False After setting a = 10, b = -20: Functor is feasible: False After setting a = 1, b = 2: Functor is feasible: False After setting a = 10, b = 20: Functor is feasible: True