new file: detector_geometry.dat new file: eloss_calculations/Eloss.py new file: eloss_calculations/alpha_lookup_20MeV.dat new file: eloss_calculations/alpha_lookup_6.0MeV.dat new file: eloss_calculations/make_eloss_table.C new file: eloss_calculations/proton_lookup_20MeV.dat new file: eloss_calculations/proton_lookup_6.0MeV.dat new file: grid_generate.py new file: shadowplay.py
152 lines
5.6 KiB
Python
152 lines
5.6 KiB
Python
import math
|
|
import csv
|
|
|
|
# ==========================================
|
|
# CONFIGURATION
|
|
# ==========================================
|
|
VTK_FILE = "anasen_geometry.vtk"
|
|
CSV_FILE = "anasen_labels.csv"
|
|
|
|
Z_SOURCE = 53.0 # Source position
|
|
R_A = 37.0 # Anode radius (mm)
|
|
R_C = 43.0 # Cathode radius (mm)
|
|
R_SX3 = 88.0 # SX3 Barrel radius (mm)
|
|
Z_LEN = 348.6 # Total Z length (174.3 * 2 from ClassPW.h)
|
|
Z_HALF = Z_LEN / 2.0
|
|
|
|
points = []
|
|
lines = []
|
|
polygons = []
|
|
cell_colors = []
|
|
labels = []
|
|
|
|
def add_point(x_code, y_code, z_code):
|
|
# TRANSFORM: Map the C++ Frame (+Y Down, +Z Into Page)
|
|
# to the Visual ParaView Frame (+Y Up, +Z Out of Page)
|
|
points.append((x_code, -y_code, -z_code))
|
|
return len(points) - 1
|
|
|
|
def project_shadow(r_wire, phi_minusZ_deg, phi_plusZ_deg, color_code):
|
|
shadow_pts = []
|
|
steps = 50
|
|
for i in range(steps + 1):
|
|
t = i / float(steps)
|
|
# 1. Coordinate on the wire in CODE frame
|
|
z_w = -Z_HALF + (t * Z_LEN)
|
|
phi_w_deg = phi_minusZ_deg * (1 - t) + phi_plusZ_deg * t
|
|
phi_w = math.radians(phi_w_deg)
|
|
|
|
# 2. Ray from Source through the wire
|
|
dx = r_wire * math.cos(phi_w)
|
|
dy = r_wire * math.sin(phi_w)
|
|
dz = z_w - Z_SOURCE
|
|
|
|
# 3. Scale ray until it hits SX3 (R = 88)
|
|
r_current = math.sqrt(dx**2 + dy**2)
|
|
alpha = R_SX3 / r_current
|
|
|
|
x_proj = alpha * dx
|
|
y_proj = alpha * dy
|
|
z_proj = Z_SOURCE + alpha * dz
|
|
|
|
shadow_pts.append(add_point(x_proj, y_proj, z_proj))
|
|
|
|
lines.append(shadow_pts)
|
|
cell_colors.append(color_code)
|
|
|
|
# ==========================================
|
|
# 1. GENERATE PC WIRES & SHADOWS (LINES)
|
|
# ==========================================
|
|
k = 360.0 / 24.0
|
|
|
|
for i in range(24):
|
|
# --- ANODES ---
|
|
# From ClassPW.h: offset_a1 = -135 deg, offset_a2 = -90 deg
|
|
phi_a_minusZ = -k * i - 135.0
|
|
phi_a_plusZ = -k * i - 90.0
|
|
|
|
x_a1, y_a1 = R_A * math.cos(math.radians(phi_a_minusZ)), R_A * math.sin(math.radians(phi_a_minusZ))
|
|
x_a2, y_a2 = R_A * math.cos(math.radians(phi_a_plusZ)), R_A * math.sin(math.radians(phi_a_plusZ))
|
|
|
|
pa1 = add_point(x_a1, y_a1, -Z_HALF)
|
|
pa2 = add_point(x_a2, y_a2, Z_HALF)
|
|
lines.append([pa1, pa2])
|
|
cell_colors.append(1) # Color 1 = Anodes
|
|
project_shadow(R_A, phi_a_minusZ, phi_a_plusZ, 4)
|
|
|
|
# Place label at +Z_visual (which maps from -Z_code in the transform)
|
|
labels.append((x_a1 * 1.1, -y_a1 * 1.1, Z_HALF + 15, f"A{i}"))
|
|
|
|
# --- CATHODES ---
|
|
# From ClassPW.h: offset_c1 = -97.5 deg, offset_c2 = -142.5 deg
|
|
phi_c_minusZ = k * i - 97.5
|
|
phi_c_plusZ = k * i - 142.5
|
|
|
|
x_c1, y_c1 = R_C * math.cos(math.radians(phi_c_minusZ)), R_C * math.sin(math.radians(phi_c_minusZ))
|
|
x_c2, y_c2 = R_C * math.cos(math.radians(phi_c_plusZ)), R_C * math.sin(math.radians(phi_c_plusZ))
|
|
|
|
pc1 = add_point(x_c1, y_c1, -Z_HALF)
|
|
pc2 = add_point(x_c2, y_c2, Z_HALF)
|
|
lines.append([pc1, pc2])
|
|
cell_colors.append(2) # Color 2 = Cathodes
|
|
project_shadow(R_C, phi_c_minusZ, phi_c_plusZ, 5)
|
|
|
|
labels.append((x_c1 * 1.1, -y_c1 * 1.1, Z_HALF + 30, f"C{i}"))
|
|
|
|
# ==========================================
|
|
# 2. GENERATE SX3 BARREL (POLYGONS)
|
|
# ==========================================
|
|
# Calculate exact strip positions based on MakeVertex.C formulas
|
|
for det_id in range(12):
|
|
for stripF in range(4):
|
|
stripF_rev = 3 - stripF
|
|
num = (2 * stripF_rev - 3) * 40.30
|
|
den = 8.0 * R_SX3 * math.cos(math.radians(15.0))
|
|
beta_n = 15.0 + math.degrees(math.atan2(num, den))
|
|
|
|
# phi_n perfectly computes the C++ angle
|
|
phi_code_deg = ((-det_id + 0.5) * 30.0 + beta_n) + 45.0
|
|
phi_code = math.radians(phi_code_deg)
|
|
|
|
d_phi = 10.0 / R_SX3 # ~6.5 degrees width per strip
|
|
phi_L = phi_code - (d_phi / 2.0)
|
|
phi_R = phi_code + (d_phi / 2.0)
|
|
|
|
p1 = add_point(R_SX3 * math.cos(phi_L), R_SX3 * math.sin(phi_L), -Z_HALF)
|
|
p2 = add_point(R_SX3 * math.cos(phi_R), R_SX3 * math.sin(phi_R), -Z_HALF)
|
|
p3 = add_point(R_SX3 * math.cos(phi_R), R_SX3 * math.sin(phi_R), Z_HALF)
|
|
p4 = add_point(R_SX3 * math.cos(phi_L), R_SX3 * math.sin(phi_L), Z_HALF)
|
|
|
|
polygons.append([p1, p2, p3, p4])
|
|
cell_colors.append(3) # SX3 Color
|
|
|
|
# Place Labels correctly in visual space
|
|
x_lbl, y_lbl = R_SX3 * 1.15 * math.cos(phi_code), R_SX3 * 1.15 * math.sin(phi_code)
|
|
labels.append((x_lbl, -y_lbl, 0, f"D{det_id}_S{stripF}"))
|
|
|
|
# ==========================================
|
|
# 3. WRITE VTK AND CSV
|
|
# ==========================================
|
|
with open(VTK_FILE, "w") as f:
|
|
f.write("# vtk DataFile Version 2.0\nANASEN Geometry\nASCII\nDATASET POLYDATA\n")
|
|
f.write(f"POINTS {len(points)} float\n")
|
|
for pt in points: f.write(f"{pt[0]:.4f} {pt[1]:.4f} {pt[2]:.4f}\n")
|
|
|
|
line_data_size = sum(len(l) + 1 for l in lines)
|
|
f.write(f"\nLINES {len(lines)} {line_data_size}\n")
|
|
for l in lines: f.write(f"{len(l)} " + " ".join(map(str, l)) + "\n")
|
|
|
|
poly_data_size = sum(len(p) + 1 for p in polygons)
|
|
f.write(f"\nPOLYGONS {len(polygons)} {poly_data_size}\n")
|
|
for p in polygons: f.write(f"{len(p)} " + " ".join(map(str, p)) + "\n")
|
|
|
|
f.write(f"\nCELL_DATA {len(lines) + len(polygons)}\n")
|
|
f.write("SCALARS EntityType int 1\nLOOKUP_TABLE default\n")
|
|
for c in cell_colors: f.write(f"{c}\n")
|
|
|
|
with open(CSV_FILE, "w", newline='') as f:
|
|
writer = csv.writer(f)
|
|
writer.writerow(["X", "Y", "Z", "Label"])
|
|
writer.writerows(labels)
|
|
|
|
print(f"Generated {VTK_FILE} and {CSV_FILE}.") |