Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-25 08:29:11

0001 """
0002 Tag parameter schemas — required and optional fields per tag type.
0003 
0004 Extensible without migration: add fields here and they appear in forms and validation.
0005 The 'required' list is enforced on tag creation. The 'optional' list populates form fields.
0006 All values are stored as JSON in the tag's parameters field.
0007 
0008 Processes and choices assembled from 26.02.0 campaign production pages:
0009   https://eic.github.io/epic-prod/FULL/26.02.0/
0010   https://eic.github.io/epic-prod/RECO/26.02.0/
0011 """
0012 
0013 TAG_SCHEMAS = {
0014     'p': {
0015         'required': ['process', 'beam_energy_electron', 'beam_energy_hadron'],
0016         'optional': [
0017             'beam_species', 'q2_range',
0018             'decay_mode', 'hadron_charge', 'coherence', 'model', 'polarization',
0019             'notes',
0020         ],
0021         'label': 'Physics',
0022         'prefix': 'p',
0023         'model': 'PhysicsTag',
0024         'choices': {
0025             'process': [
0026                 'DIS_NC', 'DIS_CC', 'DDIS',
0027                 'DVCS', 'DDVCS',
0028                 'SIDIS_D0',
0029                 'DEMP', 'DVMP',
0030                 'DIFFRACTIVE_JPSI', 'DIFFRACTIVE_PHI', 'DIFFRACTIVE_RHO',
0031                 'PHOTOPRODUCTION_JPSI', 'UPSILON',
0032             ],
0033             'beam_energy_electron': ['5', '10', '18', 'N/A'],
0034             'beam_energy_hadron': ['41', '100', '110', '130', '250', '275', 'N/A'],
0035             'beam_species': ['ep', 'eHe3', 'eAu'],
0036             'q2_range': [
0037                 'minQ2=1', 'minQ2=10', 'minQ2=100', 'minQ2=1000',
0038                 'q2_0_10', 'q2_1_100', 'q2_1_1000',
0039                 'q2_1to10', 'q2_1to50', 'q2_1to10000',
0040                 'q2_2to10', 'q2_10to100', 'q2_100to10000',
0041                 'q2_nocut',
0042             ],
0043             'decay_mode': ['edecay', 'mudecay'],
0044             'hadron_charge': ['hplus', 'hminus'],
0045             'coherence': ['coherent'],
0046             'model': ['bsat', 'hiAcc', 'hiDiv'],
0047             'polarization': ['unpolarised'],
0048         },
0049     },
0050     'e': {
0051         'required': ['generator', 'generator_version'],
0052         'optional': [
0053             'signal_freq', 'signal_status',
0054             'bg_tag_prefix', 'bg_files',
0055             'notes',
0056         ],
0057         'label': 'EvGen',
0058         'prefix': 'e',
0059         'model': 'EvgenTag',
0060         'choices': {
0061             'generator': [
0062                 'pythia8', 'EpIC', 'BeAGLE', 'eSTARlight', 'sartre',
0063                 'DEMPgen', 'lAger', 'rapgap', 'particle_gun',
0064             ],
0065             'generator_version': [
0066                 '8.310', '8.306-1.0', '8.306-1.1',
0067                 'v1.1.6-1.2', '1.1.6-1.0',
0068                 '1.03.02-1.2', '1.03.02-2.0', '1.03.02-1.1',
0069                 '1.3.0-1.0', '1.39-1.1', '1.2.4',
0070                 '3.6.1-1.0', '3.310-1.0',
0071             ],
0072             'bg_tag_prefix': [
0073                 'Bkg_Exact1S_2us/GoldCt/5um',
0074                 'Bkg_Exact1S_2us/GoldCt/10um',
0075             ],
0076         },
0077     },
0078     's': {
0079         'required': ['detector_sim', 'sim_version'],
0080         'optional': ['background_config', 'digitization', 'notes'],
0081         'label': 'Simulation',
0082         'prefix': 's',
0083         'model': 'SimuTag',
0084         'choices': {
0085             'detector_sim': ['npsim'],
0086             'sim_version': ['26.02.0'],
0087             'background_config': [
0088                 'none',
0089                 'Bkg_Exact1S_2us/GoldCt/5um',
0090                 'Bkg_Exact1S_2us/GoldCt/10um',
0091             ],
0092         },
0093     },
0094     'r': {
0095         'required': ['reco_version', 'reco_config'],
0096         'optional': ['calibration_tag', 'alignment_tag', 'notes'],
0097         'label': 'Reconstruction',
0098         'prefix': 'r',
0099         'model': 'RecoTag',
0100         'choices': {
0101             'reco_version': ['26.02.0'],
0102             'reco_config': ['standard'],
0103         },
0104     },
0105 }
0106 
0107 
0108 def get_tag_model(tag_type):
0109     from . import models
0110     return getattr(models, TAG_SCHEMAS[tag_type]['model'])
0111 
0112 
0113 def _schema_to_param_defs(tag_type):
0114     schema = TAG_SCHEMAS[tag_type]
0115     choices = schema.get('choices', {})
0116     defs = []
0117     for i, name in enumerate(schema['required']):
0118         defs.append({
0119             'name': name,
0120             'type': 'string',
0121             'required': True,
0122             'choices': choices.get(name, []),
0123             'allow_other': True,
0124             'sort_order': i,
0125         })
0126     offset = len(schema['required'])
0127     for i, name in enumerate(schema['optional']):
0128         defs.append({
0129             'name': name,
0130             'type': 'string',
0131             'required': False,
0132             'choices': choices.get(name, []),
0133             'allow_other': True,
0134             'sort_order': offset + i,
0135         })
0136     return defs
0137 
0138 
0139 def _state_key(tag_type):
0140     return f'pcs_param_defs_{tag_type}'
0141 
0142 
0143 def get_param_defs(tag_type):
0144     from monitor_app.models import PersistentState
0145     key = _state_key(tag_type)
0146     try:
0147         ps = PersistentState.objects.get(id=1)
0148         defs = ps.state_data.get(key)
0149         if defs is not None:
0150             return defs
0151     except PersistentState.DoesNotExist:
0152         pass
0153     return seed_param_defs(tag_type)
0154 
0155 
0156 def seed_param_defs(tag_type):
0157     from monitor_app.models import PersistentState
0158     defs = _schema_to_param_defs(tag_type)
0159     ps, _ = PersistentState.objects.get_or_create(id=1, defaults={'state_data': {}})
0160     ps.state_data[_state_key(tag_type)] = defs
0161     ps.save(update_fields=['state_data', 'updated_at'])
0162     return defs
0163 
0164 
0165 def save_param_defs(tag_type, defs):
0166     from monitor_app.models import PersistentState
0167     ps, _ = PersistentState.objects.get_or_create(id=1, defaults={'state_data': {}})
0168     ps.state_data[_state_key(tag_type)] = defs
0169     ps.save(update_fields=['state_data', 'updated_at'])
0170 
0171 
0172 def validate_parameters(tag_type, parameters):
0173     defs = get_param_defs(tag_type)
0174     required = [d['name'] for d in defs if d.get('required')]
0175     missing = [f for f in required if f not in parameters or not parameters[f]]
0176     if missing:
0177         return False, f"Missing required parameters: {', '.join(missing)}"
0178     return True, None