Commit 9885f6a4 authored by Michal Maciejewski's avatar Michal Maciejewski
Browse files

Introduced new GUI for HWC notebooks (RB, RQ, IT). Added images for IPD HWC notebooks.

parent 6058bbfc
%% Cell type:markdown id: tags:
<h1><center>Analysis of an FPA in an IT Circuit</center></h1>
The main quadrupole magnet circuits of the 8 Inner Triplet (IT) systems in the LHC are composed of four single aperture quadrupole magnets in series and have a particular powering configuration, consisting of three nested power converters (PC), see Figure below.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/IT.png" width=75%>
Main quadrupole magnet circuit of the Inner Triplet system for IT’s at points 1 and 5 (left) and IT’s at points 2 and 8 (right).
Note that the configuration for the IT’s in points 1 and 5 is different from the configuration in points 2 and 8. An earth detection system is present at the minus of the RTQX2 converter. Detailed information concerning the converters is given in EDMS 1054483. Note that the currents in the quadrupole magnets are given by:
\begin{equation}
I_\text{Q1} = I_\text{RQX} + I_\text{RTQX1} \\
I_\text{Q2} = I_\text{RQX} + I_\text{RTQX2} \\
I_\text{Q3} = I_\text{RQX} \\
\end{equation}
The two magnets Q1 and Q3 are type MQXA and the two combined magnets Q2a and Q2b are type MQXB. Q1 is located towards the interaction point.
Note that the IT’s at points 2 and 8 have a slightly higher nominal operating current than the IT’s at points 1 and 5, see Table 1.
|Circuit|I\_PNO RQX|I\_PNO RTQX2|I\_PNO RTQX1|
|-------|----------|------------|------------|
|RQX.L2, RQX.R2, RQX.L8, RQX.R8|7180 A| 4780 A|550 A|
|RQX.L1, RQX.R1, RQX.L5, RQX.R5|6800 A| 4600 A|550 A|
Nominal operating currents for 7 TeV of the three PC’s as given in the LHC design report volume I. For the nominal current during HWC see EDMS 1375861.
source: Test Procedure and Acceptance Criteria for the Inner Triplet Circuits in the LHC, MP3 Procedure, <a href="https://edms.cern.ch/document/874886/2.1">https://edms.cern.ch/document/874886/2.1</a>
%% Cell type:markdown id: tags:
# Analysis Assumptions
- We consider standard analysis scenarios, i.e., all signals can be queried. If a signal is missing, an analysis can raise a warning and continue or an error and abort the analysis.
- In case a signal is not needed for the analysis, a particular analysis is skipped. In other words, all signals have to be available in order to perform an analysis.
- It is recommended to execute each cell one after another. However, since the signals are queried prior to analysis, any order of execution is allowed. In case an analysis cell is aborted, the following ones may not be executed (e.g. I\_MEAS not present).
# Plot Convention
- Scales are labeled with signal name followed by a comma and a unit in square brackets, e.g., I_MEAS, [A].
- If a reference signal is present, it is represented with a dashed line.
- If the main current is present, its axis is on the left. Remaining signals are attached to the axis on the right. The legend of these signals is located on the lower left and upper right, respectively.
- The grid comes from the left axis.
- The title contains timestamp, circuit name, and signal name allowing to re-access the signal.
- The plots assigned to the left scale have colors: blue (C0) and orange (C1). Plots presented on the right have colors red (C2) and green (C3).
- Each plot has an individual time-synchronization mentioned explicitly in the description.
- If an axis has a single signal, then the color of the label matches the signal's color. Otherwise, the label color is black.
%% Cell type:markdown id: tags:
# 0. Initialise Working Environment
%% Cell type:code id: tags:
``` python
import io
import re
import sys
import pandas as pd
import numpy as np
from datetime import datetime
import time
from IPython.display import display, Javascript, HTML
from lhcsmapi.Time import Time
from lhcsmapi.Timer import Timer
from lhcsmapi.pyedsl.QueryBuilder import QueryBuilder
from lhcsmapi.analysis.ItCircuitQuery import ItCircuitQuery
from lhcsmapi.analysis.ItCircuitAnalysis import ItCircuitAnalysis
from lhcsmapi.analysis.expert_input import get_expert_decision
from lhcsmapi.analysis.report_template import apply_report_template
# GUI
from lhcsmapi.gui.qh.DateTimeBaseModule import DateTimeBaseModule
from lhcsmapi.gui.pc.FgcPmSearchModuleMediator import FgcPmSearchModuleMediator
from lhcsmapi.gui.pc.ItFgcPmSearchBaseModule import ItFgcPmSearchBaseModule
analysis_start_time = datetime.now().strftime("%Y.%m.%d_%H%M%S.%f")
import lhcsmapi
print('Analysis executed with lhcsmapi version: {}'.format(lhcsmapi.__version__))
with io.open("../__init__.py", "rt", encoding="utf8") as f:
version = re.search(r'__version__ = "(.*?)"', f.read()).group(1)
print('Analysis executed with lhc-sm-hwc notebooks version: {}'.format(version))
```
%% Cell type:markdown id: tags:
# 1. Select FGC Post Mortem Entry
%% Cell type:markdown id: tags:skip_cell
In order to perform the analysis of a FPA in an IT circuit please:
1. Select circuit name (e.g., RQX.R1)
2. Choose start and end time
3. Choose analysis mode (Automatic by default)
Once these inputs are provided, click 'Find FGC PM entries' button. This will trigger a search of the PM database in order to provide a list of timestamps of FGC events associated with the selected circuit name for the provided period of time. Select one timestamp from the 'FGC PM Entries' list to be processed by the following cells.
%% Cell type:code id: tags:
``` python
circuit_type = 'IT'
fgc_pm_search = FgcPmSearchModuleMediator(DateTimeBaseModule(start_date_time='2018-08-29 00:00:00+01:00',
end_date_time='2018-08-31 00:00:00+01:00'), ItFgcPmSearchBaseModule(), circuit_type=circuit_type)
```
%% Cell type:markdown id: tags:
# 2. Query All Signals Prior to Analysis
%% Cell type:code id: tags:skip_output
``` python
circuit_name = fgc_pm_search.get_circuit_name()
timestamp_fgc = fgc_pm_search.get_fgc_timestamp()
author = fgc_pm_search.get_author()
is_automatic = fgc_pm_search.is_automatic_mode()
it_query = ItCircuitQuery(circuit_type, circuit_name, max_executions=12)
with Timer():
# PIC
timestamp_pic = it_query.find_timestamp_pic(timestamp_fgc, spark=spark)
# PC
source_timestamp_fgc_df = QueryBuilder().with_pm() \
.with_duration(t_start=timestamp_fgc, duration=[(1, 's'), (1, 's')]) \
.with_circuit_type(circuit_type) \
.with_metadata(circuit_name=circuit_name, system='PC', source='*') \
.event_query().df
source_fgc_rqx, timestamp_fgc_rqx = it_query.split_source_timestamp_fgc(source_timestamp_fgc_df, 'RQX')
source_fgc_rtqx1, timestamp_fgc_rtqx1 = it_query.split_source_timestamp_fgc(source_timestamp_fgc_df, 'RTQX1')
source_fgc_rtqx2, timestamp_fgc_rtqx2 = it_query.split_source_timestamp_fgc(source_timestamp_fgc_df, 'RTQX2')
i_meas_rqx_df, i_ref_rqx_df, i_a_rqx_df, i_earth_rqx_df = it_query.query_pc_pm_with_source(timestamp_fgc_rqx, timestamp_fgc_rqx,
source_fgc_rqx, signal_names=['I_MEAS', 'I_REF', 'I_A', 'I_EARTH'])
i_meas_rtqx1_df, i_ref_rtqx1_df, i_a_rtqx1_df, i_earth_rtqx1_df = it_query.query_pc_pm_with_source(timestamp_fgc_rtqx1, timestamp_fgc_rtqx1,
source_fgc_rtqx1, signal_names=['I_MEAS', 'I_REF', 'I_A', 'I_EARTH'])
i_meas_rtqx2_df, i_ref_rtqx2_df, i_a_rtqx2_df, i_earth_rtqx2_df = it_query.query_pc_pm_with_source(timestamp_fgc_rtqx2, timestamp_fgc_rtqx2,
source_fgc_rtqx2, signal_names=['I_MEAS', 'I_REF', 'I_A', 'I_EARTH'])
i_meas_q1_df = pd.DataFrame(index=i_meas_rqx_df.index, data=i_meas_rqx_df.values + i_meas_rtqx1_df.values, columns=['I_MEAS_Q1'])
i_meas_q2_df = pd.DataFrame(index=i_meas_rqx_df.index, data=i_meas_rqx_df.values + i_meas_rtqx2_df.values, columns=['I_MEAS_Q2'])
i_meas_q3_df = pd.DataFrame(index=i_meas_rqx_df.index, data=i_meas_rqx_df.values, columns=['I_MEAS_Q3'])
# QDS
source_timestamp_qds_df = it_query.find_source_timestamp_qds(timestamp_fgc_rqx, duration=[(2, 's'), (2, 's')])
timestamp_qds = np.nan if source_timestamp_qds_df.empty else source_timestamp_qds_df.loc[0, 'timestamp']
u_res_q1_df, u_res_q2_df, u_res_q3_df = it_query.query_qds_pm(timestamp_qds, timestamp_qds, signal_names=['U_RES_Q1', 'U_RES_Q2', 'U_RES_Q3'])
u_1_q1_df, u_1_q2_df, u_1_q3_df = it_query.query_qds_pm(timestamp_qds, timestamp_qds, signal_names=['U_1_Q1', 'U_1_Q2', 'U_1_Q3'])
u_2_q1_df, u_2_q2_df, u_2_q3_df = it_query.query_qds_pm(timestamp_qds, timestamp_qds, signal_names=['U_2_Q1', 'U_2_Q2', 'U_2_Q3'])
# QH
u_hds_dfss = it_query.query_qh_pm(source_timestamp_qds_df, signal_names=['U_HDS'])
u_hds_dfs = u_hds_dfss[0] if u_hds_dfss else []
# # Reference
u_hds_ref_dfss = it_query.query_qh_pm(source_timestamp_qds_df, signal_names=['U_HDS'], is_ref=True)
u_hds_ref_dfs = u_hds_ref_dfss[0] if u_hds_ref_dfss else []
# LEADS
u_hts_dfs = it_query.query_leads(timestamp_fgc, source_timestamp_qds_df, system='LEADS', signal_names=['U_HTS'], spark=spark, duration=[(300, 's'), (900, 's')])
u_res_dfs = it_query.query_leads(timestamp_fgc, source_timestamp_qds_df, system='LEADS', signal_names=['U_RES'], spark=spark, duration=[(300, 's'), (900, 's')])
# Results Table
results_table = it_query.create_report_analysis_template(timestamp_fgc=timestamp_fgc, author=author)
it_analysis = ItCircuitAnalysis(circuit_type, results_table, is_automatic=is_automatic)
```
%% Cell type:markdown id: tags:
# 3. Timestamps
The analysis for MP3 consists of checking the existence of PM file and of consistency of the PM timestamps (PC, QPS). The criterion of passing this test described in detail in 600APIC2.
In short the following criteria should be checked:
- The PC timestamp (51_self) is QPS timestamp +-20 ms.
- The difference between QPS board A and B timestamp = 1ms.
If one or more of these conditions are not fulfilled, then an in-depth analysis has to be performed by the QPS team.
%% Cell type:code id: tags:
``` python
timestamp_dct = {'FGC_RQX': timestamp_fgc_rqx, 'FGC_RTQX1': timestamp_fgc_rtqx1, 'FGC_RTQX2': timestamp_fgc_rtqx2,
'PIC': timestamp_pic,
'QDS_A':source_timestamp_qds_df.loc[0, 'timestamp'] if len(source_timestamp_qds_df) > 0 else np.nan,
'QDS_B':source_timestamp_qds_df.loc[1, 'timestamp'] if len(source_timestamp_qds_df) > 1 else np.nan}
it_analysis.create_timestamp_table(timestamp_dct)
```
%% Cell type:markdown id: tags:
# 4. PC
## 4.1. Main Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_meas_rq_df |DataFrame |A |PM|Main current of a power converter, I_MEAS_RQX, I_MEAS_RTQX1, I_MEAS_RTQX2|
|i_a_rq_df |DataFrame |A |PM|Actual current of a power converter, I_A_RQX, I_A_RTQX1, I_A_RTQX2|
|i_ref_rq_df |DataFrame |A |PM|Reference current of the RQX power converter, I_REF_RQX, I_REF_RTQX1, I_REF_RTQX2|
Note that **rq** in the table above denotes RQX, RTQX1, and RTQX2, i.e., there are three signals for each power converter.
*ANALYSIS*:
- calculation of the ramp rate
- calculation of the duration of a plateau prior to a quench
- calculation of DCCT MIIts
*GRAPHS*:
- t = 0 s corresponds to the FGC timestamp
- one plot for each power converter
%% Cell type:code id: tags:
``` python
it_analysis.plot_i_meas_pc(circuit_name, timestamp_fgc_rqx, [i_meas_rqx_df, i_meas_rtqx1_df, i_meas_rtqx2_df, i_ref_rqx_df, i_ref_rtqx1_df, i_ref_rtqx2_df], [], xlim=(-0.1, 0.5))
```
%% Cell type:code id: tags:
``` python
t_quench = it_analysis.find_time_of_quench(i_ref_rqx_df)
it_analysis.plot_i_meas_pc(circuit_name, timestamp_fgc_rqx, [i_meas_rqx_df, i_a_rqx_df], i_ref_rqx_df,
xlim=(-0.1, 0.2), ylim=(i_meas_rqx_df.max().values[0]-1500, i_meas_rqx_df.max().values[0]+500))
it_analysis.calculate_current_slope(i_meas_rqx_df.rename(columns={'STATUS.I_MEAS_RQX': 'STATUS.I_MEAS'}))
it_analysis.calculate_current_miits(i_meas_rqx_df, t_quench, col_name='MITTs_DCCT_RQX')
it_analysis.calculate_quench_current(i_meas_rqx_df, t_quench, col_name='I_RQX')
```
%% Cell type:code id: tags:
``` python
it_analysis.plot_i_meas_pc(circuit_name.replace('RQX', 'RTQX1'), timestamp_fgc_rqx, [i_meas_rtqx1_df, i_a_rtqx1_df], i_ref_rtqx1_df,
xlim=(-0.1, 0.2), ylim=(i_meas_rtqx1_df.max().values[0] - 250, i_meas_rtqx1_df.max().values[0] + 250))
it_analysis.calculate_current_slope(i_meas_rtqx1_df.rename(columns={'STATUS.I_MEAS_RTQX1': 'STATUS.I_MEAS'}))
it_analysis.calculate_current_miits(i_meas_rtqx1_df, t_quench, col_name='MITTs_DCCT_RTQX1')
it_analysis.calculate_quench_current(i_meas_rtqx1_df, t_quench, col_name='I_RTQX1')
```
%% Cell type:code id: tags:
``` python
it_analysis.plot_i_meas_pc(circuit_name.replace('RQX', 'RTQX2'), timestamp_fgc_rqx, [i_meas_rtqx2_df, i_a_rtqx2_df], i_ref_rtqx2_df,
xlim=(-0.1, 0.2), ylim=(i_meas_rtqx2_df.max().values[0] - 1500, i_meas_rtqx2_df.max().values[0] + 500))
it_analysis.calculate_current_slope(i_meas_rtqx2_df.rename(columns={'STATUS.I_MEAS_RTQX2': 'STATUS.I_MEAS'}))
it_analysis.calculate_current_miits(i_meas_rtqx2_df, t_quench, col_name='MITTs_DCCT_RTQX2')
it_analysis.calculate_quench_current(i_meas_rtqx2_df, t_quench, col_name='I_RTQX2')
```
%% Cell type:markdown id: tags:
## 4.2. Magnet Current
*QUERY*:
*No need for a query as the magnet currents are calculated from I_MEAS power converter currents*
|Variable Name |Variable Type |Variable Unit |Comment
|---------------|---------------|---------------|------|
|i_meas_q_df |DataFrame |A |Main current of the Q1 magnet, I_MEAS_Q1, I_MEAS_Q2, I_MEAS_Q3|
Note that **q** in the table above denotes Q1, Q2, and Q3, i.e., there is one signal for each magnet.
*ANALYSIS*:
- calculation of the magnet MIITs
- calculation of the quench current
*GRAPHS*:
- t = 0 s corresponds to the FGC timestamp
- one plot for each magnet
%% Cell type:code id: tags:
``` python
it_analysis.plot_magnet_current(circuit_name, timestamp_fgc, i_meas_q1_df, i_meas_q2_df, i_meas_q3_df)
it_analysis.calculate_current_miits(i_meas_q1_df, t_quench, col_name='MITTs_Q1')
it_analysis.calculate_quench_current(i_meas_q1_df, t_quench, col_name='I_Q1')
it_analysis.calculate_current_miits(i_meas_q2_df, t_quench, col_name='MITTs_Q2')
it_analysis.calculate_quench_current(i_meas_q2_df, t_quench, col_name='I_Q2')
it_analysis.calculate_current_miits(i_meas_q3_df, t_quench, col_name='MITTs_Q3')
it_analysis.calculate_quench_current(i_meas_q3_df, t_quench, col_name='I_Q3')
```
%% Cell type:markdown id: tags:
## 4.3. Earth Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|-------|
|i_earth_rq_df |DataFrame |A |PM|Main current of the RQX power converter, I_EARTH_RQX, I_EARTH_RTQX1, I_EARTH_RTQX2|
Note that **rq** in the table above denotes RQX, RTQX1, and RTQX2, i.e., there is one signal for each power converter.
*ANALYSIS*:
- calculation of the maximum earth current
*GRAPHS*:
- t = 0 s corresponds to the FGC timestamp
- one plot for each power converter
%% Cell type:code id: tags:
``` python
it_analysis.plot_i_earth_pc(circuit_name, timestamp_fgc_rqx, i_earth_rqx_df)
it_analysis.calculate_max_i_earth_pc(i_earth_rqx_df, col_name='max_I_EARTH_RQX')
```
%% Cell type:code id: tags:
``` python
it_analysis.plot_i_earth_pc(circuit_name.replace('RQX', 'RTQX1'), timestamp_fgc_rtqx1, i_earth_rtqx1_df)
it_analysis.calculate_max_i_earth_pc(i_earth_rtqx1_df, col_name='max_I_EARTH_RTQX1')
```
%% Cell type:code id: tags:
``` python
it_analysis.plot_i_earth_pc(circuit_name.replace('RQX', 'RTQX2'), timestamp_fgc_rtqx2, i_earth_rtqx2_df)
it_analysis.calculate_max_i_earth_pc(i_earth_rtqx2_df, col_name='max_I_EARTH_RTQX2')
```
%% Cell type:markdown id: tags:
# 5. Quench Protection System
The signal names used for quench detection are shown in Figure below (picture from A. Erokhin).
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/IT_QPS_Signals.png" width=50%>
A quench in the superconducting circuits is detected and all the quench heaters are fired as soon as one of the following signals exceeds the threshold.
\begin{equation}
U_\text{RES,Q1} = U_\text{1,Q1} + U_\text{2,Q1} \\
U_\text{RES,Q2} = U_\text{1,Q2} + U_\text{2,Q2} \\
U_\text{RES,Q3} = U_\text{1,Q3} + U_\text{2,Q3} \\
\end{equation}
More details on the QPS system and the quench heaters can be found on the MP3 web site (https://cern.ch/MP3).
%% Cell type:markdown id: tags:
## 5.1. Resistive Voltage
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|u_res_q_df |DataFrame |V |PM|Resistive voltage of magnets measured with QPS, U_RES_Q1, U_RES_Q2, U_RES_Q3|
|u_1_q_df |DataFrame |V |PM|Voltage of the first aperture measured with QPS, U_1_Q1, U_1_Q2, U_1_Q3|
|u_2_q_df |DataFrame |V |PM|Voltage of the first aperture measured with QPS, U_2_Q1, U_2_Q2, U_2Tak_Q3|
Note that **q** in the table above denotes Q1, Q2, and Q3, i.e., there are three signals for each magnet.
*ANALYSIS*:
- Initial voltage slope of U_RES signal. The slope is calculated as a ratio of the voltage change from 50 to 200 mV and the corresponding time change.
- Origin of a quench, i.e., name of the first magnet for which the U_RES voltage exceeded the 100 mV threshold.
*GRAPHS*:
t = 0 s corresponds to the QPS timestamp
%% Cell type:code id: tags:
``` python
it_analysis.plot_u_res_q1_q2_q3(circuit_name, timestamp_qds, u_res_q1_df, u_res_q2_df, u_res_q3_df)
it_analysis.find_quench_origin(u_res_q1_df, u_res_q2_df, u_res_q3_df)
```
%% Cell type:code id: tags:
``` python
u_res_q1_slope_df = it_analysis.calculate_u_res_slope(u_res_q1_df, col_name='dU_RES_dt_Q1')
it_analysis.plot_u_res_u_res_slope_u_1_u_2(circuit_name, timestamp_qds, u_res_q1_df, u_res_q1_slope_df, u_1_q1_df, u_2_q1_df, suffix='_Q1')
```
%% Cell type:code id: tags:
``` python
u_res_q2_slope_df = it_analysis.calculate_u_res_slope(u_res_q2_df, col_name='dU_RES_dt_Q2')
it_analysis.plot_u_res_u_res_slope_u_1_u_2(circuit_name, timestamp_qds, u_res_q2_df, u_res_q2_slope_df, u_1_q2_df, u_2_q2_df, suffix='_Q2')
```
%% Cell type:code id: tags:
``` python
u_res_q3_slope_df = it_analysis.calculate_u_res_slope(u_res_q3_df, col_name='dU_RES_dt_Q3')
it_analysis.plot_u_res_u_res_slope_u_1_u_2(circuit_name, timestamp_qds, u_res_q3_df, u_res_q3_slope_df, u_1_q3_df, u_2_q3_df, suffix='_Q3')
```
%% Cell type:markdown id: tags:
## 5.2. Current Leads
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|u_res_dfs |DataFrame |V |PM|Leads resisitive voltage, U_RES|
|u_hts_dfs |DataFrame |V |PM|Leads HTS voltage, U_HTS|
*CRITERIA*:
- quench detection for U_HTS for 2 consecutive datapoints above the threshold of 3 mV
- detection for U_RES for 2 consecutive datapoints above the threshold of 100 mV
*GRAPHS*:
- t = 0 s corresponds to the LEADS timestamp.
%% Cell type:code id: tags:
``` python
it_analysis.analyze_leads_voltage(u_hts_dfs, circuit_name, timestamp_qds, signal='U_HTS', value_min=-0.003, value_max=0.003)
```
%% Cell type:code id: tags:
``` python
it_analysis.analyze_leads_voltage(u_res_dfs, circuit_name, timestamp_qds, signal='U_RES', value_min=-0.1, value_max=0.1)
```
%% Cell type:code id: tags:
``` python
it_analysis.results_table['Reason'] = get_expert_decision('Reason for FPA: ', ['quench', 'coupling', 'other'])
```
%% Cell type:markdown id: tags:
## 5.3. Quench Heaters
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|u_hds_dfs |list of DataFrame| V |PM| A list of U_HDS_1-2/U_HDS_1-4, signals from PM for quenched magnets|
|u_hds_ref_dfs |list of DataFrame| V |PM| A list of U_HDS_1-2 from PM for reference magnets|
*CRITERIA*:
- all characteristic times of an exponential decay calculated with the 'charge' approach for voltage is +/- 5 ms from the reference ones
- the initial voltage should be between 810 V and 1000 V
- the final voltage should be between 0 V and 10 V
*GRAPHS*:
t = 0 s corresponds to the start of the pseudo-exponential decay
Voltage view (linear and log)
- the queried and filtered quench heater voltage on the left axis (actual signal continuous, reference dashed), U_HDS
%% Cell type:code id: tags:
``` python
if u_hds_dfs:
it_analysis.analyze_qh(circuit_name, timestamp_qds, u_hds_dfs, u_hds_ref_dfs)
```
%% Cell type:markdown id: tags:
# 6. Final Report
%% Cell type:code id: tags:
``` python
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
!mkdir -p /eos/project/l/lhcsm/operation/IT/$circuit_name
file_name = "{}-{}-PM_IT_FPA".format(Time.to_datetime(timestamp_fgc).strftime("%Y.%m.%d_%H%M%S.%f"), analysis_start_time)
full_path = '/eos/project/l/lhcsm/operation/IT/{}/{}_mp3_results_table.csv'.format(circuit_name, file_name)
mp3_results_table = it_analysis.create_mp3_results_table()
display(HTML(mp3_results_table.T.to_html()))
mp3_results_table.to_csv(full_path)
print('MP3 results table saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
apply_report_template()
file_name_html = file_name + '_report.html'
full_path = '/eos/project/l/lhcsm/operation/IT/{}/{}'.format(circuit_name, file_name_html)
print('Compact notebook report saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
display(Javascript('IPython.notebook.save_notebook();'))
time.sleep(5)
!{sys.executable} -m jupyter nbconvert --to html $'AN_IT_FPA.ipynb' --output /eos/project/l/lhcsm/operation/IT/$circuit_name/$file_name_html --TemplateExporter.exclude_input=True --TagRemovePreprocessor.remove_all_outputs_tags='["skip_output"]' --TagRemovePreprocessor.remove_cell_tags='["skip_cell"]'
```
%% Cell type:code id: tags:
``` python
```
......
This diff is collapsed.
%% Cell type:markdown id: tags:
<h1><center>Analysis of a PNO.A9 HWC Test in an IT Circuit</center></h1>
The main quadrupole magnet circuits of the 8 Inner Triplet (IT) systems in the LHC are composed of four single aperture quadrupole magnets in series and have a particular powering configuration, consisting of three nested power converters (PC), see Figure below.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/IT.png" width=75%>
Main quadrupole magnet circuit of the Inner Triplet system for IT’s at points 1 and 5 (left) and IT’s at points 2 and 8 (right).
Note that the configuration for the IT’s in points 1 and 5 is different from the configuration in points 2 and 8. An earth detection system is present at the minus of the RTQX2 converter. Detailed information concerning the converters is given in EDMS 1054483. Note that the currents in the quadrupole magnets are given by:
\begin{equation}
I_\text{Q1} = I_\text{RQX} + I_\text{RTQX1} \\
I_\text{Q2} = I_\text{RQX} + I_\text{RTQX2} \\
I_\text{Q3} = I_\text{RQX} \\
\end{equation}
The two magnets Q1 and Q3 are type MQXA and the two combined magnets Q2a and Q2b are type MQXB. Q1 is located towards the interaction point.
Note that the IT’s at points 2 and 8 have a slightly higher nominal operating current than the IT’s at points 1 and 5, see Table 1.
|Circuit|I\_PNO RQX|I\_PNO RTQX2|I\_PNO RTQX1|
|-------|----------|------------|------------|
|RQX.L2, RQX.R2, RQX.L8, RQX.R8|7180 A| 4780 A|550 A|
|RQX.L1, RQX.R1, RQX.L5, RQX.R5|6800 A| 4600 A|550 A|
### PNO.A9: Training and plateau at nominal current
The aim of this test is:
- to reach nominal current with a small margin, required for stable operation, which might require some training quenches,
- to check the correct behaviour of the leads during a plateau,
- to check the splice resistances,
- to check the correct functioning of the PC’s during a current cycle.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/PNO.A9_current_pcs.png" width=75%>
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/PNO.A9_current_magnets.png" width=75%>
<center>Currents vs time for test PLNO.A9.</center>
The offline analysis is given in the table below:
|Responsible|Type of analysis|Criteria|
|-----------|----------------|--------|
|PC|Verification of the tracking error between I_REF and I_MEAS for the three PC's|I_ERR < 10 ppm|
|~|~|I_EARTH < 10 mA (online checked by the sequencer)|
|MP3|Calculate splice resistances|R_max < 5 nOhm|
|MP3|Check DFB regulation|T_top_HTS (TT891A) = 50 +/- 4K|
|~|~|T_top_Cu (TT893) = 293 +/- 10 K|
|MP3|Check margin between U_RES and the QPS threshold|U_RES < 30 mV for both boards at the start of the PC fault|
|MP3|Quench analysis, in case a quench occurs (for details see cern.ch/MP3 and AN_IT_FPA notebook|U_HDS_1-8 within 5 % of the reference signals.|
|~|~|Delay between QPS trigger and heater firing less than 10 ms.|
|~|~|I_MEAS and V_MEAS (of RQX and RTQX2 converters) within 10% and 20%, respectively, od the reference signals (for a quench close to nominal current)|
|~|~|I_EARTH within 20% of the reference|
source: Test Procedure and Acceptance Criteria for the Inner Triplet Circuits in the LHC, MP3 Procedure, <a href="https://edms.cern.ch/document/874886/2.1">https://edms.cern.ch/document/874886/2.1</a>
%% Cell type:markdown id: tags:
# Analysis Assumptions
- We consider standard analysis scenarios, i.e., all signals can be queried. Depending on what signal is missing, an analysis can raise a warning and continue or an error and abort the analysis.
- In case an analyzed signal can't be queried, a particular analysis is skipped. In other words, all signals have to be available in order to perform an analysis.
- It is recommended to execute each cell one after another. However, since the signals are queried prior to an analysis, any order of execution is allowed. In case an analysis cell is aborted, the following ones may not be executed (e.g. I\_MEAS not present).
# Plot Convention
- Scales are labeled with signal name followed by a comma and a unit in the square bracket, e.g., I_MEAS, [A]
- If a reference signal is present, it is represented with a dashed line
- If the main current is present, its axis is on the left. Remaining signals are attached to the axis on the right. The legend of these signals is located on the lower left and upper right, respectively.
- The grid comes from the left axis
- Title contains timestamp, circuit name, signal name allowing for re-access the signal.
- The plots assigned to the left scale got colors: blue (C0) and orange (C1). Plots presented on the right have colors red (C2) and green (C3).
- Each plot has an individual time-synchronization mentioned explicitly in the description.
- If an axis has a single signal, change color of the label to match the signal's color. Otherwise, the label color is black.
%% Cell type:markdown id: tags:
# 0. Initialise Working Environment
%% Cell type:code id: tags:
``` python
import io
import re
import sys
import pandas as pd
from datetime import datetime
import time
from IPython.display import display, Javascript
from lhcsmapi.Time import Time
from lhcsmapi.Timer import Timer
from lhcsmapi.pyedsl.QueryBuilder import QueryBuilder
from lhcsmapi.pyedsl.PlotBuilder import PlotBuilder
import lhcsmapi.pyedsl.SignalTransformationBuilder as SignalTransformationBuilder
from lhcsmapi.pyedsl.AssertionBuilder import AssertionBuilder
from lhcsmapi.analysis.ItCircuitQuery import ItCircuitQuery
from lhcsmapi.analysis.ItCircuitAnalysis import ItCircuitAnalysis
# GUI
from lhcsmapi.gui.hwc.HwcBrowser import HwcBrowser
from lhcsmapi.gui.hwc.HwcSearchModuleMediator import HwcSearchModuleMediator
analysis_start_time = datetime.now().strftime("%Y.%m.%d_%H%M%S.%f")
import lhcsmapi
print('Analysis executed with lhcsmapi version: {}'.format(lhcsmapi.__version__))
with io.open("../__init__.py", "rt", encoding="utf8") as f:
version = re.search(r'__version__ = "(.*?)"', f.read()).group(1)
print('Analysis executed with lhc-sm-hwc notebooks version: {}'.format(version))
```
%% Cell type:markdown id: tags:
# 1. Select HWC Test
%% Cell type:code id: tags:
``` python
circuit_type = 'IT'
hwc_test = 'PNO.A9'
hwc_test_history_df = pd.read_csv('/eos/project/l/lhcsm/hwc/IT/hwc_test_history.csv')
hwcb = HwcBrowser(hwc_test_history_df, circuit_type, hwc_test)
display(hwcb.widget)
hwc_test = 'PNO.a9'
hwcb = HwcSearchModuleMediator(circuit_type=circuit_type, hwc_test=hwc_test, hwc_summary_path='/eos/project/l/lhcsm/hwc/HWC_Summary.csv')
```
%% Cell type:markdown id: tags:
# 2. Query All Signals Prior to Analysis
%% Cell type:code id: tags:skip_output
``` python
circuit_name = hwcb.get_circuit_name()
t_start = hwcb.get_start_time()
t_end = hwcb.get_end_time()
author = hwcb.get_author()
is_automatic = hwcb.is_automatic_mode()
it_query = ItCircuitQuery(circuit_type, circuit_name)
it_analysis = ItCircuitAnalysis(circuit_type, results_table=None, is_automatic=is_automatic)
with Timer():
# PC - NXCALS
i_meas_rqx_nxcals_df, i_meas_rtqx1_nxcals_df, i_meas_rtqx2_nxcals_df = it_query.query_signal_nxcals(t_start, t_end, system='PC', signal_names='I_MEAS', spark=spark)
i_meas_rqx_nxcals_df.rename(columns={"I_MEAS": "I_MEAS_RQX"}, inplace=True)
i_meas_rtqx1_nxcals_df.rename(columns={"I_MEAS": "I_MEAS_RTQX1"}, inplace=True)
i_meas_rtqx2_nxcals_df.rename(columns={"I_MEAS": "I_MEAS_RTQX2"}, inplace=True)
# I_Q1 = I_RQX + I_RTQX1
i_meas_q1_nxcals_df = SignalTransformationBuilder.add_two_dataframes(i_meas_rqx_nxcals_df, i_meas_rtqx1_nxcals_df, col_name='I_MEAS_Q1')
# I_Q2 = I_RQX + I_RTQX2
i_meas_q2_nxcals_df = SignalTransformationBuilder.add_two_dataframes(i_meas_rqx_nxcals_df, i_meas_rtqx2_nxcals_df, col_name='I_MEAS_Q2')
# I_Q3 = I_RQX
i_meas_q3_nxcals_df = pd.DataFrame(index=i_meas_rqx_nxcals_df.index, data=i_meas_rqx_nxcals_df.values, columns=['I_MEAS_Q3'])
# PC - PM
source_timestamp_fgc_df = QueryBuilder().with_pm() \
.with_duration(t_start=t_start, t_end=t_end) \
.with_circuit_type(circuit_type) \
.with_metadata(circuit_name=circuit_name, system='PC', source='*') \
.event_query().df
timestamp_fgc = min(source_timestamp_fgc_df['timestamp'].values)
# QDS - U_RES
u_res_dfs = it_query.query_signal_nxcals(t_start, t_end, system='QDS', signal_names=['U_RES_Q1', 'U_RES_Q2', 'U_RES_Q3'], spark=spark)
# Splice resistance
plateau_start, plateau_end = it_query.calculate_current_plateau_start_end(Time.to_unix_timestamp(t_start), Time.to_unix_timestamp(t_end), i_meas_threshold=0, min_duration_in_sec=10, spark=spark)
u_mag_feature_df, i_meas_feature_df = it_query.get_busbar_resistances(Time.to_unix_timestamp(t_start), Time.to_unix_timestamp(t_end), plateau_start, plateau_end,
signal_name=['U_RES_Q1', 'U_RES_Q2', 'U_RES_Q3'], system='QDS', spark=spark)
r_res_df = it_analysis.calculate_resistance(i_meas_feature_df, u_mag_feature_df)
# DFB
tt893_nxcals_dfs = it_query.query_dfb_signal_nxcals(t_start, t_end, system='LEADS_NXCALS_WINCCOA', signal_names='TT893', spark=spark)
tt891a_nxcals_dfs = it_query.query_dfb_signal_nxcals(t_start, t_end, system='LEADS_NXCALS_WINCCOA', signal_names='TT891A', spark=spark)
cv891_nxcals_dfs = it_query.query_dfb_signal_nxcals(t_start, t_end, system='LEADS_NXCALS_WINCCOA', signal_names='CV891', spark=spark)
u_res_nxcals_dfs = it_query.query_signal_nxcals(t_start, t_end, system='LEADS', signal_names='U_RES', spark=spark)
u_hts_nxcals_dfs = it_query.query_signal_nxcals(t_start, t_end, system='LEADS', signal_names='U_HTS', spark=spark)
```
%% Cell type:markdown id: tags:
# 3. PC
## 3.1. Main Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_meas_rq_nxcals_df |DataFrame |A |NXCALS|Main current of a power converter, I_MEAS_RQX, I_MEAS_RTQX1, I_MEAS_RTQX2|
Note that **rq** in the table above denotes RQX, RTQX1, and RTQX2, i.e., there are three signals for each power converter.
*GRAPHS*:
- t = 0 s corresponds to the start time of the test
%% Cell type:code id: tags:
``` python
title = '%s, %s: %s-%s' % (circuit_name, hwc_test, Time.to_string(t_start).split('.')[0], Time.to_string(t_end).split('.')[0])
ax = PlotBuilder().with_signal([i_meas_rqx_nxcals_df, i_meas_rtqx2_nxcals_df], title=title, grid=True) \
.with_ylabel(ylabel='I_MEAS_RQX, I_MEAS_RTQX2, [A]') \
.with_signal(i_meas_rtqx1_nxcals_df) \
.with_ylabel(ylabel='I_MEAS_RTQX1, [A]') \
.with_ylim((0, 600)) \
.plot(show_plot=False).get_axes()[0]
for ps, pe in zip(plateau_start, plateau_end):
ax.axvspan(xmin=(ps-Time.to_unix_timestamp(t_start))/1e9, xmax=(pe-Time.to_unix_timestamp(t_start))/1e9, facecolor='xkcd:orange')
```
%% Cell type:markdown id: tags:
## 3.2. Magnet Current
*QUERY*:
- *No query is needed as the magnet current is calculated from I_MEAS power converter currents*
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_meas_q1_df |DataFrame |A |NXCALS|Main current of the Q1 magnet, I_MEAS_Q1|
|i_meas_q2_df |DataFrame |A |NXCALS|Main current of the Q2 magnet, I_MEAS_Q2|
|i_meas_q3_df |DataFrame |A |NXCALS|Main current of the Q3 magnet, I_MEAS_Q3|
*GRAPHS*:
- t = 0 s corresponds to the start of the test
%% Cell type:code id: tags:
``` python
PlotBuilder().with_signal([i_meas_q1_nxcals_df, i_meas_q2_nxcals_df, i_meas_q3_nxcals_df], title=title, grid=True) \
.with_ylabel(ylabel='I, [A]') \
.plot()
```
%% Cell type:markdown id: tags:
# 4. Quench Detection System
The signal names used for quench detection are shown in Figure below (picture from A. Erokhin).
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/IT_QPS_Signals.png" width=75%>
A quench in the superconducting circuits is detected and all the quench heaters are fired as soon as one of the following signals exceeds the threshold.
\begin{equation}
U_\text{RES,Q1} = U_\text{1,Q1} + U_\text{2,Q1} \\
U_\text{RES,Q2} = U_\text{1,Q2} + U_\text{2,Q2} \\
U_\text{RES,Q3} = U_\text{1,Q3} + U_\text{2,Q3} \\
\end{equation}
More details on the QPS system and the quench heaters can be found on the MP3 web site (https://cern.ch/MP3).
%% Cell type:markdown id: tags:
## 4.1. Resistive Voltage
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Comment
|---------------|---------------|---------------|------|
|u_res_df |DataFrame |V |Resistive voltage of magnets measured with QPS, U_RES|
*CRITERIA*:
- Check if U_RES < 30 mV for both boards at the start of the PC fault
*GRAPHS*:
- t = 0 s corresponds to the start of the test
%% Cell type:code id: tags:
``` python
AssertionBuilder().with_signal(u_res_dfs) \
.for_time_greater_than(t_greater=(timestamp_fgc-Time.to_unix_timestamp(t_start))/1e9) \
.has_min_max_value(value_min=-30e-3, value_max=30e-3) \
.show_plot(ylabel='U_RES, [V]')
```
%% Cell type:markdown id: tags:
## 4.2. Splice Resistance
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Databse|Comment
|---------------|---------------|---------------|-------|------|
|i_meas_features_df |DataFrame| A |NXCALS| Power converter current mean values|
|u_res_features_df |DataFrame| V |NXCALS| U_RES voltage mean values|
*ANALYSIS*:
- Calculate splice resistance values based on power converter currents and QDS voltages
*CRITERIA*
- Check if R_max < 5 nOhm
*GRAPHS*:
- t = 0 s corresponds to the start of the test
%% Cell type:code id: tags:
``` python
for i_q_df, u_res_df in zip([i_meas_q1_nxcals_df, i_meas_q2_nxcals_df, i_meas_q3_nxcals_df], u_res_dfs):
ax = PlotBuilder().with_signal(i_q_df, title=title, grid=True) \
.with_ylabel(ylabel='I_Q, [A]') \
.with_signal(u_res_df) \
.with_ylabel(ylabel='U_RES_Q, [V]') \
.plot(show_plot=False).get_axes()[0]
for ps, pe in zip(plateau_start, plateau_end):
ax.axvspan(xmin=(ps-Time.to_unix_timestamp(t_start))/1e9, xmax=(pe-Time.to_unix_timestamp(t_start))/1e9, facecolor='xkcd:orange')
```
%% Cell type:code id: tags:
``` python
res_magnet_rqd_outliers_df = it_analysis.analyze_busbar_magnet_resistance(r_res_df, signal_name='R_RES', max_value=5-9)
res_magnet_rqd_outliers_df = it_analysis.analyze_busbar_magnet_resistance(r_res_df, signal_name='R_RES', max_value=5e-9)
```
%% Cell type:markdown id: tags:
## 4.3. DFB Regulation
*QUERY*
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|tt893_nxcals_dfs |list of DataFrames |K |NXCALS|Temperature at the top of the current lead, TT893.TEMPERATURECALC|
|tt891a_nxcals_dfs |list of DataFrames |K |NXCALS|Temperature between the HTS and resistive part of the current lead, TT891A.TEMPERATURECALC|
|u_res_nxcals_dfs |list of DataFrames |V |NXCALS|Voltage of the resistive part of even and odd leads, U_RES|
|u_hts_nxcals_dfs |list of DataFrames |V |NXCALS|Voltage of the HTS part of even and odd leads, U_HTS|
|cv891_nxcals_dfs |list of DataFrames |% |NXCALS|Valve for regulation of TT891A, CV891.POSST|
*CRITERIA*
- Check if the temperatures TT893 at the top of the copper part of the four current leads, which must be over dew point, but not overheated: 285 K < TT893 < 305 K, even without current
- Check if the temperatures TT891A at the top of the HTS part of the four current leads, which must be regulated around 50 K: 46 K < TT891A < 54 K, even without current
- Check if the voltages U_RES over the copper part of the four current leads, which, at constant current, must stay constant (no drift) and ABS(U_RES) < 65 mV at 11.0 kA or 70 mV at 11.8 kA
- Check if the voltages U_HTS over the HTS part of the four current leads,which must stay below 50% of the threshold: ABS(U_HTS) < 0.5 mV
- Check if the valve opening regulating the helium flow along the top of the HTS part of the four current leads, which should never be blocked/saturated at its minimum/maximum.
*GRAPHS*:
- t = 0 s corresponds to the start of the test
%% Cell type:code id: tags:
``` python
it_analysis.assert_tt893_min_max_value(tt893_nxcals_dfs, value_range=(285, 305))
```
%% Cell type:code id: tags:
``` python
it_analysis.assert_tt891a_min_max_value(tt891a_nxcals_dfs, value_range=(46, 54))
```
%% Cell type:code id: tags:
``` python
it_analysis.assert_u_res_min_max_slope(u_res_nxcals_dfs, plateau_start, plateau_end, Time.to_unix_timestamp(t_start), slope_range=(-2, 2))
```
%% Cell type:code id: tags:
``` python
it_analysis.assert_u_hts_min_max_value(u_hts_nxcals_dfs, value_range=(-0.5e-3, 0.5e-3))
```
%% Cell type:code id: tags:
``` python
it_analysis.assert_cv891_min_max_variation(cv891_nxcals_dfs, 8, plateau_start, plateau_end, Time.to_unix_timestamp(t_start))
```
%% Cell type:markdown id: tags:
# 5. Final Report
## 5.1. Export Notebook as an HTML File
%% Cell type:code id: tags:
``` python
campaign = hwcb.get_campaign()
file_name_html = '{}-{}_report.html'.format(Time.to_datetime(t_start).strftime("%Y.%m.%d_%H%M%S.%f"), Time.to_datetime(t_end).strftime("%Y.%m.%d_%H%M%S.%f"))
full_path = '/eos/project/l/lhcsm/hwc/IT/{}/{}/{}/{}'.format(circuit_name, hwc_test, campaign, file_name_html)
!mkdir -p /eos/project/l/lhcsm/hwc/IT/$circuit_name/$hwc_test/$campaign
print('Compact notebook report saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
display(Javascript('IPython.notebook.save_notebook();'))
time.sleep(5)
!mkdir -p /eos/project/l/lhcsm/hwc/IT/$circuit_name/$hwc_test/$campaign
!{sys.executable} -m jupyter nbconvert --to html $'AN_IT_PNO.A9.ipynb' --output /eos/project/l/lhcsm/hwc/IT/$circuit_name/$hwc_test/$campaign/$file_name_html --TemplateExporter.exclude_input=True --TagRemovePreprocessor.remove_all_outputs_tags='["skip_output"]'
```
......
%% Cell type:markdown id: tags:
<h1><center>Analysis of a PNO.D14 HWC Test in an IT Circuit</center></h1>
The main quadrupole magnet circuits of the 8 Inner Triplet (IT) systems in the LHC are composed of four single aperture quadrupole magnets in series and have a particular powering configuration, consisting of three nested power converters (PC), see Figure below.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/IT.png" width=75%>
Main quadrupole magnet circuit of the Inner Triplet system for IT’s at points 1 and 5 (left) and IT’s at points 2 and 8 (right).
Note that the configuration for the IT’s in points 1 and 5 is different from the configuration in points 2 and 8. An earth detection system is present at the minus of the RTQX2 converter. Detailed information concerning the converters is given in EDMS 1054483. Note that the currents in the quadrupole magnets are given by:
\begin{equation}
I_\text{Q1} = I_\text{RQX} + I_\text{RTQX1} \\
I_\text{Q2} = I_\text{RQX} + I_\text{RTQX2} \\
I_\text{Q3} = I_\text{RQX} \\
\end{equation}
The two magnets Q1 and Q3 are type MQXA and the two combined magnets Q2a and Q2b are type MQXB. Q1 is located towards the interaction point.
Note that the IT’s at points 2 and 8 have a slightly higher nominal operating current than the IT’s at points 1 and 5, see Table 1.
|Circuit|I\_PNO RQX|I\_PNO RTQX2|I\_PNO RTQX1|
|-------|----------|------------|------------|
|RQX.L2, RQX.R2, RQX.L8, RQX.R8|7180 A| 4780 A|550 A|
|RQX.L1, RQX.R1, RQX.L5, RQX.R5|6800 A| 4600 A|550 A|
### PNO.D14: PC Failure at 50% of I_PNO during an SPA
The aim of this test is to calculate the splice resistances, check the regulation of the current leads, check the margin between U_RES and the QPS threshold for board A and B, and verify the correct functionality of the PC when a powering failure is generated. The currents are equal to 50% of the nominal current in the RQX, RTQX1, and RTQX2 converters, see figures below.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/PNO.D14_current_pcs.png" width=75%>
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/PNO.D14_current_magnets.png" width=75%>
<center>Currents vs time for test PNO.D14.</center>
The offline analysis is given in the table below:
|Responsible|Type of analysis|Criteria|
|-----------|----------------|--------|
|PC|Verification of the tracking error between I_REF and I_MEAS for the three PC's|I_ERR < 10 ppm|
|~|~|I_EARTH < 10 mA (online checked by the sequencer)|
|MP3|Calculate splice resistances|R_max < 5 nOhm|
|MP3|Check DFB regulation|T_top_HTS (TT891A) = 50 +/- 4K|
|~|~|T_top_Cu (TT893) = 293 +/- 10 K|
|MP3|Check margin between U_RES and the QPS threshold|U_RES < 30 mV for both boards at the start of the PC fault|
source: Test Procedure and Acceptance Criteria for the Inner Triplet Circuits in the LHC, MP3 Procedure, <a href="https://edms.cern.ch/document/874886/2.1">https://edms.cern.ch/document/874886/2.1</a>
%% Cell type:markdown id: tags:
# Analysis Assumptions
- We consider standard analysis scenarios, i.e., all signals can be queried. Depending on what signal is missing, an analysis can raise a warning and continue or an error and abort the analysis.
- In case an analyzed signal can't be queried, a particular analysis is skipped. In other words, all signals have to be available in order to perform an analysis.
- It is recommended to execute each cell one after another. However, since the signals are queried prior to an analysis, any order of execution is allowed. In case an analysis cell is aborted, the following ones may not be executed (e.g. I\_MEAS not present).
# Plot Convention
- Scales are labeled with signal name followed by a comma and a unit in the square bracket, e.g., I_MEAS, [A]
- If a reference signal is present, it is represented with a dashed line
- If the main current is present, its axis is on the left. Remaining signals are attached to the axis on the right. The legend of these signals is located on the lower left and upper right, respectively.
- The grid comes from the left axis
- Title contains timestamp, circuit name, signal name allowing for re-access the signal.
- The plots assigned to the left scale got colors: blue (C0) and orange (C1). Plots presented on the right have colors red (C2) and green (C3).
- Each plot has an individual time-synchronization mentioned explicitly in the description.
- If an axis has a single signal, change color of the label to match the signal's color. Otherwise, the label color is black.
%% Cell type:markdown id: tags:
# 0. Initialise Working Environment
%% Cell type:code id: tags:
``` python
import io
import re
import sys
import pandas as pd
from datetime import datetime
import time
from IPython.display import display, Javascript
from lhcsmapi.Time import Time
from lhcsmapi.Timer import Timer
from lhcsmapi.pyedsl.QueryBuilder import QueryBuilder
from lhcsmapi.pyedsl.PlotBuilder import PlotBuilder
import lhcsmapi.pyedsl.SignalTransformationBuilder as SignalTransformationBuilder
from lhcsmapi.pyedsl.AssertionBuilder import AssertionBuilder
from lhcsmapi.analysis.ItCircuitQuery import ItCircuitQuery
from lhcsmapi.analysis.ItCircuitAnalysis import ItCircuitAnalysis
# GUI
from lhcsmapi.gui.hwc.HwcBrowser import HwcBrowser
from lhcsmapi.gui.hwc.HwcSearchModuleMediator import HwcSearchModuleMediator
analysis_start_time = datetime.now().strftime("%Y.%m.%d_%H%M%S.%f")
import lhcsmapi
print('Analysis executed with lhcsmapi version: {}'.format(lhcsmapi.__version__))
with io.open("../__init__.py", "rt", encoding="utf8") as f:
version = re.search(r'__version__ = "(.*?)"', f.read()).group(1)
print('Analysis executed with lhc-sm-hwc notebooks version: {}'.format(version))
```
%% Cell type:markdown id: tags:
# 1. Select HWC Test
%% Cell type:code id: tags:
``` python
circuit_type = 'IT'
hwc_test = 'PNO.D14'
hwc_test_history_df = pd.read_csv('/eos/project/l/lhcsm/hwc/IT/hwc_test_history.csv')
hwcb = HwcBrowser(hwc_test_history_df, circuit_type, hwc_test)
display(hwcb.widget)
hwc_test = 'PNO.d14'
hwcb = HwcSearchModuleMediator(circuit_type=circuit_type, hwc_test=hwc_test, hwc_summary_path='/eos/project/l/lhcsm/hwc/HWC_Summary.csv')
```
%% Cell type:markdown id: tags:
# 2. Query All Signals Prior to Analysis
%% Cell type:code id: tags:skip_output
``` python
circuit_name = hwcb.get_circuit_name()
t_start = hwcb.get_start_time()
t_end = hwcb.get_end_time()
author = hwcb.get_author()
is_automatic = hwcb.is_automatic_mode()
it_query = ItCircuitQuery(circuit_type, circuit_name)
it_analysis = ItCircuitAnalysis(circuit_type, results_table=None, is_automatic=is_automatic)
with Timer():
# PC - NXCALS
i_meas_rqx_nxcals_df, i_meas_rtqx1_nxcals_df, i_meas_rtqx2_nxcals_df = it_query.query_signal_nxcals(t_start, t_end, system='PC', signal_names='I_MEAS', spark=spark)
i_meas_rqx_nxcals_df.rename(columns={"I_MEAS": "I_MEAS_RQX"}, inplace=True)
i_meas_rtqx1_nxcals_df.rename(columns={"I_MEAS": "I_MEAS_RTQX1"}, inplace=True)
i_meas_rtqx2_nxcals_df.rename(columns={"I_MEAS": "I_MEAS_RTQX2"}, inplace=True)
# I_Q1 = I_RQX + I_RTQX1
i_meas_q1_nxcals_df = SignalTransformationBuilder.add_two_dataframes(i_meas_rqx_nxcals_df, i_meas_rtqx1_nxcals_df, col_name='I_MEAS_Q1')
# I_Q2 = I_RQX + I_RTQX2
i_meas_q2_nxcals_df = SignalTransformationBuilder.add_two_dataframes(i_meas_rqx_nxcals_df, i_meas_rtqx2_nxcals_df, col_name='I_MEAS_Q2')
# I_Q3 = I_RQX
i_meas_q3_nxcals_df = pd.DataFrame(index=i_meas_rqx_nxcals_df.index, data=i_meas_rqx_nxcals_df.values, columns=['I_MEAS_Q3'])
# PC - PM
source_timestamp_fgc_df = QueryBuilder().with_pm() \
.with_duration(t_start=t_start, t_end=t_end) \
.with_circuit_type(circuit_type) \
.with_metadata(circuit_name=circuit_name, system='PC', source='*') \
.event_query().df
timestamp_fgc = min(source_timestamp_fgc_df['timestamp'].values)
# QDS - U_RES
u_res_dfs = it_query.query_signal_nxcals(t_start, t_end, system='QDS', signal_names=['U_RES_Q1', 'U_RES_Q2', 'U_RES_Q3'], spark=spark)
# Splice resistance
plateau_start, plateau_end = it_query.calculate_current_plateau_start_end(Time.to_unix_timestamp(t_start), Time.to_unix_timestamp(t_end), i_meas_threshold=0, min_duration_in_sec=10, spark=spark)
u_mag_feature_df, i_meas_feature_df = it_query.get_busbar_resistances(Time.to_unix_timestamp(t_start), Time.to_unix_timestamp(t_end), plateau_start, plateau_end,
signal_name=['U_RES_Q1', 'U_RES_Q2', 'U_RES_Q3'], system='QDS', spark=spark)
r_res_df = it_analysis.calculate_resistance(i_meas_feature_df, u_mag_feature_df)
# DFB
tt893_nxcals_dfs = it_query.query_dfb_signal_nxcals(t_start, t_end, system='LEADS_NXCALS_WINCCOA', signal_names='TT893', spark=spark)
tt891a_nxcals_dfs = it_query.query_dfb_signal_nxcals(t_start, t_end, system='LEADS_NXCALS_WINCCOA', signal_names='TT891A', spark=spark)
cv891_nxcals_dfs = it_query.query_dfb_signal_nxcals(t_start, t_end, system='LEADS_NXCALS_WINCCOA', signal_names='CV891', spark=spark)
u_res_nxcals_dfs = it_query.query_signal_nxcals(t_start, t_end, system='LEADS', signal_names='U_RES', spark=spark)
u_hts_nxcals_dfs = it_query.query_signal_nxcals(t_start, t_end, system='LEADS', signal_names='U_HTS', spark=spark)
```
%% Cell type:markdown id: tags:
# 3. PC
## 3.1. Main Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_meas_rq_nxcals_df |DataFrame |A |NXCALS|Main current of a power converter, I_MEAS_RQX, I_MEAS_RTQX1, I_MEAS_RTQX2|
Note that **rq** in the table above denotes RQX, RTQX1, and RTQX2, i.e., there are three signals for each power converter.
*GRAPHS*:
- t = 0 s corresponds to the start time of the test
%% Cell type:code id: tags:
``` python
title = '%s, %s: %s-%s' % (circuit_name, hwc_test, Time.to_string(t_start).split('.')[0], Time.to_string(t_end).split('.')[0])
ax = PlotBuilder().with_signal([i_meas_rqx_nxcals_df, i_meas_rtqx2_nxcals_df], title=title, grid=True) \
.with_ylabel(ylabel='I_MEAS_RQX, I_MEAS_RTQX2, [A]') \
.with_signal(i_meas_rtqx1_nxcals_df) \
.with_ylabel(ylabel='I_MEAS_RTQX1, [A]') \
.with_ylim((0, 600)) \
.plot(show_plot=False).get_axes()[0]
for ps, pe in zip(plateau_start, plateau_end):
ax.axvspan(xmin=(ps-Time.to_unix_timestamp(t_start))/1e9, xmax=(pe-Time.to_unix_timestamp(t_start))/1e9, facecolor='xkcd:orange')
```
%% Cell type:markdown id: tags:
## 3.2. Magnet Current
*QUERY*:
- *No query is needed as the magnet current is calculated from I_MEAS power converter currents*
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_meas_q1_df |DataFrame |A |NXCALS|Main current of the Q1 magnet, I_MEAS_Q1|
|i_meas_q2_df |DataFrame |A |NXCALS|Main current of the Q2 magnet, I_MEAS_Q2|
|i_meas_q3_df |DataFrame |A |NXCALS|Main current of the Q3 magnet, I_MEAS_Q3|
*GRAPHS*:
- t = 0 s corresponds to the start of the test
%% Cell type:code id: tags:
``` python
PlotBuilder().with_signal([i_meas_q1_nxcals_df, i_meas_q2_nxcals_df, i_meas_q3_nxcals_df], title=title, grid=True) \
.with_ylabel(ylabel='I, [A]') \
.plot()
```
%% Cell type:markdown id: tags:
# 4. Quench Detection System
The signal names used for quench detection are shown in Figure below (picture from A. Erokhin).
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/IT_QPS_Signals.png" width=75%>
A quench in the superconducting circuits is detected and all the quench heaters are fired as soon as one of the following signals exceeds the threshold.
\begin{equation}
U_\text{RES,Q1} = U_\text{1,Q1} + U_\text{2,Q1} \\
U_\text{RES,Q2} = U_\text{1,Q2} + U_\text{2,Q2} \\
U_\text{RES,Q3} = U_\text{1,Q3} + U_\text{2,Q3} \\
\end{equation}
More details on the QPS system and the quench heaters can be found on the MP3 web site (https://cern.ch/MP3).
%% Cell type:markdown id: tags:
## 4.1. Resistive Voltage
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Comment
|---------------|---------------|---------------|------|
|u_res_df |DataFrame |V |Resistive voltage of magnets measured with QPS, U_RES|
*CRITERIA*:
- Check if U_RES < 30 mV for both boards at the start of the PC fault
*GRAPHS*:
- t = 0 s corresponds to the start of the test
%% Cell type:code id: tags:
``` python
AssertionBuilder().with_signal(u_res_dfs) \
.for_time_greater_than(t_greater=(timestamp_fgc-Time.to_unix_timestamp(t_start))/1e9) \
.has_min_max_value(value_min=-30e-3, value_max=30e-3) \
.show_plot(ylabel='U_RES, [V]')
```
%% Cell type:markdown id: tags:
## 4.2. Splice Resistance
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Databse|Comment
|---------------|---------------|---------------|-------|------|
|i_meas_features_df |DataFrame| A |NXCALS| Power converter current mean values|
|u_res_features_df |DataFrame| V |NXCALS| U_RES voltage mean values|
*ANALYSIS*:
- Calculate splice resistance values based on power converter currents and QDS voltages
*CRITERIA*
- Check if R_max < 5 nOhm
*GRAPHS*:
- t = 0 s corresponds to the start of the test
%% Cell type:code id: tags:
``` python
for i_q_df, u_res_df in zip([i_meas_q1_nxcals_df, i_meas_q2_nxcals_df, i_meas_q3_nxcals_df], u_res_dfs):
ax = PlotBuilder().with_signal(i_q_df, title=title, grid=True) \
.with_ylabel(ylabel='I_Q, [A]') \
.with_signal(u_res_df) \
.with_ylabel(ylabel='U_RES_Q, [V]') \
.plot(show_plot=False).get_axes()[0]
for ps, pe in zip(plateau_start, plateau_end):
ax.axvspan(xmin=(ps-Time.to_unix_timestamp(t_start))/1e9, xmax=(pe-Time.to_unix_timestamp(t_start))/1e9, facecolor='xkcd:orange')
```
%% Cell type:code id: tags:
``` python
res_outliers_df = AssertionBuilder().with_feature(r_res_df) \
.has_min_max_value(feature='R_RES', min_value=0, max_value=5e-9) \
.show_plot(xlabel='Busbar, [-]', ylabel='R_RES (Calculated), [Ohm]') \
.get_features_outside_range()
```
%% Cell type:markdown id: tags:
## 4.3. DFB Regulation
*QUERY*
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|tt893_nxcals_dfs |list of DataFrames |K |NXCALS|Temperature at the top of the current lead, TT893.TEMPERATURECALC|
|tt891a_nxcals_dfs |list of DataFrames |K |NXCALS|Temperature between the HTS and resistive part of the current lead, TT891A.TEMPERATURECALC|
|u_res_nxcals_dfs |list of DataFrames |V |NXCALS|Voltage of the resistive part of even and odd leads, U_RES|
|u_hts_nxcals_dfs |list of DataFrames |V |NXCALS|Voltage of the HTS part of even and odd leads, U_HTS|
|cv891_nxcals_dfs |list of DataFrames |% |NXCALS|Valve for regulation of TT891A, CV891.POSST|
*CRITERIA*
- Check if the temperatures TT893 at the top of the copper part of the four current leads, which must be over dew point, but not overheated: 285 K < TT893 < 305 K, even without current
- Check if the temperatures TT891A at the top of the HTS part of the four current leads, which must be regulated around 50 K: 46 K < TT891A < 54 K, even without current
- Check if the voltages U_RES over the copper part of the four current leads, which, at constant current, must stay constant (no drift) and ABS(U_RES) < 65 mV at 11.0 kA or 70 mV at 11.8 kA
- Check if the voltages U_HTS over the HTS part of the four current leads,which must stay below 50% of the threshold: ABS(U_HTS) < 0.5 mV
- Check if the valve opening regulating the helium flow along the top of the HTS part of the four current leads, which should never be blocked/saturated at its minimum/maximum.
*GRAPHS*:
- t = 0 s corresponds to the start of the test
%% Cell type:code id: tags:
``` python
it_analysis.assert_tt893_min_max_value(tt893_nxcals_dfs, value_range=(285, 305))
```
%% Cell type:code id: tags:
``` python
it_analysis.assert_tt891a_min_max_value(tt891a_nxcals_dfs, value_range=(46, 54))
```
%% Cell type:code id: tags:
``` python
it_analysis.assert_u_res_min_max_slope(u_res_nxcals_dfs, plateau_start, plateau_end, Time.to_unix_timestamp(t_start), slope_range=(-2, 2))
```
%% Cell type:code id: tags:
``` python
it_analysis.assert_u_hts_min_max_value(u_hts_nxcals_dfs, value_range=(-0.5e-3, 0.5e-3))
```
%% Cell type:code id: tags:
``` python
it_analysis.assert_cv891_min_max_variation(cv891_nxcals_dfs, 8, plateau_start, plateau_end, Time.to_unix_timestamp(t_start))
```
%% Cell type:markdown id: tags:
# 5. Final Report
## 5.1. Export Notebook as an HTML File
%% Cell type:code id: tags:
``` python
campaign = hwcb.get_campaign()
file_name_html = '{}-{}_report.html'.format(Time.to_datetime(t_start).strftime("%Y.%m.%d_%H%M%S.%f"), Time.to_datetime(t_end).strftime("%Y.%m.%d_%H%M%S.%f"))
full_path = '/eos/project/l/lhcsm/hwc/IT/{}/{}/{}/{}'.format(circuit_name, hwc_test, campaign, file_name_html)
!mkdir -p /eos/project/l/lhcsm/hwc/IT/$circuit_name/$hwc_test/$campaign
print('Compact notebook report saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
display(Javascript('IPython.notebook.save_notebook();'))
time.sleep(5)
!mkdir -p /eos/project/l/lhcsm/hwc/IT/$circuit_name/$hwc_test/$campaign
!{sys.executable} -m jupyter nbconvert --to html $'AN_IT_PNO.D14.ipynb' --output /eos/project/l/lhcsm/hwc/IT/$circuit_name/$hwc_test/$campaign/$file_name_html --TemplateExporter.exclude_input=True --TagRemovePreprocessor.remove_all_outputs_tags='["skip_output"]'
```
......
%% Cell type:markdown id: tags:
<h1><center>Analysis of a PNO.D16 HWC Test in an IT Circuit</center></h1>
The main quadrupole magnet circuits of the 8 Inner Triplet (IT) systems in the LHC are composed of four single aperture quadrupole magnets in series and have a particular powering configuration, consisting of three nested power converters (PC), see Figure below.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/IT.png" width=75%>
Main quadrupole magnet circuit of the Inner Triplet system for IT’s at points 1 and 5 (left) and IT’s at points 2 and 8 (right).
Note that the configuration for the IT’s in points 1 and 5 is different from the configuration in points 2 and 8. An earth detection system is present at the minus of the RTQX2 converter. Detailed information concerning the converters is given in EDMS 1054483. Note that the currents in the quadrupole magnets are given by:
\begin{equation}
I_\text{Q1} = I_\text{RQX} + I_\text{RTQX1} \\
I_\text{Q2} = I_\text{RQX} + I_\text{RTQX2} \\
I_\text{Q3} = I_\text{RQX} \\
\end{equation}
The two magnets Q1 and Q3 are type MQXA and the two combined magnets Q2a and Q2b are type MQXB. Q1 is located towards the interaction point.
Note that the IT’s at points 2 and 8 have a slightly higher nominal operating current than the IT’s at points 1 and 5, see Table 1.
|Circuit|I\_PNO RQX|I\_PNO RTQX2|I\_PNO RTQX1|
|-------|----------|------------|------------|
|RQX.L2, RQX.R2, RQX.L8, RQX.R8|7180 A| 4780 A|550 A|
|RQX.L1, RQX.R1, RQX.L5, RQX.R5|6800 A| 4600 A|550 A|
### PNO.D16: PC Failure at 90% of I_PNO
The aim of this test is to calculate the splice resistances, check the regulation of the current leads, and verify the correct functionality of the PC when a powering failure is generated. The currents are equal to 90% of the nominal current in the RQX, RTQX1, and RTQX2 converters, see figures below.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/it/PNO.D16_current_pcs.png" width=75%>