Skip to content

Commit e7d6ede

Browse files
committed
Add funcxy, funcx
1 parent 79d9dff commit e7d6ede

File tree

10 files changed

+74
-54
lines changed

10 files changed

+74
-54
lines changed

src/diffpy/morph/morph_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def morph(
209209
refpars.append("baselineslope")
210210
elif k == "funcy":
211211
morph_inst = morph_cls()
212-
morph_inst.function = rv_cfg.get("function", None)
212+
morph_inst.function = rv_cfg.get("funcy_function", None)
213213
if morph_inst.function is None:
214214
raise ValueError(
215215
"Must provide a 'function' when using 'parameters'"

src/diffpy/morph/morph_io.py

Lines changed: 31 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,40 +79,41 @@ def single_morph_output(
7979
rw_pos + idx, (f"squeeze a{idx}", sq_dict[f"a{idx}"])
8080
)
8181
mr_copy = dict(morph_results_list)
82-
func_function = None
83-
if "function" in mr_copy:
84-
func_function = mr_copy.pop("function")
85-
if "funcxy" in mr_copy:
86-
fxy_dict = mr_copy.pop("funcxy")
87-
rw_pos = list(mr_copy.keys()).index("Rw")
88-
morph_results_list = list(mr_copy.items())
89-
for idx, key in enumerate(fxy_dict):
90-
morph_results_list.insert(
91-
rw_pos + idx, (f"funcxy {key}", fxy_dict[key])
92-
)
93-
mr_copy = dict(morph_results_list)
94-
elif "funcy" in mr_copy:
95-
fy_dict = mr_copy.pop("funcy")
96-
rw_pos = list(mr_copy.keys()).index("Rw")
97-
morph_results_list = list(mr_copy.items())
98-
for idx, key in enumerate(fy_dict):
99-
morph_results_list.insert(
100-
rw_pos + idx, (f"funcy {key}", fy_dict[key])
101-
)
102-
mr_copy = dict(morph_results_list)
82+
83+
# Handle special inputs (functional remove)
84+
func_dicts = {
85+
"funcxy": [None, None],
86+
"funcx": [None, None],
87+
"funcy": [None, None],
88+
}
89+
for func in func_dicts.keys():
90+
if f"{func}_function" in mr_copy:
91+
func_dicts[func][0] = mr_copy.pop(f"{func}_function")
92+
if func in mr_copy:
93+
func_dicts[func][1] = mr_copy.pop(func)
94+
rw_pos = list(mr_copy.keys()).index("Rw")
95+
morph_results_list = list(mr_copy.items())
96+
for idx, key in enumerate(func_dicts[func][1]):
97+
morph_results_list.insert(
98+
rw_pos + idx, (f"{func} {key}", func_dicts[func][1][key])
99+
)
100+
mr_copy = dict(morph_results_list)
101+
103102
# Normal inputs
104103
morphs_out += "\n".join(
105104
f"# {key} = {mr_copy[key]:.6f}" for key in mr_copy.keys()
106105
)
107-
# Special inputs (functional)
108-
if func_function is not None:
109-
morphs_in += '# function =\n"""\n'
110-
f_code, _ = inspect.getsourcelines(func_function)
111-
n_leading = len(f_code[0]) - len(f_code[0].lstrip())
112-
for idx, f_line in enumerate(f_code):
113-
f_code[idx] = f_line[n_leading:]
114-
morphs_in += "".join(f_code)
115-
morphs_in += '"""\n'
106+
107+
# Handle special inputs (functional add)
108+
for func in func_dicts.keys():
109+
if func_dicts[func][0] is not None:
110+
morphs_in += f'# {func} function =\n"""\n'
111+
f_code, _ = inspect.getsourcelines(func_dicts[func][0])
112+
n_leading = len(f_code[0]) - len(f_code[0].lstrip())
113+
for idx, f_line in enumerate(f_code):
114+
f_code[idx] = f_line[n_leading:]
115+
morphs_in += "".join(f_code)
116+
morphs_in += '"""\n'
116117

117118
# Printing to terminal
118119
if stdout_flag:

src/diffpy/morph/morphapp.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ def custom_error(self, msg):
9999
parser.add_option(
100100
"--rmin",
101101
type="float",
102-
help="Minimum r-value to use for PDF comparisons.",
102+
help="Minimum r-value (abscissa) to use for function comparisons.",
103103
)
104104
parser.add_option(
105105
"--rmax",
106106
type="float",
107-
help="Maximum r-value to use for PDF comparisons.",
107+
help="Maximum r-value (abscissa) to use for function comparisons.",
108108
)
109109
parser.add_option(
110110
"--tolerance",
@@ -510,20 +510,26 @@ def single_morph(
510510

511511
# Python-Specific Morphs
512512
if pymorphs is not None:
513-
# funcxy value is a tuple (function,{param_dict})
513+
# funcxy/funcx/funcy value is a tuple (function,{param_dict})
514514
if "funcxy" in pymorphs:
515515
mfxy_function = pymorphs["funcxy"][0]
516516
mfxy_params = pymorphs["funcxy"][1]
517517
chain.append(morphs.MorphFuncxy())
518-
config["function"] = mfxy_function
518+
config["funcxy_function"] = mfxy_function
519519
config["funcxy"] = mfxy_params
520520
refpars.append("funcxy")
521-
# funcy value is a tuple (function,{param_dict})
522-
elif "funcy" in pymorphs:
521+
if "funcx" in pymorphs:
522+
mfx_function = pymorphs["funcx"][0]
523+
mfx_params = pymorphs["funcx"][1]
524+
chain.append(morphs.MorphFuncx())
525+
config["funcx_function"] = mfx_function
526+
config["funcx"] = mfx_params
527+
refpars.append("funcx")
528+
if "funcy" in pymorphs:
523529
mfy_function = pymorphs["funcy"][0]
524530
mfy_params = pymorphs["funcy"][1]
525531
chain.append(morphs.MorphFuncy())
526-
config["function"] = mfy_function
532+
config["funcy_function"] = mfy_function
527533
config["funcy"] = mfy_params
528534
refpars.append("funcy")
529535

@@ -690,6 +696,9 @@ def single_morph(
690696

691697
# FOR FUTURE MAINTAINERS
692698
# Any new morph should have their input morph parameters updated here
699+
# You should also update the IO in morph_io
700+
# if you think there requires special handling
701+
693702
# Input morph parameters
694703
morph_inputs = {
695704
"scale": scale_in,
@@ -712,11 +721,16 @@ def single_morph(
712721
]
713722
}
714723
)
715-
elif "funcy" in pymorphs:
724+
if "funcy" in pymorphs:
716725
for funcy_param in pymorphs["funcy"][1].keys():
717726
morph_inputs.update(
718727
{f"funcy {funcy_param}": pymorphs["funcy"][1][funcy_param]}
719728
)
729+
if "funcx" in pymorphs:
730+
for funcy_param in pymorphs["funcx"][1].keys():
731+
morph_inputs.update(
732+
{f"funcx {funcy_param}": pymorphs["funcx"][1][funcy_param]}
733+
)
720734

721735
# Output morph parameters
722736
morph_results = dict(config.items())

src/diffpy/morph/morphs/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from diffpy.morph.morphs.morph import Morph # noqa: F401
1919
from diffpy.morph.morphs.morphchain import MorphChain # noqa: F401
20+
from diffpy.morph.morphs.morphfuncx import MorphFuncx
2021
from diffpy.morph.morphs.morphfuncxy import MorphFuncxy
2122
from diffpy.morph.morphs.morphfuncy import MorphFuncy
2223
from diffpy.morph.morphs.morphishape import MorphISphere, MorphISpheroid
@@ -43,6 +44,7 @@
4344
MorphShift,
4445
MorphSqueeze,
4546
MorphFuncy,
47+
MorphFuncx,
4648
MorphFuncxy,
4749
]
4850

src/diffpy/morph/morphs/morphfuncx.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66

77
class MorphFuncx(Morph):
8-
"""Apply a custom function to the x-axis of the morph function.
8+
"""Apply a custom function to the x-axis (grid) of the morph
9+
function.
910
1011
General morph function that applies a user-supplied function to the
11-
y-coordinates of morph data to make it align with a target.
12+
x-coordinates of morph data to make it align with a target.
13+
14+
Notice: the morph should maintain the monotonicity of the grid.
1215
1316
Configuration Variables
1417
-----------------------
@@ -56,7 +59,7 @@ class MorphFuncx(Morph):
5659
>>> y_morph_in = morph.y_morph_in
5760
>>> x_target_in = morph.x_target_in
5861
>>> y_target_in = morph.y_target_in
59-
>>> parameters_out = morph.funcy
62+
>>> parameters_out = morph.funcx
6063
"""
6164

6265
# Define input output types
@@ -65,13 +68,13 @@ class MorphFuncx(Morph):
6568
yinlabel = LABEL_GR
6669
xoutlabel = LABEL_RA
6770
youtlabel = LABEL_GR
68-
parnames = ["function", "funcy"]
71+
parnames = ["funcx_function", "funcx"]
6972

7073
def morph(self, x_morph, y_morph, x_target, y_target):
71-
"""Apply the user-supplied Python function to the y-coordinates
74+
"""Apply the user-supplied Python function to the x-coordinates
7275
of the morph data."""
7376
Morph.morph(self, x_morph, y_morph, x_target, y_target)
74-
self.x_morph_out = self.function(
75-
self.x_morph_in, self.y_morph_in, **self.funcy
77+
self.x_morph_out = self.funcx_function(
78+
self.x_morph_in, self.y_morph_in, **self.funcx
7679
)
7780
return self.xyallout

src/diffpy/morph/morphs/morphfuncxy.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class MorphFuncxy(Morph):
5656
>>> y_morph_in = morph.y_morph_in
5757
>>> x_target_in = morph.x_target_in
5858
>>> y_target_in = morph.y_target_in
59-
>>> parameters_out = morph.funcy
59+
>>> parameters_out = morph.funcxy
6060
"""
6161

6262
# Define input output types
@@ -65,13 +65,13 @@ class MorphFuncxy(Morph):
6565
yinlabel = LABEL_GR
6666
xoutlabel = LABEL_RA
6767
youtlabel = LABEL_GR
68-
parnames = ["function", "funcxy"]
68+
parnames = ["funcxy_function", "funcxy"]
6969

7070
def morph(self, x_morph, y_morph, x_target, y_target):
7171
"""Apply the user-supplied Python function to the y-coordinates
7272
of the morph data."""
7373
Morph.morph(self, x_morph, y_morph, x_target, y_target)
74-
self.x_morph_out, self.y_morph_out = self.function(
74+
self.x_morph_out, self.y_morph_out = self.funcxy_function(
7575
self.x_morph_in, self.y_morph_in, **self.funcxy
7676
)
7777
return self.xyallout

src/diffpy/morph/morphs/morphfuncy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ class MorphFuncy(Morph):
6565
yinlabel = LABEL_GR
6666
xoutlabel = LABEL_RA
6767
youtlabel = LABEL_GR
68-
parnames = ["function", "funcy"]
68+
parnames = ["funcy_function", "funcy"]
6969

7070
def morph(self, x_morph, y_morph, x_target, y_target):
7171
"""Apply the user-supplied Python function to the y-coordinates
7272
of the morph data."""
7373
Morph.morph(self, x_morph, y_morph, x_target, y_target)
74-
self.y_morph_out = self.function(
74+
self.y_morph_out = self.funcy_function(
7575
self.x_morph_in, self.y_morph_in, **self.funcy
7676
)
7777
return self.xyallout

tests/test_morph_func.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def linear_function(x, y, scale, offset):
145145
x_target = x_morph.copy()
146146
y_target = np.sin(x_target) * 2 * x_target + 0.4
147147
cfg = morph_default_config(funcy={"scale": 1.2, "offset": 0.1})
148-
cfg["function"] = linear_function
148+
cfg["funcy_function"] = linear_function
149149
morph_rv = morph(x_morph, y_morph, x_target, y_target, **cfg)
150150
morphed_cfg = morph_rv["morphed_config"]
151151
x_morph_out, y_morph_out, x_target_out, y_target_out = morph_rv[

tests/test_morphfuncy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def test_funcy(function, parameters, expected_function):
6262
x_morph_expected = x_morph
6363
y_morph_expected = expected_function(x_morph, y_morph)
6464
morph = MorphFuncy()
65-
morph.function = function
65+
morph.funcy_function = function
6666
morph.funcy = parameters
6767
x_morph_actual, y_morph_actual, x_target_actual, y_target_actual = (
6868
morph.morph(x_morph, y_morph, x_target, y_target)

tests/testdata/funcy_target.cgr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# funcy a0 = 1.0
1414
# funcy a1 = 2.0
1515
# funcy a2 = 3.0
16-
# function =
16+
# funcy function =
1717
"""
1818
def quadratic(x, y, a0, a1, a2):
1919
return a0 + a1 * x + a2 * y**2

0 commit comments

Comments
 (0)