wip: digital twin
This commit is contained in:
@@ -146,7 +146,10 @@ def calc_positions(cfg):
|
||||
f = (p*q)/(p+q) # focal length
|
||||
|
||||
# Bender radius
|
||||
radius = 2 * q / np.sin(cfg['fm_pitch']) # ideal bending radius
|
||||
if cfg['fm_qy'] is None:
|
||||
radius = 2 * q / np.sin(cfg['fm_pitch']) # ideal bending radius for focused beam
|
||||
else:
|
||||
radius = 2 * cfg['fm_qy'] / np.sin(cfg['fm_pitch']) # ideal bending radius for unfocused beam
|
||||
pos['fm_bnd_radius'] = {'value': radius * 1e-6} # Convert to km
|
||||
|
||||
# Pitch
|
||||
|
||||
@@ -88,10 +88,14 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.input.mo1_mode.activated_connect(self.calc_assistant)
|
||||
self.input.mo1_xtal.activated_connect(self.calc_assistant)
|
||||
self.input.fm_stripe.activated_connect(self.calc_assistant)
|
||||
self.input.fm_focus.activated_connect(self.calc_assistant)
|
||||
self.input.fm_pitch.value_changed_connect(self.calc_assistant)
|
||||
self.input.fm_focx.value_changed_connect(self.calc_assistant)
|
||||
self.input.fm_focy.value_changed_connect(self.calc_assistant)
|
||||
self.input.smpl.value_changed_connect(self.calc_assistant)
|
||||
|
||||
self.bragg_angle = 0
|
||||
self.qy = 0
|
||||
|
||||
# Initialize all values
|
||||
self.calc_assistant(identifier='init')
|
||||
@@ -111,6 +115,7 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.calc_mo1_bragg_angle()
|
||||
self.calc_cm_crit_pitch()
|
||||
self.calc_cm_reflectivity()
|
||||
self.update_fm_mode()
|
||||
self.calc_fm_reflectivity()
|
||||
self.calc_cm_fm_harm_suppr()
|
||||
self.calc_fm_ideal_pitch()
|
||||
@@ -134,6 +139,13 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
case 'mo1_xtal':
|
||||
self.calc_mo1_bragg_angle()
|
||||
self.calc_mo1_energy_resolution()
|
||||
case 'fm_focus':
|
||||
self.update_fm_mode()
|
||||
self.calc_fm_ideal_pitch()
|
||||
case 'fm_focx':
|
||||
self.calc_fm_ideal_pitch()
|
||||
case 'fm_focy':
|
||||
self.calc_fm_ideal_pitch()
|
||||
case 'fm_stripe':
|
||||
self.calc_fm_reflectivity()
|
||||
self.calc_cm_fm_harm_suppr()
|
||||
@@ -144,6 +156,24 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.calc_assistant_sideview()
|
||||
self.calc_assistant_surfaces()
|
||||
|
||||
def update_fm_mode(self):
|
||||
fm_focus = self.input.fm_focus.currentText()
|
||||
if fm_focus in 'Manual':
|
||||
self.input.fm_pitch.setVisible(True)
|
||||
self.input.fm_pitch_ideal.setVisible(True)
|
||||
self.input.fm_focx.setVisible(False)
|
||||
self.input.fm_focy.setVisible(False)
|
||||
elif fm_focus in 'Focused':
|
||||
self.input.fm_pitch.setVisible(False)
|
||||
self.input.fm_pitch_ideal.setVisible(True)
|
||||
self.input.fm_focx.setVisible(False)
|
||||
self.input.fm_focy.setVisible(False)
|
||||
else: # Defocused
|
||||
self.input.fm_pitch.setVisible(False)
|
||||
self.input.fm_pitch_ideal.setVisible(True)
|
||||
self.input.fm_focx.setVisible(True)
|
||||
self.input.fm_focy.setVisible(True)
|
||||
|
||||
@SafeSlot()
|
||||
def calc_reality(self):
|
||||
config = self.get_reality_config()
|
||||
@@ -226,6 +256,18 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
self.input.cm_fm_harm_suppr.setLabel(f"Total Suppression Factor at {3 * self.input.energy.value():.0f} eV")
|
||||
|
||||
def get_assistant_config(self):
|
||||
|
||||
fm_focus = self.input.fm_focus.currentText()
|
||||
if fm_focus in 'Manual':
|
||||
fm_pitch = self.input.fm_pitch.value()
|
||||
fm_qy = None
|
||||
elif fm_focus in 'Focused':
|
||||
fm_pitch = self.input.fm_pitch_ideal.value()
|
||||
fm_qy = None
|
||||
else: # Focused
|
||||
fm_pitch = self.input.fm_pitch_ideal.value()
|
||||
fm_qy = self.qy
|
||||
|
||||
config = { # Config in SI units!
|
||||
'energy' : self.input.energy.value(),
|
||||
'h_acc' : self.input.sldi_hacc.value() * 1e-3,
|
||||
@@ -236,9 +278,10 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
'mo1_mode' : self.input.mo1_mode.currentText(),
|
||||
'mo1_xtal' : self.input.mo1_xtal.currentText(),
|
||||
'mo1_bragg' : self.bragg_angle,
|
||||
'fm_pitch' : -self.input.fm_pitch.value() * 1e-3,
|
||||
'fm_pitch' : -fm_pitch * 1e-3,
|
||||
'fm_stripe' : self.input.fm_stripe.currentText(),
|
||||
'fm_trx' : None,
|
||||
'fm_qy' : fm_qy,
|
||||
'fm_gain_height' : 1,
|
||||
'smpl' : self.input.smpl.value(),
|
||||
}
|
||||
@@ -364,15 +407,28 @@ class DigitalTwin(BECWidget, QWidget):
|
||||
@SafeSlot()
|
||||
def update_mo1_mode(self):
|
||||
if self.input.mo1_mode.currentText() in 'Monochromatic':
|
||||
self.input.mo1_xtal.setDisabled(False)
|
||||
self.input.mo1_xtal.setVisible(True)
|
||||
self.input.mo1_bragg_angle.setVisible(True)
|
||||
self.input.mo1_eres.setVisible(True)
|
||||
else:
|
||||
self.input.mo1_xtal.setDisabled(True)
|
||||
self.input.mo1_xtal.setVisible(False)
|
||||
self.input.mo1_bragg_angle.setVisible(False)
|
||||
self.input.mo1_eres.setVisible(False)
|
||||
|
||||
@SafeSlot()
|
||||
def calc_fm_ideal_pitch(self):
|
||||
p = bl.fm.center[1] # posFM
|
||||
q = self.input.smpl.value() - bl.fm.center[1] # dist posFM to posEX
|
||||
f = (p * q) / (p + q) # focal length
|
||||
if self.input.fm_focus.currentText() in 'Defocused':
|
||||
a = 2 * np.tan(self.input.sldi_hacc.value() * 1e-3) * bl.fm.center[1] # Beam width at focusing mirror
|
||||
b = 2 * np.tan(self.input.sldi_vacc.value() * 1e-3) * bl.cm.center[1] # Beam height at focusing mirror (collimated beam)
|
||||
x = self.input.fm_focx.value()
|
||||
y = self.input.fm_focy.value()
|
||||
qx = q + x * p / a
|
||||
self.qy = q + y * p / b
|
||||
f = (p * qx) / (p + qx) # focal length
|
||||
else: # Calculate for focused beam on sample in "manual" and "focused" mode
|
||||
f = (p * q) / (p + q) # focal length
|
||||
pitch = 0
|
||||
if 'Rh' in self.input.fm_stripe.currentText():
|
||||
pitch = np.arcsin(bl.fm.r[0]/(2*f))# ideal pitch for FM
|
||||
@@ -423,16 +479,16 @@ class InputPanel(QWidget):
|
||||
|
||||
# Collimating mirror
|
||||
self.cm_stripe = ComboBox('cm_stripe', 'Stripe', ['Si', 'Rh', 'Pt'])
|
||||
self.cm_pitch_critical = NumberIndicator('Critical Pitch', 'mrad', decimals=3)
|
||||
self.cm_pitch = InputNumberField('cm_pitch', 'Pitch [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-4.6, hl=-1.2)
|
||||
self.cm_pitch_critical = NumberIndicator('Critical Pitch', 'mrad', decimals=3)
|
||||
self.cm_refl = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
|
||||
self.cm_refl_harm = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
|
||||
self.cm_ass_group = Group(
|
||||
'Collimating Mirror',
|
||||
[
|
||||
self.cm_stripe,
|
||||
self.cm_pitch_critical,
|
||||
self.cm_pitch,
|
||||
self.cm_pitch_critical,
|
||||
self.cm_refl,
|
||||
self.cm_refl_harm,
|
||||
]
|
||||
@@ -455,16 +511,22 @@ class InputPanel(QWidget):
|
||||
|
||||
# Focusing Mirror
|
||||
self.fm_stripe = ComboBox('fm_stripe', 'Stripe', ['Rh (toroid)', 'Rh (flat)', 'Pt (toroid)', 'Pt (flat)'])
|
||||
self.fm_pitch_ideal = NumberIndicator('Ideal Incidence Angle', 'mrad', decimals=3)
|
||||
self.fm_focus = ComboBox('fm_focus', 'Focus Type', ['Manual', 'Focused', 'Defocused'])
|
||||
self.fm_pitch = InputNumberField('fm_pitch', 'Incidence Angle [mrad]', init=-2.391, decimals=3, single_step=0.01, ll=-10, hl=2)
|
||||
self.fm_focx = InputNumberField('fm_focx', 'Beam Size Horizontal [mm]', init=1, decimals=1, single_step=0.1, ll=0, hl=30)
|
||||
self.fm_focy = InputNumberField('fm_focy', 'Beam Size Vertical [mm]', init=1, decimals=1, single_step=0.1, ll=0, hl=10)
|
||||
self.fm_pitch_ideal = NumberIndicator('Incidence Angle for focused beam', 'mrad', decimals=3)
|
||||
self.fm_refl = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
|
||||
self.fm_refl_harm = NumberIndicator('Reflectivity at x eV', '%', decimals=0)
|
||||
self.fm_ass_group = Group(
|
||||
'Focusing Mirror',
|
||||
[
|
||||
self.fm_stripe,
|
||||
self.fm_pitch_ideal,
|
||||
self.fm_focus,
|
||||
self.fm_pitch,
|
||||
self.fm_focx,
|
||||
self.fm_focy,
|
||||
self.fm_pitch_ideal,
|
||||
self.fm_refl,
|
||||
self.fm_refl_harm,
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user