Skip to content

Commit c75bbe5

Browse files
committed
Add morphfuncxy (scrappy)
1 parent 322b75e commit c75bbe5

File tree

6 files changed

+115
-11
lines changed

6 files changed

+115
-11
lines changed

src/diffpy/morph/morph_io.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,19 @@ 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-
funcy_function = None
82+
func_function = None
8383
if "function" in mr_copy:
84-
funcy_function = mr_copy.pop("function")
85-
print(funcy_function)
86-
if "funcy" 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:
8795
fy_dict = mr_copy.pop("funcy")
8896
rw_pos = list(mr_copy.keys()).index("Rw")
8997
morph_results_list = list(mr_copy.items())
@@ -97,9 +105,9 @@ def single_morph_output(
97105
f"# {key} = {mr_copy[key]:.6f}" for key in mr_copy.keys()
98106
)
99107
# Special inputs (functional)
100-
if funcy_function is not None:
101-
morphs_in += '# funcy function =\n"""\n'
102-
f_code, _ = inspect.getsourcelines(funcy_function)
108+
if func_function is not None:
109+
morphs_in += '# function =\n"""\n'
110+
f_code, _ = inspect.getsourcelines(func_function)
103111
n_leading = len(f_code[0]) - len(f_code[0].lstrip())
104112
for idx, f_line in enumerate(f_code):
105113
f_code[idx] = f_line[n_leading:]

src/diffpy/morph/morphapp.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,8 +510,16 @@ def single_morph(
510510

511511
# Python-Specific Morphs
512512
if pymorphs is not None:
513+
# funcxy value is a tuple (function,{param_dict})
514+
if "funcxy" in pymorphs:
515+
mfxy_function = pymorphs["funcxy"][0]
516+
mfxy_params = pymorphs["funcxy"][1]
517+
chain.append(morphs.MorphFuncxy())
518+
config["function"] = mfxy_function
519+
config["funcxy"] = mfxy_params
520+
refpars.append("funcxy")
513521
# funcy value is a tuple (function,{param_dict})
514-
if "funcy" in pymorphs:
522+
elif "funcy" in pymorphs:
515523
mfy_function = pymorphs["funcy"][0]
516524
mfy_params = pymorphs["funcy"][1]
517525
chain.append(morphs.MorphFuncy())
@@ -695,7 +703,16 @@ def single_morph(
695703
for idx, _ in enumerate(squeeze_dict):
696704
morph_inputs.update({f"squeeze a{idx}": squeeze_dict[f"a{idx}"]})
697705
if pymorphs is not None:
698-
if "funcy" in pymorphs:
706+
if "funcxy" in pymorphs:
707+
for funcxy_param in pymorphs["funcxy"][1].keys():
708+
morph_inputs.update(
709+
{
710+
f"funcxy {funcxy_param}": pymorphs["funcxy"][1][
711+
funcxy_param
712+
]
713+
}
714+
)
715+
elif "funcy" in pymorphs:
699716
for funcy_param in pymorphs["funcy"][1].keys():
700717
morph_inputs.update(
701718
{f"funcy {funcy_param}": pymorphs["funcy"][1][funcy_param]}

src/diffpy/morph/morphpy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def get_args(parser, params, kwargs):
2121

2222
def __get_morph_opts__(parser, scale, stretch, smear, plot, **kwargs):
2323
# Check for Python-specific options
24-
python_morphs = ["funcy"]
24+
python_morphs = ["funcy", "funcx", "funcxy"]
2525
pymorphs = {}
2626
for pmorph in python_morphs:
2727
if pmorph in kwargs:

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.morphfuncxy import MorphFuncxy
2021
from diffpy.morph.morphs.morphfuncy import MorphFuncy
2122
from diffpy.morph.morphs.morphishape import MorphISphere, MorphISpheroid
2223
from diffpy.morph.morphs.morphresolution import MorphResolutionDamping
@@ -42,6 +43,7 @@
4243
MorphShift,
4344
MorphSqueeze,
4445
MorphFuncy,
46+
MorphFuncxy,
4547
]
4648

4749
# End of file
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
"""Class MorphFuncxy -- apply a user-supplied python function to the x
2+
and y axes."""
3+
4+
from diffpy.morph.morphs.morph import LABEL_GR, LABEL_RA, Morph
5+
6+
7+
class MorphFuncxy(Morph):
8+
"""Apply a custom function to the y-axis of the morph function.
9+
10+
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+
13+
Configuration Variables
14+
-----------------------
15+
function: callable
16+
The user-supplied function that applies a transformation to the
17+
y-coordinates of the data.
18+
19+
parameters: dict
20+
A dictionary of parameters to pass to the function.
21+
22+
Returns
23+
-------
24+
A tuple (x_morph_out, y_morph_out, x_target_out, y_target_out)
25+
where the target values remain the same and the morph data is
26+
transformed according to the user-specified function and parameters
27+
The morphed data is returned on the same grid as the unmorphed data
28+
29+
Example
30+
-------
31+
Import the funcy morph function:
32+
33+
>>> from diffpy.morph.morphs.morphfuncy import MorphFuncy
34+
35+
Define or import the user-supplied transformation function:
36+
37+
>>> def sine_function(x, y, amplitude, frequency):
38+
>>> return amplitude * np.sin(frequency * x) * y
39+
40+
Provide initial guess for parameters:
41+
42+
>>> parameters = {'amplitude': 2, 'frequency': 2}
43+
44+
Run the funcy morph given input morph array (x_morph, y_morph)and target
45+
array (x_target, y_target):
46+
47+
>>> morph = MorphFuncy()
48+
>>> morph.function = sine_function
49+
>>> morph.funcy = parameters
50+
>>> x_morph_out, y_morph_out, x_target_out, y_target_out =
51+
... morph.morph(x_morph, y_morph, x_target, y_target)
52+
53+
To access parameters from the morph instance:
54+
55+
>>> x_morph_in = morph.x_morph_in
56+
>>> y_morph_in = morph.y_morph_in
57+
>>> x_target_in = morph.x_target_in
58+
>>> y_target_in = morph.y_target_in
59+
>>> parameters_out = morph.funcy
60+
"""
61+
62+
# Define input output types
63+
summary = "Apply a Python function to the y-axis data"
64+
xinlabel = LABEL_RA
65+
yinlabel = LABEL_GR
66+
xoutlabel = LABEL_RA
67+
youtlabel = LABEL_GR
68+
parnames = ["function", "funcxy"]
69+
70+
def morph(self, x_morph, y_morph, x_target, y_target):
71+
"""Apply the user-supplied Python function to the y-coordinates
72+
of the morph data."""
73+
Morph.morph(self, x_morph, y_morph, x_target, y_target)
74+
self.x_morph_out, self.y_morph_out = self.function(
75+
self.x_morph_in, self.y_morph_in, **self.funcxy
76+
)
77+
return self.xyallout

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-
# funcy function =
16+
# function =
1717
"""
1818
def quadratic(x, y, a0, a1, a2):
1919
return a0 + a1 * x + a2 * y**2

0 commit comments

Comments
 (0)