Skip to content

Commit f515866

Browse files
committed
Merge remote-tracking branch 'origin/main' into 2026-run-prep
2 parents f53ad0e + f33166b commit f515866

8 files changed

Lines changed: 139 additions & 114 deletions

File tree

docs/_sidebar.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323

2424
**Advanced**:
2525
- [Development guide](development/development.md)
26-
- [Database selector](development/database-selector.md)
2726
- [Migrate to RCDB2](development/rcdb2-migration.md)
2827
- [DAQ Setup](daq/daq.md)
29-
- [Website](web_site_setup.md)
28+
- [Website install](website/install.md)
29+
- [Muli-Database](website/database-selector.md)
3030

3131

3232

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ The RCDB web interface supports switching between multiple databases from the br
44
When configured, a dropdown selector appears in the navbar allowing users to pick a database.
55
The selection is saved in a cookie and persists across sessions.
66

7-
## How It Works
7+
### How It Works
88

99
- The Flask app has two config keys: `AVAILABLE_DATABASES` (a dict of `name -> connection_string`)
1010
and `DEFAULT_DATABASE` (the connection string to use when no cookie is set).
@@ -14,9 +14,8 @@ The selection is saved in a cookie and persists across sessions.
1414
is not in the available list, it logs a warning and uses the first entry.
1515
- When `AVAILABLE_DATABASES` is empty (the default), all behavior is identical to a single-database setup.
1616

17-
## Configuration
1817

19-
### CLI (`rcdb web`)
18+
## CLI (`rcdb web`)
2019

2120
Use the `--add-db` flag (repeatable) to register named databases:
2221

@@ -30,6 +29,9 @@ rcdb -c mysql+pymysql://rcdb@prodhost/rcdb web \
3029
- The `-c` / `--connection` / `RCDB_CONNECTION` value becomes the default database.
3130
- If no `-c` is provided, the first `--add-db` entry is used as the default.
3231

32+
33+
## Server Configuration
34+
3335
### WSGI
3436

3537
Set the config keys directly in the WSGI script:

docs/website/index.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Website
2+
3+
[install.md](install.md ':include')
4+
5+
[database-selector.md](database-selector.md ':include')
Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
# Installing RCDB Website
1+
# Install on server
22

33
Instruction on how to install central RCDB website.
44

5-
We use RHEL9 + Apache Server + mod_wsgi as the example, as this is what usually is used at Jefferson Lab (now is 2025).
5+
RHEL9 + Apache Server + mod_wsgi is used as the example,
6+
as this is what usually is used at Jefferson Lab (now is 2025).
67

8+
***Notes:***
9+
10+
- The RCDB web interface requires the proper database schema to be installed
11+
- For production use, consider setting up HTTPS with SSL certificates
12+
- Consider adjusting the number of threads in the WSGIDaemonProcess directive based on your server's capacity and expected load
13+
14+
15+
### Preinstalled docker image
716
There is [a dockerfile with example Rocky Linux 9](https://github.com/JeffersonLab/rcdb/tree/main/docker/rocky)
817
(binary compatible with RHEL9) setup with config files. To build and run it:
918

@@ -17,15 +26,16 @@ docker run --rm -it --init -p 8888:80 rcdb-rocky:latest
1726
http://localhost:8888/rcdb/
1827
```
1928

20-
2129
- RHEL9 (or compatible) server with Apache HTTP Server installed
2230
- Root access or sudo privileges
2331
- Python 3.9+ (default on RHEL9)
2432
- `mod_wsgi` package for Apache
2533

26-
## Install Required Packages
34+
## Requirements
2735

28-
First, install the necessary packages:
36+
### System Packages
37+
38+
Required system packages:
2939

3040
```bash
3141
# Install Apache and mod_wsgi
@@ -35,7 +45,7 @@ sudo dnf install httpd python3-mod_wsgi python3-pip python3-devel
3545
sudo systemctl enable --now httpd
3646
```
3747

38-
There are two ways of managing rcdb and dependencies:
48+
There are two ways of managing python rcdb and dependencies:
3949

4050
- Install centrally on the server e.g. via RPM
4151
- Install venv and use mod_wsgi with python and packages from venv
@@ -68,11 +78,11 @@ dnf install -y \
6878
```
6979

7080

71-
## Install RCDB Library
81+
### Python dependencies
7282

7383
You have two options for installing the RCDB library:
7484

75-
### Option A: System-wide Installation
85+
#### Option A: System-wide Installation
7686

7787
```bash
7888
git clone --depth=1 https://github.com/JeffersonLab/rcdb.git /opt/rcdb
@@ -93,9 +103,9 @@ pip install rcdb
93103
deactivate
94104
```
95105

96-
## 3. Create the WSGI Script
106+
## WSGI Script
97107

98-
Create a WSGI script at `/group/halld/www/halldwebdev/html/rcdb/rcdb_www.wsgi`:
108+
Example HallD WSGI script is at `/group/halld/www/halldwebdev/html/rcdb/rcdb_www.wsgi`:
99109

100110
If RCDB is installed as a system-wide library:
101111

@@ -131,7 +141,7 @@ rcdb.web.app.config["SQL_CONNECTION_STRING"] = "mysql://rcdb@hallddb.jlab.org/rc
131141
application = rcdb.web.app
132142
```
133143

134-
## 4. Configure Apache
144+
## Apache Configuration
135145

136146
Create an Apache configuration file at `/etc/httpd/conf.d/rcdb.conf`:
137147

@@ -164,16 +174,10 @@ Create an Apache configuration file at `/etc/httpd/conf.d/rcdb.conf`:
164174
```
165175

166176

167-
## 5. Restart Apache
177+
**Restart Apache**
168178

169179
```bash
170180
sudo systemctl restart httpd
171181
```
172182

173-
## Additional Notes
174-
175-
- The RCDB web interface requires the proper database schema to be installed
176-
- For production use, consider setting up HTTPS with SSL certificates
177-
- Consider adjusting the number of threads in the WSGIDaemonProcess directive based on your server's capacity and expected load
178-
179183
Now your RCDB web interface should be up and running on your RHEL9 Apache server!
File renamed without changes.

python/halld_rcdb/roc_config_finder.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ def find_roc_configuration_files(parse_result):
134134
if parse_result.fcal_fadc250_files_info:
135135
infos.append(HallDFilesGrabInfo('fcal', parse_result.fcal_fadc250_files_info))
136136

137+
if parse_result.ecal_fadc250_files_info:
138+
infos.append(HallDFilesGrabInfo('ecal', parse_result.ecal_fadc250_files_info))
139+
137140
if parse_result.bcal_fadc250_files_info:
138141
infos.append(HallDFilesGrabInfo('bcal', parse_result.bcal_fadc250_files_info))
139142

python/halld_rcdb/run_config_parser.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
# Setup logger
99
log = logging.getLogger('rcdb.halld.main_config_parser') # create run configuration standard logger
1010

11-
section_names = ["TRIGGER", "GLOBAL", "FCAL", "BCAL", "TOF", "ST", "TAGH", "TAGM", "PS",
11+
section_names = ["TRIGGER", "GLOBAL", "FCAL", "ECAL", "BCAL", "TOF", "ST", "TAGH", "TAGM", "PS",
1212
"PSC", "TPOL", "CDC", "FDC", "DIRC", "CCAL"]
1313

1414

@@ -27,12 +27,15 @@ def __init__(self, config_parse_result):
2727
self.trigger_buffer_level = None # --type int --description "BUFFERLEVEL from TRIGGER section"
2828
self.fcal_fadc250_mode = None # FADC250_MODE from FCAL run config section
2929
self.fcal_fadc250_params = None # some FADC250_* parameters from FCAL section of run config
30+
self.ecal_fadc250_mode = None # FADC250_MODE from ECAL run config section
31+
self.ecal_fadc250_params = None # some FADC250_* parameters from ECAL section of run config
3032
self.bcal_fadc250_mode = None # int FADC250_MODE from BCAL run config section
3133
self.bcal_fadc250_params = None # some FADC250_* parameters from BCAL section of run config
3234
self.cdc_fadc125_mode = -1
3335
self.cdc_fadc125_params = None # some FADC125_* parameters from CDC section of run config
3436

3537
self.fcal_fadc250_files_info = (None, None, None, None)
38+
self.ecal_fadc250_files_info = (None, None, None, None)
3639
self.bcal_fadc250_files_info = (None, None, None, None)
3740
self.tof_fadc250_files_info = (None, None, None, None)
3841
self.tagh_fadc250_files_info = (None, None, None, None)
@@ -85,6 +88,7 @@ def _process_parse_result(parse_result, file_name=""):
8588

8689
# setting COM_DIR, COM_VER, USER_DIR, USER_VER parameters for subsystems
8790
result.fcal_fadc250_files_info = _fill_com_user_dir_ver(parse_result, 'FCAL')
91+
result.ecal_fadc250_files_info = _fill_com_user_dir_ver(parse_result, 'ECAL')
8892
result.bcal_fadc250_files_info = _fill_com_user_dir_ver(parse_result, 'BCAL')
8993
result.tof_fadc250_files_info = _fill_com_user_dir_ver(parse_result, 'TOF')
9094
result.tagh_fadc250_files_info = _fill_com_user_dir_ver(parse_result, 'TAGH')

python/rcdb/alias.py

Lines changed: 97 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,97 @@
1-
class ConditionSearchAlias(object):
2-
def __init__(self, name, expression, comment):
3-
self.name = name
4-
self.expression = expression
5-
self.comment = comment
6-
7-
8-
default_aliases = [
9-
ConditionSearchAlias('is_production', """run_type in ['hd_all.tsg', 'hd_all.tsg_ps', 'hd_all.bcal_fcal_st.tsg'] and
10-
beam_current and beam_current > 2 and
11-
event_count > 500000 and
12-
solenoid_current and solenoid_current > 100 and
13-
collimator_diameter != 'Blocking'""",
14-
"Is production run"),
15-
16-
ConditionSearchAlias('is_2018production', """daq_run == 'PHYSICS' and
17-
beam_current > 2 and
18-
event_count > 10000000 and
19-
solenoid_current > 100 and
20-
collimator_diameter != 'Blocking'""",
21-
"Is production run"),
22-
23-
ConditionSearchAlias('is_primex_production', """daq_run == 'PHYSICS_PRIMEX' and
24-
event_count > 1000000 and
25-
collimator_diameter != 'Blocking'""",
26-
"Is PrimEx production run"),
27-
28-
ConditionSearchAlias('is_dirc_production', """daq_run == 'PHYSICS_DIRC' and
29-
beam_current > 2 and
30-
event_count > 5000000 and
31-
solenoid_current > 100 and
32-
collimator_diameter != 'Blocking'""",
33-
"Is DIRC production run"),
34-
35-
ConditionSearchAlias('is_src_production', """daq_run == 'PHYSICS_SRC' and
36-
beam_current > 2 and
37-
event_count > 5000000 and
38-
solenoid_current > 100 and
39-
collimator_diameter != 'Blocking'""",
40-
"Is SRC production run"),
41-
42-
ConditionSearchAlias('is_cpp_production', """daq_run == 'PHYSICS_CPP' and
43-
beam_current > 2 and
44-
event_count > 5000000 and
45-
solenoid_current > 100 and
46-
collimator_diameter != 'Blocking'""",
47-
"Is CPP production run"),
48-
49-
ConditionSearchAlias('is_production_long', """daq_run == 'PHYSICS_raw'
50-
beam_current > 2 and
51-
event_count > 5000000 and
52-
solenoid_current > 100 and
53-
collimator_diameter != 'Blocking'""",
54-
"Is production run with long mode data"),
55-
56-
ConditionSearchAlias('is_cosmic', '"cosmic" in run_config and beam_current < 1 and event_count > 5000',
57-
"Is cosmic run"),
58-
59-
ConditionSearchAlias('is_empty_target', "target_type == 'EMPTY & Ready'", "Target is empty"),
60-
61-
# These should be true starting in 2017. Need to check to make sure that 2016 data is accurate...
62-
ConditionSearchAlias('is_amorph_radiator', "polarization_angle < 0.", "Amorphous Radiator"),
63-
ConditionSearchAlias('is_coherent_beam', "polarization_angle >= 0.", "Coherent Beam"),
64-
#ConditionSearchAlias('is_amorph_radiator', "radiator_index == -1 and radiator_type != 'None' and target_type == 'FULL & Ready'",
65-
# "Amorphous Radiator"),
66-
#ConditionSearchAlias('is_coherent_beam', "(radiator_id != 5 and radiator_id > 0) and target_type == 'FULL & Ready'", "Coherent Beam"),
67-
68-
ConditionSearchAlias('is_field_off', "solenoid_current < 100", " Field Off"),
69-
70-
ConditionSearchAlias('is_field_on', "solenoid_current >= 100", " Field On"),
71-
72-
ConditionSearchAlias('status_calibration', "status == 3", "Run status = calibration"),
73-
74-
ConditionSearchAlias('status_approved_long', "status == 2", "Run status = approved (long)"),
75-
76-
ConditionSearchAlias('status_approved', "status == 1", "Run status = approved"),
77-
78-
ConditionSearchAlias('status_unchecked', "status == -1", "Run status = unchecked"),
79-
80-
ConditionSearchAlias('status_reject', " status == 0", "Run status = reject"),
81-
]
82-
83-
_def_al_by_name = None
84-
85-
86-
def get_default_aliases_by_name():
87-
global _def_al_by_name
88-
if _def_al_by_name is None:
89-
_def_al_by_name = {al.name:al for al in default_aliases }
90-
return _def_al_by_name
1+
class ConditionSearchAlias(object):
2+
def __init__(self, name, expression, comment):
3+
self.name = name
4+
self.expression = expression
5+
self.comment = comment
6+
7+
8+
default_aliases = [
9+
ConditionSearchAlias('is_production', """run_type in ['hd_all.tsg', 'hd_all.tsg_ps', 'hd_all.bcal_fcal_st.tsg'] and
10+
beam_current and beam_current > 2 and
11+
event_count > 500000 and
12+
solenoid_current and solenoid_current > 100 and
13+
collimator_diameter != 'Blocking'""",
14+
"Is production run"),
15+
16+
ConditionSearchAlias('is_2018production', """daq_run == 'PHYSICS' and
17+
beam_current > 2 and
18+
event_count > 10000000 and
19+
solenoid_current > 100 and
20+
collimator_diameter != 'Blocking'""",
21+
"Is production run"),
22+
23+
ConditionSearchAlias('is_primex_production', """daq_run == 'PHYSICS_PRIMEX' and
24+
event_count > 1000000 and
25+
collimator_diameter != 'Blocking'""",
26+
"Is PrimEx production run"),
27+
28+
ConditionSearchAlias('is_dirc_production', """daq_run == 'PHYSICS_DIRC' and
29+
beam_current > 2 and
30+
event_count > 5000000 and
31+
solenoid_current > 100 and
32+
collimator_diameter != 'Blocking'""",
33+
"Is DIRC production run"),
34+
35+
ConditionSearchAlias('is_dirctrd_production', """(daq_run == 'PHYSICS_DIRC' or daq_run == 'PHYSICS_DIRC_TRD') and
36+
beam_current > 2 and
37+
event_count > 5000000 and
38+
solenoid_current > 100 and
39+
collimator_diameter != 'Blocking'""",
40+
"Is DIRC/TRD production run"),
41+
42+
ConditionSearchAlias('is_src_production', """daq_run == 'PHYSICS_SRC' and
43+
beam_current > 2 and
44+
event_count > 5000000 and
45+
solenoid_current > 100 and
46+
collimator_diameter != 'Blocking'""",
47+
"Is SRC production run"),
48+
49+
ConditionSearchAlias('is_cpp_production', """daq_run == 'PHYSICS_CPP' and
50+
beam_current > 2 and
51+
event_count > 5000000 and
52+
solenoid_current > 100 and
53+
collimator_diameter != 'Blocking'""",
54+
"Is CPP production run"),
55+
56+
ConditionSearchAlias('is_production_long', """daq_run == 'PHYSICS_raw'
57+
beam_current > 2 and
58+
event_count > 5000000 and
59+
solenoid_current > 100 and
60+
collimator_diameter != 'Blocking'""",
61+
"Is production run with long mode data"),
62+
63+
ConditionSearchAlias('is_cosmic', '"cosmic" in run_config and beam_current < 1 and event_count > 5000',
64+
"Is cosmic run"),
65+
66+
ConditionSearchAlias('is_empty_target', "target_type == 'EMPTY & Ready'", "Target is empty"),
67+
68+
# These should be true starting in 2017. Need to check to make sure that 2016 data is accurate...
69+
ConditionSearchAlias('is_amorph_radiator', "polarization_angle < 0.", "Amorphous Radiator"),
70+
ConditionSearchAlias('is_coherent_beam', "polarization_angle >= 0.", "Coherent Beam"),
71+
#ConditionSearchAlias('is_amorph_radiator', "radiator_index == -1 and radiator_type != 'None' and target_type == 'FULL & Ready'",
72+
# "Amorphous Radiator"),
73+
#ConditionSearchAlias('is_coherent_beam', "(radiator_id != 5 and radiator_id > 0) and target_type == 'FULL & Ready'", "Coherent Beam"),
74+
75+
ConditionSearchAlias('is_field_off', "solenoid_current < 100", " Field Off"),
76+
77+
ConditionSearchAlias('is_field_on', "solenoid_current >= 100", " Field On"),
78+
79+
ConditionSearchAlias('status_calibration', "status == 3", "Run status = calibration"),
80+
81+
ConditionSearchAlias('status_approved_long', "status == 2", "Run status = approved (long)"),
82+
83+
ConditionSearchAlias('status_approved', "status == 1", "Run status = approved"),
84+
85+
ConditionSearchAlias('status_unchecked', "status == -1", "Run status = unchecked"),
86+
87+
ConditionSearchAlias('status_reject', " status == 0", "Run status = reject"),
88+
]
89+
90+
_def_al_by_name = None
91+
92+
93+
def get_default_aliases_by_name():
94+
global _def_al_by_name
95+
if _def_al_by_name is None:
96+
_def_al_by_name = {al.name:al for al in default_aliases }
97+
return _def_al_by_name

0 commit comments

Comments
 (0)