Commit 09ccdd49 authored by Islam, Fahima's avatar Islam, Fahima
Browse files

Upload New File

parent af25d4ee
Loading
Loading
Loading
Loading
+288 −0
Original line number Diff line number Diff line
import xml.etree.ElementTree as ET
import numpy as np
from scipy.spatial.transform import Rotation as R
import re

def extract_bank_data(file_path, selected_banks=None):
    """
    Extracts bank data from an XML file.

    Parameters:
    - file_path (str): Path to the XML file.
    - selected_banks (list, optional): List of bank names to extract (e.g., ["bank1", "bank2"]).
                                       If None, all banks will be extracted.

    Returns:
    - dict: Dictionary with bank names as keys and their data as values.
    """
    tree = ET.parse(file_path)
    root = tree.getroot()
    namespace = '{http://www.mantidproject.org/IDF/1.0}'

    bank_data = {}

    for component in root.findall(f".//{namespace}component"):
        component_type = component.attrib.get("type", "")
        if re.match(r'^pack', component_type):  # Match any type that starts with 'pack'
            location = component.find(f"{namespace}location")

            if location is not None:
                bank_name = location.attrib.get("name", "")

                # If selected_banks is None, extract all banks. Otherwise, filter based on selection.
                if selected_banks is None or bank_name in selected_banks:
                    x = float(location.attrib.get("x"))
                    y = float(location.attrib.get("y"))
                    z = float(location.attrib.get("z"))

                    # Check for different rotation formats
                    y1_rot = location.find(f"{namespace}rot")
                    if y1_rot is not None:
                        y1 = float(y1_rot.attrib['val'])  # First Y rotation

                        # Check if there are nested rotations
                        z_rot = y1_rot.find(f"{namespace}rot")
                        if z_rot is not None:
                            z1 = float(z_rot.attrib['val'])  # Z rotation

                            y2_rot = z_rot.find(f"{namespace}rot")
                            if y2_rot is not None:
                                y2 = float(y2_rot.attrib['val'])  # Second Y rotation
                                # Store both rotations in nested format
                                bank_data[bank_name] = {
                                    "location": (x, y, z),
                                    "yzy_angles": (y1, z1, y2),
                                    "pack_type": component_type
                                }
                        else:
                            # For a single rotation element, store as Y rotation only
                            bank_data[bank_name] = {
                                "location": (x, y, z),
                                "yzy_angles": (y1, 0, 0),
                                "pack_type": component_type
                            }

    return bank_data

# # Example Usage:
# file_path = "your_file.xml"
#
# # **Option 1: Extract All Banks (Default)**
# all_banks_data = extract_bank_data(file_path)
# print("Extracted All Banks:", all_banks_data)
#
# # **Option 2: Extract Only Specific Banks (e.g., bank1 to bank14)**
# selected_banks = [f"bank{i}" for i in range(1, 15)]
# specific_banks_data = extract_bank_data(file_path, selected_banks)
# print("Extracted Selected Banks:", specific_banks_data)





# def extract_bank_data(file_path):
#     tree = ET.parse(file_path)
#     root = tree.getroot()
#     namespace = '{http://www.mantidproject.org/IDF/1.0}'
#
#     bank_data = {}
#
#     for component in root.findall(f".//{namespace}component"):
#         component_type = component.attrib.get("type", "")
#         if re.match(r'^pack', component_type):  # Match any type that starts with 'pack'
#             location = component.find(f"{namespace}location")
#
#             if location is not None and re.match(r'bank\d+', location.attrib.get("name", "")):
#                 bank_name = location.attrib["name"]
#                 x = float(location.attrib.get("x"))
#                 y = float(location.attrib.get("y"))
#                 z = float(location.attrib.get("z"))
#
#                 # Check for different rotation formats
#                 y1_rot = location.find(f"{namespace}rot")
#                 if y1_rot is not None:
#                     y1 = float(y1_rot.attrib['val'])  # First Y rotation
#
#                     # Check if there are nested rotations
#                     z_rot = y1_rot.find(f"{namespace}rot")
#                     if z_rot is not None:
#                         z1 = float(z_rot.attrib['val'])  # Z rotation
#
#                         y2_rot = z_rot.find(f"{namespace}rot")
#                         if y2_rot is not None:
#                             y2 = float(y2_rot.attrib['val'])  # Second Y rotation
#                             # Store both rotations in nested format
#                             bank_data[bank_name] = {
#                                 "location": (x, y, z),
#                                 "yzy_angles": (y1, z1, y2),
#                                 "pack_type": component_type
#                             }
#                     else:
#                         # For a single rotation element, store as Y rotation only
#                         bank_data[bank_name] = {
#                             "location": (x, y, z),
#                             "yzy_angles": (y1, 0, 0),
#                             "pack_type": component_type
#                         }
#
#     return bank_data
# # ## example use
# # file_path = 'NOMAD_Definition.xml'
# # bank_data = extract_bank_data(file_path)



def convert_to_euler_angles_xyz(yzy_angles):
    """
    Converts given rotations around Y, Z, and Y axes to Euler angles in X-Y-Z convention (alpha, beta, gamma).

    Parameters:
    yzy_angles (tuple or list): A tuple or list containing (theta_Y1, theta_Z, theta_Y2) in degrees.

    Returns:
    tuple: (alpha, beta, gamma) in degrees, in the X-Y-Z convention.
    """
    theta_Y1, theta_Z, theta_Y2 = yzy_angles  # Unpack the angles

    # Convert angles to radians
    theta_Y1 = np.deg2rad(theta_Y1)
    theta_Z = np.deg2rad(theta_Z)
    theta_Y2 = np.deg2rad(theta_Y2)

    # Rotation matrices
    R_Y1 = np.array([
        [np.cos(theta_Y1), 0, np.sin(theta_Y1)],
        [0, 1, 0],
        [-np.sin(theta_Y1), 0, np.cos(theta_Y1)]
    ])

    R_Z = np.array([
        [np.cos(theta_Z), -np.sin(theta_Z), 0],
        [np.sin(theta_Z), np.cos(theta_Z), 0],
        [0, 0, 1]
    ])

    R_Y2 = np.array([
        [np.cos(theta_Y2), 0, np.sin(theta_Y2)],
        [0, 1, 0],
        [-np.sin(theta_Y2), 0, np.cos(theta_Y2)]
    ])

    # Combined rotation matrix
    R = R_Y2 @ R_Z @ R_Y1
    #     print('Rotation matrix:', R)

    # Extract Euler angles in X-Y-Z convention
    alpha = np.arctan2(R[2, 1], R[2, 2])
    beta = np.arcsin(-R[2, 0])
    gamma = np.arctan2(R[1, 0], R[0, 0])

    # Convert to degrees
    alpha_deg = np.rad2deg(alpha)
    beta_deg = np.rad2deg(beta)
    gamma_deg = np.rad2deg(gamma)

    return alpha_deg, beta_deg, gamma_deg

# ##example use
# for bank_name, data in bank_data.items():
#     location = data["location"]
#     yzy_angles = data["yzy_angles"]
# #     euler_angles = convert_to_euler(yzy_angles)
#     euler_angles = convert_to_euler_angles_xyz(yzy_angles[::-1])
#     print(f"Bank: {bank_name}")
#     print("Location:", location)
#     print("YZY Angles:", yzy_angles)
#     print("Euler Angles (XYZ):", euler_angles)
#     print("-" * 30)

from detector import Detector


# Default pack types for NOMAD
def get_pack_types():
    return {
        "pack": {"tube_count": 8, "pixels_in_tube": 128, "width": 0.2172, "height": 128 * 0.00794},
        "packhalf": {"tube_count": 8, "pixels_in_tube": 128, "width": 0.0606, "height": 128 * 0.00781},
        "packhalfshort": {"tube_count": 16, "pixels_in_tube": 64, "width": 0.11546, "height": 64 * 0.00720}
    }


def generate_detectors(bank_data, sample="sample_reference", output_file=None):
    """
    Generates detector instances and returns a formatted script string.

    Parameters:
    bank_data (dict): Dictionary containing detector bank data.
    sample (str): Reference to the sample position.
    output_file (str, optional): If provided, writes the output to a file.

    Returns:
    str: The formatted script containing detector definitions.
    """
    pack_types = get_pack_types()
    snippet_string = ""
    snippet_template = """
{bank_name} = Detector(name='{bank_name}', xwidth={width}, yheight={height}, Nx={Nx}, Ny={Ny}, outfile='{bank_name}', start_index={start_index})

instrument.append(
    {bank_name},
    position={location}, 
    orientation={orientation}, 
    relativeTo={sample}
)
"""

    start_index = 0
    for bank_name, data in bank_data.items():
        location = data["location"]
        yzy_angles = data["yzy_angles"]
        pack = pack_types[data["pack_type"]]
        euler_angles = convert_to_euler_angles_xyz(yzy_angles[::-1])

        snippet_string += snippet_template.format(
            bank_name=bank_name,
            width=pack["width"],
            height=pack["height"],
            Nx=pack["tube_count"],
            Ny=pack["pixels_in_tube"],
            start_index=start_index,
            location=location,
            orientation=tuple(euler_angles),
            sample=sample
        )
        start_index += pack["tube_count"] * pack["pixels_in_tube"]

    if output_file:
        with open(output_file, "w") as file:
            file.write(snippet_string)

    return snippet_string

# Example usage:
# generated_script = generate_detectors(bank_data, output_file="nom_detectors_only.py")

def count_total_pixels(bank_data):
    """
    Calculates the total number of pixels across all detector banks.

    Parameters:
    bank_data (dict): Dictionary containing detector bank data.

    Returns:
    int: Total number of pixels.
    """
    pack_types = get_pack_types()  # Assuming this function returns detector pack types
    total_pixels = 0

    for data in bank_data.values():
        pack = pack_types[data["pack_type"]]
        total_pixels += pack["tube_count"] * pack["pixels_in_tube"]

    return total_pixels

# Example usage:
# total_pixels = count_total_pixels(bank_data)
# print("Total number of pixels:", total_pixels)