Skip to content

Commit f22b5f5

Browse files
authored
Add tolerance option (#217)
1 parent 651fad5 commit f22b5f5

File tree

4 files changed

+86
-6
lines changed

4 files changed

+86
-6
lines changed

news/tolerance.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* Option to set tolerance for the morph refinement (default 1e-08).
4+
5+
**Changed:**
6+
7+
* <news item>
8+
9+
**Deprecated:**
10+
11+
* <news item>
12+
13+
**Removed:**
14+
15+
* <news item>
16+
17+
**Fixed:**
18+
19+
* <news item>
20+
21+
**Security:**
22+
23+
* <news item>

src/diffpy/morph/morphapp.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ def custom_error(self, msg):
104104
type="float",
105105
help="Maximum r-value to use for PDF comparisons.",
106106
)
107+
parser.add_option(
108+
"--tolerance",
109+
"-t",
110+
type="float",
111+
metavar="TOL",
112+
help="Specify refiner tolerance as TOL. Default: 10e-8.",
113+
)
107114
parser.add_option(
108115
"--pearson",
109116
action="store_true",
@@ -444,6 +451,11 @@ def single_morph(parser, opts, pargs, stdout_flag=True):
444451
if y_target is None:
445452
parser.error(f"No data table found in file: {pargs[1]}.")
446453

454+
# Get tolerance
455+
tolerance = 1e-08
456+
if opts.tolerance is not None:
457+
tolerance = opts.tolerance
458+
447459
# Get configuration values
448460
scale_in = "None"
449461
stretch_in = "None"
@@ -558,7 +570,9 @@ def single_morph(parser, opts, pargs, stdout_flag=True):
558570
refpars = list(set(refpars) - set(opts.exclude))
559571

560572
# Refine or execute the morph
561-
refiner = refine.Refiner(chain, x_morph, y_morph, x_target, y_target)
573+
refiner = refine.Refiner(
574+
chain, x_morph, y_morph, x_target, y_target, tolerance=tolerance
575+
)
562576
if opts.pearson:
563577
refiner.residual = refiner._pearson
564578
if opts.addpearson:

src/diffpy/morph/refine.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,15 @@ class Refiner(object):
4242
to other functions.
4343
"""
4444

45-
def __init__(self, chain, x_morph, y_morph, x_target, y_target):
45+
def __init__(
46+
self, chain, x_morph, y_morph, x_target, y_target, tolerance=1e-08
47+
):
4648
self.chain = chain
4749
self.x_morph = x_morph
4850
self.y_morph = y_morph
4951
self.x_target = x_target
5052
self.y_target = y_target
53+
self.tolerance = tolerance
5154
self.pars = []
5255
self.residual = self._residual
5356
self.flat_to_grouped = {}
@@ -143,7 +146,11 @@ def refine(self, *args, **kw):
143146
self.flat_to_grouped[len(initial) - 1] = (p, None)
144147

145148
sol, cov_sol, infodict, emesg, ier = leastsq(
146-
self.residual, initial, full_output=1
149+
self.residual,
150+
initial,
151+
full_output=1,
152+
ftol=self.tolerance,
153+
xtol=self.tolerance,
147154
)
148155
fvec = infodict["fvec"]
149156

tests/test_refine.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def test_refine_morph(self, setup):
4646

4747
assert (x_morph == x_target).all()
4848
assert numpy.allclose(y_morph, y_target)
49-
pytest.approx(config["scale"], 3.0)
49+
assert pytest.approx(config["scale"]) == 3.0
5050
return
5151

5252
def test_refine_chain(self, setup):
@@ -74,8 +74,44 @@ def test_refine_chain(self, setup):
7474
err = 15.0 * 2
7575
res = sum(numpy.fabs(y_target - y_morph))
7676
assert res < err
77-
pytest.approx(chain.scale, 3, 2)
78-
pytest.approx(chain.stretch, 0.1, 2)
77+
assert pytest.approx(chain.scale, 0.01, 0.01) == 3.0
78+
assert pytest.approx(chain.stretch, 0.01, 0.01) == 0.1
79+
return
80+
81+
def test_refine_tolerance(self, setup):
82+
# Check that small tolerance gives good result
83+
stol = 1e-16
84+
config = {
85+
"scale": 1.0,
86+
}
87+
mscale = MorphScale(config)
88+
refiner = Refiner(
89+
mscale,
90+
self.x_morph,
91+
self.y_morph,
92+
self.x_target,
93+
self.y_target,
94+
tolerance=stol,
95+
)
96+
refiner.refine()
97+
assert pytest.approx(config["scale"], stol, stol) == 3.0
98+
99+
# Check that larger tolerance does not give as good of result
100+
ltol = 100
101+
config = {
102+
"scale": 1.0,
103+
}
104+
mscale = MorphScale(config)
105+
refiner = Refiner(
106+
mscale,
107+
self.x_morph,
108+
self.y_morph,
109+
self.x_target,
110+
self.y_target,
111+
tolerance=ltol,
112+
)
113+
refiner.refine()
114+
assert not pytest.approx(config["scale"], stol, stol) == 3.0
79115
return
80116

81117

0 commit comments

Comments
 (0)