add: import 100 run results + more

- master log parser to get run info
- test for master log parser
- master log reader
- note field for single run
- fix datetime manipulation for single result table
This commit is contained in:
Wataru Otsubo 2024-09-13 13:39:51 +09:00 committed by qwjyh
parent f5e6caf936
commit 21f38e83db
9 changed files with 1505 additions and 16 deletions

View file

@ -3,13 +3,43 @@ module PSBoardDataBase
using SQLite
using DBInterface
using Tables
using CSV
using DataFrames
using Dates
include("parse_qaqc_master_log.jl")
include("create_table.jl")
include("import_data.jl")
function create_database_from_exported_csvs(
dbpath::AbstractString;
single_run_csv::AbstractString,
runlist_csv::AbstractString,
dispatch_csv::AbstractString,
hundred_csv::AbstractString,
masterlog_dir::AbstractString,
)
db = create_database(dbpath)
single_result_df = CSV.read(single_run_csv, DataFrame)
runlist_table = CSV.read(runlist_csv, DataFrame)
dispatch_table = CSV.read(dispatch_csv, DataFrame)
extra_100test_result_df = CSV.read(hundred_csv, DataFrame)
insert_qaqc_campaign_id(db)
insert_qaqc_positions(db)
add_psboard_ids(db, single_result_df)
add_qaqc_runlist(db, runlist_table)
add_qaqc_single_result(db, single_result_df, runlist_table)
add_qaqc_dispatch(db, dispatch_table)
add_qaqc_runlist_from_masterlogs(db, masterlog_dir)
add_qaqc_100test_result(db, extra_100test_result_df)
db
end
greet() = print("Hello World!")
end # module PSBoardDataBase

View file

@ -130,11 +130,23 @@ function add_qaqc_runlist(db::SQLite.DB, runlist_table::DataFrame)
nothing
end
function get_campaign_id_from_run_id(runid::Integer)
if runid < 63
1
elseif runid < 98
2
else
3
end
end
function add_qaqc_single_result(
db::SQLite.DB,
single_result_table::DataFrame,
runlist_table::DataFrame,
)
single_result_table = prepare_single_result_df(single_result_table)
position_id_map =
["B-$i-$j" for i in 0:1 for j in 1:9] |> enumerate .|> (x -> begin
(i, s) = x
@ -180,7 +192,8 @@ function add_qaqc_single_result(
clock,
asdtp,
reset,
qaqc_result
qaqc_result,
note
)
VALUES (
:runid,
@ -194,7 +207,8 @@ function add_qaqc_single_result(
:clock,
:asdtp,
:reset,
:qaqc_result
:qaqc_result,
:note
)
""",
)
@ -221,13 +235,7 @@ function add_qaqc_single_result(
# Add run if it's not in `qaqc_runs` table
# or update info on the run (such as datetime)
if DBInterface.execute(stmt_search_runid, (; runid = row.runid)) |> isempty
campaign_id = if row.runid < 63
1
elseif row.runid < 98
2
else
3
end
campaign_id = get_campaign_id_from_run_id(row.runid)
comment = let
row_run = filter(
Symbol("Run ID") => x -> !ismissing(x) && x == row.runid,
@ -245,7 +253,7 @@ function add_qaqc_single_result(
(
runid = row.runid,
campaign_id = campaign_id,
run_datetime = row.timestamp,
run_datetime = row.timestamp |> string,
note = comment,
shifter = row.shifter,
logfile = row.qaqc_log_file,
@ -257,7 +265,7 @@ function add_qaqc_single_result(
stmt_update_runid,
(
runid = row.runid,
run_datetime = row.timestamp,
run_datetime = row.timestamp |> string,
shifter = row.shifter,
logfile = row.qaqc_log_file,
shiftscript_ver = row.shiftscript_ver,
@ -287,6 +295,7 @@ function add_qaqc_single_result(
asdtp = row.asdtp,
reset = row.reset,
qaqc_result = row.qaqc_result,
note = row.comment,
),
)
end
@ -325,7 +334,7 @@ function prepare_dispatch_table(raw_dispatch_table::DataFrame)::DataFrame
df
end
function add_qaqcdispatch(db::SQLite.DB, dispatch_table::DataFrame)
function add_qaqc_dispatch(db::SQLite.DB, dispatch_table::DataFrame)
dispatch_table = prepare_dispatch_table(dispatch_table)
# TODO: provide datetime
@ -344,3 +353,197 @@ function add_qaqcdispatch(db::SQLite.DB, dispatch_table::DataFrame)
nothing
end
"""
Add qaqc run list from master log files in `logs_dir`.
Currently, it adds long runs and run with id 20-23 only (since normal runs are added from single run results table).
"""
function add_qaqc_runlist_from_masterlogs(db::SQLite.DB, logs_dir::AbstractString)
stmt_search_runid = DBInterface.prepare(
db,
sql"""
SELECT id
FROM qaqc_runs
WHERE id = :runid
""",
)
stmt_insert_runid = DBInterface.prepare(
db,
sql"""
INSERT INTO qaqc_runs
VALUES (:runid, :campaign_id, :run_datetime, :note, :shifter, :logfile, :shiftscript_ver)
""",
)
is_run_to_add(log_file) = begin
m = match(r"(\d+)\.log", log_file)
contains("_long.log")(log_file) ||
!isnothing(m) && (
begin
num = parse(Int64, m[1])
20 <= num <= 23 || num == 27 || num == 28
end
)
end
longrun_logs = readdir(logs_dir; join = true) |> filter(is_run_to_add)
# longrun_logs = readdir(logs_dir; join = true) |> filter(contains("_long.log"))
for longrun_log in longrun_logs
run_metadata = QaqcMasterLog.parse_master_log(longrun_log)
if isnothing(run_metadata)
continue
end
if !isempty(DBInterface.execute(stmt_search_runid, (; runid = run_metadata.runid)))
# runid is already in the database
continue
end
DBInterface.execute(
stmt_insert_runid,
(
runid = run_metadata.runid,
campaign_id = get_campaign_id_from_run_id(run_metadata.runid),
run_datetime = run_metadata.timestamp,
note = "",
shifter = run_metadata.shifters,
logfile = splitdir(longrun_log) |> last,
shiftscript_ver = run_metadata.shiftscript_version,
),
)
end
nothing
end
function prepare_100test_table(table::DataFrame)::DataFrame
df = copy(table, copycols = true)
transform!(
df,
Symbol("motherboard ID") =>
ByRow(s -> if startswith("PS")(s)
parse(Int64, s[3:end])
else
parse(Int64, s)
end) => :motherboard_id,
)
transform!(
df,
Cols(:motherboard_id, :runid, 4:13) =>
ByRow((psbid, runid, items...) -> if psbid == 484 && runid == 115
missings(items |> length)
else
items
end) => names(df)[4:13],
)
df
end
function add_qaqc_100test_result(db::SQLite.DB, table::DataFrame)
position_id_map =
["B-$i-$j" for i in 0:1 for j in 1:9] |> enumerate .|> (x -> begin
(i, s) = x
s => i
end) |> Dict
table = prepare_100test_table(table)
stmt_search_runid = DBInterface.prepare(
db,
sql"""
SELECT id
FROM qaqc_runs
WHERE id = :runid
""",
)
stmt_search_resistance_error = DBInterface.prepare(
db,
sql"""
SELECT psb_id
FROM qaqc_resistance_check
WHERE psb_id = :psboard_id AND passed = 0
""",
)
stmt_insert_result = DBInterface.prepare(
db,
sql"""
INSERT INTO
qaqc_extra_run_results (
runid,
psboard_id,
position,
num_tests,
insufficient_reset_with_10,
reset_failed_though_reconfig_done,
always_hit_flag_true,
dac_is_0,
bcid_shift,
efficiency_99percent,
bcid_fail_111,
bcid_fail_000,
low_efficiency,
bcid_fail,
invalid_register_value,
power_out_of_range,
note
)
VALUES (
:runid,
:psboard_id,
:position,
100,
:insufficient_reset_with_10,
:reset_failed_though_reconfig_done,
:always_hit_flag_true,
:dac_is_0,
:bcid_shift,
:efficiency_99percent,
:bcid_fail_111,
:bcid_fail_000,
:low_efficiency,
:bcid_fail,
:invalid_register_value,
:power_out_of_range,
:note
)
""",
)
for row in eachrow(table)
# TODO: get runid from master log file
if DBInterface.execute(stmt_search_runid, (; runid = row.runid)) |> isempty
# search for resistance error
if !isempty(
DBInterface.execute(stmt_search_resistance_error, (; psboard_id = row.motherboard_id)),
)
continue
end
end
DBInterface.execute(
stmt_insert_result,
(
runid = row.runid,
psboard_id = row.motherboard_id,
position = position_id_map[row.position],
insufficient_reset_with_10 = row.var"10回reset足りず",
reset_failed_though_reconfig_done = row.var"reconfig_done = 0なのにresetしていない",
always_hit_flag_true = row.var"always_hit_flag",
dac_is_0 = row.var"DAC = 0",
bcid_shift = row.var"DAC = 0",
efficiency_99percent = row.var"efficiency 99%",
bcid_fail_111 = row.var"BCID 0:0:0",
bcid_fail_000 = row.var"BCID 1:1:1",
low_efficiency = row.var"low efficiency",
bcid_fail = row.var"BCID fail",
invalid_register_value = row.var"invalid register values",
power_out_of_range = row.var"power out of range",
note = row.Column20,
),
)
end
nothing
end

View file

@ -0,0 +1,56 @@
module QaqcMasterLog
using Dates
"""
Metadata(not results) of QAQC run from master log.
# Fields
- `timestamp`: in UTC
- `runid`
- `shifters`
- `shiftscript_version::VersionNumber`
"""
struct QaqcMasterLogMetadata
timestamp::DateTime
runid::Int64
shifters::String
shiftscript_version::VersionNumber
end
"""
Parse master log.
If the `logfile` is empty, return `nothing`.
"""
function parse_master_log(logfile::AbstractString)
open(logfile) do f
first_line = readline(f)
if isempty(first_line)
@debug "file $(logfile) is empty"
@assert read(logfile) |> isempty
return nothing
end
shiftscript_version = split(first_line) |> last |> VersionNumber
@assert readline(f) |> contains("-----")
date_line = readline(f)
@assert date_line |> split |> first |> contains("Date")
date_part = split(date_line) |> last
datetime, timezone = split(date_part, '+')
@assert timezone == "0000" "Unexpected timestamp: timezone is not UTC"
# Maybe use ZonedDateTime here
timestamp = datetime |> DateTime
runid_line = readline(f)
runid = parse(Int64, runid_line |> split |> last)
shifters_line = readline(f)
@assert shifters_line |> split |> first |> contains("Shifters")
shifters = shifters_line |> split |> last
return QaqcMasterLogMetadata(timestamp, runid, shifters, shiftscript_version)
end
end
end

View file

@ -17,6 +17,7 @@ CREATE TABLE qaqc_single_run_results (
asdtp INTEGER,
reset INTEGER,
qaqc_result INTEGER,
note TEXT,
FOREIGN KEY("runid") REFERENCES "qaqc_runs"("id"),
FOREIGN KEY("psboard_id") REFERENCES "ps_boards"("id"),
FOREIGN KEY("position") REFERENCES "qaqc_positions"("id")
@ -63,11 +64,27 @@ CREATE TABLE qaqc_extra_run_results (
runid INTEGER,
psboard_id INTEGER NOT NULL,
position INTEGER,
num_tests INTEGER,
insufficient_reset_with_10 INTEGER,
reset_failed_though_reconfig_done INTEGER,
always_hit_flag_true INTEGER,
dac_is_0 INTEGER,
bcid_shift INTEGER,
efficiency_99percent INTEGER,
bcid_fail_111 INTEGER,
bcid_fail_000 INTEGER,
low_efficiency INTEGER,
bcid_fail INTEGER,
invalid_register_value INTEGER,
power_out_of_range INTEGER,
note TEXT,
FOREIGN KEY("runid") REFERENCES "qaqc_runs"("id"),
FOREIGN KEY("psboard_id") REFERENCES "ps_boards"("id"),
FOREIGN KEY("position") REFERENCES "qaqc_positions"("id")
);
-- TODO: add table for desciptions of each error?
CREATE TABLE qaqc_positions (
id INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
@ -98,4 +115,5 @@ AS
qaqc_runs
WHERE
qaqc_positions.id = qaqc_single_run_results.position AND
qaqc_runs.id = qaqc_single_run_results.runid
qaqc_runs.id = qaqc_single_run_results.runid;