module-qc-database-tools 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+
5
+ from module_qc_database_tools._version import __version__
6
+
7
+ if sys.version_info >= (3, 9):
8
+ from importlib import resources
9
+ else:
10
+ import importlib_resources as resources
11
+ data = resources.files("module_qc_database_tools") / "data"
12
+
13
+ __all__ = ("__version__", "data")
@@ -0,0 +1,4 @@
1
+ # file generated by setuptools_scm
2
+ # don't change, don't track in version control
3
+ __version__ = version = '0.0.1'
4
+ __version_tuple__ = version_tuple = (0, 0, 1)
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ from module_qc_database_tools.cli.main import app
6
+
7
+ logging.basicConfig()
8
+ __all__ = ("app",)
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from module_qc_database_tools.cli.main import app
4
+
5
+ app()
@@ -0,0 +1,450 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import math
5
+ from pathlib import Path
6
+
7
+ import itkdb
8
+ import pandas as pd
9
+ import typer
10
+
11
+ import module_qc_database_tools
12
+
13
+ app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
14
+
15
+
16
+ @app.command()
17
+ def main(
18
+ serial_number: str = typer.Option(..., "-sn", "--sn", help="ATLAS serialNumber"),
19
+ chip_template: Path = typer.Option(
20
+ (module_qc_database_tools.data / "YARR" / "chip_template.json").resolve(),
21
+ "-ch",
22
+ "--chipTemplate",
23
+ help="Default chip template from which the chip configs are generated.",
24
+ exists=True,
25
+ file_okay=True,
26
+ readable=True,
27
+ resolve_path=True,
28
+ ),
29
+ output_dir: Path = typer.Option(
30
+ ...,
31
+ "-o",
32
+ "--outdir",
33
+ help="Path to output directory. Configs must be in Yarr/configs.",
34
+ exists=False,
35
+ writable=True,
36
+ ),
37
+ ):
38
+ """
39
+ Main executable for generating yarr config.
40
+ """
41
+ client = itkdb.Client()
42
+ module = Module(client, serial_number)
43
+ typer.echo("INFO: Getting layer-dependent config from module SN...")
44
+ layer_config = get_layer_from_serial_number(serial_number)
45
+
46
+ module.generate_config(chip_template, output_dir, layer_config, suffix="warm")
47
+ module.generate_config(chip_template, output_dir, layer_config, suffix="cold")
48
+ module.generate_config(chip_template, output_dir, layer_config, suffix="LP")
49
+
50
+
51
+ class Module:
52
+ """
53
+ Module class.
54
+ """
55
+
56
+ def __init__(self, client, serial_number, name=None):
57
+ self.client = client
58
+ self.serial_number = serial_number
59
+ self.name = name if name else self.serial_number
60
+ self.module = client.get("getComponent", json={"component": serial_number})
61
+ self.bare_modules = []
62
+ for child in self.module["children"]:
63
+ if child["componentType"]["code"] == "BARE_MODULE":
64
+ self.bare_modules.append(
65
+ client.get(
66
+ "getComponent",
67
+ json={"component": child["component"]["serialNumber"]},
68
+ )
69
+ )
70
+ self.chips = []
71
+ for bare_module in self.bare_modules:
72
+ for child in bare_module["children"]:
73
+ if child["componentType"]["code"] == "FE_CHIP":
74
+ self.chips.append(
75
+ Chip(
76
+ client,
77
+ child["component"]["serialNumber"],
78
+ module_name=self.name,
79
+ )
80
+ )
81
+ if len(self.bare_modules) == 3 and len(self.chips) == 3:
82
+ self.module_type = "triplet"
83
+ typer.echo(f"INFO: triplet {self.serial_number} initiated.")
84
+ else:
85
+ self.module_type = "quad"
86
+ typer.echo(f"INFO: quad module {self.serial_number} initiated.")
87
+
88
+ def generate_config(self, chip_template, outdir, layer_config, suffix):
89
+ """
90
+ Generate module config.
91
+ """
92
+ typer.echo(
93
+ f"INFO: generating module config for module {self.serial_number} with {layer_config}"
94
+ )
95
+
96
+ spec = {"chipType": "RD53B", "chips": []}
97
+
98
+ for chip_index, chip in enumerate(self.chips):
99
+ if self.module_type == "triplet":
100
+ spec["chips"].append(
101
+ {
102
+ "config": chip.generate_config(
103
+ chip_template,
104
+ outdir,
105
+ chip_index,
106
+ layer_config,
107
+ self.module_type,
108
+ suffix=suffix,
109
+ ),
110
+ "path": "relToCon",
111
+ "tx": 0,
112
+ "rx": [0, 1, 2][chip_index],
113
+ "enable": 1,
114
+ "locked": 0,
115
+ }
116
+ )
117
+ else:
118
+ spec["chips"].append(
119
+ {
120
+ "config": chip.generate_config(
121
+ chip_template,
122
+ outdir,
123
+ chip_index,
124
+ layer_config,
125
+ self.module_type,
126
+ suffix=suffix,
127
+ ),
128
+ "path": "relToCon",
129
+ "tx": 0,
130
+ "rx": [2, 1, 0, 3][chip_index],
131
+ "enable": 1,
132
+ "locked": 0,
133
+ }
134
+ )
135
+
136
+ output_path = Path(outdir, self.name)
137
+ output_path.mkdir(parents=True, exist_ok=True)
138
+ with output_path.joinpath(
139
+ f"{self.name}_{layer_config}{'_'+suffix if suffix else ''}.json"
140
+ ).open("w", encoding="utf-8") as serialized:
141
+ json.dump(spec, serialized, indent=4)
142
+ typer.echo(
143
+ f"INFO: connectivity file saved to {outdir}/{self.name}/{self.name}_{layer_config}{'_'+suffix if suffix else ''}.json"
144
+ )
145
+
146
+
147
+ class Chip:
148
+ """
149
+ Chip class.
150
+ """
151
+
152
+ def __init__(self, client, serial_number, module_name=None):
153
+ self.client = client
154
+ self.serial_number = serial_number
155
+ self.chip_uid = hex(int(serial_number[-7:]))
156
+ self.module_name = module_name or self.serial_number
157
+ self.chip = client.get("getComponent", json={"component": serial_number})
158
+ self.test_run = None
159
+
160
+ typer.echo(f"INFO: chip {self.chip_uid} initiated.")
161
+
162
+ def load_wafer_probing_data(self):
163
+ """
164
+ Load chip wafer probing data.
165
+ """
166
+ test_id = None
167
+ tests = pd.DataFrame(self.chip["tests"])
168
+ if len(tests[tests["code"] == "FECHIP_TEST"]) > 0:
169
+ test_id = tests[tests["code"] == "FECHIP_TEST"]["testRuns"].iloc[-1][-1][
170
+ "id"
171
+ ]
172
+ if not test_id:
173
+ msg = (
174
+ f"No wafer probing data in production DB for chip {self.serial_number}!"
175
+ )
176
+ raise RuntimeError(msg)
177
+ self.test_run = TestRun(self.client, test_id)
178
+
179
+ def generate_config(
180
+ self, chip_template, outdir, chip_index, layer_config, module_type, suffix=""
181
+ ):
182
+ """
183
+ Generate chip config.
184
+ """
185
+ typer.echo(
186
+ f"INFO: generating chip config for chip {self.chip_uid} with {layer_config}"
187
+ )
188
+
189
+ with Path(chip_template).open(encoding="utf-8") as serialized:
190
+ spec = json.load(serialized)
191
+
192
+ power_config = "LP" if suffix == "LP" else layer_config
193
+
194
+ spec["RD53B"]["GlobalConfig"]["DiffPreComp"] = {
195
+ "R0": 350,
196
+ "R0.5": 350,
197
+ "L0": 350,
198
+ "L1": 350,
199
+ "L2": 350,
200
+ "LP": 0,
201
+ }[power_config]
202
+ spec["RD53B"]["GlobalConfig"]["DiffPreampL"] = {
203
+ "R0": 900,
204
+ "R0.5": 900,
205
+ "L0": 900,
206
+ "L1": 730,
207
+ "L2": 550,
208
+ "LP": 0,
209
+ }[power_config]
210
+ spec["RD53B"]["GlobalConfig"]["DiffPreampM"] = {
211
+ "R0": 900,
212
+ "R0.5": 900,
213
+ "L0": 900,
214
+ "L1": 730,
215
+ "L2": 550,
216
+ "LP": 0,
217
+ }[power_config]
218
+ spec["RD53B"]["GlobalConfig"]["DiffPreampR"] = {
219
+ "R0": 900,
220
+ "R0.5": 900,
221
+ "L0": 900,
222
+ "L1": 730,
223
+ "L2": 550,
224
+ "LP": 0,
225
+ }[power_config]
226
+ spec["RD53B"]["GlobalConfig"]["DiffPreampT"] = {
227
+ "R0": 900,
228
+ "R0.5": 900,
229
+ "L0": 900,
230
+ "L1": 730,
231
+ "L2": 550,
232
+ "LP": 0,
233
+ }[power_config]
234
+ spec["RD53B"]["GlobalConfig"]["DiffPreampTL"] = {
235
+ "R0": 900,
236
+ "R0.5": 900,
237
+ "L0": 900,
238
+ "L1": 730,
239
+ "L2": 550,
240
+ "LP": 0,
241
+ }[power_config]
242
+ spec["RD53B"]["GlobalConfig"]["DiffPreampTR"] = {
243
+ "R0": 900,
244
+ "R0.5": 900,
245
+ "L0": 900,
246
+ "L1": 730,
247
+ "L2": 550,
248
+ "LP": 0,
249
+ }[power_config]
250
+ spec["RD53B"]["GlobalConfig"]["DiffVff"] = {
251
+ "R0": 150,
252
+ "R0.5": 150,
253
+ "L0": 150,
254
+ "L1": 150,
255
+ "L2": 60,
256
+ "LP": 0,
257
+ }[power_config]
258
+ spec["RD53B"]["GlobalConfig"]["EnCoreCol0"] = {
259
+ "R0": 65535,
260
+ "R0.5": 65535,
261
+ "L0": 65535,
262
+ "L1": 65535,
263
+ "L2": 65535,
264
+ "LP": 0,
265
+ }[power_config]
266
+ spec["RD53B"]["GlobalConfig"]["EnCoreCol1"] = {
267
+ "R0": 65535,
268
+ "R0.5": 65535,
269
+ "L0": 65535,
270
+ "L1": 65535,
271
+ "L2": 65535,
272
+ "LP": 0,
273
+ }[power_config]
274
+ spec["RD53B"]["GlobalConfig"]["EnCoreCol2"] = {
275
+ "R0": 65535,
276
+ "R0.5": 65535,
277
+ "L0": 65535,
278
+ "L1": 65535,
279
+ "L2": 65535,
280
+ "LP": 0,
281
+ }[power_config]
282
+ spec["RD53B"]["GlobalConfig"]["EnCoreCol3"] = {
283
+ "R0": 63,
284
+ "R0.5": 63,
285
+ "L0": 63,
286
+ "L1": 63,
287
+ "L2": 63,
288
+ "LP": 0,
289
+ }[power_config]
290
+ spec["RD53B"]["Parameter"]["Name"] = self.chip_uid
291
+
292
+ if module_type == "triplet":
293
+ spec["RD53B"]["Parameter"]["ChipId"] = chip_index + 1
294
+ spec["RD53B"]["GlobalConfig"]["AuroraActiveLanes"] = {
295
+ "R0": 7,
296
+ "R0.5": 3,
297
+ "L0": 15,
298
+ }[
299
+ layer_config
300
+ ] ## TODO: add source for R0 and R0.5
301
+ # spec["RD53B"]["GlobalConfig"]["MonitorEnable"] = 0
302
+ # spec["RD53B"]["GlobalConfig"]["MonitorV"] = 63
303
+ for index in range(4):
304
+ spec["RD53B"]["GlobalConfig"][f"DataMergeOutMux{index}"] = (
305
+ 0 + index
306
+ ) % 4
307
+ spec["RD53B"]["GlobalConfig"]["SerEnLane"] = {"R0": 7, "R0.5": 3, "L0": 15}[
308
+ layer_config
309
+ ]
310
+ else:
311
+ spec["RD53B"]["Parameter"]["ChipId"] = 12 + chip_index
312
+ spec["RD53B"]["GlobalConfig"]["AuroraActiveLanes"] = 1
313
+ for index in range(4):
314
+ spec["RD53B"]["GlobalConfig"][f"DataMergeOutMux{index}"] = (
315
+ [2, 0, 1, 0][chip_index] + index
316
+ ) % 4
317
+ spec["RD53B"]["GlobalConfig"]["SerEnLane"] = [4, 1, 8, 1][chip_index]
318
+
319
+ if not self.test_run:
320
+ self.load_wafer_probing_data()
321
+ if self.test_run:
322
+ spec["RD53B"]["GlobalConfig"]["SldoTrimA"] = self.test_run.get_result(
323
+ "VDDA_TRIM"
324
+ )
325
+ spec["RD53B"]["GlobalConfig"]["SldoTrimD"] = self.test_run.get_result(
326
+ "VDDD_TRIM"
327
+ )
328
+ spec["RD53B"]["Parameter"]["ADCcalPar"][0] = (
329
+ self.test_run.get_result("ADC_OFFSET") * 1000
330
+ )
331
+ spec["RD53B"]["Parameter"]["ADCcalPar"][1] = (
332
+ self.test_run.get_result("ADC_SLOPE") * 1000
333
+ )
334
+ spec["RD53B"]["Parameter"]["InjCap"] = self.test_run.get_result(
335
+ "InjectionCapacitance"
336
+ ) * (10**15)
337
+
338
+ # For transistor sensors calibration, the ideality factor is calculated following the presentation:
339
+ # https://indico.cern.ch/event/1011941/contributions/4278988/attachments/2210633/3741190/RD53B_calibatrion_sensor_temperature.pdf
340
+ e_charge = 1.602e-19
341
+ kB = 1.38064852e-23
342
+ PC_NTC = self.test_run.get_result("PC_NTC") + 273
343
+ DeltaT = 2 # 2 degree difference between PC NTC and transistor sensors
344
+ spec["RD53B"]["Parameter"]["NfDSLDO"] = (
345
+ self.test_run.get_result("TEMPERATURE_D")
346
+ * e_charge
347
+ / (kB * math.log(15) * (PC_NTC + DeltaT))
348
+ )
349
+ spec["RD53B"]["Parameter"]["NfASLDO"] = (
350
+ self.test_run.get_result("TEMPERATURE_A")
351
+ * e_charge
352
+ / (kB * math.log(15) * (PC_NTC + DeltaT))
353
+ )
354
+ spec["RD53B"]["Parameter"]["NfACB"] = (
355
+ self.test_run.get_result("TEMPERATURE_C")
356
+ * e_charge
357
+ / (kB * math.log(15) * (PC_NTC + DeltaT))
358
+ )
359
+
360
+ spec["RD53B"]["Parameter"]["VcalPar"] = [
361
+ abs(self.test_run.get_result("VCAL_HIGH_LARGE_RANGE_OFFSET") * 1000),
362
+ self.test_run.get_result("VCAL_HIGH_LARGE_RANGE_SLOPE") * 1000,
363
+ ]
364
+ spec["RD53B"]["Parameter"]["IrefTrim"] = self.test_run.get_result(
365
+ "IREF_TRIM"
366
+ )
367
+ spec["RD53B"]["Parameter"]["KSenseInA"] = self.test_run.get_result(
368
+ "CURR_MULT_FAC_A"
369
+ )
370
+ spec["RD53B"]["Parameter"]["KSenseInD"] = self.test_run.get_result(
371
+ "CURR_MULT_FAC_D"
372
+ )
373
+ spec["RD53B"]["Parameter"]["KSenseShuntA"] = (
374
+ self.test_run.get_result("CURR_MULT_FAC_A") * 26000.0 / 21000.0
375
+ )
376
+ spec["RD53B"]["Parameter"]["KSenseShuntD"] = (
377
+ self.test_run.get_result("CURR_MULT_FAC_D") * 26000.0 / 21000.0
378
+ )
379
+ spec["RD53B"]["Parameter"]["KShuntA"] = self.test_run.get_result(
380
+ "VINA_SHUNT_KFACTOR"
381
+ )
382
+ spec["RD53B"]["Parameter"]["KShuntD"] = self.test_run.get_result(
383
+ "VIND_SHUNT_KFACTOR"
384
+ )
385
+
386
+ output_path = Path(
387
+ outdir, self.module_name, f"{layer_config}{'_'+suffix if suffix else ''}"
388
+ )
389
+ output_path.mkdir(parents=True, exist_ok=True)
390
+ output_file = output_path.joinpath(
391
+ f"{self.chip_uid}_{layer_config}{'_'+suffix if suffix else ''}.json"
392
+ )
393
+ with output_file.open("w", encoding="utf-8") as serialized:
394
+ json.dump(spec, serialized, indent=4)
395
+
396
+ typer.echo(f"INFO: chip config saved to {output_file}")
397
+ return str(Path(*output_file.parts[-2:]))
398
+
399
+
400
+ class TestRun:
401
+ """
402
+ TestRun class.
403
+ """
404
+
405
+ def __init__(self, client, test_run_id):
406
+ self.client = client
407
+ self.identifier = test_run_id
408
+ self.test_run = client.get("getTestRun", json={"testRun": test_run_id})
409
+ self.results = pd.DataFrame(self.test_run["results"])
410
+
411
+ typer.echo(f"INFO: test run {self.identifier} initiated.")
412
+
413
+ def get_result(self, code):
414
+ """
415
+ Get test run result.
416
+ """
417
+ if len(self.results[self.results["code"] == code]) > 0:
418
+ return self.results[self.results["code"] == code]["value"].iloc[-1]
419
+ return None
420
+
421
+
422
+ def get_layer_from_serial_number(serial_number):
423
+ """
424
+ Get the layer from the serial number.
425
+ """
426
+ if len(serial_number) != 14 or not serial_number.startswith("20U"):
427
+ typer.echo("Error: Please enter a valid ATLAS SN.")
428
+ raise typer.Exit(code=1)
429
+
430
+ if "PIMS" in serial_number or "PIR6" in serial_number:
431
+ return "L0"
432
+
433
+ if "PIM0" in serial_number or "PIR7" in serial_number:
434
+ return "R0"
435
+
436
+ if "PIM5" in serial_number or "PIR8" in serial_number:
437
+ return "R0.5"
438
+
439
+ if "PIM1" in serial_number or "PIRB" in serial_number:
440
+ return "L1"
441
+
442
+ if "PG" in serial_number:
443
+ return "L2"
444
+
445
+ typer.echo("Error: invalid module SN.")
446
+ raise typer.Exit(code=1)
447
+
448
+
449
+ if __name__ == "__main__":
450
+ typer.run(main)
@@ -0,0 +1,40 @@
1
+ """
2
+ Top-level entrypoint for the command line interface.
3
+ """
4
+ from __future__ import annotations
5
+
6
+ import typer
7
+
8
+ import module_qc_database_tools
9
+ from module_qc_database_tools.cli.generate_yarr_config import (
10
+ main as generate_yarr_config,
11
+ )
12
+ from module_qc_database_tools.cli.register_component import main as register_component
13
+
14
+ # subcommands
15
+ app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
16
+
17
+
18
+ @app.callback(invoke_without_command=True)
19
+ def main(
20
+ version: bool = typer.Option(False, "--version", help="Print the current version."),
21
+ prefix: bool = typer.Option(
22
+ False, "--prefix", help="Print the path prefix for data files."
23
+ ),
24
+ ) -> None:
25
+ """
26
+ Manage top-level options
27
+ """
28
+ if version:
29
+ typer.echo(f"module-qc-database-tools v{module_qc_database_tools.__version__}")
30
+ raise typer.Exit()
31
+ if prefix:
32
+ typer.echo(module_qc_database_tools.data.resolve())
33
+ raise typer.Exit()
34
+
35
+
36
+ app.command("generate-yarr-config")(generate_yarr_config)
37
+ app.command("register-component")(register_component)
38
+
39
+ # for generating documentation using mkdocs-click
40
+ typer_click_object = typer.main.get_command(app)
@@ -0,0 +1,61 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from pathlib import Path
6
+
7
+ import itkdb
8
+ import typer
9
+
10
+ import module_qc_database_tools
11
+
12
+ app = typer.Typer(context_settings={"help_option_names": ["-h", "--help"]})
13
+
14
+
15
+ @app.command()
16
+ def main(
17
+ serial_number: str = typer.Option(..., "-sn", "--sn", help="ATLAS serialNumber"),
18
+ config_path: Path = typer.Option(
19
+ (module_qc_database_tools.data / "componentConfigs.json").resolve(),
20
+ "-c",
21
+ "--config",
22
+ help="component configs for registering components",
23
+ exists=True,
24
+ file_okay=True,
25
+ readable=True,
26
+ resolve_path=True,
27
+ ),
28
+ component: str = typer.Option(
29
+ ...,
30
+ "-cp",
31
+ "--component",
32
+ help="Component to register",
33
+ ),
34
+ institution: str = typer.Option("", "-i", "--institution", help="Institution"),
35
+ ):
36
+ """
37
+ Main executable for registering components.
38
+ """
39
+ with config_path.open() as fpointer:
40
+ config = json.load(fpointer)[component]
41
+
42
+ institution = institution or os.environ.get("INSTITUTION")
43
+ if not institution:
44
+ msg = "Must specify institution from commandline or set the appropriate environment variable."
45
+ raise ValueError(msg)
46
+
47
+ client = itkdb.Client()
48
+ register_component(client, institution, config, serial_number)
49
+
50
+
51
+ def register_component(client, institution, config, serial_number):
52
+ """
53
+ Register a component in production database using institution, config, and serial number
54
+ """
55
+ config["institution"] = institution
56
+ config["serialNumber"] = serial_number
57
+ client.post("registerComponent", json=config)
58
+
59
+
60
+ if __name__ == "__main__":
61
+ typer.run(main)
@@ -0,0 +1,19 @@
1
+ {
2
+ "RD53B": {
3
+ "GlobalConfig": {
4
+ "AuroraActiveLanes": 1,
5
+ "CmlBias0": 800,
6
+ "CmlBias1": 200,
7
+ "CmlBias2": 0,
8
+ "SerEnTap": 1,
9
+ "SerInvTap": 1,
10
+ "MonitorEnable": 1,
11
+ "MonitorI": 63,
12
+ "MonitorV": 1,
13
+ "ServiceBlockEn": 1
14
+ },
15
+ "Parameter": {
16
+ "ADCcalPar": [5.894350051879883, 0.1920430064201355, 10000.0]
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "quad_PCB_2_4": {
3
+ "project": "P",
4
+ "subproject": "PG",
5
+ "componentType": "PCB",
6
+ "type": "QUAD_PCB",
7
+ "properties": {
8
+ "VERSION_OF_HYBRID_DESIGN": 2.4,
9
+ "FECHIP_VERSION": "2"
10
+ }
11
+ },
12
+ "quad_PCB_1_5": {
13
+ "project": "P",
14
+ "subproject": "PG",
15
+ "componentType": "PCB",
16
+ "type": "QUAD_PCB",
17
+ "properties": {
18
+ "VERSION_OF_HYBRID_DESIGN": 1.5,
19
+ "FECHIP_VERSION": "2"
20
+ }
21
+ },
22
+ "digital_quad_bare_module": {
23
+ "project": "P",
24
+ "subproject": "PG",
25
+ "componentType": "BARE_MODULE",
26
+ "type": "DIGITAL_QUAD_BARE_MODULE",
27
+ "properties": {
28
+ "FECHIP_VERSION": "2",
29
+ "SENSOR_TYPE": "0",
30
+ "THICKNESS": "1",
31
+ "VENDOR": "1"
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.1
2
+ Name: module-qc-database-tools
3
+ Version: 0.0.1
4
+ Summary: Python wrapper to interface with LocalDB and Production DB for common tasks for pixel modules.
5
+ Project-URL: Homepage, https://gitlab.cern.ch/atlas-itk/pixel/module/module-qc-database-tools
6
+ Project-URL: Bug Tracker, https://gitlab.cern.ch/atlas-itk/pixel/module/module-qc-database-tools/issues
7
+ Project-URL: Source, https://gitlab.cern.ch/atlas-itk/pixel/module/module-qc-database-tools
8
+ Author-email: Jay Chan <jay.chan@cern.ch>
9
+ Maintainer-email: Giordon Stark <kratsg@gmail.com>, Elisabetta Pianori <elisabetta.pianori@cern.ch>, Lingxin Meng <lingxin.meng@cern.ch>
10
+ Classifier: Development Status :: 1 - Planning
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: BSD License
14
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.7
20
+ Classifier: Programming Language :: Python :: 3.8
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Topic :: Scientific/Engineering
25
+ Requires-Python: >=3.7
26
+ Requires-Dist: importlib-resources>=1.4.0; python_version < '3.9'
27
+ Requires-Dist: itkdb>=0.4.0
28
+ Requires-Dist: pandas
29
+ Requires-Dist: typer
30
+ Description-Content-Type: text/markdown
31
+
32
+ # Module QC Database Tools v0.0.1
33
+
34
+ The package to regisiter ITkPixV1.1 modules, and generate YARR configs from ITk
35
+ production database using `itkdb` API.
36
+
37
+ ## Set-Up and First-time Installation
38
+
39
+ A minimum of python version 3.7+ is required.
40
+
41
+ ### Virtual Python Environment
42
+
43
+ Creating the python virtual environment the standard way used the python version
44
+ available on the operating system. For CentOS 7 this is version 3.6. If using
45
+ CentOS 7, you can install python 3.8 following these
46
+ [instructions](https://tecadmin.net/install-python-3-8-centos/).
47
+
48
+ After installing python 3.8, create the virtual environment:
49
+
50
+ ```
51
+ $ python3 -m venv venv
52
+ $ source venv/bin/activate
53
+ ```
54
+
55
+ For future use:
56
+
57
+ ```
58
+ $ source venv/bin/activate
59
+ ```
60
+
61
+ Alternatively, [anaconda](https://docs.anaconda.com/anaconda/install/index.html)
62
+ or [miniconda](https://docs.conda.io/en/latest/miniconda.html) can also be
63
+ installed.
64
+
65
+ For future use:
66
+
67
+ ```
68
+ $ conda activate
69
+ ```
70
+
71
+ ### Install
72
+
73
+ ```
74
+ $ python -m pip install module-qc-database-tools
75
+ ```
76
+
77
+ ### Environment Variables
78
+
79
+ If not already set elsewhere (e.g. `~/.bashrc`), copy `.env.template` to `.env`
80
+ and update the values of the shell variables. Essentially, the following
81
+ variables regarding the production database should be available, shown below as
82
+ an example of environmental variables in `~/.bashrc`:
83
+
84
+ ```bash
85
+ export INSTITUTION="LBNL_PIXEL_MODULES"
86
+ export ITKDB_ACCESS_CODE1="accesscode1"
87
+ export ITKDB_ACCESS_CODE2="accesscode2"
88
+ ```
89
+
90
+ ## Module registration
91
+
92
+ Under construction...
93
+
94
+ ## Generate YARR configuration
95
+
96
+ This script has been tested on python 3.7+.
97
+
98
+ To generate YARR configuration for a given module, run `generateYARRConfig` or
99
+ `mqdbt generate-yarr-config`:
100
+
101
+ ```
102
+ $ generateYARRConfig -sn [ATLAS SN] -o [outdir]
103
+ $ mqdbt generate-yarr-config -sn [ATLAS SN] -o [outdir]
104
+
105
+ Parameters:
106
+ -sn, --sn, required=True: ATLAS serial number of the module
107
+ -ch, --chipTemplate, default="configs/YARR/chip_template.json": provide the path of a chip config template to generate the new chip configs from
108
+ -o, --outdir, required=True: Path to output directory config folder will be placed in
109
+ ```
110
+
111
+ For example, to generate the YARR configs for the module `20UPGR91301046` with
112
+ all power configs:
113
+
114
+ ```
115
+ $ generateYARRConfig -sn 20UPGR91301046 -o ~/module_data/.
116
+ $ mqdbt generate-yarr-config -sn 20UPGR91301046 -o ~/module_data/.
117
+ ```
118
+
119
+ The time needed to generate warm and cold L2 configs for a quad module is about
120
+ 4 seconds.
@@ -0,0 +1,13 @@
1
+ module_qc_database_tools/__init__.py,sha256=Ug7pRtlzlDzQFNexHqET-BnZxOh4qbIHdOoDE0CvjqA,319
2
+ module_qc_database_tools/_version.py,sha256=0E2q3bbXSYHV7qQaXVj0To-J2XdlP2Roo0TsM8oQtR4,160
3
+ module_qc_database_tools/cli/__init__.py,sha256=1W6Ei7U8ZHuCUe_qNkzr7-no5RJHBhVGGr0XzMCNkEs,144
4
+ module_qc_database_tools/cli/__main__.py,sha256=FMkuLcxfugwbVz6KD0R0DEUamhpgCJCAsD_CbadKltI,93
5
+ module_qc_database_tools/cli/generate_yarr_config.py,sha256=bQjkAozFNIOXL4dRyfcqD9drSkeV7Iv0CQt71rrBADI,15476
6
+ module_qc_database_tools/cli/main.py,sha256=aZR8tHF7qZk6T5oaX6bTlRm6rCn0wrPLCm_to3JTQW0,1180
7
+ module_qc_database_tools/cli/register_component.py,sha256=QDROimbJafcIAFRcjTkYZzU8_qZA1ynPuUqFfiNDVx4,1694
8
+ module_qc_database_tools/data/componentConfigs.json,sha256=6XWYBjrT5It7CM0IA_6tYTB4mDXFSph5ncwgsvvYYlE,713
9
+ module_qc_database_tools/data/YARR/chip_template.json,sha256=CysMQxQYav_kKzhDt--tbpuWW5JKNLCK-WRhXuZDPv4,378
10
+ module_qc_database_tools-0.0.1.dist-info/METADATA,sha256=XpqqEtQXDiEhslCE4rckFV1td5RgB_GYPrwcLV5UXfI,4032
11
+ module_qc_database_tools-0.0.1.dist-info/WHEEL,sha256=EI2JsGydwUL5GP9t6kzZv7G3HDPi7FuZDDf9In6amRM,87
12
+ module_qc_database_tools-0.0.1.dist-info/entry_points.txt,sha256=VYCepcugT-1ZbTRVDGXyF59PTTGKYEIYLpSv6rmlw6Q,266
13
+ module_qc_database_tools-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.14.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ generateYARRConfig = module_qc_database_tools.cli.generate_yarr_config:app
3
+ module-qc-database-tools = module_qc_database_tools.cli:app
4
+ mqdbt = module_qc_database_tools.cli:app
5
+ registerComponent = module_qc_database_tools.cli.register_component:app