From 0ce58a96e038d66a38d03cc36a7300023221082a Mon Sep 17 00:00:00 2001 From: ksunden Date: Mon, 18 Feb 2019 00:22:48 -0600 Subject: [PATCH 1/9] Re-write Topas curve IO --- attune/curve/_base.py | 7 +- attune/curve/_dependent.py | 3 +- attune/curve/_topas.py | 264 +++++++++--------- .../OPA1 (10743) base - 2018-10-26 40490.crv | 2 +- tests/TopasCurve/add/xkloo.py | 6 +- tests/TopasCurve/read/2018-10-26/niuce.py | 8 +- 6 files changed, 147 insertions(+), 143 deletions(-) diff --git a/attune/curve/_base.py b/attune/curve/_base.py index e3982a4..29979e9 100644 --- a/attune/curve/_base.py +++ b/attune/curve/_base.py @@ -36,6 +36,7 @@ def __init__( subcurve=None, source_setpoints=None, fmt=None, + **kwargs, ): """Create a ``Curve`` object. @@ -79,6 +80,8 @@ def __init__( fmt = ["%.2f"] + ["%.5f"] * len(self.dependents) self.fmt = fmt self.interpolate() + for k, v in kwargs.items(): + setattr(self, k, v) def __add__(self, other): # copy @@ -130,7 +133,9 @@ def __setitem__(self, key, value): if value.interpolator is not None: value.positions = value(self.setpoints[:], self.setpoints.units) elif len(value) != len(self.setpoints): - raise ValueError(f"Incorrect number of points in dependent: {len(value)} for number of setpoints: {len(self.setpoints)}") + raise ValueError( + f"Incorrect number of points in dependent: {len(value)} for number of setpoints: {len(self.setpoints)}" + ) value.interpolator = self.method(self.setpoints, value) self.dependents[key] = value diff --git a/attune/curve/_dependent.py b/attune/curve/_dependent.py index 6c79722..38f8de0 100644 --- a/attune/curve/_dependent.py +++ b/attune/curve/_dependent.py @@ -30,7 +30,7 @@ class Setpoints(Variable): class Dependent(Variable): """Container class for dependent arrays.""" - def __init__(self, positions, name, units=None, differential=False): + def __init__(self, positions, name, units=None, differential=False, index=None): """Create a ``Dependent`` object. Parameters @@ -43,6 +43,7 @@ def __init__(self, positions, name, units=None, differential=False): super(Dependent, self).__init__(positions, name, units=units) self.interpolator = None self.differential = differential + self.index = index def __call__(self, val, units="same"): return self.interpolator(val, units) diff --git a/attune/curve/_topas.py b/attune/curve/_topas.py index 66a33d0..acbed49 100644 --- a/attune/curve/_topas.py +++ b/attune/curve/_topas.py @@ -51,7 +51,7 @@ class TopasCurve(Curve): @classmethod - def read(cls, filepaths, kind, interaction_string): + def read(cls, filepaths, interaction_string): """Create a curve object from a TOPAS crv file. Parameters @@ -59,8 +59,6 @@ def read(cls, filepaths, kind, interaction_string): filepaths : list of str [base, mixer 1, mixer 2, mixer 3] Paths to all crv files for OPA. Filepaths may be None if not needed / not applicable. - kind : {'TOPAS-C', 'TOPAS-800'} - The kind of TOPAS represented. interaction_string : str Interaction string for this curve, in the style of Light Conversion - e.g. 'NON-SF-NON-Sig'. @@ -69,58 +67,81 @@ def read(cls, filepaths, kind, interaction_string): ------- WrightTools.tuning.curve.TopasCurve object """ - TOPAS_interactions = TOPAS_interaction_by_kind[kind] - # setup to recursively import data - interactions = interaction_string.split("-") - interaction_strings = [] # most subservient tuning curve comes first - idx = 3 - while idx >= 0: - if not interactions[idx] == "NON": - interaction_strings.append("NON-" * idx + "-".join(interactions[idx:])) - idx -= 1 - # create curve objects, starting from most subservient curve - subcurve = None - for interaction_string in interaction_strings: - # open appropriate crv - interactions = interaction_string.split("-") - curve_index = next((i for i, v in enumerate(interactions) if v != "NON"), -1) - crv_path = filepaths[-(curve_index + 1)] - with open(crv_path, "r") as crv: - crv_lines = crv.readlines() - # collect information from file - for i in range(len(crv_lines)): - if crv_lines[i].rstrip() == interaction_string: - line_index = i + TOPAS_interactions[interaction_string][0] - num_tune_points = int(crv_lines[line_index - 1]) - # get the actual array - lis = [] - for i in range(line_index, line_index + num_tune_points): - line_arr = np.fromstring(crv_lines[i], sep="\t") - lis.append(line_arr) - arr = np.array(lis).T - # create the curve - source_setpoints = Dependent(arr[0], "source setpoints") + return cls.read_all(filepaths)[interaction_string] + + @classmethod + def read_all(cls, filepaths): + curves = {} + for f in filepaths: + curves.update(cls._read_file(f)) + for i, c in curves.items(): + interaction = i.split("-") + for j, part in enumerate(interaction): + if part != "NON": + interaction[j] = "NON" + break + interaction = "-".join(interaction) + if interaction in curves: + c.subcurve = curves[interaction] + return curves + + @classmethod + def _read_file(cls, filepath): + ds = np.DataSource(None) + f = ds.open(str(filepath), "rt") + head = f.readline().strip() + if head != "600": + warnings.warn(f"Unexpected header {head}, expected '600'") + kind = f.readline().strip() + config = {} + if kind == "OPA/NOPA": + kind = "OPA" if f.readline().strip() == "0" else "NOPA" + config["use grating equation"] = f.readline().strip() == "1" + config["grating motor index"] = int(f.readline()) + config["grating constant"] = float(f.readline()) + config["maximum grating position"] = float(f.readline()) + n_motors = int(f.readline()) + motor_indexes = np.fromstring(f.readline(), dtype=int, sep="\t") + n_curves = int(f.readline().strip()) + curves = {} + for _ in range(n_curves): + interaction_string = f.readline().strip() + comment = "" + for _a in range(int(f.readline())): + comment += f.readline() + + # TODO: Check H/V + polarization = "H" if int(f.readline()) else "V" + pump_wavelength = float(f.readline()) + f.readline() # n_motors + offsets = np.fromstring(f.readline(), dtype=float, sep="\t") + npts = int(f.readline()) + strings = [f.readline().strip() for _ in range(npts)] + arr = np.genfromtxt(strings, delimiter="\t", max_rows=npts, filling_values=np.nan).T + source_setpoints = Dependent(arr[0], "source", "nm") + setpoints = Setpoints(arr[1], "output", "nm") dependents = [] - for i in range(3, len(arr)): - dependent_name = TOPAS_interactions[interaction_string][1][i - 3] - dependent = Dependent(arr[i], dependent_name) - dependents.append(dependent) - name = pathlib.Path(crv_path).stem - setpoints = Setpoints(arr[1], "Setpoints", "nm") - curve = cls( - setpoints, - dependents, - name, - interaction_string, - kind, - method=Linear, - subcurve=subcurve, - source_setpoints=source_setpoints, - ) - subcurve = curve.copy() - # finish - setattr(curve, "old_filepaths", filepaths) - return curve + for i in range(n_motors): + name = str(motor_indexes[i]) + units = None + dependents.append(Dependent(arr[i + 3], name, units, index=motor_indexes[i])) + # TODO: figure out what namem should default to + name = interaction_string + curves[interaction_string] = cls( + setpoints, + dependents, + name=name, + interaction=interaction_string, + kind=kind, + source_setpoints=source_setpoints, + polarization=polarization, + pump_wavelength=pump_wavelength, + config=config, + motor_indexes=motor_indexes, + comment=comment, + offsets=offsets, + ) + return curves def save(self, save_directory, full=True): """Save a curve object. @@ -139,103 +160,78 @@ def save(self, save_directory, full=True): string Output path. """ - TOPAS_interactions = TOPAS_interaction_by_kind[self.kind] # unpack curve = self.copy() curve.convert("nm") - old_filepaths = self.old_filepaths interaction_string = curve.interaction - # open appropriate crv - interactions = interaction_string.split("-") - curve_index = next((i for i, v in enumerate(interactions) if v != "NON"), -1) - curve_index += 1 - curve_index = len(old_filepaths) - curve_index - crv_path = old_filepaths[curve_index] - save_directory = pathlib.Path(save_directory) - save_directory.mkdir(parents=True, exist_ok=True) - if full: - # copy other curves over as well - for i, p in enumerate(old_filepaths): - print(i, p, curve_index) - if i == curve_index: - continue - if p is None: - continue - print(i, p) - p = pathlib.Path(p) - d = save_directory / p.name - shutil.copy(p, d) - with open(crv_path, "r") as crv: - crv_lines = crv.readlines() - # collect information from file - for i in range(len(crv_lines)): - if crv_lines[i].rstrip() == interaction_string: - line_index = i + TOPAS_interactions[interaction_string][0] - - num_tune_points = int(crv_lines[line_index - 1]) - # construct to_insert (dictionary of arrays) + to_insert = {} if interaction_string == "NON-NON-NON-Idl": - spitfire_output = float(crv_lines[line_index - 4].rstrip()) - to_insert["NON-NON-NON-Sig"] = _convert(_insert(curve, TOPAS_interactions[interaction_string][1]), spitfire_output) - to_insert[interaction_string] = _insert(curve, TOPAS_interactions[interaction_string][1]) + to_insert["NON-NON-NON-Sig"] = ( + _convert(_insert(curve), curve.pump_wavelength), + not curve.polarization, + ) + to_insert[interaction_string] = (_insert(curve), curve.polarization) if interaction_string == "NON-NON-NON-Sig": - spitfire_output = float(crv_lines[line_index - 4].rstrip()) - to_insert["NON-NON-NON-Idl"] = _convert(_insert(curve, TOPAS_interactions[interaction_string][1]), spitfire_output) - # generate output - out_lines = copy.copy(crv_lines) - for interaction_string, arr in to_insert.items(): - # get current properties of out_lines - for i in range(len(crv_lines)): - if crv_lines[i].rstrip() == interaction_string: - line_index = i + TOPAS_interactions[interaction_string][0] - num_tune_points = int(crv_lines[line_index - 1]) - # prepare array for addition - arr = arr.T - # TOPAS wants curves to be ascending in nm - # curves get added 'backwards' here - # so arr should be decending in nm - if arr[0, 1] < arr[-1, 1]: - arr = np.flipud(arr) - # remove old points - del out_lines[line_index - 1 : line_index + num_tune_points] - # add strings to out_lines - for row in arr: - line = "" - for value in row: - # the number of motors must be written as an integer for TOPAS - if value in [1, 3, 4]: - value_as_string = str(int(value)) - else: - value_as_string = "%f.6" % value - portion_before_decimal = value_as_string.split(".")[0] - portion_after_decimal = value_as_string.split(".")[1].ljust(6, "0") - value_as_string = portion_before_decimal + "." + portion_after_decimal - line += value_as_string + "\t" - line += "\n" - out_lines.insert(line_index - 1, line) - out_lines.insert( - line_index - 1, str(len(arr)) + "\n" - ) # number of points of new curve - # filename + to_insert["NON-NON-NON-Idl"] = ( + _convert(_insert(curve), curve.pump_wavelength), + not curve.polarization, + ) + + save_directory = pathlib.Path(save_directory) + save_directory.mkdir(parents=True, exist_ok=True) timestamp = wt.kit.TimeStamp().path out_name = curve.name.split("-")[0] + "- " + timestamp out_path = (save_directory / out_name).with_suffix(".crv") - # save + with open(out_path, "w") as new_crv: - new_crv.write("".join(out_lines).rstrip()) + new_crv.write("600\r\n") + if curve.kind in "OPA/NOPA": + new_crv.write("OPA/NOPA\r\n") + new_crv.write(f"{int(curve.kind=='NOPA')}\r\n") + new_crv.write(f"{int(curve.config.get('use grating equation', 0))}\r\n") + new_crv.write(f"{curve.config.get('grating motor index', -1)}\r\n") + new_crv.write(f"{curve.config.get('grating constant', 0)}\r\n") + new_crv.write(f"{curve.config.get('maximum grating position', 0)}\r\n") + new_crv.write(f"{len(curve.dependents)}\r\n") + new_crv.write("\t".join(str(i) for i in curve.motor_indexes)) + new_crv.write("\r\n") + new_crv.write(f"{len(to_insert)}\r\n") + for k, v in to_insert.items(): + array, polarization = v + array = array.T + new_crv.write(k + "\r\n") + if curve.comment[-1] != "\n": + curve.comment += "\r\n" + num_lines = curve.comment.count("\n") + new_crv.write(f"{num_lines}\r\n") + new_crv.write(curve.comment) + new_crv.write(f"{int(polarization=='H')}\r\n") + new_crv.write(f"{curve.pump_wavelength}\r\n") + new_crv.write(f"{len(curve.dependents)}\r\n") + new_crv.write("\t".join(str(i) for i in curve.offsets)) + new_crv.write("\r\n") + new_crv.write(f"{len(array)}\r\n") + fmt = ["%0.6f"] * len(array.T) + fmt[2] = "%0.f" # this field is an int + np.savetxt(new_crv, array, fmt=fmt, delimiter="\t", newline="\r\n") return out_path -def _insert(curve, motors): - arr = np.empty((len(motors) + 3, len(curve.setpoints[:]))) + +def _insert(curve): + motor_indexes = curve.motor_indexes + arr = np.empty((len(motor_indexes) + 3, len(curve.setpoints))) arr[0] = curve.source_setpoints[:] arr[1] = curve.setpoints[:] - arr[2] = len(motors) - for i, m in enumerate(motors): - arr[3 + i] = curve[m][:] + arr[2] = len(motor_indexes) + print(motor_indexes) + for i, m in enumerate(motor_indexes): + arr[3 + i] = next(d for d in curve.dependents.values() if d.index == m)[:] return arr + def _convert(arr, sum_): arr = np.copy(arr) - arr[1] = 1 / ((1 / sum_) - (1 / arr[0])) + arr[1] = 1 / ((1 / sum_) - (1 / arr[1])) + arr = arr[:, ::-1] return arr diff --git a/tests/TopasCurve/add/OPA1 (10743) base - 2018-10-26 40490.crv b/tests/TopasCurve/add/OPA1 (10743) base - 2018-10-26 40490.crv index 4068cd5..a0cc53e 100644 --- a/tests/TopasCurve/add/OPA1 (10743) base - 2018-10-26 40490.crv +++ b/tests/TopasCurve/add/OPA1 (10743) base - 2018-10-26 40490.crv @@ -73,4 +73,4 @@ NON-NON-NON-Idl 795.000000 2355.555556 4 -8.862022 2.220362 6.647657 56.954180 795.000000 2436.623377 4 -9.017717 2.201328 6.840363 56.867483 795.000000 2526.575342 4 -9.175520 2.179907 7.040502 56.767563 -795.000000 2626.956522 4 -9.343733 2.154716 7.259192 56.647702 \ No newline at end of file +795.000000 2626.956522 4 -9.343733 2.154716 7.259192 56.647702 diff --git a/tests/TopasCurve/add/xkloo.py b/tests/TopasCurve/add/xkloo.py index ecf5b22..150b96c 100644 --- a/tests/TopasCurve/add/xkloo.py +++ b/tests/TopasCurve/add/xkloo.py @@ -14,13 +14,13 @@ def test_add_differential(): __here__ / "OPA1 (10743) mixer2 - 2018-10-07 47923.crv", __here__ / "OPA1 (10743) mixer3 - 2013.06.01.crv", ] - curve = attune.TopasCurve.read(paths, kind="TOPAS-C", interaction_string="NON-NON-NON-Sig") + curve = attune.TopasCurve.read(paths, interaction_string="NON-NON-NON-Sig") - d = attune.Dependent(np.ones(len(curve["Crystal_1"][:])), "Crystal_1", differential=True) + d = attune.Dependent(np.ones(len(curve["0"][:])), "0", differential=True) s = curve.setpoints diff = attune.Curve(s, [d], "diff") c = curve + diff assert isinstance(c, attune.TopasCurve) - assert np.allclose(curve["Crystal_1"][:], c["Crystal_1"][:] - 1) + assert np.allclose(curve["0"][:], c["0"][:] - 1) diff --git a/tests/TopasCurve/read/2018-10-26/niuce.py b/tests/TopasCurve/read/2018-10-26/niuce.py index c3a8327..3899ee9 100644 --- a/tests/TopasCurve/read/2018-10-26/niuce.py +++ b/tests/TopasCurve/read/2018-10-26/niuce.py @@ -15,9 +15,10 @@ def test_is_instance(): __here__ / "OPA1 (10743) mixer2 - 2018-10-07 47923.crv", __here__ / "OPA1 (10743) mixer3 - 2013.06.01.crv", ] - curve = attune.TopasCurve.read(paths, kind="TOPAS-C", interaction_string="NON-NON-NON-Sig") + curve = attune.TopasCurve.read(paths, interaction_string="NON-NON-NON-Sig") assert isinstance(curve, attune.TopasCurve) + def test_round_trip(): paths = [ __here__ / "OPA1 (10743) base - 2018-10-26 40490.crv", @@ -25,15 +26,16 @@ def test_round_trip(): __here__ / "OPA1 (10743) mixer2 - 2018-10-07 47923.crv", __here__ / "OPA1 (10743) mixer3 - 2013.06.01.crv", ] - curve = attune.TopasCurve.read(paths, kind="TOPAS-C", interaction_string="NON-SH-NON-Sig") + curve = attune.TopasCurve.read(paths, interaction_string="NON-SH-NON-Sig") with tempfile.TemporaryDirectory() as td: td = pathlib.Path(td) paths[2] = curve.save(save_directory=td) - read_curve = attune.TopasCurve.read(paths, kind="TOPAS-C", interaction_string="NON-SH-NON-Sig") + read_curve = attune.TopasCurve.read(paths, interaction_string="NON-SH-NON-Sig") assert np.allclose(curve.setpoints[:], read_curve.setpoints[:]) assert curve.dependent_names == read_curve.dependent_names for d1, d2 in zip(curve.dependents, read_curve.dependents): assert np.allclose(curve[d1][:], read_curve[d2][:]) + if __name__ == "__main__": test_is_instance() From 4fb394226703408aedf1504f6b79dd46eae3ed20 Mon Sep 17 00:00:00 2001 From: ksunden Date: Mon, 18 Feb 2019 00:56:15 -0600 Subject: [PATCH 2/9] Forgot to print kind --- attune/curve/_topas.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/attune/curve/_topas.py b/attune/curve/_topas.py index acbed49..00625a2 100644 --- a/attune/curve/_topas.py +++ b/attune/curve/_topas.py @@ -193,6 +193,8 @@ def save(self, save_directory, full=True): new_crv.write(f"{curve.config.get('grating motor index', -1)}\r\n") new_crv.write(f"{curve.config.get('grating constant', 0)}\r\n") new_crv.write(f"{curve.config.get('maximum grating position', 0)}\r\n") + else: + new_crv.write(f"{curve.kind}\r\n") new_crv.write(f"{len(curve.dependents)}\r\n") new_crv.write("\t".join(str(i) for i in curve.motor_indexes)) new_crv.write("\r\n") From 20540558546430156ac42fc7eccedc7d220e7d0f Mon Sep 17 00:00:00 2001 From: Kyle Sunden Date: Mon, 18 Feb 2019 10:14:31 -0600 Subject: [PATCH 3/9] Add close --- attune/curve/_topas.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/attune/curve/_topas.py b/attune/curve/_topas.py index 00625a2..cd71d98 100644 --- a/attune/curve/_topas.py +++ b/attune/curve/_topas.py @@ -1,8 +1,6 @@ import numpy as np import pathlib -import shutil -import copy -from ._base import Curve, Linear +from ._base import Curve from ._dependent import Setpoints, Dependent import WrightTools as wt @@ -141,6 +139,7 @@ def _read_file(cls, filepath): comment=comment, offsets=offsets, ) + f.close() return curves def save(self, save_directory, full=True): From e2be478a81f7c3fc21165d6151b969d7cc440c47 Mon Sep 17 00:00:00 2001 From: wright_stuff Date: Mon, 18 Feb 2019 10:29:52 -0600 Subject: [PATCH 4/9] remove \r which was causing problems on windows --- attune/curve/_topas.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/attune/curve/_topas.py b/attune/curve/_topas.py index cd71d98..79b8850 100644 --- a/attune/curve/_topas.py +++ b/attune/curve/_topas.py @@ -184,38 +184,38 @@ def save(self, save_directory, full=True): out_path = (save_directory / out_name).with_suffix(".crv") with open(out_path, "w") as new_crv: - new_crv.write("600\r\n") + new_crv.write("600\n") if curve.kind in "OPA/NOPA": - new_crv.write("OPA/NOPA\r\n") - new_crv.write(f"{int(curve.kind=='NOPA')}\r\n") - new_crv.write(f"{int(curve.config.get('use grating equation', 0))}\r\n") - new_crv.write(f"{curve.config.get('grating motor index', -1)}\r\n") - new_crv.write(f"{curve.config.get('grating constant', 0)}\r\n") - new_crv.write(f"{curve.config.get('maximum grating position', 0)}\r\n") + new_crv.write("OPA/NOPA\n") + new_crv.write(f"{int(curve.kind=='NOPA')}\n") + new_crv.write(f"{int(curve.config.get('use grating equation', 0))}\n") + new_crv.write(f"{curve.config.get('grating motor index', -1)}\n") + new_crv.write(f"{curve.config.get('grating constant', 0)}\n") + new_crv.write(f"{curve.config.get('maximum grating position', 0)}\n") else: - new_crv.write(f"{curve.kind}\r\n") - new_crv.write(f"{len(curve.dependents)}\r\n") + new_crv.write(f"{curve.kind}\n") + new_crv.write(f"{len(curve.dependents)}\n") new_crv.write("\t".join(str(i) for i in curve.motor_indexes)) - new_crv.write("\r\n") - new_crv.write(f"{len(to_insert)}\r\n") + new_crv.write("\n") + new_crv.write(f"{len(to_insert)}\n") for k, v in to_insert.items(): array, polarization = v array = array.T - new_crv.write(k + "\r\n") + new_crv.write(k + "\n") if curve.comment[-1] != "\n": - curve.comment += "\r\n" + curve.comment += "\n" num_lines = curve.comment.count("\n") - new_crv.write(f"{num_lines}\r\n") + new_crv.write(f"{num_lines}\n") new_crv.write(curve.comment) - new_crv.write(f"{int(polarization=='H')}\r\n") - new_crv.write(f"{curve.pump_wavelength}\r\n") - new_crv.write(f"{len(curve.dependents)}\r\n") + new_crv.write(f"{int(polarization=='H')}\n") + new_crv.write(f"{curve.pump_wavelength}\n") + new_crv.write(f"{len(curve.dependents)}\n") new_crv.write("\t".join(str(i) for i in curve.offsets)) - new_crv.write("\r\n") - new_crv.write(f"{len(array)}\r\n") + new_crv.write("\n") + new_crv.write(f"{len(array)}\n") fmt = ["%0.6f"] * len(array.T) fmt[2] = "%0.f" # this field is an int - np.savetxt(new_crv, array, fmt=fmt, delimiter="\t", newline="\r\n") + np.savetxt(new_crv, array, fmt=fmt, delimiter="\t", newline="\n") return out_path From f8f1845c4016eb50cec80409bceef479eab4d3d7 Mon Sep 17 00:00:00 2001 From: Kyle Sunden Date: Mon, 18 Feb 2019 15:25:09 -0600 Subject: [PATCH 5/9] Curve family relationships and saving --- attune/curve/_base.py | 10 ++ attune/curve/_topas.py | 136 +++++++++++++--------- tests/TopasCurve/read/2018-10-26/niuce.py | 2 +- 3 files changed, 95 insertions(+), 53 deletions(-) diff --git a/attune/curve/_base.py b/attune/curve/_base.py index 29979e9..a5cdc11 100644 --- a/attune/curve/_base.py +++ b/attune/curve/_base.py @@ -336,6 +336,16 @@ def map_setpoints(self, setpoints, units="same"): for obj in self.dependents.values(): setattr(self, obj.name, obj) self.interpolate() + + def sort(self): + order = self.setpoints[:].argsort() + self.setpoints[:] = self.setpoints[order] + if self.subcurve_setpoints: + self.subcurve_setpoints[:] = self.subcurve_setpoints[order] + + for d in self.dependents.values(): + d[:] = d[order] + def offset_by(self, dependent, amount): """Offset a dependent by some ammount. diff --git a/attune/curve/_topas.py b/attune/curve/_topas.py index 79b8850..abaaa59 100644 --- a/attune/curve/_topas.py +++ b/attune/curve/_topas.py @@ -81,6 +81,7 @@ def read_all(cls, filepaths): interaction = "-".join(interaction) if interaction in curves: c.subcurve = curves[interaction] + curves[interaction].supercurves.append(c) return curves @classmethod @@ -139,6 +140,9 @@ def _read_file(cls, filepath): comment=comment, offsets=offsets, ) + for key,value in curves.items(): + setattr(value, "siblings", [v for k,v in curves.items() if key != k]) + setattr(value, "supercurves", []) f.close() return curves @@ -165,59 +169,54 @@ def save(self, save_directory, full=True): interaction_string = curve.interaction to_insert = {} + if full: + to_insert = curve._get_family_dict() if interaction_string == "NON-NON-NON-Idl": - to_insert["NON-NON-NON-Sig"] = ( - _convert(_insert(curve), curve.pump_wavelength), - not curve.polarization, - ) - to_insert[interaction_string] = (_insert(curve), curve.polarization) + to_insert["NON-NON-NON-Sig"] = _convert(curve) + to_insert[interaction_string] = curve if interaction_string == "NON-NON-NON-Sig": - to_insert["NON-NON-NON-Idl"] = ( - _convert(_insert(curve), curve.pump_wavelength), - not curve.polarization, - ) + to_insert["NON-NON-NON-Idl"] = _convert(curve) save_directory = pathlib.Path(save_directory) save_directory.mkdir(parents=True, exist_ok=True) timestamp = wt.kit.TimeStamp().path - out_name = curve.name.split("-")[0] + "- " + timestamp - out_path = (save_directory / out_name).with_suffix(".crv") - - with open(out_path, "w") as new_crv: - new_crv.write("600\n") - if curve.kind in "OPA/NOPA": - new_crv.write("OPA/NOPA\n") - new_crv.write(f"{int(curve.kind=='NOPA')}\n") - new_crv.write(f"{int(curve.config.get('use grating equation', 0))}\n") - new_crv.write(f"{curve.config.get('grating motor index', -1)}\n") - new_crv.write(f"{curve.config.get('grating constant', 0)}\n") - new_crv.write(f"{curve.config.get('maximum grating position', 0)}\n") - else: - new_crv.write(f"{curve.kind}\n") - new_crv.write(f"{len(curve.dependents)}\n") - new_crv.write("\t".join(str(i) for i in curve.motor_indexes)) - new_crv.write("\n") - new_crv.write(f"{len(to_insert)}\n") - for k, v in to_insert.items(): - array, polarization = v - array = array.T - new_crv.write(k + "\n") - if curve.comment[-1] != "\n": - curve.comment += "\n" - num_lines = curve.comment.count("\n") - new_crv.write(f"{num_lines}\n") - new_crv.write(curve.comment) - new_crv.write(f"{int(polarization=='H')}\n") - new_crv.write(f"{curve.pump_wavelength}\n") - new_crv.write(f"{len(curve.dependents)}\n") - new_crv.write("\t".join(str(i) for i in curve.offsets)) - new_crv.write("\n") - new_crv.write(f"{len(array)}\n") - fmt = ["%0.6f"] * len(array.T) - fmt[2] = "%0.f" # this field is an int - np.savetxt(new_crv, array, fmt=fmt, delimiter="\t", newline="\n") - return out_path + out_paths = [] + + while len(to_insert): + _, curve = to_insert.popitem() + out_name = curve.kind + "- " + timestamp + out_path = (save_directory / out_name).with_suffix(".crv") + out_paths.append(out_path) + all_sibs = [curve] + if curve.siblings: + all_sibs += curve.siblings + + with open(out_path, "w") as new_crv: + _write_headers(new_crv, curve) + new_crv.write(f"{len(all_sibs)}\n") + for c in all_sibs: + _write_curve(new_crv, c) + to_insert.pop(c.interaction, None) + + return out_paths + def _get_family_dict(self, start=None): + if start is None: + start = {} + d = {k:v for k,v in start.items()} + d.update({self.interaction: self}) + if self.siblings: + for s in self.siblings: + if s.interaction not in d: + d.update(s._get_family_dict(d)) + if self.subcurve: + if self.subcurve.interaction not in d: + d.update(self.subcurve._get_family_dict(d)) + if self.supercurves: + for s in self.supercurves: + if s.interaction not in d: + d.update(s._get_family_dict(d)) + return d def _insert(curve): motor_indexes = curve.motor_indexes @@ -225,14 +224,47 @@ def _insert(curve): arr[0] = curve.source_setpoints[:] arr[1] = curve.setpoints[:] arr[2] = len(motor_indexes) - print(motor_indexes) for i, m in enumerate(motor_indexes): arr[3 + i] = next(d for d in curve.dependents.values() if d.index == m)[:] - return arr + return arr.T -def _convert(arr, sum_): - arr = np.copy(arr) - arr[1] = 1 / ((1 / sum_) - (1 / arr[1])) - arr = arr[:, ::-1] +def _convert(curve): + curve = curve.copy() + curve.setpoints[:] = 1 / ((1 / curve.pump_wavelength) - (1 / curve.setpoints[:])) + curve.polarization = "V" if curve.polarization == "H" else "H" + curve.sort() return arr + +def _write_headers(f, curve): + f.write("600\n") + if curve.kind in "OPA/NOPA": + f.write("OPA/NOPA\n") + f.write(f"{int(curve.kind=='NOPA')}\n") + f.write(f"{int(curve.config.get('use grating equation', 0))}\n") + f.write(f"{curve.config.get('grating motor index', -1)}\n") + f.write(f"{curve.config.get('grating constant', 0)}\n") + f.write(f"{curve.config.get('maximum grating position', 0)}\n") + else: + f.write(f"{curve.kind}\n") + f.write(f"{len(curve.dependents)}\n") + f.write("\t".join(str(i) for i in curve.motor_indexes)) + f.write("\n") + +def _write_curve(f, curve): + f.write(f"{curve.interaction}\n") + if curve.comment[-1] != "\n": + curve.comment += "\n" + num_lines = curve.comment.count("\n") + f.write(f"{num_lines}\n") + f.write(curve.comment) + f.write(f"{int(curve.polarization=='H')}\n") + f.write(f"{curve.pump_wavelength}\n") + f.write(f"{len(curve.dependents)}\n") + f.write("\t".join(str(i) for i in curve.offsets)) + f.write("\n") + array = _insert(curve) + f.write(f"{len(array)}\n") + fmt = ["%0.6f"] * len(array.T) + fmt[2] = "%0.f" # this field is an int + np.savetxt(f, array, fmt=fmt, delimiter="\t", newline="\n") diff --git a/tests/TopasCurve/read/2018-10-26/niuce.py b/tests/TopasCurve/read/2018-10-26/niuce.py index 3899ee9..4fe49e6 100644 --- a/tests/TopasCurve/read/2018-10-26/niuce.py +++ b/tests/TopasCurve/read/2018-10-26/niuce.py @@ -29,7 +29,7 @@ def test_round_trip(): curve = attune.TopasCurve.read(paths, interaction_string="NON-SH-NON-Sig") with tempfile.TemporaryDirectory() as td: td = pathlib.Path(td) - paths[2] = curve.save(save_directory=td) + paths = curve.save(save_directory=td) read_curve = attune.TopasCurve.read(paths, interaction_string="NON-SH-NON-Sig") assert np.allclose(curve.setpoints[:], read_curve.setpoints[:]) assert curve.dependent_names == read_curve.dependent_names From eee34e2110c6f469e3df30742b655d32d1bd1f47 Mon Sep 17 00:00:00 2001 From: Kyle Sunden Date: Mon, 18 Feb 2019 15:46:46 -0600 Subject: [PATCH 6/9] tweak to sorting, adding sig/idl --- attune/curve/_base.py | 5 +++-- attune/curve/_topas.py | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/attune/curve/_base.py b/attune/curve/_base.py index a5cdc11..07fc8ca 100644 --- a/attune/curve/_base.py +++ b/attune/curve/_base.py @@ -340,9 +340,10 @@ def map_setpoints(self, setpoints, units="same"): def sort(self): order = self.setpoints[:].argsort() self.setpoints[:] = self.setpoints[order] - if self.subcurve_setpoints: + try: self.subcurve_setpoints[:] = self.subcurve_setpoints[order] - + except (AttributeError, TypeError): + pass # no subcurve setpoints for d in self.dependents.values(): d[:] = d[order] diff --git a/attune/curve/_topas.py b/attune/curve/_topas.py index abaaa59..90d9edf 100644 --- a/attune/curve/_topas.py +++ b/attune/curve/_topas.py @@ -171,11 +171,13 @@ def save(self, save_directory, full=True): to_insert = {} if full: to_insert = curve._get_family_dict() + to_insert[interaction_string] = curve if interaction_string == "NON-NON-NON-Idl": to_insert["NON-NON-NON-Sig"] = _convert(curve) - to_insert[interaction_string] = curve + to_insert["NON-NON-NON-Sig"].interaction = "NON-NON-NON-Sig" if interaction_string == "NON-NON-NON-Sig": to_insert["NON-NON-NON-Idl"] = _convert(curve) + to_insert["NON-NON-NON-Idl"].interaction = "NON-NON-NON-Idl" save_directory = pathlib.Path(save_directory) save_directory.mkdir(parents=True, exist_ok=True) @@ -231,10 +233,9 @@ def _insert(curve): def _convert(curve): curve = curve.copy() - curve.setpoints[:] = 1 / ((1 / curve.pump_wavelength) - (1 / curve.setpoints[:])) + curve.setpoints.positions = 1 / ((1 / curve.pump_wavelength) - (1 / curve.setpoints[:])) curve.polarization = "V" if curve.polarization == "H" else "H" - curve.sort() - return arr + return curve def _write_headers(f, curve): f.write("600\n") @@ -252,6 +253,9 @@ def _write_headers(f, curve): f.write("\n") def _write_curve(f, curve): + curve = curve.copy() + curve.convert("nm") + curve.sort() f.write(f"{curve.interaction}\n") if curve.comment[-1] != "\n": curve.comment += "\n" From eb70f6ba385991303efe2ebafb6634142c91a821 Mon Sep 17 00:00:00 2001 From: Kyle Sunden Date: Mon, 18 Feb 2019 17:52:19 -0600 Subject: [PATCH 7/9] Propagate index in map_setpoints --- attune/curve/_base.py | 5 ++--- attune/curve/_topas.py | 2 ++ tests/workup/intensity/2018-11-30/qgnsm.py | 5 ++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/attune/curve/_base.py b/attune/curve/_base.py index 0b42d84..f5b080e 100644 --- a/attune/curve/_base.py +++ b/attune/curve/_base.py @@ -110,7 +110,6 @@ def __add__(self, other): if wt.units.is_valid_conversion(other[k].units, self[k].units): other[k].convert(self[k].units) else: - print(type(other[k].units), type(self[k].units)) raise ValueError( f"Invalid unit conversion: {other[k].units} -> {self[k].units}" ) @@ -324,14 +323,14 @@ def map_setpoints(self, setpoints, units="same"): for k, v in self.dependents.items(): positions = v(new_setpoints) new_dependent = Dependent( - positions, k, v.units, v.differential + positions, k, v.units, v.differential, v.index ) # new dependent objects new_dependents.update({k: new_dependent}) # map source setpoints, subcurves if self.subcurve: new_source_setpoints = self.source_setpoints(new_setpoints) self.source_setpoints = Dependent( - new_source_setpoints, self.source_setpoints.name, self.source_setpoints.units + new_source_setpoints, self.source_setpoints.name, self.source_setpoints.units, index=self.source_setpoints.index ) # finish self.setpoints = Setpoints(new_setpoints, self.setpoints.name, self.setpoints.units) diff --git a/attune/curve/_topas.py b/attune/curve/_topas.py index 90d9edf..f1c1296 100644 --- a/attune/curve/_topas.py +++ b/attune/curve/_topas.py @@ -226,6 +226,8 @@ def _insert(curve): arr[0] = curve.source_setpoints[:] arr[1] = curve.setpoints[:] arr[2] = len(motor_indexes) + print(motor_indexes) + print([d.index for d in curve.dependents.values()]) for i, m in enumerate(motor_indexes): arr[3 + i] = next(d for d in curve.dependents.values() if d.index == m)[:] return arr.T diff --git a/tests/workup/intensity/2018-11-30/qgnsm.py b/tests/workup/intensity/2018-11-30/qgnsm.py index 06acbf8..72d7d0f 100644 --- a/tests/workup/intensity/2018-11-30/qgnsm.py +++ b/tests/workup/intensity/2018-11-30/qgnsm.py @@ -14,11 +14,10 @@ def test(): data.moment("wa_points", moment=0) data.transform("w1=wm", "w1_Delay_2_points") old = attune.TopasCurve.read( - [__here__ / "old.crv", None, None, None], - kind="TOPAS-C", + [__here__ / "old.crv"], interaction_string="NON-NON-NON-Sig", ) - new = attune.workup.intensity(data, -1, "Delay_2", curve=old) + new = attune.workup.intensity(data, -1, "3", curve=old) print(new) From 37aff26ebf81f2404b3bae1d783ad9a1e861aa9d Mon Sep 17 00:00:00 2001 From: wright_stuff Date: Mon, 18 Feb 2019 18:19:47 -0600 Subject: [PATCH 8/9] missing import --- attune/curve/_topas.py | 1 + 1 file changed, 1 insertion(+) diff --git a/attune/curve/_topas.py b/attune/curve/_topas.py index f1c1296..07bae04 100644 --- a/attune/curve/_topas.py +++ b/attune/curve/_topas.py @@ -1,5 +1,6 @@ import numpy as np import pathlib +import warnings from ._base import Curve from ._dependent import Setpoints, Dependent import WrightTools as wt From 6a9e6082769c4a77cbbc0c8b4cd76cca84655304 Mon Sep 17 00:00:00 2001 From: wright_stuff Date: Tue, 19 Feb 2019 10:53:39 -0600 Subject: [PATCH 9/9] Add [:] to source_setpoints --- attune/curve/_base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/attune/curve/_base.py b/attune/curve/_base.py index f5b080e..3137cfc 100644 --- a/attune/curve/_base.py +++ b/attune/curve/_base.py @@ -500,7 +500,7 @@ def read(cls, filepath, subcurve=None): setpoints = Setpoints(arr[0], setpoint_name, units[0]) if subcurve is not None: kwargs["subcurve"] = subcurve - kwargs["source_setpoints"] = Dependent(setpoints, setpoint_name, units=units[0]) + kwargs["source_setpoints"] = Dependent(setpoints[:], setpoint_name, units=units[0]) # finish curve = cls(setpoints, dependents, **kwargs) return curve