From 6f3a5c2fe04de40421b2aa3d8abab73e5cbb4e28 Mon Sep 17 00:00:00 2001
From: Gaetan Fine <fineg@ill.fr>
Date: Fri, 13 May 2022 09:54:57 +0100
Subject: [PATCH] Upgraded to new way to calculate path Fixed bugs

---
 .gitignore                     |   1 +
 src/dummy_requester.py         |  66 ++++++++-------
 src/path_creator.py            | 141 +++++++++++++++++++++++----------
 test/example_data-no_path.json |   6 +-
 test/example_status.json       |  18 +++--
 5 files changed, 156 insertions(+), 76 deletions(-)

diff --git a/.gitignore b/.gitignore
index b601188..9d722f2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ logs
 __pycache__
 log
 *.sublime*
+*.dat
\ No newline at end of file
diff --git a/src/dummy_requester.py b/src/dummy_requester.py
index 3864e18..0e9f0ba 100644
--- a/src/dummy_requester.py
+++ b/src/dummy_requester.py
@@ -7,6 +7,9 @@ import matplotlib.pyplot as plt
 
 numberOfTimes = 1 if len(sys.argv) < 3 else int(sys.argv[1])
 
+write = True
+show = False
+
 
 def process_response(raw_json):
     json_data = json.loads(raw_json)
@@ -23,22 +26,31 @@ def process_response(raw_json):
             print("Error while reading response")
             return
 
-        print("Found a path, showing")
-        regions = json_data['data']['regions']
+        if show:
+            print("Found a path, showing")
+            regions = json_data['data']['regions']
+
+            for r in regions:
+                plt.fill(r['x1'], r['y1'], "-", linewidth = 1.,
+                    fill = not (r['inverted'] == 'True'),
+                    color = "#ff0000")
+
+            x, y = zip(*vertices)
+            plt.xlabel("Sample Scattering Angle 2\u03b8_S (deg)")
+            plt.ylabel("Monochromator Scattering Angle 2\u03b8_M (deg)")
+            plt.plot(x, y, "-", linewidth=2)
+
+            plt.scatter(x[0], y[0], s=15, color="green")
+            plt.scatter(x[-1], y[-1], s=15, color="red")
+            plt.show()
 
-        for r in regions:
-            plt.fill(r['x1'], r['y1'], "-", linewidth = 1.,
-                fill = not (r['inverted'] == 'True'),
-                color = "#ff0000")
+        if write:
+            print("Found a path, writing")
+            with open("path_.dat", "w") as datafile:
+                for vertex in vertices:
+                    datafile.write("%.4f %.4f\n" % (vertex[0], vertex[1]))
 
-        x, y = zip(*vertices)
-        plt.xlabel("Sample Scattering Angle 2\u03b8_S (deg)")
-        plt.ylabel("Monochromator Scattering Angle 2\u03b8_M (deg)")
-        plt.plot(x, y, "-", linewidth=2)
 
-        plt.scatter(x[0], y[0], s=15, color="green")
-        plt.scatter(x[-1], y[-1], s=15, color="red")
-        plt.show()
         return True
     elif json_data["type"] == "ok":
         print("Done.\n")
@@ -79,19 +91,19 @@ response = requester.receiveString()
 process_response(response)
 
 
-print("setup builder")
-f = open('test/example_builder-options.json')
-request = f.read()
-f.close()
-requester.send(request)
-response = requester.receiveString()
-process_response(response)
+# print("setup builder")
+# f = open('test/example_builder-options.json')
+# request = f.read()
+# f.close()
+# requester.send(request)
+# response = requester.receiveString()
+# process_response(response)
 
 
-print("working data")
-f = open('test/example_data-working.json')
-request = f.read()
-f.close()
-requester.send(request)
-response = requester.receiveString()
-process_response(response)
\ No newline at end of file
+# print("working data")
+# f = open('test/example_data-working.json')
+# request = f.read()
+# f.close()
+# requester.send(request)
+# response = requester.receiveString()
+# process_response(response)
\ No newline at end of file
diff --git a/src/path_creator.py b/src/path_creator.py
index 5a7c430..35fc160 100644
--- a/src/path_creator.py
+++ b/src/path_creator.py
@@ -1,5 +1,14 @@
 #!/usr/bin/python3
 
+####################################################
+# TODO
+# 
+# SetSampleAngleOffset ? 
+# ScatteringSense ?
+# 
+# 
+####################################################
+
 import sys
 import os
 import math as m
@@ -76,6 +85,9 @@ ERROR = None
 
 # The crystal config and instrument config
 current_crystal_config = {
+    "sense0" : None,
+    "sense1" : None,
+    "sense2" : None,
     "sampleLatticeConstantA": None,
     "sampleLatticeConstantB": None,
     "sampleLatticeConstantC": None,
@@ -88,6 +100,7 @@ current_crystal_config = {
     "sampleScatteringPlaneBx" : None,
     "sampleScatteringPlaneBy" : None,
     "sampleScatteringPlaneBz" : None,
+    "setSampleAngleOffset" : None
 }
 
 current_instrument_config = {
@@ -128,6 +141,7 @@ parser.add_argument('--instr-space',
                     metavar='INSTRUMENT_SPACE_FILE')
 argv = None
 
+
 if sys.argv[-1][0] != '{':
     warning('Must be run from a cameo server')
     argv = sys.argv[1:]
@@ -151,7 +165,10 @@ logging.basicConfig(filename=args.log_dir + os.sep + log_file, level=args.log_le
 def setup_crystal(data):
     global tascalc
 
-    tascalc.SetScatteringSenses(True, False, True)
+    debug("Setting up tascalc crystal configuration with :{}".format(str(data)))
+
+
+    tascalc.SetScatteringSenses(data["sense0"] >= 0., data["sense1"] >= 0., data["sense2"] >= 0.)
 
     tascalc.SetSampleLatticeConstants(float(data["sampleLatticeConstantA"]),
                                       float(data["sampleLatticeConstantB"]),
@@ -168,6 +185,11 @@ def setup_crystal(data):
                                      float(data["sampleScatteringPlaneBx"]), 
                                      float(data["sampleScatteringPlaneBy"]),
                                      float(data["sampleScatteringPlaneBz"]))
+    
+    if data["setSampleAngleOffset"] == 1:
+        tascalc.SetSampleAngleOffset(90./180.*m.pi)
+
+
 
     tascalc.UpdateB()
     tascalc.UpdateUB()
@@ -196,12 +218,8 @@ def init():
     info("Instrument definition loaded.\n")
     # -----------------------------------------------------------------------------
 
-    # -----------------------------------------------------------------------------
-    # Set-up a sample single-crystal
-    # -----------------------------------------------------------------------------
-
+ 
     tascalc = tas.TasCalculator()
-    # setup_crystal(current_crystal_config)
     # -----------------------------------------------------------------------------
     return True
 
@@ -217,15 +235,18 @@ def build_mesh():
         warning("You must set Kf or Ki to be fixed before calculating mesh")
         return False
 
-    if current_instrument_config["fixedAngle"] == "Kf":
-        tascalc.SetKf(1.4)
-    else:
-        tascalc.SetKi(1.4)
     # -----------------------------------------------------------------------------
     # Create path builder
     # -----------------------------------------------------------------------------
 
     builder = tas.PathsBuilder()
+
+    if current_instrument_config["fixedAngle"] == "Kf":
+        tascalc.SetKf(1.4)
+    else:
+        tascalc.SetKi(1.4)
+
+
     builder.AddConsoleProgressHandler()
     builder.SetInstrumentSpace(instrspace)
     #builder.SetScatteringSenses(senses)
@@ -236,21 +257,33 @@ def build_mesh():
     # Build path mesh
     # -----------------------------------------------------------------------------
 
+
     # angular ranges to probe
-    angle_padding = 4.
-    a2_delta = 1./180.*m.pi   # if mode is ki fixed a2 is a6
-    a4_delta = 2./180.*m.pi
-    a2_begin = 0. - angle_padding*a2_delta
-    a2_end = m.pi + angle_padding*a2_delta
-    a4_begin = -m.pi - angle_padding*a4_delta
-    a4_end = m.pi + angle_padding*a4_delta
+    if current_instrument_config["fixedAngle"] == "Kf":
+        angle_padding = 4.
+
+        analyzer_delta = 2./180.*m.pi
+        analyzer_begin = -m.pi - angle_padding*analyzer_delta
+        analyzer_end = m.pi + angle_padding*analyzer_delta
+
+        free_part_delta = 1./180.*m.pi
+        free_part_begin = 0. - angle_padding*free_part_delta
+        free_part_end = m.pi + angle_padding*free_part_delta
+    else:
+        free_part_delta = 4./180.*m.pi
+        analyzer_delta = 4./180.*m.pi
+        free_part_begin = -m.pi
+        free_part_end = m.pi
+        analyzer_begin = -m.pi
+        analyzer_end = m.pi
+
 
     builder.StartPathMeshWorkflow()
 
     if not builder.CalculateConfigSpace(
-        a2_delta, a4_delta,
-        a2_begin, a2_end,
-        a4_begin, a4_end):
+        free_part_delta, analyzer_delta,
+        free_part_begin, free_part_end,
+        analyzer_begin, analyzer_end):
         critical("Angular configuration space could not be calculated.")
         return False
 
@@ -281,21 +314,29 @@ def calculate_path(target_angles):
     global builder
 
 
-    target_angles.monoXtalAngle = abs(target_angles.monoXtalAngle)
-    target_angles.sampleXtalAngle = abs(target_angles.sampleXtalAngle)
-    target_angles.sampleScatteringAngle = abs(target_angles.sampleScatteringAngle)
+    if current_instrument_config["fixedAngle"] == "Kf":
+        debug("Using fixed Kf path building")
+        target_angles.monoXtalAngle = target_angles.monoXtalAngle * current_crystal_config["sense0"]
+    else:
+        debug("Using fixed Ki path building")
+        target_angles.anaXtalAngle = target_angles.anaXtalAngle * current_crystal_config["sense2"]
+    
+
 
-    info("Start angles: a1 = %.2f deg, a5 = %.2f deg, a3 = %.2f deg, a4 = %.2f deg." % (
-        float(current_instrument_config["monoXtalAngle"]) / m.pi*180.,
-        float(current_instrument_config["anaXtalAngle"]) / m.pi*180.,
-        float(current_instrument_config["sampleXtalAngle"]) / m.pi*180.,
-        float(current_instrument_config["sampleScatteringAngle"]) / m.pi*180.))
+    target_angles.sampleXtalAngle = target_angles.sampleXtalAngle * current_crystal_config["sense1"]
+    target_angles.sampleScatteringAngle = target_angles.sampleScatteringAngle * current_crystal_config["sense1"]
 
-    info("Target angles: a1 = %.2f deg, a5 = %.2f deg, a3 = %.2f deg, a4 = %.2f deg." % (
-        target_angles.monoXtalAngle / m.pi*180.,
-        target_angles.anaXtalAngle / m.pi*180.,
-        target_angles.sampleXtalAngle / m.pi*180.,
-        target_angles.sampleScatteringAngle / m.pi*180.))
+    info("Start angles: a1 = %.2f rad, a5 = %.2f rad, a3 = %.2f rad, a4 = %.2f rad." % (
+        float(current_instrument_config["monoXtalAngle"]),
+        float(current_instrument_config["anaXtalAngle"]),
+        float(current_instrument_config["sampleXtalAngle"]),
+        float(current_instrument_config["sampleScatteringAngle"])))
+
+    info("Target angles: a1 = %.2f rad, a5 = %.2f rad, a3 = %.2f rad, a4 = %.2f rad." % (
+        target_angles.monoXtalAngle,
+        target_angles.anaXtalAngle,
+        target_angles.sampleXtalAngle,
+        target_angles.sampleScatteringAngle))
     # -----------------------------------------------------------------------------
 
 
@@ -304,14 +345,15 @@ def calculate_path(target_angles):
     # -----------------------------------------------------------------------------
     path = None
 
+
     if current_instrument_config["fixedAngle"] == "Kf":
         path = builder.FindPath(
-            float(current_instrument_config["monoScatteringAngle"]), float(current_instrument_config["sampleScatteringAngle"]),
+            float(current_instrument_config["monoXtalAngle"]) * 2, float(current_instrument_config["sampleScatteringAngle"]),
             target_angles.monoXtalAngle * 2., target_angles.sampleScatteringAngle,
             tas.PathStrategy_PENALISE_WALLS)
     else:
         path = builder.FindPath(
-            float(current_instrument_config["anaScatteringAngle"]), float(current_instrument_config["sampleScatteringAngle"]),
+            float(current_instrument_config["anaXtalAngle"])* 2., float(current_instrument_config["sampleScatteringAngle"]),
             target_angles.anaXtalAngle * 2., target_angles.sampleScatteringAngle,
             tas.PathStrategy_PENALISE_WALLS)
 
@@ -368,6 +410,11 @@ def write_json_path_data(vertices):
 def update_crystal(data):
     global current_crystal_config
 
+    if len(data.keys()) != 16:
+        setError(INCONSISTENT_DATA, "Missing or too many value in crystal configuration")
+        warning("Missing value in crystal configuration")
+        return False
+
     # Ensuring data is consistent
     for key in data.keys():
         if key not in current_crystal_config or \
@@ -382,6 +429,13 @@ def update_crystal(data):
 
     # Re do the crystal setup
     setup_crystal(current_crystal_config)
+
+    # if not build_mesh():
+    #     setError(CRITICAL_CANT_BUILD_MESH)
+    #     warning("Couldn't build mesh")
+    #     ready = False
+    #     return False
+
     return True
 
 
@@ -407,8 +461,8 @@ def update_instr(data):
     # More verification on consistency
     if 2* data["monoXtalAngle"] != data["monoScatteringAngle"] or\
        2* data["anaXtalAngle"] != data["anaScatteringAngle"] :
-       setError(INCONSISTENT_DATA, "Instrument configuration data is inconsistent\nMonochromator and Analyser axis angles must be 2 times crystal angles")
-       warning("Instrument configuration data is inconsistent\nMonochromator and Analyser axis angles must be 2 times crystal angles")
+       setError(INCONSISTENT_DATA, "Instrument configuration data is inconsistent\nMonochromator and Analyzer axis angles must be 2 times crystal angles")
+       warning("Instrument configuration data is inconsistent\nMonochromator and Analyzer axis angles must be 2 times crystal angles")
        return False
 
     if data["fixedAngle"] != "Kf" and data["fixedAngle"] != "Ki":
@@ -507,7 +561,8 @@ while True:
 
     if request:
         info('Reveived request')
-        debug("Current instrument state : " + str(current_crystal_config))
+        debug("Current crystal state : " + str(current_crystal_config))
+        debug("Current instrument state : " + str(current_instrument_config))
         vertices = None
         # Try to read the request data
         try:
@@ -524,12 +579,16 @@ while True:
             if data[0] == "path":
                 # Always need a first setup to get the instrument state
                 if not ready:
+                    warning("Setup is needed before calculating path\n")
                     setError(SETUP_NEEDED)
                     reply(request, ERROR)
                     continue
 
                 target_angles = data[1]["targetAngles"]
-                target_angles = tascalc.GetAngles( float( target_angles["h"]), -0.5, 0., float( target_angles["E"]))
+                target_angles = tascalc.GetAngles( float( target_angles["h"]),
+                                                   float( target_angles["k"]),
+                                                   float( target_angles["l"]),
+                                                   float( target_angles["E"]))
                 # Calculate the path
                 vertices = calculate_path(target_angles)
                 
@@ -548,13 +607,15 @@ while True:
                         info("Updated crystal state\n")
                     else:
                         reply(request, ERROR)
+                        continue
 
                 # Instrument state
                 if "instrument" in data[1]:
                     if update_instr(data[1]["instrument"]):
-                        info("Updated crystal instrument\n")
+                        info("Updated instrument state\n")
                     else:
                         reply(request, ERROR)
+                        continue
 
                 reply(request, OK_REPLY)
                 if is_ready():
diff --git a/test/example_data-no_path.json b/test/example_data-no_path.json
index eec4aed..5b3e553 100644
--- a/test/example_data-no_path.json
+++ b/test/example_data-no_path.json
@@ -2,8 +2,10 @@
 	"type": "path",
 	"data" : {
 		"targetAngles" : {
-			"h" : 1.5,
-			"E" : 2.5
+			"h" : 1,
+			"k" : 1,
+			"l" : 0,
+			"E" : 1.2
 		}	
 	}
 }
\ No newline at end of file
diff --git a/test/example_status.json b/test/example_status.json
index 6368fcc..ba6ab90 100644
--- a/test/example_status.json
+++ b/test/example_status.json
@@ -3,6 +3,9 @@
 	"data": {
 
 		"crystal" : {
+		    "sense0" : -1,
+		    "sense1" : 1,
+		    "sense2" : -1,
 		    "sampleLatticeConstantA": 5,
 		    "sampleLatticeConstantB": 5,
 		    "sampleLatticeConstantC": 5,
@@ -14,15 +17,16 @@
 		    "sampleScatteringPlaneAz" : 0,
 		    "sampleScatteringPlaneBx" : 0,
 		    "sampleScatteringPlaneBy" : 1,
-		    "sampleScatteringPlaneBz" : 0
+		    "sampleScatteringPlaneBz" : 0,
+		    "setSampleAngleOffset" : 1
 		},
 		"instrument" : {
-		    "monoXtalAngle" : 0.785398,
-		    "monoScatteringAngle" : 1.570796,
-		    "sampleXtalAngle" : 0.785398,
-		    "sampleScatteringAngle" : -1.570796,
-		    "anaXtalAngle" : 0.785398,
-		    "anaScatteringAngle" : 1.570796,
+		    "monoXtalAngle" : -0.732662,
+		    "monoScatteringAngle" : -1.465324,
+		    "sampleXtalAngle" :  0.677828,
+		    "sampleScatteringAngle" : 1.012062,
+		    "anaXtalAngle" : 0.946123,
+		    "anaScatteringAngle" : 1.892246,
 		    "fixedAngle": "Ki"
 		}
 	}
-- 
GitLab