Commit fdc09cb6 authored by Michal Maciejewski's avatar Michal Maciejewski
Browse files

Introduced a more robust html generation mechanism

parent a394f8c6
%% Cell type:markdown id: tags:
<h1><center>Analysis of an FPA in an 600A Circuit - RCBX Family</center></h1>
Figure below shows a generic circuit diagram, equipped with EE and parallel resistor, as well as lead resistances and a quench resistance.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/600A/600A_without_EE.png" width=75%>
source: Test Procedure and Acceptance Criteria for the 600 A Circuits, MP3 Procedure, <a href="https://edms.cern.ch/document/874716/5.3">https://edms.cern.ch/document/874716/5.3</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
## 0.1. Import Necessary Packages
%% 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
# lhc-sm-api
from lhcsmapi.Time import Time
from lhcsmapi.Timer import Timer
from lhcsmapi.pyedsl.QueryBuilder import QueryBuilder
from lhcsmapi.analysis.R600ACircuitQuery import R600ACircuitQuery
from lhcsmapi.analysis.expert_input import get_expert_decision
from lhcsmapi.analysis.report_template import apply_report_template
from lhcsmapi.analysis.R600ACircuitAnalysis import R600ACircuitAnalysis
from lhcsmapi.metadata.SignalMetadata import SignalMetadata
# GUI
from lhcsmapi.gui.qh.DateTimeBaseModule import DateTimeBaseModule
from lhcsmapi.gui.pc.FgcPmSearchModuleMediator import FgcPmSearchModuleMediator
from lhcsmapi.gui.pc.R600AFgcPmSearchBaseModule import R600ARcbxhvFgcPmSearchBaseModule
analysis_start_time = datetime.now().strftime("%Y.%m.%d_%H%M%S.%f")
```
%% Cell type:markdown id: tags:
## 0.2. LHCSMAPI Version
%% Cell type:code id: tags:
``` python
import lhcsmapi
print('Analysis executed with lhcsmapi version: {}'.format(lhcsmapi.__version__))
```
%% Cell type:markdown id: tags:
## 0.3. Notebook Version
%% Cell type:code id: tags:
``` python
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 RCD/O 600A circuit please:
1. Select circuit name (e.g., RC.A12B1)
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
fgc_pm_search = FgcPmSearchModuleMediator(DateTimeBaseModule(start_date_time='2017-04-26 00:00:00+01:00',
end_date_time='2017-04-28 00:00:00+01:00'), R600ARcbxhvFgcPmSearchBaseModule(), circuit_type='600A_RCBXHV')
display(fgc_pm_search.widget)
```
%% Cell type:markdown id: tags:
# 2. Query All Signals Prior to Analysis
%% Cell type:code id: tags:skip_output
``` python
with Timer():
author = fgc_pm_search.get_author()
is_automatic = fgc_pm_search.is_automatic_mode()
circuit_type = '600A'
circuit_names = fgc_pm_search.get_fgc_circuit()
timestamp_fgc_rcbxh, timestamp_fgc_rcbxv = fgc_pm_search.get_fgc_timestamp()
query_rcbxh = R600ACircuitQuery(circuit_type, circuit_names[0], max_executions=10)
query_rcbxv = R600ACircuitQuery(circuit_type, circuit_names[1], max_executions=10)
# RCBXH
i_meas_rcbxh_df, i_a_rcbxh_df, i_ref_rcbxh_df, i_earth_rcbxh_df = query_rcbxh.query_pc_pm(timestamp_fgc_rcbxh, timestamp_fgc_rcbxh,
signal_names=['I_MEAS', 'I_A', 'I_REF', 'I_EARTH'])
events_action_rcbxh_df, events_symbol_rcbxh_df = query_rcbxh.query_pc_pm_events(timestamp_fgc_rcbxh, signal_names=['ACTION', 'SYMBOL'])
# RCBXV
i_meas_rcbxv_df, i_a_rcbxv_df, i_ref_rcbxv_df, i_earth_rcbxv_df = query_rcbxv.query_pc_pm(timestamp_fgc_rcbxv, timestamp_fgc_rcbxv,
signal_names=['I_MEAS', 'I_A', 'I_REF', 'I_EARTH'])
events_action_rcbxv_df, events_symbol_rcbxv_df = query_rcbxv.query_pc_pm_events(timestamp_fgc_rcbxv, signal_names=['ACTION', 'SYMBOL'])
# PIC
# # RCBXH
timestamp_pic_rcbxh = query_rcbxh.find_timestamp_pic(timestamp_fgc_rcbxh, spark=spark)
# # RCBXV
timestamp_pic_rcbxv = query_rcbxv.find_timestamp_pic(timestamp_fgc_rcbxv, spark=spark)
# QDS NXCALS - To check if there was any drift of QDS cards prior to the trigger
# # RCBXH
i_meas_nxcals_rcbxh_df = query_rcbxh.query_pc_nxcals(timestamp_fgc_rcbxh, signal_names=['I_MEAS'], spark=spark)[0]
u_res_nxcals_rcbxh_df = query_rcbxh.query_iqps_nxcals(timestamp_fgc_rcbxh, signal_names=['U_RES'], spark=spark)[0]
# # RCBXV
i_meas_nxcals_rcbxv_df = query_rcbxv.query_pc_nxcals(timestamp_fgc_rcbxv, signal_names=['I_MEAS'], spark=spark)[0]
u_res_nxcals_rcbxv_df = query_rcbxv.query_iqps_nxcals(timestamp_fgc_rcbxv, signal_names=['U_RES'], spark=spark)[0]
# QDS PM
# # RCBXH
source_timestamp_qds_rcbxh_df = query_rcbxh.find_source_timestamp_qds(timestamp_fgc_rcbxh, duration=[(2, 's'), (2, 's')])
timestamp_qds_rcbxh = np.nan if source_timestamp_qds_rcbxh_df.empty else source_timestamp_qds_rcbxh_df.loc[0, 'timestamp']
i_dcct_rcbxh_df, i_didt_rcbxh_df, u_res_rcbxh_df, u_diff_rcbxh_df = query_rcbxh.query_qds_pm(timestamp_qds_rcbxh, timestamp_qds_rcbxh,
signal_names=['I_DCCT', 'I_DIDT', 'U_RES', 'U_DIFF'])
# # RCBXV
source_timestamp_qds_rcbxv_df = query_rcbxv.find_source_timestamp_qds(timestamp_fgc_rcbxv, duration=[(2, 's'), (2, 's')])
timestamp_qds_rcbxv = np.nan if source_timestamp_qds_rcbxv_df.empty else source_timestamp_qds_rcbxv_df.loc[0, 'timestamp']
i_dcct_rcbxv_df, i_didt_rcbxv_df, u_res_rcbxv_df, u_diff_rcbxv_df = query_rcbxv.query_qds_pm(timestamp_qds_rcbxv, timestamp_qds_rcbxv,
signal_names=['I_DCCT', 'I_DIDT', 'U_RES', 'U_DIFF'])
# LEADS
# # RCBXH
leads_name = [x for x in SignalMetadata.get_system_types_per_circuit_name(circuit_type, circuit_names[0]) if 'LEADS' in x][0]
source_timestamp_leads_rcbxh_df = query_rcbxh.find_timestamp_leads(timestamp_fgc_rcbxh, leads_name)
u_hts_leads_rcbxh_dfs = query_rcbxh.query_leads(timestamp_fgc_rcbxh, source_timestamp_leads_rcbxh_df, system=leads_name, signal_names=['U_HTS'], spark=spark, duration=[(300, 's'), (900, 's')])
u_res_leads_rcbxh_dfs = query_rcbxh.query_leads(timestamp_fgc_rcbxh, source_timestamp_leads_rcbxh_df, system=leads_name, signal_names=['U_RES'], spark=spark, duration=[(300, 's'), (900, 's')])
# # RCBXV
leads_name = [x for x in SignalMetadata.get_system_types_per_circuit_name(circuit_type, circuit_names[1]) if 'LEADS' in x][0]
source_timestamp_leads_rcbxv_df = query_rcbxv.find_timestamp_leads(timestamp_fgc_rcbxv, leads_name)
u_hts_leads_rcbxv_dfs = query_rcbxv.query_leads(timestamp_fgc_rcbxv, source_timestamp_leads_rcbxv_df, system=leads_name, signal_names=['U_HTS'], spark=spark, duration=[(300, 's'), (900, 's')])
u_res_leads_rcbxv_dfs = query_rcbxv.query_leads(timestamp_fgc_rcbxv, source_timestamp_leads_rcbxv_df, system=leads_name, signal_names=['U_RES'], spark=spark, duration=[(300, 's'), (900, 's')])
# Create results table - RCBXH/V
results_table = query_rcbxh.create_report_analysis_template_rcbx(timestamp_fgc_rcbxh, timestamp_fgc_rcbxv, circuit_names, author=author)
analysis_rcbxh = R600ACircuitAnalysis(circuit_type, results_table, is_automatic=is_automatic)
analysis_rcbxv = R600ACircuitAnalysis(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:
- 2 PM DQAMGNA (A+B) files and 1 PM EE file should be generated for 600 A circuits with EE
- Difference between QPS board A and B timestamp = 1 ms
- PC timestamp is QPS timestamp +/- 20 ms
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_RCBXH': timestamp_fgc_rcbxh, 'FGC_RCBXV': timestamp_fgc_rcbxv,
'PIC_RCBXH': timestamp_pic_rcbxh, 'PIC_RCBXV': timestamp_pic_rcbxv,
'QDS_A_RCBXH':source_timestamp_qds_rcbxh_df.loc[0, 'timestamp'] if len(source_timestamp_qds_rcbxh_df) > 0 else np.nan,
'QDS_B_RCBXH':source_timestamp_qds_rcbxh_df.loc[1, 'timestamp'] if len(source_timestamp_qds_rcbxh_df) > 1 else np.nan,
'QDS_A_RCBXV':source_timestamp_qds_rcbxv_df.loc[0, 'timestamp'] if len(source_timestamp_qds_rcbxv_df) > 0 else np.nan,
'QDS_B_RCBXV':source_timestamp_qds_rcbxv_df.loc[1, 'timestamp'] if len(source_timestamp_qds_rcbxv_df) > 1 else np.nan}
analysis_rcbxh.create_timestamp_table(timestamp_dct, circuit_name=circuit_names[0])
```
%% Cell type:markdown id: tags:
# 4. PC
## 4.1. Main Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_a_rcbx_df |DataFrame |A |PM|I_A is the raw RCBX power converter current logged around the FPA with high sampling frequency|
|i_meas_rcbx_df |DataFrame |A |PM|I_MEAS RCBX power converter current is filtered I_A with lower sampling frequency and longer duration|
|i_ref_rcbx_df |DataFrame |A |PM|The reference current of an RCBX power converter, I_REF|
|events_action_rcbx_df |DataFrame |text |PM|event action storing information about the state of an RCBX PC operation, e.g. FAULT, EVENTS.ACTION|
|events_symbol_rcbx_df |DataFrame |text |PM|event action storing information about source of an RCBX PC FPA, e.g. TRG EXTERNAL FAST ABORT, EVENTS.SYMBOL|
Note that **rcbx** in the table above denotes RCBXH and RCBXV, i.e., there are four signals for each circuit.
*ANALYSIS*:
- determination of the source of an FPA trigger based on EVENTS.SYMBOL and EVENTS.ACTION signals
- detection of the start of a quench as a deviation of I_A and I_REF
- calculation of the MIITs
- calculation of the quench current
- calculation of the duration of a plateau / the ramp rate before a quench (based on PM event buffer)
*GRAPHS*:
- dashed blue line denotes the start of a quench (I_A starts to deviate from I_REF)
- t = 0 s corresponds to the FGC timestamp
%% Cell type:code id: tags:
``` python
t_quench = analysis_rcbxh.find_time_of_quench(i_ref_rcbxh_df, i_a_rcbxh_df)
t_quench = 0 if t_quench is None else t_quench
analysis_rcbxh.plot_i_meas_pc(circuit_names[0], timestamp_fgc_rcbxh, [i_meas_rcbxh_df, i_ref_rcbxh_df, i_a_rcbxh_df], xlim=(t_quench-0.1, t_quench+0.1))
```
%% Cell type:code id: tags:
``` python
analysis_rcbxh.plot_i_meas_pc_zoom(circuit_names[0], timestamp_fgc_rcbxh, t_quench, [i_meas_rcbxh_df, i_ref_rcbxh_df, i_a_rcbxh_df], xlim=(t_quench-0.1, t_quench+0.1))
analysis_rcbxh.analyze_i_meas_pc_trigger(timestamp_fgc_rcbxh, events_action_rcbxh_df, events_symbol_rcbxh_df)
analysis_rcbxh.calculate_current_miits(i_meas_rcbxh_df, t_quench, col_name='I_MEAS MIITs H')
analysis_rcbxh.calculate_quench_current(i_meas_rcbxh_df, t_quench, col_name='I_Q_H')
analysis_rcbxh.calculate_current_slope(i_meas_rcbxh_df, col_name='Ramp Rate H')
```
%% Cell type:code id: tags:
``` python
t_quench = analysis_rcbxv.find_time_of_quench(i_ref_rcbxv_df, i_a_rcbxv_df)
t_quench = 0 if t_quench is None else t_quench
analysis_rcbxv.plot_i_meas_pc(circuit_names[1], timestamp_fgc_rcbxv, [i_meas_rcbxv_df, i_ref_rcbxv_df, i_a_rcbxv_df], xlim=(t_quench-1, t_quench+1))
```
%% Cell type:code id: tags:
``` python
analysis_rcbxv.plot_i_meas_pc_zoom(circuit_names[1], timestamp_fgc_rcbxv, t_quench, [i_meas_rcbxv_df, i_ref_rcbxv_df, i_a_rcbxv_df], xlim=(t_quench-0.1, t_quench+0.1))
analysis_rcbxv.analyze_i_meas_pc_trigger(timestamp_fgc_rcbxv, events_action_rcbxv_df, events_symbol_rcbxv_df)
analysis_rcbxv.calculate_current_miits(i_meas_rcbxv_df, t_quench, col_name='I_MEAS MIITs V')
analysis_rcbxv.calculate_quench_current(i_meas_rcbxv_df, t_quench, col_name='I_Q_V')
analysis_rcbxv.calculate_current_slope(i_meas_rcbxv_df, col_name='Ramp Rate V')
```
%% Cell type:code id: tags:
``` python
analysis_rcbxh.results_table[['Circuit Name', 'Date', 'Time', 'I_Q_H', 'I_Q_V', 'I_MEAS MIITs H', 'I_MEAS MIITs V', 'Ramp Rate H', 'Ramp Rate V', 'Plateau Duration']]
```
%% Cell type:markdown id: tags:
## 4.2. Earth Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_earth_rcbx_df |DataFrame |A |PM|Earth current of an RCBX circuit power converter, I_EARTH|
Note that **rcbx** in the table above denotes RCBXH and RCBXV, i.e., there is one signal for each circuit.
*ANALYSIS*:
- calculation of the maximum absolute earth current (maintaining the sign)
*GRAPHS*:
- t = 0 s corresponds to the FGC timestamp
%% Cell type:code id: tags:
``` python
analysis_rcbxh.plot_i_earth_pc(circuit_names[0], timestamp_fgc_rcbxh, i_earth_rcbxh_df)
analysis_rcbxh.calculate_max_i_earth_pc(i_earth_rcbxh_df, col_name='Earth Current H')
```
%% Cell type:code id: tags:
``` python
analysis_rcbxv.plot_i_earth_pc(circuit_names[1], timestamp_fgc_rcbxv, i_earth_rcbxv_df)
analysis_rcbxv.calculate_max_i_earth_pc(i_earth_rcbxv_df, col_name='Earth Current V')
```
%% Cell type:markdown id: tags:
# 5. QDS
The quench voltage U_RES is calculated according to the following formula:
\begin{equation}
U_{\text{RES}} = U_{\text{DIFF}} + L d/dt (I+U_{\text{DIFF}}/R).
\end{equation}
Note that I_DCCT is the QPS signal name, even though the current is actually measured not with a DCCT, but with a LEM detector, hence the poorer quality w.r.t. to the FGC I_A/B/MEAS signals that are measured with a DCCT.
It can be seen from the sign convention in the figure below that a resistive voltage always has opposite sign to the measured current.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/600A/600A_without_EE.png" width=75%>
As U_DIFF contributes directly to U_RES, the resolution of U_RES is, at least partially, limited by that of U_DIFF. Moreover, U_RES is affected by the noisy time derivative of the current signal.
The QPS signals that are communicated to the post-mortem system have only 12 bit resolution.
## 5.1. Resistive Voltage
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_meas_nxcals_rcbx_df |DataFrame |A |NXCALS|Power converter current in an RCBX circuit, I_MEAS|
|u_res_nxcals_rcbx_df |DataFrame |V |NXCALS|Resistive voltage of magnets measured with QPS in an RCBX circuit, U_RES|
|u_res_rc_df |DataFrame |V |PM|Resistive voltage of magnets measured with QPS in an RCBX circuit, U_RES|
Note that **rcbx** in the table above denotes RCBXH and RCBXV, i.e., there are two signals for each circuit.
*ANALYSIS*:
- Check if the U_RES signal before a quench is increasing for at least one board, which would indicate a QPS trip
- Calculate the 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.
*GRAPHS*:
First plot (U_RES and I_MEAS prior to a quench)
- t = 0 s corresponds to the FGC timestamp
Second plot (U_RES and the initial slope of U_RES)
- t = 0 s corresponds to the QPS timestamp
%% Cell type:code id: tags:
``` python
analysis_rcbxh.plot_u_res(circuit_names[0], timestamp_qds_rcbxh, u_res_nxcals_rcbxh_df, i_meas_nxcals_rcbxh_df)
```
%% Cell type:code id: tags:
``` python
u_res_rcbxh_slope_df = analysis_rcbxh.calculate_u_res_slope(u_res_rcbxh_df, col_name='dUres/dt H')
analysis_rcbxh.plot_u_res_slope(circuit_names[0], timestamp_qds_rcbxh, u_res_rcbxh_df, u_res_rcbxh_slope_df)
```
%% Cell type:code id: tags:
``` python
analysis_rcbxv.plot_u_res(circuit_names[1], timestamp_qds_rcbxv, u_res_nxcals_rcbxv_df, i_meas_nxcals_rcbxv_df)
```
%% Cell type:code id: tags:
``` python
u_res_rcbxv_slope_df = analysis_rcbxv.calculate_u_res_slope(u_res_rcbxv_df, col_name='dUres/dt V')
analysis_rcbxv.plot_u_res_slope(circuit_names[1], timestamp_qds_rcbxv, u_res_rcbxv_df, u_res_rcbxv_slope_df)
```
%% Cell type:code id: tags:
``` python
analysis_rcbxh.results_table[['Circuit Name', 'Date', 'Time', 'dUres/dt H', 'dUres/dt V']]
```
%% Cell type:markdown id: tags:
## 5.2. I_DCCT, I_DIDT Currents; U_RES, U_DIFF Voltages
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_dcct_rcbx_df |DataFrame |A |PM|DC current leads of QPS in an RCBX circuit, I_DCCT|
|i_didt_rcbx_df |DataFrame |A/s |PM|di/dt current leads of QPS in an RCBX circuit, I_DIDT|
|u_diff_rcbx_df |DataFrame |V |PM|differential voltage of QPS in an RCBX circuit, U_DIFF|
|u_res_rcbx_df |DataFrame |V |PM|resistive voltage (after inductance compensation) of QPS in an RCBX circuit used for quench detection, U_RES|
Note that **rcbx** in the table above denotes RCBXH and RCBXV, i.e., there are two signals for each circuit.
*ANALYSIS*
- Check the integrity of all four signals (U_DIFF, I_DCCT, I_DIDT and U_RES). If one of the signals (especially U_DIFF or I_DCCT) stays at zero or shows wrong values the cabling of this quench detector could have issues. Compare U_DIFF (measured signal) to U_REF (signal compensated for inductive voltage).
*CRITERIA*
- **U_RES < 0.7*100 mV and noise of U_RES on the plateaus < 20mV**
*GRAPHS*:
- t = 0 s corresponds to the QPS timestamp
%% Cell type:code id: tags:
``` python
analysis_rcbxh.plot_qds(circuit_names[0], timestamp_qds_rcbxh, i_dcct_rcbxh_df, i_didt_rcbxh_df, u_diff_rcbxh_df, u_res_rcbxh_df)
```
%% Cell type:code id: tags:
``` python
analysis_rcbxv.plot_qds(circuit_names[1], timestamp_qds_rcbxv, i_dcct_rcbxv_df, i_didt_rcbxv_df, u_diff_rcbxv_df, u_res_rcbxv_df)
# Get expert input on reason
analysis_rcbxv.results_table['Reason'] = get_expert_decision('Reason for FPA: ', ['quench', 'coupling', 'other'])
# Get expert input on quench origin
analysis_rcbxv.results_table['Quench Origin'] = get_expert_decision('Origin of a quench', ['magnet', 'busbar', 'other'])
```
%% Cell type:markdown id: tags:
# 6. LEADS
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|u_hts_leads_rcbx_df |DataFrame |V |PM/NXCALS|RC leads voltage, U_HTS|
|u_res_leads_rcbx_df |DataFrame |V |PM/NXCALS|RC leads voltage, U_RES|
Note that **rcbx** in the table above denotes RCBXH and RCBXV, i.e., there are two signals for each circuit.
*ANALYSIS*:
- check if U_HTS for 2 consecutive datapoints is above the threshold 3 mV
- check if U_RES for 2 consecutive datapoints is above the threshold 100 mV
*GRAPHS*:
- t = 0 s corresponds to the LEADS timestamp
%% Cell type:code id: tags:
``` python
analysis_rcbxh.analyze_leads_voltage(u_hts_leads_rcbxh_dfs, circuit_names[0], timestamp_fgc_rcbxh, signal='U_HTS', value_min=-0.003, value_max=0.003)
```
%% Cell type:code id: tags:
``` python
analysis_rcbxh.analyze_leads_voltage(u_res_leads_rcbxh_dfs, circuit_names[0], timestamp_fgc_rcbxh, signal='U_RES', value_min=-0.1, value_max=0.1)
```
%% Cell type:code id: tags:
``` python
analysis_rcbxv.analyze_leads_voltage(u_hts_leads_rcbxv_dfs, circuit_names[1], timestamp_fgc_rcbxv, signal='U_HTS', value_min=-0.003, value_max=0.003)
```
%% Cell type:code id: tags:
``` python
analysis_rcbxv.analyze_leads_voltage(u_res_leads_rcbxv_dfs, circuit_names[1], timestamp_fgc_rcbxv, signal='U_RES', value_min=-0.1, value_max=0.1)
```
%% Cell type:markdown id: tags:
# 7. Final Report
## 7.1. Display Results Table
%% Cell type:code id: tags:skip_output
``` python
pd.set_option('display.max_columns', None)
analysis_rcbxh.results_table
```
%% Cell type:markdown id: tags:
## 7.2. Write Results Table to CSV
%% Cell type:code id: tags:
``` python
timestamp_fgc = timestamp_fgc_rcbxh if not np.isnan(timestamp_fgc_rcbxh) else timestamp_fgc_rcbxv
file_name = "{}-{}-PM_600A_RCBX_FPA".format(Time.to_datetime(timestamp_fgc).strftime("%Y.%m.%d_%H%M%S.%f"), analysis_start_time)
```
%% Cell type:code id: tags:
``` python
# Create folder for circuit_name
circuit_name = circuit_names[0]
!mkdir -p /eos/project/l/lhcsm/operation/600A/$circuit_name
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}_results_table.csv'.format(circuit_name, file_name)
analysis_rcbxh.results_table.to_csv(full_path)
print('Full results table saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
```
%% Cell type:markdown id: tags:
## 7.3. Display MP3 Results Table
%% Cell type:code id: tags:skip_output
``` python
mp3_results_table = analysis_rcbxh.create_mp3_results_table_rcbxhv()
mp3_results_table
```
%% Cell type:markdown id: tags:
## 7.4. Write MP3 Quench Database Table to CSV
%% Cell type:code id: tags:
``` python
# Create folder for circuit_name
circuit_name = circuit_names[0]
!mkdir -p /eos/project/l/lhcsm/operation/600A/$circuit_name
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}_mp3_results_table.csv'.format(circuit_name, file_name)
mp3_results_table.to_csv(full_path)
print('MP3 results table saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
```
%% Cell type:markdown id: tags:
## 7.5. Export Notebook as an HTML File
%% Cell type:code id: tags:
``` python
file_name_html = file_name + '_report.html'
!mkdir -p /eos/project/l/lhcsm/operation/600A/$circuit_name
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}'.format(circuit_name, file_name_html)
!{sys.executable} -m jupyter nbconvert --to html $'AN_600A_RCBXHV_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html
print('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_600A_RCBXHV_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html
```
%% Cell type:markdown id: tags:
## 7.6. Export Compact Notebook as an HTML File
%% Cell type:code id: tags:
``` python
apply_report_template()
file_name_html = file_name + '_compact_report.html'
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}'.format(circuit_name, file_name_html)
!{sys.executable} -m jupyter nbconvert --to html $'AN_600A_RCBXHV_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html --TemplateExporter.exclude_input=True --TagRemovePreprocessor.remove_all_outputs_tags='["skip_output"]' --TagRemovePreprocessor.remove_cell_tags='["skip_cell"]'
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_600A_RCBXHV_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$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
```
......
%% Cell type:markdown id: tags:
<h1><center>Analysis of an FPA in an 600A Circuit - RCD-RCO Family</center></h1>
Figure below shows a generic circuit diagram, equipped with parallel resistance, as well as lead resistances and a quench resistance.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/600A/600A_without_EE.png" width=75%>
source: Test Procedure and Acceptance Criteria for the 600 A Circuits, MP3 Procedure, <a href="https://edms.cern.ch/document/874716/5.3">https://edms.cern.ch/document/874716/5.3</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
## 0.1. Import Necessary Packages
%% 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
# lhc-sm-api
from lhcsmapi.Time import Time
from lhcsmapi.Timer import Timer
from lhcsmapi.pyedsl.QueryBuilder import QueryBuilder
from lhcsmapi.analysis.R600ACircuitQuery import R600ACircuitQuery
from lhcsmapi.analysis.expert_input import get_expert_decision
from lhcsmapi.analysis.report_template import apply_report_template
from lhcsmapi.analysis.R600ACircuitAnalysis import R600ACircuitAnalysis
from lhcsmapi.metadata.SignalMetadata import SignalMetadata
# GUI
from lhcsmapi.gui.qh.DateTimeBaseModule import DateTimeBaseModule
from lhcsmapi.gui.pc.FgcPmSearchModuleMediator import FgcPmSearchModuleMediator
from lhcsmapi.gui.pc.R600AFgcPmSearchBaseModule import R600ARcdoFgcPmSearchBaseModule
analysis_start_time = datetime.now().strftime("%Y.%m.%d_%H%M%S.%f")
```
%% Cell type:markdown id: tags:
## 0.2. LHCSMAPI Version
%% Cell type:code id: tags:
``` python
import lhcsmapi
print('Analysis executed with lhcsmapi version: {}'.format(lhcsmapi.__version__))
```
%% Cell type:markdown id: tags:
## 0.3. Notebook Version
%% Cell type:code id: tags:
``` python
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 RCD/O 600A circuit please:
1. Select circuit name (e.g., RC.A12B1)
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
fgc_pm_search = FgcPmSearchModuleMediator(DateTimeBaseModule(start_date_time='2018-03-19 00:00:00+01:00',
end_date_time='2018-03-20 00:00:00+01:00'), R600ARcdoFgcPmSearchBaseModule(), circuit_type='600A_RCDO')
display(fgc_pm_search.widget)
```
%% Cell type:markdown id: tags:
# 2. Query All Signals Prior to Analysis
%% Cell type:code id: tags:skip_output
``` python
with Timer():
author = fgc_pm_search.get_author()
is_automatic = fgc_pm_search.is_automatic_mode()
circuit_type = '600A'
circuit_names = fgc_pm_search.get_fgc_circuit()
timestamp_fgc_rcd, timestamp_fgc_rco = fgc_pm_search.get_fgc_timestamp()
query_rcd = R600ACircuitQuery(circuit_type, circuit_names[0], max_executions=10)
query_rco = R600ACircuitQuery(circuit_type, circuit_names[1], max_executions=10)
# RCD
i_meas_rcd_df, i_a_rcd_df, i_ref_rcd_df, i_earth_rcd_df = query_rcd.query_pc_pm(timestamp_fgc_rcd, timestamp_fgc_rcd,
signal_names=['I_MEAS', 'I_A', 'I_REF', 'I_EARTH'])
events_action_rcd_df, events_symbol_rcd_df = query_rcd.query_pc_pm_events(timestamp_fgc_rcd, signal_names=['ACTION', 'SYMBOL'])
# RCO
i_meas_rco_df, i_a_rco_df, i_ref_rco_df, i_earth_rco_df = query_rco.query_pc_pm(timestamp_fgc_rco, timestamp_fgc_rco,
signal_names=['I_MEAS', 'I_A', 'I_REF', 'I_EARTH'])
events_action_rco_df, events_symbol_rco_df = query_rco.query_pc_pm_events(timestamp_fgc_rco, signal_names=['ACTION', 'SYMBOL'])
# PIC
# # RCD
timestamp_pic_rcd = query_rcd.find_timestamp_pic(timestamp_fgc_rcd, spark=spark)
# # RCO
timestamp_pic_rco = query_rco.find_timestamp_pic(timestamp_fgc_rco, spark=spark)
# QDS NXCALS - To check if there was any drift of QDS cards prior to the trigger
# # RCD
i_meas_nxcals_rcd_df = query_rcd.query_pc_nxcals(timestamp_fgc_rcd, signal_names=['I_MEAS'], spark=spark)[0]
u_res_nxcals_rcd_df = query_rcd.query_iqps_nxcals(timestamp_fgc_rcd, signal_names=['U_RES'], spark=spark)[0]
# # RCO
i_meas_nxcals_rco_df = query_rco.query_pc_nxcals(timestamp_fgc_rco, signal_names=['I_MEAS'], spark=spark)[0]
u_res_nxcals_rco_df = query_rco.query_iqps_nxcals(timestamp_fgc_rco, signal_names=['U_RES'], spark=spark)[0]
# QDS PM
# # RCD
source_timestamp_qds_rcd_df = query_rcd.find_source_timestamp_qds(timestamp_fgc_rcd, duration=[(2, 's'), (2, 's')])
timestamp_qds_rcd = np.nan if source_timestamp_qds_rcd_df.empty else source_timestamp_qds_rcd_df.loc[0, 'timestamp']
i_dcct_rcd_df, i_didt_rcd_df, u_res_rcd_df, u_diff_rcd_df = query_rcd.query_qds_pm(timestamp_qds_rcd, timestamp_qds_rcd,
signal_names=['I_DCCT', 'I_DIDT', 'U_RES', 'U_DIFF'])
# # RCO
source_timestamp_qds_rco_df = query_rco.find_source_timestamp_qds(timestamp_fgc_rco, duration=[(2, 's'), (2, 's')])
timestamp_qds_rco = np.nan if source_timestamp_qds_rco_df.empty else source_timestamp_qds_rco_df.loc[0, 'timestamp']
i_dcct_rco_df, i_didt_rco_df, u_res_rco_df, u_diff_rco_df = query_rco.query_qds_pm(timestamp_qds_rco, timestamp_qds_rco,
signal_names=['I_DCCT', 'I_DIDT', 'U_RES', 'U_DIFF'])
# LEADS
# # RCD
leads_name = [x for x in SignalMetadata.get_system_types_per_circuit_name(circuit_type, circuit_names[0]) if 'LEADS' in x][0]
source_timestamp_leads_rcd_df = query_rcd.find_timestamp_leads(timestamp_fgc_rcd, leads_name)
u_hts_leads_rcd_dfs = query_rcd.query_leads(timestamp_fgc_rcd, source_timestamp_leads_rcd_df, system=leads_name, signal_names=['U_HTS'], spark=spark, duration=[(300, 's'), (900, 's')])
u_res_leads_rcd_dfs = query_rcd.query_leads(timestamp_fgc_rcd, source_timestamp_leads_rcd_df, system=leads_name, signal_names=['U_RES'], spark=spark, duration=[(300, 's'), (900, 's')])
# # RCO
leads_name = [x for x in SignalMetadata.get_system_types_per_circuit_name(circuit_type, circuit_names[1]) if 'LEADS' in x][0]
source_timestamp_leads_rco_df = query_rco.find_timestamp_leads(timestamp_fgc_rco, leads_name)
u_hts_leads_rco_dfs = query_rco.query_leads(timestamp_fgc_rco, source_timestamp_leads_rco_df, system=leads_name, signal_names=['U_HTS'], spark=spark, duration=[(300, 's'), (900, 's')])
u_res_leads_rco_dfs = query_rco.query_leads(timestamp_fgc_rco, source_timestamp_leads_rco_df, system=leads_name, signal_names=['U_RES'], spark=spark, duration=[(300, 's'), (900, 's')])
# Create results table - RCD/O
results_table = query_rcd.create_report_analysis_template_rcd(timestamp_fgc_rcd, timestamp_fgc_rco, circuit_names, author=author)
analysis_rcd = R600ACircuitAnalysis(circuit_type, results_table, is_automatic=is_automatic)
analysis_rco = R600ACircuitAnalysis(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:
- 2 PM DQAMGNA (A+B) files and 1 PM EE file should be generated for 600 A circuits with EE
- Difference between QPS board A and B timestamp = 1 ms
- PC timestamp is QPS timestamp +/- 20 ms
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_RCD': timestamp_fgc_rcd, 'FGC_RCO': timestamp_fgc_rco,
'PIC_RCD': timestamp_pic_rcd, 'PIC_RCO': timestamp_pic_rco,
'QDS_A_RCD':source_timestamp_qds_rcd_df.loc[0, 'timestamp'] if len(source_timestamp_qds_rcd_df) > 0 else np.nan,
'QDS_B_RCD':source_timestamp_qds_rcd_df.loc[1, 'timestamp'] if len(source_timestamp_qds_rcd_df) > 1 else np.nan,
'QDS_A_RCO':source_timestamp_qds_rco_df.loc[0, 'timestamp'] if len(source_timestamp_qds_rco_df) > 0 else np.nan,
'QDS_B_RCO':source_timestamp_qds_rco_df.loc[1, 'timestamp'] if len(source_timestamp_qds_rco_df) > 1 else np.nan}
analysis_rcd.create_timestamp_table(timestamp_dct, circuit_names[0])
```
%% Cell type:markdown id: tags:
# 4. PC
## 4.1. Main Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_a_rc_df |DataFrame |A |PM|I_A is the raw RC power converter current logged around the FPA with high sampling frequency|
|i_meas_rc_df |DataFrame |A |PM|I_MEAS RC power converter current is filtered I_A with lower sampling frequency and longer duration|
|i_ref_rc_df |DataFrame |A |PM|The reference current of an RC power converter, I_REF|
|events_action_rc_df |DataFrame |text |PM|event action storing information about the state of an RC PC operation, e.g. FAULT, EVENTS.ACTION|
|events_symbol_rc_df |DataFrame |text |PM|event action storing information about source of an RC PC FPA, e.g. TRG EXTERNAL FAST ABORT, EVENTS.SYMBOL|
Note that **rc** in the table above denotes RCD and RCO, i.e., there are four signals for each circuit.
*ANALYSIS*:
- determination of the source of an FPA trigger based on EVENTS.SYMBOL and EVENTS.ACTION signals
- detection of the start of a quench as a deviation of I_A and I_REF
- calculation of the MIITs
- calculation of the quench current
- calculation of the duration of a plateau / the ramp rate before a quench (based on PM event buffer)
*GRAPHS*:
- dashed blue line denotes the start of a quench (I_A starts to deviate from I_REF)
- t = 0 s corresponds to the FGC timestamp
%% Cell type:code id: tags:
``` python
t_quench = analysis_rcd.find_time_of_quench(i_ref_rcd_df, i_a_rcd_df)
t_quench = 0 if t_quench is None else t_quench
analysis_rcd.plot_i_meas_pc(circuit_names[0], timestamp_fgc_rcd, [i_meas_rcd_df, i_ref_rcd_df, i_a_rcd_df], xlim=(t_quench-1, t_quench+1))
```
%% Cell type:code id: tags:
``` python
analysis_rcd.plot_i_meas_pc_zoom(circuit_names[0], timestamp_fgc_rcd, t_quench, [i_meas_rcd_df, i_ref_rcd_df, i_a_rcd_df], xlim=(t_quench-0.1, t_quench+0.1))
analysis_rcd.analyze_i_meas_pc_trigger(timestamp_fgc_rcd, events_action_rcd_df, events_symbol_rcd_df)
analysis_rcd.calculate_current_miits(i_meas_rcd_df, t_quench, col_name='I_MEAS MIITs RCD')
analysis_rcd.calculate_quench_current(i_meas_rcd_df, t_quench, col_name='I_Q_RCD')
analysis_rcd.calculate_current_slope(i_meas_rcd_df, col_name='Ramp Rate RCD')
```
%% Cell type:code id: tags:
``` python
t_quench = analysis_rco.find_time_of_quench(i_ref_rco_df, i_a_rco_df)
t_quench = 0 if t_quench is None else t_quench
analysis_rco.plot_i_meas_pc(circuit_names[1], timestamp_fgc_rco, [i_meas_rco_df, i_ref_rco_df, i_a_rco_df], xlim=(t_quench-1, t_quench+1))
```
%% Cell type:code id: tags:
``` python
analysis_rco.plot_i_meas_pc_zoom(circuit_names[1], timestamp_fgc_rco, t_quench, [i_meas_rco_df, i_ref_rco_df, i_a_rco_df], xlim=(t_quench-0.1, t_quench+0.1))
analysis_rco.analyze_i_meas_pc_trigger(timestamp_fgc_rco, events_action_rco_df, events_symbol_rco_df)
analysis_rco.calculate_current_miits(i_meas_rco_df, t_quench, col_name='I_MEAS MIITs RCO')
analysis_rco.calculate_quench_current(i_meas_rco_df, t_quench, col_name='I_Q_RCO')
analysis_rco.calculate_current_slope(i_meas_rco_df, col_name='Ramp Rate RCO')
```
%% Cell type:code id: tags:
``` python
analysis_rcd.results_table[['Circuit Name', 'Date', 'Time', 'I_Q_RCD', 'I_Q_RCO', 'I_MEAS MIITs RCD', 'I_MEAS MIITs RCO', 'Ramp Rate RCD', 'Ramp Rate RCO', 'Plateau Duration']]
```
%% Cell type:markdown id: tags:
## 4.2. Earth Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_earth_rc_df |DataFrame |A |PM|Earth current of an RC circuit power converter, I_EARTH|
Note that **rc** in the table above denotes RCD and RCO, i.e., there is one signal for each circuit.
*ANALYSIS*:
- calculation of the maximum absolute earth current (maintaining the sign)
*GRAPHS*:
- t = 0 s corresponds to the FGC timestamp
%% Cell type:code id: tags:
``` python
analysis_rcd.plot_i_earth_pc(circuit_names[0], timestamp_fgc_rcd, i_earth_rcd_df)
analysis_rcd.calculate_max_i_earth_pc(i_earth_rcd_df, col_name='Earth Current RCD')
```
%% Cell type:code id: tags:
``` python
analysis_rco.plot_i_earth_pc(circuit_names[0], timestamp_fgc_rco, i_earth_rco_df)
analysis_rco.calculate_max_i_earth_pc(i_earth_rco_df, col_name='Earth Current RCO')
```
%% Cell type:markdown id: tags:
# 5. QDS
The quench voltage U_RES is calculated according to the following formula:
\begin{equation}
U_{\text{RES}} = U_{\text{DIFF}} + L d/dt (I+U_{\text{DIFF}}/R).
\end{equation}
Note that I_DCCT is the QPS signal name, even though the current is actually measured not with a DCCT, but with a LEM detector, hence the poorer quality w.r.t. to the FGC I_A/B/MEAS signals that are measured with a DCCT.
It can be seen from the sign convention in the figure below that a resistive voltage always has opposite sign to the measured current.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/600A/600A_without_EE.png" width=75%>
As U_DIFF contributes directly to U_RES, the resolution of U_RES is, at least partially, limited by that of U_DIFF. Moreover, U_RES is affected by the noisy time derivative of the current signal.
The QPS signals that are communicated to the post-mortem system have only 12 bit resolution.
%% Cell type:markdown id: tags:
## 5.1. Resistive Voltage
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_meas_nxcals_rc_df |DataFrame |A |NXCALS|Power converter current in an RC circuit, I_MEAS|
|u_res_nxcals_rc_df |DataFrame |V |NXCALS|Resistive voltage of magnets measured with QPS in an RC circuit, U_RES|
|u_res_rc_df |DataFrame |V |PM|Resistive voltage of magnets measured with QPS in an RC circuit, U_RES|
Note that **rc** in the table above denotes RCD and RCO, i.e., there are two signals for each circuit.
*ANALYSIS*:
- Check if the U_RES signal before a quench is increasing for at least one board, which would indicate a QPS trip
- Calculate the 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.
*GRAPHS*:
First plot (U_RES and I_MEAS prior to a quench)
- t = 0 s corresponds to the FGC timestamp
Second plot (U_RES and the initial slope of U_RES)
- t = 0 s corresponds to the QPS timestamp
%% Cell type:code id: tags:
``` python
analysis_rcd.plot_u_res(circuit_names[0], timestamp_qds_rcd, u_res_nxcals_rcd_df, i_meas_nxcals_rcd_df)
u_res_rcd_slope_df = analysis_rcd.calculate_u_res_slope(u_res_rcd_df, col_name='dUres/dt RCD')
analysis_rcd.plot_u_res_slope(circuit_names[0], timestamp_qds_rcd, u_res_rcd_df, u_res_rcd_slope_df)
```
%% Cell type:code id: tags:
``` python
analysis_rco.plot_u_res(circuit_names[1], timestamp_qds_rco, u_res_nxcals_rco_df, i_meas_nxcals_rco_df)
u_res_rco_slope_df = analysis_rco.calculate_u_res_slope(u_res_rco_df, col_name='dUres/dt RCO')
analysis_rco.plot_u_res_slope(circuit_names[1], timestamp_qds_rco, u_res_rco_df, u_res_rco_slope_df)
```
%% Cell type:code id: tags:
``` python
analysis_rcd.results_table[['Circuit Name', 'Date', 'Time', 'dUres/dt RCD', 'dUres/dt RCO']]
```
%% Cell type:markdown id: tags:
## 5.2. I_DCCT, I_DIDT Currents; U_RES, U_DIFF Voltages
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_dcct_rc_df |DataFrame |A |PM|DC current leads of QPS in an RC circuit, I_DCCT|
|i_didt_rc_df |DataFrame |A/s |PM|di/dt current leads of QPS in an RC circuit, I_DIDT|
|u_diff_rc_df |DataFrame |V |PM|differential voltage of QPS in an RC circuit, U_DIFF|
|u_res_rc_df |DataFrame |V |PM|resistive voltage (after inductance compensation) of QPS in an RC circuit used for quench detection, U_RES|
Note that **rc** in the table above denotes RCD and RCO, i.e., there are two signals for each circuit.
*ANALYSIS*
- Check the integrity of all four signals (U_DIFF, I_DCCT, I_DIDT and U_RES). If one of the signals (especially U_DIFF or I_DCCT) stays at zero or shows wrong values the cabling of this quench detector could have issues. Compare U_DIFF (measured signal) to U_REF (signal compensated for inductive voltage).
*CRITERIA*
- **U_RES < 0.7*100 mV and noise of U_RES on the plateaus < 20mV**
*GRAPHS*:
- t = 0 s corresponds to the QPS timestamp
%% Cell type:code id: tags:
``` python
analysis_rcd.plot_qds(circuit_names[0], timestamp_qds_rcd, i_dcct_rcd_df, i_didt_rcd_df, u_diff_rcd_df, u_res_rcd_df)
```
%% Cell type:code id: tags:
``` python
analysis_rco.plot_qds(circuit_names[1], timestamp_qds_rco, i_dcct_rco_df, i_didt_rco_df, u_diff_rco_df, u_res_rco_df)
```
%% Cell type:code id: tags:
``` python
# Get expert input on reason
analysis_rco.results_table['Reason'] = get_expert_decision('Reason for FPA: ', ['quench', 'coupling', 'other'])
# Get expert input on quench origin
analysis_rco.results_table['Quench Origin'] = get_expert_decision('Origin of a quench', ['magnet', 'busbar', 'other'])
```
%% Cell type:markdown id: tags:
# 6. LEADS
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|u_hts_leads_rc_df |DataFrame |V |PM/NXCALS|RC leads voltage, U_HTS|
|u_res_leads_rc_df |DataFrame |V |PM/NXCALS|RC leads voltage, U_RES|
Note that **rc** in the table above denotes RCD and RCO, i.e., there are two signals for each circuit.
*ANALYSIS*:
- check if U_HTS for 2 consecutive datapoints is above the threshold 3 mV
- check if U_RES for 2 consecutive datapoints is above the threshold 100 mV
*GRAPHS*:
- t = 0 s corresponds to the LEADS timestamp
%% Cell type:code id: tags:
``` python
analysis_rcd.analyze_leads_voltage(u_hts_leads_rcd_dfs, circuit_names[0], timestamp_fgc_rcd, signal='U_HTS', value_min=-0.003, value_max=0.003)
```
%% Cell type:code id: tags:
``` python
analysis_rcd.analyze_leads_voltage(u_res_leads_rcd_dfs, circuit_names[0], timestamp_fgc_rcd, signal='U_RES', value_min=-0.1, value_max=0.1)
```
%% Cell type:code id: tags:
``` python
analysis_rco.analyze_leads_voltage(u_hts_leads_rco_dfs, circuit_names[1], timestamp_fgc_rco, signal='U_HTS', value_min=-0.003, value_max=0.003)
```
%% Cell type:code id: tags:
``` python
analysis_rco.analyze_leads_voltage(u_res_leads_rco_dfs, circuit_names[1], timestamp_fgc_rco, signal='U_RES', value_min=-0.1, value_max=0.1)
```
%% Cell type:markdown id: tags:
# 7. Final Report
## 7.1. Display Results Table
%% Cell type:code id: tags:skip_output
``` python
pd.set_option('display.max_columns', None)
analysis_rcd.results_table
```
%% Cell type:markdown id: tags:
## 7.2. Write Results Table to CSV
%% Cell type:code id: tags:
``` python
timestamp_fgc = timestamp_fgc_rcd if not np.isnan(timestamp_fgc_rcd) else timestamp_fgc_rco
file_name = "{}-{}-PM_600A_RCD-RCO_FPA".format(Time.to_datetime(timestamp_fgc).strftime("%Y.%m.%d_%H%M%S.%f"), analysis_start_time)
```
%% Cell type:code id: tags:
``` python
# Create folder for circuit_name
circuit_name = circuit_names[0]
!mkdir -p /eos/project/l/lhcsm/operation/600A/$circuit_name
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}_results_table.csv'.format(circuit_name, file_name)
analysis_rcd.results_table.to_csv(full_path)
print('Full results table saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
```
%% Cell type:markdown id: tags:
## 7.3. Display MP3 Results Table
%% Cell type:code id: tags:skip_output
``` python
mp3_results_table = analysis_rcd.create_mp3_results_table_rcdo()
mp3_results_table
```
%% Cell type:markdown id: tags:
## 7.4. Write MP3 Quench Database Table to CSV
%% Cell type:code id: tags:
``` python
# Create folder for circuit_name
circuit_name = circuit_names[0]
!mkdir -p /eos/project/l/lhcsm/operation/600A/$circuit_name
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}_mp3_results_table.csv'.format(circuit_name, file_name)
mp3_results_table.to_csv(full_path)
print('MP3 results table saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
```
%% Cell type:markdown id: tags:
## 7.5. Export Notebook as an HTML File
%% Cell type:code id: tags:
``` python
file_name_html = file_name + '_report.html'
!mkdir -p /eos/project/l/lhcsm/operation/600A/$circuit_name
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}'.format(circuit_name, file_name_html)
!{sys.executable} -m jupyter nbconvert --to html $'AN_600A_RCDO_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html
print('Notebook report to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
display(Javascript('IPython.notebook.save_notebook();'))
time.sleep(5)
!{sys.executable} -m jupyter nbconvert --to html $'AN_600A_RCDO_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html
```
%% Cell type:markdown id: tags:
## 7.6. Export Compact Notebook as an HTML File
%% Cell type:code id: tags:
``` python
apply_report_template()
file_name_html = file_name + '_compact_report.html'
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}'.format(circuit_name, file_name_html)
!{sys.executable} -m jupyter nbconvert --to html $'AN_600A_RCDO_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html --TemplateExporter.exclude_input=True --TagRemovePreprocessor.remove_all_outputs_tags='["skip_output"]' --TagRemovePreprocessor.remove_cell_tags='["skip_cell"]'
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_600A_RCDO_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$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
```
......
%% Cell type:markdown id: tags:
<h1><center>Analysis of an FPA in an 600A Circuit - with/without Energy Extraction</center></h1>
Figure 1 shows a generic circuit diagram, equipped with EE and parallel resistor, as well as lead resistances and a quench resistance.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/600A/600A.png" width=75%>
source: Test Procedure and Acceptance Criteria for the 600 A Circuits, MP3 Procedure, <a href="https://edms.cern.ch/document/874716/5.3">https://edms.cern.ch/document/874716/5.3</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
## 0.1. Import Necessary Packages
%% 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
# lhc-sm-api
from lhcsmapi.Time import Time
from lhcsmapi.Timer import Timer
from lhcsmapi.pyedsl.QueryBuilder import QueryBuilder
from lhcsmapi.analysis.R600ACircuitQuery import R600ACircuitQuery
from lhcsmapi.analysis.expert_input import get_expert_decision
from lhcsmapi.analysis.report_template import apply_report_template
from lhcsmapi.analysis.R600ACircuitAnalysis import R600ACircuitAnalysis
from lhcsmapi.metadata.SignalMetadata import SignalMetadata
# GUI
from lhcsmapi.gui.qh.DateTimeBaseModule import DateTimeBaseModule
from lhcsmapi.gui.pc.FgcPmSearchModuleMediator import FgcPmSearchModuleMediator
from lhcsmapi.gui.pc.R600AFgcPmSearchBaseModule import R600AFgcPmSearchBaseModule
analysis_start_time = datetime.now().strftime("%Y.%m.%d_%H%M%S.%f")
```
%% Cell type:markdown id: tags:
## 0.2. LHCSMAPI Version
%% Cell type:code id: tags:
``` python
import lhcsmapi
print('Analysis executed with lhcsmapi version: {}'.format(lhcsmapi.__version__))
```
%% Cell type:markdown id: tags:
## 0.3. Notebook Version
%% Cell type:code id: tags:
``` python
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 600A circuit with/without EE please:
1. Select circuit family (e.g., RCS)
2. Choose start and end time
3. Choose analysis mode (Automatic by default)
Once these inputs are provided, click 'Find FGC PM' button entries'. 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 = '600A'
fgc_pm_search = FgcPmSearchModuleMediator(DateTimeBaseModule(start_date_time='2018-12-06 00:00:00+01:00',
end_date_time='2018-12-07 00:00:00+01:00'), R600AFgcPmSearchBaseModule(), circuit_type=circuit_type)
display(fgc_pm_search.widget)
```
%% Cell type:markdown id: tags:
# 2. Query All Signals Prior to Analysis
%% Cell type:code id: tags:skip_output
``` python
with Timer():
author = fgc_pm_search.get_author()
is_automatic = fgc_pm_search.is_automatic_mode()
timestamp_fgc = fgc_pm_search.get_fgc_timestamp()
circuit_name = fgc_pm_search.get_fgc_circuit()
query = R600ACircuitQuery(circuit_type, circuit_name, max_executions=10)
i_meas_df, i_a_df, i_ref_df, i_earth_df = query.query_pc_pm(timestamp_fgc, timestamp_fgc, signal_names=['I_MEAS', 'I_A', 'I_REF', 'I_EARTH'])
events_action_df, events_symbol_df = query.query_pc_pm_events(timestamp_fgc, signal_names=['ACTION', 'SYMBOL'])
# Create results table
results_table = query.create_report_analysis_template(timestamp_fgc, author=author)
# PIC
timestamp_pic = query.find_timestamp_pic(timestamp_fgc, spark=spark)
# EE
if 'EE' in SignalMetadata.get_system_types_per_circuit_name(circuit_type, circuit_name):
query.max_executions += 2
source_timestamp_ee_df = query.find_source_timestamp_ee(timestamp_fgc)
timestamp_ee = source_timestamp_ee_df.loc[0, 'timestamp']
u_dump_res_df = query.query_ee_u_dump_res_pm(timestamp_ee, timestamp_fgc, system='EE', signal_names=['U_DUMP_RES'])[0]
else:
source_timestamp_ee_df = pd.DataFrame()
results_table['EE max voltage'] = 'No EE'
# QDS
# To check if there was any drift of QDS cards prior to the trigger
i_meas_nxcals_df = query.query_pc_nxcals(timestamp_fgc, signal_names=['I_MEAS'], spark=spark)[0]
u_res_nxcals_df = query.query_iqps_nxcals(timestamp_fgc, signal_names=['U_RES'], spark=spark)[0]
source_timestamp_qds_df = query.find_source_timestamp_qds(timestamp_fgc, duration=[(2, 's'), (2, 's')])
timestamp_qds = np.nan if source_timestamp_qds_df.empty else source_timestamp_qds_df.loc[0, 'timestamp']
i_dcct_df, i_didt_df, u_res_df, u_diff_df = query.query_qds_pm(timestamp_qds, timestamp_qds, signal_names=['I_DCCT', 'I_DIDT', 'U_RES', 'U_DIFF'])
# LEADS
leads_name = [x for x in SignalMetadata.get_system_types_per_circuit_name(circuit_type, circuit_name) if 'LEADS' in x][0]
source_timestamp_leads_df = query.find_timestamp_leads(timestamp_fgc, leads_name)
u_hts_leads_dfs = query.query_leads(timestamp_fgc, source_timestamp_leads_df, system=leads_name, signal_names=['U_HTS'], spark=spark, duration=[(300, 's'), (900, 's')])
u_res_leads_dfs = query.query_leads(timestamp_fgc, source_timestamp_leads_df, system=leads_name, signal_names=['U_RES'], spark=spark, duration=[(300, 's'), (900, 's')])
analysis = R600ACircuitAnalysis(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, EE if applicable). The criterion of passing this test described in detail in 600APIC2.
In short the following criteria should be checked:
- 2 PM DQAMGNA (A+B) files and 1 PM EE file should be generated for 600 A circuits with EE
- Difference between QPS board A and B timestamp = 1 ms
- PC timestamp is QPS timestamp +/- 20 ms
- EE timestamp is +/-20 ms from the QPS timestamp
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': timestamp_fgc, '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}
if 'EE' in SignalMetadata.get_system_types_per_circuit_name(circuit_type, circuit_name):
timestamp_dct['EE'] = source_timestamp_ee_df.loc[0, 'timestamp'] if len(source_timestamp_ee_df) > 0 else np.nan
analysis.create_timestamp_table(timestamp_dct, circuit_name)
```
%% Cell type:markdown id: tags:
# 4. PC
## 4.1. Main Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_a_df |DataFrame |A |PM|I_A is the raw power converter current logged around the FPA with high sampling frequency|
|i_meas_df |DataFrame |A |PM|I_MEAS power converter current is filtered I_A with lower sampling frequency and longer duration|
|i_ref_df |DataFrame |A |PM|The reference current of the power converter, I_REF|
|events_action_df |DataFrame |text |PM|event action storing information about the state of the PC operation, e.g. FAULT, EVENTS.ACTION|
|events_symbol_df |DataFrame |text |PM|event action storing information about source of PC FPA, e.g. TRG EXTERNAL FAST ABORT, EVENTS.SYMBOL|
*ANALYSIS*:
- determination of the source of an FPA trigger based on EVENTS.SYMBOL and EVENTS.ACTION signals
- detection of the start of a quench as a deviation of I_A and I_REF
- calculation of the MIITs
- calculation of the quench current
- calculation of the duration of a plateau / the ramp rate before a quench
*GRAPHS*:
- dashed blue line denotes the start of a quench (I_A starts to deviate from I_REF)
- t = 0 s corresponds to the FGC timestamp
%% Cell type:code id: tags:
``` python
t_quench = analysis.find_time_of_quench(i_ref_df, i_a_df)
t_quench = 0 if t_quench is None else t_quench
analysis.plot_i_meas_pc(circuit_name, timestamp_fgc, [i_meas_df, i_ref_df, i_a_df], xlim=(t_quench-1, t_quench+1))
```
%% Cell type:code id: tags:
``` python
analysis.plot_i_meas_pc_zoom(circuit_name, timestamp_fgc, t_quench, [i_meas_df, i_ref_df, i_a_df], xlim=(t_quench-0.1, t_quench+0.1))
analysis.analyze_i_meas_pc_trigger(timestamp_fgc, events_action_df, events_symbol_df)
analysis.calculate_current_miits(i_meas_df, t_quench)
analysis.calculate_quench_current(i_meas_df, t_quench)
analysis.calculate_current_slope(i_meas_df)
```
%% Cell type:markdown id: tags:
## 4.2. Earth Current
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_earth_df |DataFrame |A |PM|Earth current of the RCD power converter, I_EARTH|
*ANALYSIS*:
- calculation of the maximum absolute earth current (maintaining the sign)
*PLOT*:
- t = 0 s corresponds to the FGC timestamp
%% Cell type:code id: tags:
``` python
analysis.plot_i_earth_pc(circuit_name, timestamp_fgc, i_earth_df)
analysis.calculate_max_i_earth_pc(i_earth_df)
```
%% Cell type:markdown id: tags:
# 5. EE
The analysis is only performed for circuits with an EE system.
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|u_dump_res_df |DataFrame |V |PM|Voltage of the energy extraction system, U_DUMP_RES|
|i_meas_df |DataFrame |A |PM|I_MEAS power converter current is filtered I_A with lower sampling frequency and longer duration|
*ANALYSIS*:
- calculation of the maximum voltage over the energy extraction system
*GRAPHS*:
- t = 0 s corresponds to the FGC timestamp
%% Cell type:code id: tags:
``` python
if 'EE' in SignalMetadata.get_system_types_per_circuit_name(circuit_type, circuit_name):
analysis.analyze_u_dump_res_ee(circuit_name, timestamp_fgc, i_meas_df, u_dump_res_df)
else:
print('Circuit %s does not contain an EE system, analysis skipped.' % circuit_name)
```
%% Cell type:markdown id: tags:
# 6. QDS
The quench voltage U_RES is calculated according to the following formula:
\begin{equation}
U_{\text{RES}} = U_{\text{DIFF}} + L d/dt (I+U_{\text{DIFF}}/R).
\end{equation}
Note that I_DCCT is the QPS signal name, even though the current is actually measured not with a DCCT, but with a LEM detector, hence the poorer quality w.r.t. to the FGC I_A/B/MEAS signals that are measured with a DCCT.
It can be seen from the sign convention in the figure below that a resistive voltage always has opposite sign to the measured current.
<img src="https://gitlab.cern.ch/LHCData/lhc-sm-hwc/-/raw/master/figures/600A/600A.png" width=75%>
As U_DIFF contributes directly to U_RES, the resolution of U_RES is, at least partially, limited by that of U_DIFF. Moreover, U_RES is affected by the noisy time derivative of the current signal.
The QPS signals that are communicated to the post-mortem system have only 12 bit resolution.
%% Cell type:markdown id: tags:
## 6.1. Resistive Voltage
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_meas_nxcals_df |DataFrame |A |NXCALS|Power converter current in a 600A circuit, I_MEAS|
|u_res_nxcals_df |DataFrame |V |NXCALS|Resistive voltage of magnets measured with QPS in a 600A circuit, U_RES|
|u_res_df |DataFrame |V |PM|Resistive voltage of magnets measured with QPS in a 600A circuit, U_RES|
*ANALYSIS*:
- Check if the U_RES signal before a quench is increasing for at least one board, which would indicate a QPS trip
- Calculate the 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.
*GRAPHS*:
First plot (U_RES and I_MEAS prior to a quench)
- t = 0 s corresponds to the FGC timestamp
Second plot (U_RES and the initial slope of U_RES)
- t = 0 s corresponds to the QPS timestamp
%% Cell type:code id: tags:
``` python
analysis.plot_u_res(circuit_name, timestamp_qds, u_res_nxcals_df, i_meas_nxcals_df)
```
%% Cell type:code id: tags:
``` python
u_res_slope_df = analysis.calculate_u_res_slope(u_res_df)
analysis.plot_u_res_slope(circuit_name, timestamp_qds, u_res_df, u_res_slope_df)
```
%% Cell type:markdown id: tags:
## 6.2. I_DCCT, I_DIDT Currents; U_RES, U_DIFF Voltages
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|i_dcct_df |DataFrame |A |PM|DC current leads of QPS, I_DCCT|
|i_didt_df |DataFrame |A/s |PM|di/dt current leads of QPS, I_DIDT|
|u_diff_df |DataFrame |V |PM|differential voltage of QPS, U_DIFF|
|u_res_df |DataFrame |V |PM|resistive voltage (after inductance compensation) of QPS used for quench detection, U_RES|
*ANALYSIS*
- Check the integrity of all four signals (U_DIFF, I_DCCT, I_DIDT and U_RES). If one of the signals (especially U_DIFF or I_DCCT) stays at zero or shows wrong values the cabling of this quench detector could have issues. Compare U_DIFF (measured signal) to U_REF (signal compensated for inductive voltage).
*CRITERIA*
- **U_RES < 0.7*100 mV and noise of U_RES on the plateaus < 20mV**
*GRAPHS*:
- t = 0 s corresponds to the QPS timestamp
%% Cell type:code id: tags:
``` python
analysis.plot_qds(circuit_name, timestamp_qds, i_dcct_df, i_didt_df, u_diff_df, u_res_df)
# Get expert input on reason
analysis.results_table['Reason'] = get_expert_decision('Reason for FPA: ', ['quench', 'coupling', 'other'])
# Get expert input on quench origin
analysis.results_table['Quench Origin'] = get_expert_decision('Origin of a quench', ['magnet', 'busbar', 'other'])
```
%% Cell type:markdown id: tags:
# 7. LEADS
*QUERY*:
|Variable Name |Variable Type |Variable Unit |Database|Comment
|---------------|---------------|---------------|--------|------|
|u_hts_leads_df |DataFrame |V |PM/NXCALS|RC leads voltage, U_HTS|
|u_res_leads_df |DataFrame |V |PM/NXCALS|RC leads voltage, U_RES|
*ANALYSIS*:
- check if U_HTS for 2 consecutive datapoints is above the threshold 3 mV
- check if U_RES for 2 consecutive datapoints is above the threshold 100 mV
*GRAPHS*:
- t = 0 s corresponds to the LEADS timestamp
%% Cell type:code id: tags:
``` python
analysis.analyze_leads_voltage(u_hts_leads_dfs, circuit_name, timestamp_fgc, signal='U_HTS', value_min=-0.003, value_max=0.003)
```
%% Cell type:code id: tags:
``` python
analysis.analyze_leads_voltage(u_res_leads_dfs, circuit_name, timestamp_fgc, signal='U_RES', value_min=-0.1, value_max=0.1)
```
%% Cell type:markdown id: tags:
# 8. Final Report
## 8.1. Display Results Table
%% Cell type:code id: tags:skip_output
``` python
pd.set_option('display.max_columns', None)
analysis.results_table
```
%% Cell type:markdown id: tags:
## 8.2. Write Results Table to CSV
%% Cell type:code id: tags:
``` python
file_name = "{}-{}-PM_600A_with_without_EE_FPA".format(Time.to_datetime(timestamp_fgc).strftime("%Y.%m.%d_%H%M%S.%f"), analysis_start_time)
# Create folder for circuit_name
!mkdir -p /eos/project/l/lhcsm/operation/600A/$circuit_name
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}_results_table.csv'.format(circuit_name, file_name)
analysis.create_mp3_results_table().to_csv(full_path)
print('Full results table saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
```
%% Cell type:markdown id: tags:
## 8.3. Display MP3 Quench Database Table
%% Cell type:code id: tags:skip_output
``` python
mp3_results_table = analysis.create_mp3_results_table()
mp3_results_table
```
%% Cell type:markdown id: tags:
## 8.4. Write MP3 Quench Database Table to CSV
%% Cell type:code id: tags:
``` python
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}_mp3_results_table.csv'.format(circuit_name, file_name)
mp3_results_table.to_csv(full_path)
print('MP3 results table saved to (Windows): ' + '\\\\cernbox-smb' + full_path.replace('/', '\\'))
```
%% Cell type:markdown id: tags:
## 8.5. Export Notebook as an HTML File
%% Cell type:code id: tags:
``` python
file_name_html = file_name + '_report.html'
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}'.format(circuit_name, file_name_html)
!{sys.executable} -m jupyter nbconvert --to html $'AN_600A_with_without_EE_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html
print('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_600A_with_without_EE_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html
```
%% Cell type:markdown id: tags:
## 8.6. Export Compact Notebook as an HTML File
%% Cell type:code id: tags:
``` python
apply_report_template()
file_name_html = file_name + '_compact_report.html'
full_path = '/eos/project/l/lhcsm/operation/600A/{}/{}'.format(circuit_name, file_name_html)
!{sys.executable} -m jupyter nbconvert --to html $'AN_600A_with_without_EE_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$circuit_name/$file_name_html --TemplateExporter.exclude_input=True --TagRemovePreprocessor.remove_all_outputs_tags='["skip_output"]' --TagRemovePreprocessor.remove_cell_tags='["skip_cell"]'
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_600A_with_without_EE_FPA.ipynb' --output /eos/project/l/lhcsm/operation/600A/$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
```
......