diff --git a/docs/source/_static/_logo/pyaml-logo.svg b/docs/source/_static/_logo/pyaml-logo.svg index bf5ac623a..783e705af 100644 --- a/docs/source/_static/_logo/pyaml-logo.svg +++ b/docs/source/_static/_logo/pyaml-logo.svg @@ -33,8 +33,8 @@ inkscape:cy="306.36035" inkscape:window-width="1746" inkscape:window-height="1229" - inkscape:window-x="2377" - inkscape:window-y="152" + inkscape:window-x="798" + inkscape:window-y="124" inkscape:window-maximized="0" inkscape:current-layer="layer1" showguides="false" />pyAMLpyAML logo str: # Main code sr = Accelerator.from_dict(acc_config) -tm1 = sr.live.get_betatron_tune_monitor("MY_TUNE_MONITOR") +tm1 = sr.live.diagnostic.get("MY_TUNE_MONITOR") print(tm1.tune.get()) print(tm1.frequency.get()) diff --git a/examples/use_cases/01-tune_correction.ipynb b/examples/use_cases/01-tune_correction.ipynb index dfba75bb0..4e20ff1f9 100644 --- a/examples/use_cases/01-tune_correction.ipynb +++ b/examples/use_cases/01-tune_correction.ipynb @@ -207,7 +207,7 @@ } ], "source": [ - "tune_monitor = SR.get_betatron_tune_monitor(\"BETATRON_TUNE\")\n", + "tune_monitor = SR.diagnostic.get(\"BETATRON_TUNE\")\n", "print(f\"Current tune: {tune_monitor.tune.get()}\")\n", "tune_monitor # string representation" ] @@ -282,83 +282,15 @@ "cell_type": "markdown", "id": "04431246", "metadata": {}, - "source": [ - "### Standard tune correction tool\n", - "\n", - "`SR.tune` is the `DEFAULT_TUNE_CORRECTION` tool. `SR.trm` is the `DEFAULT_TUNE_RESPONSE_MATRIX` tool.\n", - "\n", - "Before correcting the tune you need a response matrix. It can be measured (below) or loaded from a previously saved file." - ] + "source": "### Standard tune correction tool\n\n`SR.tool.tune` is the `DEFAULT_TUNE_CORRECTION` tool. `SR.tool.trm` is the `DEFAULT_TUNE_RESPONSE_MATRIX` tool.\n\nBefore correcting the tune you need a response matrix. It can be measured (below) or loaded from a previously saved file." }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "5c57ef30", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Tune(quad_array_name='QForTune', betatron_tune_name='BETATRON_TUNE', response_matrix=array([[ 0.17853128, 0.17890919, 0.17917984, 0.17843061, 0.17932054,\n", - " 0.17884878, 0.1786898 , 0.17950221, 0.17836418, 0.1790288 ,\n", - " 0.17907229, 0.17845344, 0.17936885, 0.1787317 , 0.17880339,\n", - " 0.1793422 , 0.17843576, 0.17914062, 0.17895506, 0.17850485,\n", - " 0.15843663, 0.1575313 , 0.15237977, 0.15250702, 0.17830408,\n", - " 0.17955648, 0.1784584 , 0.17880469, 0.17936621, 0.17824945,\n", - " 0.17941811, 0.17905372, 0.17841113, 0.17957284, 0.17835113,\n", - " 0.17897118, 0.17923226, 0.17825399, 0.17950825, 0.17876573,\n", - " 0.17866201, 0.17954684, 0.17827911, 0.17925585, 0.17897151,\n", - " 0.17830041, 0.17956082, 0.17873061, 0.17871689, 0.17948152,\n", - " 0.15577439, 0.15662709, 0.178933 , 0.17847488, 0.17937198,\n", - " 0.17881763, 0.17874021, 0.17931638, 0.17843723, 0.17929549,\n", - " 0.17880609, 0.17853484, 0.59082023, 0.59180433, 0.59274339,\n", - " 0.59079241, 0.59387998, 0.59265135, 0.59209988, 0.59391444,\n", - " 0.59072413, 0.59219559, 0.59234655, 0.59073497, 0.59391106,\n", - " 0.59225191, 0.59250056, 0.59390362, 0.59075881, 0.59259427,\n", - " 0.5919504 , 0.59077803, 0.52411485, 0.52163044, 0.50248335,\n", - " 0.50266086, 0.59115919, 0.59419444, 0.59038465, 0.59128648,\n", - " 0.59323464, 0.59032653, 0.59438116, 0.59313174, 0.59165988,\n", - " 0.5944257 , 0.59018699, 0.59180163, 0.59270748, 0.59015999,\n", - " 0.59451179, 0.5925782 , 0.59221837, 0.59452251, 0.59012406,\n", - " 0.59236712, 0.59213945, 0.59013148, 0.59450445, 0.59204248,\n", - " 0.59275305, 0.59448392, 0.51467256, 0.51681741, 0.59219055,\n", - " 0.59076114, 0.59387372, 0.59213029, 0.59261978, 0.59385979,\n", - " 0.59080955, 0.59274399, 0.59180476, 0.59083819],\n", - " [-1.26055967, -1.26031469, -1.2598023 , -1.26083158, -1.25981216,\n", - " -1.26160634, -1.26143231, -1.25920552, -1.26001143, -1.26105243,\n", - " -1.26026455, -1.26115601, -1.26145837, -1.25972946, -1.26035568,\n", - " -1.26035017, -1.25972691, -1.26145864, -1.2611518 , -1.26026992,\n", - " -1.28718859, -1.28580227, -1.29551207, -1.29591315, -1.26023455,\n", - " -1.26119118, -1.2611013 , -1.26019174, -1.26077014, -1.26007772,\n", - " -1.25987122, -1.260857 , -1.2609502 , -1.26075456, -1.26134921,\n", - " -1.25965397, -1.25996982, -1.26071455, -1.25976978, -1.26108183,\n", - " -1.26034272, -1.26107775, -1.26118967, -1.25922595, -1.25959951,\n", - " -1.26157551, -1.26072113, -1.26058879, -1.26193197, -1.25939288,\n", - " -1.28878699, -1.28913722, -1.26030408, -1.26116608, -1.26092241,\n", - " -1.25960761, -1.2599948 , -1.26128422, -1.26055622, -1.26012439,\n", - " -1.26052166, -1.2609009 , -0.49429912, -0.49420118, -0.49402884,\n", - " -0.49444032, -0.49392715, -0.49464442, -0.49464248, -0.49384803,\n", - " -0.4940031 , -0.49450349, -0.49410766, -0.49446404, -0.49461625,\n", - " -0.49392508, -0.49424032, -0.49423811, -0.49392437, -0.49461667,\n", - " -0.4944622 , -0.49410966, -0.49580432, -0.4952599 , -0.49584758,\n", - " -0.49606291, -0.49405329, -0.49450455, -0.4944593 , -0.49409569,\n", - " -0.49438685, -0.49411004, -0.49400608, -0.49449611, -0.4942921 ,\n", - " -0.49429813, -0.49459747, -0.49391976, -0.49407876, -0.49437648,\n", - " -0.49398646, -0.49451098, -0.49413892, -0.49443276, -0.49457543,\n", - " -0.49388618, -0.49382348, -0.49469773, -0.49426765, -0.49431067,\n", - " -0.49473566, -0.49380506, -0.49553592, -0.49574219, -0.49407224,\n", - " -0.4944902 , -0.4944531 , -0.49402325, -0.49396739, -0.49456722,\n", - " -0.49428634, -0.49420954, -0.49415863, -0.49439461]]), _tm=BetatronTuneMonitor(tune_h='srdiag/beam-tune/main/Qh', tune_v='srdiag/beam-tune/main/Qv', name='BETATRON_TUNE'), _quads=[Quadrupole(peer='Simulator:design', name='QD2E-C04', model_name='QD2E-C04', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C05', model_name='QD2A-C05', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C05', model_name='QD2E-C05', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C06', model_name='QD2A-C06', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C06', model_name='QD2E-C06', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C07', model_name='QD2A-C07', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C07', model_name='QD2E-C07', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C08', model_name='QD2A-C08', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C08', model_name='QD2E-C08', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C09', model_name='QD2A-C09', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C09', model_name='QD2E-C09', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C10', model_name='QD2A-C10', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C10', model_name='QD2E-C10', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C11', model_name='QD2A-C11', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C11', model_name='QD2E-C11', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C12', model_name='QD2A-C12', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C12', model_name='QD2E-C12', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C13', model_name='QD2A-C13', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C13', model_name='QD2E-C13', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C14', model_name='QD2A-C14', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C14', model_name='QD2E-C14', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C15', model_name='QD2A-C15', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C15', model_name='QD2E-C15', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C16', model_name='QD2A-C16', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C16', model_name='QD2E-C16', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C17', model_name='QD2A-C17', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C17', model_name='QD2E-C17', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C18', model_name='QD2A-C18', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C18', model_name='QD2E-C18', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C19', model_name='QD2A-C19', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C19', model_name='QD2E-C19', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C20', model_name='QD2A-C20', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C20', model_name='QD2E-C20', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C21', model_name='QD2A-C21', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C21', model_name='QD2E-C21', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C22', model_name='QD2A-C22', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C22', model_name='QD2E-C22', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C23', model_name='QD2A-C23', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C23', model_name='QD2E-C23', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C24', model_name='QD2A-C24', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C24', model_name='QD2E-C24', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C25', model_name='QD2A-C25', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C25', model_name='QD2E-C25', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C26', model_name='QD2A-C26', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C26', model_name='QD2E-C26', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C27', model_name='QD2A-C27', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C27', model_name='QD2E-C27', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C28', model_name='QD2A-C28', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C28', model_name='QD2E-C28', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C29', model_name='QD2A-C29', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C29', model_name='QD2E-C29', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C30', model_name='QD2A-C30', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C30', model_name='QD2E-C30', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C31', model_name='QD2A-C31', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C31', model_name='QD2E-C31', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C32', model_name='QD2A-C32', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C32', model_name='QD2E-C32', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C01', model_name='QD2A-C01', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C01', model_name='QD2E-C01', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C02', model_name='QD2A-C02', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C02', model_name='QD2E-C02', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C03', model_name='QD2A-C03', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C04', model_name='QF1E-C04', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C05', model_name='QF1A-C05', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C05', model_name='QF1E-C05', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C06', model_name='QF1A-C06', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C06', model_name='QF1E-C06', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C07', model_name='QF1A-C07', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C07', model_name='QF1E-C07', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C08', model_name='QF1A-C08', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C08', model_name='QF1E-C08', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C09', model_name='QF1A-C09', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C09', model_name='QF1E-C09', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C10', model_name='QF1A-C10', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C10', model_name='QF1E-C10', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C11', model_name='QF1A-C11', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C11', model_name='QF1E-C11', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C12', model_name='QF1A-C12', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C12', model_name='QF1E-C12', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C13', model_name='QF1A-C13', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C13', model_name='QF1E-C13', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C14', model_name='QF1A-C14', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C14', model_name='QF1E-C14', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C15', model_name='QF1A-C15', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C15', model_name='QF1E-C15', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C16', model_name='QF1A-C16', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C16', model_name='QF1E-C16', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C17', model_name='QF1A-C17', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C17', model_name='QF1E-C17', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C18', model_name='QF1A-C18', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C18', model_name='QF1E-C18', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C19', model_name='QF1A-C19', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C19', model_name='QF1E-C19', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C20', model_name='QF1A-C20', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C20', model_name='QF1E-C20', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C21', model_name='QF1A-C21', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C21', model_name='QF1E-C21', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C22', model_name='QF1A-C22', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C22', model_name='QF1E-C22', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C23', model_name='QF1A-C23', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C23', model_name='QF1E-C23', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C24', model_name='QF1A-C24', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C24', model_name='QF1E-C24', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C25', model_name='QF1A-C25', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C25', model_name='QF1E-C25', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C26', model_name='QF1A-C26', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C26', model_name='QF1E-C26', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C27', model_name='QF1A-C27', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C27', model_name='QF1E-C27', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C28', model_name='QF1A-C28', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C28', model_name='QF1E-C28', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C29', model_name='QF1A-C29', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C29', model_name='QF1E-C29', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C30', model_name='QF1A-C30', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C30', model_name='QF1E-C30', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C31', model_name='QF1A-C31', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C31', model_name='QF1E-C31', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C32', model_name='QF1A-C32', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C32', model_name='QF1E-C32', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C01', model_name='QF1A-C01', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C01', model_name='QF1E-C01', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C02', model_name='QF1A-C02', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C02', model_name='QF1E-C02', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C03', model_name='QF1A-C03', magnet_model=LinearMagnetModel)], name='DEFAULT_TUNE_CORRECTION')" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "SR.tune # string representation" - ] + "outputs": [], + "source": "SR.tool.tune # string representation" }, { "cell_type": "markdown", @@ -391,142 +323,25 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "c81cdb05", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Response matrix loaded.\n" - ] - }, - { - "data": { - "text/plain": [ - "TuneResponseMatrix(quad_array_name='QForTune', betatron_tune_name='BETATRON_TUNE', quad_delta=0.0001, n_step=1, sleep_between_step=0.0, n_avg_meas=1, sleep_between_meas=0.0, name='DEFAULT_TUNE_RESPONSE_MATRIX')" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "if SR.tune.response_matrix is None:\n", - " SR.trm.measure(sleep_between_step=wait_time, callback=tune_callback)\n", - " SR.trm.save(CONFIG_DIR / \"trm.json\")\n", - "\n", - "SR.tune.load(CONFIG_DIR / \"trm.json\")\n", - "print(\"Response matrix loaded.\")\n", - "SR.trm # string representation" - ] + "outputs": [], + "source": "if SR.tool.tune.response_matrix is None:\n SR.tool.trm.measure(sleep_between_step=wait_time, callback=tune_callback)\n SR.tool.trm.save(CONFIG_DIR / \"trm.json\")\n\nSR.tool.tune.load(CONFIG_DIR / \"trm.json\")\nprint(\"Response matrix loaded.\")\nSR.tool.trm # string representation" }, { "cell_type": "markdown", "id": "ef7d7ce4", "metadata": {}, - "source": [ - "#### Correcting the tune\n", - "\n", - "`SR.tune.set([qx, qy])` runs the correction iteratively. The `iter` parameter controls the number of iterations and `wait_time` the settling time between each iteration." - ] + "source": "#### Correcting the tune\n\n`SR.tool.tune.set([qx, qy])` runs the correction iteratively. The `iter` parameter controls the number of iterations and `wait_time` the settling time between each iteration." }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "6b8bcf91", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tune before correction: [0.16000001 0.33999986]\n", - "\n", - "Setting tune to [0.19, 0.28]\n", - "Tune after correction: [0.19 0.28]\n", - "\n", - "Setting tune to [0.21, 0.3]\n", - "Tune after correction: [0.21 0.3 ]\n" - ] - }, - { - "data": { - "text/plain": [ - "Tune(quad_array_name='QForTune', betatron_tune_name='BETATRON_TUNE', response_matrix=array([[ 0.17853128, 0.17890919, 0.17917984, 0.17843061, 0.17932054,\n", - " 0.17884878, 0.1786898 , 0.17950221, 0.17836418, 0.1790288 ,\n", - " 0.17907229, 0.17845344, 0.17936885, 0.1787317 , 0.17880339,\n", - " 0.1793422 , 0.17843576, 0.17914062, 0.17895506, 0.17850485,\n", - " 0.15843663, 0.1575313 , 0.15237977, 0.15250702, 0.17830408,\n", - " 0.17955648, 0.1784584 , 0.17880469, 0.17936621, 0.17824945,\n", - " 0.17941811, 0.17905372, 0.17841113, 0.17957284, 0.17835113,\n", - " 0.17897118, 0.17923226, 0.17825399, 0.17950825, 0.17876573,\n", - " 0.17866201, 0.17954684, 0.17827911, 0.17925585, 0.17897151,\n", - " 0.17830041, 0.17956082, 0.17873061, 0.17871689, 0.17948152,\n", - " 0.15577439, 0.15662709, 0.178933 , 0.17847488, 0.17937198,\n", - " 0.17881763, 0.17874021, 0.17931638, 0.17843723, 0.17929549,\n", - " 0.17880609, 0.17853484, 0.59082023, 0.59180433, 0.59274339,\n", - " 0.59079241, 0.59387998, 0.59265135, 0.59209988, 0.59391444,\n", - " 0.59072413, 0.59219559, 0.59234655, 0.59073497, 0.59391106,\n", - " 0.59225191, 0.59250056, 0.59390362, 0.59075881, 0.59259427,\n", - " 0.5919504 , 0.59077803, 0.52411485, 0.52163044, 0.50248335,\n", - " 0.50266086, 0.59115919, 0.59419444, 0.59038465, 0.59128648,\n", - " 0.59323464, 0.59032653, 0.59438116, 0.59313174, 0.59165988,\n", - " 0.5944257 , 0.59018699, 0.59180163, 0.59270748, 0.59015999,\n", - " 0.59451179, 0.5925782 , 0.59221837, 0.59452251, 0.59012406,\n", - " 0.59236712, 0.59213945, 0.59013148, 0.59450445, 0.59204248,\n", - " 0.59275305, 0.59448392, 0.51467256, 0.51681741, 0.59219055,\n", - " 0.59076114, 0.59387372, 0.59213029, 0.59261978, 0.59385979,\n", - " 0.59080955, 0.59274399, 0.59180476, 0.59083819],\n", - " [-1.26055967, -1.26031469, -1.2598023 , -1.26083158, -1.25981216,\n", - " -1.26160634, -1.26143231, -1.25920552, -1.26001143, -1.26105243,\n", - " -1.26026455, -1.26115601, -1.26145837, -1.25972946, -1.26035568,\n", - " -1.26035017, -1.25972691, -1.26145864, -1.2611518 , -1.26026992,\n", - " -1.28718859, -1.28580227, -1.29551207, -1.29591315, -1.26023455,\n", - " -1.26119118, -1.2611013 , -1.26019174, -1.26077014, -1.26007772,\n", - " -1.25987122, -1.260857 , -1.2609502 , -1.26075456, -1.26134921,\n", - " -1.25965397, -1.25996982, -1.26071455, -1.25976978, -1.26108183,\n", - " -1.26034272, -1.26107775, -1.26118967, -1.25922595, -1.25959951,\n", - " -1.26157551, -1.26072113, -1.26058879, -1.26193197, -1.25939288,\n", - " -1.28878699, -1.28913722, -1.26030408, -1.26116608, -1.26092241,\n", - " -1.25960761, -1.2599948 , -1.26128422, -1.26055622, -1.26012439,\n", - " -1.26052166, -1.2609009 , -0.49429912, -0.49420118, -0.49402884,\n", - " -0.49444032, -0.49392715, -0.49464442, -0.49464248, -0.49384803,\n", - " -0.4940031 , -0.49450349, -0.49410766, -0.49446404, -0.49461625,\n", - " -0.49392508, -0.49424032, -0.49423811, -0.49392437, -0.49461667,\n", - " -0.4944622 , -0.49410966, -0.49580432, -0.4952599 , -0.49584758,\n", - " -0.49606291, -0.49405329, -0.49450455, -0.4944593 , -0.49409569,\n", - " -0.49438685, -0.49411004, -0.49400608, -0.49449611, -0.4942921 ,\n", - " -0.49429813, -0.49459747, -0.49391976, -0.49407876, -0.49437648,\n", - " -0.49398646, -0.49451098, -0.49413892, -0.49443276, -0.49457543,\n", - " -0.49388618, -0.49382348, -0.49469773, -0.49426765, -0.49431067,\n", - " -0.49473566, -0.49380506, -0.49553592, -0.49574219, -0.49407224,\n", - " -0.4944902 , -0.4944531 , -0.49402325, -0.49396739, -0.49456722,\n", - " -0.49428634, -0.49420954, -0.49415863, -0.49439461]]), _tm=BetatronTuneMonitor(tune_h='srdiag/beam-tune/main/Qh', tune_v='srdiag/beam-tune/main/Qv', name='BETATRON_TUNE'), _quads=[Quadrupole(peer='Simulator:design', name='QD2E-C04', model_name='QD2E-C04', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C05', model_name='QD2A-C05', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C05', model_name='QD2E-C05', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C06', model_name='QD2A-C06', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C06', model_name='QD2E-C06', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C07', model_name='QD2A-C07', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C07', model_name='QD2E-C07', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C08', model_name='QD2A-C08', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C08', model_name='QD2E-C08', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C09', model_name='QD2A-C09', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C09', model_name='QD2E-C09', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C10', model_name='QD2A-C10', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C10', model_name='QD2E-C10', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C11', model_name='QD2A-C11', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C11', model_name='QD2E-C11', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C12', model_name='QD2A-C12', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C12', model_name='QD2E-C12', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C13', model_name='QD2A-C13', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C13', model_name='QD2E-C13', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C14', model_name='QD2A-C14', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C14', model_name='QD2E-C14', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C15', model_name='QD2A-C15', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C15', model_name='QD2E-C15', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C16', model_name='QD2A-C16', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C16', model_name='QD2E-C16', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C17', model_name='QD2A-C17', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C17', model_name='QD2E-C17', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C18', model_name='QD2A-C18', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C18', model_name='QD2E-C18', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C19', model_name='QD2A-C19', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C19', model_name='QD2E-C19', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C20', model_name='QD2A-C20', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C20', model_name='QD2E-C20', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C21', model_name='QD2A-C21', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C21', model_name='QD2E-C21', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C22', model_name='QD2A-C22', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C22', model_name='QD2E-C22', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C23', model_name='QD2A-C23', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C23', model_name='QD2E-C23', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C24', model_name='QD2A-C24', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C24', model_name='QD2E-C24', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C25', model_name='QD2A-C25', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C25', model_name='QD2E-C25', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C26', model_name='QD2A-C26', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C26', model_name='QD2E-C26', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C27', model_name='QD2A-C27', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C27', model_name='QD2E-C27', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C28', model_name='QD2A-C28', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C28', model_name='QD2E-C28', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C29', model_name='QD2A-C29', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C29', model_name='QD2E-C29', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C30', model_name='QD2A-C30', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C30', model_name='QD2E-C30', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C31', model_name='QD2A-C31', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C31', model_name='QD2E-C31', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C32', model_name='QD2A-C32', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C32', model_name='QD2E-C32', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C01', model_name='QD2A-C01', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C01', model_name='QD2E-C01', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C02', model_name='QD2A-C02', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2E-C02', model_name='QD2E-C02', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QD2A-C03', model_name='QD2A-C03', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C04', model_name='QF1E-C04', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C05', model_name='QF1A-C05', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C05', model_name='QF1E-C05', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C06', model_name='QF1A-C06', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C06', model_name='QF1E-C06', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C07', model_name='QF1A-C07', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C07', model_name='QF1E-C07', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C08', model_name='QF1A-C08', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C08', model_name='QF1E-C08', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C09', model_name='QF1A-C09', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C09', model_name='QF1E-C09', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C10', model_name='QF1A-C10', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C10', model_name='QF1E-C10', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C11', model_name='QF1A-C11', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C11', model_name='QF1E-C11', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C12', model_name='QF1A-C12', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C12', model_name='QF1E-C12', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C13', model_name='QF1A-C13', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C13', model_name='QF1E-C13', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C14', model_name='QF1A-C14', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C14', model_name='QF1E-C14', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C15', model_name='QF1A-C15', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C15', model_name='QF1E-C15', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C16', model_name='QF1A-C16', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C16', model_name='QF1E-C16', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C17', model_name='QF1A-C17', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C17', model_name='QF1E-C17', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C18', model_name='QF1A-C18', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C18', model_name='QF1E-C18', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C19', model_name='QF1A-C19', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C19', model_name='QF1E-C19', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C20', model_name='QF1A-C20', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C20', model_name='QF1E-C20', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C21', model_name='QF1A-C21', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C21', model_name='QF1E-C21', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C22', model_name='QF1A-C22', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C22', model_name='QF1E-C22', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C23', model_name='QF1A-C23', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C23', model_name='QF1E-C23', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C24', model_name='QF1A-C24', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C24', model_name='QF1E-C24', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C25', model_name='QF1A-C25', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C25', model_name='QF1E-C25', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C26', model_name='QF1A-C26', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C26', model_name='QF1E-C26', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C27', model_name='QF1A-C27', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C27', model_name='QF1E-C27', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C28', model_name='QF1A-C28', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C28', model_name='QF1E-C28', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C29', model_name='QF1A-C29', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C29', model_name='QF1E-C29', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C30', model_name='QF1A-C30', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C30', model_name='QF1E-C30', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C31', model_name='QF1A-C31', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C31', model_name='QF1E-C31', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C32', model_name='QF1A-C32', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C32', model_name='QF1E-C32', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C01', model_name='QF1A-C01', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C01', model_name='QF1E-C01', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C02', model_name='QF1A-C02', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1E-C02', model_name='QF1E-C02', magnet_model=LinearMagnetModel), Quadrupole(peer='Simulator:design', name='QF1A-C03', model_name='QF1A-C03', magnet_model=LinearMagnetModel)], name='DEFAULT_TUNE_CORRECTION')" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "print(f\"Tune before correction: {SR.tune.readback()}\")\n", - "\n", - "qx, qy = 0.19, 0.28\n", - "print(f\"\\nSetting tune to [{qx}, {qy}]\")\n", - "SR.tune.set([qx, qy], iter=10, wait_time=wait_time)\n", - "print(f\"Tune after correction: {SR.tune.readback()}\")\n", - "\n", - "qx, qy = 0.21, 0.30\n", - "print(f\"\\nSetting tune to [{qx}, {qy}]\")\n", - "SR.tune.set([qx, qy], iter=10, wait_time=wait_time)\n", - "print(f\"Tune after correction: {SR.tune.readback()}\")\n", - "\n", - "SR.tune # string representation" - ] + "outputs": [], + "source": "print(f\"Tune before correction: {SR.tool.tune.readback()}\")\n\nqx, qy = 0.19, 0.28\nprint(f\"\\nSetting tune to [{qx}, {qy}]\")\nSR.tool.tune.set([qx, qy], iter=10, wait_time=wait_time)\nprint(f\"Tune after correction: {SR.tool.tune.readback()}\")\n\nqx, qy = 0.21, 0.30\nprint(f\"\\nSetting tune to [{qx}, {qy}]\")\nSR.tool.tune.set([qx, qy], iter=10, wait_time=wait_time)\nprint(f\"Tune after correction: {SR.tool.tune.readback()}\")\n\nSR.tool.tune # string representation" }, { "cell_type": "code", diff --git a/examples/use_cases/01-tune_correction.py b/examples/use_cases/01-tune_correction.py index d77cb3671..1525b993a 100644 --- a/examples/use_cases/01-tune_correction.py +++ b/examples/use_cases/01-tune_correction.py @@ -80,7 +80,7 @@ # In[4]: -tune_monitor = SR.get_betatron_tune_monitor("BETATRON_TUNE") +tune_monitor = SR.diagnostic.get("BETATRON_TUNE") print(f"Current tune: {tune_monitor.tune.get()}") print(tune_monitor) # string representation @@ -112,14 +112,14 @@ # ### Standard tune correction tool # -# `SR.tune` is the `DEFAULT_TUNE_CORRECTION` tool. `SR.trm` is the `DEFAULT_TUNE_RESPONSE_MATRIX` tool. +# `SR.tool.tune` is the `DEFAULT_TUNE_CORRECTION` tool. `SR.tool.trm` is the `DEFAULT_TUNE_RESPONSE_MATRIX` tool. # # Before correcting the tune you need a response matrix. It can be measured (below) or loaded from a previously saved file. # In[7]: -print(SR.tune) # string representation +print(SR.tool.tune) # string representation # #### Measuring the tune response matrix @@ -145,36 +145,36 @@ def tune_callback(action: int, cb_data: dict): # In[9]: -if SR.tune.response_matrix is None: - SR.trm.measure(sleep_between_step=wait_time, callback=tune_callback) - SR.trm.save(CONFIG_DIR / "trm.json") +if SR.tool.tune.response_matrix is None: + SR.tool.trm.measure(sleep_between_step=wait_time, callback=tune_callback) + SR.tool.trm.save(CONFIG_DIR / "trm.json") -SR.tune.load(CONFIG_DIR / "trm.json") +SR.tool.tune.load(CONFIG_DIR / "trm.json") print("Response matrix loaded.") -print(SR.trm) # string representation +print(SR.tool.trm) # string representation # #### Correcting the tune # -# `SR.tune.set([qx, qy])` runs the correction iteratively. The `iter` parameter controls +# `SR.tool.tune.set([qx, qy])` runs the correction iteratively. The `iter` parameter controls # the number of iterations and `wait_time` the settling time between each iteration. # In[10]: -print(f"Tune before correction: {SR.tune.readback()}") +print(f"Tune before correction: {SR.tool.tune.readback()}") qx, qy = 0.19, 0.28 print(f"\nSetting tune to [{qx}, {qy}]") -SR.tune.set([qx, qy], iter=10, wait_time=wait_time) -print(f"Tune after correction: {SR.tune.readback()}") +SR.tool.tune.set([qx, qy], iter=10, wait_time=wait_time) +print(f"Tune after correction: {SR.tool.tune.readback()}") qx, qy = 0.21, 0.30 print(f"\nSetting tune to [{qx}, {qy}]") -SR.tune.set([qx, qy], iter=10, wait_time=wait_time) -print(f"Tune after correction: {SR.tune.readback()}") +SR.tool.tune.set([qx, qy], iter=10, wait_time=wait_time) +print(f"Tune after correction: {SR.tool.tune.readback()}") -print(SR.tune) # string representation +print(SR.tool.tune) # string representation # In[ ]: diff --git a/examples/use_cases/02-chromaticity_measurement.ipynb b/examples/use_cases/02-chromaticity_measurement.ipynb index 9ac1afca7..05ea57a2c 100644 --- a/examples/use_cases/02-chromaticity_measurement.ipynb +++ b/examples/use_cases/02-chromaticity_measurement.ipynb @@ -267,7 +267,7 @@ } ], "source": [ - "chroma_monitor = SR.get_chromaticity_monitor(\"CHROMATICITY_MONITOR\")\n", + "chroma_monitor = SR.tool.get(\"CHROMATICITY_MONITOR\")\n", "\n", "chroma_monitor.measure(\n", " callback=chroma_callback,\n", diff --git a/examples/use_cases/02-chromaticity_measurement.py b/examples/use_cases/02-chromaticity_measurement.py index 966b23ef3..320aa0b94 100644 --- a/examples/use_cases/02-chromaticity_measurement.py +++ b/examples/use_cases/02-chromaticity_measurement.py @@ -109,7 +109,7 @@ def chroma_callback(action: int, cb_data: dict): # In[17]: -chroma_monitor = SR.get_chromaticity_monitor("CHROMATICITY_MONITOR") +chroma_monitor = SR.tool.get("CHROMATICITY_MONITOR") chroma_monitor.measure( callback=chroma_callback, diff --git a/examples/use_cases/03-orbit_correction.ipynb b/examples/use_cases/03-orbit_correction.ipynb index e476b7a0e..9121fd64a 100644 --- a/examples/use_cases/03-orbit_correction.ipynb +++ b/examples/use_cases/03-orbit_correction.ipynb @@ -185,163 +185,33 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "6adb7436", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "BPMs: 320, H correctors: 288, V correctors: 288\n" - ] - } - ], - "source": [ - "bpms = SR.bpms.get(\"BPM\")\n", - "hcorr = SR.magnets.get(\"HCorr\")\n", - "vcorr = SR.magnets.get(\"VCorr\")\n", - "print(f\"BPMs: {len(bpms)}, H correctors: {len(hcorr)}, V correctors: {len(vcorr)}\")" - ] + "outputs": [], + "source": "bpms = SR.diagnostic.bpms.get(\"BPM\")\nhcorr = SR.magnets.get(\"HCorr\")\nvcorr = SR.magnets.get(\"VCorr\")\nprint(f\"BPMs: {len(bpms)}, H correctors: {len(hcorr)}, V correctors: {len(vcorr)}\")" }, { "cell_type": "markdown", "id": "808334df", "metadata": {}, - "source": [ - "### Orbit response matrix\n", - "\n", - "The ORM can be saved in multiple formats. Load it into `SR.orbit` before correcting." - ] + "source": "### Orbit response matrix\n\nThe ORM can be saved in multiple formats. Load it into `SR.tool.orbit` before correcting." }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "33636af2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "OrbitResponseMatrix(bpm_array_name='BPM', hcorr_array_name='HCorr', vcorr_array_name='VCorr', corrector_delta=1e-06, n_step=1, sleep_between_step=0.0, n_avg_meas=1, sleep_between_meas=0.0, name='DEFAULT_ORBIT_RESPONSE_MATRIX')" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "SR.orm # string representation" - ] + "outputs": [], + "source": "SR.tool.orm # string representation" }, { "cell_type": "code", "execution_count": null, "id": "3f9dcb18", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "14 Sep 2026, 15:10:12 | INFO | Measuring correctors from the default arrays: HCorr and VCorr.\n", - "14 Sep 2026, 15:10:14 | INFO | Measured response of SH1A-C04-H.\n", - "14 Sep 2026, 15:10:16 | INFO | Measured response of SJ1A-C04-H.\n", - "14 Sep 2026, 15:10:17 | INFO | Measured response of SJ2A-C04-H.\n", - "14 Sep 2026, 15:10:18 | INFO | Measured response of SJ1B-C04-H.\n", - "14 Sep 2026, 15:10:19 | INFO | Measured response of SH2B-C04-H.\n", - "14 Sep 2026, 15:10:21 | INFO | Measured response of SJ1D-C04-H.\n", - "14 Sep 2026, 15:10:22 | INFO | Measured response of SJ2E-C04-H.\n", - "14 Sep 2026, 15:10:23 | INFO | Measured response of SJ1E-C04-H.\n", - "14 Sep 2026, 15:10:24 | INFO | Measured response of SH3E-C04-H.\n", - "14 Sep 2026, 15:10:26 | INFO | Measured response of SH1A-C05-H.\n", - "14 Sep 2026, 15:10:27 | INFO | Measured response of SD1A-C05-H.\n", - "14 Sep 2026, 15:10:28 | INFO | Measured response of SF2A-C05-H.\n", - "14 Sep 2026, 15:10:29 | INFO | Measured response of SD1B-C05-H.\n", - "14 Sep 2026, 15:10:31 | INFO | Measured response of SH2B-C05-H.\n", - "14 Sep 2026, 15:10:32 | INFO | Measured response of SD1D-C05-H.\n", - "14 Sep 2026, 15:10:33 | INFO | Measured response of SF2E-C05-H.\n", - "14 Sep 2026, 15:10:34 | INFO | Measured response of SD1E-C05-H.\n", - "14 Sep 2026, 15:10:36 | INFO | Measured response of SH3E-C05-H.\n", - "14 Sep 2026, 15:10:37 | INFO | Measured response of SH1A-C06-H.\n", - "14 Sep 2026, 15:10:38 | INFO | Measured response of SD1A-C06-H.\n", - "14 Sep 2026, 15:10:39 | INFO | Measured response of SF2A-C06-H.\n", - "14 Sep 2026, 15:10:41 | INFO | Measured response of SD1B-C06-H.\n", - "14 Sep 2026, 15:10:42 | INFO | Measured response of SH2B-C06-H.\n", - "14 Sep 2026, 15:10:43 | INFO | Measured response of SD1D-C06-H.\n", - "14 Sep 2026, 15:10:44 | INFO | Measured response of SF2E-C06-H.\n", - "14 Sep 2026, 15:10:45 | INFO | Measured response of SD1E-C06-H.\n", - "14 Sep 2026, 15:10:47 | INFO | Measured response of SH3E-C06-H.\n", - "14 Sep 2026, 15:10:48 | INFO | Measured response of SH1A-C07-H.\n", - "14 Sep 2026, 15:10:49 | INFO | Measured response of SD1A-C07-H.\n", - "14 Sep 2026, 15:10:50 | INFO | Measured response of SF2A-C07-H.\n", - "14 Sep 2026, 15:10:52 | INFO | Measured response of SD1B-C07-H.\n", - "14 Sep 2026, 15:10:53 | INFO | Measured response of SH2B-C07-H.\n", - "14 Sep 2026, 15:10:54 | INFO | Measured response of SD1D-C07-H.\n", - "14 Sep 2026, 15:10:55 | INFO | Measured response of SF2E-C07-H.\n", - "14 Sep 2026, 15:10:56 | INFO | Measured response of SD1E-C07-H.\n", - "14 Sep 2026, 15:10:57 | INFO | Measured response of SH3E-C07-H.\n", - "14 Sep 2026, 15:10:59 | INFO | Measured response of SH1A-C08-H.\n", - "14 Sep 2026, 15:11:00 | INFO | Measured response of SD1A-C08-H.\n", - "14 Sep 2026, 15:11:01 | INFO | Measured response of SF2A-C08-H.\n", - "14 Sep 2026, 15:11:02 | INFO | Measured response of SD1B-C08-H.\n", - "14 Sep 2026, 15:11:04 | INFO | Measured response of SH2B-C08-H.\n", - "14 Sep 2026, 15:11:05 | INFO | Measured response of SD1D-C08-H.\n", - "14 Sep 2026, 15:11:06 | INFO | Measured response of SF2E-C08-H.\n", - "14 Sep 2026, 15:11:07 | INFO | Measured response of SD1E-C08-H.\n", - "14 Sep 2026, 15:11:08 | INFO | Measured response of SH3E-C08-H.\n", - "14 Sep 2026, 15:11:10 | INFO | Measured response of SH1A-C09-H.\n", - "14 Sep 2026, 15:11:11 | INFO | Measured response of SD1A-C09-H.\n", - "14 Sep 2026, 15:11:12 | INFO | Measured response of SF2A-C09-H.\n", - "14 Sep 2026, 15:11:13 | INFO | Measured response of SD1B-C09-H.\n", - "14 Sep 2026, 15:11:14 | INFO | Measured response of SH2B-C09-H.\n", - "14 Sep 2026, 15:11:16 | INFO | Measured response of SD1D-C09-H.\n", - "14 Sep 2026, 15:11:17 | INFO | Measured response of SF2E-C09-H.\n", - "14 Sep 2026, 15:11:18 | INFO | Measured response of SD1E-C09-H.\n", - "14 Sep 2026, 15:11:19 | INFO | Measured response of SH3E-C09-H.\n", - "14 Sep 2026, 15:11:21 | INFO | Measured response of SH1A-C10-H.\n", - "14 Sep 2026, 15:11:22 | INFO | Measured response of SD1A-C10-H.\n", - "14 Sep 2026, 15:11:23 | INFO | Measured response of SF2A-C10-H.\n", - "14 Sep 2026, 15:11:24 | INFO | Measured response of SD1B-C10-H.\n", - "14 Sep 2026, 15:11:26 | INFO | Measured response of SH2B-C10-H.\n", - "14 Sep 2026, 15:11:27 | INFO | Measured response of SD1D-C10-H.\n", - "14 Sep 2026, 15:11:28 | INFO | Measured response of SF2E-C10-H.\n", - "14 Sep 2026, 15:11:29 | INFO | Measured response of SD1E-C10-H.\n", - "14 Sep 2026, 15:11:31 | INFO | Measured response of SH3E-C10-H.\n", - "14 Sep 2026, 15:11:32 | INFO | Measured response of SH1A-C11-H.\n", - "14 Sep 2026, 15:11:33 | INFO | Measured response of SD1A-C11-H.\n", - "14 Sep 2026, 15:11:34 | INFO | Measured response of SF2A-C11-H.\n", - "14 Sep 2026, 15:11:35 | INFO | Measured response of SD1B-C11-H.\n", - "14 Sep 2026, 15:11:37 | INFO | Measured response of SH2B-C11-H.\n", - "14 Sep 2026, 15:11:38 | INFO | Measured response of SD1D-C11-H.\n", - "14 Sep 2026, 15:11:39 | INFO | Measured response of SF2E-C11-H.\n", - "14 Sep 2026, 15:11:40 | INFO | Measured response of SD1E-C11-H.\n", - "14 Sep 2026, 15:11:41 | INFO | Measured response of SH3E-C11-H.\n", - "14 Sep 2026, 15:11:43 | INFO | Measured response of SH1A-C12-H.\n", - "14 Sep 2026, 15:11:44 | INFO | Measured response of SD1A-C12-H.\n", - "14 Sep 2026, 15:11:45 | INFO | Measured response of SF2A-C12-H.\n", - "14 Sep 2026, 15:11:46 | INFO | Measured response of SD1B-C12-H.\n", - "14 Sep 2026, 15:11:47 | INFO | Measured response of SH2B-C12-H.\n", - "14 Sep 2026, 15:11:49 | INFO | Measured response of SD1D-C12-H.\n", - "14 Sep 2026, 15:11:50 | INFO | Measured response of SF2E-C12-H.\n", - "14 Sep 2026, 15:11:51 | INFO | Measured response of SD1E-C12-H.\n", - "14 Sep 2026, 15:11:52 | INFO | Measured response of SH3E-C12-H.\n", - "14 Sep 2026, 15:11:54 | INFO | Measured response of SH1A-C13-H.\n", - "14 Sep 2026, 15:11:55 | INFO | Measured response of SD1A-C13-H.\n", - "14 Sep 2026, 15:11:56 | INFO | Measured response of SF2A-C13-H.\n" - ] - } - ], - "source": [ - "SR.orm.measure(sleep_between_step=wait_time)\n", - "SR.orm.save(CONFIG_DIR / \"orm.json\")\n", - "SR.orm.save(CONFIG_DIR / \"orm.yaml\", with_type=\"yaml\")\n", - "SR.orm.save(CONFIG_DIR / \"orm.npz\", with_type=\"npz\")\n", - "\n", - "SR.orbit.load(CONFIG_DIR / \"orm.json\")\n", - "print(\"ORM measured, saved and loaded.\")" - ] + "outputs": [], + "source": "SR.tool.orm.measure(sleep_between_step=wait_time)\nSR.tool.orm.save(CONFIG_DIR / \"orm.json\")\nSR.tool.orm.save(CONFIG_DIR / \"orm.yaml\", with_type=\"yaml\")\nSR.tool.orm.save(CONFIG_DIR / \"orm.npz\", with_type=\"npz\")\n\nSR.tool.orbit.load(CONFIG_DIR / \"orm.json\")\nprint(\"ORM measured, saved and loaded.\")" }, { "cell_type": "markdown", @@ -357,15 +227,7 @@ "id": "942f8f3b", "metadata": {}, "outputs": [], - "source": [ - "orm_data = SR.orm.get()\n", - "plt.imshow(np.array(orm_data[\"matrix\"]))\n", - "plt.colorbar()\n", - "plt.title(\"Orbit response matrix\")\n", - "plt.xlabel(\"Corrector index\")\n", - "plt.ylabel(\"BPM index\")\n", - "plt.show()" - ] + "source": "orm_data = SR.tool.orm.get()\nplt.imshow(np.array(orm_data[\"matrix\"]))\nplt.colorbar()\nplt.title(\"Orbit response matrix\")\nplt.xlabel(\"Corrector index\")\nplt.ylabel(\"BPM index\")\nplt.show()" }, { "cell_type": "markdown", @@ -383,28 +245,7 @@ "id": "693fc409", "metadata": {}, "outputs": [], - "source": [ - "# Uncomment to measure and visualise dispersion\n", - "\n", - "# def disp_callback(action: int, cb_data) -> bool:\n", - "# from pyaml.common.constants import Action\n", - "# if action == Action.APPLY:\n", - "# print(\"Changing RF frequency\")\n", - "# elif action == Action.MEASURE:\n", - "# print(\"Reading orbit\")\n", - "# elif action == Action.RESTORE:\n", - "# print(\"Restoring RF frequency\")\n", - "# return True\n", - "\n", - "# SR.dispersion.measure(callback=disp_callback)\n", - "# disp_data = SR.dispersion.get()\n", - "# plt.plot(disp_data[\"frequency_response_x\"], label=\"H dispersion\")\n", - "# plt.plot(disp_data[\"frequency_response_y\"], label=\"V dispersion\")\n", - "# plt.xlabel(\"BPM index\")\n", - "# plt.ylabel(\"Orbit / Δf [m/Hz]\")\n", - "# plt.legend()\n", - "# plt.show()" - ] + "source": "# Uncomment to measure and visualise dispersion\n\n# def disp_callback(action: int, cb_data) -> bool:\n# from pyaml.common.constants import Action\n# if action == Action.APPLY:\n# print(\"Changing RF frequency\")\n# elif action == Action.MEASURE:\n# print(\"Reading orbit\")\n# elif action == Action.RESTORE:\n# print(\"Restoring RF frequency\")\n# return True\n\n# SR.tool.dispersion.measure(callback=disp_callback)\n# disp_data = SR.tool.dispersion.get()\n# plt.plot(disp_data[\"frequency_response_x\"], label=\"H dispersion\")\n# plt.plot(disp_data[\"frequency_response_y\"], label=\"V dispersion\")\n# plt.xlabel(\"BPM index\")\n# plt.ylabel(\"Orbit / Δf [m/Hz]\")\n# plt.legend()\n# plt.show()" }, { "cell_type": "markdown", @@ -477,16 +318,7 @@ "cell_type": "markdown", "id": "cf49c543", "metadata": {}, - "source": [ - "### Correct the orbit\n", - "\n", - "Standard correction: `SR.orbit.correct(reference=reference)`.\n", - "\n", - "Optional variants (uncomment to use):\n", - "- **Virtual corrector weight**: down-weights correctors that are already at large strengths.\n", - "- **RF correction**: also adjusts the RF frequency to minimise dispersion-driven orbit.\n", - "- **Live unit mismatch**: if BESSY2 BPMs read in nm, pass `gain=1e-9`." - ] + "source": "### Correct the orbit\n\nStandard correction: `SR.tool.orbit.correct(reference=reference)`.\n\nOptional variants (uncomment to use):\n- **Virtual corrector weight**: down-weights correctors that are already at large strengths.\n- **RF correction**: also adjusts the RF frequency to minimise dispersion-driven orbit.\n- **Live unit mismatch**: if BESSY2 BPMs read in nm, pass `gain=1e-9`." }, { "cell_type": "code", @@ -494,22 +326,7 @@ "id": "93135a4c", "metadata": {}, "outputs": [], - "source": [ - "# Standard correction\n", - "SR.orbit.correct(reference=reference)\n", - "\n", - "# With virtual corrector weight (ESRF style):\n", - "# SR.orbit.set_virtual_weight(1000)\n", - "# SR.orbit.correct(reference=reference)\n", - "\n", - "# With RF orbit correction (ESRF style, requires dispersion in ORM):\n", - "# SR.orbit.correct(reference=reference, rf=True)\n", - "\n", - "# BESSY2 live mode — BPMs in nm, use gain to compensate unit mismatch:\n", - "# SR.orbit.correct(reference=reference, gain=1e-9)\n", - "\n", - "sleep(wait_time)" - ] + "source": "# Standard correction\nSR.tool.orbit.correct(reference=reference)\n\n# With virtual corrector weight (ESRF style):\n# SR.tool.orbit.set_virtual_weight(1000)\n# SR.tool.orbit.correct(reference=reference)\n\n# With RF orbit correction (ESRF style, requires dispersion in ORM):\n# SR.tool.orbit.correct(reference=reference, rf=True)\n\n# BESSY2 live mode — BPMs in nm, use gain to compensate unit mismatch:\n# SR.tool.orbit.correct(reference=reference, gain=1e-9)\n\nsleep(wait_time)" }, { "cell_type": "code", diff --git a/examples/use_cases/03-orbit_correction.py b/examples/use_cases/03-orbit_correction.py index ceef8ec18..7271f26fb 100644 --- a/examples/use_cases/03-orbit_correction.py +++ b/examples/use_cases/03-orbit_correction.py @@ -84,7 +84,7 @@ # In[4]: -bpms = SR.bpms.get("BPM") +bpms = SR.diagnostic.bpms.get("BPM") hcorr = SR.magnets.get("HCorr") vcorr = SR.magnets.get("VCorr") print(f"BPMs: {len(bpms)}, H correctors: {len(hcorr)}, V correctors: {len(vcorr)}") @@ -92,23 +92,23 @@ # ### Orbit response matrix # -# The ORM can be saved in multiple formats. Load it into `SR.orbit` before correcting. +# The ORM can be saved in multiple formats. Load it into `SR.tool.orbit` before correcting. # In[5]: -print(SR.orm) # string representation +print(SR.tool.orm) # string representation # In[6]: -SR.orm.measure(sleep_between_step=wait_time) -SR.orm.save(CONFIG_DIR / "orm.json") -SR.orm.save(CONFIG_DIR / "orm.yaml", with_type="yaml") -SR.orm.save(CONFIG_DIR / "orm.npz", with_type="npz") +SR.tool.orm.measure(sleep_between_step=wait_time) +SR.tool.orm.save(CONFIG_DIR / "orm.json") +SR.tool.orm.save(CONFIG_DIR / "orm.yaml", with_type="yaml") +SR.tool.orm.save(CONFIG_DIR / "orm.npz", with_type="npz") -SR.orbit.load(CONFIG_DIR / "orm.json") +SR.tool.orbit.load(CONFIG_DIR / "orm.json") print("ORM measured, saved and loaded.") @@ -117,7 +117,7 @@ # In[7]: -orm_data = SR.orm.get() +orm_data = SR.tool.orm.get() plt.imshow(np.array(orm_data["matrix"])) plt.colorbar() plt.title("Orbit response matrix") @@ -147,8 +147,8 @@ # print("Restoring RF frequency") # return True -# SR.dispersion.measure(callback=disp_callback) -# disp_data = SR.dispersion.get() +# SR.tool.dispersion.measure(callback=disp_callback) +# disp_data = SR.tool.dispersion.get() # plt.plot(disp_data["frequency_response_x"], label="H dispersion") # plt.plot(disp_data["frequency_response_y"], label="V dispersion") # plt.xlabel("BPM index") @@ -202,7 +202,7 @@ # ### Correct the orbit # -# Standard correction: `SR.orbit.correct(reference=reference)`. +# Standard correction: `SR.tool.orbit.correct(reference=reference)`. # # Optional variants (uncomment to use): # - **Virtual corrector weight**: down-weights correctors that are already at large strengths. @@ -213,17 +213,17 @@ # Standard correction -SR.orbit.correct(reference=reference) +SR.tool.orbit.correct(reference=reference) # With virtual corrector weight (ESRF style): -# SR.orbit.set_virtual_weight(1000) -# SR.orbit.correct(reference=reference) +# SR.tool.orbit.set_virtual_weight(1000) +# SR.tool.orbit.correct(reference=reference) # With RF orbit correction (ESRF style, requires dispersion in ORM): -# SR.orbit.correct(reference=reference, rf=True) +# SR.tool.orbit.correct(reference=reference, rf=True) # BESSY2 live mode — BPMs in nm, use gain to compensate unit mismatch: -# SR.orbit.correct(reference=reference, gain=1e-9) +# SR.tool.orbit.correct(reference=reference, gain=1e-9) sleep(wait_time) diff --git a/examples/use_cases/README.md b/examples/use_cases/README.md index ebcfe8c99..6bc3076ed 100644 --- a/examples/use_cases/README.md +++ b/examples/use_cases/README.md @@ -89,8 +89,8 @@ In `design` mode all wait times can be set to `0.0`. In `live` mode use `wait_ti | `BPM` | Beam position monitors | | `BETATRON_TUNE` | Betatron tune monitor | | `CHROMATICITY_MONITOR` | Chromaticity monitor | -| `DEFAULT_TUNE_CORRECTION` | Tune correction tool → `SR.tune` | -| `DEFAULT_TUNE_RESPONSE_MATRIX` | Tune response matrix tool → `SR.trm` | -| `DEFAULT_ORBIT_CORRECTION` | Orbit correction tool → `SR.orbit` | -| `DEFAULT_ORBIT_RESPONSE_MATRIX` | Orbit response matrix tool → `SR.orm` | -| `DEFAULT_DISPERSION` | Dispersion measurement tool → `SR.dispersion` | +| `DEFAULT_TUNE_CORRECTION` | Tune correction tool → `SR.tool.tune` | +| `DEFAULT_TUNE_RESPONSE_MATRIX` | Tune response matrix tool → `SR.tool.trm` | +| `DEFAULT_ORBIT_CORRECTION` | Orbit correction tool → `SR.tool.orbit` | +| `DEFAULT_ORBIT_RESPONSE_MATRIX` | Orbit response matrix tool → `SR.tool.orm` | +| `DEFAULT_DISPERSION` | Dispersion measurement tool → `SR.tool.dispersion` | diff --git a/examples/use_cases/config/bessy2/bessy2.yaml b/examples/use_cases/config/bessy2/bessy2.yaml index eb4938153..8d5d1f354 100644 --- a/examples/use_cases/config/bessy2/bessy2.yaml +++ b/examples/use_cases/config/bessy2/bessy2.yaml @@ -1356,495 +1356,495 @@ devices: unit: 1/m powerconverter: (VS3P1D1R:rdbk, VS3P1D1R:set)[A] hardware_unit: A -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5D1R x_pos: ORBITCC:rdPos@0 y_pos: ORBITCC:rdPos@1 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6D1R x_pos: ORBITCC:rdPos@2 y_pos: ORBITCC:rdPos@3 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7D1R x_pos: ORBITCC:rdPos@4 y_pos: ORBITCC:rdPos@5 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1T1R x_pos: ORBITCC:rdPos@6 y_pos: ORBITCC:rdPos@7 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2T1R x_pos: ORBITCC:rdPos@8 y_pos: ORBITCC:rdPos@9 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3T1R x_pos: ORBITCC:rdPos@10 y_pos: ORBITCC:rdPos@11 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4T1R x_pos: ORBITCC:rdPos@12 y_pos: ORBITCC:rdPos@13 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ41T1R x_pos: ORBITCC:rdPos@14 y_pos: ORBITCC:rdPos@15 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5T1R x_pos: ORBITCC:rdPos@16 y_pos: ORBITCC:rdPos@17 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6T1R x_pos: ORBITCC:rdPos@18 y_pos: ORBITCC:rdPos@19 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7T1R x_pos: ORBITCC:rdPos@20 y_pos: ORBITCC:rdPos@21 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1D2R x_pos: ORBITCC:rdPos@22 y_pos: ORBITCC:rdPos@23 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2D2R x_pos: ORBITCC:rdPos@24 y_pos: ORBITCC:rdPos@25 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3D2R x_pos: ORBITCC:rdPos@26 y_pos: ORBITCC:rdPos@27 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4D2R x_pos: ORBITCC:rdPos@28 y_pos: ORBITCC:rdPos@29 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5D2R x_pos: ORBITCC:rdPos@30 y_pos: ORBITCC:rdPos@31 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6D2R x_pos: ORBITCC:rdPos@32 y_pos: ORBITCC:rdPos@33 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7D2R x_pos: ORBITCC:rdPos@34 y_pos: ORBITCC:rdPos@35 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1T2R x_pos: ORBITCC:rdPos@36 y_pos: ORBITCC:rdPos@37 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2T2R x_pos: ORBITCC:rdPos@38 y_pos: ORBITCC:rdPos@39 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3T2R x_pos: ORBITCC:rdPos@40 y_pos: ORBITCC:rdPos@41 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4T2R x_pos: ORBITCC:rdPos@42 y_pos: ORBITCC:rdPos@43 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ41T2R x_pos: ORBITCC:rdPos@44 y_pos: ORBITCC:rdPos@45 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ42T2R x_pos: ORBITCC:rdPos@46 y_pos: ORBITCC:rdPos@47 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ43T2R x_pos: ORBITCC:rdPos@48 y_pos: ORBITCC:rdPos@49 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5T2R x_pos: ORBITCC:rdPos@50 y_pos: ORBITCC:rdPos@51 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6T2R x_pos: ORBITCC:rdPos@52 y_pos: ORBITCC:rdPos@53 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7T2R x_pos: ORBITCC:rdPos@54 y_pos: ORBITCC:rdPos@55 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1D3R x_pos: ORBITCC:rdPos@56 y_pos: ORBITCC:rdPos@57 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2D3R x_pos: ORBITCC:rdPos@58 y_pos: ORBITCC:rdPos@59 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3D3R x_pos: ORBITCC:rdPos@60 y_pos: ORBITCC:rdPos@61 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4D3R x_pos: ORBITCC:rdPos@62 y_pos: ORBITCC:rdPos@63 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5D3R x_pos: ORBITCC:rdPos@64 y_pos: ORBITCC:rdPos@65 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6D3R x_pos: ORBITCC:rdPos@66 y_pos: ORBITCC:rdPos@67 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7D3R x_pos: ORBITCC:rdPos@68 y_pos: ORBITCC:rdPos@69 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1T3R x_pos: ORBITCC:rdPos@70 y_pos: ORBITCC:rdPos@71 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2T3R x_pos: ORBITCC:rdPos@72 y_pos: ORBITCC:rdPos@73 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3T3R x_pos: ORBITCC:rdPos@74 y_pos: ORBITCC:rdPos@75 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4T3R x_pos: ORBITCC:rdPos@76 y_pos: ORBITCC:rdPos@77 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5T3R x_pos: ORBITCC:rdPos@78 y_pos: ORBITCC:rdPos@79 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6T3R x_pos: ORBITCC:rdPos@80 y_pos: ORBITCC:rdPos@81 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7T3R x_pos: ORBITCC:rdPos@82 y_pos: ORBITCC:rdPos@83 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1D4R x_pos: ORBITCC:rdPos@84 y_pos: ORBITCC:rdPos@85 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2D4R x_pos: ORBITCC:rdPos@86 y_pos: ORBITCC:rdPos@87 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3D4R x_pos: ORBITCC:rdPos@88 y_pos: ORBITCC:rdPos@89 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4D4R x_pos: ORBITCC:rdPos@90 y_pos: ORBITCC:rdPos@91 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5D4R x_pos: ORBITCC:rdPos@92 y_pos: ORBITCC:rdPos@93 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6D4R x_pos: ORBITCC:rdPos@94 y_pos: ORBITCC:rdPos@95 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7D4R x_pos: ORBITCC:rdPos@96 y_pos: ORBITCC:rdPos@97 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1T4R x_pos: ORBITCC:rdPos@98 y_pos: ORBITCC:rdPos@99 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2T4R x_pos: ORBITCC:rdPos@100 y_pos: ORBITCC:rdPos@101 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3T4R x_pos: ORBITCC:rdPos@102 y_pos: ORBITCC:rdPos@103 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4T4R x_pos: ORBITCC:rdPos@104 y_pos: ORBITCC:rdPos@105 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5T4R x_pos: ORBITCC:rdPos@106 y_pos: ORBITCC:rdPos@107 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6T4R x_pos: ORBITCC:rdPos@108 y_pos: ORBITCC:rdPos@109 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7T4R x_pos: ORBITCC:rdPos@110 y_pos: ORBITCC:rdPos@111 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1D5R x_pos: ORBITCC:rdPos@112 y_pos: ORBITCC:rdPos@113 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2D5R x_pos: ORBITCC:rdPos@114 y_pos: ORBITCC:rdPos@115 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3D5R x_pos: ORBITCC:rdPos@116 y_pos: ORBITCC:rdPos@117 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4D5R x_pos: ORBITCC:rdPos@118 y_pos: ORBITCC:rdPos@119 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5D5R x_pos: ORBITCC:rdPos@120 y_pos: ORBITCC:rdPos@121 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6D5R x_pos: ORBITCC:rdPos@122 y_pos: ORBITCC:rdPos@123 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7D5R x_pos: ORBITCC:rdPos@124 y_pos: ORBITCC:rdPos@125 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1T5R x_pos: ORBITCC:rdPos@126 y_pos: ORBITCC:rdPos@127 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2T5R x_pos: ORBITCC:rdPos@128 y_pos: ORBITCC:rdPos@129 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3T5R x_pos: ORBITCC:rdPos@130 y_pos: ORBITCC:rdPos@131 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4T5R x_pos: ORBITCC:rdPos@132 y_pos: ORBITCC:rdPos@133 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5T5R x_pos: ORBITCC:rdPos@134 y_pos: ORBITCC:rdPos@135 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6T5R x_pos: ORBITCC:rdPos@136 y_pos: ORBITCC:rdPos@137 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7T5R x_pos: ORBITCC:rdPos@138 y_pos: ORBITCC:rdPos@139 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1D6R x_pos: ORBITCC:rdPos@140 y_pos: ORBITCC:rdPos@141 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2D6R x_pos: ORBITCC:rdPos@142 y_pos: ORBITCC:rdPos@143 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3D6R x_pos: ORBITCC:rdPos@144 y_pos: ORBITCC:rdPos@145 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4D6R x_pos: ORBITCC:rdPos@146 y_pos: ORBITCC:rdPos@147 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ41D6R x_pos: ORBITCC:rdPos@148 y_pos: ORBITCC:rdPos@149 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ42D6R x_pos: ORBITCC:rdPos@150 y_pos: ORBITCC:rdPos@151 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ43D6R x_pos: ORBITCC:rdPos@152 y_pos: ORBITCC:rdPos@153 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ44D6R x_pos: ORBITCC:rdPos@154 y_pos: ORBITCC:rdPos@155 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6D6R x_pos: ORBITCC:rdPos@156 y_pos: ORBITCC:rdPos@157 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7D6R x_pos: ORBITCC:rdPos@158 y_pos: ORBITCC:rdPos@159 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1T6R x_pos: ORBITCC:rdPos@160 y_pos: ORBITCC:rdPos@161 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2T6R x_pos: ORBITCC:rdPos@162 y_pos: ORBITCC:rdPos@163 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3T6R x_pos: ORBITCC:rdPos@164 y_pos: ORBITCC:rdPos@165 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4T6R x_pos: ORBITCC:rdPos@166 y_pos: ORBITCC:rdPos@167 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ41T6R x_pos: ORBITCC:rdPos@168 y_pos: ORBITCC:rdPos@169 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5T6R x_pos: ORBITCC:rdPos@170 y_pos: ORBITCC:rdPos@171 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6T6R x_pos: ORBITCC:rdPos@172 y_pos: ORBITCC:rdPos@173 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7T6R x_pos: ORBITCC:rdPos@174 y_pos: ORBITCC:rdPos@175 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1D7R x_pos: ORBITCC:rdPos@176 y_pos: ORBITCC:rdPos@177 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2D7R x_pos: ORBITCC:rdPos@178 y_pos: ORBITCC:rdPos@179 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3D7R x_pos: ORBITCC:rdPos@180 y_pos: ORBITCC:rdPos@181 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4D7R x_pos: ORBITCC:rdPos@182 y_pos: ORBITCC:rdPos@183 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5D7R x_pos: ORBITCC:rdPos@184 y_pos: ORBITCC:rdPos@185 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6D7R x_pos: ORBITCC:rdPos@186 y_pos: ORBITCC:rdPos@187 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7D7R x_pos: ORBITCC:rdPos@188 y_pos: ORBITCC:rdPos@189 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1T7R x_pos: ORBITCC:rdPos@190 y_pos: ORBITCC:rdPos@191 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2T7R x_pos: ORBITCC:rdPos@192 y_pos: ORBITCC:rdPos@193 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3T7R x_pos: ORBITCC:rdPos@194 y_pos: ORBITCC:rdPos@195 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4T7R x_pos: ORBITCC:rdPos@196 y_pos: ORBITCC:rdPos@197 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ41T7R x_pos: ORBITCC:rdPos@198 y_pos: ORBITCC:rdPos@199 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5T7R x_pos: ORBITCC:rdPos@200 y_pos: ORBITCC:rdPos@201 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6T7R x_pos: ORBITCC:rdPos@202 y_pos: ORBITCC:rdPos@203 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7T7R x_pos: ORBITCC:rdPos@204 y_pos: ORBITCC:rdPos@205 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1D8R x_pos: ORBITCC:rdPos@206 y_pos: ORBITCC:rdPos@207 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2D8R x_pos: ORBITCC:rdPos@208 y_pos: ORBITCC:rdPos@209 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3D8R x_pos: ORBITCC:rdPos@210 y_pos: ORBITCC:rdPos@211 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4D8R x_pos: ORBITCC:rdPos@212 y_pos: ORBITCC:rdPos@213 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5D8R x_pos: ORBITCC:rdPos@214 y_pos: ORBITCC:rdPos@215 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6D8R x_pos: ORBITCC:rdPos@216 y_pos: ORBITCC:rdPos@217 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7D8R x_pos: ORBITCC:rdPos@218 y_pos: ORBITCC:rdPos@219 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1T8R x_pos: ORBITCC:rdPos@220 y_pos: ORBITCC:rdPos@221 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2T8R x_pos: ORBITCC:rdPos@222 y_pos: ORBITCC:rdPos@223 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3T8R x_pos: ORBITCC:rdPos@224 y_pos: ORBITCC:rdPos@225 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4T8R x_pos: ORBITCC:rdPos@226 y_pos: ORBITCC:rdPos@227 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ5T8R x_pos: ORBITCC:rdPos@228 y_pos: ORBITCC:rdPos@229 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ6T8R x_pos: ORBITCC:rdPos@230 y_pos: ORBITCC:rdPos@231 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ7T8R x_pos: ORBITCC:rdPos@232 y_pos: ORBITCC:rdPos@233 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ1D1R x_pos: ORBITCC:rdPos@234 y_pos: ORBITCC:rdPos@235 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ2D1R x_pos: ORBITCC:rdPos@236 y_pos: ORBITCC:rdPos@237 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ3D1R x_pos: ORBITCC:rdPos@238 y_pos: ORBITCC:rdPos@239 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ4D1R x_pos: ORBITCC:rdPos@240 y_pos: ORBITCC:rdPos@241 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ41D1R x_pos: ORBITCC:rdPos@242 y_pos: ORBITCC:rdPos@243 -- class: pyaml.bpm.bpm.BPM +- class: pyaml.diagnostics.bpm.bpm.BPM name: BPMZ42D1R x_pos: ORBITCC:rdPos@244 y_pos: ORBITCC:rdPos@245 diff --git a/examples/use_cases/config/esrf/catalogs/ebs_catalogs.yaml b/examples/use_cases/config/esrf/catalogs/ebs_catalogs.yaml index d15349d6f..b3da9a0d4 100644 --- a/examples/use_cases/config/esrf/catalogs/ebs_catalogs.yaml +++ b/examples/use_cases/config/esrf/catalogs/ebs_catalogs.yaml @@ -1,8 +1,8 @@ type: tango.pyaml.static_catalog entries: - - catalogs/ebs_bpm_catalogs.yaml - - catalogs/ebs_rf_catalogs.yaml - - catalogs/ebs_diag_catalogs.yaml - - catalogs/ebs_magnets_catalogs.yaml - - catalogs/ebs_sh_catalogs.yaml - - catalogs/ebs_sext_catalogs.yaml + - ${include:catalogs/ebs_bpm_catalogs.yaml} + - ${include:catalogs/ebs_rf_catalogs.yaml} + - ${include:catalogs/ebs_diag_catalogs.yaml} + - ${include:catalogs/ebs_magnets_catalogs.yaml} + - ${include:catalogs/ebs_sh_catalogs.yaml} + - ${include:catalogs/ebs_sext_catalogs.yaml} diff --git a/examples/use_cases/config/esrf/esrf.yaml b/examples/use_cases/config/esrf/esrf.yaml index a3bdba75a..bb8a929e0 100644 --- a/examples/use_cases/config/esrf/esrf.yaml +++ b/examples/use_cases/config/esrf/esrf.yaml @@ -11,7 +11,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet @@ -5713,1285 +5713,1285 @@ devices: - srmag/ps-corr-sh3/c03-e-ch3/current - srmag/ps-corr-sh3/c03-e-ch5/current - srmag/ps-corr-sh3/c03-e-ch6/current -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-01 x_pos: srdiag/bpm/c04-01/SA_HPosition y_pos: srdiag/bpm/c04-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-02 x_pos: srdiag/bpm/c04-02/SA_HPosition y_pos: srdiag/bpm/c04-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-03 x_pos: srdiag/bpm/c04-03/SA_HPosition y_pos: srdiag/bpm/c04-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-04 x_pos: srdiag/bpm/c04-04/SA_HPosition y_pos: srdiag/bpm/c04-04/SA_VPosition x_offset: srdiag/bpm/c04-04/HOffset y_offset: srdiag/bpm/c04-04/VOffset -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-05 x_pos: srdiag/bpm/c04-05/SA_HPosition y_pos: srdiag/bpm/c04-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-06 x_pos: srdiag/bpm/c04-06/SA_HPosition y_pos: srdiag/bpm/c04-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-07 x_pos: srdiag/bpm/c04-07/SA_HPosition y_pos: srdiag/bpm/c04-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-08 x_pos: srdiag/bpm/c04-08/SA_HPosition y_pos: srdiag/bpm/c04-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-09 x_pos: srdiag/bpm/c04-09/SA_HPosition y_pos: srdiag/bpm/c04-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-10 x_pos: srdiag/bpm/c04-10/SA_HPosition y_pos: srdiag/bpm/c04-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-01 x_pos: srdiag/bpm/c05-01/SA_HPosition y_pos: srdiag/bpm/c05-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-02 x_pos: srdiag/bpm/c05-02/SA_HPosition y_pos: srdiag/bpm/c05-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-03 x_pos: srdiag/bpm/c05-03/SA_HPosition y_pos: srdiag/bpm/c05-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-04 x_pos: srdiag/bpm/c05-04/SA_HPosition y_pos: srdiag/bpm/c05-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-05 x_pos: srdiag/bpm/c05-05/SA_HPosition y_pos: srdiag/bpm/c05-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-06 x_pos: srdiag/bpm/c05-06/SA_HPosition y_pos: srdiag/bpm/c05-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-07 x_pos: srdiag/bpm/c05-07/SA_HPosition y_pos: srdiag/bpm/c05-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-08 x_pos: srdiag/bpm/c05-08/SA_HPosition y_pos: srdiag/bpm/c05-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-09 x_pos: srdiag/bpm/c05-09/SA_HPosition y_pos: srdiag/bpm/c05-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-10 x_pos: srdiag/bpm/c05-10/SA_HPosition y_pos: srdiag/bpm/c05-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-01 x_pos: srdiag/bpm/c06-01/SA_HPosition y_pos: srdiag/bpm/c06-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-02 x_pos: srdiag/bpm/c06-02/SA_HPosition y_pos: srdiag/bpm/c06-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-03 x_pos: srdiag/bpm/c06-03/SA_HPosition y_pos: srdiag/bpm/c06-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-04 x_pos: srdiag/bpm/c06-04/SA_HPosition y_pos: srdiag/bpm/c06-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-05 x_pos: srdiag/bpm/c06-05/SA_HPosition y_pos: srdiag/bpm/c06-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-06 x_pos: srdiag/bpm/c06-06/SA_HPosition y_pos: srdiag/bpm/c06-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-07 x_pos: srdiag/bpm/c06-07/SA_HPosition y_pos: srdiag/bpm/c06-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-08 x_pos: srdiag/bpm/c06-08/SA_HPosition y_pos: srdiag/bpm/c06-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-09 x_pos: srdiag/bpm/c06-09/SA_HPosition y_pos: srdiag/bpm/c06-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-10 x_pos: srdiag/bpm/c06-10/SA_HPosition y_pos: srdiag/bpm/c06-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-01 x_pos: srdiag/bpm/c07-01/SA_HPosition y_pos: srdiag/bpm/c07-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-02 x_pos: srdiag/bpm/c07-02/SA_HPosition y_pos: srdiag/bpm/c07-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-03 x_pos: srdiag/bpm/c07-03/SA_HPosition y_pos: srdiag/bpm/c07-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-04 x_pos: srdiag/bpm/c07-04/SA_HPosition y_pos: srdiag/bpm/c07-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-05 x_pos: srdiag/bpm/c07-05/SA_HPosition y_pos: srdiag/bpm/c07-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-06 x_pos: srdiag/bpm/c07-06/SA_HPosition y_pos: srdiag/bpm/c07-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-07 x_pos: srdiag/bpm/c07-07/SA_HPosition y_pos: srdiag/bpm/c07-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-08 x_pos: srdiag/bpm/c07-08/SA_HPosition y_pos: srdiag/bpm/c07-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-09 x_pos: srdiag/bpm/c07-09/SA_HPosition y_pos: srdiag/bpm/c07-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-10 x_pos: srdiag/bpm/c07-10/SA_HPosition y_pos: srdiag/bpm/c07-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-01 x_pos: srdiag/bpm/c08-01/SA_HPosition y_pos: srdiag/bpm/c08-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-02 x_pos: srdiag/bpm/c08-02/SA_HPosition y_pos: srdiag/bpm/c08-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-03 x_pos: srdiag/bpm/c08-03/SA_HPosition y_pos: srdiag/bpm/c08-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-04 x_pos: srdiag/bpm/c08-04/SA_HPosition y_pos: srdiag/bpm/c08-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-05 x_pos: srdiag/bpm/c08-05/SA_HPosition y_pos: srdiag/bpm/c08-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-06 x_pos: srdiag/bpm/c08-06/SA_HPosition y_pos: srdiag/bpm/c08-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-07 x_pos: srdiag/bpm/c08-07/SA_HPosition y_pos: srdiag/bpm/c08-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-08 x_pos: srdiag/bpm/c08-08/SA_HPosition y_pos: srdiag/bpm/c08-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-09 x_pos: srdiag/bpm/c08-09/SA_HPosition y_pos: srdiag/bpm/c08-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-10 x_pos: srdiag/bpm/c08-10/SA_HPosition y_pos: srdiag/bpm/c08-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-01 x_pos: srdiag/bpm/c09-01/SA_HPosition y_pos: srdiag/bpm/c09-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-02 x_pos: srdiag/bpm/c09-02/SA_HPosition y_pos: srdiag/bpm/c09-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-03 x_pos: srdiag/bpm/c09-03/SA_HPosition y_pos: srdiag/bpm/c09-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-04 x_pos: srdiag/bpm/c09-04/SA_HPosition y_pos: srdiag/bpm/c09-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-05 x_pos: srdiag/bpm/c09-05/SA_HPosition y_pos: srdiag/bpm/c09-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-06 x_pos: srdiag/bpm/c09-06/SA_HPosition y_pos: srdiag/bpm/c09-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-07 x_pos: srdiag/bpm/c09-07/SA_HPosition y_pos: srdiag/bpm/c09-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-08 x_pos: srdiag/bpm/c09-08/SA_HPosition y_pos: srdiag/bpm/c09-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-09 x_pos: srdiag/bpm/c09-09/SA_HPosition y_pos: srdiag/bpm/c09-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-10 x_pos: srdiag/bpm/c09-10/SA_HPosition y_pos: srdiag/bpm/c09-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-01 x_pos: srdiag/bpm/c10-01/SA_HPosition y_pos: srdiag/bpm/c10-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-02 x_pos: srdiag/bpm/c10-02/SA_HPosition y_pos: srdiag/bpm/c10-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-03 x_pos: srdiag/bpm/c10-03/SA_HPosition y_pos: srdiag/bpm/c10-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-04 x_pos: srdiag/bpm/c10-04/SA_HPosition y_pos: srdiag/bpm/c10-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-05 x_pos: srdiag/bpm/c10-05/SA_HPosition y_pos: srdiag/bpm/c10-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-06 x_pos: srdiag/bpm/c10-06/SA_HPosition y_pos: srdiag/bpm/c10-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-07 x_pos: srdiag/bpm/c10-07/SA_HPosition y_pos: srdiag/bpm/c10-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-08 x_pos: srdiag/bpm/c10-08/SA_HPosition y_pos: srdiag/bpm/c10-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-09 x_pos: srdiag/bpm/c10-09/SA_HPosition y_pos: srdiag/bpm/c10-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-10 x_pos: srdiag/bpm/c10-10/SA_HPosition y_pos: srdiag/bpm/c10-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-01 x_pos: srdiag/bpm/c11-01/SA_HPosition y_pos: srdiag/bpm/c11-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-02 x_pos: srdiag/bpm/c11-02/SA_HPosition y_pos: srdiag/bpm/c11-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-03 x_pos: srdiag/bpm/c11-03/SA_HPosition y_pos: srdiag/bpm/c11-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-04 x_pos: srdiag/bpm/c11-04/SA_HPosition y_pos: srdiag/bpm/c11-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-05 x_pos: srdiag/bpm/c11-05/SA_HPosition y_pos: srdiag/bpm/c11-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-06 x_pos: srdiag/bpm/c11-06/SA_HPosition y_pos: srdiag/bpm/c11-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-07 x_pos: srdiag/bpm/c11-07/SA_HPosition y_pos: srdiag/bpm/c11-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-08 x_pos: srdiag/bpm/c11-08/SA_HPosition y_pos: srdiag/bpm/c11-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-09 x_pos: srdiag/bpm/c11-09/SA_HPosition y_pos: srdiag/bpm/c11-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-10 x_pos: srdiag/bpm/c11-10/SA_HPosition y_pos: srdiag/bpm/c11-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-01 x_pos: srdiag/bpm/c12-01/SA_HPosition y_pos: srdiag/bpm/c12-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-02 x_pos: srdiag/bpm/c12-02/SA_HPosition y_pos: srdiag/bpm/c12-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-03 x_pos: srdiag/bpm/c12-03/SA_HPosition y_pos: srdiag/bpm/c12-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-04 x_pos: srdiag/bpm/c12-04/SA_HPosition y_pos: srdiag/bpm/c12-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-05 x_pos: srdiag/bpm/c12-05/SA_HPosition y_pos: srdiag/bpm/c12-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-06 x_pos: srdiag/bpm/c12-06/SA_HPosition y_pos: srdiag/bpm/c12-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-07 x_pos: srdiag/bpm/c12-07/SA_HPosition y_pos: srdiag/bpm/c12-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-08 x_pos: srdiag/bpm/c12-08/SA_HPosition y_pos: srdiag/bpm/c12-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-09 x_pos: srdiag/bpm/c12-09/SA_HPosition y_pos: srdiag/bpm/c12-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-10 x_pos: srdiag/bpm/c12-10/SA_HPosition y_pos: srdiag/bpm/c12-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-01 x_pos: srdiag/bpm/c13-01/SA_HPosition y_pos: srdiag/bpm/c13-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-02 x_pos: srdiag/bpm/c13-02/SA_HPosition y_pos: srdiag/bpm/c13-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-03 x_pos: srdiag/bpm/c13-03/SA_HPosition y_pos: srdiag/bpm/c13-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-04 x_pos: srdiag/bpm/c13-04/SA_HPosition y_pos: srdiag/bpm/c13-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-05 x_pos: srdiag/bpm/c13-05/SA_HPosition y_pos: srdiag/bpm/c13-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-06 x_pos: srdiag/bpm/c13-06/SA_HPosition y_pos: srdiag/bpm/c13-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-07 x_pos: srdiag/bpm/c13-07/SA_HPosition y_pos: srdiag/bpm/c13-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-08 x_pos: srdiag/bpm/c13-08/SA_HPosition y_pos: srdiag/bpm/c13-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-09 x_pos: srdiag/bpm/c13-09/SA_HPosition y_pos: srdiag/bpm/c13-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-10 x_pos: srdiag/bpm/c13-10/SA_HPosition y_pos: srdiag/bpm/c13-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-01 x_pos: srdiag/bpm/c14-01/SA_HPosition y_pos: srdiag/bpm/c14-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-02 x_pos: srdiag/bpm/c14-02/SA_HPosition y_pos: srdiag/bpm/c14-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-03 x_pos: srdiag/bpm/c14-03/SA_HPosition y_pos: srdiag/bpm/c14-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-04 x_pos: srdiag/bpm/c14-04/SA_HPosition y_pos: srdiag/bpm/c14-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-05 x_pos: srdiag/bpm/c14-05/SA_HPosition y_pos: srdiag/bpm/c14-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-06 x_pos: srdiag/bpm/c14-06/SA_HPosition y_pos: srdiag/bpm/c14-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-07 x_pos: srdiag/bpm/c14-07/SA_HPosition y_pos: srdiag/bpm/c14-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-08 x_pos: srdiag/bpm/c14-08/SA_HPosition y_pos: srdiag/bpm/c14-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-09 x_pos: srdiag/bpm/c14-09/SA_HPosition y_pos: srdiag/bpm/c14-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-10 x_pos: srdiag/bpm/c14-10/SA_HPosition y_pos: srdiag/bpm/c14-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-01 x_pos: srdiag/bpm/c15-01/SA_HPosition y_pos: srdiag/bpm/c15-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-02 x_pos: srdiag/bpm/c15-02/SA_HPosition y_pos: srdiag/bpm/c15-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-03 x_pos: srdiag/bpm/c15-03/SA_HPosition y_pos: srdiag/bpm/c15-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-04 x_pos: srdiag/bpm/c15-04/SA_HPosition y_pos: srdiag/bpm/c15-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-05 x_pos: srdiag/bpm/c15-05/SA_HPosition y_pos: srdiag/bpm/c15-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-06 x_pos: srdiag/bpm/c15-06/SA_HPosition y_pos: srdiag/bpm/c15-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-07 x_pos: srdiag/bpm/c15-07/SA_HPosition y_pos: srdiag/bpm/c15-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-08 x_pos: srdiag/bpm/c15-08/SA_HPosition y_pos: srdiag/bpm/c15-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-09 x_pos: srdiag/bpm/c15-09/SA_HPosition y_pos: srdiag/bpm/c15-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-10 x_pos: srdiag/bpm/c15-10/SA_HPosition y_pos: srdiag/bpm/c15-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-01 x_pos: srdiag/bpm/c16-01/SA_HPosition y_pos: srdiag/bpm/c16-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-02 x_pos: srdiag/bpm/c16-02/SA_HPosition y_pos: srdiag/bpm/c16-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-03 x_pos: srdiag/bpm/c16-03/SA_HPosition y_pos: srdiag/bpm/c16-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-04 x_pos: srdiag/bpm/c16-04/SA_HPosition y_pos: srdiag/bpm/c16-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-05 x_pos: srdiag/bpm/c16-05/SA_HPosition y_pos: srdiag/bpm/c16-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-06 x_pos: srdiag/bpm/c16-06/SA_HPosition y_pos: srdiag/bpm/c16-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-07 x_pos: srdiag/bpm/c16-07/SA_HPosition y_pos: srdiag/bpm/c16-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-08 x_pos: srdiag/bpm/c16-08/SA_HPosition y_pos: srdiag/bpm/c16-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-09 x_pos: srdiag/bpm/c16-09/SA_HPosition y_pos: srdiag/bpm/c16-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-10 x_pos: srdiag/bpm/c16-10/SA_HPosition y_pos: srdiag/bpm/c16-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-01 x_pos: srdiag/bpm/c17-01/SA_HPosition y_pos: srdiag/bpm/c17-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-02 x_pos: srdiag/bpm/c17-02/SA_HPosition y_pos: srdiag/bpm/c17-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-03 x_pos: srdiag/bpm/c17-03/SA_HPosition y_pos: srdiag/bpm/c17-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-04 x_pos: srdiag/bpm/c17-04/SA_HPosition y_pos: srdiag/bpm/c17-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-05 x_pos: srdiag/bpm/c17-05/SA_HPosition y_pos: srdiag/bpm/c17-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-06 x_pos: srdiag/bpm/c17-06/SA_HPosition y_pos: srdiag/bpm/c17-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-07 x_pos: srdiag/bpm/c17-07/SA_HPosition y_pos: srdiag/bpm/c17-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-08 x_pos: srdiag/bpm/c17-08/SA_HPosition y_pos: srdiag/bpm/c17-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-09 x_pos: srdiag/bpm/c17-09/SA_HPosition y_pos: srdiag/bpm/c17-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-10 x_pos: srdiag/bpm/c17-10/SA_HPosition y_pos: srdiag/bpm/c17-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-01 x_pos: srdiag/bpm/c18-01/SA_HPosition y_pos: srdiag/bpm/c18-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-02 x_pos: srdiag/bpm/c18-02/SA_HPosition y_pos: srdiag/bpm/c18-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-03 x_pos: srdiag/bpm/c18-03/SA_HPosition y_pos: srdiag/bpm/c18-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-04 x_pos: srdiag/bpm/c18-04/SA_HPosition y_pos: srdiag/bpm/c18-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-05 x_pos: srdiag/bpm/c18-05/SA_HPosition y_pos: srdiag/bpm/c18-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-06 x_pos: srdiag/bpm/c18-06/SA_HPosition y_pos: srdiag/bpm/c18-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-07 x_pos: srdiag/bpm/c18-07/SA_HPosition y_pos: srdiag/bpm/c18-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-08 x_pos: srdiag/bpm/c18-08/SA_HPosition y_pos: srdiag/bpm/c18-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-09 x_pos: srdiag/bpm/c18-09/SA_HPosition y_pos: srdiag/bpm/c18-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-10 x_pos: srdiag/bpm/c18-10/SA_HPosition y_pos: srdiag/bpm/c18-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-01 x_pos: srdiag/bpm/c19-01/SA_HPosition y_pos: srdiag/bpm/c19-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-02 x_pos: srdiag/bpm/c19-02/SA_HPosition y_pos: srdiag/bpm/c19-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-03 x_pos: srdiag/bpm/c19-03/SA_HPosition y_pos: srdiag/bpm/c19-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-04 x_pos: srdiag/bpm/c19-04/SA_HPosition y_pos: srdiag/bpm/c19-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-05 x_pos: srdiag/bpm/c19-05/SA_HPosition y_pos: srdiag/bpm/c19-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-06 x_pos: srdiag/bpm/c19-06/SA_HPosition y_pos: srdiag/bpm/c19-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-07 x_pos: srdiag/bpm/c19-07/SA_HPosition y_pos: srdiag/bpm/c19-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-08 x_pos: srdiag/bpm/c19-08/SA_HPosition y_pos: srdiag/bpm/c19-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-09 x_pos: srdiag/bpm/c19-09/SA_HPosition y_pos: srdiag/bpm/c19-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-10 x_pos: srdiag/bpm/c19-10/SA_HPosition y_pos: srdiag/bpm/c19-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-01 x_pos: srdiag/bpm/c20-01/SA_HPosition y_pos: srdiag/bpm/c20-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-02 x_pos: srdiag/bpm/c20-02/SA_HPosition y_pos: srdiag/bpm/c20-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-03 x_pos: srdiag/bpm/c20-03/SA_HPosition y_pos: srdiag/bpm/c20-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-04 x_pos: srdiag/bpm/c20-04/SA_HPosition y_pos: srdiag/bpm/c20-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-05 x_pos: srdiag/bpm/c20-05/SA_HPosition y_pos: srdiag/bpm/c20-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-06 x_pos: srdiag/bpm/c20-06/SA_HPosition y_pos: srdiag/bpm/c20-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-07 x_pos: srdiag/bpm/c20-07/SA_HPosition y_pos: srdiag/bpm/c20-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-08 x_pos: srdiag/bpm/c20-08/SA_HPosition y_pos: srdiag/bpm/c20-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-09 x_pos: srdiag/bpm/c20-09/SA_HPosition y_pos: srdiag/bpm/c20-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-10 x_pos: srdiag/bpm/c20-10/SA_HPosition y_pos: srdiag/bpm/c20-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-01 x_pos: srdiag/bpm/c21-01/SA_HPosition y_pos: srdiag/bpm/c21-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-02 x_pos: srdiag/bpm/c21-02/SA_HPosition y_pos: srdiag/bpm/c21-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-03 x_pos: srdiag/bpm/c21-03/SA_HPosition y_pos: srdiag/bpm/c21-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-04 x_pos: srdiag/bpm/c21-04/SA_HPosition y_pos: srdiag/bpm/c21-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-05 x_pos: srdiag/bpm/c21-05/SA_HPosition y_pos: srdiag/bpm/c21-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-06 x_pos: srdiag/bpm/c21-06/SA_HPosition y_pos: srdiag/bpm/c21-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-07 x_pos: srdiag/bpm/c21-07/SA_HPosition y_pos: srdiag/bpm/c21-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-08 x_pos: srdiag/bpm/c21-08/SA_HPosition y_pos: srdiag/bpm/c21-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-09 x_pos: srdiag/bpm/c21-09/SA_HPosition y_pos: srdiag/bpm/c21-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-10 x_pos: srdiag/bpm/c21-10/SA_HPosition y_pos: srdiag/bpm/c21-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-01 x_pos: srdiag/bpm/c22-01/SA_HPosition y_pos: srdiag/bpm/c22-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-02 x_pos: srdiag/bpm/c22-02/SA_HPosition y_pos: srdiag/bpm/c22-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-03 x_pos: srdiag/bpm/c22-03/SA_HPosition y_pos: srdiag/bpm/c22-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-04 x_pos: srdiag/bpm/c22-04/SA_HPosition y_pos: srdiag/bpm/c22-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-05 x_pos: srdiag/bpm/c22-05/SA_HPosition y_pos: srdiag/bpm/c22-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-06 x_pos: srdiag/bpm/c22-06/SA_HPosition y_pos: srdiag/bpm/c22-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-07 x_pos: srdiag/bpm/c22-07/SA_HPosition y_pos: srdiag/bpm/c22-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-08 x_pos: srdiag/bpm/c22-08/SA_HPosition y_pos: srdiag/bpm/c22-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-09 x_pos: srdiag/bpm/c22-09/SA_HPosition y_pos: srdiag/bpm/c22-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-10 x_pos: srdiag/bpm/c22-10/SA_HPosition y_pos: srdiag/bpm/c22-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-01 x_pos: srdiag/bpm/c23-01/SA_HPosition y_pos: srdiag/bpm/c23-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-02 x_pos: srdiag/bpm/c23-02/SA_HPosition y_pos: srdiag/bpm/c23-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-03 x_pos: srdiag/bpm/c23-03/SA_HPosition y_pos: srdiag/bpm/c23-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-04 x_pos: srdiag/bpm/c23-04/SA_HPosition y_pos: srdiag/bpm/c23-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-05 x_pos: srdiag/bpm/c23-05/SA_HPosition y_pos: srdiag/bpm/c23-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-06 x_pos: srdiag/bpm/c23-06/SA_HPosition y_pos: srdiag/bpm/c23-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-07 x_pos: srdiag/bpm/c23-07/SA_HPosition y_pos: srdiag/bpm/c23-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-08 x_pos: srdiag/bpm/c23-08/SA_HPosition y_pos: srdiag/bpm/c23-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-09 x_pos: srdiag/bpm/c23-09/SA_HPosition y_pos: srdiag/bpm/c23-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-10 x_pos: srdiag/bpm/c23-10/SA_HPosition y_pos: srdiag/bpm/c23-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-01 x_pos: srdiag/bpm/c24-01/SA_HPosition y_pos: srdiag/bpm/c24-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-02 x_pos: srdiag/bpm/c24-02/SA_HPosition y_pos: srdiag/bpm/c24-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-03 x_pos: srdiag/bpm/c24-03/SA_HPosition y_pos: srdiag/bpm/c24-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-04 x_pos: srdiag/bpm/c24-04/SA_HPosition y_pos: srdiag/bpm/c24-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-05 x_pos: srdiag/bpm/c24-05/SA_HPosition y_pos: srdiag/bpm/c24-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-06 x_pos: srdiag/bpm/c24-06/SA_HPosition y_pos: srdiag/bpm/c24-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-07 x_pos: srdiag/bpm/c24-07/SA_HPosition y_pos: srdiag/bpm/c24-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-08 x_pos: srdiag/bpm/c24-08/SA_HPosition y_pos: srdiag/bpm/c24-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-09 x_pos: srdiag/bpm/c24-09/SA_HPosition y_pos: srdiag/bpm/c24-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-10 x_pos: srdiag/bpm/c24-10/SA_HPosition y_pos: srdiag/bpm/c24-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-01 x_pos: srdiag/bpm/c25-01/SA_HPosition y_pos: srdiag/bpm/c25-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-02 x_pos: srdiag/bpm/c25-02/SA_HPosition y_pos: srdiag/bpm/c25-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-03 x_pos: srdiag/bpm/c25-03/SA_HPosition y_pos: srdiag/bpm/c25-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-04 x_pos: srdiag/bpm/c25-04/SA_HPosition y_pos: srdiag/bpm/c25-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-05 x_pos: srdiag/bpm/c25-05/SA_HPosition y_pos: srdiag/bpm/c25-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-06 x_pos: srdiag/bpm/c25-06/SA_HPosition y_pos: srdiag/bpm/c25-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-07 x_pos: srdiag/bpm/c25-07/SA_HPosition y_pos: srdiag/bpm/c25-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-08 x_pos: srdiag/bpm/c25-08/SA_HPosition y_pos: srdiag/bpm/c25-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-09 x_pos: srdiag/bpm/c25-09/SA_HPosition y_pos: srdiag/bpm/c25-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-10 x_pos: srdiag/bpm/c25-10/SA_HPosition y_pos: srdiag/bpm/c25-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-01 x_pos: srdiag/bpm/c26-01/SA_HPosition y_pos: srdiag/bpm/c26-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-02 x_pos: srdiag/bpm/c26-02/SA_HPosition y_pos: srdiag/bpm/c26-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-03 x_pos: srdiag/bpm/c26-03/SA_HPosition y_pos: srdiag/bpm/c26-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-04 x_pos: srdiag/bpm/c26-04/SA_HPosition y_pos: srdiag/bpm/c26-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-05 x_pos: srdiag/bpm/c26-05/SA_HPosition y_pos: srdiag/bpm/c26-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-06 x_pos: srdiag/bpm/c26-06/SA_HPosition y_pos: srdiag/bpm/c26-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-07 x_pos: srdiag/bpm/c26-07/SA_HPosition y_pos: srdiag/bpm/c26-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-08 x_pos: srdiag/bpm/c26-08/SA_HPosition y_pos: srdiag/bpm/c26-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-09 x_pos: srdiag/bpm/c26-09/SA_HPosition y_pos: srdiag/bpm/c26-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-10 x_pos: srdiag/bpm/c26-10/SA_HPosition y_pos: srdiag/bpm/c26-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-01 x_pos: srdiag/bpm/c27-01/SA_HPosition y_pos: srdiag/bpm/c27-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-02 x_pos: srdiag/bpm/c27-02/SA_HPosition y_pos: srdiag/bpm/c27-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-03 x_pos: srdiag/bpm/c27-03/SA_HPosition y_pos: srdiag/bpm/c27-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-04 x_pos: srdiag/bpm/c27-04/SA_HPosition y_pos: srdiag/bpm/c27-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-05 x_pos: srdiag/bpm/c27-05/SA_HPosition y_pos: srdiag/bpm/c27-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-06 x_pos: srdiag/bpm/c27-06/SA_HPosition y_pos: srdiag/bpm/c27-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-07 x_pos: srdiag/bpm/c27-07/SA_HPosition y_pos: srdiag/bpm/c27-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-08 x_pos: srdiag/bpm/c27-08/SA_HPosition y_pos: srdiag/bpm/c27-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-09 x_pos: srdiag/bpm/c27-09/SA_HPosition y_pos: srdiag/bpm/c27-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-10 x_pos: srdiag/bpm/c27-10/SA_HPosition y_pos: srdiag/bpm/c27-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-01 x_pos: srdiag/bpm/c28-01/SA_HPosition y_pos: srdiag/bpm/c28-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-02 x_pos: srdiag/bpm/c28-02/SA_HPosition y_pos: srdiag/bpm/c28-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-03 x_pos: srdiag/bpm/c28-03/SA_HPosition y_pos: srdiag/bpm/c28-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-04 x_pos: srdiag/bpm/c28-04/SA_HPosition y_pos: srdiag/bpm/c28-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-05 x_pos: srdiag/bpm/c28-05/SA_HPosition y_pos: srdiag/bpm/c28-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-06 x_pos: srdiag/bpm/c28-06/SA_HPosition y_pos: srdiag/bpm/c28-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-07 x_pos: srdiag/bpm/c28-07/SA_HPosition y_pos: srdiag/bpm/c28-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-08 x_pos: srdiag/bpm/c28-08/SA_HPosition y_pos: srdiag/bpm/c28-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-09 x_pos: srdiag/bpm/c28-09/SA_HPosition y_pos: srdiag/bpm/c28-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-10 x_pos: srdiag/bpm/c28-10/SA_HPosition y_pos: srdiag/bpm/c28-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-01 x_pos: srdiag/bpm/c29-01/SA_HPosition y_pos: srdiag/bpm/c29-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-02 x_pos: srdiag/bpm/c29-02/SA_HPosition y_pos: srdiag/bpm/c29-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-03 x_pos: srdiag/bpm/c29-03/SA_HPosition y_pos: srdiag/bpm/c29-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-04 x_pos: srdiag/bpm/c29-04/SA_HPosition y_pos: srdiag/bpm/c29-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-05 x_pos: srdiag/bpm/c29-05/SA_HPosition y_pos: srdiag/bpm/c29-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-06 x_pos: srdiag/bpm/c29-06/SA_HPosition y_pos: srdiag/bpm/c29-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-07 x_pos: srdiag/bpm/c29-07/SA_HPosition y_pos: srdiag/bpm/c29-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-08 x_pos: srdiag/bpm/c29-08/SA_HPosition y_pos: srdiag/bpm/c29-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-09 x_pos: srdiag/bpm/c29-09/SA_HPosition y_pos: srdiag/bpm/c29-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-10 x_pos: srdiag/bpm/c29-10/SA_HPosition y_pos: srdiag/bpm/c29-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-01 x_pos: srdiag/bpm/c30-01/SA_HPosition y_pos: srdiag/bpm/c30-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-02 x_pos: srdiag/bpm/c30-02/SA_HPosition y_pos: srdiag/bpm/c30-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-03 x_pos: srdiag/bpm/c30-03/SA_HPosition y_pos: srdiag/bpm/c30-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-04 x_pos: srdiag/bpm/c30-04/SA_HPosition y_pos: srdiag/bpm/c30-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-05 x_pos: srdiag/bpm/c30-05/SA_HPosition y_pos: srdiag/bpm/c30-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-06 x_pos: srdiag/bpm/c30-06/SA_HPosition y_pos: srdiag/bpm/c30-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-07 x_pos: srdiag/bpm/c30-07/SA_HPosition y_pos: srdiag/bpm/c30-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-08 x_pos: srdiag/bpm/c30-08/SA_HPosition y_pos: srdiag/bpm/c30-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-09 x_pos: srdiag/bpm/c30-09/SA_HPosition y_pos: srdiag/bpm/c30-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-10 x_pos: srdiag/bpm/c30-10/SA_HPosition y_pos: srdiag/bpm/c30-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-01 x_pos: srdiag/bpm/c31-01/SA_HPosition y_pos: srdiag/bpm/c31-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-02 x_pos: srdiag/bpm/c31-02/SA_HPosition y_pos: srdiag/bpm/c31-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-03 x_pos: srdiag/bpm/c31-03/SA_HPosition y_pos: srdiag/bpm/c31-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-04 x_pos: srdiag/bpm/c31-04/SA_HPosition y_pos: srdiag/bpm/c31-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-05 x_pos: srdiag/bpm/c31-05/SA_HPosition y_pos: srdiag/bpm/c31-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-06 x_pos: srdiag/bpm/c31-06/SA_HPosition y_pos: srdiag/bpm/c31-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-07 x_pos: srdiag/bpm/c31-07/SA_HPosition y_pos: srdiag/bpm/c31-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-08 x_pos: srdiag/bpm/c31-08/SA_HPosition y_pos: srdiag/bpm/c31-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-09 x_pos: srdiag/bpm/c31-09/SA_HPosition y_pos: srdiag/bpm/c31-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-10 x_pos: srdiag/bpm/c31-10/SA_HPosition y_pos: srdiag/bpm/c31-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-01 x_pos: srdiag/bpm/c32-01/SA_HPosition y_pos: srdiag/bpm/c32-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-02 x_pos: srdiag/bpm/c32-02/SA_HPosition y_pos: srdiag/bpm/c32-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-03 x_pos: srdiag/bpm/c32-03/SA_HPosition y_pos: srdiag/bpm/c32-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-04 x_pos: srdiag/bpm/c32-04/SA_HPosition y_pos: srdiag/bpm/c32-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-05 x_pos: srdiag/bpm/c32-05/SA_HPosition y_pos: srdiag/bpm/c32-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-06 x_pos: srdiag/bpm/c32-06/SA_HPosition y_pos: srdiag/bpm/c32-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-07 x_pos: srdiag/bpm/c32-07/SA_HPosition y_pos: srdiag/bpm/c32-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-08 x_pos: srdiag/bpm/c32-08/SA_HPosition y_pos: srdiag/bpm/c32-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-09 x_pos: srdiag/bpm/c32-09/SA_HPosition y_pos: srdiag/bpm/c32-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-10 x_pos: srdiag/bpm/c32-10/SA_HPosition y_pos: srdiag/bpm/c32-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-01 x_pos: srdiag/bpm/c01-01/SA_HPosition y_pos: srdiag/bpm/c01-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-02 x_pos: srdiag/bpm/c01-02/SA_HPosition y_pos: srdiag/bpm/c01-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-03 x_pos: srdiag/bpm/c01-03/SA_HPosition y_pos: srdiag/bpm/c01-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-04 x_pos: srdiag/bpm/c01-04/SA_HPosition y_pos: srdiag/bpm/c01-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-05 x_pos: srdiag/bpm/c01-05/SA_HPosition y_pos: srdiag/bpm/c01-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-06 x_pos: srdiag/bpm/c01-06/SA_HPosition y_pos: srdiag/bpm/c01-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-07 x_pos: srdiag/bpm/c01-07/SA_HPosition y_pos: srdiag/bpm/c01-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-08 x_pos: srdiag/bpm/c01-08/SA_HPosition y_pos: srdiag/bpm/c01-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-09 x_pos: srdiag/bpm/c01-09/SA_HPosition y_pos: srdiag/bpm/c01-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-10 x_pos: srdiag/bpm/c01-10/SA_HPosition y_pos: srdiag/bpm/c01-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-01 x_pos: srdiag/bpm/c02-01/SA_HPosition y_pos: srdiag/bpm/c02-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-02 x_pos: srdiag/bpm/c02-02/SA_HPosition y_pos: srdiag/bpm/c02-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-03 x_pos: srdiag/bpm/c02-03/SA_HPosition y_pos: srdiag/bpm/c02-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-04 x_pos: srdiag/bpm/c02-04/SA_HPosition y_pos: srdiag/bpm/c02-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-05 x_pos: srdiag/bpm/c02-05/SA_HPosition y_pos: srdiag/bpm/c02-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-06 x_pos: srdiag/bpm/c02-06/SA_HPosition y_pos: srdiag/bpm/c02-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-07 x_pos: srdiag/bpm/c02-07/SA_HPosition y_pos: srdiag/bpm/c02-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-08 x_pos: srdiag/bpm/c02-08/SA_HPosition y_pos: srdiag/bpm/c02-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-09 x_pos: srdiag/bpm/c02-09/SA_HPosition y_pos: srdiag/bpm/c02-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-10 x_pos: srdiag/bpm/c02-10/SA_HPosition y_pos: srdiag/bpm/c02-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-01 x_pos: srdiag/bpm/c03-01/SA_HPosition y_pos: srdiag/bpm/c03-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-02 x_pos: srdiag/bpm/c03-02/SA_HPosition y_pos: srdiag/bpm/c03-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-03 x_pos: srdiag/bpm/c03-03/SA_HPosition y_pos: srdiag/bpm/c03-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-04 x_pos: srdiag/bpm/c03-04/SA_HPosition y_pos: srdiag/bpm/c03-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-05 x_pos: srdiag/bpm/c03-05/SA_HPosition y_pos: srdiag/bpm/c03-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-06 x_pos: srdiag/bpm/c03-06/SA_HPosition y_pos: srdiag/bpm/c03-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-07 x_pos: srdiag/bpm/c03-07/SA_HPosition y_pos: srdiag/bpm/c03-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-08 x_pos: srdiag/bpm/c03-08/SA_HPosition y_pos: srdiag/bpm/c03-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-09 x_pos: srdiag/bpm/c03-09/SA_HPosition y_pos: srdiag/bpm/c03-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-10 x_pos: srdiag/bpm/c03-10/SA_HPosition y_pos: srdiag/bpm/c03-10/SA_VPosition diff --git a/examples/use_cases/config/soleil_ii/devices.yaml b/examples/use_cases/config/soleil_ii/devices.yaml index e75b0954a..c19b50ada 100644 --- a/examples/use_cases/config/soleil_ii/devices.yaml +++ b/examples/use_cases/config/soleil_ii/devices.yaml @@ -1,4 +1,4 @@ -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_001 x_pos: AN01-SD/DG-EPOS/BPM.02/x_pos y_pos: AN01-SD/DG-EPOS/BPM.02/y_pos @@ -54,7 +54,7 @@ physics: - AN01-AR/EM-OCT/OH.02/strength - AN01-AR/EM-COR/OH.02-CQLN.02/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_002 x_pos: AN01-AR/DG-EPOS/BPM.03/x_pos y_pos: AN01-AR/DG-EPOS/BPM.03/y_pos @@ -108,7 +108,7 @@ physics: - AN01-AR/EM-SX/SCF.02/strength - AN01-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_003 x_pos: AN01-AR/DG-EPOS/BPM.04/x_pos y_pos: AN01-AR/DG-EPOS/BPM.04/y_pos @@ -168,7 +168,7 @@ physics: - AN01-AR/EM-SX/SCF.05/strength - AN01-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_004 x_pos: AN01-AR/DG-EPOS/BPM.05/x_pos y_pos: AN01-AR/DG-EPOS/BPM.05/y_pos @@ -228,7 +228,7 @@ physics: - AN01-AR/EM-SX/SCF.08/strength - AN01-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_005 x_pos: AN01-AR/DG-EPOS/BPM.06/x_pos y_pos: AN01-AR/DG-EPOS/BPM.06/y_pos @@ -288,7 +288,7 @@ - AN01-AR/EM-OCT/OC.04/strength - AN01-AR/EM-COR/OC.04-CQLN.13/strength - AN01-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_006 x_pos: AN01-AR/DG-EPOS/BPM.07/x_pos y_pos: AN01-AR/DG-EPOS/BPM.07/y_pos @@ -348,7 +348,7 @@ - AN01-AR/EM-OCT/OC.05/strength - AN01-AR/EM-COR/OC.05-CQLN.16/strength - AN01-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_007 x_pos: AN01-AR/DG-EPOS/BPM.08/x_pos y_pos: AN01-AR/DG-EPOS/BPM.08/y_pos @@ -420,7 +420,7 @@ physics: - AN01-AR/EM-SX/SCD.18/strength - AN01-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_008 x_pos: AN01-AR/DG-EPOS/BPM.09/x_pos y_pos: AN01-AR/DG-EPOS/BPM.09/y_pos @@ -462,7 +462,7 @@ physics: - AN01-AR/EM-OCT/OH.03/strength - AN01-AR/EM-COR/OH.03-CQLN.21/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_009 x_pos: AN01-AR/DG-EPOS/BPM.10/x_pos y_pos: AN01-AR/DG-EPOS/BPM.10/y_pos @@ -494,11 +494,11 @@ - AN01-AR/EM-OCT/OH.04/strength - AN01-AR/EM-COR/OH.04-CQLN.22/strength - AN01-AR/EM-COR/OH.04-CQLT.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_010 x_pos: AN02-SD/DG-EPOS/BPM.01/x_pos y_pos: AN02-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_011 x_pos: AN02-SD/DG-EPOS/BPM.02/x_pos y_pos: AN02-SD/DG-EPOS/BPM.02/y_pos @@ -530,7 +530,7 @@ - AN02-AR/EM-SX/SHF.01/strength - AN02-AR/EM-COR/SHF.01-CDLH.01/strength - AN02-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_012 x_pos: AN02-AR/DG-EPOS/BPM.03/x_pos y_pos: AN02-AR/DG-EPOS/BPM.03/y_pos @@ -604,7 +604,7 @@ physics: - AN02-AR/EM-SX/SCF.02/strength - AN02-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_013 x_pos: AN02-AR/DG-EPOS/BPM.04/x_pos y_pos: AN02-AR/DG-EPOS/BPM.04/y_pos @@ -664,7 +664,7 @@ physics: - AN02-AR/EM-SX/SCF.05/strength - AN02-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_014 x_pos: AN02-AR/DG-EPOS/BPM.05/x_pos y_pos: AN02-AR/DG-EPOS/BPM.05/y_pos @@ -736,7 +736,7 @@ physics: - AN02-AR/EM-SX/SCD.09/strength - AN02-AR/EM-COR/SCD.09-CDLV.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_015 x_pos: AN02-AR/DG-EPOS/BPM.06/x_pos y_pos: AN02-AR/DG-EPOS/BPM.06/y_pos @@ -772,7 +772,7 @@ type: pyaml.magnet.identity_model unit: 1/m physics: AN02-AR/EM-COR/CQLN.12/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_016 x_pos: AN02-AR/DG-EPOS/BPM.07/x_pos y_pos: AN02-AR/DG-EPOS/BPM.07/y_pos @@ -804,11 +804,11 @@ - AN02-AR/EM-OCT/OH.03/strength - AN02-AR/EM-COR/OH.03-CQLN.13/strength - AN02-AR/EM-COR/OH.03-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_017 x_pos: AN03-SD/DG-EPOS/BPM.01/x_pos y_pos: AN03-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_018 x_pos: AN03-SD/DG-EPOS/BPM.02/x_pos y_pos: AN03-SD/DG-EPOS/BPM.02/y_pos @@ -840,7 +840,7 @@ - AN03-AR/EM-SX/SHF.01/strength - AN03-AR/EM-COR/SHF.01-CDLH.01/strength - AN03-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_019 x_pos: AN03-AR/DG-EPOS/BPM.03/x_pos y_pos: AN03-AR/DG-EPOS/BPM.03/y_pos @@ -908,7 +908,7 @@ physics: - AN03-AR/EM-SX/SCF.02/strength - AN03-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_020 x_pos: AN03-AR/DG-EPOS/BPM.04/x_pos y_pos: AN03-AR/DG-EPOS/BPM.04/y_pos @@ -968,7 +968,7 @@ physics: - AN03-AR/EM-SX/SCF.05/strength - AN03-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_021 x_pos: AN03-AR/DG-EPOS/BPM.05/x_pos y_pos: AN03-AR/DG-EPOS/BPM.05/y_pos @@ -1028,7 +1028,7 @@ physics: - AN03-AR/EM-SX/SCF.08/strength - AN03-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_022 x_pos: AN03-AR/DG-EPOS/BPM.06/x_pos y_pos: AN03-AR/DG-EPOS/BPM.06/y_pos @@ -1088,7 +1088,7 @@ - AN03-AR/EM-OCT/OC.04/strength - AN03-AR/EM-COR/OC.04-CQLN.13/strength - AN03-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_023 x_pos: AN03-AR/DG-EPOS/BPM.07/x_pos y_pos: AN03-AR/DG-EPOS/BPM.07/y_pos @@ -1148,7 +1148,7 @@ - AN03-AR/EM-OCT/OC.05/strength - AN03-AR/EM-COR/OC.05-CQLN.16/strength - AN03-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_024 x_pos: AN03-AR/DG-EPOS/BPM.08/x_pos y_pos: AN03-AR/DG-EPOS/BPM.08/y_pos @@ -1220,7 +1220,7 @@ physics: - AN03-AR/EM-SX/SCD.18/strength - AN03-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_025 x_pos: AN03-AR/DG-EPOS/BPM.09/x_pos y_pos: AN03-AR/DG-EPOS/BPM.09/y_pos @@ -1256,7 +1256,7 @@ type: pyaml.magnet.identity_model unit: 1/m physics: AN03-AR/EM-COR/CQLN.21/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_026 x_pos: AN03-AR/DG-EPOS/BPM.10/x_pos y_pos: AN03-AR/DG-EPOS/BPM.10/y_pos @@ -1288,11 +1288,11 @@ - AN03-AR/EM-OCT/OH.02/strength - AN03-AR/EM-COR/OH.02-CQLN.22/strength - AN03-AR/EM-COR/OH.02-CQLT.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_027 x_pos: AN04-SD/DG-EPOS/BPM.01/x_pos y_pos: AN04-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_028 x_pos: AN04-SD/DG-EPOS/BPM.02/x_pos y_pos: AN04-SD/DG-EPOS/BPM.02/y_pos @@ -1324,7 +1324,7 @@ - AN04-AR/EM-SX/SHF.01/strength - AN04-AR/EM-COR/SHF.01-CDLH.01/strength - AN04-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_029 x_pos: AN04-AR/DG-EPOS/BPM.03/x_pos y_pos: AN04-AR/DG-EPOS/BPM.03/y_pos @@ -1392,7 +1392,7 @@ physics: - AN04-AR/EM-SX/SCF.02/strength - AN04-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_030 x_pos: AN04-AR/DG-EPOS/BPM.04/x_pos y_pos: AN04-AR/DG-EPOS/BPM.04/y_pos @@ -1452,7 +1452,7 @@ - AN04-AR/EM-OCT/OC.02/strength - AN04-AR/EM-COR/OC.02-CQLN.07/strength - AN04-AR/EM-COR/OC.02-CQLT.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_031 x_pos: AN04-AR/DG-EPOS/BPM.05/x_pos y_pos: AN04-AR/DG-EPOS/BPM.05/y_pos @@ -1524,7 +1524,7 @@ physics: - AN04-AR/EM-SX/SCD.09/strength - AN04-AR/EM-COR/SCD.09-CDLV.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_032 x_pos: AN04-AR/DG-EPOS/BPM.06/x_pos y_pos: AN04-AR/DG-EPOS/BPM.06/y_pos @@ -1566,7 +1566,7 @@ physics: - AN04-AR/EM-OCT/OH.02/strength - AN04-AR/EM-COR/OH.02-CQLN.12/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_033 x_pos: AN04-AR/DG-EPOS/BPM.07/x_pos y_pos: AN04-AR/DG-EPOS/BPM.07/y_pos @@ -1598,11 +1598,11 @@ - AN04-AR/EM-OCT/OH.03/strength - AN04-AR/EM-COR/OH.03-CQLN.13/strength - AN04-AR/EM-COR/OH.03-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_034 x_pos: AN05-SD/DG-EPOS/BPM.01/x_pos y_pos: AN05-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_035 x_pos: AN05-SD/DG-EPOS/BPM.02/x_pos y_pos: AN05-SD/DG-EPOS/BPM.02/y_pos @@ -1634,7 +1634,7 @@ - AN05-AR/EM-SX/SHF.01/strength - AN05-AR/EM-COR/SHF.01-CDLH.01/strength - AN05-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_036 x_pos: AN05-AR/DG-EPOS/BPM.03/x_pos y_pos: AN05-AR/DG-EPOS/BPM.03/y_pos @@ -1708,7 +1708,7 @@ physics: - AN05-AR/EM-SX/SCF.02/strength - AN05-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_037 x_pos: AN05-AR/DG-EPOS/BPM.04/x_pos y_pos: AN05-AR/DG-EPOS/BPM.04/y_pos @@ -1768,7 +1768,7 @@ physics: - AN05-AR/EM-SX/SCF.05/strength - AN05-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_038 x_pos: AN05-AR/DG-EPOS/BPM.05/x_pos y_pos: AN05-AR/DG-EPOS/BPM.05/y_pos @@ -1828,7 +1828,7 @@ physics: - AN05-AR/EM-SX/SCF.08/strength - AN05-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_039 x_pos: AN05-AR/DG-EPOS/BPM.06/x_pos y_pos: AN05-AR/DG-EPOS/BPM.06/y_pos @@ -1888,7 +1888,7 @@ - AN05-AR/EM-OCT/OC.04/strength - AN05-AR/EM-COR/OC.04-CQLN.13/strength - AN05-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_040 x_pos: AN05-AR/DG-EPOS/BPM.07/x_pos y_pos: AN05-AR/DG-EPOS/BPM.07/y_pos @@ -1948,7 +1948,7 @@ - AN05-AR/EM-OCT/OC.05/strength - AN05-AR/EM-COR/OC.05-CQLN.16/strength - AN05-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_041 x_pos: AN05-AR/DG-EPOS/BPM.08/x_pos y_pos: AN05-AR/DG-EPOS/BPM.08/y_pos @@ -2020,7 +2020,7 @@ physics: - AN05-AR/EM-SX/SCD.18/strength - AN05-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_042 x_pos: AN05-AR/DG-EPOS/BPM.09/x_pos y_pos: AN05-AR/DG-EPOS/BPM.09/y_pos @@ -2042,7 +2042,7 @@ physics: - AN05-AR/EM-SX/SHD.04/strength - AN05-AR/EM-COR/SHD.04-CDLV.09/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_043 x_pos: AN05-AR/DG-EPOS/BPM.10/x_pos y_pos: AN05-AR/DG-EPOS/BPM.10/y_pos @@ -2098,11 +2098,11 @@ - AN05-AR/EM-OCT/OH.04/strength - AN05-AR/EM-COR/OH.04-CQLN.22/strength - AN05-AR/EM-COR/OH.04-CQLT.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_044 x_pos: AN06-SD/DG-EPOS/BPM.01/x_pos y_pos: AN06-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_045 x_pos: AN06-SD/DG-EPOS/BPM.02/x_pos y_pos: AN06-SD/DG-EPOS/BPM.02/y_pos @@ -2158,11 +2158,11 @@ physics: - AN06-SD/EM-OCT/OH.02/strength - AN06-SD/EM-COR/OH.02-CQLN.02/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_046 x_pos: AN06-SD/DG-EPOS/BPM.03/x_pos y_pos: AN06-SD/DG-EPOS/BPM.03/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_047 x_pos: AN06-SD/DG-EPOS/BPM.04/x_pos y_pos: AN06-SD/DG-EPOS/BPM.04/y_pos @@ -2218,7 +2218,7 @@ physics: - AN06-AR/EM-SX/SHD.02/strength - AN06-AR/EM-COR/SHD.02-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_048 x_pos: AN06-AR/DG-EPOS/BPM.05/x_pos y_pos: AN06-AR/DG-EPOS/BPM.05/y_pos @@ -2272,7 +2272,7 @@ physics: - AN06-AR/EM-SX/SCF.02/strength - AN06-AR/EM-COR/SCF.02-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_049 x_pos: AN06-AR/DG-EPOS/BPM.06/x_pos y_pos: AN06-AR/DG-EPOS/BPM.06/y_pos @@ -2332,7 +2332,7 @@ physics: - AN06-AR/EM-SX/SCF.05/strength - AN06-AR/EM-COR/SCF.05-CDLH.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_050 x_pos: AN06-AR/DG-EPOS/BPM.07/x_pos y_pos: AN06-AR/DG-EPOS/BPM.07/y_pos @@ -2392,7 +2392,7 @@ physics: - AN06-AR/EM-SX/SCF.08/strength - AN06-AR/EM-COR/SCF.08-CDLH.07/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_051 x_pos: AN06-AR/DG-EPOS/BPM.08/x_pos y_pos: AN06-AR/DG-EPOS/BPM.08/y_pos @@ -2452,7 +2452,7 @@ - AN06-AR/EM-OCT/OC.04/strength - AN06-AR/EM-COR/OC.04-CQLN.13/strength - AN06-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_052 x_pos: AN06-AR/DG-EPOS/BPM.09/x_pos y_pos: AN06-AR/DG-EPOS/BPM.09/y_pos @@ -2512,7 +2512,7 @@ - AN06-AR/EM-OCT/OC.05/strength - AN06-AR/EM-COR/OC.05-CQLN.16/strength - AN06-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_053 x_pos: AN06-AR/DG-EPOS/BPM.10/x_pos y_pos: AN06-AR/DG-EPOS/BPM.10/y_pos @@ -2584,7 +2584,7 @@ physics: - AN06-AR/EM-SX/SCD.18/strength - AN06-AR/EM-COR/SCD.18-CDLV.10/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_054 x_pos: AN06-AR/DG-EPOS/BPM.11/x_pos y_pos: AN06-AR/DG-EPOS/BPM.11/y_pos @@ -2626,7 +2626,7 @@ physics: - AN06-AR/EM-OCT/OH.03/strength - AN06-AR/EM-COR/OH.03-CQLN.21/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_055 x_pos: AN06-AR/DG-EPOS/BPM.12/x_pos y_pos: AN06-AR/DG-EPOS/BPM.12/y_pos @@ -2658,11 +2658,11 @@ - AN06-AR/EM-OCT/OH.04/strength - AN06-AR/EM-COR/OH.04-CQLN.22/strength - AN06-AR/EM-COR/OH.04-CQLT.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_056 x_pos: AN07-SD/DG-EPOS/BPM.01/x_pos y_pos: AN07-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_057 x_pos: AN07-SD/DG-EPOS/BPM.02/x_pos y_pos: AN07-SD/DG-EPOS/BPM.02/y_pos @@ -2694,7 +2694,7 @@ - AN07-AR/EM-SX/SHF.01/strength - AN07-AR/EM-COR/SHF.01-CDLH.01/strength - AN07-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_058 x_pos: AN07-AR/DG-EPOS/BPM.03/x_pos y_pos: AN07-AR/DG-EPOS/BPM.03/y_pos @@ -2768,7 +2768,7 @@ physics: - AN07-AR/EM-SX/SCF.02/strength - AN07-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_059 x_pos: AN07-AR/DG-EPOS/BPM.04/x_pos y_pos: AN07-AR/DG-EPOS/BPM.04/y_pos @@ -2828,7 +2828,7 @@ physics: - AN07-AR/EM-SX/SCF.05/strength - AN07-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_060 x_pos: AN07-AR/DG-EPOS/BPM.05/x_pos y_pos: AN07-AR/DG-EPOS/BPM.05/y_pos @@ -2900,7 +2900,7 @@ physics: - AN07-AR/EM-SX/SCD.09/strength - AN07-AR/EM-COR/SCD.09-CDLV.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_061 x_pos: AN07-AR/DG-EPOS/BPM.06/x_pos y_pos: AN07-AR/DG-EPOS/BPM.06/y_pos @@ -2936,7 +2936,7 @@ type: pyaml.magnet.identity_model unit: 1/m physics: AN07-AR/EM-COR/CQLN.12/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_062 x_pos: AN07-AR/DG-EPOS/BPM.07/x_pos y_pos: AN07-AR/DG-EPOS/BPM.07/y_pos @@ -2968,11 +2968,11 @@ - AN07-AR/EM-OCT/OH.03/strength - AN07-AR/EM-COR/OH.03-CQLN.13/strength - AN07-AR/EM-COR/OH.03-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_063 x_pos: AN08-SD/DG-EPOS/BPM.01/x_pos y_pos: AN08-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_064 x_pos: AN08-SD/DG-EPOS/BPM.02/x_pos y_pos: AN08-SD/DG-EPOS/BPM.02/y_pos @@ -3004,7 +3004,7 @@ - AN08-AR/EM-SX/SHF.01/strength - AN08-AR/EM-COR/SHF.01-CDLH.01/strength - AN08-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_065 x_pos: AN08-AR/DG-EPOS/BPM.03/x_pos y_pos: AN08-AR/DG-EPOS/BPM.03/y_pos @@ -3072,7 +3072,7 @@ physics: - AN08-AR/EM-SX/SCF.02/strength - AN08-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_066 x_pos: AN08-AR/DG-EPOS/BPM.04/x_pos y_pos: AN08-AR/DG-EPOS/BPM.04/y_pos @@ -3132,7 +3132,7 @@ physics: - AN08-AR/EM-SX/SCF.05/strength - AN08-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_067 x_pos: AN08-AR/DG-EPOS/BPM.05/x_pos y_pos: AN08-AR/DG-EPOS/BPM.05/y_pos @@ -3192,7 +3192,7 @@ physics: - AN08-AR/EM-SX/SCF.08/strength - AN08-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_068 x_pos: AN08-AR/DG-EPOS/BPM.06/x_pos y_pos: AN08-AR/DG-EPOS/BPM.06/y_pos @@ -3252,7 +3252,7 @@ - AN08-AR/EM-OCT/OC.04/strength - AN08-AR/EM-COR/OC.04-CQLN.13/strength - AN08-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_069 x_pos: AN08-AR/DG-EPOS/BPM.07/x_pos y_pos: AN08-AR/DG-EPOS/BPM.07/y_pos @@ -3312,7 +3312,7 @@ - AN08-AR/EM-OCT/OC.05/strength - AN08-AR/EM-COR/OC.05-CQLN.16/strength - AN08-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_070 x_pos: AN08-AR/DG-EPOS/BPM.08/x_pos y_pos: AN08-AR/DG-EPOS/BPM.08/y_pos @@ -3384,7 +3384,7 @@ physics: - AN08-AR/EM-SX/SCD.18/strength - AN08-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_071 x_pos: AN08-AR/DG-EPOS/BPM.09/x_pos y_pos: AN08-AR/DG-EPOS/BPM.09/y_pos @@ -3420,7 +3420,7 @@ type: pyaml.magnet.identity_model unit: 1/m physics: AN08-AR/EM-COR/CQLN.21/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_072 x_pos: AN08-AR/DG-EPOS/BPM.10/x_pos y_pos: AN08-AR/DG-EPOS/BPM.10/y_pos @@ -3452,11 +3452,11 @@ - AN08-AR/EM-OCT/OH.02/strength - AN08-AR/EM-COR/OH.02-CQLN.22/strength - AN08-AR/EM-COR/OH.02-CQLT.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_073 x_pos: AN09-SD/DG-EPOS/BPM.01/x_pos y_pos: AN09-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_074 x_pos: AN09-SD/DG-EPOS/BPM.02/x_pos y_pos: AN09-SD/DG-EPOS/BPM.02/y_pos @@ -3488,7 +3488,7 @@ - AN09-AR/EM-SX/SHF.01/strength - AN09-AR/EM-COR/SHF.01-CDLH.01/strength - AN09-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_075 x_pos: AN09-AR/DG-EPOS/BPM.03/x_pos y_pos: AN09-AR/DG-EPOS/BPM.03/y_pos @@ -3556,7 +3556,7 @@ physics: - AN09-AR/EM-SX/SCF.02/strength - AN09-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_076 x_pos: AN09-AR/DG-EPOS/BPM.04/x_pos y_pos: AN09-AR/DG-EPOS/BPM.04/y_pos @@ -3616,7 +3616,7 @@ - AN09-AR/EM-OCT/OC.02/strength - AN09-AR/EM-COR/OC.02-CQLN.07/strength - AN09-AR/EM-COR/OC.02-CQLT.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_077 x_pos: AN09-AR/DG-EPOS/BPM.05/x_pos y_pos: AN09-AR/DG-EPOS/BPM.05/y_pos @@ -3688,7 +3688,7 @@ physics: - AN09-AR/EM-SX/SCD.09/strength - AN09-AR/EM-COR/SCD.09-CDLV.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_078 x_pos: AN09-AR/DG-EPOS/BPM.06/x_pos y_pos: AN09-AR/DG-EPOS/BPM.06/y_pos @@ -3730,7 +3730,7 @@ physics: - AN09-AR/EM-OCT/OH.02/strength - AN09-AR/EM-COR/OH.02-CQLN.12/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_079 x_pos: AN09-AR/DG-EPOS/BPM.07/x_pos y_pos: AN09-AR/DG-EPOS/BPM.07/y_pos @@ -3762,11 +3762,11 @@ - AN09-AR/EM-OCT/OH.03/strength - AN09-AR/EM-COR/OH.03-CQLN.13/strength - AN09-AR/EM-COR/OH.03-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_080 x_pos: AN10-SD/DG-EPOS/BPM.01/x_pos y_pos: AN10-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_081 x_pos: AN10-SD/DG-EPOS/BPM.02/x_pos y_pos: AN10-SD/DG-EPOS/BPM.02/y_pos @@ -3798,7 +3798,7 @@ - AN10-AR/EM-SX/SHF.01/strength - AN10-AR/EM-COR/SHF.01-CDLH.01/strength - AN10-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_082 x_pos: AN10-AR/DG-EPOS/BPM.03/x_pos y_pos: AN10-AR/DG-EPOS/BPM.03/y_pos @@ -3872,7 +3872,7 @@ physics: - AN10-AR/EM-SX/SCF.02/strength - AN10-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_083 x_pos: AN10-AR/DG-EPOS/BPM.04/x_pos y_pos: AN10-AR/DG-EPOS/BPM.04/y_pos @@ -3932,7 +3932,7 @@ physics: - AN10-AR/EM-SX/SCF.05/strength - AN10-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_084 x_pos: AN10-AR/DG-EPOS/BPM.05/x_pos y_pos: AN10-AR/DG-EPOS/BPM.05/y_pos @@ -3992,7 +3992,7 @@ physics: - AN10-AR/EM-SX/SCF.08/strength - AN10-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_085 x_pos: AN10-AR/DG-EPOS/BPM.06/x_pos y_pos: AN10-AR/DG-EPOS/BPM.06/y_pos @@ -4052,7 +4052,7 @@ - AN10-AR/EM-OCT/OC.04/strength - AN10-AR/EM-COR/OC.04-CQLN.13/strength - AN10-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_086 x_pos: AN10-AR/DG-EPOS/BPM.07/x_pos y_pos: AN10-AR/DG-EPOS/BPM.07/y_pos @@ -4112,7 +4112,7 @@ - AN10-AR/EM-OCT/OC.05/strength - AN10-AR/EM-COR/OC.05-CQLN.16/strength - AN10-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_087 x_pos: AN10-AR/DG-EPOS/BPM.08/x_pos y_pos: AN10-AR/DG-EPOS/BPM.08/y_pos @@ -4184,7 +4184,7 @@ physics: - AN10-AR/EM-SX/SCD.18/strength - AN10-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_088 x_pos: AN10-AR/DG-EPOS/BPM.09/x_pos y_pos: AN10-AR/DG-EPOS/BPM.09/y_pos @@ -4206,7 +4206,7 @@ physics: - AN10-AR/EM-SX/SHD.04/strength - AN10-AR/EM-COR/SHD.04-CDLV.09/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_089 x_pos: AN10-AR/DG-EPOS/BPM.10/x_pos y_pos: AN10-AR/DG-EPOS/BPM.10/y_pos @@ -4262,11 +4262,11 @@ - AN10-AR/EM-SX/SHF.06/strength - AN10-AR/EM-COR/SHF.06-CDLH.10/strength - AN10-AR/EM-COR/SHF.06-CDLV.10/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_090 x_pos: AN11-SD/DG-EPOS/BPM.01/x_pos y_pos: AN11-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_091 x_pos: AN11-SD/DG-EPOS/BPM.02/x_pos y_pos: AN11-SD/DG-EPOS/BPM.02/y_pos @@ -4322,7 +4322,7 @@ physics: - AN11-AR/EM-OCT/OH.02/strength - AN11-AR/EM-COR/OH.02-CQLN.02/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_092 x_pos: AN11-AR/DG-EPOS/BPM.03/x_pos y_pos: AN11-AR/DG-EPOS/BPM.03/y_pos @@ -4376,7 +4376,7 @@ physics: - AN11-AR/EM-SX/SCF.02/strength - AN11-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_093 x_pos: AN11-AR/DG-EPOS/BPM.04/x_pos y_pos: AN11-AR/DG-EPOS/BPM.04/y_pos @@ -4436,7 +4436,7 @@ physics: - AN11-AR/EM-SX/SCF.05/strength - AN11-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_094 x_pos: AN11-AR/DG-EPOS/BPM.05/x_pos y_pos: AN11-AR/DG-EPOS/BPM.05/y_pos @@ -4496,7 +4496,7 @@ physics: - AN11-AR/EM-SX/SCF.08/strength - AN11-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_095 x_pos: AN11-AR/DG-EPOS/BPM.06/x_pos y_pos: AN11-AR/DG-EPOS/BPM.06/y_pos @@ -4556,7 +4556,7 @@ - AN11-AR/EM-OCT/OC.04/strength - AN11-AR/EM-COR/OC.04-CQLN.13/strength - AN11-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_096 x_pos: AN11-AR/DG-EPOS/BPM.07/x_pos y_pos: AN11-AR/DG-EPOS/BPM.07/y_pos @@ -4616,7 +4616,7 @@ - AN11-AR/EM-OCT/OC.05/strength - AN11-AR/EM-COR/OC.05-CQLN.16/strength - AN11-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_097 x_pos: AN11-AR/DG-EPOS/BPM.08/x_pos y_pos: AN11-AR/DG-EPOS/BPM.08/y_pos @@ -4688,7 +4688,7 @@ physics: - AN11-AR/EM-SX/SCD.18/strength - AN11-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_098 x_pos: AN11-AR/DG-EPOS/BPM.09/x_pos y_pos: AN11-AR/DG-EPOS/BPM.09/y_pos @@ -4730,7 +4730,7 @@ physics: - AN11-AR/EM-OCT/OH.03/strength - AN11-AR/EM-COR/OH.03-CQLN.21/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_099 x_pos: AN11-AR/DG-EPOS/BPM.10/x_pos y_pos: AN11-AR/DG-EPOS/BPM.10/y_pos @@ -4762,11 +4762,11 @@ - AN11-AR/EM-OCT/OH.04/strength - AN11-AR/EM-COR/OH.04-CQLN.22/strength - AN11-AR/EM-COR/OH.04-CQLT.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_100 x_pos: AN12-SD/DG-EPOS/BPM.01/x_pos y_pos: AN12-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_101 x_pos: AN12-SD/DG-EPOS/BPM.02/x_pos y_pos: AN12-SD/DG-EPOS/BPM.02/y_pos @@ -4798,7 +4798,7 @@ - AN12-AR/EM-SX/SHF.01/strength - AN12-AR/EM-COR/SHF.01-CDLH.01/strength - AN12-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_102 x_pos: AN12-AR/DG-EPOS/BPM.03/x_pos y_pos: AN12-AR/DG-EPOS/BPM.03/y_pos @@ -4872,7 +4872,7 @@ physics: - AN12-AR/EM-SX/SCF.02/strength - AN12-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_103 x_pos: AN12-AR/DG-EPOS/BPM.04/x_pos y_pos: AN12-AR/DG-EPOS/BPM.04/y_pos @@ -4932,7 +4932,7 @@ physics: - AN12-AR/EM-SX/SCF.05/strength - AN12-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_104 x_pos: AN12-AR/DG-EPOS/BPM.05/x_pos y_pos: AN12-AR/DG-EPOS/BPM.05/y_pos @@ -5004,7 +5004,7 @@ physics: - AN12-AR/EM-SX/SCD.09/strength - AN12-AR/EM-COR/SCD.09-CDLV.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_105 x_pos: AN12-AR/DG-EPOS/BPM.06/x_pos y_pos: AN12-AR/DG-EPOS/BPM.06/y_pos @@ -5040,7 +5040,7 @@ type: pyaml.magnet.identity_model unit: 1/m physics: AN12-AR/EM-COR/CQLN.12/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_106 x_pos: AN12-AR/DG-EPOS/BPM.07/x_pos y_pos: AN12-AR/DG-EPOS/BPM.07/y_pos @@ -5072,11 +5072,11 @@ - AN12-AR/EM-OCT/OH.03/strength - AN12-AR/EM-COR/OH.03-CQLN.13/strength - AN12-AR/EM-COR/OH.03-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_107 x_pos: AN13-SD/DG-EPOS/BPM.01/x_pos y_pos: AN13-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_108 x_pos: AN13-SD/DG-EPOS/BPM.02/x_pos y_pos: AN13-SD/DG-EPOS/BPM.02/y_pos @@ -5108,7 +5108,7 @@ - AN13-AR/EM-SX/SHF.01/strength - AN13-AR/EM-COR/SHF.01-CDLH.01/strength - AN13-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_109 x_pos: AN13-AR/DG-EPOS/BPM.03/x_pos y_pos: AN13-AR/DG-EPOS/BPM.03/y_pos @@ -5176,7 +5176,7 @@ physics: - AN13-AR/EM-SX/SCF.02/strength - AN13-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_110 x_pos: AN13-AR/DG-EPOS/BPM.04/x_pos y_pos: AN13-AR/DG-EPOS/BPM.04/y_pos @@ -5236,7 +5236,7 @@ physics: - AN13-AR/EM-SX/SCF.05/strength - AN13-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_111 x_pos: AN13-AR/DG-EPOS/BPM.05/x_pos y_pos: AN13-AR/DG-EPOS/BPM.05/y_pos @@ -5296,7 +5296,7 @@ physics: - AN13-AR/EM-SX/SCF.08/strength - AN13-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_112 x_pos: AN13-AR/DG-EPOS/BPM.06/x_pos y_pos: AN13-AR/DG-EPOS/BPM.06/y_pos @@ -5356,7 +5356,7 @@ - AN13-AR/EM-OCT/OC.04/strength - AN13-AR/EM-COR/OC.04-CQLN.13/strength - AN13-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_113 x_pos: AN13-AR/DG-EPOS/BPM.07/x_pos y_pos: AN13-AR/DG-EPOS/BPM.07/y_pos @@ -5416,7 +5416,7 @@ - AN13-AR/EM-OCT/OC.05/strength - AN13-AR/EM-COR/OC.05-CQLN.16/strength - AN13-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_114 x_pos: AN13-AR/DG-EPOS/BPM.08/x_pos y_pos: AN13-AR/DG-EPOS/BPM.08/y_pos @@ -5488,7 +5488,7 @@ physics: - AN13-AR/EM-SX/SCD.18/strength - AN13-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_115 x_pos: AN13-AR/DG-EPOS/BPM.09/x_pos y_pos: AN13-AR/DG-EPOS/BPM.09/y_pos @@ -5524,7 +5524,7 @@ type: pyaml.magnet.identity_model unit: 1/m physics: AN13-AR/EM-COR/CQLN.21/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_116 x_pos: AN13-AR/DG-EPOS/BPM.10/x_pos y_pos: AN13-AR/DG-EPOS/BPM.10/y_pos @@ -5556,11 +5556,11 @@ - AN13-AR/EM-OCT/OH.02/strength - AN13-AR/EM-COR/OH.02-CQLN.22/strength - AN13-AR/EM-COR/OH.02-CQLT.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_117 x_pos: AN14-SD/DG-EPOS/BPM.01/x_pos y_pos: AN14-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_118 x_pos: AN14-SD/DG-EPOS/BPM.02/x_pos y_pos: AN14-SD/DG-EPOS/BPM.02/y_pos @@ -5592,7 +5592,7 @@ - AN14-AR/EM-SX/SHF.01/strength - AN14-AR/EM-COR/SHF.01-CDLH.01/strength - AN14-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_119 x_pos: AN14-AR/DG-EPOS/BPM.03/x_pos y_pos: AN14-AR/DG-EPOS/BPM.03/y_pos @@ -5660,7 +5660,7 @@ physics: - AN14-AR/EM-SX/SCF.02/strength - AN14-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_120 x_pos: AN14-AR/DG-EPOS/BPM.04/x_pos y_pos: AN14-AR/DG-EPOS/BPM.04/y_pos @@ -5720,7 +5720,7 @@ - AN14-AR/EM-OCT/OC.02/strength - AN14-AR/EM-COR/OC.02-CQLN.07/strength - AN14-AR/EM-COR/OC.02-CQLT.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_121 x_pos: AN14-AR/DG-EPOS/BPM.05/x_pos y_pos: AN14-AR/DG-EPOS/BPM.05/y_pos @@ -5792,7 +5792,7 @@ physics: - AN14-AR/EM-SX/SCD.09/strength - AN14-AR/EM-COR/SCD.09-CDLV.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_122 x_pos: AN14-AR/DG-EPOS/BPM.06/x_pos y_pos: AN14-AR/DG-EPOS/BPM.06/y_pos @@ -5834,7 +5834,7 @@ physics: - AN14-AR/EM-OCT/OH.02/strength - AN14-AR/EM-COR/OH.02-CQLN.12/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_123 x_pos: AN14-AR/DG-EPOS/BPM.07/x_pos y_pos: AN14-AR/DG-EPOS/BPM.07/y_pos @@ -5866,11 +5866,11 @@ - AN14-AR/EM-OCT/OH.03/strength - AN14-AR/EM-COR/OH.03-CQLN.13/strength - AN14-AR/EM-COR/OH.03-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_124 x_pos: AN15-SD/DG-EPOS/BPM.01/x_pos y_pos: AN15-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_125 x_pos: AN15-SD/DG-EPOS/BPM.02/x_pos y_pos: AN15-SD/DG-EPOS/BPM.02/y_pos @@ -5902,7 +5902,7 @@ - AN15-AR/EM-SX/SHF.01/strength - AN15-AR/EM-COR/SHF.01-CDLH.01/strength - AN15-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_126 x_pos: AN15-AR/DG-EPOS/BPM.03/x_pos y_pos: AN15-AR/DG-EPOS/BPM.03/y_pos @@ -5976,7 +5976,7 @@ physics: - AN15-AR/EM-SX/SCF.02/strength - AN15-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_127 x_pos: AN15-AR/DG-EPOS/BPM.04/x_pos y_pos: AN15-AR/DG-EPOS/BPM.04/y_pos @@ -6036,7 +6036,7 @@ physics: - AN15-AR/EM-SX/SCF.05/strength - AN15-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_128 x_pos: AN15-AR/DG-EPOS/BPM.05/x_pos y_pos: AN15-AR/DG-EPOS/BPM.05/y_pos @@ -6096,7 +6096,7 @@ physics: - AN15-AR/EM-SX/SCF.08/strength - AN15-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_129 x_pos: AN15-AR/DG-EPOS/BPM.06/x_pos y_pos: AN15-AR/DG-EPOS/BPM.06/y_pos @@ -6156,7 +6156,7 @@ - AN15-AR/EM-OCT/OC.04/strength - AN15-AR/EM-COR/OC.04-CQLN.13/strength - AN15-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_130 x_pos: AN15-AR/DG-EPOS/BPM.07/x_pos y_pos: AN15-AR/DG-EPOS/BPM.07/y_pos @@ -6216,7 +6216,7 @@ - AN15-AR/EM-OCT/OC.05/strength - AN15-AR/EM-COR/OC.05-CQLN.16/strength - AN15-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_131 x_pos: AN15-AR/DG-EPOS/BPM.08/x_pos y_pos: AN15-AR/DG-EPOS/BPM.08/y_pos @@ -6288,7 +6288,7 @@ physics: - AN15-AR/EM-SX/SCD.18/strength - AN15-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_132 x_pos: AN15-AR/DG-EPOS/BPM.09/x_pos y_pos: AN15-AR/DG-EPOS/BPM.09/y_pos @@ -6310,7 +6310,7 @@ physics: - AN15-AR/EM-SX/SHD.04/strength - AN15-AR/EM-COR/SHD.04-CDLV.09/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_133 x_pos: AN15-AR/DG-EPOS/BPM.10/x_pos y_pos: AN15-AR/DG-EPOS/BPM.10/y_pos @@ -6364,11 +6364,11 @@ physics: - AN15-AR/EM-OCT/OH.04/strength - AN15-AR/EM-COR/OH.04-CQLN.22/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_134 x_pos: AN16-SD/DG-EPOS/BPM.01/x_pos y_pos: AN16-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_135 x_pos: AN16-SD/DG-EPOS/BPM.02/x_pos y_pos: AN16-SD/DG-EPOS/BPM.02/y_pos @@ -6424,11 +6424,11 @@ physics: - AN16-SD/EM-OCT/OH.02/strength - AN16-SD/EM-COR/OH.02-CQLN.02/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_136 x_pos: AN16-SD/DG-EPOS/BPM.03/x_pos y_pos: AN16-SD/DG-EPOS/BPM.03/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_137 x_pos: AN16-SD/DG-EPOS/BPM.04/x_pos y_pos: AN16-SD/DG-EPOS/BPM.04/y_pos @@ -6482,7 +6482,7 @@ physics: - AN16-AR/EM-SX/SHD.02/strength - AN16-AR/EM-COR/SHD.02-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_138 x_pos: AN16-AR/DG-EPOS/BPM.05/x_pos y_pos: AN16-AR/DG-EPOS/BPM.05/y_pos @@ -6536,7 +6536,7 @@ physics: - AN16-AR/EM-SX/SCF.02/strength - AN16-AR/EM-COR/SCF.02-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_139 x_pos: AN16-AR/DG-EPOS/BPM.06/x_pos y_pos: AN16-AR/DG-EPOS/BPM.06/y_pos @@ -6596,7 +6596,7 @@ physics: - AN16-AR/EM-SX/SCF.05/strength - AN16-AR/EM-COR/SCF.05-CDLH.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_140 x_pos: AN16-AR/DG-EPOS/BPM.07/x_pos y_pos: AN16-AR/DG-EPOS/BPM.07/y_pos @@ -6656,7 +6656,7 @@ physics: - AN16-AR/EM-SX/SCF.08/strength - AN16-AR/EM-COR/SCF.08-CDLH.07/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_141 x_pos: AN16-AR/DG-EPOS/BPM.08/x_pos y_pos: AN16-AR/DG-EPOS/BPM.08/y_pos @@ -6716,7 +6716,7 @@ - AN16-AR/EM-OCT/OC.04/strength - AN16-AR/EM-COR/OC.04-CQLN.13/strength - AN16-AR/EM-COR/OC.04-CQLT.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_142 x_pos: AN16-AR/DG-EPOS/BPM.09/x_pos y_pos: AN16-AR/DG-EPOS/BPM.09/y_pos @@ -6776,7 +6776,7 @@ - AN16-AR/EM-OCT/OC.05/strength - AN16-AR/EM-COR/OC.05-CQLN.16/strength - AN16-AR/EM-COR/OC.05-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_143 x_pos: AN16-AR/DG-EPOS/BPM.10/x_pos y_pos: AN16-AR/DG-EPOS/BPM.10/y_pos @@ -6848,7 +6848,7 @@ physics: - AN16-AR/EM-SX/SCD.18/strength - AN16-AR/EM-COR/SCD.18-CDLV.10/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_144 x_pos: AN16-AR/DG-EPOS/BPM.11/x_pos y_pos: AN16-AR/DG-EPOS/BPM.11/y_pos @@ -6890,7 +6890,7 @@ physics: - AN16-AR/EM-OCT/OH.03/strength - AN16-AR/EM-COR/OH.03-CQLN.21/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_145 x_pos: AN16-AR/DG-EPOS/BPM.12/x_pos y_pos: AN16-AR/DG-EPOS/BPM.12/y_pos @@ -6922,11 +6922,11 @@ - AN16-AR/EM-OCT/OH.04/strength - AN16-AR/EM-COR/OH.04-CQLN.22/strength - AN16-AR/EM-COR/OH.04-CQLT.07/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_146 x_pos: AN17-SD/DG-EPOS/BPM.01/x_pos y_pos: AN17-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_147 x_pos: AN17-SD/DG-EPOS/BPM.02/x_pos y_pos: AN17-SD/DG-EPOS/BPM.02/y_pos @@ -6958,7 +6958,7 @@ - AN17-AR/EM-SX/SHF.01/strength - AN17-AR/EM-COR/SHF.01-CDLH.01/strength - AN17-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_148 x_pos: AN17-AR/DG-EPOS/BPM.03/x_pos y_pos: AN17-AR/DG-EPOS/BPM.03/y_pos @@ -7032,7 +7032,7 @@ physics: - AN17-AR/EM-SX/SCF.02/strength - AN17-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_149 x_pos: AN17-AR/DG-EPOS/BPM.04/x_pos y_pos: AN17-AR/DG-EPOS/BPM.04/y_pos @@ -7092,7 +7092,7 @@ physics: - AN17-AR/EM-SX/SCF.05/strength - AN17-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_150 x_pos: AN17-AR/DG-EPOS/BPM.05/x_pos y_pos: AN17-AR/DG-EPOS/BPM.05/y_pos @@ -7164,7 +7164,7 @@ physics: - AN17-AR/EM-SX/SCD.09/strength - AN17-AR/EM-COR/SCD.09-CDLV.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_151 x_pos: AN17-AR/DG-EPOS/BPM.06/x_pos y_pos: AN17-AR/DG-EPOS/BPM.06/y_pos @@ -7200,7 +7200,7 @@ type: pyaml.magnet.identity_model unit: 1/m physics: AN17-AR/EM-COR/CQLN.12/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_152 x_pos: AN17-AR/DG-EPOS/BPM.07/x_pos y_pos: AN17-AR/DG-EPOS/BPM.07/y_pos @@ -7232,11 +7232,11 @@ - AN17-AR/EM-OCT/OH.03/strength - AN17-AR/EM-COR/OH.03-CQLN.13/strength - AN17-AR/EM-COR/OH.03-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_153 x_pos: AN18-SD/DG-EPOS/BPM.01/x_pos y_pos: AN18-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_154 x_pos: AN18-SD/DG-EPOS/BPM.02/x_pos y_pos: AN18-SD/DG-EPOS/BPM.02/y_pos @@ -7268,7 +7268,7 @@ - AN18-AR/EM-SX/SHF.01/strength - AN18-AR/EM-COR/SHF.01-CDLH.01/strength - AN18-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_155 x_pos: AN18-AR/DG-EPOS/BPM.03/x_pos y_pos: AN18-AR/DG-EPOS/BPM.03/y_pos @@ -7336,7 +7336,7 @@ physics: - AN18-AR/EM-SX/SCF.02/strength - AN18-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_156 x_pos: AN18-AR/DG-EPOS/BPM.04/x_pos y_pos: AN18-AR/DG-EPOS/BPM.04/y_pos @@ -7396,7 +7396,7 @@ physics: - AN18-AR/EM-SX/SCF.05/strength - AN18-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_157 x_pos: AN18-AR/DG-EPOS/BPM.05/x_pos y_pos: AN18-AR/DG-EPOS/BPM.05/y_pos @@ -7456,7 +7456,7 @@ physics: - AN18-AR/EM-SX/SCF.08/strength - AN18-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_158 x_pos: AN18-AR/DG-EPOS/BPM.06/x_pos y_pos: AN18-AR/DG-EPOS/BPM.06/y_pos @@ -7516,7 +7516,7 @@ - AN18-AR/EM-OCT/OC.04/strength - AN18-AR/EM-COR/OC.04-CQLN.13/strength - AN18-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_159 x_pos: AN18-AR/DG-EPOS/BPM.07/x_pos y_pos: AN18-AR/DG-EPOS/BPM.07/y_pos @@ -7576,7 +7576,7 @@ - AN18-AR/EM-OCT/OC.05/strength - AN18-AR/EM-COR/OC.05-CQLN.16/strength - AN18-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_160 x_pos: AN18-AR/DG-EPOS/BPM.08/x_pos y_pos: AN18-AR/DG-EPOS/BPM.08/y_pos @@ -7648,7 +7648,7 @@ physics: - AN18-AR/EM-SX/SCD.18/strength - AN18-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_161 x_pos: AN18-AR/DG-EPOS/BPM.09/x_pos y_pos: AN18-AR/DG-EPOS/BPM.09/y_pos @@ -7684,7 +7684,7 @@ type: pyaml.magnet.identity_model unit: 1/m physics: AN18-AR/EM-COR/CQLN.21/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_162 x_pos: AN18-AR/DG-EPOS/BPM.10/x_pos y_pos: AN18-AR/DG-EPOS/BPM.10/y_pos @@ -7716,11 +7716,11 @@ - AN18-AR/EM-OCT/OH.02/strength - AN18-AR/EM-COR/OH.02-CQLN.22/strength - AN18-AR/EM-COR/OH.02-CQLT.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_163 x_pos: AN19-SD/DG-EPOS/BPM.01/x_pos y_pos: AN19-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_164 x_pos: AN19-SD/DG-EPOS/BPM.02/x_pos y_pos: AN19-SD/DG-EPOS/BPM.02/y_pos @@ -7752,7 +7752,7 @@ - AN19-AR/EM-SX/SHF.01/strength - AN19-AR/EM-COR/SHF.01-CDLH.01/strength - AN19-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_165 x_pos: AN19-AR/DG-EPOS/BPM.03/x_pos y_pos: AN19-AR/DG-EPOS/BPM.03/y_pos @@ -7820,7 +7820,7 @@ physics: - AN19-AR/EM-SX/SCF.02/strength - AN19-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_166 x_pos: AN19-AR/DG-EPOS/BPM.04/x_pos y_pos: AN19-AR/DG-EPOS/BPM.04/y_pos @@ -7880,7 +7880,7 @@ - AN19-AR/EM-OCT/OC.02/strength - AN19-AR/EM-COR/OC.02-CQLN.07/strength - AN19-AR/EM-COR/OC.02-CQLT.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_167 x_pos: AN19-AR/DG-EPOS/BPM.05/x_pos y_pos: AN19-AR/DG-EPOS/BPM.05/y_pos @@ -7952,7 +7952,7 @@ physics: - AN19-AR/EM-SX/SCD.09/strength - AN19-AR/EM-COR/SCD.09-CDLV.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_168 x_pos: AN19-AR/DG-EPOS/BPM.06/x_pos y_pos: AN19-AR/DG-EPOS/BPM.06/y_pos @@ -7994,7 +7994,7 @@ physics: - AN19-AR/EM-OCT/OH.02/strength - AN19-AR/EM-COR/OH.02-CQLN.12/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_169 x_pos: AN19-AR/DG-EPOS/BPM.07/x_pos y_pos: AN19-AR/DG-EPOS/BPM.07/y_pos @@ -8026,11 +8026,11 @@ - AN19-AR/EM-OCT/OH.03/strength - AN19-AR/EM-COR/OH.03-CQLN.13/strength - AN19-AR/EM-COR/OH.03-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_170 x_pos: AN20-SD/DG-EPOS/BPM.01/x_pos y_pos: AN20-SD/DG-EPOS/BPM.01/y_pos -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_171 x_pos: AN20-SD/DG-EPOS/BPM.02/x_pos y_pos: AN20-SD/DG-EPOS/BPM.02/y_pos @@ -8062,7 +8062,7 @@ - AN20-AR/EM-SX/SHF.01/strength - AN20-AR/EM-COR/SHF.01-CDLH.01/strength - AN20-AR/EM-COR/SHF.01-CDLV.01/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_172 x_pos: AN20-AR/DG-EPOS/BPM.03/x_pos y_pos: AN20-AR/DG-EPOS/BPM.03/y_pos @@ -8136,7 +8136,7 @@ physics: - AN20-AR/EM-SX/SCF.02/strength - AN20-AR/EM-COR/SCF.02-CDLH.03/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_173 x_pos: AN20-AR/DG-EPOS/BPM.04/x_pos y_pos: AN20-AR/DG-EPOS/BPM.04/y_pos @@ -8196,7 +8196,7 @@ physics: - AN20-AR/EM-SX/SCF.05/strength - AN20-AR/EM-COR/SCF.05-CDLH.04/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_174 x_pos: AN20-AR/DG-EPOS/BPM.05/x_pos y_pos: AN20-AR/DG-EPOS/BPM.05/y_pos @@ -8256,7 +8256,7 @@ physics: - AN20-AR/EM-SX/SCF.08/strength - AN20-AR/EM-COR/SCF.08-CDLH.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_175 x_pos: AN20-AR/DG-EPOS/BPM.06/x_pos y_pos: AN20-AR/DG-EPOS/BPM.06/y_pos @@ -8316,7 +8316,7 @@ - AN20-AR/EM-OCT/OC.04/strength - AN20-AR/EM-COR/OC.04-CQLN.13/strength - AN20-AR/EM-COR/OC.04-CQLT.05/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_176 x_pos: AN20-AR/DG-EPOS/BPM.07/x_pos y_pos: AN20-AR/DG-EPOS/BPM.07/y_pos @@ -8376,7 +8376,7 @@ - AN20-AR/EM-OCT/OC.05/strength - AN20-AR/EM-COR/OC.05-CQLN.16/strength - AN20-AR/EM-COR/OC.05-CQLT.06/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_177 x_pos: AN20-AR/DG-EPOS/BPM.08/x_pos y_pos: AN20-AR/DG-EPOS/BPM.08/y_pos @@ -8448,7 +8448,7 @@ physics: - AN20-AR/EM-SX/SCD.18/strength - AN20-AR/EM-COR/SCD.18-CDLV.08/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_178 x_pos: AN20-AR/DG-EPOS/BPM.09/x_pos y_pos: AN20-AR/DG-EPOS/BPM.09/y_pos @@ -8470,7 +8470,7 @@ physics: - AN20-AR/EM-SX/SHD.04/strength - AN20-AR/EM-COR/SHD.04-CDLV.09/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_179 x_pos: AN20-AR/DG-EPOS/BPM.10/x_pos y_pos: AN20-AR/DG-EPOS/BPM.10/y_pos @@ -8526,7 +8526,7 @@ - AN20-AR/EM-SX/SHF.06/strength - AN20-AR/EM-COR/SHF.06-CDLH.10/strength - AN20-AR/EM-COR/SHF.06-CDLV.10/strength -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_180 x_pos: AN01-SD/DG-EPOS/BPM.01/x_pos y_pos: AN01-SD/DG-EPOS/BPM.01/y_pos diff --git a/examples/use_cases/config/soleil_ii/p.yaml b/examples/use_cases/config/soleil_ii/p.yaml index d8829096d..3eab94047 100644 --- a/examples/use_cases/config/soleil_ii/p.yaml +++ b/examples/use_cases/config/soleil_ii/p.yaml @@ -14,8 +14,8 @@ controls: - type: tango.pyaml.controlsystem name: live tango_host: localhost:11000 - catalog: catalogs.yaml -arrays: arrays.yaml + catalog: ${include:catalogs.yaml} +arrays: ${include:arrays.yaml} devices: -- devices.yaml -- tuning_tools.yaml +- ${include:devices.yaml} +- ${include:tuning_tools.yaml} diff --git a/pyaml/apidoc/gen_api.py b/pyaml/apidoc/gen_api.py index e2b05a8ae..4439e85e2 100644 --- a/pyaml/apidoc/gen_api.py +++ b/pyaml/apidoc/gen_api.py @@ -20,7 +20,6 @@ "pyaml.arrays.magnet_array", "pyaml.arrays.serialized_magnet", "pyaml.arrays.serialized_magnet_array", - "pyaml.bpm.bpm", "pyaml.common.abstract", "pyaml.common.abstract_aggregator", "pyaml.common.constants", @@ -40,6 +39,7 @@ "pyaml.control.deviceaccesslist", "pyaml.control.readback_value", "pyaml.diagnostics.atune_monitor", + "pyaml.diagnostics.bpm.bpm", "pyaml.diagnostics.tune_monitor", "pyaml.external.pySC_interface", "pyaml.lattice.abstract_impl", diff --git a/pyaml/arrays/bpm.py b/pyaml/arrays/bpm.py index 4ea849271..dd9d29969 100644 --- a/pyaml/arrays/bpm.py +++ b/pyaml/arrays/bpm.py @@ -88,4 +88,4 @@ def fill_array(self, holder: ElementHolder): holder : ElementHolder The element holder to populate the :py:class:`.BPMArray` with. """ - holder.bpms.add(self._name, self._elements) + holder.diagnostic.bpms.add(self._name, self._elements) diff --git a/pyaml/arrays/bpm_array.py b/pyaml/arrays/bpm_array.py index 9006af38c..f3751226e 100644 --- a/pyaml/arrays/bpm_array.py +++ b/pyaml/arrays/bpm_array.py @@ -6,7 +6,8 @@ import numpy as np -from ..bpm.bpm import BPM +from pyaml.diagnostics.bpm import BPM + from ..common.abstract import ReadFloatArray from ..control.deviceaccesslist import DeviceAccessList from .element_array import ElementArray @@ -24,7 +25,7 @@ class RWBPMPosition(ReadFloatArray): ---------- name : str Name of the position accessor - bpms : list[pyaml.bpm.bpm.BPM] + bpms : list[pyaml.diagnostics.bpm.bpm.BPM] List of BPM objects to access Methods @@ -98,7 +99,7 @@ class RWBPMSinglePosition(ReadFloatArray): ---------- name : str Name of the position accessor - bpms : list[pyaml.bpm.bpm.BPM] + bpms : list[pyaml.diagnostics.bpm.bpm.BPM] List of BPM objects to access idx : int Index for the position axis (0 for horizontal, 1 for vertical) @@ -170,7 +171,7 @@ class BPMArray(ElementArray): ---------- arrayName : str Array name - bpms : list[pyaml.bpm.bpm.BPM] + bpms : list[pyaml.diagnostics.bpm.bpm.BPM] BPM list, all elements must be attached to the same instance of either a (:py:class:`~pyaml.lattice.simulator.Simulator` or a :py:class:`~pyaml.control.controlsystem.ControlSystem`). diff --git a/pyaml/arrays/element.py b/pyaml/arrays/element.py index 6483f03de..4b93276a0 100644 --- a/pyaml/arrays/element.py +++ b/pyaml/arrays/element.py @@ -65,7 +65,7 @@ def fill_array(self, holder: ElementHolder): .. code-block:: python >>> elt_cfg.fill_array(sr.design) - >>> names = sr.design.get_elements("MyArray").names() + >>> names = sr.design.get("MyArray").names() >>> print(names) ['BPM_C04-01', 'SH1A-C04-H'] diff --git a/pyaml/arrays/element_array.py b/pyaml/arrays/element_array.py index 26b7ce260..d39d7cbbf 100644 --- a/pyaml/arrays/element_array.py +++ b/pyaml/arrays/element_array.py @@ -10,9 +10,11 @@ import numpy as np -from ..bpm.bpm import BPM +from pyaml.diagnostics.bpm import BPM + from ..common.element import Element, __pyaml_repr__ from ..common.exception import PyAMLException +from ..common.name_matching import resolve_names from ..magnet.cfm_magnet import CombinedFunctionMagnet from ..magnet.magnet import Magnet from ..magnet.serialized_magnet import SerializedMagnets @@ -60,7 +62,7 @@ class ElementArray(list[Element]): .. code-block:: python >>> sr = Accelerator.load("acc.yaml") - >>> elements = sr.design.get_elements("QuadForTune") + >>> elements = sr.design.get("QuadForTune") """ def __init__(self, array_name: str, elements: list[Element], use_aggregator=True): @@ -136,13 +138,17 @@ def __create_array(self, array_name: str, element_type: type, elements: list): array_class = getattr(m, "BPMArray", None) return array_class(array_name, elements, self.__use_aggregator) elif issubclass(element_type, CombinedFunctionMagnet): + # CombinedFunctionMagnetArray has no aggregator support, unlike the + # array type this selection was derived from. m = importlib.import_module("pyaml.arrays.cfm_magnet_array") array_class = getattr(m, "CombinedFunctionMagnetArray", None) - return array_class(array_name, elements, self.__use_aggregator) + return array_class(array_name, elements, False) elif issubclass(element_type, SerializedMagnets): + # SerializedMagnetsArray has no aggregator support, unlike the + # array type this selection was derived from. m = importlib.import_module("pyaml.arrays.serialized_magnet_array") array_class = getattr(m, "SerializedMagnetsArray", None) - return array_class(array_name, elements, self.__use_aggregator) + return array_class(array_name, elements, False) elif issubclass(element_type, Element): return ElementArray(array_name, elements, self.__use_aggregator) else: @@ -240,22 +246,6 @@ def mro_as_list(cls: type) -> list[type]: return self.__create_array("", chosen, elements) - def _select_names(self, pattern: str) -> "ElementArray": - """Select names without interpreting field selectors. - - Parameters - ---------- - pattern : str - A fnmatch pattern applied to each element name. - - Returns - ------- - ElementArray - Typed selection in the original order, including an empty array - when no names match. - """ - return self._typed_array([element for element in self if fnmatch.fnmatch(element.get_name(), pattern)]) - def __is_bool_mask(self, other: object) -> bool: """Return True if 'other' looks like a boolean mask (list or numpy array).""" # --- numpy boolean array --- @@ -293,7 +283,7 @@ def __and__(self, other: object): .. code-block:: python - >>> cell1 = sr.live.get_elements("C01") + >>> cell1 = sr.live.get("C01") >>> sexts = sr.live.get_magnets("SEXT") >>> cell1_sext = cell1 & sexts @@ -576,8 +566,15 @@ def __getitem__(self, key): Parameters ---------- - key : int, slice or str - Element index, slice, name pattern, or existing field selector. + key : int, slice, str, list[str] or tuple[str, ...] + Element index, slice, name pattern (or ``field:pattern`` field + selector), or a list/tuple of name patterns. A name pattern is a + literal name (must match an element in this array), an fnmatch + wildcard (``*``, ``?`` or ``[``), or a ``re:``-prefixed regular + expression. A list or tuple resolves each entry independently + and unions the results. Prefix a name pattern with ``~`` to + exclude its matches instead; a lone ``~pattern`` means every + element except those matches. Returns ------- @@ -585,33 +582,47 @@ def __getitem__(self, key): Indexed element or an array inferred from all selected elements. Different Magnet subclasses produce a MagnetArray; mixed element families produce an ElementArray. Empty selections return an - empty ElementArray. + empty ElementArray, except a literal name pattern (or literal + entry within a list/tuple) matching nothing, which raises. + + Raises + ------ + PyAMLException + If a literal name pattern, or a literal entry within a list or + tuple, matches no element in this array, or a ``re:`` pattern is + not a valid regular expression. Examples -------- >>> magnets = sr.design.magnets.get() >>> subset = magnets[:] # MagnetArray, including mixed magnet classes >>> correctors = magnets["SH*"] # MagnetArray + >>> correctors = magnets["re:^SH1A-C0[12]-H$"] # MagnetArray + >>> selection = magnets[["SH1A-C01-H", "SH*-V"]] # Union of patterns + >>> all_but_one = magnets["~SH1A-C01-H"] # Every magnet except one """ if isinstance(key, slice): # Slicing r = super().__getitem__(key) + elif isinstance(key, (list, tuple)): + # Selection by a list/tuple of name patterns + matched = set(resolve_names([e.get_name() for e in self], key)) + r = [e for e in self if e.get_name() in matched] + elif isinstance(key, str): - fields = key.split(":") + fields = [] if key.lstrip("~").startswith("re:") else key.split(":") if len(fields) <= 1: - # Selection by name - r = [] - for e in self: - if fnmatch.fnmatch(e.get_name(), key): - r.append(e) + # Selection by name pattern + matched = set(resolve_names([e.get_name() for e in self], key)) + r = [e for e in self if e.get_name() in matched] else: # Selection by fields r = [] for e in self: txt = self.__eval_field(fields[0], e) - if fnmatch.fnmatch(txt, fields[1]): + if fnmatch.fnmatchcase(txt, fields[1]): r.append(e) else: diff --git a/pyaml/bpm/__init__.py b/pyaml/bpm/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/pyaml/common/constants.py b/pyaml/common/constants.py index 4f8703a25..4d4ee5aca 100644 --- a/pyaml/common/constants.py +++ b/pyaml/common/constants.py @@ -20,15 +20,17 @@ class Action(Enum): Attributes ---------- APPLY : int - Callback triggered immediately after an actuator excitation. + Callback triggered after an actuator excitation completes (including the waiting time). RESTORE : int Callback triggered immediately after restoring the actuator. MEASURE : int Callback triggered immediately after taking a measurement. + INIT : int + Triggered once before the measurement starts """ APPLY = 0 - "Triggered immediately after actuator excitation." + "Triggered after an actuator excitation completes (including the waiting time)." RESTORE = 1 "Triggered immediately after restoring the actuator to its initial value." MEASURE = 2 diff --git a/pyaml/common/element.py b/pyaml/common/element.py index 7314c8d13..cdf83239a 100644 --- a/pyaml/common/element.py +++ b/pyaml/common/element.py @@ -232,7 +232,9 @@ class ElementConfigModel(BaseModel): - [name]@idx[,idx] : Element indices in the subset formed by name. - [name]#start_idx..end_idx : Element range in the subset formed by name. In the above syntax, if the name is not specficied, the whole set - of lattice element is used for indexing. + of lattice element is used for indexing. ``name`` refers to the + ``FamName`` of the lattice elements, or to the attribute configured + in the simulator linker when one is used. """ model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid") @@ -260,7 +262,9 @@ class Element: | ``[name]#start_idx..end_idx`` : Lattice element range in the subset formed by name. In the above syntax, if the name is not specficied, the whole set - of lattice element is used for indexing. + of lattice element is used for indexing. ``name`` refers to the + ``FamName`` of the lattice elements, or to the attribute configured + in the simulator linker when one is used. description : str or None, optional Human-readable element description. diff --git a/pyaml/common/holders/diagnostic_holder.py b/pyaml/common/holders/diagnostic_holder.py new file mode 100644 index 000000000..fa156c684 --- /dev/null +++ b/pyaml/common/holders/diagnostic_holder.py @@ -0,0 +1,146 @@ +"""Holder interface for diagnostics.""" + +from typing import TYPE_CHECKING + +from ...arrays.element_array import ElementArray +from ...diagnostics.tune_monitor import BetatronTuneMonitor +from ..element import Element, __pyaml_repr__ +from ..exception import PyAMLException +from ..name_matching import is_wildcard, resolve_names +from .sub_holders import BPMHolder, BPMsHolder + +if TYPE_CHECKING: + from .element_holder import ElementHolder + + +class DiagnosticHolder: + """ + Provide access to diagnostics. + + Parameters + ---------- + peer : 'ElementHolder' + Parent holder containing the diagnostic store. + + Attributes + ---------- + bpm, bpms + Single BPM by name, or a named BPM array. + betatron_tune + Betatron tune monitor configured as ``BETATRON_TUNE``, the default, validated + against its expected class. + + Methods + ------- + get(name=None) + Return a named diagnostic, or all configured diagnostics when no name is given. + + Examples + -------- + >>> default_tune_monitor = sr.live.diagnostic.betatron_tune + >>> measured_tune = default_tune_monitor.tune.get() + >>> spare_tune_monitor = sr.live.diagnostic.get("SPARE_BETATRON_TUNE_MONITOR") + >>> all_diagnostics = sr.live.diagnostic.get() + >>> bpm = sr.live.diagnostic.bpm.get("BPM01") + >>> bpms = sr.live.diagnostic.bpms.get("BPMS") + """ + + def __init__(self, peer: "ElementHolder"): + """ + Initialize a diagnostic holder for an element holder. + """ + self._peer = peer + self._bpm_holder = BPMHolder(peer) + self._bpms_holder = BPMsHolder(peer) + + @property + def bpm(self) -> BPMHolder: + """Return the bpm.""" + return self._bpm_holder + + @property + def bpms(self) -> BPMsHolder: + """Return the bpms.""" + return self._bpms_holder + + def get(self, name: str = None) -> "Element | ElementArray": + """ + Return a named diagnostic, or all configured diagnostics when no name is given. + + Parameters + ---------- + name : str, optional + Name of the diagnostic to look up, as declared in the configuration. When + omitted, every configured diagnostic is returned instead. + + Returns + ------- + Element or ElementArray + The diagnostic registered under ``name``, or an + :class:`~pyaml.arrays.element_array.ElementArray` holding every configured + diagnostic, in insertion order, when ``name`` is omitted. + + Raises + ------ + PyAMLException + If ``name`` is given and no diagnostic is registered under it. + """ + if name is None: + return ElementArray("", list(self._peer._DIAG.values())) + return self._peer._get_diagnostic(name) + + def __getitem__(self, key: str | list[str] | tuple[str, ...]) -> "Element | ElementArray": + """ + Return a diagnostic, or a selection typed as a generic ElementArray. + + Parameters + ---------- + key : str, list[str] or tuple[str, ...] + An exact literal name returns the stored diagnostic. An fnmatch + wildcard, a ``re:``-prefixed regular expression, or a list/tuple + of such patterns returns an ElementArray of matches (possibly + empty). + + Returns + ------- + Element or ElementArray + The stored diagnostic for an exact literal name, otherwise an + ElementArray of matches. + + Raises + ------ + PyAMLException + If an exact literal name, or a literal entry within a list or + tuple, does not match any diagnostic, or a ``re:`` pattern is + not a valid regular expression. + """ + store = self._peer._DIAG + if isinstance(key, str) and not key.startswith(("re:", "~")) and not is_wildcard(key): + return self._peer._get_diagnostic(key) + matched = set(resolve_names(store.keys(), key, what="Diagnostic")) + return ElementArray("", [v for n, v in store.items() if n in matched]) + + @property + def betatron_tune(self) -> BetatronTuneMonitor: + """ + Return the betatron tune monitor configured as ``BETATRON_TUNE``. + + Returns + ------- + BetatronTuneMonitor + Betatron tune monitor registered under ``BETATRON_TUNE``. + + Raises + ------ + PyAMLException + If no diagnostic is registered under ``BETATRON_TUNE``, or if it is not a + :class:`~pyaml.diagnostics.tune_monitor.BetatronTuneMonitor`. + """ + name = "BETATRON_TUNE" + obj = self.get(name) + if not isinstance(obj, BetatronTuneMonitor): + raise PyAMLException(f"{name}: BetatronTuneMonitor expected but got {type(obj).__name__}") + return obj + + def __repr__(self): + return __pyaml_repr__(self) diff --git a/pyaml/common/holders/element_holder.py b/pyaml/common/holders/element_holder.py index aa2b16dc0..1cf63dfb1 100644 --- a/pyaml/common/holders/element_holder.py +++ b/pyaml/common/holders/element_holder.py @@ -1,26 +1,24 @@ """Store, resolve, and group elements shared by runtime backends.""" -import fnmatch -import re from abc import ABCMeta, abstractmethod from typing import TYPE_CHECKING, overload +from pyaml.diagnostics.bpm import BPM + from ...arrays.element_array import ElementArray -from ...bpm.bpm import BPM from ...diagnostics.tune_monitor import BetatronTuneMonitor from ...magnet.cfm_magnet import CombinedFunctionMagnet from ...magnet.magnet import Magnet from ...magnet.serialized_magnet import SerializedMagnets from ...rf.rf_plant import RFPlant from ...rf.rf_transmitter import RFTransmitter -from ...tuning_tools.chromaticity_monitor import ChromaticityMonitor from ..abstract_aggregator import ScalarAggregator from ..element import Element from ..exception import PyAMLException +from ..name_matching import is_wildcard, resolve_names +from .diagnostic_holder import DiagnosticHolder from .rf_holder import RFHolder from .sub_holders import ( - BPMHolder, - BPMsHolder, CombinedFunctionMagnetHolder, CombinedFunctionMagnetsHolder, MagnetHolder, @@ -28,19 +26,12 @@ SerializedMagnetHolder, SerializedMagnetsHolder, ) +from .tool_holder import ToolHolder if TYPE_CHECKING: from ...accelerator import Accelerator from ...configuration.unbound_element import UnboundElement - from ...tuning_tools.bba import BBA - from ...tuning_tools.chromaticity import Chromaticity - from ...tuning_tools.chromaticity_response_matrix import ChromaticityResponseMatrix - from ...tuning_tools.dispersion import Dispersion from ...tuning_tools.measurement_tool import MeasurementTool - from ...tuning_tools.orbit import Orbit - from ...tuning_tools.orbit_response_matrix import OrbitResponseMatrix - from ...tuning_tools.tune import Tune - from ...tuning_tools.tune_response_matrix import TuneResponseMatrix from ...tuning_tools.tuning_tool import TuningTool @@ -57,18 +48,16 @@ class ElementHolder(metaclass=ABCMeta): ---------- magnet, magnets Single magnet by name, or a named magnet array. - bpm, bpms - Single BPM by name, or a named BPM array. combined_function_magnet, combined_function_magnets Single combined-function magnet by name, or a named array. serialized_magnet, serialized_magnets Single serialized magnet group by name, or a named array. rf RF plant and transmitters of this mode. - tune, chromaticity, orbit, dispersion - Tuning tools attached to this mode, looked up by name. - trm, crm, orm - Response-matrix measurement tools, looked up by name. + diagnostic + Diagnostics of this mode, with typed default-name access. + tool + Tuning and measurement tools of this mode, with typed default-name access. Methods ------- @@ -88,36 +77,12 @@ class ElementHolder(metaclass=ABCMeta): Create and register a generic element array. add_element(element) Add an element to the global element store. - get_element(name) - Return a named element from the global store. - get_elements(name) - Return a named generic element array. - get_all_elements() - Return all registered elements in insertion order. - get_betatron_tune_monitor(name) - Return a named betatron tune monitor. + get(name=None) + Return a named element array, or every registered element when no name is given. add_betatron_tune_monitor(tune_monitor) Add a betatron tune monitor to the diagnostics store. add_tool(tool) Add a tuning or measurement tool to the tool store. - get_chromaticity_monitor(name) - Return a named chromaticity monitor. - get_chromaticity_tuning(name) - Return a named chromaticity tuning tool. - get_crm_tuning(name) - Return a named chromaticity response-matrix tool. - get_tune_tuning(name) - Return a named tune correction tool. - get_trm_tuning(name) - Return a named tune response-matrix tool. - get_orbit_tuning(name) - Return a named orbit correction tool. - get_orm_tuning(name) - Return a named orbit response-matrix tool. - get_bba(name) - Return a named beam-based alignment tool. - get_dispersion_tuning(name) - Return a named dispersion tuning tool. """ def __init__(self): @@ -156,9 +121,9 @@ def __init__(self): self._serialized_magnets_holder = SerializedMagnetsHolder(self) self._combined_function_magnet_holder = CombinedFunctionMagnetHolder(self) self._combined_function_magnets_holder = CombinedFunctionMagnetsHolder(self) - self._bpm_holder = BPMHolder(self) - self._bpms_holder = BPMsHolder(self) self._rf_holder = RFHolder(self) + self._diagnostic_holder = DiagnosticHolder(self) + self._tool_holder = ToolHolder(self) @property def peer(self) -> "Accelerator": @@ -198,23 +163,23 @@ def combined_function_magnets(self) -> CombinedFunctionMagnetsHolder: return self._combined_function_magnets_holder @property - def bpm(self) -> BPMHolder: - """Return the bpm.""" - return self._bpm_holder + def rf(self) -> RFHolder: + """Return the rf.""" + return self._rf_holder @property - def bpms(self) -> BPMsHolder: - """Return the bpms.""" - return self._bpms_holder + def diagnostic(self) -> DiagnosticHolder: + """Return the diagnostic.""" + return self._diagnostic_holder @property - def rf(self) -> RFHolder: - """Return the rf.""" - return self._rf_holder + def tool(self) -> ToolHolder: + """Return the tool.""" + return self._tool_holder def post_init(self): """Run post-initialization hooks for every stored element.""" - for e in self.get_all_elements(): + for e in self._ALL.values(): e.post_init() def fill_device(self, elements: list[Element]): @@ -308,29 +273,34 @@ def create_bpm_aggregators(self, bpms: list[BPM]) -> list[ScalarAggregator | Non # Elements - def find_elements(self, filter: str) -> list[str]: + def find_elements(self, filter: str | list[str] | tuple[str, ...]) -> list[str]: """ - Find element names matching a literal, wildcard, or regular expression. + Find element names matching one or several literal, wildcard, or regex patterns. Parameters ---------- - filter : str - Pattern to match. Prefix with ``re:`` for a regular expression. + filter : str, list[str] or tuple[str, ...] + Pattern, or patterns, to match. A pattern is a literal name, an + fnmatch wildcard (``*``, ``?`` or ``[`` anywhere in the string), + or a regular expression prefixed with ``re:``. Prefix any of + those with ``~`` to exclude its matches instead, as in the + ``elements:`` selector list of a YAML array declaration, e.g. + ``["QD2*", "QF1*", "~QF1E-C05"]``. A lone ``~pattern`` (or a list + made only of ``~`` entries) means "every element except those". Returns ------- list[str] Matching element names. - """ - if filter.startswith("re:"): - pattern = re.compile(rf"{filter[3:]}") - elements = [k for k in self._ALL.keys() if pattern.fullmatch(k)] - elif "*" in filter or "?" in filter: - elements = [k for k in self._ALL.keys() if fnmatch.fnmatch(k, filter)] - else: - elements = [filter] - return elements + Raises + ------ + PyAMLException + If a literal pattern (or a ``~``-prefixed literal) matches no + element, or a ``re:`` pattern is not a valid regular expression. + """ + matched = set(resolve_names(self._ALL.keys(), filter, what="Element")) + return [n for n in self._ALL if n in matched] def _fill_array( self, @@ -340,7 +310,6 @@ def _fill_array( constructor, ARR: dict, ): - # Handle wildcard, regexp and exclusion pattern """ Resolve selectors and store a constructed element array. @@ -358,16 +327,14 @@ def _fill_array( Destination array store. """ all_names: list[str] = [] - excluded_names: list[str] = [] + excluded_names: set[str] = set() for name in element_names: if name.startswith("~"): - names = self.find_elements(name[1:]) - excluded_names.extend(names) + excluded_names.update(self.find_elements(name[1:])) else: - names = self.find_elements(name) - all_names.extend(names) + all_names.extend(self.find_elements(name)) - [all_names.remove(name) for name in excluded_names] + all_names = [n for n in all_names if n not in excluded_names] a = [] for n in all_names: @@ -376,7 +343,7 @@ def _fill_array( except Exception as err: raise PyAMLException(f"{constructor.__name__} {array_name} : {err} @index {len(a)}") from None if m in a: - raise PyAMLException(f"{constructor.__name__} {array_name} : duplicate name {name} @index {len(a)}") from None + raise PyAMLException(f"{constructor.__name__} {array_name} : duplicate name {n} @index {len(a)}") from None a.append(m) ARR[array_name] = constructor(array_name, a) @@ -419,13 +386,27 @@ def _get(self, what, name, array) -> Element: return array[name] # Generic elements - def get(self) -> ElementArray: - """Return all registered elements in insertion order. + def get(self, name: str | None = None) -> ElementArray: + """Return a named element array, or every registered element when no name is given. + + Parameters + ---------- + name : str, optional + Name of the element array to look up, as declared in the configuration. + When omitted, every registered element is returned instead. Returns ------- ElementArray - New unnamed container sharing the registered element references. + The element array registered under ``name``, regardless of its concrete + family (magnet, BPM, combined-function magnet, serialized-magnet, or + generic element array), or a new unnamed container of every registered + element, in insertion order, when ``name`` is omitted. + + Raises + ------ + PyAMLException + If ``name`` is given and no array is registered under it. Notes ----- @@ -437,8 +418,11 @@ def get(self) -> ElementArray: -------- >>> elements = sr.live.get() >>> names = elements.names() + >>> cell08 = sr.live.get("CELL08") """ - return ElementArray("", list(self._ALL.values())) + if name is None: + return ElementArray("", list(self._ALL.values())) + return self._get_array(name) @overload def __getitem__(self, key: int) -> Element: ... @@ -447,32 +431,46 @@ def __getitem__(self, key: int) -> Element: ... def __getitem__(self, key: slice) -> ElementArray: ... @overload - def __getitem__(self, key: str) -> Element | ElementArray | None: ... + def __getitem__(self, key: str) -> Element: ... - def __getitem__(self, key: int | slice | str) -> Element | ElementArray | None: + @overload + def __getitem__(self, key: list[str] | tuple[str, ...]) -> ElementArray: ... + + def __getitem__(self, key: int | slice | str | list[str] | tuple[str, ...]) -> Element | ElementArray: """Retrieve an element or select a collection. Parameters ---------- - key : int, slice or str - Index in registration order, slice, exact name, or name pattern. - Strings containing ``*``, ``?`` or ``[`` use fnmatch matching. - Other strings are exact registry keys. Colons are literal. + key : int, slice, str, list[str] or tuple[str, ...] + Index in registration order, slice, exact name, name pattern, or + a list/tuple of patterns. Strings containing ``*``, ``?`` or + ``[`` use fnmatch matching; a ``re:`` prefix uses a regular + expression instead. Any other string is an exact registry key. + Colons are literal. A list or tuple resolves each entry + independently and unions the results. Prefix any pattern with + ``~`` to exclude its matches instead, as in a YAML array's + ``elements:`` list; a lone ``~pattern`` means every element + except those matches. Returns ------- - Element or ElementArray or None - An index returns an element. An exact name returns its element - or None. Patterns and slices return the most specific compatible - array, or an empty ElementArray when nothing matches. + Element or ElementArray + An index or an exact literal name returns its element. Patterns, + lists/tuples of patterns, and slices return the most specific + compatible array, or an empty ElementArray when nothing matches. The full slice ``[:]`` returns a generic ElementArray, like get(). Raises ------ + PyAMLException + If an exact literal name, or a literal entry within a list or + tuple, does not match any registered element, or if a ``re:`` + pattern is not a valid regular expression. IndexError If the index is out of bounds. TypeError - If the key is neither an integer, a slice, nor a string. + If the key is neither an integer, a slice, a string, nor a + list/tuple of strings. ValueError If a slice has a zero step. @@ -480,25 +478,35 @@ def __getitem__(self, key: int | slice | str) -> Element | ElementArray | None: ----- Indices follow insertion order, not necessarily lattice order. Collections share element references but do not modify the registry. - Field filters and regular expressions are not interpreted here. + Field filters are not interpreted here. Examples -------- >>> bpm = sr.live["BPM01"] - >>> missing = sr.live["UNKNOWN"] # None + >>> missing = sr.live["UNKNOWN"] # raises PyAMLException >>> bpms = sr.live["BPM*"] >>> bpms = sr.live["BPM0[123]"] # BPM01, BPM02 or BPM03 >>> bpms = sr.live["BPM0[1-3]"] # Same selection using a range >>> quads = sr.live["Q[FD]*"] # Names starting with QF or QD >>> bpms = sr.live["BPM0[!3]"] # One character after BPM0, except 3 + >>> bpms = sr.live["re:^BPM0[12]$"] # Regular expression + >>> mixed = sr.live[["BPM01", "QF1*"]] # Union of several patterns + >>> all_but_one = sr.live["~BPM01"] # Every element except BPM01 + >>> most_quads = sr.live[["QF1*", "~QF1A-C01"]] # QF1* minus one name >>> first = sr.live[0] >>> subset = sr.live[1:10] >>> all_elements = sr.live[:] """ if isinstance(key, str): - if any(marker in key for marker in "*?["): - return self.get()._select_names(key) - return self._ALL.get(key) + if key.startswith("re:") or key.startswith("~") or is_wildcard(key): + matched = set(resolve_names(self._ALL.keys(), key)) + return self.get()._typed_array([v for n, v in self._ALL.items() if n in matched]) + if key not in self._ALL: + raise PyAMLException(f"Element {key} not defined") + return self._ALL[key] + if isinstance(key, (list, tuple)): + matched = set(resolve_names(self._ALL.keys(), key)) + return self.get()._typed_array([v for n, v in self._ALL.items() if n in matched]) if isinstance(key, int): return list(self._ALL.values())[key] if isinstance(key, slice): @@ -506,7 +514,7 @@ def __getitem__(self, key: int | slice | str) -> Element | ElementArray | None: if key == slice(None): return elements return elements._typed_array(list(elements)[key]) - raise TypeError("ElementHolder keys must be integers, slices or strings") + raise TypeError("ElementHolder keys must be integers, slices, strings, or lists/tuples of strings") def fill_element_array(self, arrayName: str, elementNames: list[str]): """ @@ -522,7 +530,7 @@ def fill_element_array(self, arrayName: str, elementNames: list[str]): self._fill_array( arrayName, elementNames, - self.get_element, + self._get_element, ElementArray, self._ELEMENT_ARRAYS, ) @@ -538,60 +546,14 @@ def add_element(self, element: Element): """ self._ALL[element.get_name()] = element - def get_element(self, name: str) -> Element: + def _get_element(self, name: str) -> Element: """ - Return a named element from the global store. - - Parameters - ---------- - name : str - Name of the element to look up, as declared in the configuration. - - Returns - ------- - Element - The element registered under ``name``. + Generic single-element resolver used internally to build element arrays. """ return self._get("Element", name, self._ALL) - def get_elements(self, name: str) -> ElementArray: - """ - Return a named generic element array. - - Parameters - ---------- - name : str - Name of the element array to look up, as declared in the configuration. - - Returns - ------- - ElementArray - The element array registered under ``name``. - """ - return self._get("Element array", name, self._ELEMENT_ARRAYS) - - def get_all_elements(self) -> list[Element]: - """Return all registered elements in insertion order.""" - return [value for key, value in self._ALL.items()] - # Tune monitor - def get_betatron_tune_monitor(self, name: str) -> BetatronTuneMonitor: - """ - Return a named betatron tune monitor. - - Parameters - ---------- - name : str - Name of the betatron tune monitor to look up, as declared in the configuration. - - Returns - ------- - BetatronTuneMonitor - The betatron tune monitor registered under ``name``. - """ - return self._get("Diagnostic", name, self._DIAG) - def add_betatron_tune_monitor(self, tune_monitor: Element): """ Add a betatron tune monitor to the diagnostics store. @@ -616,196 +578,6 @@ def add_tool(self, tool: Element): """ self._add(self._TOOLS, tool) - # ---- Chromaticity ------------------------------------------------- - - def get_chromaticity_monitor(self, name: str) -> ChromaticityMonitor: - """ - Return a named chromaticity monitor. - - Parameters - ---------- - name : str - Name of the chromaticity monitor to look up, as declared in the configuration. - - Returns - ------- - ChromaticityMonitor - The chromaticity monitor registered under ``name``. - """ - obj = self._get("Chromaticity monitor", name, self._TOOLS) - return obj - - def get_chromaticity_tuning(self, name: str) -> "Chromaticity": - """ - Return a named chromaticity tuning tool. - - Parameters - ---------- - name : str - Name of the chromaticity tuning tool to look up, as declared in the configuration. - - Returns - ------- - 'Chromaticity' - The chromaticity tuning tool registered under ``name``. - """ - return self._get("Chromaticity tool", name, self._TOOLS) - - def get_crm_tuning(self, name: str) -> "ChromaticityResponseMatrix": - """ - Return a named chromaticity response-matrix tool. - - Parameters - ---------- - name : str - Name of the chromaticity response-matrix tool to look up, as declared in the configuration. - - Returns - ------- - 'ChromaticityResponseMatrix' - The chromaticity response-matrix tool registered under ``name``. - """ - return self._get("ChromaticityResponseMatrix tool", name, self._TOOLS) - - @property - def chromaticity(self) -> "Chromaticity": - """Return the chromaticity.""" - return self.get_chromaticity_tuning("DEFAULT_CHROMATICITY_CORRECTION") - - @property - def crm(self) -> "ChromaticityResponseMatrix": - """Return the crm.""" - return self.get_crm_tuning("DEFAULT_CHROMATICITY_RESPONSE_MATRIX") - - # ---- Tune --------------------------------------------------------- - - def get_tune_tuning(self, name: str) -> "Tune": - """ - Return a named tune correction tool. - - Parameters - ---------- - name : str - Name of the tune correction tool to look up, as declared in the configuration. - - Returns - ------- - 'Tune' - The tune correction tool registered under ``name``. - """ - return self._get("Tune tuning tool", name, self._TOOLS) - - @property - def tune(self) -> "Tune": - """Return the tune.""" - return self.get_tune_tuning("DEFAULT_TUNE_CORRECTION") - - def get_trm_tuning(self, name: str) -> "TuneResponseMatrix": - """ - Return a named tune response-matrix tool. - - Parameters - ---------- - name : str - Name of the tune response-matrix tool to look up, as declared in the configuration. - - Returns - ------- - 'TuneResponseMatrix' - The tune response-matrix tool registered under ``name``. - """ - return self._get("TuneResponseMatrix tool", name, self._TOOLS) - - @property - def trm(self) -> "TuneResponseMatrix": - """Return the default tune response-matrix tool.""" - return self.get_trm_tuning("DEFAULT_TUNE_RESPONSE_MATRIX") - - # ---- Orbit -------------------------------------------------------- - - def get_orbit_tuning(self, name: str) -> "Orbit": - """ - Return a named orbit correction tool. - - Parameters - ---------- - name : str - Name of the orbit correction tool to look up, as declared in the configuration. - - Returns - ------- - 'Orbit' - The orbit correction tool registered under ``name``. - """ - return self._get("Orbit tuning tool", name, self._TOOLS) - - @property - def orbit(self) -> "Orbit": - """Return the orbit.""" - return self.get_orbit_tuning("DEFAULT_ORBIT_CORRECTION") - - def get_orm_tuning(self, name: str) -> "OrbitResponseMatrix": - """ - Return a named orbit response-matrix tool. - - Parameters - ---------- - name : str - Name of the orbit response-matrix tool to look up, as declared in the configuration. - - Returns - ------- - 'OrbitResponseMatrix' - The orbit response-matrix tool registered under ``name``. - """ - return self._get("OrbitResponseMatrix tool", name, self._TOOLS) - - @property - def orm(self) -> "OrbitResponseMatrix": - """Return the default orbit response-matrix tool.""" - return self.get_orm_tuning("DEFAULT_ORBIT_RESPONSE_MATRIX") - - # ---- BBA -------------------------------------------------------- - - def get_bba(self, name: str) -> "BBA": - """ - Return a named beam-based alignment tool. - - Parameters - ---------- - name : str - Name of the beam-based alignment tool to look up, as declared in the configuration. - - Returns - ------- - 'BBA' - The beam-based alignment tool registered under ``name``. - """ - return self._get("BBA tool", name, self._TOOLS) - - # ---- Dispersive orbit -------------------------------------------- - - def get_dispersion_tuning(self, name: str) -> "Dispersion": - """ - Return a named dispersion tuning tool. - - Parameters - ---------- - name : str - Name of the dispersion tuning tool to look up, as declared in the configuration. - - Returns - ------- - 'Dispersion' - The dispersion tuning tool registered under ``name``. - """ - return self._get("Dispersion tool", name, self._TOOLS) - - @property - def dispersion(self) -> "Dispersion": - """Return the dispersion.""" - return self.get_dispersion_tuning("DEFAULT_DISPERSION") - def _get_array(self, name: str): """ Generic array resolver used by YellowPages. @@ -876,7 +648,7 @@ def _set_energy(self, E: float): Energy in eV """ # Needed by energy dependant element (i.e. magnet coil current calculation) - for m in self.get_all_elements(): + for m in self._ALL.values(): m.set_energy(E) def _set_mcf(self, alphac: float): @@ -889,7 +661,7 @@ def _set_mcf(self, alphac: float): Moment compaction factor """ # Needed by some off energy dependant element (i.e. chromaticty tools) - for m in self.get_all_elements(): + for m in self._ALL.values(): m.set_mcf(alphac) def _set_harmonic(self, h: int): @@ -901,5 +673,5 @@ def _set_harmonic(self, h: int): h : int Harmonic number """ - for m in self.get_all_elements(): + for m in self._ALL.values(): m.set_harmonic(h) diff --git a/pyaml/common/holders/generic_array_holder.py b/pyaml/common/holders/generic_array_holder.py index 0ce624410..50fec2c19 100644 --- a/pyaml/common/holders/generic_array_holder.py +++ b/pyaml/common/holders/generic_array_holder.py @@ -42,6 +42,13 @@ class GenericArrayHolder(Generic[T, A]): Return a named array or a transient array of all elements. add(arrayName, elementNames) Create and register a named array from element selectors. + + Notes + ----- + A configured array is also reachable as an attribute when its name is a + valid Python identifier, e.g. ``holder.QuadForTune`` is equivalent to + ``holder.get("QuadForTune")``. Array names appear in ``dir(holder)`` so + interactive completion (IPython, Jupyter) discovers them. """ def __init__( @@ -103,19 +110,87 @@ def add(self, arrayName: str, elementNames: list[str]): def __getitem__(self, key): """ - Return an element from the aggregate array by index. + Select from the aggregate array of every individual element. + + Delegates to :meth:`ElementArray.__getitem__ + ` on ``self.get()`` + (the array of every individual element of this type), so ``key`` + matches against **individual element names**, not against the + registered array/family names that :meth:`get` searches. These are + deliberately two different, non-overlapping namespaces: ``get(name)`` + looks up a configured family (e.g. ``"QForTune"``), while ``[key]`` + looks up the elements themselves (e.g. ``"QF1A-C01"`` or ``"QF1*"``). Parameters ---------- - key : int or slice - Index or slice passed to the aggregate array. + key : int, slice, str, list[str] or tuple[str, ...] + Index or slice into the aggregate array, an individual element's + exact name, an fnmatch wildcard or ``re:`` regular expression + over element names, or a list/tuple of such patterns. Returns ------- object Element or sub-array selected by ``key``. + + Raises + ------ + PyAMLException + If ``key`` is an exact literal element name (or a literal entry + within a list or tuple) that matches no individual element, or a + ``re:`` pattern is not a valid regular expression. + + Examples + -------- + >>> family = sr.live.magnets.get("QForTune") # array-name namespace + >>> one_magnet = sr.live.magnets["QF1A-C01"] # element-name namespace + >>> some_magnets = sr.live.magnets["QF1*"] # element-name namespace """ return self.get().__getitem__(key) + def __getattr__(self, name: str) -> A: + """ + Return a configured array through attribute access. + + Only called when normal attribute lookup fails, so it never shadows + :meth:`get`, :meth:`add`, or any other existing attribute. + + Parameters + ---------- + name : str + Configured array name. Must be a valid Python identifier. + + Returns + ------- + A + The array registered under ``name``. + + Raises + ------ + AttributeError + If ``name`` starts with an underscore, is not a valid Python + identifier, or does not match a configured array. + + Examples + -------- + >>> quad_family = sr.live.magnets.get("QuadForTune") + >>> same_quad_family = sr.live.magnets.QuadForTune + """ + if name.startswith("_") or not name.isidentifier() or name not in self._array_store: + raise AttributeError(f"'{type(self).__name__}' object has no array named '{name}'") + return self._array_store[name] + + def __dir__(self) -> list[str]: + """ + List attributes, including configured array names. + + Returns + ------- + list of str + Default attributes plus configured array names that are valid + Python identifiers, for interactive completion (IPython, Jupyter). + """ + return sorted(set(super().__dir__()) | {name for name in self._array_store if name.isidentifier()}) + def __repr__(self): return __pyaml_repr__(self) diff --git a/pyaml/common/holders/generic_element_holder.py b/pyaml/common/holders/generic_element_holder.py index a23dec8b0..d5c404ffe 100644 --- a/pyaml/common/holders/generic_element_holder.py +++ b/pyaml/common/holders/generic_element_holder.py @@ -2,7 +2,9 @@ from typing import TYPE_CHECKING, Generic, TypeVar +from ...arrays.element_array import ElementArray from ..element import Element, __pyaml_repr__ +from ..name_matching import is_wildcard, resolve_names if TYPE_CHECKING: from .element_holder import ElementHolder @@ -73,6 +75,38 @@ def get(self, name: str) -> T: """ return self._peer._get(self._what, name, self._store) + def __getitem__(self, key: str | list[str] | tuple[str, ...]) -> "T | ElementArray": + """ + Return an element, or a selection typed as the most specific compatible array. + + Parameters + ---------- + key : str, list[str] or tuple[str, ...] + An exact literal name returns the stored element. An fnmatch + wildcard (``*``, ``?`` or ``[``), a ``re:``-prefixed regular + expression, or a list/tuple of such patterns returns the most + specific compatible array of matches (possibly empty), like + :meth:`.ElementHolder.__getitem__`. + + Returns + ------- + T or ElementArray + The stored element for an exact literal name, otherwise a + typed array of matches. + + Raises + ------ + PyAMLException + If an exact literal name, or a literal entry within a list or + tuple, does not match any element in this holder, or a ``re:`` + pattern is not a valid regular expression. + """ + if isinstance(key, str) and not key.startswith(("re:", "~")) and not is_wildcard(key): + return self._peer._get(self._what, key, self._store) + matched = set(resolve_names(self._store.keys(), key, what=self._what)) + elements = [v for n, v in self._store.items() if n in matched] + return ElementArray("", elements)._typed_array(elements) + def add(self, m: T): """ Add an element to the holder's name-indexed store. diff --git a/pyaml/common/holders/rf_holder.py b/pyaml/common/holders/rf_holder.py index 257c396a4..43c070284 100644 --- a/pyaml/common/holders/rf_holder.py +++ b/pyaml/common/holders/rf_holder.py @@ -2,10 +2,12 @@ from typing import TYPE_CHECKING +from ...arrays.element_array import ElementArray from ...rf.rf_plant import RFPlant from ...rf.rf_transmitter import RFTransmitter from ..abstract import ReadWriteFloatScalar from ..element import __pyaml_repr__ +from ..name_matching import is_wildcard, resolve_names if TYPE_CHECKING: from .element_holder import ElementHolder @@ -50,6 +52,37 @@ def get(self, name: str) -> RFTransmitter: """ return self._peer._get("RFTransmitter", name, self._peer._RFTRANSMITTER) + def __getitem__(self, key: str | list[str] | tuple[str, ...]) -> "RFTransmitter | ElementArray": + """ + Return a transmitter, or a selection typed as a generic ElementArray. + + Parameters + ---------- + key : str, list[str] or tuple[str, ...] + An exact literal name returns the stored transmitter. An fnmatch + wildcard, a ``re:``-prefixed regular expression, or a list/tuple + of such patterns returns an ElementArray of matches (possibly + empty). + + Returns + ------- + RFTransmitter or ElementArray + The stored transmitter for an exact literal name, otherwise an + ElementArray of matches. + + Raises + ------ + PyAMLException + If an exact literal name, or a literal entry within a list or + tuple, does not match any transmitter, or a ``re:`` pattern is + not a valid regular expression. + """ + store = self._peer._RFTRANSMITTER + if isinstance(key, str) and not key.startswith(("re:", "~")) and not is_wildcard(key): + return self._peer._get("RFTransmitter", key, store) + matched = set(resolve_names(store.keys(), key, what="RFTransmitter")) + return ElementArray("", [v for n, v in store.items() if n in matched]) + def add(self, rf: RFTransmitter): """ Add an RF transmitter to the holder. @@ -134,6 +167,37 @@ def get(self, name: str) -> RFPlant: """ return self._peer._get("RFPlant", name, self._peer._RFPLANT) + def __getitem__(self, key: str | list[str] | tuple[str, ...]) -> "RFPlant | ElementArray": + """ + Return an RF plant, or a selection typed as a generic ElementArray. + + Parameters + ---------- + key : str, list[str] or tuple[str, ...] + An exact literal name returns the stored RF plant. An fnmatch + wildcard, a ``re:``-prefixed regular expression, or a list/tuple + of such patterns returns an ElementArray of matches (possibly + empty). + + Returns + ------- + RFPlant or ElementArray + The stored RF plant for an exact literal name, otherwise an + ElementArray of matches. + + Raises + ------ + PyAMLException + If an exact literal name, or a literal entry within a list or + tuple, does not match any RF plant, or a ``re:`` pattern is not + a valid regular expression. + """ + store = self._peer._RFPLANT + if isinstance(key, str) and not key.startswith(("re:", "~")) and not is_wildcard(key): + return self._peer._get("RFPlant", key, store) + matched = set(resolve_names(store.keys(), key, what="RFPlant")) + return ElementArray("", [v for n, v in store.items() if n in matched]) + def add(self, rf: RFPlant): """ Add an RF plant to the holder. diff --git a/pyaml/common/holders/sub_holders.py b/pyaml/common/holders/sub_holders.py index 399485eb0..7d2bdc0ac 100644 --- a/pyaml/common/holders/sub_holders.py +++ b/pyaml/common/holders/sub_holders.py @@ -2,11 +2,12 @@ from typing import TYPE_CHECKING +from pyaml.diagnostics.bpm import BPM + from ...arrays.bpm_array import BPMArray from ...arrays.cfm_magnet_array import CombinedFunctionMagnetArray from ...arrays.magnet_array import MagnetArray from ...arrays.serialized_magnet_array import SerializedMagnetsArray -from ...bpm.bpm import BPM from ...magnet.cfm_magnet import CombinedFunctionMagnet from ...magnet.magnet import Magnet from ...magnet.serialized_magnet import SerializedMagnets @@ -42,6 +43,19 @@ class MagnetsHolder(GenericArrayHolder[Magnet, MagnetArray]): ---------- peer : 'ElementHolder' Parent element holder that owns this specialized holder. + + Notes + ----- + A configured magnet family is also reachable as an attribute when its + name is a valid Python identifier, e.g. ``magnets.QuadForTune`` is + equivalent to ``magnets.get("QuadForTune")``. Family names appear in + ``dir(magnets)`` for interactive completion. + + Examples + -------- + >>> quad_family = sr.live.magnets.get("QuadForTune") + >>> same_quad_family = sr.live.magnets.QuadForTune + >>> combined_function_magnets = sr.live.magnets.get_cfm() """ def __init__(self, peer: "ElementHolder"): @@ -57,6 +71,22 @@ def __init__(self, peer: "ElementHolder"): "Magnet array", ) + def get_cfm(self) -> CombinedFunctionMagnetArray: + """ + Return all combined-function magnets. + + Returns + ------- + CombinedFunctionMagnetArray + New unnamed container with every registered combined-function + magnet. + + Examples + -------- + >>> combined_function_magnets = sr.live.magnets.get_cfm() + """ + return self._peer.combined_function_magnets.get() + class CombinedFunctionMagnetHolder(GenericElementHolder[CombinedFunctionMagnet]): """ @@ -83,6 +113,13 @@ class CombinedFunctionMagnetsHolder(GenericArrayHolder[CombinedFunctionMagnet, C ---------- peer : 'ElementHolder' Parent element holder that owns this specialized holder. + + Notes + ----- + A configured array is also reachable as an attribute when its name is a + valid Python identifier, e.g. ``combined_function_magnets.CFM`` is + equivalent to ``combined_function_magnets.get("CFM")``. Array names + appear in ``dir(combined_function_magnets)`` for interactive completion. """ def __init__(self, peer: "ElementHolder"): @@ -124,6 +161,13 @@ class SerializedMagnetsHolder(GenericArrayHolder[SerializedMagnets, SerializedMa ---------- peer : 'ElementHolder' Parent element holder that owns this specialized holder. + + Notes + ----- + A configured array is also reachable as an attribute when its name is a + valid Python identifier, e.g. ``serialized_magnets.QForTune`` is + equivalent to ``serialized_magnets.get("QForTune")``. Array names appear + in ``dir(serialized_magnets)`` for interactive completion. """ def __init__(self, peer: "ElementHolder"): @@ -165,17 +209,25 @@ class BPMsHolder(GenericArrayHolder[BPM, BPMArray]): ---------- peer : 'ElementHolder' Parent element holder that owns this specialized holder. + + Notes + ----- + A configured array is also reachable as an attribute when its name is a + valid Python identifier, e.g. ``bpms.BPMS`` is equivalent to + ``bpms.get("BPMS")``. Array names appear in ``dir(bpms)`` for interactive + completion. """ def __init__(self, peer: "ElementHolder"): """ Initialize the BPMsHolder. """ + bpm_holder = BPMHolder(peer) super().__init__( peer, peer._BPM_ARRAYS, - peer.bpm.all, - peer.bpm.get, + bpm_holder.all, + bpm_holder.get, BPMArray, "BPM array", ) diff --git a/pyaml/common/holders/tool_holder.py b/pyaml/common/holders/tool_holder.py new file mode 100644 index 000000000..9f8619593 --- /dev/null +++ b/pyaml/common/holders/tool_holder.py @@ -0,0 +1,185 @@ +"""Holder interface for tuning and measurement tools.""" + +from typing import TYPE_CHECKING + +from ...arrays.element_array import ElementArray +from ..element import Element, __pyaml_repr__ +from ..exception import PyAMLException +from ..name_matching import is_wildcard, resolve_names + +if TYPE_CHECKING: + from ...tuning_tools.chromaticity import Chromaticity + from ...tuning_tools.chromaticity_response_matrix import ChromaticityResponseMatrix + from ...tuning_tools.dispersion import Dispersion + from ...tuning_tools.orbit import Orbit + from ...tuning_tools.orbit_response_matrix import OrbitResponseMatrix + from ...tuning_tools.tune import Tune + from ...tuning_tools.tune_response_matrix import TuneResponseMatrix + from .element_holder import ElementHolder + + +class ToolHolder: + """ + Provide access to tuning and measurement tools. + + Parameters + ---------- + peer : 'ElementHolder' + Parent holder containing the tool store. + + Attributes + ---------- + tune, chromaticity, orbit, dispersion + Default tuning tool for each kind, resolved from its ``DEFAULT_...`` name and + validated against the expected class. + trm, crm, orm + Default response-matrix measurement tool for each kind, resolved the same way. + + Methods + ------- + get(name=None) + Return a named tool, or all configured tools when no name is given. + + Examples + -------- + >>> tune_correction = sr.live.tool.tune + >>> tune_correction.set([0.31, 0.22]) + >>> tune_response = sr.live.tool.trm + >>> tune_response.measure() + >>> other_tool = sr.live.tool.get("OTHER_TUNE_CORRECTION") + >>> all_tools = sr.live.tool.get() + """ + + def __init__(self, peer: "ElementHolder"): + """ + Initialize a tool holder for an element holder. + """ + self._peer = peer + + def get(self, name: str = None) -> "Element | ElementArray": + """ + Return a named tool, or all configured tools when no name is given. + + Parameters + ---------- + name : str, optional + Name of the tuning or measurement tool to look up, as declared in the + configuration. When omitted, every configured tool is returned instead. + + Returns + ------- + Element or ElementArray + The tool registered under ``name``, or an :class:`~pyaml.arrays.element_array.ElementArray` + holding every configured tool, in insertion order, when ``name`` is omitted. + + Raises + ------ + PyAMLException + If ``name`` is given and no tool is registered under it. + """ + if name is None: + return ElementArray("", list(self._peer._TOOLS.values())) + return self._peer._get_tool(name) + + def __getitem__(self, key: str | list[str] | tuple[str, ...]) -> "Element | ElementArray": + """ + Return a tool, or a selection typed as a generic ElementArray. + + Parameters + ---------- + key : str, list[str] or tuple[str, ...] + An exact literal name returns the stored tool. An fnmatch + wildcard, a ``re:``-prefixed regular expression, or a list/tuple + of such patterns returns an ElementArray of matches (possibly + empty). + + Returns + ------- + Element or ElementArray + The stored tool for an exact literal name, otherwise an + ElementArray of matches. + + Raises + ------ + PyAMLException + If an exact literal name, or a literal entry within a list or + tuple, does not match any tool, or a ``re:`` pattern is not a + valid regular expression. + """ + store = self._peer._TOOLS + if isinstance(key, str) and not key.startswith(("re:", "~")) and not is_wildcard(key): + return self._peer._get_tool(key) + matched = set(resolve_names(store.keys(), key, what="Tool")) + return ElementArray("", [v for n, v in store.items() if n in matched]) + + def _validate_type(self, name: str, obj: Element, expected_type: type) -> Element: + """ + Ensure a resolved default tool matches the type its accessor expects. + + Raises + ------ + PyAMLException + If ``obj`` is not an instance of ``expected_type``. + """ + if not isinstance(obj, expected_type): + raise PyAMLException(f"{name}: {expected_type.__name__} expected but got {type(obj).__name__}") + return obj + + @property + def chromaticity(self) -> "Chromaticity": + """Return the chromaticity tuning tool configured as ``DEFAULT_CHROMATICITY_CORRECTION``.""" + from ...tuning_tools.chromaticity import Chromaticity + + name = "DEFAULT_CHROMATICITY_CORRECTION" + return self._validate_type(name, self.get(name), Chromaticity) + + @property + def crm(self) -> "ChromaticityResponseMatrix": + """Return the chromaticity response-matrix tool configured as ``DEFAULT_CHROMATICITY_RESPONSE_MATRIX``.""" + from ...tuning_tools.chromaticity_response_matrix import ChromaticityResponseMatrix + + name = "DEFAULT_CHROMATICITY_RESPONSE_MATRIX" + return self._validate_type(name, self.get(name), ChromaticityResponseMatrix) + + @property + def tune(self) -> "Tune": + """Return the tune correction tool configured as ``DEFAULT_TUNE_CORRECTION``.""" + from ...tuning_tools.tune import Tune + + name = "DEFAULT_TUNE_CORRECTION" + return self._validate_type(name, self.get(name), Tune) + + @property + def trm(self) -> "TuneResponseMatrix": + """Return the tune response-matrix tool configured as ``DEFAULT_TUNE_RESPONSE_MATRIX``.""" + from ...tuning_tools.tune_response_matrix import TuneResponseMatrix + + name = "DEFAULT_TUNE_RESPONSE_MATRIX" + return self._validate_type(name, self.get(name), TuneResponseMatrix) + + @property + def orbit(self) -> "Orbit": + """Return the orbit correction tool configured as ``DEFAULT_ORBIT_CORRECTION``.""" + from ...tuning_tools.orbit import Orbit + + name = "DEFAULT_ORBIT_CORRECTION" + return self._validate_type(name, self.get(name), Orbit) + + @property + def orm(self) -> "OrbitResponseMatrix": + """Return the orbit response-matrix tool configured as ``DEFAULT_ORBIT_RESPONSE_MATRIX``.""" + from ...tuning_tools.orbit_response_matrix import OrbitResponseMatrix + + name = "DEFAULT_ORBIT_RESPONSE_MATRIX" + return self._validate_type(name, self.get(name), OrbitResponseMatrix) + + @property + def dispersion(self) -> "Dispersion": + """Return the dispersion tool configured as ``DEFAULT_DISPERSION``.""" + from ...tuning_tools.dispersion import Dispersion + + name = "DEFAULT_DISPERSION" + return self._validate_type(name, self.get(name), Dispersion) + + def __repr__(self): + return __pyaml_repr__(self) diff --git a/pyaml/common/name_matching.py b/pyaml/common/name_matching.py new file mode 100644 index 000000000..9125cd3af --- /dev/null +++ b/pyaml/common/name_matching.py @@ -0,0 +1,84 @@ +"""Shared name and wildcard resolution convention used by every holder and array.""" + +import fnmatch +import re +from typing import Iterable + +from .exception import PyAMLException + +WILDCARD_CHARS = frozenset("*?[") + + +def is_wildcard(pattern: str) -> bool: + """Return True if `pattern` contains an fnmatch wildcard character.""" + return any(c in pattern for c in WILDCARD_CHARS) + + +def resolve_names(pool: Iterable[str], pattern: str | list[str] | tuple[str, ...], what: str = "Element") -> list[str]: + """ + Resolve one pattern, or several, against a pool of names. + + Parameters + ---------- + pool : Iterable[str] + Names to match against. + pattern : str, list[str] or tuple[str, ...] + A literal name, an fnmatch wildcard (triggered by ``*``, ``?`` or + ``[`` anywhere in the string), or a regular expression prefixed with + ``re:``. Prefix any of those with ``~`` to exclude its matches + instead of including them, mirroring the ``elements:`` selector list + convention used in YAML configuration. A sequence of patterns is + resolved entry by entry: non-``~`` entries are unioned, + de-duplicated, in first-encounter order, then anything matched by a + ``~`` entry is removed from that union. If every entry is + ``~``-prefixed (including a single lone ``~pattern``, treated as a + one-entry sequence), there is no explicit inclusion, so the base set + defaults to the full pool: ``~pattern`` alone means "everything + except pattern". + + Returns + ------- + list[str] + Matching names. + + Raises + ------ + PyAMLException + If a literal pattern (or the remainder of a ``~``-prefixed one) does + not match any name in `pool`, or if a `re:`-prefixed pattern is not + a valid regular expression. + """ + names = list(pool) + patterns = pattern if isinstance(pattern, (list, tuple)) else [pattern] + + included: list[str] = [] + seen: set[str] = set() + excluded: set[str] = set() + has_inclusion = False + for p in patterns: + if p.startswith("~"): + excluded.update(_resolve_one(names, p[1:], what)) + continue + has_inclusion = True + for name in _resolve_one(names, p, what): + if name not in seen: + seen.add(name) + included.append(name) + + base = included if has_inclusion else names + return [n for n in base if n not in excluded] + + +def _resolve_one(names: list[str], pattern: str, what: str) -> list[str]: + if pattern.startswith("re:"): + source = pattern[3:] + try: + compiled = re.compile(source) + except re.error as exc: + raise PyAMLException(f"Invalid regex '{source}': {exc}") from exc + return [n for n in names if compiled.fullmatch(n)] + if is_wildcard(pattern): + return [n for n in names if fnmatch.fnmatchcase(n, pattern)] + if pattern not in names: + raise PyAMLException(f"{what} {pattern} not defined") + return [pattern] diff --git a/pyaml/configuration/fileloader.py b/pyaml/configuration/fileloader.py index ef5f9f0eb..c8b09aa96 100644 --- a/pyaml/configuration/fileloader.py +++ b/pyaml/configuration/fileloader.py @@ -29,7 +29,6 @@ LOCATION_KEY = "__location__" FIELD_LOCATIONS_KEY = "__fieldlocations__" -ACCEPTED_SUFFIXES = (".yaml", ".yml", ".json") RESOLVER_PATTERN = re.compile(r"\$\{([^{}]+)\}") @@ -189,7 +188,7 @@ def resolver(name: str): Args: name: Prefix used to invoke the resolver (for example ``"env"`` - or ``"file"``). + or ``"include"``). Returns: A decorator that registers the decorated function in the global @@ -266,10 +265,10 @@ def resolve_path(value: str, _context: LoadContext | None = None) -> str: return str(ROOT.expand_path(value)) -@resolver("file") -def resolve_file(value: str, context: LoadContext | None = None) -> Any: +@resolver("include") +def resolve_include(value: str, context: LoadContext | None = None) -> Any: """ - Load and return the contents of a configuration file. + Load and include the contents of a configuration file. Parameters ---------- @@ -289,7 +288,7 @@ def resolve_file(value: str, context: LoadContext | None = None) -> Any: If no loading context is provided. """ if context is None: - raise RuntimeError("File resolver requires LoadContext") + raise RuntimeError("Include resolver requires LoadContext") return _load(value, context) @@ -323,11 +322,6 @@ def _load(filename: str, context: LoadContext) -> Union[dict, list]: return loader.load() -def _is_supported_file(value: Any) -> bool: - """Return True if the value looks like a supported configuration file name.""" - return isinstance(value, str) and value.endswith(ACCEPTED_SUFFIXES) - - class ConfigLoader(ABC): """ Base class for parsers that expand nested configuration references. @@ -375,7 +369,7 @@ def _expand_string(self, value: str) -> Any: Expand resolver expressions and file references in a string. If the entire string is a resolver expression (for example - ``"${env:HOME}"`` or ``"${file:config.yaml}"``), the resolved value is + ``"${env:HOME}"`` or ``"${include:config.yaml}"``), the resolved value is returned directly and may be of any type. Resolver expressions embedded inside a larger string are interpolated @@ -424,9 +418,6 @@ def replace(match: re.Match[str]) -> str: value = RESOLVER_PATTERN.sub(replace, value) - if _is_supported_file(value): - return RESOLVERS["file"](value, self.context) - return value def _resolve_resolver_expression(self, expr: str) -> Any: @@ -434,7 +425,7 @@ def _resolve_resolver_expression(self, expr: str) -> Any: Resolve a single resolver expression. The expression must have the form ``":"``, for - example ``"env:HOME"`` or ``"file:config.yaml"``. The resolver is + example ``"env:HOME"`` or ``"include:config.yaml"``. The resolver is looked up in the global resolver registry and invoked with the supplied payload. @@ -487,31 +478,24 @@ def _expand_list(self, items: list) -> list: """ Recursively expand the elements of a list. - Plain string values that refer to supported configuration files are - treated as list includes. If the referenced file loads to a list, its - elements are spliced into the current list. Otherwise, the loaded - object is appended as a single element. - - All other items are expanded recursively using :meth:`expand`. - - Args: - items: The list to expand. - - Returns: - The expanded list. + Lists returned by an explicit include resolver are spliced into the + current list. Other nested lists are preserved. """ expanded: list[Any] = [] for item in items: - if isinstance(item, str) and _is_supported_file(item): - loaded = RESOLVERS["file"](item, self.context) - if isinstance(loaded, list): - expanded.extend(loaded) - else: - expanded.append(loaded) - continue - - expanded.append(self.expand(item)) + is_include = ( + isinstance(item, str) + and (match := RESOLVER_PATTERN.fullmatch(item)) is not None + and match.group(1).strip().startswith("include:") + ) + + value = self.expand(item) + + if is_include and isinstance(value, list): + expanded.extend(value) + else: + expanded.append(value) return expanded diff --git a/pyaml/configuration/restfetcher.py b/pyaml/configuration/restfetcher.py index 96a754502..0ae0612f6 100644 --- a/pyaml/configuration/restfetcher.py +++ b/pyaml/configuration/restfetcher.py @@ -18,12 +18,12 @@ from yaml import CLoader from ..common.exception import PyAMLConfigException -from .fileloader import ACCEPTED_SUFFIXES, SafeLineLoader +from .fileloader import SafeLineLoader REMOTE_BASE_URL_KEY = "__baseurl__" SourceRoot = Path | str | None _REMOTE_SCHEMES = {"http", "https"} - +INCLUDE_PREFIX = "${include:" FILE_PREFIX = "${path:" @@ -285,9 +285,10 @@ def _expand_remote_dict( """ values.setdefault(REMOTE_BASE_URL_KEY, base_url) for key, value in list(values.items()): - if _is_config_reference(value): + if _is_include(value): + reference = _include_reference(value) values[key] = _load_remote_document( - _resolve_remote_config_reference(value, base_url), + _resolve_remote_config_reference(reference, base_url), include_locations=include_locations, stack=stack, ) @@ -324,9 +325,10 @@ def _expand_remote_list(values: list[Any], base_url: str, stack: list[str], *, i index = 0 while index < len(values): value = values[index] - if _is_config_reference(value): + if _is_include(value): + reference = _include_reference(value) expanded = _load_remote_document( - _resolve_remote_config_reference(value, base_url), + _resolve_remote_config_reference(reference, base_url), include_locations=include_locations, stack=stack, ) @@ -348,29 +350,14 @@ def _expand_remote_list(values: list[Any], base_url: str, stack: list[str], *, i return values -def _is_config_reference(value: Any) -> bool: - """ - Return whether a value names a supported configuration document. - - Parameters - ---------- - value : Any - Value to inspect. - - Returns - ------- - bool - ``True`` for a YAML, JSON, or supported remote document reference. - """ - if not isinstance(value, str): - return False +def _is_include(value: Any) -> bool: + """Return whether a value is an explicit include expression.""" + return isinstance(value, str) and value.startswith(INCLUDE_PREFIX) and value.endswith("}") - if value.startswith(FILE_PREFIX): - return False - parsed = urlparse(value) - path = parsed.path if parsed.scheme in _REMOTE_SCHEMES else value - return any(path.endswith(suffix) for suffix in ACCEPTED_SUFFIXES) +def _include_reference(value: str) -> str: + """Return the reference contained in an include expression.""" + return value[len(INCLUDE_PREFIX) : -1].strip() def _resolve_remote_config_reference(reference: str, base_url: str) -> str: diff --git a/pyaml/control/abstract_impl.py b/pyaml/control/abstract_impl.py index 077a819dd..5b1105628 100644 --- a/pyaml/control/abstract_impl.py +++ b/pyaml/control/abstract_impl.py @@ -294,6 +294,89 @@ def nb_device(self) -> int: # ------------------------------------------------------------------------------ +class CSSparseScalarAggregator(CSScalarAggregator): + """ + Scalar aggregator whose slots may have no device. + + Only existing devices are added to the backend aggregator, so they are + still read in one grouped call. Values are scattered back to their slots + and missing slots read NaN. + + Parameters + ---------- + devs : DeviceAccessList + Backend aggregator holding the existing devices. + + Methods + ------- + add_devices(devices) + Add one or more slots, ``None`` for a slot without device. + set(value) + Write the values of the slots that have a device. + set_and_wait(value) + Write the values of the slots that have a device and wait. + get() + Read all slots, NaN for slots without device. + readback() + Read all slot readbacks, NaN for slots without device. + nb_device() + Return the number of slots. + """ + + def __init__(self, devs: DeviceAccessList): + """ + Initialize the CSSparseScalarAggregator. + """ + super().__init__(devs) + self._nb_slots = 0 + self._slots: list[int] = [] + + def add_devices(self, devices: DeviceAccess | None | list[DeviceAccess | None]): + """ + Add one or more slots, ``None`` for a slot without device. + + Parameters + ---------- + devices : DeviceAccess | None | list[DeviceAccess | None] + Control-system device or devices to manage. + """ + for d in devices if isinstance(devices, list) else [devices]: + if d is not None: + self._devs.add_devices(d) + self._slots.append(self._nb_slots) + self._nb_slots += 1 + + def _scatter(self, values: NDArray[np.float64]) -> NDArray[np.float64]: + out = np.full(self._nb_slots, np.nan) + out[self._slots] = values + return out + + def set(self, value: NDArray[np.float64]): + """Write the values of the slots that have a device.""" + if self._slots: + self._devs.set(np.asarray(value)[self._slots]) + + def set_and_wait(self, value: NDArray[np.float64]): + """Write the values of the slots that have a device and wait.""" + if self._slots: + self._devs.set_and_wait(np.asarray(value)[self._slots]) + + def get(self) -> NDArray[np.float64]: + """Read all slots, NaN for slots without device.""" + return self._scatter(self._devs.get() if self._slots else []) + + def readback(self) -> np.array: + """Read all slot readbacks, NaN for slots without device.""" + return self._scatter(self._devs.readback() if self._slots else []) + + def nb_device(self) -> int: + """Return the number of slots.""" + return self._nb_slots + + +# ------------------------------------------------------------------------------ + + class CSStrengthScalarAggregator(CSScalarAggregator): """ Aggregate magnet strengths while avoiding duplicate hardware writes. @@ -347,7 +430,10 @@ def add_magnet(self, magnet: Magnet, devs: list[DeviceAccess]): devs : list[DeviceAccess] Hardware devices associated with the magnet model. """ - strengthIndex = magnet.strength.index() if isinstance(magnet.strength, abstract.RWMapper) else 0 + # Magnets of a serialized group share the serialized model (one power supply for N strengths): + # the power-supply current is computed by the model from the N strengths (mean of the implied currents). + is_indexed = isinstance(magnet.strength, (abstract.RWMapper, RWSerializedStrengthScalar)) + strengthIndex = magnet.strength.index() if is_indexed else 0 if magnet.model not in self.__models: index = len(self.__models) self.__models.append(magnet.model) @@ -628,6 +714,42 @@ def set_magnet_rigidity(self, brho: np.double): self.__model.set_magnet_rigidity(brho) +class RWSerializedStrengthScalar(RWStrengthScalar): + """ + Expose the strength of one magnet of a serialized group. + + All magnets of a serialized group share one power supply. This accessor + converts with the magnet's own sub-model and remembers the magnet position + in the group so that aggregators can map it to the right strength of the + serialized model. + + Parameters + ---------- + model : MagnetModel + Sub-model of the magnet, used for strength conversion and units. + dev : DeviceAccess + Power-supply device shared by the serialized group. + idx : int + Zero-based position of the magnet in the serialized group. + + Methods + ------- + index() + Return the position of the magnet in the serialized group. + """ + + def __init__(self, model: MagnetModel, dev: DeviceAccess, idx: int): + """ + Initialize the RWSerializedStrengthScalar. + """ + super().__init__(model, dev) + self.__idx = idx + + def index(self) -> int: + """Return the position of the magnet in the serialized group.""" + return self.__idx + + # ------------------------------------------------------------------------------ @@ -801,20 +923,22 @@ class RBpmArray(abstract.ReadFloatArray): Parameters ---------- - hDev : DeviceAccess - Device providing the horizontal BPM position. - vDev : DeviceAccess - Device providing the vertical BPM position. + hDev : DeviceAccess | None + Device providing the horizontal BPM position, ``None`` for a BPM + without horizontal plane. + vDev : DeviceAccess | None + Device providing the vertical BPM position, ``None`` for a BPM + without vertical plane. Methods ------- get() - Return horizontal and vertical BPM positions. + Return horizontal and vertical BPM positions (NaN for a missing plane). unit() Return the unit reported by the BPM device. """ - def __init__(self, hDev: DeviceAccess, vDev: DeviceAccess): + def __init__(self, hDev: DeviceAccess | None, vDev: DeviceAccess | None): """ Initialize the RBpmArray. """ @@ -822,14 +946,14 @@ def __init__(self, hDev: DeviceAccess, vDev: DeviceAccess): self._vDev = vDev def get(self) -> np.array: - """Return horizontal and vertical BPM positions.""" - return np.array([self._hDev.get(), self._vDev.get()]) + """Return horizontal and vertical BPM positions (NaN for a missing plane).""" + return np.array([d.get() if d is not None else np.nan for d in (self._hDev, self._vDev)], dtype=float) # Gets the unit of the value Assume that x and y, offsets and positions # have the same unit def unit(self) -> str: """Return the unit reported by the BPM device.""" - return self._hDev.unit() + return (self._hDev if self._hDev is not None else self._vDev).unit() # ------------------------------------------------------------------------------ diff --git a/pyaml/control/controlsystem.py b/pyaml/control/controlsystem.py index 9199f98de..4800f7967 100644 --- a/pyaml/control/controlsystem.py +++ b/pyaml/control/controlsystem.py @@ -10,7 +10,8 @@ from pydantic import BaseModel -from ..bpm.bpm import BPM +from pyaml.diagnostics.bpm import BPM + from ..common.abstract import RWMapper from ..common.abstract_aggregator import ScalarAggregator from ..common.exception import PyAMLException @@ -18,6 +19,7 @@ from ..configuration.unbound_element import UnboundElement from ..control.abstract_impl import ( CSScalarAggregator, + CSSparseScalarAggregator, CSStrengthScalarAggregator, RBetatronTuneArray, RBpmArray, @@ -28,6 +30,7 @@ RWRFFrequencyScalar, RWRFPhaseScalar, RWRFVoltageScalar, + RWSerializedStrengthScalar, RWStrengthArray, RWStrengthScalar, ) @@ -197,12 +200,14 @@ def create_bpm_aggregators(self, bpms: list[BPM]) -> list[ScalarAggregator | Non ------- list[ScalarAggregator | None] Aggregators for combined, horizontal, and vertical positions. + A plane without device (e.g. the horizontal plane of a + vertical-only XBPM) reads NaN, the other devices are still read + in one grouped call. """ - agg = self._create_scalar_aggregator() - aggh = self._create_scalar_aggregator() - aggv = self._create_scalar_aggregator() - if agg is None or aggh is None or aggv is None: + aggs = [self.get_aggregator() for _ in range(3)] + if any(a is None for a in aggs): return [None, None, None] + agg, aggh, aggv = (CSSparseScalarAggregator(a) for a in aggs) for b in bpms: devs = self.get_devices_access(b.get_pos_devices()) agg.add_devices(devs) @@ -226,16 +231,14 @@ def _fill_combined_function_magnet(self, magnet: CombinedFunctionMagnet) -> None self.magnet.add(virtual_magnet) def _fill_serialized_magnets(self, magnets: SerializedMagnets) -> None: - devices = self.get_devices_access(magnets.model.get_device_names()) + # All magnets of the group share the same power supply + device = self.get_device_access(magnets.model.get_device_names()[0]) currents = [] strengths = [] for index in range(magnets.get_nb_magnets()): - currents.append( - RWHardwareScalar(magnets.model.get_sub_model(index), devices[index]) if magnets.model.has_hardware() else None - ) - strengths.append( - RWStrengthScalar(magnets.model.get_sub_model(index), devices[index]) if magnets.model.has_physics() else None - ) + sub_model = magnets.model.get_sub_model(index) + currents.append(RWHardwareScalar(sub_model, device) if magnets.model.has_hardware() else None) + strengths.append(RWSerializedStrengthScalar(sub_model, device, index) if magnets.model.has_physics() else None) attached_magnets = magnets.attach(self, strengths, currents) self.serialized_magnet.add(attached_magnets[0]) for magnet in attached_magnets[1:]: @@ -248,7 +251,7 @@ def _fill_bpm(self, bpm: BPM) -> None: positions = RBpmArray(position_devices[0], position_devices[1]) tilt = RWBpmTiltScalar(tilt_devices[0]) offsets = RWBpmOffsetArray(offset_devices[0], offset_devices[1]) - self.bpm.add(bpm.attach(self, positions, offsets, tilt)) + self.diagnostic.bpm.add(bpm.attach(self, positions, offsets, tilt)) def _fill_rf_plant(self, rf_plant: RFPlant) -> None: attached_transmitters: list[RFTransmitter] = [] diff --git a/pyaml/diagnostics/bpm/__init__.py b/pyaml/diagnostics/bpm/__init__.py new file mode 100644 index 000000000..84915bda0 --- /dev/null +++ b/pyaml/diagnostics/bpm/__init__.py @@ -0,0 +1,3 @@ +from pyaml.diagnostics.bpm.bpm import BPM + +__all__ = ["BPM"] diff --git a/pyaml/bpm/bpm.py b/pyaml/diagnostics/bpm/bpm.py similarity index 90% rename from pyaml/bpm/bpm.py rename to pyaml/diagnostics/bpm/bpm.py index dd7015c2e..c63f662aa 100644 --- a/pyaml/bpm/bpm.py +++ b/pyaml/diagnostics/bpm/bpm.py @@ -3,13 +3,13 @@ import copy from typing import TYPE_CHECKING, Self -from ..common.abstract import ReadFloatArray, ReadWriteFloatArray, ReadWriteFloatScalar -from ..common.element import Element, __pyaml_repr__ -from ..common.exception import PyAMLException -from ..validation import DynamicValidation, register_schema +from pyaml.common.abstract import ReadFloatArray, ReadWriteFloatArray, ReadWriteFloatScalar +from pyaml.common.element import Element, __pyaml_repr__ +from pyaml.common.exception import PyAMLException +from pyaml.validation import DynamicValidation, register_schema if TYPE_CHECKING: - from ..common.holders.element_holder import ElementHolder + from pyaml.common.holders.element_holder import ElementHolder PYAMLCLASS = "BPM" @@ -61,6 +61,19 @@ class BPM(Element, DynamicValidation): Return the configured device key used for tilt access. get_offset_devices() Return configured device keys used for offset control. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.diagnostics.bpm.bpm + name: BPM_NAME + lattice_names: LATTICE_BPM_NAME + x_pos: DEVICE/X_POSITION + y_pos: DEVICE/Y_POSITION + x_offset: DEVICE/X_OFFSET + y_offset: DEVICE/Y_OFFSET + tilt: DEVICE/TILT """ def __init__( diff --git a/pyaml/diagnostics/tune_monitor.py b/pyaml/diagnostics/tune_monitor.py index 3b5206d77..3a771cb6a 100644 --- a/pyaml/diagnostics/tune_monitor.py +++ b/pyaml/diagnostics/tune_monitor.py @@ -61,6 +61,16 @@ class BetatronTuneMonitor(Element, DynamicValidation, ABetatronTuneMonitor): Set the harmonic number used for tune-frequency conversion. attach(peer, betatron_tune) Attach the tune monitor to a peer with betatron tune data. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.diagnostics.tune_monitor + name: BETATRON_TUNE + tune_h: DEVICE/HORIZONTAL_TUNE + tune_v: DEVICE/VERTICAL_TUNE + rf_plant_name: RF """ def __init__( diff --git a/pyaml/external/pySC_interface.py b/pyaml/external/pySC_interface.py index 3be5196ea..b9e604932 100644 --- a/pyaml/external/pySC_interface.py +++ b/pyaml/external/pySC_interface.py @@ -56,7 +56,7 @@ def __init__( """ self.element_holder = element_holder - self.bpm_array = element_holder.bpms.get(bpm_array_name) + self.bpm_array = element_holder.diagnostic.bpms.get(bpm_array_name) self.rf_plant_name = rf_plant_name if rf_plant_name is not None: diff --git a/pyaml/lattice/abstract_impl.py b/pyaml/lattice/abstract_impl.py index 91c07975e..a734a5871 100644 --- a/pyaml/lattice/abstract_impl.py +++ b/pyaml/lattice/abstract_impl.py @@ -12,6 +12,7 @@ from ..common import abstract from ..common.abstract_aggregator import ScalarAggregator +from ..common.exception import PyAMLException from ..magnet.model import MagnetModel from .polynom_info import PolynomInfo @@ -20,6 +21,21 @@ # ------------------------------------------------------------------------------ +def _effective_lengths(elements: list[at.Element]) -> list[float]: + """ + Return the lengths used to convert between integrated strengths and polynom coefficients. + + AT convention is followed: a zero-length (thin) element stores the *integrated* strength in + ``PolynomA``/``PolynomB``, so it behaves as a unit-length element for the conversion. When every element of the + group is thin, each one is given a unit length, so that the integrated strength is shared equally between the + slices. Otherwise the real lengths are used and any thin slice of the group is left untouched. + """ + lengths = [float(e.Length) for e in elements] + if all(L == 0.0 for L in lengths): + return [1.0] * len(lengths) + return lengths + + class RWHardwareScalar(abstract.ReadWriteFloatScalar): """ Provide read/write access to a simulated magnet in hardware units. @@ -62,19 +78,23 @@ def __init__(self, elements: list[at.Element], poly: PolynomInfo, model: MagnetM self._poly = [e.__getattribute__(poly.attName) for e in elements] self._sign = poly.sign self._polyIdx = poly.index - self._length: float = 0.0 - for e in elements: - self._length += e.Length + self._is_thin = all(e.Length == 0 for e in elements) + self._lengths = _effective_lengths(elements) + self._length: float = sum(self._lengths) def get_length(self) -> float: - """Return the total length of the lattice elements.""" + """Return the total effective length of the lattice elements (1.0 per element when they are all thin).""" return self._length + def is_thin(self) -> bool: + """Return True when every lattice element of this magnet has zero length.""" + return self._is_thin + def get(self) -> float: """Return the current value.""" s = 0 - for idx, e in enumerate(self._elements): - s += self._poly[idx][self._polyIdx] * self._sign * e.Length + for idx, _ in enumerate(self._elements): + s += self._poly[idx][self._polyIdx] * self._sign * self._lengths[idx] return self._model.compute_hardware_values([s])[0] def set(self, value: float): @@ -160,9 +180,8 @@ def __init__(self, elements: list[at.Element], poly: PolynomInfo, model: MagnetM self._poly = [e.__getattribute__(poly.attName) for e in elements] self._sign = poly.sign self._polyIdx = poly.index - self._length = 0 - for e in elements: - self._length += e.Length + self._lengths = _effective_lengths(elements) + self._length: float = sum(self._lengths) def get_element_length(self) -> float: """Return the total length of the represented element.""" @@ -195,8 +214,8 @@ def get(self, polynom: str = None, polyidx: int = None) -> float: poly = [e.__getattribute__(polynom) for e in self._elements] s = 0 - for idx, e in enumerate(self._elements): - s += poly[idx][pIdx] * self._sign * e.Length + for idx, _ in enumerate(self._elements): + s += poly[idx][pIdx] * self._sign * self._lengths[idx] return s # Sets the value @@ -398,6 +417,14 @@ def __init__( self.__elements_strength = elements_strength self.__elements_hardware = elements_hardware self.__element_index = element_index + # The strength is shared between the serialized magnets in proportion to their (effective) length: thick + # magnets share by length, thin magnets share equally. Mixing both has no meaningful share rule. + thin_flags = [e.is_thin() for e in elements_hardware] + if any(thin_flags) and not all(thin_flags): + raise PyAMLException( + "Serialized magnets must be either all thin (zero length) or all thick; " + f"got {sum(thin_flags)} thin out of {len(thin_flags)} magnets" + ) self.__total_length = 0 for e in self.__elements_hardware: self.__total_length += e.get_length() @@ -509,6 +536,7 @@ def __init__(self, elements: list[at.Element], poly: list[PolynomInfo], model: M self.__polyIdx = [] self.__sign = [] self.__model = model + self.__length = _effective_lengths(elements[:1])[0] for p in poly: self.__poly.append(elements[0].__getattribute__(p.attName)) self.__polyIdx.append(p.index) @@ -520,7 +548,7 @@ def get(self) -> np.array: nbStrength = len(self.__poly) s = np.zeros(nbStrength) for i in range(nbStrength): - s[i] = self.__poly[i][self.__polyIdx[i]] * self.__sign[i] * self.__elements[0].Length + s[i] = self.__poly[i][self.__polyIdx[i]] * self.__sign[i] * self.__length return self.__model.compute_hardware_values(s) # Sets the value @@ -536,7 +564,7 @@ def set(self, value: np.array): nbStrength = len(self.__poly) s = self.__model.compute_strengths(value) for i in range(nbStrength): - self.__poly[i][self.__polyIdx[i]] = s[i] / (self.__elements[0].Length * self.__sign[i]) + self.__poly[i][self.__polyIdx[i]] = s[i] / (self.__length * self.__sign[i]) # Sets the value and wait that the read value reach the setpoint def set_and_wait(self, value: np.array): @@ -599,6 +627,7 @@ def __init__(self, elements: list[at.Element], poly: list[PolynomInfo], model: M self.__polyIdx = [] self.__sign = [] self.__model = model + self.__length = _effective_lengths(elements[:1])[0] for p in poly: self.__poly.append(elements[0].__getattribute__(p.attName)) self.__polyIdx.append(p.index) @@ -610,7 +639,7 @@ def get(self) -> np.array: nbStrength = len(self.__poly) s = np.zeros(nbStrength) for i in range(nbStrength): - s[i] = self.__poly[i][self.__polyIdx[i]] * self.__sign[i] * self.__elements[0].Length + s[i] = self.__poly[i][self.__polyIdx[i]] * self.__sign[i] * self.__length return s # Sets the value @@ -626,7 +655,7 @@ def set(self, value: np.array): nbStrength = len(self.__poly) s = np.zeros(nbStrength) for i in range(nbStrength): - self.__poly[i][self.__polyIdx[i]] = value[i] / (self.__elements[0].Length * self.__sign[i]) + self.__poly[i][self.__polyIdx[i]] = value[i] / (self.__length * self.__sign[i]) # Sets the value and wait that the read value reach the setpoint def set_and_wait(self, value: np.array): @@ -679,13 +708,14 @@ class BPMScalarAggregator(ScalarAggregator): Return the value unit. """ - def __init__(self, ring: at.Lattice): + def __init__(self, ring: at.Lattice, twiss_in: dict): """ Initialize the BPMScalarAggregator. """ self._lattice = ring self._refpts = [] self._matrices = [] + self._twiss_in = twiss_in def add_elem(self, elem: at.Element): """ @@ -735,9 +765,15 @@ def unit(self) -> str: def _transform(self) -> np.array: """Transform the configured value for the lattice interface.""" - _, orbit = at.find_orbit(self._lattice, refpts=self._refpts) + if self._twiss_in is None: + _, orbit = at.find_orbit(self._lattice, refpts=self._refpts) + pts = orbit[:, [0, 2]] # Extract x,y + else: + _, _, elemdata = at.get_optics(self._lattice, refpts=self._refpts, twiss_in=self._twiss_in) + pts = [e.closed_orbit[[0, 2]] for e in elemdata] + ones = np.ones(len(self._refpts)) - pts = orbit[:, [0, 2]] # Extract x,y + # Transfom BPM coordinates (offset and tilt) # Batch matrices multiplication (homogeneous coordinates) return np.matmul(self._matrices, np.column_stack([pts, ones])[:, :, None]).squeeze(-1) @@ -827,19 +863,25 @@ class RBpmArray(abstract.ReadFloatArray): Return the value unit. """ - def __init__(self, element: at.Element, lattice: at.Lattice): + def __init__(self, element: at.Element, lattice: at.Lattice, twiss_in: dict): """ Initialize the RBpmArray. """ self._element = element self._lattice = lattice + self._twiss_in = twiss_in # Gets the value def get(self) -> np.array: """Return the current value.""" index = self._lattice.index(self._element) - _, orbit = at.find_orbit(self._lattice, refpts=index) - pts = orbit[0, [0, 2]] + if self._twiss_in is None: + _, orbit = at.find_orbit(self._lattice, refpts=index) + pts = orbit[0, [0, 2]] + else: + _, _, elemdata = at.get_optics(self._lattice, refpts=index, twiss_in=self._twiss_in) + pts = elemdata[0].closed_orbit[[0, 2]] + # Transfom BPM coordinates (offset and tilt) return np.dot(self._element._transform, np.hstack([pts, 1])) # Use homogeneous coordinates # Gets the unit of the value diff --git a/pyaml/lattice/attribute_linker.py b/pyaml/lattice/attribute_linker.py index affa5bcf3..053ef10ee 100644 --- a/pyaml/lattice/attribute_linker.py +++ b/pyaml/lattice/attribute_linker.py @@ -109,7 +109,23 @@ def get_element_identifier(self, element: Element) -> LinkerIdentifier: LinkerIdentifier The identifier for linking the element """ - return PyAtAttributeIdentifier(self.linker_config_model.attribute_name, element.get_name()) + return self.get_identifier_for_name(element.get_name()) + + def get_identifier_for_name(self, name: str) -> LinkerIdentifier: + """ + Get the identifier for a name used in an element ``lattice_names`` selector. + + Parameters + ---------- + name : str + Expected value of the configured attribute. + + Returns + ------- + LinkerIdentifier + The identifier matching the lattice elements whose attribute equals ``name`` + """ + return PyAtAttributeIdentifier(self.linker_config_model.attribute_name, name) def _test_at_element(self, identifier: PyAtAttributeIdentifier, element: at.Element) -> bool: """ diff --git a/pyaml/lattice/lattice_elements_linker.py b/pyaml/lattice/lattice_elements_linker.py index ef11e559b..87703667c 100644 --- a/pyaml/lattice/lattice_elements_linker.py +++ b/pyaml/lattice/lattice_elements_linker.py @@ -70,6 +70,8 @@ class LatticeElementsLinker(ABC): Set the lattice for element linking. get_element_identifier(element) Get the identifier for linking an element. + get_identifier_for_name(name) + Get the identifier for a name given in an element ``lattice_names`` selector. get_at_elements(element_id) Return a list of PyAT elements matching the given identifiers. get_at_element(element_id) @@ -130,6 +132,31 @@ def get_element_identifier(self, element: Element) -> LinkerIdentifier: """ pass + def get_identifier_for_name(self, name: str) -> LinkerIdentifier: + """ + Get the identifier for a name used in an element ``lattice_names`` selector. + + Called when a PyAML element selects its lattice elements explicitly + (``lattice_names: list(a,b)``, ``a@0,1`` or ``a#0..2``): each ``name`` of the + selector is resolved through the linker instead of the element name. + + Parameters + ---------- + name : str + Name given in the ``lattice_names`` selector. + + Returns + ------- + LinkerIdentifier + The identifier matching the lattice element(s) designated by ``name``. + + Raises + ------ + NotImplementedError + If the linker does not support ``lattice_names`` selectors. + """ + raise NotImplementedError(f"{self.__class__.__name__} does not support 'lattice_names' selectors") + def _iter_matches(self, identifier: LinkerIdentifier) -> Iterable[at.Element]: """ Yield all lattice elements matching ``identifier``. diff --git a/pyaml/lattice/simulator.py b/pyaml/lattice/simulator.py index 071d66a8e..e0922ae38 100644 --- a/pyaml/lattice/simulator.py +++ b/pyaml/lattice/simulator.py @@ -10,7 +10,8 @@ import at -from ..bpm.bpm import BPM +from pyaml.diagnostics.bpm import BPM + from ..common.abstract_aggregator import ScalarAggregator from ..common.element import Element, __pyaml_repr__ from ..common.exception import PyAMLException @@ -47,6 +48,7 @@ from ..tuning_tools.tuning_tool import TuningTool from ..validation import DynamicValidation, register_schema from .lattice_elements_linker import LatticeElementsLinker +from .twiss_in import TwissIn if TYPE_CHECKING: from ..configuration.unbound_element import UnboundElement @@ -78,6 +80,8 @@ class Simulator(ElementHolder, DynamicValidation): mat_key : str, optional Variable name of the lattice when loading a MATLAB ``.mat`` lattice file. + twiss_in : TwissIn, optional + Describe input beam parameters of a tranfer line, when not specified the lattice is considered as a ring linker : LatticeElementsLinker, optional Custom linker used to associate PyAML elements with PyAT lattice elements. If omitted, elements are matched by name. @@ -122,6 +126,7 @@ def __init__( name: str, lattice: str, mat_key: str | None = None, + twiss_in: TwissIn | None = None, linker: LatticeElementsLinker | None = None, description: str | None = None, ): @@ -134,6 +139,11 @@ def __init__( self._lattice = lattice self._mat_key = mat_key self.description = description + self.twiss_in = twiss_in + if twiss_in is None: + self._at_twiss_in = None + else: + self._at_twiss_in = self.twiss_in._to_at() path: Path = ROOT.get() / self._lattice @@ -225,9 +235,9 @@ def create_bpm_aggregators(self, bpms: list[BPM]) -> list[ScalarAggregator]: list[ScalarAggregator] Aggregators for combined, horizontal, and vertical BPM positions. """ - agg = BPMScalarAggregator(self.get_lattice()) - aggh = BPMHScalarAggregator(self.get_lattice()) - aggv = BPMVScalarAggregator(self.get_lattice()) + agg = BPMScalarAggregator(self.get_lattice(), self._at_twiss_in) + aggh = BPMHScalarAggregator(self.get_lattice(), self._at_twiss_in) + aggv = BPMVScalarAggregator(self.get_lattice(), self._at_twiss_in) for b in bpms: e = self.get_at_elems(b)[0] agg.add_elem(e) @@ -291,7 +301,11 @@ def _fill_bpm(self, bpm: BPM) -> None: if len(bpm_elt.Offset) != 2: raise PyAMLException(f"BPM {bpm.get_name()} offset must be a 2-element array.") update_bpm_transform_matrix(bpm_elt) - self.bpm.add(bpm.attach(self, RBpmArray(bpm_elt, self.ring), RWBpmOffsetArray(bpm_elt), RWBpmTiltScalar(bpm_elt))) + self.diagnostic.bpm.add( + bpm.attach( + self, RBpmArray(bpm_elt, self.ring, self._at_twiss_in), RWBpmOffsetArray(bpm_elt), RWBpmTiltScalar(bpm_elt) + ) + ) def _fill_rf_plant(self, rf_plant: RFPlant) -> None: if rf_plant.transmitters: @@ -387,6 +401,12 @@ def get_at_elems(self, element: Element) -> list[at.Element]: """ Resolve a PyAML element to matching PyAT lattice elements. + The ``lattice_names`` selector of the element is honoured with or without a + linker. With a linker, the names of the selector are resolved through + ``linker.get_identifier_for_name`` (e.g. the configured attribute for + ``pyaml.lattice.attribute_linker``) instead of ``FamName``; without a + selector the linker uses the element name. + Parameters ---------- element : Element @@ -398,11 +418,28 @@ def get_at_elems(self, element: Element) -> list[at.Element]: Matching Accelerator Toolbox lattice elements. """ if self._linker: - identifier = self._linker.get_element_identifier(element) - element_list = self._linker.get_at_elements(identifier) - if not element_list: - raise PyAMLException(f"{identifier} not found in lattice:{self._lattice}") - return element_list + if element.get_lattice_names() is None: + # By name + return self._linker.get_at_elements(self._linker.get_element_identifier(element)) + # By list + nameList = self.get_names(element) + if nameList is not None: + identifiers = [self._linker.get_identifier_for_name(name) for name in nameList] + return self._linker.get_at_elements(identifiers) + # By name or indices + name, indices = self.get_indices(element) + if name is None: + # Direct indexing in the ring + return [self.ring[idx] for idx in indices] + elts = self._linker.get_at_elements(self._linker.get_identifier_for_name(name)) + if indices is None: + return elts + try: + return [elts[idx] for idx in indices] + except IndexError as err: + strErr = f"{element.get_name()}: Invalid lattice_names index " + strErr += f"for {element.get_lattice_names()}, {len(elts)} element(s) found for {name}" + raise PyAMLException(strErr) from err else: # By list nameList = self.get_names(element) diff --git a/pyaml/lattice/twiss_in.py b/pyaml/lattice/twiss_in.py new file mode 100644 index 000000000..c42ee6c7e --- /dev/null +++ b/pyaml/lattice/twiss_in.py @@ -0,0 +1,52 @@ +""" +Initial input beam parameters for a transfer line +""" + +import numpy + +from ..validation import DynamicValidation, register_schema + +# Define the main class name for this module +PYAMLCLASS = "TwissIn" + + +@register_schema +class TwissIn(DynamicValidation): + """ + Class that describes input beam parameters of a transfer line + + Attributes + ---------- + alpha : list[float] + Initial alpha parameters (x,y) + beta : list[float] | None + Initial beta parameters (x,y), default [0,0] + position : list[float] | None + Initial position (6D), default [0,0,0,0,0,0] + dispersion : list[float] | None + Initial dispersion (4D), default [0,0,0,0] + """ + + def __init__( + self, + alpha: list[float], + beta: list[float] | None = None, + position: list[float] | None = None, + dispersion: list[float] | None = None, + ): + """ + Create TwissIn object + """ + super().__init__() + self.alpha = alpha + self.beta = beta if beta is not None else [0.0, 0.0] + self.position = position if position is not None else [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + self.dispersion = dispersion if dispersion is not None else [0.0, 0.0, 0.0, 0.0] + + def _to_at(self) -> dict: + return { + "beta": numpy.array(self.alpha, dtype=float), + "alpha": numpy.array(self.beta, dtype=float), + "closed_orbit": numpy.array(self.position, dtype=float), + "dispersion": numpy.array(self.dispersion, dtype=float), + } diff --git a/pyaml/magnet/cfm_magnet.py b/pyaml/magnet/cfm_magnet.py index eb7db64e8..83c5578fd 100644 --- a/pyaml/magnet/cfm_magnet.py +++ b/pyaml/magnet/cfm_magnet.py @@ -93,6 +93,21 @@ class CombinedFunctionMagnet(Element, DynamicValidation): PyAMLException If the mapping is invalid, if an unsupported multipole is requested, or if the model does not provide the required multipole information. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.cfm_magnet + name: COMBINED_FUNCTION_MAGNET_NAME + mapping: + - [B2, SEXTUPOLE_NAME] + - [B0, HORIZONTAL_CORRECTOR_NAME] + - [A0, VERTICAL_CORRECTOR_NAME] + model: path/to/combined_function_magnet_model.yaml """ def __init__( diff --git a/pyaml/magnet/hcorrector.py b/pyaml/magnet/hcorrector.py index 84bfbfb2e..968c4c330 100644 --- a/pyaml/magnet/hcorrector.py +++ b/pyaml/magnet/hcorrector.py @@ -44,6 +44,18 @@ class HCorrector(Magnet, DynamicValidation): ------- attach(peer, strength, hardware) Return an attached copy with a bound horizontal-angle handle. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.hcorrector + name: HORIZONTAL_CORRECTOR_NAME + lattice_names: LATTICE_CORRECTOR_NAME + model: path/to/magnet_model.yaml """ polynom = PolynomInfo("PolynomB", 0, HORIZONTAL_KICK_SIGN) diff --git a/pyaml/magnet/identity_cfm_model.py b/pyaml/magnet/identity_cfm_model.py index 0f578f2cc..497afb6eb 100644 --- a/pyaml/magnet/identity_cfm_model.py +++ b/pyaml/magnet/identity_cfm_model.py @@ -71,6 +71,18 @@ class IdentityCFMagnetModel(MagnetModel, DynamicValidation): Return whether the model provides physics strengths. has_hardware() Return whether the model provides hardware values. + + Configuration + ------------- + .. code-block:: yaml + + type: pyaml.magnet.identity_cfm_model + multipoles: [B2, B0, A0] + units: [1/m**2, rad, rad] + physics: + - DEVICE/SEXTUPOLE_STRENGTH + - DEVICE/HORIZONTAL_KICK + - DEVICE/VERTICAL_KICK """ def __init__( diff --git a/pyaml/magnet/identity_model.py b/pyaml/magnet/identity_model.py index 9d5f94f6a..744321d3d 100644 --- a/pyaml/magnet/identity_model.py +++ b/pyaml/magnet/identity_model.py @@ -64,6 +64,14 @@ class IdentityMagnetModel(MagnetModel, DynamicValidation): ----- The model does not perform any numerical conversion: strengths are returned as hardware values and hardware values are returned as strengths. + + Configuration + ------------- + .. code-block:: yaml + + type: pyaml.magnet.identity_model + unit: 1/m + physics: DEVICE/MAGNET_STRENGTH """ def __init__( diff --git a/pyaml/magnet/linear_cfm_model.py b/pyaml/magnet/linear_cfm_model.py index 75489526b..2288df68d 100644 --- a/pyaml/magnet/linear_cfm_model.py +++ b/pyaml/magnet/linear_cfm_model.py @@ -101,6 +101,23 @@ class LinearCFMagnetModel(MagnetModel, DynamicValidation): Set the magnetic rigidity used for conversion. has_hardware() Return whether the model provides hardware values. + + Configuration + ------------- + .. code-block:: yaml + + type: pyaml.magnet.linear_cfm_model + multipoles: [B0, A0] + units: [rad, rad] + hardware_units: [A, A] + curves: + - type: pyaml.magnet.csvcurve + file: path/to/horizontal_excitation_curve.csv + - type: pyaml.magnet.csvcurve + file: path/to/vertical_excitation_curve.csv + powerconverters: + - DEVICE/HORIZONTAL_POWER_CONVERTER_CURRENT + - DEVICE/VERTICAL_POWER_CONVERTER_CURRENT """ def __init__( diff --git a/pyaml/magnet/linear_model.py b/pyaml/magnet/linear_model.py index 148629bf5..6ffa0608d 100644 --- a/pyaml/magnet/linear_model.py +++ b/pyaml/magnet/linear_model.py @@ -66,6 +66,20 @@ class LinearMagnetModel(MagnetModel, DynamicValidation): If a curve is provided, the model interpolates between strength and current values using the curve and its inverse. If no curve is provided, the model uses a simple linear relation with the stored scaling factor and offset. + + Configuration + ------------- + .. code-block:: yaml + + type: pyaml.magnet.linear_model + unit: 1/m + hardware_unit: A + calibration_factor: 1.0 + calibration_offset: 0.0 + curve: + type: pyaml.magnet.csvcurve + file: path/to/excitation_curve.csv + powerconverter: DEVICE/POWER_CONVERTER_CURRENT """ def __init__( diff --git a/pyaml/magnet/linear_serialized_model.py b/pyaml/magnet/linear_serialized_model.py index 7b30c2ea5..1e912c113 100644 --- a/pyaml/magnet/linear_serialized_model.py +++ b/pyaml/magnet/linear_serialized_model.py @@ -177,6 +177,20 @@ class LinearSerializedMagnetModel(MagnetModel, DynamicValidation): ----- The number of magnets is inferred from the longest list among the supplied configuration values. Scalars are expanded to match that length. + + Configuration + ------------- + .. code-block:: yaml + + type: pyaml.magnet.linear_serialized_model + unit: 1/m + hardware_unit: A + calibration_factors: 1.0 + calibration_offsets: 0.0 + curves: + type: pyaml.magnet.csvcurve + file: path/to/excitation_curve.csv + powerconverter: DEVICE/POWER_CONVERTER_CURRENT """ def __init__( diff --git a/pyaml/magnet/octupole.py b/pyaml/magnet/octupole.py index 2247c1afd..41749abf7 100644 --- a/pyaml/magnet/octupole.py +++ b/pyaml/magnet/octupole.py @@ -38,6 +38,18 @@ class Octupole(Magnet, DynamicValidation): See Also -------- Magnet : Base class listing the strength and hardware accessors. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.octupole + name: OCTUPOLE_NAME + lattice_names: LATTICE_OCTUPOLE_NAME + model: path/to/magnet_model.yaml """ polynom = PolynomInfo("PolynomB", 3) diff --git a/pyaml/magnet/quadrupole.py b/pyaml/magnet/quadrupole.py index c3b749a12..90afac558 100644 --- a/pyaml/magnet/quadrupole.py +++ b/pyaml/magnet/quadrupole.py @@ -38,6 +38,18 @@ class Quadrupole(Magnet, DynamicValidation): See Also -------- Magnet : Base class listing the strength and hardware accessors. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.quadrupole + name: QUADRUPOLE_NAME + lattice_names: LATTICE_QUADRUPOLE_NAME + model: path/to/magnet_model.yaml """ polynom = PolynomInfo("PolynomB", 1) diff --git a/pyaml/magnet/serialized_magnet.py b/pyaml/magnet/serialized_magnet.py index 58ef44222..ddfe1733d 100644 --- a/pyaml/magnet/serialized_magnet.py +++ b/pyaml/magnet/serialized_magnet.py @@ -221,6 +221,21 @@ class SerializedMagnets(Element, DynamicValidation): The serialized group stores a virtual magnet for each underlying element. When attached, each virtual magnet is bound to the same peer and the group exposes aggregate strength and hardware accessors. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.serialized_magnet + name: SERIALIZED_QUADRUPOLES + function: B1 + elements: + - QUADRUPOLE_1 + - QUADRUPOLE_2 + model: path/to/serialized_magnet_model.yaml """ def __init__( diff --git a/pyaml/magnet/sextupole.py b/pyaml/magnet/sextupole.py index 7928c6395..7380ab9eb 100644 --- a/pyaml/magnet/sextupole.py +++ b/pyaml/magnet/sextupole.py @@ -38,6 +38,18 @@ class Sextupole(Magnet, DynamicValidation): See Also -------- Magnet : Base class listing the strength and hardware accessors. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.sextupole + name: SEXTUPOLE_NAME + lattice_names: LATTICE_SEXTUPOLE_NAME + model: path/to/magnet_model.yaml """ polynom = PolynomInfo("PolynomB", 2) diff --git a/pyaml/magnet/skewoctu.py b/pyaml/magnet/skewoctu.py index b76bf3ccc..7fb69abcd 100644 --- a/pyaml/magnet/skewoctu.py +++ b/pyaml/magnet/skewoctu.py @@ -38,6 +38,18 @@ class SkewOctu(Magnet, DynamicValidation): See Also -------- Magnet : Base class listing the strength and hardware accessors. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.skewoctu + name: SKEW_OCTUPOLE_NAME + lattice_names: LATTICE_SKEW_OCTUPOLE_NAME + model: path/to/magnet_model.yaml """ polynom = PolynomInfo("PolynomA", 3) diff --git a/pyaml/magnet/skewquad.py b/pyaml/magnet/skewquad.py index abf6bab9b..40a7b054f 100644 --- a/pyaml/magnet/skewquad.py +++ b/pyaml/magnet/skewquad.py @@ -38,6 +38,18 @@ class SkewQuad(Magnet, DynamicValidation): See Also -------- Magnet : Base class listing the strength and hardware accessors. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.skewquad + name: SKEW_QUADRUPOLE_NAME + lattice_names: LATTICE_SKEW_QUADRUPOLE_NAME + model: path/to/magnet_model.yaml """ polynom = PolynomInfo("PolynomA", 1) diff --git a/pyaml/magnet/skewsext.py b/pyaml/magnet/skewsext.py index 5d82c1d16..cc483684c 100644 --- a/pyaml/magnet/skewsext.py +++ b/pyaml/magnet/skewsext.py @@ -38,6 +38,18 @@ class SkewSext(Magnet, DynamicValidation): See Also -------- Magnet : Base class listing the strength and hardware accessors. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.skewsext + name: SKEW_SEXTUPOLE_NAME + lattice_names: LATTICE_SKEW_SEXTUPOLE_NAME + model: path/to/magnet_model.yaml """ polynom = PolynomInfo("PolynomA", 2) diff --git a/pyaml/magnet/spline_model.py b/pyaml/magnet/spline_model.py index e38734451..cdda528cb 100644 --- a/pyaml/magnet/spline_model.py +++ b/pyaml/magnet/spline_model.py @@ -70,6 +70,19 @@ class SplineMagnetModel(MagnetModel, DynamicValidation): ----- The magnet rigidity ``brho`` must be set with :meth:`set_magnet_rigidity` before using the conversion methods. + + Configuration + ------------- + .. code-block:: yaml + + type: pyaml.magnet.spline_model + unit: 1/m + hardware_unit: A + alpha: 0.0 + curve: + type: pyaml.magnet.csvcurve + file: path/to/excitation_curve.csv + powerconverter: DEVICE/POWER_CONVERTER_CURRENT """ def __init__( diff --git a/pyaml/magnet/vcorrector.py b/pyaml/magnet/vcorrector.py index f9614754f..80a379904 100644 --- a/pyaml/magnet/vcorrector.py +++ b/pyaml/magnet/vcorrector.py @@ -43,6 +43,18 @@ class VCorrector(Magnet, DynamicValidation): ------- attach(peer, strength, hardware) Return an attached copy with a bound vertical-angle handle. + + Configuration + ------------- + The model can be defined inline or in a separate file. See + :mod:`pyaml.magnet.model` and its subclasses for model configuration. + + .. code-block:: yaml + + - type: pyaml.magnet.vcorrector + name: VERTICAL_CORRECTOR_NAME + lattice_names: LATTICE_CORRECTOR_NAME + model: path/to/magnet_model.yaml """ polynom = PolynomInfo("PolynomA", 0) diff --git a/pyaml/rf/rf_plant.py b/pyaml/rf/rf_plant.py index 4a0055370..62e5954b6 100644 --- a/pyaml/rf/rf_plant.py +++ b/pyaml/rf/rf_plant.py @@ -54,6 +54,19 @@ class RFPlant(Element, DynamicValidation): ------- attach(peer, frequency, voltage) Return a copy attached to RF read/write handles. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.rf.rf_plant + name: RF + masterclock: DEVICE/RF_FREQUENCY + transmitters: + - type: pyaml.rf.rf_transmitter + name: RF_TRANSMITTER + cavities: [CAVITY_1, CAVITY_2] + voltage: DEVICE/RF_VOLTAGE """ def __init__( diff --git a/pyaml/rf/rf_transmitter.py b/pyaml/rf/rf_transmitter.py index 69abe2296..7b1677fda 100644 --- a/pyaml/rf/rf_transmitter.py +++ b/pyaml/rf/rf_transmitter.py @@ -55,6 +55,21 @@ class RFTransmitter(Element, DynamicValidation): ------- attach(peer, voltage, phase) Return a copy with voltage and phase handles attached. + + Configuration + ------------- + RF transmitters are normally nested under an + :class:`~pyaml.rf.rf_plant.RFPlant`. + + .. code-block:: yaml + + - type: pyaml.rf.rf_transmitter + name: RF_TRANSMITTER + cavities: [CAVITY_1, CAVITY_2] + voltage: DEVICE/RF_VOLTAGE + phase: DEVICE/RF_PHASE + harmonic: 1 + distribution: 1 """ def __init__( diff --git a/pyaml/tuning_tools/bba.py b/pyaml/tuning_tools/bba.py index ed0b8cc27..feb8bccd3 100644 --- a/pyaml/tuning_tools/bba.py +++ b/pyaml/tuning_tools/bba.py @@ -23,8 +23,9 @@ from .measurement_tool import MeasurementTool if TYPE_CHECKING: + from pyaml.diagnostics.bpm import BPM + from ..arrays.bpm_array import BPMArray - from ..bpm.bpm import BPM from ..magnet.magnet import Magnet logger = logging.getLogger(__name__) @@ -106,6 +107,22 @@ class BBA(MeasurementTool, DynamicValidation): Vertical corrector used for the alignment. quadrupole : Magnet Quadrupole being aligned. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.bba + name: BBA + bpm_array_name: BPM + bpm_name: BPM_NAME + hcorr_name: HORIZONTAL_CORRECTOR_NAME + vcorr_name: VERTICAL_CORRECTOR_NAME + quad_name: QUADRUPOLE_NAME + hcorr_delta: 1e-5 + vcorr_delta: 1e-5 + hquad_delta: 5e-3 + vquad_delta: 5e-3 """ def __init__( @@ -147,13 +164,13 @@ def __init__( def bpms(self) -> "BPMArray": """Return the BPM array used for the measurement.""" self.check_peer() - return self.peer.bpms.get(self.bpm_array_name) + return self.peer.diagnostic.bpms.get(self.bpm_array_name) @property def bpm(self) -> "BPM": """Return the reference BPM used for the alignment.""" self.check_peer() - return self.peer.bpm.get(self.bpm_name) + return self.peer.diagnostic.bpm.get(self.bpm_name) @property def hcorrector(self) -> "Magnet": @@ -190,7 +207,7 @@ def measure( sr = Accelerator.load("tests/config/EBSOrbit.yaml") SR = sr.design - bba = SR.get_bba("BBA-BPM_C04-04") + bba = SR.tool.get("BBA-BPM_C04-04") # Add a misalignement SR.get_bpm("BPM_C04-04").offset.set([20e-6,-15e-6]) diff --git a/pyaml/tuning_tools/bba2.py b/pyaml/tuning_tools/bba2.py index b1b7bb071..adaa9224d 100644 --- a/pyaml/tuning_tools/bba2.py +++ b/pyaml/tuning_tools/bba2.py @@ -18,8 +18,9 @@ from .measurement_tool import MeasurementTool if TYPE_CHECKING: + from pyaml.diagnostics.bpm import BPM + from ..arrays.bpm_array import BPMArray - from ..bpm.bpm import BPM from ..magnet.magnet import Magnet from .tune import Tune @@ -183,6 +184,22 @@ class BBA2(MeasurementTool, DynamicValidation): Return the quadrupole being aligned. tune_correction Return the tune-correction tool used during alignment. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.bba2 + name: BBA_WITH_TUNE_CORRECTION + bpm_array_name: BPM + bpm_name: BPM_NAME + hcorr_name: HORIZONTAL_CORRECTOR_NAME + vcorr_name: VERTICAL_CORRECTOR_NAME + quad_name: QUADRUPOLE_NAME + tune_correction_name: TUNE_CORRECTION + hcorr_delta: 1e-5 + vcorr_delta: 1e-5 + quad_delta: 5e-3 """ def __init__( @@ -228,13 +245,13 @@ def __init__( def bpms(self) -> "BPMArray": """Return the BPM array used for the measurement.""" self.check_peer() - return self.peer.bpms.get(self.bpm_array_name) + return self.peer.diagnostic.bpms.get(self.bpm_array_name) @property def bpm(self) -> "BPM": """Return the reference BPM used for the alignment.""" self.check_peer() - return self.peer.bpm.get(self.bpm_name) + return self.peer.diagnostic.bpm.get(self.bpm_name) @property def hcorrector(self) -> "Magnet": @@ -258,7 +275,7 @@ def quadrupole(self) -> "Magnet": def tune_correction(self) -> "Tune": """Return the tune-correction tool used during alignment.""" self.check_peer() - return self.peer.get_tune_tuning(self.tune_correction_name) + return self.peer.tool.get(self.tune_correction_name) @staticmethod def _x_intercept(x, k, n): @@ -343,9 +360,9 @@ def _init_responses( quad = design.magnet.get(quadname) sth = design.magnet.get(steererhname) stv = design.magnet.get(steerervname) - orbit = design.bpms.get(bpmname).positions - tune_design = design.get_tune_tuning(tunename) - tune_live = self._peer.get_tune_tuning(tunename) + orbit = design.diagnostic.bpms.get(bpmname).positions + tune_design = design.tool.get(tunename) + tune_live = self._peer.tool.get(tunename) # Get tune from live and adjust the model to improve quad response phase tune0 = tune_design.readback() @@ -569,7 +586,7 @@ def measure( sr = Accelerator.load("tests/config/EBSOrbit.yaml") SR = sr.live - bba = SR.get_bba("BBA2-BPM_C04-04") + bba = SR.tool.get("BBA2-BPM_C04-04") # Add a misalignement SR.get_bpm("BPM_C04-04").offset.set([200e-6,-150e-6]) diff --git a/pyaml/tuning_tools/chromaticity.py b/pyaml/tuning_tools/chromaticity.py index e1aed2640..d43c46726 100644 --- a/pyaml/tuning_tools/chromaticity.py +++ b/pyaml/tuning_tools/chromaticity.py @@ -72,6 +72,16 @@ class Chromaticity(TuningTool, DynamicValidation): Calculate sextupole-strength changes for a chromaticity change. add(dchroma, wait_time=0.0) Apply a chromaticity correction relative to the current setpoint. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.chromaticity + name: CHROMATICITY_CORRECTION + sextu_array_name: SEXTUPOLES + chromaticity_monitor_name: CHROMATICITY_MONITOR + response_matrix: path/to/chromaticity_response.json """ def __init__( @@ -125,7 +135,7 @@ def load(self, load_path: Path): def chromaticity_monitor(self) -> "ChromaticityMonitor": """Return the chromaticity monitor used for readback.""" self.check_peer() - return self.peer.get_chromaticity_monitor(self._chromaticity_monitor_name) + return self.peer.tool.get(self._chromaticity_monitor_name) @property def sextupoles(self) -> "MagnetArray": diff --git a/pyaml/tuning_tools/chromaticity_monitor.py b/pyaml/tuning_tools/chromaticity_monitor.py index c1da25079..c03e284f0 100644 --- a/pyaml/tuning_tools/chromaticity_monitor.py +++ b/pyaml/tuning_tools/chromaticity_monitor.py @@ -140,6 +140,18 @@ class ChromaticityMonitor(MeasurementTool, DynamicValidation): fit(deltas, Q, order, orbit=None, fit_disp_order=None, do_plot=False) Compute chromaticity (and dispersion) from input data and update :py:attr:`~pyaml.tuning_tools.measurement_tool.MeasurementTool.latest_measurement`. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.chromaticity_monitor + name: CHROMATICITY_MONITOR + betatron_tune_name: BETATRON_TUNE + rf_plant_name: RF + bpm_array_name: BPM + fit_dispersion: true + n_step: 5 """ def __init__( @@ -189,7 +201,7 @@ def __init__( def tune_monitor(self) -> "BetatronTuneMonitor": """Return the betatron tune monitor used for measurements.""" self.check_peer() - return self.peer.get_betatron_tune_monitor(self.betatron_tune_name) + return self.peer.diagnostic.get(self.betatron_tune_name) @property def rf_plant(self) -> "RFPlant": @@ -203,7 +215,7 @@ def bpms(self) -> "BPMArray | None": self.check_peer() if self.bpm_array_name is None: return None - return self.peer.bpms.get(self.bpm_array_name) + return self.peer.diagnostic.bpms.get(self.bpm_array_name) @property def chromaticity(self) -> ReadFloatArray: diff --git a/pyaml/tuning_tools/chromaticity_response_matrix.py b/pyaml/tuning_tools/chromaticity_response_matrix.py index 6746f4034..23d712ed4 100644 --- a/pyaml/tuning_tools/chromaticity_response_matrix.py +++ b/pyaml/tuning_tools/chromaticity_response_matrix.py @@ -68,6 +68,16 @@ class ChromaticityResponseMatrix(MeasurementTool, DynamicValidation): Sextupole array used for the measurement. chromaticity_monitor : ChromaticityMonitor Chromaticity monitor used for the measurement. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.chromaticity_response_matrix + name: CHROMATICITY_RESPONSE_MATRIX + sextu_array_name: SEXTUPOLES + chromaticity_name: CHROMATICITY_MONITOR + sextu_delta: 1e-6 """ def __init__( @@ -105,7 +115,7 @@ def sextupoles(self) -> "MagnetArray": def chromaticity_monitor(self) -> "ChromaticityMonitor": """Return the chromaticity monitor used for the measurement.""" self.check_peer() - return self.peer.get_chromaticity_monitor(self.chromaticity_name) + return self.peer.tool.get(self.chromaticity_name) def measure( self, @@ -141,10 +151,10 @@ def callback(action: Action, data:dict): sr = Accelerator.load("tests/config/EBSOrbit.yaml") acc = sr.design - if acc.crm.measure(callback=callback): - acc.crm.save("ideal_crm.json") - acc.crm.save("ideal_crm.yaml", with_type="yaml") - acc.crm.save("ideal_crm.npz", with_type="npz") + if acc.tool.crm.measure(callback=callback): + acc.tool.crm.save("ideal_crm.json") + acc.tool.crm.save("ideal_crm.yaml", with_type="yaml") + acc.tool.crm.save("ideal_crm.npz", with_type="npz") Parameters ---------- diff --git a/pyaml/tuning_tools/dispersion.py b/pyaml/tuning_tools/dispersion.py index 6bbc3844b..81fccb11a 100644 --- a/pyaml/tuning_tools/dispersion.py +++ b/pyaml/tuning_tools/dispersion.py @@ -65,6 +65,16 @@ class Dispersion(MeasurementTool, DynamicValidation): Measure beam dispersion by varying the RF frequency. get() Return the most recently measured dispersion data. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.dispersion + name: DISPERSION + bpm_array_name: BPM + rf_plant_name: RF + frequency_delta: 100 """ def __init__(self, name: str, bpm_array_name: str, rf_plant_name: str, frequency_delta: float): @@ -81,7 +91,7 @@ def __init__(self, name: str, bpm_array_name: str, rf_plant_name: str, frequency def bpms(self) -> "BPMArray": """Return the BPM array used for orbit readback.""" self.check_peer() - return self.peer.bpms.get(self.bpm_array_name) + return self.peer.diagnostic.bpms.get(self.bpm_array_name) @property def rf_plant(self) -> "RFPlant": diff --git a/pyaml/tuning_tools/measurement_tool.py b/pyaml/tuning_tools/measurement_tool.py index 646d38ed9..acdc57892 100644 --- a/pyaml/tuning_tools/measurement_tool.py +++ b/pyaml/tuning_tools/measurement_tool.py @@ -182,7 +182,7 @@ def callback(action: Action, data: dict): return True # Measure a tune response matrix using the above callback - sr.design.trm.measure(callback=callback) + sr.design.tool.trm.measure(callback=callback) Parameters ---------- diff --git a/pyaml/tuning_tools/orbit.py b/pyaml/tuning_tools/orbit.py index 3f2c8b397..61468323f 100644 --- a/pyaml/tuning_tools/orbit.py +++ b/pyaml/tuning_tools/orbit.py @@ -94,6 +94,19 @@ class Orbit(TuningTool, DynamicValidation): Return the configured RF-frequency correction weight. post_init() Bind orbit corrector and RF handles after attachment. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.orbit + name: ORBIT_CORRECTION + bpm_array_name: BPM + hcorr_array_name: HORIZONTAL_CORRECTORS + vcorr_array_name: VERTICAL_CORRECTORS + rf_plant_name: RF + singular_values: 16 + response_matrix: path/to/orbit_response.json """ def __init__( @@ -199,7 +212,7 @@ def response_matrix(self) -> OrbitResponseMatrixData | None: def bpms(self) -> BPMArray: """Return the BPM array used for orbit readback.""" self.check_peer() - return self.peer.bpms.get(self.bpm_array_name) + return self.peer.diagnostic.bpms.get(self.bpm_array_name) @property def hcorrectors(self) -> MagnetArray: diff --git a/pyaml/tuning_tools/orbit_response_matrix.py b/pyaml/tuning_tools/orbit_response_matrix.py index 7b065b49c..14bd96d2a 100644 --- a/pyaml/tuning_tools/orbit_response_matrix.py +++ b/pyaml/tuning_tools/orbit_response_matrix.py @@ -98,6 +98,17 @@ class OrbitResponseMatrix(MeasurementTool, DynamicValidation): ------- measure(...) Measure orbit response matrix. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.orbit_response_matrix + name: ORBIT_RESPONSE_MATRIX + bpm_array_name: BPM + hcorr_array_name: HORIZONTAL_CORRECTORS + vcorr_array_name: VERTICAL_CORRECTORS + corrector_delta: 1e-6 """ def __init__( @@ -130,7 +141,7 @@ def __init__( def bpms(self) -> "BPMArray": """Return the BPM array used for orbit readback.""" self.check_peer() - return self.peer.bpms.get(self.bpm_array_name) + return self.peer.diagnostic.bpms.get(self.bpm_array_name) @property def hcorrectors(self) -> "MagnetArray": @@ -162,10 +173,10 @@ def measure( sr = Accelerator.load("MyAccelerator.yaml") acc = sr.design - if acc.orm.measure(): - acc.orm.save("ideal_orm.json") - acc.orm.save("ideal_orm.yaml", with_type="yaml") - acc.orm.save("ideal_orm.npz", with_type="npz") + if acc.tool.orm.measure(): + acc.tool.orm.save("ideal_orm.json") + acc.tool.orm.save("ideal_orm.yaml", with_type="yaml") + acc.tool.orm.save("ideal_orm.npz", with_type="npz") Parameters ---------- diff --git a/pyaml/tuning_tools/tune.py b/pyaml/tuning_tools/tune.py index 068caf137..18811bba3 100644 --- a/pyaml/tuning_tools/tune.py +++ b/pyaml/tuning_tools/tune.py @@ -86,6 +86,16 @@ class Tune(TuningTool, DynamicValidation): Calculate quadrupole-strength changes for a tune change. add(dtune, wait_time=0.0) Apply a tune correction relative to the current setpoint. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.tune + name: TUNE_CORRECTION + quad_array_name: QUADRUPOLES + betatron_tune_name: BETATRON_TUNE + response_matrix: path/to/tune_response.json """ def __init__( @@ -143,7 +153,7 @@ def response_matrix(self) -> ResponseMatrixData | None: def tune_monitor(self) -> "BetatronTuneMonitor": """Return the betatron tune monitor used by the correction.""" self.check_peer() - return self.peer.get_betatron_tune_monitor(self.betatron_tune_name) + return self.peer.diagnostic.get(self.betatron_tune_name) @property def quadrupoles(self) -> "MagnetArray": diff --git a/pyaml/tuning_tools/tune_response_matrix.py b/pyaml/tuning_tools/tune_response_matrix.py index 023b86cad..fe65e0d14 100644 --- a/pyaml/tuning_tools/tune_response_matrix.py +++ b/pyaml/tuning_tools/tune_response_matrix.py @@ -109,6 +109,16 @@ class TuneResponseMatrix(MeasurementTool, DynamicValidation): Quadrupole strengths are restored after each individual scan and again when the measurement exits because of an error or interruption. + + Configuration + ------------- + .. code-block:: yaml + + - type: pyaml.tuning_tools.tune_response_matrix + name: TUNE_RESPONSE_MATRIX + quad_array_name: QUADRUPOLES + betatron_tune_name: BETATRON_TUNE + quad_delta: 1e-4 """ def __init__( @@ -144,7 +154,7 @@ def quadrupoles(self) -> "MagnetArray": def tune_monitor(self) -> "BetatronTuneMonitor": """Return the betatron tune monitor used for the measurement.""" self.check_peer() - return self.peer.get_betatron_tune_monitor(self.betatron_tune_name) + return self.peer.diagnostic.get(self.betatron_tune_name) def measure( self, @@ -180,10 +190,10 @@ def callback(action: Action, data:dict): sr = Accelerator.load("tests/config/EBSTune.yaml") acc = sr.design - if acc.trm.measure(n_avg_meas=3,sleep_between_meas=5,callback=callback): - acc.trm.save("ideal_trm.json") - acc.trm.save("ideal_trm.yaml", with_type="yaml") - acc.trm.save("ideal_trm.npz", with_type="npz") + if acc.tool.trm.measure(n_avg_meas=3,sleep_between_meas=5,callback=callback): + acc.tool.trm.save("ideal_trm.json") + acc.tool.trm.save("ideal_trm.yaml", with_type="yaml") + acc.tool.trm.save("ideal_trm.npz", with_type="npz") Parameters ---------- diff --git a/tests/arrays/test_array_selection_types.py b/tests/arrays/test_array_selection_types.py index d5cc782bf..8dce804ef 100644 --- a/tests/arrays/test_array_selection_types.py +++ b/tests/arrays/test_array_selection_types.py @@ -2,6 +2,7 @@ from pyaml.arrays.element_array import ElementArray from pyaml.arrays.magnet_array import MagnetArray +from pyaml.common.exception import PyAMLException @pytest.fixture @@ -43,7 +44,7 @@ def test_magnet_holder_selection_uses_the_same_typing(design): def test_mixed_array_stays_generic_until_only_magnets_are_selected(design): - mixed = design.get_elements("ElArray") + mixed = design.get("ElArray") assert type(mixed[:]) is ElementArray assert mixed[:].names() == mixed.names() @@ -60,3 +61,41 @@ def test_empty_selections_and_integer_indexing_keep_their_behavior(design): assert magnets["UNKNOWN*"] == [] assert magnets[0] is design.magnet.get(magnets.names()[0]) assert type(magnets - magnets) is list + + +def test_literal_name_miss_raises(design): + magnets = design.magnets.get() + + with pytest.raises(PyAMLException): + magnets["UNKNOWN"] + with pytest.raises(PyAMLException): + design.magnets["UNKNOWN"] + + +def test_literal_name_hit_still_returns_a_single_element_array(design): + magnets = design.magnets.get() + + selected = magnets["SH1A-C01-H"] + assert type(selected) is MagnetArray + assert selected.names() == ["SH1A-C01-H"] + + +def test_bracket_only_pattern_is_a_wildcard(design): + magnets = design.magnets.get() + assert sorted(magnets["SH1A-C0[12]-H"].names()) == ["SH1A-C01-H", "SH1A-C02-H"] + + +def test_regex_pattern_is_supported(design): + magnets = design.magnets.get() + assert sorted(magnets["re:^SH1A-C0[12]-H$"].names()) == ["SH1A-C01-H", "SH1A-C02-H"] + + +def test_list_of_patterns_is_supported(design): + magnets = design.magnets.get() + selected = magnets[["SH1A-C01-H", "SH1A-C02-H"]] + assert selected.names() == ["SH1A-C01-H", "SH1A-C02-H"] + + +def test_wildcard_matching_is_case_sensitive(design): + magnets = design.magnets.get() + assert magnets["sh1a*"] == [] diff --git a/tests/arrays/test_arrays.py b/tests/arrays/test_arrays.py index 7ae9b8710..5bd02a3d6 100644 --- a/tests/arrays/test_arrays.py +++ b/tests/arrays/test_arrays.py @@ -128,32 +128,32 @@ def test_arrays(install_test_package): # Test BPMs array # Using aggregator - pos = sr.design.bpms.get("BPMS").positions.get() + pos = sr.design.diagnostic.bpms.get("BPMS").positions.get() assert np.abs(pos[0][0] - 7.22262850488348e-05) < 1e-10 assert np.abs(pos[0][1] - 3.4291613955705856e-05) < 1e-10 assert np.abs(pos[1][0] + 1.1696152238807462e-04) < 1e-10 assert np.abs(pos[1][1] - 7.4265634524358045e-06) < 1e-10 # Using aggregator (h and v) - pos_h = sr.design.bpms.get("BPMS").h.get() - pos_v = sr.design.bpms.get("BPMS").v.get() + pos_h = sr.design.diagnostic.bpms.get("BPMS").h.get() + pos_v = sr.design.diagnostic.bpms.get("BPMS").v.get() assert np.all(np.isclose(pos[:, 0], pos_h, rtol=1e-15, atol=1e-15)) assert np.all(np.isclose(pos[:, 1], pos_v, rtol=1e-15, atol=1e-15)) # Test BPM transformation matrices - sr.design.bpm.get("BPM_C04-01").offset.set([0.1, 0.2]) - sr.design.bpm.get("BPM_C04-02").offset.set([0.3, 0.4]) - pos = sr.design.bpms.get("BPMS").positions.get() + sr.design.diagnostic.bpm.get("BPM_C04-01").offset.set([0.1, 0.2]) + sr.design.diagnostic.bpm.get("BPM_C04-02").offset.set([0.3, 0.4]) + pos = sr.design.diagnostic.bpms.get("BPMS").positions.get() assert np.abs(pos[0][0] - 7.22262850488348e-05 - 0.1) < 1e-10 assert np.abs(pos[0][1] - 3.4291613955705856e-05 - 0.2) < 1e-10 assert np.abs(pos[1][0] + 1.1696152238807462e-04 - 0.3) < 1e-10 assert np.abs(pos[1][1] - 7.4265634524358045e-06 - 0.4) < 1e-10 - sr.design.bpm.get("BPM_C04-01").offset.set([0.0, 0.0]) - sr.design.bpm.get("BPM_C04-02").offset.set([0.0, 0.0]) + sr.design.diagnostic.bpm.get("BPM_C04-01").offset.set([0.0, 0.0]) + sr.design.diagnostic.bpm.get("BPM_C04-02").offset.set([0.0, 0.0]) # No aggregator bpms = [] - for b in sr.design.bpms.get("BPMS"): + for b in sr.design.diagnostic.bpms.get("BPMS"): bpms.append(b) bpms = BPMArray("BPM_noagg", bpms, use_aggregator=False) @@ -164,10 +164,10 @@ def test_arrays(install_test_package): assert np.abs(pos[1][1] - 7.4265634524358045e-06) < 1e-10 # Radom array - elts = sr.design.get_elements("ElArray") + elts = sr.design.get("ElArray") # Create an array that contains all elements - allElts = ElementArray("AllElements", sr.design.get_all_elements()) + allElts = ElementArray("AllElements", sr.design.get()) assert len(allElts) == 11 # Create an array that contains all elements @@ -175,7 +175,7 @@ def test_arrays(install_test_package): assert len(allMags) == 7 # Create an array that contains all BPM - allBpms = BPMArray("AllBPMs", sr.design.bpm.all()) + allBpms = BPMArray("AllBPMs", sr.design.diagnostic.bpm.all()) assert len(allBpms) == 2 cfm = sr.design.combined_function_magnets.get("CFM") @@ -204,13 +204,13 @@ def test_arrays(install_test_package): assert np.abs(strHVSQ[4] + 0.000017) < 1e-10 # V assert np.abs(strHVSQ[5] - 1e-6) < 1e-10 # SQ - bpmsLive = BPMArray("", sr.live.bpm.all()) + bpmsLive = BPMArray("", sr.live.diagnostic.bpm.all()) bpmsLive.positions.get() # Test dynamic arrays sr: Accelerator = Accelerator.load("tests/config/EBSOrbit.yaml", include_locations=False) - ae = ElementArray("All", sr.design.get_all_elements()) + ae = ElementArray("All", sr.design.get()) acfm = ElementArray("AllCFM", sr.design.combined_function_magnet.all(), use_aggregator=False) bpmC5 = ae["BPM*"][10:20] # All BPM C5 @@ -232,7 +232,7 @@ def test_arrays(install_test_package): emptyBPM = BPM(name="emptyBPM", elements=[]) emptyBPM.fill_array(sr.design) # Attach the array - v = sr.design.bpms.get("emptyBPM").positions.get() # Ensure good attach + v = sr.design.diagnostic.bpms.get("emptyBPM").positions.get() # Ensure good attach assert np.shape(v) == (0,) emptyCFM = CombinedFunctionMagnet(name="emptyCFM", elements=[]) diff --git a/tests/arrays/test_arrays_ops.py b/tests/arrays/test_arrays_ops.py index 5fd706e2c..fd8c961fc 100644 --- a/tests/arrays/test_arrays_ops.py +++ b/tests/arrays/test_arrays_ops.py @@ -43,7 +43,7 @@ def test_element_array_and_mask_filters_and_is_autotyped_list_mask( sr.design.get_lattice().disable_6d() # "ElArray" is a mixed ElementArray in the dummy config (see existing tests) - elts = sr.design.get_elements("ElArray") + elts = sr.design.get("ElArray") assert isinstance(elts, ElementArray) assert len(elts) > 0 @@ -71,7 +71,7 @@ def test_element_array_and_mask_filters_and_is_autotyped_numpy_mask( sr = accelerator_from_fragments(*sr_configuration_fragments) sr.design.get_lattice().disable_6d() - elts = sr.design.get_elements("ElArray") + elts = sr.design.get("ElArray") assert len(elts) > 0 mask_list = [isinstance(e, Magnet) for e in elts] @@ -97,7 +97,7 @@ def test_element_array_sub_mask_removes_true_inverse_of_and( sr = accelerator_from_fragments(*sr_configuration_fragments) sr.design.get_lattice().disable_6d() - elts = sr.design.get_elements("ElArray") + elts = sr.design.get("ElArray") assert len(elts) > 0 # Keep only magnets with '& mask' @@ -134,7 +134,7 @@ def test_element_array_mask_length_mismatch_raises_for_and_and_sub( sr = accelerator_from_fragments(*sr_configuration_fragments) sr.design.get_lattice().disable_6d() - elts = sr.design.get_elements("ElArray") + elts = sr.design.get("ElArray") assert len(elts) > 0 bad_mask = [True] * (len(elts) - 1) @@ -159,7 +159,7 @@ def test_mask_by_type_returns_correct_boolean_mask( sr = accelerator_from_fragments(*sr_configuration_fragments) sr.design.get_lattice().disable_6d() - elts = sr.design.get_elements("ElArray") + elts = sr.design.get("ElArray") mask = elts.mask_by_type(Magnet) assert isinstance(mask, list) @@ -182,7 +182,7 @@ def test_filter_by_type_returns_autotyped_array(install_test_package, accelerato sr = accelerator_from_fragments(*sr_configuration_fragments) sr.design.get_lattice().disable_6d() - elts = sr.design.get_elements("ElArray") + elts = sr.design.get("ElArray") filtered = elts.of_type(Magnet) if len(filtered) == 0: diff --git a/tests/bpm/test_bpm_controlsystem.py b/tests/bpm/test_bpm_controlsystem.py deleted file mode 100644 index 13321ca12..000000000 --- a/tests/bpm/test_bpm_controlsystem.py +++ /dev/null @@ -1,96 +0,0 @@ -import numpy as np -import pytest - -from pyaml.accelerator import Accelerator - - -@pytest.mark.parametrize( - "install_test_package", - [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], - indirect=True, -) -def test_controlsystem_bpm_tilt(install_test_package): - sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") - bpm = sr.live.bpm.get("BPM_C01-01") - print(bpm.tilt.get()) - - assert bpm.tilt.get() == 0 - bpm.tilt.set(0.01) - assert bpm.tilt.get() == 0.01 - - -@pytest.mark.parametrize( - "install_test_package", - [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], - indirect=True, -) -def test_controlsystem_bpm_offset(install_test_package): - sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") - bpm = sr.live.bpm.get("BPM_C01-01") - - assert bpm.offset.get()[0] == 0 - assert bpm.offset.get()[1] == 0 - bpm.offset.set(np.array([0.1, 0.2])) - assert bpm.offset.get()[0] == 0.1 - assert bpm.offset.get()[1] == 0.2 - assert np.allclose(bpm.positions.get(), np.array([0.0, 0.0])) - - -@pytest.mark.parametrize( - "install_test_package", - [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], - indirect=True, -) -def test_controlsystem_bpm_position(install_test_package): - sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") - bpm = sr.live.bpm.get("BPM_C01-01") - bpm_simple = sr.live.bpm.get("BPM_C01-02") - - assert np.allclose(bpm.positions.get(), np.array([0.0, 0.0])) - assert np.allclose(bpm_simple.positions.get(), np.array([0.0, 0.0])) - - -@pytest.mark.parametrize( - "install_test_package", - [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], - indirect=True, -) -def test_controlsystem_get_devices_returns_attached_devices(install_test_package): - sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") - - devs = sr.live.get_devices_access(["srdiag/bpm/c01-01/SA_HPosition", "srdiag/bpm/c01-01/SA_VPosition"]) - - assert devs[0].name() == "//ebs-simu-3:10000/srdiag/bpm/c01-01/SA_HPosition" - assert devs[1].name() == "//ebs-simu-3:10000/srdiag/bpm/c01-01/SA_VPosition" - - -@pytest.mark.parametrize( - "install_test_package", - [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], - indirect=True, -) -def test_controlsystem_get_device_accepts_backend_config_model(install_test_package): - from tango.pyaml.attribute import ConfigModel as AttributeConfigModel - - sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") - - dev = sr.live.get_device_access(AttributeConfigModel(attribute="srdiag/bpm/c01-05/SA_HPosition", unit="mm")) - - assert dev.name() == "//ebs-simu-3:10000/srdiag/bpm/c01-05/SA_HPosition" - assert dev.unit() == "mm" - - -@pytest.mark.parametrize( - "install_test_package", - [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], - indirect=True, -) -def test_controlsystem_bpm_position_indexed(install_test_package): - from tango.pyaml.attribute_store import set_attribute - - set_attribute("srdiag/bpm/c01-04/Position", [0.0, 1.0], unit="mm") - - sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") - bpm = sr.live.bpm.get("BPM_C01-04") - - assert np.allclose(bpm.positions.get(), np.array([0.0, 1.0])) diff --git a/tests/common/test_array_holder_navigation.py b/tests/common/test_array_holder_navigation.py new file mode 100644 index 000000000..8bd0d2a9b --- /dev/null +++ b/tests/common/test_array_holder_navigation.py @@ -0,0 +1,315 @@ +import pytest + +from pyaml.accelerator import Accelerator +from pyaml.arrays.cfm_magnet_array import CombinedFunctionMagnetArray +from pyaml.arrays.magnet_array import MagnetArray +from pyaml.common.exception import PyAMLException +from pyaml.configuration.manager import ConfigurationManager + + +@pytest.fixture +def holder(accelerator_from_fragments, sr_configuration_fragments): + sr = accelerator_from_fragments(*sr_configuration_fragments) + sr.design.get_lattice().disable_6d() + return sr.design + + +@pytest.fixture +def serialized_holder(): + sr = Accelerator.load("tests/config/sr_serialized_magnets.yaml", include_locations=False, ignore_external=True) + return sr.design + + +def test_dynamic_attribute_returns_named_magnet_array(holder): + assert holder.magnets.HCORR is holder.magnets.get("HCORR") + assert holder.magnets.VCORR is holder.magnets.get("VCORR") + assert holder.magnets.HVCORR is holder.magnets.get("HVCORR") + + +def test_dynamic_attribute_returns_named_combined_function_magnet_array(holder): + assert holder.combined_function_magnets.CFM is holder.combined_function_magnets.get("CFM") + + +def test_dynamic_attribute_returns_named_bpm_array(holder): + assert holder.diagnostic.bpms.BPMS is holder.diagnostic.bpms.get("BPMS") + + +def test_dynamic_attribute_returns_named_serialized_magnet_array(serialized_holder): + assert serialized_holder.serialized_magnets.QForTune is serialized_holder.serialized_magnets.get("QForTune") + assert serialized_holder.serialized_magnets.series is serialized_holder.serialized_magnets.get("series") + + +def test_dynamic_attribute_unknown_name_raises_attribute_error(holder): + with pytest.raises(AttributeError): + _ = holder.magnets.UNKNOWN + + +def test_dynamic_attribute_does_not_shadow_existing_methods(holder): + holder.magnets._array_store["get"] = holder.magnets.get("HCORR") + holder.magnets._array_store["add"] = holder.magnets.get("HCORR") + + assert callable(holder.magnets.get) + assert callable(holder.magnets.add) + assert holder.magnets.get("HCORR").names() == ["SH1A-C01-H", "SH1A-C02-H"] + + +def test_dynamic_attribute_rejects_non_identifier_names(holder): + holder.magnets._array_store["not-an-id"] = holder.magnets.get("HCORR") + + with pytest.raises(AttributeError): + getattr(holder.magnets, "not-an-id") + + +def test_dir_includes_configured_array_names(holder): + assert {"HCORR", "VCORR", "HVCORR"} <= set(dir(holder.magnets)) + assert "CFM" in dir(holder.combined_function_magnets) + assert "BPMS" in dir(holder.diagnostic.bpms) + + +def test_dir_excludes_non_identifier_array_names(holder): + holder.magnets._array_store["not-an-id"] = holder.magnets.get("HCORR") + + assert "not-an-id" not in dir(holder.magnets) + + +def test_get_cfm_returns_all_combined_function_magnets(holder): + combined_function_magnets = holder.magnets.get_cfm() + + assert type(combined_function_magnets) is CombinedFunctionMagnetArray + assert combined_function_magnets.names() == holder.combined_function_magnets.get().names() + + +def test_issue_373_example(): + """Reproduce the #373 example verbatim, against real test lattice data.""" + sr = Accelerator.load("tests/config/EBSTune-patterns.yaml", ignore_external=True) + sr.design.get_lattice().disable_6d() + + all_magnets = sr.design.magnets[:] + quad_family = sr.design.magnets.get("QForTune") + same_quad_family = sr.design.magnets.QForTune + assert same_quad_family.names() == quad_family.names() + assert len(quad_family) == 124 + assert len(all_magnets) >= len(quad_family) + + combined_function_magnets = sr.design.magnets.get_cfm() + assert len(combined_function_magnets) == 0 + + matching_quadrupoles = sr.design.magnets["QF1*"] + assert matching_quadrupoles.names() == sr.design.magnets["QF1*"].names() + + one_magnet = sr.design.magnet.get("QF1E-C04") + one_magnet.strength.set(0.8) + assert one_magnet.strength.get() == pytest.approx(0.8) + + +def test_configured_exclusion_family_reproduced_with_selection_and_difference(): + """QForTest is QForTune minus a `~name`/`~pattern` YAML exclusion; `[]` and `-` reproduce it.""" + sr = Accelerator.load("tests/config/EBSTune-patterns.yaml", ignore_external=True) + sr.design.get_lattice().disable_6d() + + q_for_tune = sr.design.magnets.get("QForTune") + q_for_test = sr.design.magnets.get("QForTest") # QForTune, minus ~QF1E-C05 and ~Q???-C06 + + reproduced = q_for_tune - sr.design.magnets["QF1E-C05"] - sr.design.magnets["Q???-C06"] + + assert reproduced == q_for_test + + +def test_configured_exclusion_family_reproduced_in_a_single_getitem_call(): + """The YAML `elements:` selector list (`[QD2*, QF1*, ~QF1E-C05, ~Q???-C06]`) selects the + same *family* of elements through `[]` as declared for `QForTest`. + + Selection goes through the top-level holder, not `.magnets`, so it resolves patterns + against the same global element pool `find_elements()`/`_fill_array` use to build + `QForTest` in the YAML. The two therefore agree on *which* elements are selected, but not + necessarily on their order: `_fill_array` concatenates matches pattern by pattern (all + `QD2*` matches, then all `QF1*` matches) to build the named array, while `[]` (like every + other list-selection accessor, see `test_every_accessor_returns_a_list_selection_in_configuration_order`) + normalizes its result to configuration order regardless of how many patterns were + involved or in what order they matched. + """ + sr = Accelerator.load("tests/config/EBSTune-patterns.yaml", ignore_external=True) + sr.design.get_lattice().disable_6d() + + q_for_test = sr.design.magnets.get("QForTest") + reproduced = sr.design[["QD2*", "QF1*", "~QF1E-C05", "~Q???-C06"]] + + assert type(reproduced) is type(q_for_test) + assert set(reproduced.names()) == set(q_for_test.names()) + assert reproduced.names() == [n for n in sr.design.get().names() if n in set(q_for_test.names())] + + +def test_array_getitem_supports_a_negated_regex_pattern(): + """`~re:...` on an ElementArray excludes regex matches, same as `~wildcard`.""" + sr = Accelerator.load("tests/config/EBSTune-patterns.yaml", ignore_external=True) + sr.design.get_lattice().disable_6d() + + magnets = sr.design.magnets[:] + wildcard_exclusion = magnets["~QF1*"] + regex_exclusion = magnets["~re:^QF1.*$"] + + assert len(regex_exclusion) > 0 + assert len(regex_exclusion) < len(magnets) + assert regex_exclusion == wildcard_exclusion + + +def test_fill_array_supports_an_exclusion_outside_a_single_getitem_call_shape(): + """A YAML `elements:` list combining an inclusion and an exclusion builds an array, not a ValueError. + + `_fill_array` previously did its own include/exclude bookkeeping with `list.remove`, + which raised whenever the excluded name wasn't already gathered by an inclusion + pattern processed earlier in the same call. Delegating to `find_elements` (used here + with the same list, for comparison) avoids that ordering trap. + """ + manager = ConfigurationManager() + manager.add("tests/config/EBSTune-patterns.yaml") + manager.add({"arrays": [{"type": "pyaml.arrays.magnet", "name": "QD2Family", "elements": ["QD2*", "~QF1E-C05"]}]}) + sr = manager.build(ignore_external=True) + sr.design.get_lattice().disable_6d() + + qd2_family = sr.design.magnets.get("QD2Family") + + assert qd2_family.names() == sr.design.find_elements(["QD2*", "~QF1E-C05"]) + + +def test_magnet_holder_getitem_exact_name_matches_get(holder): + assert holder.magnet["SH1A-C01-H"] is holder.magnet.get("SH1A-C01-H") + + +def test_magnet_holder_getitem_exact_name_miss_raises(holder): + with pytest.raises(PyAMLException): + holder.magnet["UNKNOWN"] + + +def test_magnet_holder_getitem_wildcard_and_list_return_an_array(holder): + wildcard = holder.magnet["SH1A-C01-[HV]"] + assert sorted(wildcard.names()) == ["SH1A-C01-H", "SH1A-C01-V"] + assert holder.magnet["MISSING*"].names() == [] + + listed = holder.magnet[["SH1A-C01-H", "SH1A-C01-V"]] + assert listed.names() == ["SH1A-C01-H", "SH1A-C01-V"] + + +def test_magnet_holder_getitem_wildcard_returns_a_magnet_array(holder): + """A wildcard restricted to the .magnet store is auto-typed as MagnetArray, like the + top-level and .magnets holders, instead of falling back to a generic ElementArray.""" + wildcard = holder.magnet["SH1A-C0[12]-[HVQ]*"] + assert type(wildcard) is MagnetArray + + +def test_magnet_and_magnets_holder_getitem_agree_on_order(holder): + """.magnet (singular) and .magnets (plural) must return the same elements in the same + order for the same name list, regardless of the order the names were requested in. The + reference order is the configuration order, not the order of the requested names. This + must also hold for the top-level holder itself (`[]` and `find_elements`), not just its + typed sub-holders.""" + forward = holder.magnet[["SH1A-C01-H", "SH1A-C01-V"]] + backward = holder.magnet[["SH1A-C01-V", "SH1A-C01-H"]] + assert forward.names() == backward.names() == ["SH1A-C01-H", "SH1A-C01-V"] + + forward_plural = holder.magnets[["SH1A-C01-H", "SH1A-C01-V"]] + backward_plural = holder.magnets[["SH1A-C01-V", "SH1A-C01-H"]] + assert forward_plural.names() == backward_plural.names() == forward.names() + + forward_top_level = holder[["SH1A-C01-H", "SH1A-C01-V"]] + backward_top_level = holder[["SH1A-C01-V", "SH1A-C01-H"]] + assert forward_top_level.names() == backward_top_level.names() == forward.names() + + assert holder.find_elements(["SH1A-C01-H", "SH1A-C01-V"]) == forward.names() + assert holder.find_elements(["SH1A-C01-V", "SH1A-C01-H"]) == forward.names() + + +def test_combined_function_magnet_and_bpm_holders_return_list_selections_in_configuration_order(holder): + """Every typed sub-holder must normalize list selections to configuration order, not just + .magnet/.magnets: this must also hold for .combined_function_magnet(s) and .bpm(s).""" + cfm_forward = holder.combined_function_magnet[["SH1A-C01", "SH1A-C02"]] + cfm_backward = holder.combined_function_magnet[["SH1A-C02", "SH1A-C01"]] + assert cfm_forward.names() == cfm_backward.names() == ["SH1A-C01", "SH1A-C02"] + + cfm_forward_plural = holder.combined_function_magnets[["SH1A-C01", "SH1A-C02"]] + cfm_backward_plural = holder.combined_function_magnets[["SH1A-C02", "SH1A-C01"]] + assert cfm_forward_plural.names() == cfm_backward_plural.names() == cfm_forward.names() + + bpm_forward = holder.diagnostic.bpm[["BPM_C04-01", "BPM_C04-02"]] + bpm_backward = holder.diagnostic.bpm[["BPM_C04-02", "BPM_C04-01"]] + assert bpm_forward.names() == bpm_backward.names() == ["BPM_C04-01", "BPM_C04-02"] + + bpm_forward_plural = holder.diagnostic.bpms[["BPM_C04-01", "BPM_C04-02"]] + bpm_backward_plural = holder.diagnostic.bpms[["BPM_C04-02", "BPM_C04-01"]] + assert bpm_forward_plural.names() == bpm_backward_plural.names() == bpm_forward.names() + + +@pytest.mark.parametrize( + "select", + [ + pytest.param(lambda h, k: h[k].names(), id="holder[]"), + pytest.param(lambda h, k: h.find_elements(k), id="holder.find_elements"), + pytest.param(lambda h, k: h.get()[k].names(), id="holder.get()[]"), + pytest.param(lambda h, k: h.magnet[k].names(), id="holder.magnet[]"), + pytest.param(lambda h, k: h.magnets[k].names(), id="holder.magnets[]"), + ], +) +@pytest.mark.parametrize("reverse", [False, True], ids=["forward", "reversed"]) +@pytest.mark.parametrize( + "key, expected_members", + [ + pytest.param( + ["SH1A-C01-H", "SH1A-C01-V", "SH1A-C02-H"], + {"SH1A-C01-H", "SH1A-C01-V", "SH1A-C02-H"}, + id="literal-names", + ), + pytest.param( + ["SH1A-C0?-H", "SH1A-C01-V"], + {"SH1A-C01-H", "SH1A-C02-H", "SH1A-C01-V"}, + id="wildcard-and-literal", + ), + ], +) +def test_every_accessor_returns_a_list_selection_in_configuration_order(holder, select, reverse, key, expected_members): + """Every name-based accessor must return a list-of-patterns selection in configuration + order, whatever the order of the requested names/patterns, so that positional values line + up the same way whichever accessor built the array. This must hold both for a list of + literal names and for a list mixing a wildcard (matching several names) with a literal + name, since a wildcard entry is where a naive pattern-order passthrough diverges from + configuration order the most visibly.""" + expected = [n for n in holder.get().names() if n in expected_members] + assert select(holder, key[::-1] if reverse else key) == expected + + +def test_subtracting_a_magnet_selection_from_a_mixed_selection_yields_a_cfm_array(holder): + """A top-level selection mixing CombinedFunctionMagnet and their virtual correctors, minus + the corrector-only .magnets selection, must yield the CFMs alone as a + CombinedFunctionMagnetArray. Regression test: this used to raise 'Aggregator not + implemented for CombinedFunctionMagnetArray' because the derived array blindly inherited + the use_aggregator flag of the ElementArray it was built from.""" + mixed = holder["SH*"] + only_magnets = holder.magnets["SH*"] + only_cfm = mixed - only_magnets + + assert type(only_cfm) is CombinedFunctionMagnetArray + assert only_cfm.names() == ["SH1A-C01", "SH1A-C02"] + + +def test_magnet_holder_getitem_regex(holder): + matching = holder.magnet["re:^SH1A-C0[12]-H$"] + assert sorted(matching.names()) == ["SH1A-C01-H", "SH1A-C02-H"] + + +def test_combined_function_magnet_holder_getitem_exact_name_matches_get(holder): + assert holder.combined_function_magnet["SH1A-C01"] is holder.combined_function_magnet.get("SH1A-C01") + + +def test_combined_function_magnet_holder_getitem_exact_name_miss_raises(holder): + with pytest.raises(PyAMLException): + holder.combined_function_magnet["UNKNOWN"] + + +def test_serialized_magnet_holder_getitem_exact_name_matches_get(serialized_holder): + assert serialized_holder.serialized_magnet["mySeriesOfMagnets"] is serialized_holder.serialized_magnet.get( + "mySeriesOfMagnets" + ) + + +def test_serialized_magnet_holder_getitem_exact_name_miss_raises(serialized_holder): + with pytest.raises(PyAMLException): + serialized_holder.serialized_magnet["UNKNOWN"] diff --git a/tests/common/test_element_holder_collection.py b/tests/common/test_element_holder_collection.py index 937d2da79..01585cf9f 100644 --- a/tests/common/test_element_holder_collection.py +++ b/tests/common/test_element_holder_collection.py @@ -3,8 +3,8 @@ from pyaml.arrays.bpm_array import BPMArray from pyaml.arrays.element_array import ElementArray from pyaml.arrays.magnet_array import MagnetArray -from pyaml.bpm.bpm import BPM from pyaml.common.exception import PyAMLException +from pyaml.diagnostics.bpm.bpm import BPM from pyaml.lattice.simulator import Simulator @@ -15,13 +15,14 @@ def holder(accelerator_from_fragments, sr_configuration_fragments): return sr.design -def test_exact_name_returns_the_element_or_none(holder): - assert holder["BPM_C04-01"] is holder.bpm.get("BPM_C04-01") - assert holder["UNKNOWN"] is None +def test_exact_name_returns_the_element_or_raises(holder): + assert holder["BPM_C04-01"] is holder.diagnostic.bpm.get("BPM_C04-01") + with pytest.raises(PyAMLException): + holder["UNKNOWN"] def test_get_and_full_slice_keep_registration_order(holder): - names = [element.get_name() for element in holder.get_all_elements()] + names = [element.get_name() for element in holder.get()] assert type(holder.get()) is ElementArray assert type(holder[:]) is ElementArray @@ -47,7 +48,7 @@ def test_new_calls_reflect_registry_additions(holder): assert "EXTRA_BPM" not in previous.names() assert holder.get().names() == previous.names() + ["EXTRA_BPM"] - assert holder["EXTRA_BPM"] is holder.bpm.get("EXTRA_BPM") + assert holder["EXTRA_BPM"] is holder.diagnostic.bpm.get("EXTRA_BPM") def test_patterns_always_return_arrays(holder): @@ -70,7 +71,7 @@ def test_character_classes_in_name_patterns(holder): def test_colons_are_part_of_names(holder): holder.fill_device([BPM("CELL04:BPM01", lattice_names="list(BPM_C04-01)")]) - assert holder["CELL04:BPM01"] is holder.bpm.get("CELL04:BPM01") + assert holder["CELL04:BPM01"] is holder.diagnostic.bpm.get("CELL04:BPM01") assert holder["CELL04:BPM*"].names() == ["CELL04:BPM01"] assert holder["model_name:*"].names() == [] @@ -78,7 +79,7 @@ def test_colons_are_part_of_names(holder): def test_magnet_subclasses_share_a_typed_array_in_either_order(holder): horizontal = holder.magnet.get("SH1A-C01-H") vertical = holder.magnet.get("SH1A-C01-V") - start = holder.get_all_elements().index(horizontal) + start = holder.get().index(horizontal) assert type(horizontal) is not type(vertical) assert isinstance(holder["SH1A-C01-[HV]"], MagnetArray) @@ -96,7 +97,7 @@ def test_mixed_selection_returns_a_generic_array(holder): def test_indices_and_slices_follow_insertion_order(holder): - registered = holder.get_all_elements() + registered = holder.get() assert holder[0] is registered[0] assert holder[-1] is registered[-1] @@ -113,11 +114,12 @@ def test_empty_holder_returns_empty_collections(ebs_lattice_file): assert type(holder.get()) is ElementArray assert holder[:].names() == [] assert holder["BPM*"].names() == [] - assert holder["BPM_C04-01"] is None + with pytest.raises(PyAMLException): + holder["BPM_C04-01"] def test_invalid_indices_and_keys_raise_clear_errors(holder): - size = len(holder.get_all_elements()) + size = len(holder.get()) with pytest.raises(IndexError): holder[size] @@ -130,14 +132,21 @@ def test_invalid_indices_and_keys_raise_clear_errors(holder): def test_selection_intersects_with_a_configured_family(holder): - selected = holder["SH1A-C0?-H"] & holder.get_elements("ElArray") + selected = holder["SH1A-C0?-H"] & holder.get("ElArray") assert isinstance(selected, MagnetArray) assert selected.names() == ["SH1A-C02-H"] - assert holder.get_element("SH1A-C02-H") is holder["SH1A-C02-H"] - assert holder.get_all_elements() == list(holder.get()) + + +def test_get_resolves_a_named_array_regardless_of_its_concrete_family(holder): + """`get(name)` must not be limited to generic element arrays, unlike the old `get_elements`.""" + assert isinstance(holder.get("HCORR"), MagnetArray) + assert holder.get("HCORR").names() == ["SH1A-C01-H", "SH1A-C02-H"] + assert isinstance(holder.get("BPMS"), BPMArray) + assert holder.get("BPMS").names() == ["BPM_C04-01", "BPM_C04-02"] + assert holder.get("ElArray").names() == ["BPM_C04-01", "BPM_C04-02", "SH1A-C01-V", "SH1A-C02-H"] with pytest.raises(PyAMLException): - holder.get_element("UNKNOWN") + holder.get("UNKNOWN") def test_existing_array_field_filters_still_work(holder): @@ -148,3 +157,130 @@ def test_existing_array_field_filters_still_work(holder): def test_existing_empty_intersection_stays_a_list(holder): assert type(holder["SH1A-C0?-H"] & holder["SH1A-C0?-V"]) is list + + +def test_intersecting_two_wildcard_selections(holder): + """Two overlapping wildcard selections combined with `&` narrow down to their overlap.""" + by_cell = holder["SH1A-C01*"] # SH1A-C01-H, SH1A-C01-V, SH1A-C01-SQ + by_plane = holder["SH1A-C0?-H"] # SH1A-C01-H, SH1A-C02-H + + selected = by_cell & by_plane + + assert isinstance(selected, MagnetArray) + assert selected.names() == ["SH1A-C01-H"] + + +def test_union_of_a_list_selection_and_a_wildcard_selection(holder): + """A list-of-patterns selection and a wildcard selection combine with `|` like any array.""" + cell_01 = holder[["SH1A-C01-H", "SH1A-C01-V"]] + cell_02 = holder["SH1A-C02*"] # the CFM magnet SH1A-C02, plus its -H, -V, -SQ sub-magnets + + combined = cell_01 | cell_02 + + # Mixes a CombinedFunctionMagnet (SH1A-C02) with plain Magnets, so the union + # stays a generic ElementArray rather than a MagnetArray. + assert type(combined) is ElementArray + assert sorted(combined.names()) == [ + "SH1A-C01-H", + "SH1A-C01-V", + "SH1A-C02", + "SH1A-C02-H", + "SH1A-C02-SQ", + "SH1A-C02-V", + ] + + +def test_difference_with_a_regex_selection(holder): + """`-` removes a `re:` selection's matches from a wildcard selection, like any array.""" + both_planes_h = holder["SH1A-C0?-H"] # SH1A-C01-H, SH1A-C02-H + cell_01_h = holder["re:^SH1A-C01-H$"] + + selected = both_planes_h - cell_01_h + + assert isinstance(selected, MagnetArray) + assert selected.names() == ["SH1A-C02-H"] + + +def test_disjoint_regex_and_list_selections_produce_a_plain_list(holder): + """The same empty-result-is-a-plain-list quirk applies to the new selection styles too.""" + cell_01_h = holder["re:^SH1A-C01-H$"] + cell_02_h_v = holder[["SH1A-C02-H", "SH1A-C02-V"]] + + assert type(cell_01_h & cell_02_h_v) is list + + +def test_selection_combined_with_a_configured_family_via_regex_and_list(holder): + """`re:` and list-of-patterns selections intersect with a configured family, same as wildcards.""" + el_array = holder.get("ElArray") # BPM_C04-01, BPM_C04-02, SH1A-C01-V, SH1A-C02-H + + by_regex = holder["re:^SH1A-C0[12]-H$"] & el_array + assert isinstance(by_regex, MagnetArray) + assert by_regex.names() == ["SH1A-C02-H"] + + by_list = holder[["BPM_C04-01", "BPM_C04-02"]] & el_array + assert isinstance(by_list, BPMArray) + assert by_list.names() == ["BPM_C04-01", "BPM_C04-02"] + + +def test_regex_pattern_is_supported(holder): + assert holder["re:^BPM_C04-0[12]$"].names() == ["BPM_C04-01", "BPM_C04-02"] + assert holder["re:^NOTHING$"].names() == [] + + +def test_invalid_regex_raises_pyaml_exception(holder): + with pytest.raises(PyAMLException, match="Invalid regex"): + holder["re:("] + + +def test_list_of_patterns_unions_results(holder): + """Order follows configuration (registration) order, not the order patterns were requested in.""" + selected = holder[["BPM_C04-01", "SH1A-C0?-H"]] + assert selected.names() == ["SH1A-C01-H", "SH1A-C02-H", "BPM_C04-01"] + + +def test_list_of_patterns_with_missing_literal_raises(holder): + with pytest.raises(PyAMLException): + holder[["BPM_C04-01", "UNKNOWN"]] + + +def test_wildcard_matching_is_case_sensitive(holder): + assert holder["bpm_c04*"].names() == [] + + +def test_find_elements_literal_miss_raises(holder): + with pytest.raises(PyAMLException): + holder.find_elements("UNKNOWN") + + +def test_find_elements_bracket_only_pattern_is_a_wildcard(holder): + assert holder.find_elements("BPM_C04-0[12]") == ["BPM_C04-01", "BPM_C04-02"] + + +def test_find_elements_supports_regex(holder): + assert holder.find_elements("re:^BPM_C04-0[12]$") == ["BPM_C04-01", "BPM_C04-02"] + + +def test_find_elements_supports_a_list_of_patterns(holder): + """Order follows configuration (registration) order, not the order patterns were requested in.""" + assert holder.find_elements(["BPM_C04-01", "SH1A-C0?-H"]) == ["SH1A-C01-H", "SH1A-C02-H", "BPM_C04-01"] + + +def test_find_elements_supports_an_exclusion_in_a_list(holder): + both_planes = holder.find_elements(["SH1A-C0?-H", "SH1A-C0?-V"]) + assert both_planes == ["SH1A-C01-H", "SH1A-C01-V", "SH1A-C02-H", "SH1A-C02-V"] + + minus_one = holder.find_elements(["SH1A-C0?-H", "SH1A-C0?-V", "~SH1A-C02-V"]) + assert minus_one == ["SH1A-C01-H", "SH1A-C01-V", "SH1A-C02-H"] + + +def test_getitem_supports_an_exclusion_in_a_list(holder): + selected = holder[["SH1A-C0?-H", "SH1A-C0?-V", "~SH1A-C02-V"]] + assert selected.names() == ["SH1A-C01-H", "SH1A-C01-V", "SH1A-C02-H"] + + +def test_getitem_lone_exclusion_pattern_means_everything_except(holder): + all_names = holder.get() + selected = holder["~QF1A-C01"] + + assert "QF1A-C01" not in selected.names() + assert len(selected) == len(all_names) - 1 diff --git a/tests/common/test_errors.py b/tests/common/test_errors.py index 38ce79f56..ec7496df8 100644 --- a/tests/common/test_errors.py +++ b/tests/common/test_errors.py @@ -43,24 +43,24 @@ def test_tune(install_test_package): assert "Magnet QF1A-C05XX not defined" in str(exc.value) with pytest.raises(PyAMLException) as exc: - m2 = sr.design.bpm.get("QF1A-C05XX") + m2 = sr.design.diagnostic.bpm.get("QF1A-C05XX") assert "BPM QF1A-C05XX not defined" in str(exc.value) def test_duplicate_error_reports_source_line_and_column_across_files(tmp_path): devices_a = tmp_path / "devices_a.yaml" devices_a.write_text( - "- type: pyaml.bpm.bpm\n name: BPM_DUPLICATE\n", + "- type: pyaml.diagnostics.bpm.bpm\n name: BPM_DUPLICATE\n", encoding="utf-8", ) devices_b = tmp_path / "devices_b.yaml" devices_b.write_text( - "- type: pyaml.bpm.bpm\n name: BPM_UNIQUE\n- type: pyaml.bpm.bpm\n name: BPM_DUPLICATE\n", + "- type: pyaml.diagnostics.bpm.bpm\n name: BPM_UNIQUE\n- type: pyaml.diagnostics.bpm.bpm\n name: BPM_DUPLICATE\n", encoding="utf-8", ) root = tmp_path / "root.yaml" root.write_text( - "type: pyaml.accelerator\ndevices:\n - devices_a.yaml\n - devices_b.yaml\n", + "type: pyaml.accelerator\ndevices:\n - ${include:devices_a.yaml}\n - ${include:devices_b.yaml}\n", encoding="utf-8", ) @@ -76,7 +76,7 @@ def test_duplicate_error_reports_source_line_and_column_across_files(tmp_path): def test_malformed_local_included_yaml_reports_source_line_and_column(tmp_path): broken_devices = tmp_path / "broken_devices.yaml" broken_devices.write_text( - "- type: pyaml.bpm.bpm\n name: BPM_BROKEN\n model:\n type: [oops\n", + "- type: pyaml.diagnostics.bpm.bpm\n name: BPM_BROKEN\n model:\n type: [oops\n", encoding="utf-8", ) root = tmp_path / "root.yaml" @@ -86,7 +86,7 @@ def test_malformed_local_included_yaml_reports_source_line_and_column(tmp_path): "machine: sr\n" "energy: 6e9\n" "data_folder: /data/store\n" - "devices: broken_devices.yaml\n", + "devices: ${include:broken_devices.yaml}\n", encoding="utf-8", ) @@ -101,7 +101,7 @@ def test_malformed_local_included_yaml_reports_source_line_and_column(tmp_path): def test_truncated_local_included_json_reports_source_and_position(tmp_path): broken_devices = tmp_path / "broken_devices.json" broken_devices.write_text( - '{"type": "pyaml.bpm.bpm", "name": "BPM_BROKEN", "model": ', + '{"type": "pyaml.diagnostics.bpm.bpm", "name": "BPM_BROKEN", "model": ', encoding="utf-8", ) root = tmp_path / "root.yaml" @@ -111,7 +111,7 @@ def test_truncated_local_included_json_reports_source_and_position(tmp_path): "machine: sr\n" "energy: 6e9\n" "data_folder: /data/store\n" - "devices: broken_devices.json\n", + "devices: ${include:broken_devices.json}\n", encoding="utf-8", ) @@ -131,9 +131,11 @@ def test_malformed_remote_included_yaml_reports_source_line_and_column(http_conf "machine: sr\n" "energy: 6000000000.0\n" "data_folder: /data/store\n" - "devices: fragments/broken_devices.yaml\n" + "devices: ${include:fragments/broken_devices.yaml}\n" + ), + "/configs/fragments/broken_devices.yaml": ( + "- type: pyaml.diagnostics.bpm.bpm\n name: BPM_BROKEN\n model:\n type: [oops\n" ), - "/configs/fragments/broken_devices.yaml": ("- type: pyaml.bpm.bpm\n name: BPM_BROKEN\n model:\n type: [oops\n"), } with http_config_server(routes) as base_url: @@ -153,10 +155,10 @@ def test_truncated_remote_included_json_reports_source_and_position(http_config_ "machine: sr\n" "energy: 6000000000.0\n" "data_folder: /data/store\n" - "devices: fragments/broken_devices.json\n" + "devices: ${include:fragments/broken_devices.json}\n" ), "/configs/fragments/broken_devices.json": ( - '{"type": "pyaml.bpm.bpm", "name": "BPM_BROKEN", "model": ', + '{"type": "pyaml.diagnostics.bpm.bpm", "name": "BPM_BROKEN", "model": ', "application/json", 200, ), diff --git a/tests/common/test_name_matching.py b/tests/common/test_name_matching.py new file mode 100644 index 000000000..c73658625 --- /dev/null +++ b/tests/common/test_name_matching.py @@ -0,0 +1,114 @@ +import pytest + +from pyaml.common.exception import PyAMLException +from pyaml.common.name_matching import is_wildcard, resolve_names + +NAMES = ["BPM_C04-01", "BPM_C04-02", "QF1A-C01", "QF1A-C02"] + + +def test_is_wildcard_triggers_on_star_question_and_bracket(): + assert is_wildcard("BPM*") + assert is_wildcard("BPM?") + assert is_wildcard("BPM[01]") + assert not is_wildcard("BPM_C04-01") + assert not is_wildcard("re:^BPM") + + +def test_literal_hit_returns_the_single_name(): + assert resolve_names(NAMES, "QF1A-C01") == ["QF1A-C01"] + + +def test_literal_miss_raises(): + with pytest.raises(PyAMLException, match="Element UNKNOWN not defined"): + resolve_names(NAMES, "UNKNOWN") + + +def test_literal_miss_uses_the_provided_what_label(): + with pytest.raises(PyAMLException, match="Magnet UNKNOWN not defined"): + resolve_names(NAMES, "UNKNOWN", what="Magnet") + + +def test_wildcard_hit_and_empty_are_not_errors(): + assert resolve_names(NAMES, "BPM*") == ["BPM_C04-01", "BPM_C04-02"] + assert resolve_names(NAMES, "MISSING*") == [] + + +def test_wildcard_is_case_sensitive(): + assert resolve_names(NAMES, "bpm*") == [] + + +def test_bracket_only_pattern_is_a_wildcard_not_a_literal(): + assert resolve_names(NAMES, "QF1A-C0[12]") == ["QF1A-C01", "QF1A-C02"] + + +def test_regex_hit_and_empty_are_not_errors(): + assert resolve_names(NAMES, "re:^BPM_C04-0[12]$") == ["BPM_C04-01", "BPM_C04-02"] + assert resolve_names(NAMES, "re:^NOTHING$") == [] + + +def test_regex_is_a_fullmatch(): + assert resolve_names(NAMES, "re:BPM_C04") == [] + + +def test_invalid_regex_raises_pyaml_exception_not_re_error(): + with pytest.raises(PyAMLException, match="Invalid regex"): + resolve_names(NAMES, "re:(") + + +def test_list_of_patterns_unions_and_deduplicates_in_order(): + result = resolve_names(NAMES, ["QF1A-C01", "BPM*", "QF1A-C01"]) + assert result == ["QF1A-C01", "BPM_C04-01", "BPM_C04-02"] + + +def test_tuple_of_patterns_is_also_accepted(): + assert resolve_names(NAMES, ("QF1A-C01", "QF1A-C02")) == ["QF1A-C01", "QF1A-C02"] + + +def test_list_with_one_missing_literal_raises(): + with pytest.raises(PyAMLException, match="Element UNKNOWN not defined"): + resolve_names(NAMES, ["QF1A-C01", "UNKNOWN"]) + + +def test_list_mixing_literal_wildcard_and_regex(): + result = resolve_names(NAMES, ["QF1A-C01", "BPM*", "re:^QF1A-C02$"]) + assert result == ["QF1A-C01", "BPM_C04-01", "BPM_C04-02", "QF1A-C02"] + + +def test_overlapping_wildcard_patterns_in_a_list_do_not_duplicate_a_match(): + names = ["BPM_01", "BPM_02", "BPM_03", "BPM_04", "BPM_05"] + result = resolve_names(names, ["BPM_0[1-3]", "BPM_0[3-5]"]) + assert result == ["BPM_01", "BPM_02", "BPM_03", "BPM_04", "BPM_05"] + + +def test_lone_exclusion_pattern_means_everything_except(): + assert resolve_names(NAMES, "~QF1A-C01") == ["BPM_C04-01", "BPM_C04-02", "QF1A-C02"] + + +def test_list_of_only_exclusion_patterns_means_everything_except(): + result = resolve_names(NAMES, ["~QF1A-C01", "~QF1A-C02"]) + assert result == ["BPM_C04-01", "BPM_C04-02"] + + +def test_exclusion_removes_matches_from_an_inclusion_pattern(): + assert resolve_names(NAMES, ["BPM*", "~BPM_C04-01"]) == ["BPM_C04-02"] + + +def test_exclusion_order_does_not_matter(): + forward = resolve_names(NAMES, ["BPM*", "~BPM_C04-01"]) + backward = resolve_names(NAMES, ["~BPM_C04-01", "BPM*"]) + assert forward == backward == ["BPM_C04-02"] + + +def test_exclusion_of_a_wildcard_pattern_removes_all_its_matches(): + result = resolve_names(NAMES, ["QF1A-C01", "QF1A-C02", "BPM_C04-01", "~QF1A-*"]) + assert result == ["BPM_C04-01"] + + +def test_exclusion_of_a_regex_pattern_removes_all_its_matches(): + result = resolve_names(NAMES, ["BPM*", "~re:^BPM_C04-01$"]) + assert result == ["BPM_C04-02"] + + +def test_exclusion_of_a_missing_literal_raises(): + with pytest.raises(PyAMLException, match="Element UNKNOWN not defined"): + resolve_names(NAMES, ["BPM*", "~UNKNOWN"]) diff --git a/tests/config/EBSNames-linker.yaml b/tests/config/EBSNames-linker.yaml new file mode 100644 index 000000000..e322320e1 --- /dev/null +++ b/tests/config/EBSNames-linker.yaml @@ -0,0 +1,95 @@ +type: pyaml.accelerator +facility: ESRF +machine: sr +energy: 6e9 +simulators: + - type: pyaml.lattice.simulator + lattice: sr/lattices/ebs-original-names.mat + name: design + linker: + type: pyaml.lattice.attribute_linker + attribute_name: FamName # equivalent to the default linker +controls: + - type: tango.pyaml.controlsystem + tango_host: ebs-simu-3:10000 + name: live + catalog: ${include:catalogs/ebs_catalogs.yaml} +data_folder: /data/store +devices: +- type: pyaml.magnet.quadrupole + name: QF1E + model: + type: pyaml.magnet.linear_model + calibration_factor: 1.00054 + crosstalk: 1.0 + curve: + type: pyaml.magnet.csvcurve + file: sr/magnet_models/QF1_strength.csv + unit: 1/m + hardware_unit: A + powerconverter: srmag/vps-qf1/c04-e/current +- type: pyaml.magnet.quadrupole + name: QF1E-ALL + lattice_names: list(QF1E,QF1I) + model: + type: pyaml.magnet.linear_model + calibration_factor: 1.00054 + crosstalk: 1.0 + curve: + type: pyaml.magnet.csvcurve + file: sr/magnet_models/QF1_strength.csv + unit: 1/m + hardware_unit: A + powerconverter: srmag/vps-qf1/c04-e/current +- type: pyaml.magnet.quadrupole + name: QF1E-C05 + lattice_names: QF1E@1 + model: + type: pyaml.magnet.linear_model + calibration_factor: 0.996841 + crosstalk: 1.0 + curve: + type: pyaml.magnet.csvcurve + file: sr/magnet_models/QF1_strength.csv + unit: 1/m + hardware_unit: A + powerconverter: srmag/vps-qf1/c05-a/current +- type: pyaml.magnet.quadrupole + name: QF1E-C04-C05-C06 + lattice_names: QF1E@0,1,2 + model: + type: pyaml.magnet.linear_model + calibration_factor: 1.00191 + crosstalk: 1.0 + curve: + type: pyaml.magnet.csvcurve + file: sr/magnet_models/QF1_strength.csv + unit: 1/m + hardware_unit: A + powerconverter: srmag/vps-qf1/c05-e/current +- type: pyaml.magnet.quadrupole + name: QF1E-C04-C05-C06-2 + lattice_names: "@140,290,424" + model: + type: pyaml.magnet.linear_model + calibration_factor: 1.00191 + crosstalk: 1.0 + curve: + type: pyaml.magnet.csvcurve + file: sr/magnet_models/QF1_strength.csv + unit: 1/m + hardware_unit: A + powerconverter: srmag/vps-qf1/c05-e/current +- type: pyaml.magnet.quadrupole + name: QF1E-C04-C05-C06-3 + lattice_names: QF1E#0..3 + model: + type: pyaml.magnet.linear_model + calibration_factor: 1.00191 + crosstalk: 1.0 + curve: + type: pyaml.magnet.csvcurve + file: sr/magnet_models/QF1_strength.csv + unit: 1/m + hardware_unit: A + powerconverter: srmag/vps-qf1/c05-e/current diff --git a/tests/config/EBSNames.yaml b/tests/config/EBSNames.yaml index b0eee6afc..cde710651 100644 --- a/tests/config/EBSNames.yaml +++ b/tests/config/EBSNames.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.magnet.quadrupole diff --git a/tests/config/EBSOrbit.yaml b/tests/config/EBSOrbit.yaml index 5d6ea2570..c77128006 100644 --- a/tests/config/EBSOrbit.yaml +++ b/tests/config/EBSOrbit.yaml @@ -11,7 +11,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet @@ -5713,1285 +5713,1285 @@ devices: - srmag/ps-corr-sh3/c03-e-ch3/current - srmag/ps-corr-sh3/c03-e-ch5/current - srmag/ps-corr-sh3/c03-e-ch6/current -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-01 x_pos: srdiag/bpm/c04-01/SA_HPosition y_pos: srdiag/bpm/c04-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-02 x_pos: srdiag/bpm/c04-02/SA_HPosition y_pos: srdiag/bpm/c04-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-03 x_pos: srdiag/bpm/c04-03/SA_HPosition y_pos: srdiag/bpm/c04-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-04 x_pos: srdiag/bpm/c04-04/SA_HPosition y_pos: srdiag/bpm/c04-04/SA_VPosition x_offset: srdiag/bpm/c04-04/HOffset y_offset: srdiag/bpm/c04-04/VOffset -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-05 x_pos: srdiag/bpm/c04-05/SA_HPosition y_pos: srdiag/bpm/c04-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-06 x_pos: srdiag/bpm/c04-06/SA_HPosition y_pos: srdiag/bpm/c04-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-07 x_pos: srdiag/bpm/c04-07/SA_HPosition y_pos: srdiag/bpm/c04-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-08 x_pos: srdiag/bpm/c04-08/SA_HPosition y_pos: srdiag/bpm/c04-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-09 x_pos: srdiag/bpm/c04-09/SA_HPosition y_pos: srdiag/bpm/c04-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-10 x_pos: srdiag/bpm/c04-10/SA_HPosition y_pos: srdiag/bpm/c04-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-01 x_pos: srdiag/bpm/c05-01/SA_HPosition y_pos: srdiag/bpm/c05-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-02 x_pos: srdiag/bpm/c05-02/SA_HPosition y_pos: srdiag/bpm/c05-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-03 x_pos: srdiag/bpm/c05-03/SA_HPosition y_pos: srdiag/bpm/c05-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-04 x_pos: srdiag/bpm/c05-04/SA_HPosition y_pos: srdiag/bpm/c05-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-05 x_pos: srdiag/bpm/c05-05/SA_HPosition y_pos: srdiag/bpm/c05-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-06 x_pos: srdiag/bpm/c05-06/SA_HPosition y_pos: srdiag/bpm/c05-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-07 x_pos: srdiag/bpm/c05-07/SA_HPosition y_pos: srdiag/bpm/c05-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-08 x_pos: srdiag/bpm/c05-08/SA_HPosition y_pos: srdiag/bpm/c05-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-09 x_pos: srdiag/bpm/c05-09/SA_HPosition y_pos: srdiag/bpm/c05-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C05-10 x_pos: srdiag/bpm/c05-10/SA_HPosition y_pos: srdiag/bpm/c05-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-01 x_pos: srdiag/bpm/c06-01/SA_HPosition y_pos: srdiag/bpm/c06-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-02 x_pos: srdiag/bpm/c06-02/SA_HPosition y_pos: srdiag/bpm/c06-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-03 x_pos: srdiag/bpm/c06-03/SA_HPosition y_pos: srdiag/bpm/c06-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-04 x_pos: srdiag/bpm/c06-04/SA_HPosition y_pos: srdiag/bpm/c06-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-05 x_pos: srdiag/bpm/c06-05/SA_HPosition y_pos: srdiag/bpm/c06-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-06 x_pos: srdiag/bpm/c06-06/SA_HPosition y_pos: srdiag/bpm/c06-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-07 x_pos: srdiag/bpm/c06-07/SA_HPosition y_pos: srdiag/bpm/c06-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-08 x_pos: srdiag/bpm/c06-08/SA_HPosition y_pos: srdiag/bpm/c06-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-09 x_pos: srdiag/bpm/c06-09/SA_HPosition y_pos: srdiag/bpm/c06-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C06-10 x_pos: srdiag/bpm/c06-10/SA_HPosition y_pos: srdiag/bpm/c06-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-01 x_pos: srdiag/bpm/c07-01/SA_HPosition y_pos: srdiag/bpm/c07-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-02 x_pos: srdiag/bpm/c07-02/SA_HPosition y_pos: srdiag/bpm/c07-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-03 x_pos: srdiag/bpm/c07-03/SA_HPosition y_pos: srdiag/bpm/c07-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-04 x_pos: srdiag/bpm/c07-04/SA_HPosition y_pos: srdiag/bpm/c07-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-05 x_pos: srdiag/bpm/c07-05/SA_HPosition y_pos: srdiag/bpm/c07-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-06 x_pos: srdiag/bpm/c07-06/SA_HPosition y_pos: srdiag/bpm/c07-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-07 x_pos: srdiag/bpm/c07-07/SA_HPosition y_pos: srdiag/bpm/c07-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-08 x_pos: srdiag/bpm/c07-08/SA_HPosition y_pos: srdiag/bpm/c07-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-09 x_pos: srdiag/bpm/c07-09/SA_HPosition y_pos: srdiag/bpm/c07-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C07-10 x_pos: srdiag/bpm/c07-10/SA_HPosition y_pos: srdiag/bpm/c07-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-01 x_pos: srdiag/bpm/c08-01/SA_HPosition y_pos: srdiag/bpm/c08-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-02 x_pos: srdiag/bpm/c08-02/SA_HPosition y_pos: srdiag/bpm/c08-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-03 x_pos: srdiag/bpm/c08-03/SA_HPosition y_pos: srdiag/bpm/c08-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-04 x_pos: srdiag/bpm/c08-04/SA_HPosition y_pos: srdiag/bpm/c08-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-05 x_pos: srdiag/bpm/c08-05/SA_HPosition y_pos: srdiag/bpm/c08-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-06 x_pos: srdiag/bpm/c08-06/SA_HPosition y_pos: srdiag/bpm/c08-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-07 x_pos: srdiag/bpm/c08-07/SA_HPosition y_pos: srdiag/bpm/c08-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-08 x_pos: srdiag/bpm/c08-08/SA_HPosition y_pos: srdiag/bpm/c08-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-09 x_pos: srdiag/bpm/c08-09/SA_HPosition y_pos: srdiag/bpm/c08-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C08-10 x_pos: srdiag/bpm/c08-10/SA_HPosition y_pos: srdiag/bpm/c08-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-01 x_pos: srdiag/bpm/c09-01/SA_HPosition y_pos: srdiag/bpm/c09-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-02 x_pos: srdiag/bpm/c09-02/SA_HPosition y_pos: srdiag/bpm/c09-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-03 x_pos: srdiag/bpm/c09-03/SA_HPosition y_pos: srdiag/bpm/c09-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-04 x_pos: srdiag/bpm/c09-04/SA_HPosition y_pos: srdiag/bpm/c09-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-05 x_pos: srdiag/bpm/c09-05/SA_HPosition y_pos: srdiag/bpm/c09-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-06 x_pos: srdiag/bpm/c09-06/SA_HPosition y_pos: srdiag/bpm/c09-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-07 x_pos: srdiag/bpm/c09-07/SA_HPosition y_pos: srdiag/bpm/c09-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-08 x_pos: srdiag/bpm/c09-08/SA_HPosition y_pos: srdiag/bpm/c09-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-09 x_pos: srdiag/bpm/c09-09/SA_HPosition y_pos: srdiag/bpm/c09-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C09-10 x_pos: srdiag/bpm/c09-10/SA_HPosition y_pos: srdiag/bpm/c09-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-01 x_pos: srdiag/bpm/c10-01/SA_HPosition y_pos: srdiag/bpm/c10-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-02 x_pos: srdiag/bpm/c10-02/SA_HPosition y_pos: srdiag/bpm/c10-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-03 x_pos: srdiag/bpm/c10-03/SA_HPosition y_pos: srdiag/bpm/c10-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-04 x_pos: srdiag/bpm/c10-04/SA_HPosition y_pos: srdiag/bpm/c10-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-05 x_pos: srdiag/bpm/c10-05/SA_HPosition y_pos: srdiag/bpm/c10-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-06 x_pos: srdiag/bpm/c10-06/SA_HPosition y_pos: srdiag/bpm/c10-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-07 x_pos: srdiag/bpm/c10-07/SA_HPosition y_pos: srdiag/bpm/c10-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-08 x_pos: srdiag/bpm/c10-08/SA_HPosition y_pos: srdiag/bpm/c10-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-09 x_pos: srdiag/bpm/c10-09/SA_HPosition y_pos: srdiag/bpm/c10-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C10-10 x_pos: srdiag/bpm/c10-10/SA_HPosition y_pos: srdiag/bpm/c10-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-01 x_pos: srdiag/bpm/c11-01/SA_HPosition y_pos: srdiag/bpm/c11-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-02 x_pos: srdiag/bpm/c11-02/SA_HPosition y_pos: srdiag/bpm/c11-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-03 x_pos: srdiag/bpm/c11-03/SA_HPosition y_pos: srdiag/bpm/c11-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-04 x_pos: srdiag/bpm/c11-04/SA_HPosition y_pos: srdiag/bpm/c11-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-05 x_pos: srdiag/bpm/c11-05/SA_HPosition y_pos: srdiag/bpm/c11-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-06 x_pos: srdiag/bpm/c11-06/SA_HPosition y_pos: srdiag/bpm/c11-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-07 x_pos: srdiag/bpm/c11-07/SA_HPosition y_pos: srdiag/bpm/c11-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-08 x_pos: srdiag/bpm/c11-08/SA_HPosition y_pos: srdiag/bpm/c11-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-09 x_pos: srdiag/bpm/c11-09/SA_HPosition y_pos: srdiag/bpm/c11-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C11-10 x_pos: srdiag/bpm/c11-10/SA_HPosition y_pos: srdiag/bpm/c11-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-01 x_pos: srdiag/bpm/c12-01/SA_HPosition y_pos: srdiag/bpm/c12-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-02 x_pos: srdiag/bpm/c12-02/SA_HPosition y_pos: srdiag/bpm/c12-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-03 x_pos: srdiag/bpm/c12-03/SA_HPosition y_pos: srdiag/bpm/c12-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-04 x_pos: srdiag/bpm/c12-04/SA_HPosition y_pos: srdiag/bpm/c12-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-05 x_pos: srdiag/bpm/c12-05/SA_HPosition y_pos: srdiag/bpm/c12-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-06 x_pos: srdiag/bpm/c12-06/SA_HPosition y_pos: srdiag/bpm/c12-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-07 x_pos: srdiag/bpm/c12-07/SA_HPosition y_pos: srdiag/bpm/c12-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-08 x_pos: srdiag/bpm/c12-08/SA_HPosition y_pos: srdiag/bpm/c12-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-09 x_pos: srdiag/bpm/c12-09/SA_HPosition y_pos: srdiag/bpm/c12-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C12-10 x_pos: srdiag/bpm/c12-10/SA_HPosition y_pos: srdiag/bpm/c12-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-01 x_pos: srdiag/bpm/c13-01/SA_HPosition y_pos: srdiag/bpm/c13-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-02 x_pos: srdiag/bpm/c13-02/SA_HPosition y_pos: srdiag/bpm/c13-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-03 x_pos: srdiag/bpm/c13-03/SA_HPosition y_pos: srdiag/bpm/c13-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-04 x_pos: srdiag/bpm/c13-04/SA_HPosition y_pos: srdiag/bpm/c13-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-05 x_pos: srdiag/bpm/c13-05/SA_HPosition y_pos: srdiag/bpm/c13-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-06 x_pos: srdiag/bpm/c13-06/SA_HPosition y_pos: srdiag/bpm/c13-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-07 x_pos: srdiag/bpm/c13-07/SA_HPosition y_pos: srdiag/bpm/c13-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-08 x_pos: srdiag/bpm/c13-08/SA_HPosition y_pos: srdiag/bpm/c13-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-09 x_pos: srdiag/bpm/c13-09/SA_HPosition y_pos: srdiag/bpm/c13-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C13-10 x_pos: srdiag/bpm/c13-10/SA_HPosition y_pos: srdiag/bpm/c13-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-01 x_pos: srdiag/bpm/c14-01/SA_HPosition y_pos: srdiag/bpm/c14-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-02 x_pos: srdiag/bpm/c14-02/SA_HPosition y_pos: srdiag/bpm/c14-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-03 x_pos: srdiag/bpm/c14-03/SA_HPosition y_pos: srdiag/bpm/c14-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-04 x_pos: srdiag/bpm/c14-04/SA_HPosition y_pos: srdiag/bpm/c14-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-05 x_pos: srdiag/bpm/c14-05/SA_HPosition y_pos: srdiag/bpm/c14-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-06 x_pos: srdiag/bpm/c14-06/SA_HPosition y_pos: srdiag/bpm/c14-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-07 x_pos: srdiag/bpm/c14-07/SA_HPosition y_pos: srdiag/bpm/c14-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-08 x_pos: srdiag/bpm/c14-08/SA_HPosition y_pos: srdiag/bpm/c14-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-09 x_pos: srdiag/bpm/c14-09/SA_HPosition y_pos: srdiag/bpm/c14-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C14-10 x_pos: srdiag/bpm/c14-10/SA_HPosition y_pos: srdiag/bpm/c14-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-01 x_pos: srdiag/bpm/c15-01/SA_HPosition y_pos: srdiag/bpm/c15-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-02 x_pos: srdiag/bpm/c15-02/SA_HPosition y_pos: srdiag/bpm/c15-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-03 x_pos: srdiag/bpm/c15-03/SA_HPosition y_pos: srdiag/bpm/c15-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-04 x_pos: srdiag/bpm/c15-04/SA_HPosition y_pos: srdiag/bpm/c15-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-05 x_pos: srdiag/bpm/c15-05/SA_HPosition y_pos: srdiag/bpm/c15-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-06 x_pos: srdiag/bpm/c15-06/SA_HPosition y_pos: srdiag/bpm/c15-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-07 x_pos: srdiag/bpm/c15-07/SA_HPosition y_pos: srdiag/bpm/c15-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-08 x_pos: srdiag/bpm/c15-08/SA_HPosition y_pos: srdiag/bpm/c15-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-09 x_pos: srdiag/bpm/c15-09/SA_HPosition y_pos: srdiag/bpm/c15-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C15-10 x_pos: srdiag/bpm/c15-10/SA_HPosition y_pos: srdiag/bpm/c15-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-01 x_pos: srdiag/bpm/c16-01/SA_HPosition y_pos: srdiag/bpm/c16-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-02 x_pos: srdiag/bpm/c16-02/SA_HPosition y_pos: srdiag/bpm/c16-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-03 x_pos: srdiag/bpm/c16-03/SA_HPosition y_pos: srdiag/bpm/c16-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-04 x_pos: srdiag/bpm/c16-04/SA_HPosition y_pos: srdiag/bpm/c16-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-05 x_pos: srdiag/bpm/c16-05/SA_HPosition y_pos: srdiag/bpm/c16-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-06 x_pos: srdiag/bpm/c16-06/SA_HPosition y_pos: srdiag/bpm/c16-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-07 x_pos: srdiag/bpm/c16-07/SA_HPosition y_pos: srdiag/bpm/c16-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-08 x_pos: srdiag/bpm/c16-08/SA_HPosition y_pos: srdiag/bpm/c16-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-09 x_pos: srdiag/bpm/c16-09/SA_HPosition y_pos: srdiag/bpm/c16-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C16-10 x_pos: srdiag/bpm/c16-10/SA_HPosition y_pos: srdiag/bpm/c16-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-01 x_pos: srdiag/bpm/c17-01/SA_HPosition y_pos: srdiag/bpm/c17-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-02 x_pos: srdiag/bpm/c17-02/SA_HPosition y_pos: srdiag/bpm/c17-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-03 x_pos: srdiag/bpm/c17-03/SA_HPosition y_pos: srdiag/bpm/c17-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-04 x_pos: srdiag/bpm/c17-04/SA_HPosition y_pos: srdiag/bpm/c17-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-05 x_pos: srdiag/bpm/c17-05/SA_HPosition y_pos: srdiag/bpm/c17-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-06 x_pos: srdiag/bpm/c17-06/SA_HPosition y_pos: srdiag/bpm/c17-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-07 x_pos: srdiag/bpm/c17-07/SA_HPosition y_pos: srdiag/bpm/c17-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-08 x_pos: srdiag/bpm/c17-08/SA_HPosition y_pos: srdiag/bpm/c17-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-09 x_pos: srdiag/bpm/c17-09/SA_HPosition y_pos: srdiag/bpm/c17-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C17-10 x_pos: srdiag/bpm/c17-10/SA_HPosition y_pos: srdiag/bpm/c17-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-01 x_pos: srdiag/bpm/c18-01/SA_HPosition y_pos: srdiag/bpm/c18-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-02 x_pos: srdiag/bpm/c18-02/SA_HPosition y_pos: srdiag/bpm/c18-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-03 x_pos: srdiag/bpm/c18-03/SA_HPosition y_pos: srdiag/bpm/c18-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-04 x_pos: srdiag/bpm/c18-04/SA_HPosition y_pos: srdiag/bpm/c18-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-05 x_pos: srdiag/bpm/c18-05/SA_HPosition y_pos: srdiag/bpm/c18-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-06 x_pos: srdiag/bpm/c18-06/SA_HPosition y_pos: srdiag/bpm/c18-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-07 x_pos: srdiag/bpm/c18-07/SA_HPosition y_pos: srdiag/bpm/c18-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-08 x_pos: srdiag/bpm/c18-08/SA_HPosition y_pos: srdiag/bpm/c18-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-09 x_pos: srdiag/bpm/c18-09/SA_HPosition y_pos: srdiag/bpm/c18-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C18-10 x_pos: srdiag/bpm/c18-10/SA_HPosition y_pos: srdiag/bpm/c18-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-01 x_pos: srdiag/bpm/c19-01/SA_HPosition y_pos: srdiag/bpm/c19-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-02 x_pos: srdiag/bpm/c19-02/SA_HPosition y_pos: srdiag/bpm/c19-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-03 x_pos: srdiag/bpm/c19-03/SA_HPosition y_pos: srdiag/bpm/c19-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-04 x_pos: srdiag/bpm/c19-04/SA_HPosition y_pos: srdiag/bpm/c19-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-05 x_pos: srdiag/bpm/c19-05/SA_HPosition y_pos: srdiag/bpm/c19-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-06 x_pos: srdiag/bpm/c19-06/SA_HPosition y_pos: srdiag/bpm/c19-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-07 x_pos: srdiag/bpm/c19-07/SA_HPosition y_pos: srdiag/bpm/c19-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-08 x_pos: srdiag/bpm/c19-08/SA_HPosition y_pos: srdiag/bpm/c19-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-09 x_pos: srdiag/bpm/c19-09/SA_HPosition y_pos: srdiag/bpm/c19-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C19-10 x_pos: srdiag/bpm/c19-10/SA_HPosition y_pos: srdiag/bpm/c19-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-01 x_pos: srdiag/bpm/c20-01/SA_HPosition y_pos: srdiag/bpm/c20-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-02 x_pos: srdiag/bpm/c20-02/SA_HPosition y_pos: srdiag/bpm/c20-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-03 x_pos: srdiag/bpm/c20-03/SA_HPosition y_pos: srdiag/bpm/c20-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-04 x_pos: srdiag/bpm/c20-04/SA_HPosition y_pos: srdiag/bpm/c20-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-05 x_pos: srdiag/bpm/c20-05/SA_HPosition y_pos: srdiag/bpm/c20-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-06 x_pos: srdiag/bpm/c20-06/SA_HPosition y_pos: srdiag/bpm/c20-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-07 x_pos: srdiag/bpm/c20-07/SA_HPosition y_pos: srdiag/bpm/c20-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-08 x_pos: srdiag/bpm/c20-08/SA_HPosition y_pos: srdiag/bpm/c20-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-09 x_pos: srdiag/bpm/c20-09/SA_HPosition y_pos: srdiag/bpm/c20-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C20-10 x_pos: srdiag/bpm/c20-10/SA_HPosition y_pos: srdiag/bpm/c20-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-01 x_pos: srdiag/bpm/c21-01/SA_HPosition y_pos: srdiag/bpm/c21-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-02 x_pos: srdiag/bpm/c21-02/SA_HPosition y_pos: srdiag/bpm/c21-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-03 x_pos: srdiag/bpm/c21-03/SA_HPosition y_pos: srdiag/bpm/c21-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-04 x_pos: srdiag/bpm/c21-04/SA_HPosition y_pos: srdiag/bpm/c21-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-05 x_pos: srdiag/bpm/c21-05/SA_HPosition y_pos: srdiag/bpm/c21-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-06 x_pos: srdiag/bpm/c21-06/SA_HPosition y_pos: srdiag/bpm/c21-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-07 x_pos: srdiag/bpm/c21-07/SA_HPosition y_pos: srdiag/bpm/c21-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-08 x_pos: srdiag/bpm/c21-08/SA_HPosition y_pos: srdiag/bpm/c21-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-09 x_pos: srdiag/bpm/c21-09/SA_HPosition y_pos: srdiag/bpm/c21-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C21-10 x_pos: srdiag/bpm/c21-10/SA_HPosition y_pos: srdiag/bpm/c21-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-01 x_pos: srdiag/bpm/c22-01/SA_HPosition y_pos: srdiag/bpm/c22-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-02 x_pos: srdiag/bpm/c22-02/SA_HPosition y_pos: srdiag/bpm/c22-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-03 x_pos: srdiag/bpm/c22-03/SA_HPosition y_pos: srdiag/bpm/c22-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-04 x_pos: srdiag/bpm/c22-04/SA_HPosition y_pos: srdiag/bpm/c22-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-05 x_pos: srdiag/bpm/c22-05/SA_HPosition y_pos: srdiag/bpm/c22-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-06 x_pos: srdiag/bpm/c22-06/SA_HPosition y_pos: srdiag/bpm/c22-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-07 x_pos: srdiag/bpm/c22-07/SA_HPosition y_pos: srdiag/bpm/c22-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-08 x_pos: srdiag/bpm/c22-08/SA_HPosition y_pos: srdiag/bpm/c22-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-09 x_pos: srdiag/bpm/c22-09/SA_HPosition y_pos: srdiag/bpm/c22-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C22-10 x_pos: srdiag/bpm/c22-10/SA_HPosition y_pos: srdiag/bpm/c22-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-01 x_pos: srdiag/bpm/c23-01/SA_HPosition y_pos: srdiag/bpm/c23-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-02 x_pos: srdiag/bpm/c23-02/SA_HPosition y_pos: srdiag/bpm/c23-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-03 x_pos: srdiag/bpm/c23-03/SA_HPosition y_pos: srdiag/bpm/c23-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-04 x_pos: srdiag/bpm/c23-04/SA_HPosition y_pos: srdiag/bpm/c23-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-05 x_pos: srdiag/bpm/c23-05/SA_HPosition y_pos: srdiag/bpm/c23-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-06 x_pos: srdiag/bpm/c23-06/SA_HPosition y_pos: srdiag/bpm/c23-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-07 x_pos: srdiag/bpm/c23-07/SA_HPosition y_pos: srdiag/bpm/c23-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-08 x_pos: srdiag/bpm/c23-08/SA_HPosition y_pos: srdiag/bpm/c23-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-09 x_pos: srdiag/bpm/c23-09/SA_HPosition y_pos: srdiag/bpm/c23-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C23-10 x_pos: srdiag/bpm/c23-10/SA_HPosition y_pos: srdiag/bpm/c23-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-01 x_pos: srdiag/bpm/c24-01/SA_HPosition y_pos: srdiag/bpm/c24-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-02 x_pos: srdiag/bpm/c24-02/SA_HPosition y_pos: srdiag/bpm/c24-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-03 x_pos: srdiag/bpm/c24-03/SA_HPosition y_pos: srdiag/bpm/c24-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-04 x_pos: srdiag/bpm/c24-04/SA_HPosition y_pos: srdiag/bpm/c24-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-05 x_pos: srdiag/bpm/c24-05/SA_HPosition y_pos: srdiag/bpm/c24-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-06 x_pos: srdiag/bpm/c24-06/SA_HPosition y_pos: srdiag/bpm/c24-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-07 x_pos: srdiag/bpm/c24-07/SA_HPosition y_pos: srdiag/bpm/c24-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-08 x_pos: srdiag/bpm/c24-08/SA_HPosition y_pos: srdiag/bpm/c24-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-09 x_pos: srdiag/bpm/c24-09/SA_HPosition y_pos: srdiag/bpm/c24-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C24-10 x_pos: srdiag/bpm/c24-10/SA_HPosition y_pos: srdiag/bpm/c24-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-01 x_pos: srdiag/bpm/c25-01/SA_HPosition y_pos: srdiag/bpm/c25-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-02 x_pos: srdiag/bpm/c25-02/SA_HPosition y_pos: srdiag/bpm/c25-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-03 x_pos: srdiag/bpm/c25-03/SA_HPosition y_pos: srdiag/bpm/c25-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-04 x_pos: srdiag/bpm/c25-04/SA_HPosition y_pos: srdiag/bpm/c25-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-05 x_pos: srdiag/bpm/c25-05/SA_HPosition y_pos: srdiag/bpm/c25-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-06 x_pos: srdiag/bpm/c25-06/SA_HPosition y_pos: srdiag/bpm/c25-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-07 x_pos: srdiag/bpm/c25-07/SA_HPosition y_pos: srdiag/bpm/c25-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-08 x_pos: srdiag/bpm/c25-08/SA_HPosition y_pos: srdiag/bpm/c25-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-09 x_pos: srdiag/bpm/c25-09/SA_HPosition y_pos: srdiag/bpm/c25-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C25-10 x_pos: srdiag/bpm/c25-10/SA_HPosition y_pos: srdiag/bpm/c25-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-01 x_pos: srdiag/bpm/c26-01/SA_HPosition y_pos: srdiag/bpm/c26-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-02 x_pos: srdiag/bpm/c26-02/SA_HPosition y_pos: srdiag/bpm/c26-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-03 x_pos: srdiag/bpm/c26-03/SA_HPosition y_pos: srdiag/bpm/c26-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-04 x_pos: srdiag/bpm/c26-04/SA_HPosition y_pos: srdiag/bpm/c26-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-05 x_pos: srdiag/bpm/c26-05/SA_HPosition y_pos: srdiag/bpm/c26-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-06 x_pos: srdiag/bpm/c26-06/SA_HPosition y_pos: srdiag/bpm/c26-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-07 x_pos: srdiag/bpm/c26-07/SA_HPosition y_pos: srdiag/bpm/c26-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-08 x_pos: srdiag/bpm/c26-08/SA_HPosition y_pos: srdiag/bpm/c26-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-09 x_pos: srdiag/bpm/c26-09/SA_HPosition y_pos: srdiag/bpm/c26-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C26-10 x_pos: srdiag/bpm/c26-10/SA_HPosition y_pos: srdiag/bpm/c26-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-01 x_pos: srdiag/bpm/c27-01/SA_HPosition y_pos: srdiag/bpm/c27-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-02 x_pos: srdiag/bpm/c27-02/SA_HPosition y_pos: srdiag/bpm/c27-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-03 x_pos: srdiag/bpm/c27-03/SA_HPosition y_pos: srdiag/bpm/c27-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-04 x_pos: srdiag/bpm/c27-04/SA_HPosition y_pos: srdiag/bpm/c27-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-05 x_pos: srdiag/bpm/c27-05/SA_HPosition y_pos: srdiag/bpm/c27-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-06 x_pos: srdiag/bpm/c27-06/SA_HPosition y_pos: srdiag/bpm/c27-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-07 x_pos: srdiag/bpm/c27-07/SA_HPosition y_pos: srdiag/bpm/c27-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-08 x_pos: srdiag/bpm/c27-08/SA_HPosition y_pos: srdiag/bpm/c27-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-09 x_pos: srdiag/bpm/c27-09/SA_HPosition y_pos: srdiag/bpm/c27-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C27-10 x_pos: srdiag/bpm/c27-10/SA_HPosition y_pos: srdiag/bpm/c27-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-01 x_pos: srdiag/bpm/c28-01/SA_HPosition y_pos: srdiag/bpm/c28-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-02 x_pos: srdiag/bpm/c28-02/SA_HPosition y_pos: srdiag/bpm/c28-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-03 x_pos: srdiag/bpm/c28-03/SA_HPosition y_pos: srdiag/bpm/c28-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-04 x_pos: srdiag/bpm/c28-04/SA_HPosition y_pos: srdiag/bpm/c28-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-05 x_pos: srdiag/bpm/c28-05/SA_HPosition y_pos: srdiag/bpm/c28-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-06 x_pos: srdiag/bpm/c28-06/SA_HPosition y_pos: srdiag/bpm/c28-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-07 x_pos: srdiag/bpm/c28-07/SA_HPosition y_pos: srdiag/bpm/c28-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-08 x_pos: srdiag/bpm/c28-08/SA_HPosition y_pos: srdiag/bpm/c28-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-09 x_pos: srdiag/bpm/c28-09/SA_HPosition y_pos: srdiag/bpm/c28-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C28-10 x_pos: srdiag/bpm/c28-10/SA_HPosition y_pos: srdiag/bpm/c28-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-01 x_pos: srdiag/bpm/c29-01/SA_HPosition y_pos: srdiag/bpm/c29-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-02 x_pos: srdiag/bpm/c29-02/SA_HPosition y_pos: srdiag/bpm/c29-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-03 x_pos: srdiag/bpm/c29-03/SA_HPosition y_pos: srdiag/bpm/c29-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-04 x_pos: srdiag/bpm/c29-04/SA_HPosition y_pos: srdiag/bpm/c29-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-05 x_pos: srdiag/bpm/c29-05/SA_HPosition y_pos: srdiag/bpm/c29-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-06 x_pos: srdiag/bpm/c29-06/SA_HPosition y_pos: srdiag/bpm/c29-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-07 x_pos: srdiag/bpm/c29-07/SA_HPosition y_pos: srdiag/bpm/c29-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-08 x_pos: srdiag/bpm/c29-08/SA_HPosition y_pos: srdiag/bpm/c29-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-09 x_pos: srdiag/bpm/c29-09/SA_HPosition y_pos: srdiag/bpm/c29-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C29-10 x_pos: srdiag/bpm/c29-10/SA_HPosition y_pos: srdiag/bpm/c29-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-01 x_pos: srdiag/bpm/c30-01/SA_HPosition y_pos: srdiag/bpm/c30-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-02 x_pos: srdiag/bpm/c30-02/SA_HPosition y_pos: srdiag/bpm/c30-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-03 x_pos: srdiag/bpm/c30-03/SA_HPosition y_pos: srdiag/bpm/c30-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-04 x_pos: srdiag/bpm/c30-04/SA_HPosition y_pos: srdiag/bpm/c30-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-05 x_pos: srdiag/bpm/c30-05/SA_HPosition y_pos: srdiag/bpm/c30-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-06 x_pos: srdiag/bpm/c30-06/SA_HPosition y_pos: srdiag/bpm/c30-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-07 x_pos: srdiag/bpm/c30-07/SA_HPosition y_pos: srdiag/bpm/c30-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-08 x_pos: srdiag/bpm/c30-08/SA_HPosition y_pos: srdiag/bpm/c30-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-09 x_pos: srdiag/bpm/c30-09/SA_HPosition y_pos: srdiag/bpm/c30-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C30-10 x_pos: srdiag/bpm/c30-10/SA_HPosition y_pos: srdiag/bpm/c30-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-01 x_pos: srdiag/bpm/c31-01/SA_HPosition y_pos: srdiag/bpm/c31-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-02 x_pos: srdiag/bpm/c31-02/SA_HPosition y_pos: srdiag/bpm/c31-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-03 x_pos: srdiag/bpm/c31-03/SA_HPosition y_pos: srdiag/bpm/c31-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-04 x_pos: srdiag/bpm/c31-04/SA_HPosition y_pos: srdiag/bpm/c31-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-05 x_pos: srdiag/bpm/c31-05/SA_HPosition y_pos: srdiag/bpm/c31-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-06 x_pos: srdiag/bpm/c31-06/SA_HPosition y_pos: srdiag/bpm/c31-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-07 x_pos: srdiag/bpm/c31-07/SA_HPosition y_pos: srdiag/bpm/c31-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-08 x_pos: srdiag/bpm/c31-08/SA_HPosition y_pos: srdiag/bpm/c31-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-09 x_pos: srdiag/bpm/c31-09/SA_HPosition y_pos: srdiag/bpm/c31-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C31-10 x_pos: srdiag/bpm/c31-10/SA_HPosition y_pos: srdiag/bpm/c31-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-01 x_pos: srdiag/bpm/c32-01/SA_HPosition y_pos: srdiag/bpm/c32-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-02 x_pos: srdiag/bpm/c32-02/SA_HPosition y_pos: srdiag/bpm/c32-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-03 x_pos: srdiag/bpm/c32-03/SA_HPosition y_pos: srdiag/bpm/c32-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-04 x_pos: srdiag/bpm/c32-04/SA_HPosition y_pos: srdiag/bpm/c32-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-05 x_pos: srdiag/bpm/c32-05/SA_HPosition y_pos: srdiag/bpm/c32-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-06 x_pos: srdiag/bpm/c32-06/SA_HPosition y_pos: srdiag/bpm/c32-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-07 x_pos: srdiag/bpm/c32-07/SA_HPosition y_pos: srdiag/bpm/c32-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-08 x_pos: srdiag/bpm/c32-08/SA_HPosition y_pos: srdiag/bpm/c32-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-09 x_pos: srdiag/bpm/c32-09/SA_HPosition y_pos: srdiag/bpm/c32-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C32-10 x_pos: srdiag/bpm/c32-10/SA_HPosition y_pos: srdiag/bpm/c32-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-01 x_pos: srdiag/bpm/c01-01/SA_HPosition y_pos: srdiag/bpm/c01-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-02 x_pos: srdiag/bpm/c01-02/SA_HPosition y_pos: srdiag/bpm/c01-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-03 x_pos: srdiag/bpm/c01-03/SA_HPosition y_pos: srdiag/bpm/c01-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-04 x_pos: srdiag/bpm/c01-04/SA_HPosition y_pos: srdiag/bpm/c01-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-05 x_pos: srdiag/bpm/c01-05/SA_HPosition y_pos: srdiag/bpm/c01-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-06 x_pos: srdiag/bpm/c01-06/SA_HPosition y_pos: srdiag/bpm/c01-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-07 x_pos: srdiag/bpm/c01-07/SA_HPosition y_pos: srdiag/bpm/c01-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-08 x_pos: srdiag/bpm/c01-08/SA_HPosition y_pos: srdiag/bpm/c01-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-09 x_pos: srdiag/bpm/c01-09/SA_HPosition y_pos: srdiag/bpm/c01-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-10 x_pos: srdiag/bpm/c01-10/SA_HPosition y_pos: srdiag/bpm/c01-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-01 x_pos: srdiag/bpm/c02-01/SA_HPosition y_pos: srdiag/bpm/c02-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-02 x_pos: srdiag/bpm/c02-02/SA_HPosition y_pos: srdiag/bpm/c02-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-03 x_pos: srdiag/bpm/c02-03/SA_HPosition y_pos: srdiag/bpm/c02-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-04 x_pos: srdiag/bpm/c02-04/SA_HPosition y_pos: srdiag/bpm/c02-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-05 x_pos: srdiag/bpm/c02-05/SA_HPosition y_pos: srdiag/bpm/c02-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-06 x_pos: srdiag/bpm/c02-06/SA_HPosition y_pos: srdiag/bpm/c02-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-07 x_pos: srdiag/bpm/c02-07/SA_HPosition y_pos: srdiag/bpm/c02-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-08 x_pos: srdiag/bpm/c02-08/SA_HPosition y_pos: srdiag/bpm/c02-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-09 x_pos: srdiag/bpm/c02-09/SA_HPosition y_pos: srdiag/bpm/c02-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C02-10 x_pos: srdiag/bpm/c02-10/SA_HPosition y_pos: srdiag/bpm/c02-10/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-01 x_pos: srdiag/bpm/c03-01/SA_HPosition y_pos: srdiag/bpm/c03-01/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-02 x_pos: srdiag/bpm/c03-02/SA_HPosition y_pos: srdiag/bpm/c03-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-03 x_pos: srdiag/bpm/c03-03/SA_HPosition y_pos: srdiag/bpm/c03-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-04 x_pos: srdiag/bpm/c03-04/SA_HPosition y_pos: srdiag/bpm/c03-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-05 x_pos: srdiag/bpm/c03-05/SA_HPosition y_pos: srdiag/bpm/c03-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-06 x_pos: srdiag/bpm/c03-06/SA_HPosition y_pos: srdiag/bpm/c03-06/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-07 x_pos: srdiag/bpm/c03-07/SA_HPosition y_pos: srdiag/bpm/c03-07/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-08 x_pos: srdiag/bpm/c03-08/SA_HPosition y_pos: srdiag/bpm/c03-08/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-09 x_pos: srdiag/bpm/c03-09/SA_HPosition y_pos: srdiag/bpm/c03-09/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C03-10 x_pos: srdiag/bpm/c03-10/SA_HPosition y_pos: srdiag/bpm/c03-10/SA_VPosition diff --git a/tests/config/EBSTune-patterns.yaml b/tests/config/EBSTune-patterns.yaml index 0c258bdea..c0bad0f4c 100644 --- a/tests/config/EBSTune-patterns.yaml +++ b/tests/config/EBSTune-patterns.yaml @@ -12,7 +12,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet diff --git a/tests/config/EBSTune.yaml b/tests/config/EBSTune.yaml index f5a8d5c08..52c7d0119 100644 --- a/tests/config/EBSTune.yaml +++ b/tests/config/EBSTune.yaml @@ -12,7 +12,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet diff --git a/tests/config/EBS_rf_multi.yaml b/tests/config/EBS_rf_multi.yaml index d3c7133be..f1025118b 100644 --- a/tests/config/EBS_rf_multi.yaml +++ b/tests/config/EBS_rf_multi.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.rf.rf_plant diff --git a/tests/config/EBS_rf_notrans.yaml b/tests/config/EBS_rf_notrans.yaml index 1306d8c28..daff32790 100644 --- a/tests/config/EBS_rf_notrans.yaml +++ b/tests/config/EBS_rf_notrans.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.rf.rf_plant diff --git a/tests/config/bad_conf.yml b/tests/config/bad_conf.yml index 178733b4a..513aafebe 100644 --- a/tests/config/bad_conf.yml +++ b/tests/config/bad_conf.yml @@ -19,6 +19,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/bad_conf_cycles.json b/tests/config/bad_conf_cycles.json index 26af53c1f..11f0d6498 100644 --- a/tests/config/bad_conf_cycles.json +++ b/tests/config/bad_conf_cycles.json @@ -3,7 +3,7 @@ "facility": "ESRF", "machine": "sr", "energy": 6e9, - "simulators": ["../config/bad_conf_cycles.json"], + "simulators": ["${include:../config/bad_conf_cycles.json}"], "data_folder": "/data/store", "arrays": [ { @@ -21,8 +21,8 @@ } ], "devices": [ - "sr/quadrupoles/QF1AC01.yaml", - "sr/correctors/SH1AC01.yaml", - "sr/correctors/SH1AC02.yaml" + "${include:sr/quadrupoles/QF1AC01.yaml}", + "${include:sr/correctors/SH1AC01.yaml}", + "${include:sr/correctors/SH1AC02.yaml}" ] } diff --git a/tests/config/bad_conf_cycles.yml b/tests/config/bad_conf_cycles.yml index c0361864a..7cfa167d3 100644 --- a/tests/config/bad_conf_cycles.yml +++ b/tests/config/bad_conf_cycles.yml @@ -19,7 +19,7 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - ../config/bad_conf_cycles.yml # Cycle here - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:../config/bad_conf_cycles.yml} # Cycle here + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/bad_conf_duplicate_1.yaml b/tests/config/bad_conf_duplicate_1.yaml index 209c3be09..608d07655 100644 --- a/tests/config/bad_conf_duplicate_1.yaml +++ b/tests/config/bad_conf_duplicate_1.yaml @@ -20,6 +20,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/bad_conf_duplicate_2.yaml b/tests/config/bad_conf_duplicate_2.yaml index 346957aa8..a36c5400f 100644 --- a/tests/config/bad_conf_duplicate_2.yaml +++ b/tests/config/bad_conf_duplicate_2.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.bpm @@ -21,15 +21,15 @@ arrays: - BPM_C04-06 - BPM_C04-06 # duplicate name in array devices: -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-04 x_pos: srdiag/bpm/c04-04/SA_HPosition y_pos: srdiag/bpm/c04-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-05 x_pos: srdiag/bpm/c04-05/SA_HPosition y_pos: srdiag/bpm/c04-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-06 x_pos: srdiag/bpm/c04-06/SA_HPosition y_pos: srdiag/bpm/c04-06/SA_VPosition diff --git a/tests/config/bad_conf_duplicate_3.yaml b/tests/config/bad_conf_duplicate_3.yaml index 9149009fb..ed1024a4d 100644 --- a/tests/config/bad_conf_duplicate_3.yaml +++ b/tests/config/bad_conf_duplicate_3.yaml @@ -12,7 +12,7 @@ controls: name: live catalog: bpm-catalog catalogs: - - catalogs/sr_catalogs.yaml + - ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.bpm @@ -22,19 +22,19 @@ arrays: - BPM_C04-05 - BPM_C04-06 devices: -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-04 x_pos: srdiag/bpm/c04-04/SA_HPosition y_pos: srdiag/bpm/c04-04/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-05 x_pos: srdiag/bpm/c04-05/SA_HPosition y_pos: srdiag/bpm/c04-05/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C04-06 x_pos: srdiag/bpm/c04-06/SA_HPosition y_pos: srdiag/bpm/c04-06/SA_VPosition -- type: pyaml.bpm.bpm # duplicate device +- type: pyaml.diagnostics.bpm.bpm # duplicate device name: BPM_C04-06 x_pos: srdiag/bpm/c04-06/SA_HPosition y_pos: srdiag/bpm/c04-06/SA_VPosition diff --git a/tests/config/bad_conf_duplicate_4.yaml b/tests/config/bad_conf_duplicate_4.yaml index 95beb2f24..fc1faad04 100644 --- a/tests/config/bad_conf_duplicate_4.yaml +++ b/tests/config/bad_conf_duplicate_4.yaml @@ -19,6 +19,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/bpms.yaml b/tests/config/bpms.yaml index 07caf59af..3312a186e 100644 --- a/tests/config/bpms.yaml +++ b/tests/config/bpms.yaml @@ -10,25 +10,25 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store devices: -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-01 x_pos: srdiag/bpm/c01-01/SA_HPosition y_pos: srdiag/bpm/c01-01/SA_VPosition x_offset: srdiag/bpm/c01-01/HOffset y_offset: srdiag/bpm/c01-01/VOffset tilt: srdiag/bpm/c01-01/Tilt_Angle -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-02 x_pos: srdiag/bpm/c01-02/SA_HPosition y_pos: srdiag/bpm/c01-02/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-03 x_pos: srdiag/bpm/c01-03/SA_HPosition y_pos: srdiag/bpm/c01-03/SA_VPosition -- type: pyaml.bpm.bpm +- type: pyaml.diagnostics.bpm.bpm name: BPM_C01-04 x_pos: srdiag/bpm/c01-04/SA_HPosition y_pos: srdiag/bpm/c01-04/SA_VPosition @@ -42,4 +42,4 @@ devices: - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] - model: sr/magnet_models/SH1AC01.yaml + model: ${include:sr/magnet_models/SH1AC01.yaml} diff --git a/tests/config/catalogs/ebs_catalogs.yaml b/tests/config/catalogs/ebs_catalogs.yaml index d15349d6f..b3da9a0d4 100644 --- a/tests/config/catalogs/ebs_catalogs.yaml +++ b/tests/config/catalogs/ebs_catalogs.yaml @@ -1,8 +1,8 @@ type: tango.pyaml.static_catalog entries: - - catalogs/ebs_bpm_catalogs.yaml - - catalogs/ebs_rf_catalogs.yaml - - catalogs/ebs_diag_catalogs.yaml - - catalogs/ebs_magnets_catalogs.yaml - - catalogs/ebs_sh_catalogs.yaml - - catalogs/ebs_sext_catalogs.yaml + - ${include:catalogs/ebs_bpm_catalogs.yaml} + - ${include:catalogs/ebs_rf_catalogs.yaml} + - ${include:catalogs/ebs_diag_catalogs.yaml} + - ${include:catalogs/ebs_magnets_catalogs.yaml} + - ${include:catalogs/ebs_sh_catalogs.yaml} + - ${include:catalogs/ebs_sext_catalogs.yaml} diff --git a/tests/config/config_manager_sr_base.yaml b/tests/config/config_manager_sr_base.yaml index c842221ac..0d829bfda 100644 --- a/tests/config/config_manager_sr_base.yaml +++ b/tests/config/config_manager_sr_base.yaml @@ -10,5 +10,5 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store diff --git a/tests/config/config_manager_sr_catalogs.yaml b/tests/config/config_manager_sr_catalogs.yaml index 2a0f93347..6fae41e5f 100644 --- a/tests/config/config_manager_sr_catalogs.yaml +++ b/tests/config/config_manager_sr_catalogs.yaml @@ -1,2 +1,2 @@ catalogs: - - catalogs/sr_catalogs.yaml + - ${include:catalogs/sr_catalogs.yaml} diff --git a/tests/config/config_manager_sr_devices.yaml b/tests/config/config_manager_sr_devices.yaml index c6d3e2124..f763942a6 100644 --- a/tests/config/config_manager_sr_devices.yaml +++ b/tests/config/config_manager_sr_devices.yaml @@ -1,11 +1,11 @@ devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01-C02.yaml - - type: pyaml.bpm.bpm + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01-C02.yaml} + - type: pyaml.diagnostics.bpm.bpm name: BPM_C04-01 x_pos: srdiag/bpm/c04-01/SA_HPosition y_pos: srdiag/bpm/c04-01/SA_VPosition - - type: pyaml.bpm.bpm + - type: pyaml.diagnostics.bpm.bpm name: BPM_C04-02 x_pos: srdiag/bpm/c04-02/SA_HPosition y_pos: srdiag/bpm/c04-02/SA_VPosition diff --git a/tests/config/sr-attribute-linker.yaml b/tests/config/sr-attribute-linker.yaml index 1eb8edbbf..98d531d8c 100644 --- a/tests/config/sr-attribute-linker.yaml +++ b/tests/config/sr-attribute-linker.yaml @@ -22,6 +22,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/sr-ident-cfm.yaml b/tests/config/sr-ident-cfm.yaml index 7bc833fdf..11e0fbd4c 100644 --- a/tests/config/sr-ident-cfm.yaml +++ b/tests/config/sr-ident-cfm.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet @@ -24,6 +24,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01-ident.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01-ident.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/sr-range-cfm.yaml b/tests/config/sr-range-cfm.yaml index fc1b37217..466531e79 100644 --- a/tests/config/sr-range-cfm.yaml +++ b/tests/config/sr-range-cfm.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet @@ -24,6 +24,6 @@ arrays: - SH1A-C01-V - SH1A-C02-V devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01-range.yaml - - sr/correctors/SH1AC02.yaml + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01-range.yaml} + - ${include:sr/correctors/SH1AC02.yaml} diff --git a/tests/config/sr.yaml b/tests/config/sr.yaml index 3e9561e81..a5363f929 100644 --- a/tests/config/sr.yaml +++ b/tests/config/sr.yaml @@ -10,7 +10,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/sr_catalogs.yaml + catalog: ${include:catalogs/sr_catalogs.yaml} data_folder: /data/store arrays: - type: pyaml.arrays.magnet @@ -41,13 +41,13 @@ arrays: - SH1A-C01-V - SH1A-C02-H devices: - - sr/quadrupoles/QF1AC01.yaml - - sr/correctors/SH1AC01-C02.yaml - - type: pyaml.bpm.bpm + - ${include:sr/quadrupoles/QF1AC01.yaml} + - ${include:sr/correctors/SH1AC01-C02.yaml} + - type: pyaml.diagnostics.bpm.bpm name: BPM_C04-01 x_pos: srdiag/bpm/c04-01/SA_HPosition y_pos: srdiag/bpm/c04-01/SA_VPosition - - type: pyaml.bpm.bpm + - type: pyaml.diagnostics.bpm.bpm name: BPM_C04-02 x_pos: srdiag/bpm/c04-02/SA_HPosition y_pos: srdiag/bpm/c04-02/SA_VPosition diff --git a/tests/config/sr/correctors/SH1AC01-C02.yaml b/tests/config/sr/correctors/SH1AC01-C02.yaml index 0bba2e4f0..295d1e520 100644 --- a/tests/config/sr/correctors/SH1AC01-C02.yaml +++ b/tests/config/sr/correctors/SH1AC01-C02.yaml @@ -8,7 +8,7 @@ - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] - model: sr/magnet_models/SH1AC01.yaml + model: ${include:sr/magnet_models/SH1AC01.yaml} - type: pyaml.magnet.cfm_magnet name: SH1A-C02 #Name of the element in the lattice model mapping: @@ -19,4 +19,4 @@ - [B0, SH1A-C02-H] - [A0, SH1A-C02-V] - [A1, SH1A-C02-SQ] - model: sr/magnet_models/SH1AC02.yaml + model: ${include:sr/magnet_models/SH1AC02.yaml} diff --git a/tests/config/sr/correctors/SH1AC01-ident.yaml b/tests/config/sr/correctors/SH1AC01-ident.yaml index f5f568953..0f634c2a9 100644 --- a/tests/config/sr/correctors/SH1AC01-ident.yaml +++ b/tests/config/sr/correctors/SH1AC01-ident.yaml @@ -8,4 +8,4 @@ mapping: - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] -model: sr/magnet_models/SH1AC01-ident.yaml +model: ${include:sr/magnet_models/SH1AC01-ident.yaml} diff --git a/tests/config/sr/correctors/SH1AC01-range.yaml b/tests/config/sr/correctors/SH1AC01-range.yaml index ff9eeee85..0cffc86c2 100644 --- a/tests/config/sr/correctors/SH1AC01-range.yaml +++ b/tests/config/sr/correctors/SH1AC01-range.yaml @@ -8,4 +8,4 @@ mapping: - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] -model: sr/magnet_models/SH1AC01-range.yaml +model: ${include:sr/magnet_models/SH1AC01-range.yaml} diff --git a/tests/config/sr/correctors/SH1AC01.yaml b/tests/config/sr/correctors/SH1AC01.yaml index 717ad973d..9facc0bec 100644 --- a/tests/config/sr/correctors/SH1AC01.yaml +++ b/tests/config/sr/correctors/SH1AC01.yaml @@ -8,4 +8,4 @@ mapping: - [B0, SH1A-C01-H] - [A0, SH1A-C01-V] - [A1, SH1A-C01-SQ] -model: sr/magnet_models/SH1AC01.yaml +model: ${include:sr/magnet_models/SH1AC01.yaml} diff --git a/tests/config/sr/correctors/SH1AC02.yaml b/tests/config/sr/correctors/SH1AC02.yaml index 590d69b93..3818d5ade 100644 --- a/tests/config/sr/correctors/SH1AC02.yaml +++ b/tests/config/sr/correctors/SH1AC02.yaml @@ -8,4 +8,4 @@ mapping: - [B0, SH1A-C02-H] - [A0, SH1A-C02-V] - [A1, SH1A-C02-SQ] -model: sr/magnet_models/SH1AC02.yaml +model: ${include:sr/magnet_models/SH1AC02.yaml} diff --git a/tests/config/sr/magnet_models/QF1AC01.json b/tests/config/sr/magnet_models/QF1AC01.json index b9b4e8abd..966a5a459 100644 --- a/tests/config/sr/magnet_models/QF1AC01.json +++ b/tests/config/sr/magnet_models/QF1AC01.json @@ -2,7 +2,7 @@ "type": "pyaml.magnet.linear_model", "calibration_factor": 1.00504, "calibration_offset": 0.0, - "curve": "sr/magnet_models/quadcurve.json", + "curve": "${include:sr/magnet_models/quadcurve.json}", "unit": "1/m", "hardware_unit": "A", "powerconverter": "sr/ps-qf1/c01-a/current" diff --git a/tests/config/sr/magnet_models/QF1AC01.yaml b/tests/config/sr/magnet_models/QF1AC01.yaml index c2f1ac30c..8d31dee13 100644 --- a/tests/config/sr/magnet_models/QF1AC01.yaml +++ b/tests/config/sr/magnet_models/QF1AC01.yaml @@ -1,7 +1,7 @@ type: pyaml.magnet.linear_model calibration_factor: 1.00504 calibration_offset: 0.0 -curve: sr/magnet_models/quadcurve.yaml +curve: ${include:sr/magnet_models/quadcurve.yaml} unit: 1/m hardware_unit: A powerconverter: sr/ps-qf1/c01-a/current diff --git a/tests/config/sr/quadrupoles/QD5D-C04_serialized.yaml b/tests/config/sr/quadrupoles/QD5D-C04_serialized.yaml index 18f5a9123..48dcc7e2a 100644 --- a/tests/config/sr/quadrupoles/QD5D-C04_serialized.yaml +++ b/tests/config/sr/quadrupoles/QD5D-C04_serialized.yaml @@ -1,6 +1,6 @@ type: pyaml.magnet.quadrupole name: QD5D-C04 -model: sr/magnet_models/QF1AC01.yaml +model: ${include:sr/magnet_models/QF1AC01.yaml} linked_elements: - QF8B-C04 - QF8D-C04 diff --git a/tests/config/sr/quadrupoles/QF1AC01.json b/tests/config/sr/quadrupoles/QF1AC01.json index 655d06994..164fdccda 100644 --- a/tests/config/sr/quadrupoles/QF1AC01.json +++ b/tests/config/sr/quadrupoles/QF1AC01.json @@ -1,5 +1,5 @@ { "type": "pyaml.magnet.quadrupole", "name": "QF1A-C01", - "model": "sr/magnet_models/QF1AC01.json" + "model": "${include:sr/magnet_models/QF1AC01.json}" } diff --git a/tests/config/sr/quadrupoles/QF1AC01.yaml b/tests/config/sr/quadrupoles/QF1AC01.yaml index 627702adc..507d3d9dc 100644 --- a/tests/config/sr/quadrupoles/QF1AC01.yaml +++ b/tests/config/sr/quadrupoles/QF1AC01.yaml @@ -1,3 +1,3 @@ type: pyaml.magnet.quadrupole name: QF1A-C01 -model: sr/magnet_models/QF1AC01.yaml +model: ${include:sr/magnet_models/QF1AC01.yaml} diff --git a/tests/config/sr/quadrupoles/QF1C01A_2.yaml b/tests/config/sr/quadrupoles/QF1C01A_2.yaml index 6ab7f120d..6c9c21e78 100644 --- a/tests/config/sr/quadrupoles/QF1C01A_2.yaml +++ b/tests/config/sr/quadrupoles/QF1C01A_2.yaml @@ -4,7 +4,7 @@ model: type: pyaml.magnet.linear_model calibration_factor: 1.006560 calibration_offset: 0.0034 - curve: sr/magnet_models/quadcurve.yaml + curve: ${include:sr/magnet_models/quadcurve.yaml} unit: 1/m hardware_unit: A powerconverter: sr/ps-qf1/c01-a/current diff --git a/tests/config/sr_serialized_magnets_cs.yaml b/tests/config/sr_serialized_magnets_cs.yaml new file mode 100644 index 000000000..2db7546ff --- /dev/null +++ b/tests/config/sr_serialized_magnets_cs.yaml @@ -0,0 +1,57 @@ +type: pyaml.accelerator +facility: ESRF +machine: sr +energy: 6e9 +simulators: + - type: pyaml.lattice.simulator + lattice: sr/lattices/ebs.mat + name: design +controls: + - type: tango.pyaml.controlsystem + tango_host: ebs-simu-3:10000 + name: live + catalog: + type: tango.pyaml.tango_catalog +data_folder: /data/store +arrays: + - type: pyaml.arrays.magnet + name: ALL_SERIALIZED + elements: + - QF1A-C* + - QD2A-C* +devices: + - type: pyaml.magnet.serialized_magnet + name: QF1A + function: B1 + elements: + - QF1A-C05 + - QF1A-C06 + - QF1A-C07 + - QF1A-C08 + model: + type: pyaml.magnet.linear_serialized_model + calibration_factors: [1.0, 1.01, 0.99, 1.02] + calibration_offsets: 0.0 + unit: m-1 + hardware_unit: A + curves: + type: pyaml.magnet.csvcurve + file: sr/magnet_models/QF1_strength.csv + powerconverter: srmag/ps-qf1a/series/current + - type: pyaml.magnet.serialized_magnet + name: QD2A + function: B1 + elements: + - QD2A-C05 + - QD2A-C06 + - QD2A-C07 + model: + type: pyaml.magnet.linear_serialized_model + calibration_factors: 1.0 + calibration_offsets: 0.0 + unit: m-1 + hardware_unit: A + curves: + type: pyaml.magnet.csvcurve + file: sr/magnet_models/QD2_strength.csv + powerconverter: srmag/ps-qd2a/series/current diff --git a/tests/config/tl2/tl2.mat b/tests/config/tl2/tl2.mat new file mode 100644 index 000000000..0d1a909d4 Binary files /dev/null and b/tests/config/tl2/tl2.mat differ diff --git a/tests/config/tl2/tl2.yml b/tests/config/tl2/tl2.yml new file mode 100644 index 000000000..8fef60f8a --- /dev/null +++ b/tests/config/tl2/tl2.yml @@ -0,0 +1,215 @@ +type: pyaml.accelerator +facility: ESRF +machine: tl2 +energy: 6e9 + +simulators: + - class: pyaml.lattice.simulator.Simulator + lattice: tl2.mat + name: design + twiss_in: + class: pyaml.lattice.twiss_in.TwissIn + alpha: [-1.71, 1.47] + beta: [5.9 , 5.65] + dispersion: [-0.145, -0.092, 0, 0] + +data_folder: /data/store + +arrays: + + - type: pyaml.arrays.magnet + name: HCORR + elements: + - CH* + - type: pyaml.arrays.magnet + name: VCORR + elements: + - CV* + - type: pyaml.arrays.bpm + name: BPMS + elements: + - BPM* + +devices: + + - class: pyaml.tuning_tools.orbit.Orbit + bpm_array_name: BPMS + hcorr_array_name: HCORR + vcorr_array_name: VCORR + name: DEFAULT_ORBIT_CORRECTION + singular_values: 5 + response_matrix: ideal_tl2_orm.json + + - class: pyaml.tuning_tools.orbit_response_matrix.OrbitResponseMatrix + bpm_array_name: BPMS + hcorr_array_name: HCORR + vcorr_array_name: VCORR + corrector_delta: 1e-6 + name: DEFAULT_ORBIT_RESPONSE_MATRIX + + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_CV1 + x_pos: tl2/d-bpm/cv1/X_Position + y_pos: tl2/d-bpm/cv1/Z_Position + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_CH3 + x_pos: tl2/d-bpm/d2/X_Position + y_pos: tl2/d-bpm/d2/Z_Position + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_QD5 + x_pos: tl2/d-bpm/q5/X_Position + y_pos: tl2/d-bpm/q5/Z_Position + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_QF6 + x_pos: tl2/d-bpm/q6/X_Position + y_pos: tl2/d-bpm/q6/Z_Position + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_SX + x_pos: tl2/d-bpm/sx/X_Position + y_pos: tl2/d-bpm/sx/Z_Position + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_QD8 + x_pos: tl2/d-bpm/q8/X_Position + y_pos: tl2/d-bpm/q8/Z_Position + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_QD12 + x_pos: tl2/d-bpm/q12/X_Position + y_pos: tl2/d-bpm/q12/Z_Position + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_QF14 + x_pos: tl2/d-bpm/q14/X_Position + y_pos: tl2/d-bpm/q14/Z_Position + - class: pyaml.diagnostics.bpm.bpm.BPM + name: BPM_S1PM + x_pos: tl2/d-bpm/s1pm/X_Position + y_pos: tl2/d-bpm/s1pm/Z_Position + + - class: pyaml.magnet.hcorrector.HCorrector + name: CH1 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/ch1/Current + - class: pyaml.magnet.hcorrector.HCorrector + name: CH2 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/ch2/Current + - class: pyaml.magnet.hcorrector.HCorrector + name: CH3 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/ch3/Current + - class: pyaml.magnet.hcorrector.HCorrector + name: CH4 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/ch4/Current + - class: pyaml.magnet.hcorrector.HCorrector + name: CH5 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/ch5/Current + - class: pyaml.magnet.hcorrector.HCorrector + name: CH6 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/ch6/Current + - class: pyaml.magnet.hcorrector.HCorrector + name: CH7 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/ch7/Current + - class: pyaml.magnet.hcorrector.HCorrector + name: CH8 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/ch8/Current + + - class: pyaml.magnet.vcorrector.VCorrector + name: CV0 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/cv0/Current + - class: pyaml.magnet.vcorrector.VCorrector + name: CV1 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/cv1/Current + - class: pyaml.magnet.vcorrector.VCorrector + name: CV3 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/cv3/Current + - class: pyaml.magnet.vcorrector.VCorrector + name: CV4 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/cv4/Current + - class: pyaml.magnet.vcorrector.VCorrector + name: CV5 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/cv5/Current + - class: pyaml.magnet.vcorrector.VCorrector + name: CV6 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/cv6/Current + - class: pyaml.magnet.vcorrector.VCorrector + name: CV7 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/cv7/Current + - class: pyaml.magnet.vcorrector.VCorrector + name: CV8 + model: + class: pyaml.magnet.linear_model.LinearMagnetModel + calibration_factor: 3.222e-3 + unit: 1/m + hardware_unit: A + powerconverter: tl2/ps-c1/cv8/Current diff --git a/tests/config/tune_monitor.yaml b/tests/config/tune_monitor.yaml index f782a2c1c..791a62dee 100644 --- a/tests/config/tune_monitor.yaml +++ b/tests/config/tune_monitor.yaml @@ -11,7 +11,7 @@ controls: - type: tango.pyaml.controlsystem tango_host: ebs-simu-3:10000 name: live - catalog: catalogs/ebs_catalogs.yaml + catalog: ${include:catalogs/ebs_catalogs.yaml} data_folder: /data/store devices: - type: pyaml.diagnostics.tune_monitor diff --git a/tests/configuration/test_configuration_manager.py b/tests/configuration/test_configuration_manager.py index f36c37dd1..ae5699951 100644 --- a/tests/configuration/test_configuration_manager.py +++ b/tests/configuration/test_configuration_manager.py @@ -189,7 +189,7 @@ def test_configuration_manager_accumulates_multiple_device_fragments( assert manager.has("devices", "BETATRON_TUNE") assert manager.get("devices", "QF1A-C01")["class_path"] == "pyaml.magnet.quadrupole.Quadrupole" assert manager.get("devices", "SH1A-C01")["class_path"] == "pyaml.magnet.cfm_magnet.CombinedFunctionMagnet" - assert manager.get("devices", "BPM_C04-01")["class_path"] == "pyaml.bpm.bpm.BPM" + assert manager.get("devices", "BPM_C04-01")["class_path"] == "pyaml.diagnostics.bpm.bpm.BPM" assert manager.get("devices", "BETATRON_TUNE")["class_path"] == "pyaml.diagnostics.tune_monitor.BetatronTuneMonitor" @@ -222,7 +222,7 @@ def test_configuration_manager_adds_remote_source_with_relative_includes(http_co energy: 3000000000.0 data_folder: remote-data description: Loaded over HTTP -simulators: fragments/simulators.json +simulators: ${include:fragments/simulators.json} devices: [] """, "/configs/fragments/simulators.json": """ @@ -273,7 +273,7 @@ def test_configuration_manager_repr_is_yellow_pages_like( assert "live (tango.pyaml.controlsystem.TangoControlSystem) source=config_manager_sr_base.yaml" in output assert "design (pyaml.lattice.simulator.Simulator) source=config_manager_sr_base.yaml" in output assert "HCORR (pyaml.arrays.magnet.Magnet) patterns=1 source=config_manager_sr_arrays.yaml" in output - assert "BPM_C04-01 (pyaml.bpm.bpm.BPM) source=config_manager_sr_devices.yaml" in output + assert "BPM_C04-01 (pyaml.diagnostics.bpm.bpm.BPM) source=config_manager_sr_devices.yaml" in output assert " ." in output diff --git a/tests/configuration/test_fileloader.py b/tests/configuration/test_fileloader.py index 53b234a66..6fae602a0 100644 --- a/tests/configuration/test_fileloader.py +++ b/tests/configuration/test_fileloader.py @@ -9,7 +9,6 @@ ROOT, LoadContext, RootFolder, - _is_supported_file, load, ) @@ -54,16 +53,6 @@ def test_rootfolder_set_updates_root(tmp_path): assert after == (new_root / "config.yaml").resolve() -def test_is_supported_file(): - assert _is_supported_file("config.yaml") - assert _is_supported_file("config.yml") - assert _is_supported_file("config.json") - - assert not _is_supported_file("config.txt") - assert not _is_supported_file(1) - assert not _is_supported_file(None) - - def test_load_context_adds_and_removes_paths(tmp_path): ctx = LoadContext() path = tmp_path / "config.yaml" @@ -113,7 +102,7 @@ def test_load_nested_yaml(tmp_path): (tmp_path / "child.yaml").write_text("answer: 42\n") - (tmp_path / "parent.yaml").write_text("child: child.yaml\n") + (tmp_path / "parent.yaml").write_text("child: ${include:child.yaml}\n") result = load("parent.yaml") @@ -125,19 +114,19 @@ def test_load_nested_json(tmp_path): (tmp_path / "child.json").write_text(json.dumps({"answer": 42})) - (tmp_path / "parent.json").write_text(json.dumps({"child": "child.json"})) + (tmp_path / "parent.json").write_text(json.dumps({"child": "${include:child.json}"})) result = load("parent.json") assert result["child"]["answer"] == 42 -def test_load_file_resolver_loads_nested_file(tmp_path): +def test_load_include_resolver_loads_nested_file(tmp_path): ROOT.set(tmp_path) (tmp_path / "subdir").mkdir() (tmp_path / "subdir" / "child.yaml").write_text("answer: 42\n") - (tmp_path / "parent.yaml").write_text('target: "${file:subdir/child.yaml}"\n') + (tmp_path / "parent.yaml").write_text('target: "${include:subdir/child.yaml}"\n') result = load("parent.yaml") @@ -199,11 +188,11 @@ def test_load_path_resolver_resolves_without_loading_file(tmp_path): assert result["target"] == str((tmp_path / "subdir" / "missing.json").resolve()) -def test_load_interpolated_file_resolver_inside_string_raises(tmp_path): +def test_load_interpolated_include_resolver_inside_string_raises(tmp_path): ROOT.set(tmp_path) (tmp_path / "child.yaml").write_text("answer: 42\n") - (tmp_path / "config.yaml").write_text('value: "prefix-${file:child.yaml}-suffix"\n') + (tmp_path / "config.yaml").write_text('value: "prefix-${include:child.yaml}-suffix"\n') with pytest.raises(PyAMLException, match="cannot be interpolated into a string"): load("config.yaml") @@ -227,7 +216,7 @@ def test_load_list_include_extends_list(tmp_path): """ values: - start - - items.yaml + - ${include:items.yaml} - end """.strip() ) @@ -285,8 +274,8 @@ def test_load_invalid_json_raises_pyaml_exception(tmp_path): def test_load_circular_include_raises_pyaml_exception(tmp_path): ROOT.set(tmp_path) - (tmp_path / "a.yaml").write_text("b: b.yaml\n") - (tmp_path / "b.yaml").write_text("a: a.yaml\n") + (tmp_path / "a.yaml").write_text("b: ${include:b.yaml}\n") + (tmp_path / "b.yaml").write_text("a: ${include:a.yaml}\n") with pytest.raises(PyAMLException, match="Circular file inclusion"): load("a.yaml") diff --git a/tests/bpm/test_bpm.py b/tests/diagnostics/bpm/test_bpm.py similarity index 86% rename from tests/bpm/test_bpm.py rename to tests/diagnostics/bpm/test_bpm.py index 93ac68ec5..3bf8ee712 100644 --- a/tests/bpm/test_bpm.py +++ b/tests/diagnostics/bpm/test_bpm.py @@ -9,7 +9,7 @@ def test_simulator_bpm_tilt(): sr.design.get_lattice().disable_6d() sr.design.magnet.get("SH1A-C01-H").strength.set(10e-6) # Add orbit sr.design.magnet.get("SH1A-C01-V").strength.set(10e-6) # Add orbit - bpm = sr.design.bpm.get("BPM_C01-01") + bpm = sr.design.diagnostic.bpm.get("BPM_C01-01") assert np.allclose(bpm.positions.get(), np.array([5.90809968e-05, 2.24832853e-05])) assert bpm.tilt.get() == 0 alpha = np.pi / 3 @@ -30,7 +30,7 @@ def test_simulator_bpm_tilt(): def test_simulator_bpm_offset(): sr: Accelerator = Accelerator.load("tests/config/bpms.yaml", ignore_external=True) sr.design.get_lattice().disable_6d() - bpm = sr.design.bpm.get("BPM_C01-01") + bpm = sr.design.diagnostic.bpm.get("BPM_C01-01") assert bpm.offset.get()[0] == 0 assert bpm.offset.get()[1] == 0 @@ -48,8 +48,8 @@ def test_simulator_bpm_offset(): def test_simulator_bpm_position(install_test_package): sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") sr.design.get_lattice().disable_6d() - bpm = sr.design.bpm.get("BPM_C01-01") - bpm_simple = sr.live.bpm.get("BPM_C01-02") + bpm = sr.design.diagnostic.bpm.get("BPM_C01-01") + bpm_simple = sr.live.diagnostic.bpm.get("BPM_C01-02") assert np.allclose(bpm.positions.get(), np.array([0.0, 0.0])) assert np.allclose(bpm_simple.positions.get(), np.array([0.0, 0.0])) @@ -58,9 +58,9 @@ def test_simulator_bpm_position(install_test_package): def test_simulator_bpm_position_with_bad_corrector_strength(): sr: Accelerator = Accelerator.load("tests/config/bpms.yaml", ignore_external=True) sr.design.get_lattice().disable_6d() - bpm1 = sr.design.bpm.get("BPM_C01-01") - bpm_simple = sr.design.bpm.get("BPM_C01-02") - bpm3 = sr.design.bpm.get("BPM_C01-03") + bpm1 = sr.design.diagnostic.bpm.get("BPM_C01-01") + bpm_simple = sr.design.diagnostic.bpm.get("BPM_C01-02") + bpm3 = sr.design.diagnostic.bpm.get("BPM_C01-03") sr.design.magnet.get("SH1A-C01-H").strength.set(-1e-6) sr.design.magnet.get("SH1A-C01-V").strength.set(-1e-6) diff --git a/tests/diagnostics/bpm/test_bpm_controlsystem.py b/tests/diagnostics/bpm/test_bpm_controlsystem.py new file mode 100644 index 000000000..54eeb0686 --- /dev/null +++ b/tests/diagnostics/bpm/test_bpm_controlsystem.py @@ -0,0 +1,199 @@ +import numpy as np +import pytest + +from pyaml.accelerator import Accelerator + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_bpm_tilt(install_test_package): + sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") + bpm = sr.live.diagnostic.bpm.get("BPM_C01-01") + print(bpm.tilt.get()) + + assert bpm.tilt.get() == 0 + bpm.tilt.set(0.01) + assert bpm.tilt.get() == 0.01 + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_bpm_offset(install_test_package): + sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") + bpm = sr.live.diagnostic.bpm.get("BPM_C01-01") + + assert bpm.offset.get()[0] == 0 + assert bpm.offset.get()[1] == 0 + bpm.offset.set(np.array([0.1, 0.2])) + assert bpm.offset.get()[0] == 0.1 + assert bpm.offset.get()[1] == 0.2 + assert np.allclose(bpm.positions.get(), np.array([0.0, 0.0])) + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_bpm_position(install_test_package): + sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") + bpm = sr.live.diagnostic.bpm.get("BPM_C01-01") + bpm_simple = sr.live.diagnostic.bpm.get("BPM_C01-02") + + assert np.allclose(bpm.positions.get(), np.array([0.0, 0.0])) + assert np.allclose(bpm_simple.positions.get(), np.array([0.0, 0.0])) + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_get_devices_returns_attached_devices(install_test_package): + sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") + + devs = sr.live.get_devices_access(["srdiag/bpm/c01-01/SA_HPosition", "srdiag/bpm/c01-01/SA_VPosition"]) + + assert devs[0].name() == "//ebs-simu-3:10000/srdiag/bpm/c01-01/SA_HPosition" + assert devs[1].name() == "//ebs-simu-3:10000/srdiag/bpm/c01-01/SA_VPosition" + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_get_device_accepts_backend_config_model(install_test_package): + from tango.pyaml.attribute import ConfigModel as AttributeConfigModel + + sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") + + dev = sr.live.get_device_access(AttributeConfigModel(attribute="srdiag/bpm/c01-05/SA_HPosition", unit="mm")) + + assert dev.name() == "//ebs-simu-3:10000/srdiag/bpm/c01-05/SA_HPosition" + assert dev.unit() == "mm" + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_bpm_position_indexed(install_test_package): + from tango.pyaml.attribute_store import set_attribute + + set_attribute("srdiag/bpm/c01-04/Position", [0.0, 1.0], unit="mm") + + sr: Accelerator = Accelerator.load("tests/config/bpms.yaml") + bpm = sr.live.diagnostic.bpm.get("BPM_C01-04") + + assert np.allclose(bpm.positions.get(), np.array([0.0, 1.0])) + + +def _single_plane_bpm_config() -> dict: + """Two full BPMs and one vertical-only XBPM, grouped in one BPM array.""" + entries = [] + for key in ["c01-01/H", "c01-01/V", "c01-02/H", "c01-02/V", "xbpm/V"]: + entries.append( + { + "type": "tango.pyaml.static_catalog_entry", + "key": key, + "device": {"type": "tango.pyaml.attribute_read_only", "attribute": f"sr/bpm/{key}", "unit": "mm"}, + } + ) + return { + "type": "pyaml.accelerator", + "facility": "ESRF", + "machine": "sr", + "energy": 6e9, + "data_folder": "/data/store", + "controls": [ + { + "type": "tango.pyaml.controlsystem", + "tango_host": "ebs-simu-3:10000", + "name": "live", + "catalog": {"type": "tango.pyaml.static_catalog", "entries": entries}, + } + ], + "arrays": [{"type": "pyaml.arrays.bpm", "name": "BPM", "elements": ["BPM_1", "BPM_2", "XBPM"]}], + "devices": [ + {"type": "pyaml.diagnostics.bpm.bpm", "name": "BPM_1", "x_pos": "c01-01/H", "y_pos": "c01-01/V"}, + {"type": "pyaml.diagnostics.bpm.bpm", "name": "BPM_2", "x_pos": "c01-02/H", "y_pos": "c01-02/V"}, + {"type": "pyaml.diagnostics.bpm.bpm", "name": "XBPM", "y_pos": "xbpm/V"}, + ], + } + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_bpm_single_plane(install_test_package): + from tango.pyaml.attribute_store import set_attribute + + set_attribute("sr/bpm/xbpm/V", 0.3, unit="mm") + sr = Accelerator.from_dict(_single_plane_bpm_config()) + xbpm = sr.live.diagnostic.bpm.get("XBPM") + + pos = xbpm.positions.get() + assert np.isnan(pos[0]) + assert pos[1] == pytest.approx(0.3) + assert xbpm.positions.unit() == "mm" + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_bpm_array_with_single_plane_bpm(install_test_package): + from tango.pyaml.attribute_store import set_attribute + + for name, value in [("c01-01/H", 0.1), ("c01-01/V", -0.1), ("c01-02/H", 0.2), ("c01-02/V", -0.2), ("xbpm/V", 0.3)]: + set_attribute(f"sr/bpm/{name}", value, unit="mm") + sr = Accelerator.from_dict(_single_plane_bpm_config()) + bpms = sr.live.diagnostic.bpms.get("BPM") + + pos = bpms.positions.get() + assert pos.shape == (3, 2) + assert np.isnan(pos[2, 0]) + assert np.allclose(pos[:2], [[0.1, -0.1], [0.2, -0.2]]) + assert pos[2, 1] == pytest.approx(0.3) + + h = bpms.h.get() + assert np.allclose(h[:2], [0.1, 0.2]) + assert np.isnan(h[2]) + assert np.allclose(bpms.v.get(), [-0.1, -0.2, 0.3]) + + # The missing plane must not disable the grouped reads + agg, aggh, aggv = sr.live.create_bpm_aggregators(list(bpms)) + assert [agg.nb_device(), aggh.nb_device(), aggv.nb_device()] == [6, 3, 3] + assert np.allclose(agg.get(), pos.flatten(), equal_nan=True) + assert np.allclose(aggh.get(), h, equal_nan=True) + assert np.allclose(aggv.get(), [-0.1, -0.2, 0.3]) + + +@pytest.mark.parametrize( + "install_test_package", + [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}], + indirect=True, +) +def test_controlsystem_bpm_array_without_horizontal_plane(install_test_package): + from tango.pyaml.attribute_store import set_attribute + + set_attribute("sr/bpm/xbpm/V", 0.3, unit="mm") + config = _single_plane_bpm_config() + config["arrays"][0]["elements"] = ["XBPM"] + sr = Accelerator.from_dict(config) + bpms = sr.live.diagnostic.bpms.get("BPM") + + assert np.isnan(bpms.h.get()).all() + assert np.allclose(bpms.v.get(), [0.3]) + assert bpms.positions.get().shape == (1, 2) diff --git a/tests/diagnostics/test_diagnostic_accessors.py b/tests/diagnostics/test_diagnostic_accessors.py new file mode 100644 index 000000000..0046d975e --- /dev/null +++ b/tests/diagnostics/test_diagnostic_accessors.py @@ -0,0 +1,172 @@ +import copy + +import pytest + +from pyaml.accelerator import Accelerator +from pyaml.common.exception import PyAMLException +from pyaml.lattice.simulator import Simulator + + +def test_diagnostic_get_returns_named_monitor(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + assert design.diagnostic.get("BETATRON_TUNE") is design._DIAG["BETATRON_TUNE"] + + +def test_diagnostic_get_with_no_name_returns_all_configured_diagnostics(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + all_diagnostics = design.diagnostic.get() + assert design.diagnostic.get("BETATRON_TUNE") in all_diagnostics + + +def test_diagnostic_betatron_tune_returns_default_monitor(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + assert design.diagnostic.betatron_tune is design.diagnostic.get("BETATRON_TUNE") + + +def test_diagnostic_raises_when_default_missing(ebs_lattice_file): + holder = Simulator(name="empty", lattice=str(ebs_lattice_file)) + + with pytest.raises(PyAMLException) as exc: + _ = holder.diagnostic.betatron_tune + assert "BETATRON_TUNE" in str(exc.value) + + +def test_diagnostic_raises_when_default_wrong_type(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + # Swap the registered default so it points to an object of the wrong type. + design._DIAG["BETATRON_TUNE"] = design.tool.orbit + + with pytest.raises(PyAMLException) as exc: + _ = design.diagnostic.betatron_tune + assert "BETATRON_TUNE" in str(exc.value) + assert "BetatronTuneMonitor" in str(exc.value) + + +def test_diagnostic_bpm_returns_named_bpm(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + assert design.diagnostic.bpm.get("BPM_C04-04").get_name() == "BPM_C04-04" + + +def test_diagnostic_bpms_returns_named_array(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + bpms = design.diagnostic.bpms.get("BPM") + assert design.diagnostic.bpm.get("BPM_C04-04") in bpms + + +def test_diagnostic_getitem_exact_name_matches_get(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + assert design.diagnostic["BETATRON_TUNE"] is design.diagnostic.get("BETATRON_TUNE") + + +def test_diagnostic_getitem_exact_name_miss_raises(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + with pytest.raises(PyAMLException): + design.diagnostic["UNKNOWN"] + + +def test_diagnostic_getitem_wildcard_returns_an_array(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + matching = design.diagnostic["BETATRON*"] + assert matching.names() == ["BETATRON_TUNE"] + assert design.diagnostic["MISSING*"].names() == [] + + +def test_diagnostic_getitem_list_selection_ignores_request_order(): + """A list-of-patterns selection lands in configuration order, whatever order the names + were requested in, same as every other holder (see + test_every_accessor_returns_a_list_selection_in_configuration_order). Only one diagnostic + is registered by any existing fixture, so a distinct second entry is poked directly into + the store (a renamed copy of the existing monitor) to make request order and + configuration order observably different.""" + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + spare_monitor = copy.copy(design.diagnostic.get("BETATRON_TUNE")) + spare_monitor._name = "SPARE_BETATRON_TUNE" + design._DIAG["SPARE_BETATRON_TUNE"] = spare_monitor + + forward = design.diagnostic[["BETATRON_TUNE", "SPARE_BETATRON_TUNE"]] + backward = design.diagnostic[["SPARE_BETATRON_TUNE", "BETATRON_TUNE"]] + assert forward.names() == backward.names() == ["BETATRON_TUNE", "SPARE_BETATRON_TUNE"] + + +def test_diagnostic_bpm_getitem_exact_name_matches_get(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + assert design.diagnostic.bpm["BPM_C04-04"] is design.diagnostic.bpm.get("BPM_C04-04") + + +def test_diagnostic_bpm_getitem_exact_name_miss_raises(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + with pytest.raises(PyAMLException): + design.diagnostic.bpm["UNKNOWN"] + + +def test_diagnostic_bpm_getitem_wildcard_and_list_return_an_array(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + wildcard = design.diagnostic.bpm["BPM_C04-0[14]"] + assert sorted(wildcard.names()) == ["BPM_C04-01", "BPM_C04-04"] + + listed = design.diagnostic.bpm[["BPM_C04-01", "BPM_C04-04"]] + assert listed.names() == ["BPM_C04-01", "BPM_C04-04"] diff --git a/tests/integration/test_dt4acc_twin_smoke.py b/tests/integration/test_dt4acc_twin_smoke.py index 549bdb4e7..d9edec864 100644 --- a/tests/integration/test_dt4acc_twin_smoke.py +++ b/tests/integration/test_dt4acc_twin_smoke.py @@ -3,7 +3,6 @@ import numpy as np import pytest -import yaml from pyaml_test_lattice import configurations, lattices from pyaml.accelerator import Accelerator @@ -37,22 +36,17 @@ def _readback_value(device_access): def _load_fragment(config_key: str) -> dict: """Load one pyaml-test-lattice merged config fragment as a plain dict. - Bypasses pyaml's own YAML loader (which auto-loads any bare - ``*.yaml``/``*.json`` string value as a nested file relative to the - parent file's directory) since the lattice file ships under a different + The ``lattice`` reference is overridden since it lives in a different package subtree (``data/lattice``) than the config fragment - (``data/configuration``). The ``lattice`` and ``catalog`` references are - resolved explicitly instead. + (``data/configuration``). """ config_path = Path(configurations[config_key]) - fragment = yaml.safe_load(config_path.read_text()) + manager = ConfigurationManager() + manager.add(config_path) + fragment = manager.to_dict() fragment["simulators"][0]["lattice"] = str(Path(lattices[FODO_LATTICE_KEY])) - catalog_name = fragment["controls"][0]["catalog"] - catalog_path = config_path.parent / catalog_name - fragment["controls"][0]["catalog"] = yaml.safe_load(catalog_path.read_text()) - return fragment @@ -134,9 +128,9 @@ def deactivated_test_orbit_correction(config_key: str): try: accelerator = _build_accelerator(config_key) control_mode = accelerator.live - bpms = control_mode.bpms.get("bpms") - orbit_response_matrix = control_mode.get_orm_tuning("DEFAULT_ORBIT_RESPONSE_MATRIX") - orbit_correction = control_mode.get_orbit_tuning("DEFAULT_ORBIT_CORRECTION") + bpms = control_mode.diagnostic.bpms.get("bpms") + orbit_response_matrix = control_mode.tool.get("DEFAULT_ORBIT_RESPONSE_MATRIX") + orbit_correction = control_mode.tool.get("DEFAULT_ORBIT_CORRECTION") orbit_response_matrix.measure() ormdata = orbit_response_matrix.get() orbit_response_matrix.save("orm.json") @@ -179,7 +173,7 @@ def deactivated_test_chromaticity_measurement(config_key: str): accelerator = _build_accelerator(config_key) control_mode = accelerator.live - chromaticity_measurement = control_mode.get_chromaticity_monitor("DEFAULT_CHROMATICITY_MEASUREMENT") + chromaticity_measurement = control_mode.tool.get("DEFAULT_CHROMATICITY_MEASUREMENT") def chroma_callback(action: int, cb_data: dict): if action == Action.MEASURE: diff --git a/tests/lattice/test_linkers.py b/tests/lattice/test_linkers.py index 75585da74..957c2cae8 100644 --- a/tests/lattice/test_linkers.py +++ b/tests/lattice/test_linkers.py @@ -1,3 +1,4 @@ +import at import pytest from pyaml import PyAMLException @@ -6,6 +7,7 @@ PyAtAttributeElementsLinker, PyAtAttributeIdentifier, ) +from pyaml.lattice.simulator import Simulator # ----------------------- # Dummy PyAML Element @@ -13,14 +15,18 @@ class DummyPyAMLElement: - """Minimal stand-in for a PyAML Element: only provides .name.""" + """Minimal stand-in for a PyAML Element: only provides .name and .lattice_names.""" - def __init__(self, name: str): + def __init__(self, name: str, lattice_names: str | None = None): self._name = name + self._lattice_names = lattice_names def get_name(self) -> str: return self._name + def get_lattice_names(self) -> str | None: + return self._lattice_names + def test_conf_with_linker(): sr: Accelerator = Accelerator.load("tests/config/sr-attribute-linker.yaml") @@ -94,90 +100,27 @@ def check_index(ring, elts, indices): assert ring.index(e) == indices[idx] -def test_various_naming_addressing(): - sr = Accelerator.load("tests/config/EBSNames.yaml", ignore_external=True) +# Ring indices of the QF1E / QF1I quadrupoles of sr/lattices/ebs-original-names.mat +QF1E_INDICES = [ + 140, 290, 424, 576, 712, 848, 982, 1116, 1250, 1384, 1525, 1662, 1803, 1937, 2078, 2212, + 2348, 2482, 2616, 2762, 2898, 3046, 3182, 3316, 3452, 3593, 3732, 3873, 4009, 4150, 4286, +] # fmt: skip +QF1E_ALL_INDICES = QF1E_INDICES + [4430] + + +@pytest.mark.parametrize("config", ["tests/config/EBSNames.yaml", "tests/config/EBSNames-linker.yaml"]) +def test_various_naming_addressing(config): + """lattice_names selectors give the same elements with and without a linker.""" + sr = Accelerator.load(config, ignore_external=True) ring = sr.design.get_lattice() elts = sr.design.magnet.get("QF1E").strength._elements assert len(elts) == 31 - check_index( - ring, - elts, - [ - 140, - 290, - 424, - 576, - 712, - 848, - 982, - 1116, - 1250, - 1384, - 1525, - 1662, - 1803, - 1937, - 2078, - 2212, - 2348, - 2482, - 2616, - 2762, - 2898, - 3046, - 3182, - 3316, - 3452, - 3593, - 3732, - 3873, - 4009, - 4150, - 4286, - ], - ) + check_index(ring, elts, QF1E_INDICES) elts = sr.design.magnet.get("QF1E-ALL").strength._elements assert len(elts) == 32 - check_index( - ring, - elts, - [ - 140, - 290, - 424, - 576, - 712, - 848, - 982, - 1116, - 1250, - 1384, - 1525, - 1662, - 1803, - 1937, - 2078, - 2212, - 2348, - 2482, - 2616, - 2762, - 2898, - 3046, - 3182, - 3316, - 3452, - 3593, - 3732, - 3873, - 4009, - 4150, - 4286, - 4430, - ], - ) + check_index(ring, elts, QF1E_ALL_INDICES) elts = sr.design.magnet.get("QF1E-C05").strength._elements assert len(elts) == 1 @@ -194,3 +137,60 @@ def test_various_naming_addressing(): elts = sr.design.magnet.get("QF1E-C04-C05-C06-3").strength._elements assert len(elts) == 3 check_index(ring, elts, [140, 290, 424]) + + +# ----------------------- +# lattice_names selectors with a linker +# ----------------------- + + +@pytest.fixture +def simulator_with_tag_linker(lattice_with_custom_attr, tmp_path) -> Simulator: + """Simulator on the 'Tag' lattice: D1(Tag=D1) QF(Tag=QF) QF2(Tag=QF) QD(Tag=QD).""" + lattice_file = tmp_path / "tag_lattice.m" + at.save_m(lattice_with_custom_attr, str(lattice_file)) + return Simulator(name="design", lattice=str(lattice_file), linker=PyAtAttributeElementsLinker(attribute_name="Tag")) + + +def _tags(elements): + return [getattr(e, "Tag", None) for e in elements] + + +def test_linker_without_lattice_names_uses_element_name(simulator_with_tag_linker): + elts = simulator_with_tag_linker.get_at_elems(DummyPyAMLElement("QF")) + assert _tags(elts) == ["QF", "QF"] + + +def test_linker_lattice_names_list(simulator_with_tag_linker): + sim = simulator_with_tag_linker + assert _tags(sim.get_at_elems(DummyPyAMLElement("anything", "list(QF)"))) == ["QF", "QF"] + assert _tags(sim.get_at_elems(DummyPyAMLElement("anything", "list(QF,QD)"))) == ["QF", "QF", "QD"] + + +def test_linker_lattice_names_indices(simulator_with_tag_linker): + sim = simulator_with_tag_linker + ring = sim.ring + assert sim.get_at_elems(DummyPyAMLElement("x", "QF@1")) == [ring[2]] + assert sim.get_at_elems(DummyPyAMLElement("x", "QF@0,1")) == [ring[1], ring[2]] + assert sim.get_at_elems(DummyPyAMLElement("x", "QF#0..2")) == [ring[1], ring[2]] + # Empty name: direct indexing in the whole ring + assert sim.get_at_elems(DummyPyAMLElement("x", "@3")) == [ring[3]] + assert sim.get_at_elems(DummyPyAMLElement("x", "#1..3")) == [ring[1], ring[2]] + + +def test_linker_lattice_names_share_lattice_element(simulator_with_tag_linker): + """Two PyAML elements with different names can drive the same PyAT element.""" + sim = simulator_with_tag_linker + main = sim.get_at_elems(DummyPyAMLElement("QD")) + coil = sim.get_at_elems(DummyPyAMLElement("QD_H", "list(QD)")) + assert main == coil == [sim.ring[3]] + + +def test_linker_lattice_names_errors(simulator_with_tag_linker): + sim = simulator_with_tag_linker + with pytest.raises(PyAMLException): + sim.get_at_elems(DummyPyAMLElement("x", "list(ZZ)")) + with pytest.raises(PyAMLException): + sim.get_at_elems(DummyPyAMLElement("x", "ZZ@0")) + with pytest.raises(PyAMLException): + sim.get_at_elems(DummyPyAMLElement("x", "QF@5")) diff --git a/tests/lattice/test_magnet_accessors.py b/tests/lattice/test_magnet_accessors.py new file mode 100644 index 000000000..e585b37ef --- /dev/null +++ b/tests/lattice/test_magnet_accessors.py @@ -0,0 +1,100 @@ +import at +import numpy as np +import pytest + +from pyaml import PyAMLException +from pyaml.lattice.abstract_impl import ( + RWHardwareArray, + RWHardwareScalar, + RWSerializedStrength, + RWStrengthArray, + RWStrengthScalar, +) +from pyaml.magnet.hcorrector import HCorrector +from pyaml.magnet.identity_cfm_model import IdentityCFMagnetModel +from pyaml.magnet.identity_model import IdentityMagnetModel +from pyaml.magnet.vcorrector import VCorrector + + +def _thin_corrector(name="COR"): + return at.Corrector(name, 0.0, [0.0, 0.0], PolynomA=[0.0], PolynomB=[0.0]) + + +@pytest.mark.parametrize("accessor_type", [RWStrengthScalar, RWHardwareScalar]) +def test_zero_length_scalar_magnet_stores_integrated_strength(accessor_type): + element = _thin_corrector() + model = IdentityMagnetModel(physics="COR", unit="rad") + accessor = accessor_type([element], HCorrector.polynom, model) + + accessor.set(1.0e-6) + + # AT convention: a thin element stores the integrated strength in its polynom + assert element.PolynomB[0] == pytest.approx(-1.0e-6) + assert accessor.get() == pytest.approx(1.0e-6) + + +@pytest.mark.parametrize("accessor_type", [RWStrengthScalar, RWHardwareScalar]) +def test_zero_length_split_magnet_shares_integrated_strength_equally(accessor_type): + elements = [_thin_corrector("COR_A"), _thin_corrector("COR_B")] + model = IdentityMagnetModel(physics="COR", unit="rad") + accessor = accessor_type(elements, HCorrector.polynom, model) + + accessor.set(1.0e-6) + + assert elements[0].PolynomB[0] == pytest.approx(-0.5e-6) + assert elements[1].PolynomB[0] == pytest.approx(-0.5e-6) + assert accessor.get() == pytest.approx(1.0e-6) + + +@pytest.mark.parametrize("accessor_type", [RWStrengthScalar, RWHardwareScalar]) +def test_thick_scalar_magnet_is_unchanged(accessor_type): + element = at.Corrector("COR", 0.2, [0.0, 0.0], PolynomA=[0.0], PolynomB=[0.0]) + model = IdentityMagnetModel(physics="COR", unit="rad") + accessor = accessor_type([element], HCorrector.polynom, model) + + accessor.set(1.0e-6) + + assert element.PolynomB[0] == pytest.approx(-5.0e-6) + assert accessor.get() == pytest.approx(1.0e-6) + + +@pytest.mark.parametrize("accessor_type", [RWStrengthArray, RWHardwareArray]) +def test_zero_length_combined_function_magnet_stores_integrated_strengths(accessor_type): + element = _thin_corrector() + model = IdentityCFMagnetModel( + multipoles=["B0", "A0"], + physics=["HCOR", "VCOR"], + units=["rad", "rad"], + ) + accessor = accessor_type([element], [HCorrector.polynom, VCorrector.polynom], model) + + accessor.set(np.array([1.0e-6, -2.0e-6])) + + assert element.PolynomB[0] == pytest.approx(-1.0e-6) + assert element.PolynomA[0] == pytest.approx(-2.0e-6) + np.testing.assert_allclose(accessor.get(), [1.0e-6, -2.0e-6]) + + +def test_zero_length_serialized_magnets_share_strength_equally(): + elements = [_thin_corrector("COR_A"), _thin_corrector("COR_B")] + model = IdentityMagnetModel(physics="COR", unit="rad") + strengths = [RWStrengthScalar([e], HCorrector.polynom, model) for e in elements] + currents = [RWHardwareScalar([e], HCorrector.polynom, model) for e in elements] + serialized = [RWSerializedStrength(strengths, currents, i) for i in range(len(elements))] + + serialized[0].set(1.0e-6) + + assert serialized[0].get() == pytest.approx(0.5e-6) + assert serialized[1].get() == pytest.approx(0.5e-6) + assert elements[0].PolynomB[0] == pytest.approx(-0.5e-6) + assert elements[1].PolynomB[0] == pytest.approx(-0.5e-6) + + +def test_serialized_magnets_mixing_thin_and_thick_is_rejected(): + elements = [_thin_corrector("COR_A"), at.Corrector("COR_B", 0.2, [0.0, 0.0], PolynomA=[0.0], PolynomB=[0.0])] + model = IdentityMagnetModel(physics="COR", unit="rad") + strengths = [RWStrengthScalar([e], HCorrector.polynom, model) for e in elements] + currents = [RWHardwareScalar([e], HCorrector.polynom, model) for e in elements] + + with pytest.raises(PyAMLException, match="all thin .* or all thick"): + RWSerializedStrength(strengths, currents, 0) diff --git a/tests/magnet/test_serialized_magnets.py b/tests/magnet/test_serialized_magnets.py index 1e95ca706..b362f7b77 100644 --- a/tests/magnet/test_serialized_magnets.py +++ b/tests/magnet/test_serialized_magnets.py @@ -27,11 +27,11 @@ def test_config_load(sr_file): sr: Accelerator = Accelerator.load(sr_file, include_locations=False, ignore_external=True) assert sr is not None magnets = [ - sr.design.get_element("QF8B-C04"), - sr.design.get_element("QF8B-C04"), - sr.design.get_element("QD5D-C04"), - sr.design.get_element("QF6D-C04"), - sr.design.get_element("QF4D-C04"), + sr.design["QF8B-C04"], + sr.design["QF8B-C04"], + sr.design["QD5D-C04"], + sr.design["QF6D-C04"], + sr.design["QF4D-C04"], ] assert None not in [magnets] @@ -115,7 +115,7 @@ def test_tune(sr_file): assert len(m.get_magnets()) == m.get_nb_magnets() quadForTuneDesign = sr.design.serialized_magnets.get("QForTune") - tune_monitor = sr.design.get_betatron_tune_monitor("BETATRON_TUNE") + tune_monitor = sr.design.diagnostic.get("BETATRON_TUNE") # Build tune response matrix tunemat = np.zeros((len(quadForTuneDesign), 2)) diff --git a/tests/magnet/test_serialized_magnets_cs.py b/tests/magnet/test_serialized_magnets_cs.py new file mode 100644 index 000000000..cd4f29982 --- /dev/null +++ b/tests/magnet/test_serialized_magnets_cs.py @@ -0,0 +1,67 @@ +import numpy as np +import pytest + +from pyaml.accelerator import Accelerator +from pyaml.magnet.serialized_magnet import SerializedMagnets + +CONFIG = "tests/config/sr_serialized_magnets_cs.yaml" +TANGO_DUMMY = [{"name": "tango-pyaml", "path": "tests/dummy_cs/tango-pyaml"}] + + +def _sub_strengths(family: SerializedMagnets, current: float) -> np.ndarray: + return np.array([family.model.get_sub_model(i).compute_strengths([current])[0] for i in range(family.get_nb_magnets())]) + + +@pytest.mark.parametrize("install_test_package", TANGO_DUMMY, indirect=True) +def test_serialized_magnets_attach_to_control_system(install_test_package): + sr: Accelerator = Accelerator.load(CONFIG) + family: SerializedMagnets = sr.live.serialized_magnet.get("QF1A") + magnets = family.get_magnets() + + assert family.get_nb_magnets() == 4 + assert [m.get_name() for m in magnets] == ["QF1A-C05", "QF1A-C06", "QF1A-C07", "QF1A-C08"] + for m in magnets: + assert sr.live.magnet.get(m.get_name()) is m + + +@pytest.mark.parametrize("install_test_package", TANGO_DUMMY, indirect=True) +def test_serialized_magnets_share_power_supply(install_test_package): + sr: Accelerator = Accelerator.load(CONFIG) + family: SerializedMagnets = sr.live.serialized_magnet.get("QF1A") + magnets = family.get_magnets() + + magnets[2].hardware.set(80.0) + assert np.allclose([m.hardware.get() for m in magnets], 80.0) + assert np.allclose([m.strength.get() for m in magnets], _sub_strengths(family, 80.0)) + + # Setting the strength of one magnet drives the shared power supply with that magnet's own sub-model + magnets[1].strength.set(0.5) + current = family.model.get_sub_model(1).compute_hardware_values([0.5])[0] + assert np.allclose([m.hardware.get() for m in magnets], current) + assert magnets[1].strength.get() == pytest.approx(0.5) + + # The other family is on its own power supply + assert np.allclose([m.hardware.get() for m in sr.live.serialized_magnet.get("QD2A").get_magnets()], 0.0) + + +@pytest.mark.parametrize("install_test_package", TANGO_DUMMY, indirect=True) +def test_serialized_magnets_aggregator(install_test_package): + sr: Accelerator = Accelerator.load(CONFIG) + qf1a: SerializedMagnets = sr.live.serialized_magnet.get("QF1A") + qd2a: SerializedMagnets = sr.live.serialized_magnet.get("QD2A") + qf1a.get_magnets()[0].hardware.set(30.0) + qd2a.get_magnets()[0].hardware.set(20.0) + + array = sr.live.magnets.get("ALL_SERIALIZED") + expected = np.concatenate([_sub_strengths(qf1a, 30.0), _sub_strengths(qd2a, 20.0)]) + assert np.allclose(array.strengths.get(), expected) + assert np.allclose(array.hardwares.get(), [30.0] * 4 + [20.0] * 3) + + # Doubling every magnet of a series moves its power supply to the current of the doubled strength (no 1/N dilution) + array.strengths.set(2 * array.strengths.get()) + assert np.allclose(array.strengths.get(), 2 * expected) + qf1a_current = qf1a.model.get_sub_model(0).compute_hardware_values([2 * expected[0]])[0] + assert np.allclose(array.hardwares.get()[:4], qf1a_current) + + array.hardwares.set(array.hardwares.get()) + assert np.allclose(array.strengths.get(), 2 * expected) diff --git a/tests/rf/test_rf_holder.py b/tests/rf/test_rf_holder.py new file mode 100644 index 000000000..b1839ea8c --- /dev/null +++ b/tests/rf/test_rf_holder.py @@ -0,0 +1,75 @@ +import copy + +import pytest + +from pyaml.accelerator import Accelerator +from pyaml.common.exception import PyAMLException + + +@pytest.fixture +def design(): + return Accelerator.load("tests/config/EBS_rf_multi.yaml", ignore_external=True).design + + +def test_rf_holder_getitem_exact_name_matches_get(design): + assert design.rf["DEFAULT_RF_PLANT"] is design.rf.get("DEFAULT_RF_PLANT") + + +def test_rf_holder_getitem_exact_name_miss_raises(design): + with pytest.raises(PyAMLException): + design.rf["UNKNOWN"] + + +def test_rf_holder_getitem_wildcard_returns_an_array(design): + matching = design.rf["DEFAULT_*"] + assert matching.names() == ["DEFAULT_RF_PLANT"] + assert design.rf["MISSING*"].names() == [] + + +def test_rf_transmitter_holder_getitem_exact_name_matches_get(design): + assert design.rf.transmitter["RFTRA1"] is design.rf.transmitter.get("RFTRA1") + + +def test_rf_transmitter_holder_getitem_exact_name_miss_raises(design): + with pytest.raises(PyAMLException): + design.rf.transmitter["UNKNOWN"] + + +def test_rf_transmitter_holder_getitem_wildcard_returns_an_array(design): + matching = design.rf.transmitter["RFTRA*"] + assert sorted(matching.names()) == ["RFTRA1", "RFTRA2", "RFTRA_HARMONIC"] + + +def test_rf_transmitter_holder_getitem_list_of_patterns(design): + selected = design.rf.transmitter[["RFTRA1", "RFTRA2"]] + assert selected.names() == ["RFTRA1", "RFTRA2"] + + +def test_rf_transmitter_holder_getitem_list_selection_ignores_request_order(design): + """A list-of-patterns selection lands in configuration order, whatever order the names + were requested in, same as every other holder (see + test_every_accessor_returns_a_list_selection_in_configuration_order).""" + forward = design.rf.transmitter[["RFTRA1", "RFTRA2"]] + backward = design.rf.transmitter[["RFTRA2", "RFTRA1"]] + assert forward.names() == backward.names() == ["RFTRA1", "RFTRA2"] + + +def test_rf_holder_getitem_list_selection_ignores_request_order(design): + """Same configuration-order guarantee as the RF transmitter holder, at the RF plant level. + + Only one RF plant is registered by this fixture, so a distinct second entry is poked + directly into the store (a renamed copy of the existing plant) to make request order and + configuration order observably different. + """ + spare_plant = copy.copy(design.rf.get("DEFAULT_RF_PLANT")) + spare_plant._name = "SPARE_RF_PLANT" + design._RFPLANT["SPARE_RF_PLANT"] = spare_plant + + forward = design.rf[["DEFAULT_RF_PLANT", "SPARE_RF_PLANT"]] + backward = design.rf[["SPARE_RF_PLANT", "DEFAULT_RF_PLANT"]] + assert forward.names() == backward.names() == ["DEFAULT_RF_PLANT", "SPARE_RF_PLANT"] + + +def test_rf_transmitter_holder_getitem_regex(design): + matching = design.rf.transmitter["re:^RFTRA[12]$"] + assert sorted(matching.names()) == ["RFTRA1", "RFTRA2"] diff --git a/tests/test_accelerator_load.py b/tests/test_accelerator_load.py index f30a68e39..57e659f08 100644 --- a/tests/test_accelerator_load.py +++ b/tests/test_accelerator_load.py @@ -9,18 +9,18 @@ def test_peer(): sr = Accelerator.load("tests/config/tune_monitor.yaml") - tm = sr.design.get_betatron_tune_monitor("BETATRON_TUNE") + tm = sr.design.diagnostic.get("BETATRON_TUNE") assert isinstance(tm.peer.peer, Accelerator) assert isinstance(tm.peer, ElementHolder) - tm = sr.live.get_betatron_tune_monitor("BETATRON_TUNE") + tm = sr.live.diagnostic.get("BETATRON_TUNE") assert isinstance(tm.peer.peer, Accelerator) assert isinstance(tm.peer, ElementHolder) def test_repr_is_informative_and_bounded(): sr = Accelerator.load("tests/config/EBSOrbit.yaml") - bpm = sr.design.bpm.get("BPM_C04-04") - bpms = sr.design.bpms.get("BPM") + bpm = sr.design.diagnostic.bpm.get("BPM_C04-04") + bpms = sr.design.diagnostic.bpms.get("BPM") assert repr(bpm) == ( "BPM(name='BPM_C04-04', lattice_names='BPM_C04-04', " @@ -46,7 +46,7 @@ def test_repr_options_limit_sequences(): set_repr_options(max_items=1) sr = Accelerator.load("tests/config/EBSOrbit.yaml") - bpms = sr.design.bpms.get("BPM") + bpms = sr.design.diagnostic.bpms.get("BPM") assert f"... +{len(bpms) - 1} more ..." in repr(bpms) finally: set_repr_options( @@ -73,7 +73,7 @@ def test_accelerator_load_supports_remote_sources(http_config_server, ebs_lattic energy: 3000000000.0 data_folder: remote-data description: Remote accelerator -simulators: fragments/simulators.json +simulators: ${include:fragments/simulators.json} devices: [] """, "/config/fragments/simulators.json": f""" @@ -160,5 +160,5 @@ def test_config_dict(): assert sr.live.dconfig()["prefix"] == "VA:" assert sr.live.dconfig()["info"]["param1"] == "Param1 value" assert sr.live.dconfig()["info"]["param2"] == 12345.0 - assert isinstance(sr.live.get_element("MY_ELEMENT"), MyElement) - assert sr.live.get_element("MY_ELEMENT")._cfg.device_h == "TUNEZR:rdH" + assert isinstance(sr.live["MY_ELEMENT"], MyElement) + assert sr.live["MY_ELEMENT"]._cfg.device_h == "TUNEZR:rdH" diff --git a/tests/test_catalogs.py b/tests/test_catalogs.py index 828627aa5..bbe42f462 100644 --- a/tests/test_catalogs.py +++ b/tests/test_catalogs.py @@ -50,7 +50,7 @@ def test_inline_catalog_is_supported(install_test_package): ], "devices": [ { - "type": "pyaml.bpm.bpm", + "type": "pyaml.diagnostics.bpm.bpm", "name": "BPM_C02-01", "x_pos": "BPM_C02-01/x", "y_pos": "BPM_C02-01/y", @@ -59,7 +59,7 @@ def test_inline_catalog_is_supported(install_test_package): } ) - bpm = sr.live.bpm.get("BPM_C02-01") + bpm = sr.live.diagnostic.bpm.get("BPM_C02-01") assert np.allclose(bpm.positions.get(), np.array([0.0, 0.0])) @@ -103,7 +103,7 @@ def test_unresolved_catalog_key_raises_runtime_error(install_test_package): ], "devices": [ { - "type": "pyaml.bpm.bpm", + "type": "pyaml.diagnostics.bpm.bpm", "name": "BPM_C03-01", "x_pos": "BPM_C03-01/x", "y_pos": "BPM_C03-01/y", @@ -175,7 +175,7 @@ def test_indexed_catalog_entry_extracts_scalar_from_vector_attribute(install_tes ], "devices": [ { - "type": "pyaml.bpm.bpm", + "type": "pyaml.diagnostics.bpm.bpm", "name": "BPM_TEST", "x_pos": "bpm/SA_HPosition", "y_pos": "bpm/SA_VPosition", @@ -184,7 +184,7 @@ def test_indexed_catalog_entry_extracts_scalar_from_vector_attribute(install_tes } ) - bpm = sr.live.bpm.get("BPM_TEST") + bpm = sr.live.diagnostic.bpm.get("BPM_TEST") positions = bpm.positions.get() assert np.isclose(positions[0], 1.5) assert np.isclose(positions[1], -0.3) diff --git a/tests/test_load_conf_with_code.py b/tests/test_load_conf_with_code.py index de4761023..41771dbfa 100644 --- a/tests/test_load_conf_with_code.py +++ b/tests/test_load_conf_with_code.py @@ -8,11 +8,13 @@ def test_load_conf_with_code(): config_path = parent_folder.joinpath("config", "EBSOrbit.yaml").resolve() sr: Accelerator = Accelerator.load(config_path) - bpms = sr.live.bpms.get("BPM") + bpms = sr.live.diagnostic.bpms.get("BPM") assert bpms is not None assert len(bpms) == 320 assert sr.live[bpms[0].get_name()] is bpms[0] assert sr.live["BPM*"].names() == bpms.names() - assert sr.live[:].names() == [element.get_name() for element in sr.live.get_all_elements()] - assert sr.design["BPM*"].names() == sr.design.bpms.get("BPM").names() + assert sr.live[:].names() == [element.get_name() for element in sr.live.get()] + assert sr.design["BPM*"].names() == sr.design.diagnostic.bpms.get("BPM").names() + + assert sr.live.diagnostic.bpms.BPM is bpms diff --git a/tests/tuning_tools/test_bba.py b/tests/tuning_tools/test_bba.py index 330c8118f..22f60c144 100644 --- a/tests/tuning_tools/test_bba.py +++ b/tests/tuning_tools/test_bba.py @@ -9,16 +9,16 @@ def test_bba(): SR = sr.design # Add a misalignement - SR.bpm.get("BPM_C04-04").offset.set([20e-6, -15e-6]) + SR.diagnostic.bpm.get("BPM_C04-04").offset.set([20e-6, -15e-6]) # BBA (standard bow tie, model independant) - bba = SR.get_bba("BBA-BPM_C04-04") + bba = SR.tool.get("BBA-BPM_C04-04") bba.measure() assert np.abs(bba.h_offset() - 20e-6) < 1e-6 assert np.abs(bba.v_offset() + 15e-6) < 1e-6 # BBA (model dependant method) - bba = SR.get_bba("BBA2-BPM_C04-04") + bba = SR.tool.get("BBA2-BPM_C04-04") bba.minicycle_sleep_time = 0 bba.measure() assert np.abs(bba.h_offset() - 20e-6) < 1e-6 diff --git a/tests/tuning_tools/test_chromaticity_monitor.py b/tests/tuning_tools/test_chromaticity_monitor.py index 3f7671d9f..4f9c7e115 100644 --- a/tests/tuning_tools/test_chromaticity_monitor.py +++ b/tests/tuning_tools/test_chromaticity_monitor.py @@ -13,7 +13,7 @@ def test_simulator_chromaticity_monitor(): sr: Accelerator = Accelerator.load("tests/config/EBSOrbit.yaml", ignore_external=True) sr.design.get_lattice().enable_6d() chromaAT = sr.design.get_lattice().get_chrom()[:-1] - chromaticity_monitor = sr.design.get_chromaticity_monitor("CHROMATICITY_MONITOR") + chromaticity_monitor = sr.design.tool.get("CHROMATICITY_MONITOR") assert chromaticity_monitor.chromaticity.unit() == "1" assert chromaticity_monitor.dispersion.unit() == "m" chromaticity_monitor.measure(fit_dispersion=True, callback=callback) @@ -43,7 +43,7 @@ def test_simulator_chromaticity_monitor(): ) def test_controlsystem_chromaticity_monitor(install_test_package): sr: Accelerator = Accelerator.load("tests/config/EBSOrbit.yaml") - chromaticity_monitor = sr.live.get_chromaticity_monitor("CHROMATICITY_MONITOR") + chromaticity_monitor = sr.live.tool.get("CHROMATICITY_MONITOR") assert chromaticity_monitor.chromaticity.get() is None chromaticity_monitor.measure( do_plot=False, diff --git a/tests/tuning_tools/test_tool_accessors.py b/tests/tuning_tools/test_tool_accessors.py index 1ccbf5dfa..f582040ac 100644 --- a/tests/tuning_tools/test_tool_accessors.py +++ b/tests/tuning_tools/test_tool_accessors.py @@ -1,4 +1,8 @@ +import pytest + from pyaml.accelerator import Accelerator +from pyaml.common.exception import PyAMLException +from pyaml.lattice.simulator import Simulator def test_tuning_tools_expose_configured_elements(): @@ -9,45 +13,97 @@ def test_tuning_tools_expose_configured_elements(): ) design = sr.design - tune_monitor = design.get_betatron_tune_monitor("BETATRON_TUNE") + tune_monitor = design.diagnostic.get("BETATRON_TUNE") quadrupoles = design.magnets.get("QForTune") - assert design.tune.tune_monitor is tune_monitor - assert design.tune.quadrupoles is quadrupoles - assert design.trm.tune_monitor is tune_monitor - assert design.trm.quadrupoles is quadrupoles + assert design.tool.tune.tune_monitor is tune_monitor + assert design.tool.tune.quadrupoles is quadrupoles + assert design.tool.trm.tune_monitor is tune_monitor + assert design.tool.trm.quadrupoles is quadrupoles - chromaticity_monitor = design.get_chromaticity_monitor("CHROMATICITY_MONITOR") + chromaticity_monitor = design.tool.get("CHROMATICITY_MONITOR") sextupoles = design.magnets.get("Sext") - assert design.chromaticity.chromaticity_monitor is chromaticity_monitor - assert design.chromaticity.sextupoles is sextupoles - assert design.crm.chromaticity_monitor is chromaticity_monitor - assert design.crm.sextupoles is sextupoles + assert design.tool.chromaticity.chromaticity_monitor is chromaticity_monitor + assert design.tool.chromaticity.sextupoles is sextupoles + assert design.tool.crm.chromaticity_monitor is chromaticity_monitor + assert design.tool.crm.sextupoles is sextupoles - bpms = design.bpms.get("BPM") + bpms = design.diagnostic.bpms.get("BPM") rf_plant = design.rf.get("DEFAULT_RF_PLANT") assert chromaticity_monitor.tune_monitor is tune_monitor assert chromaticity_monitor.bpms is bpms assert chromaticity_monitor.rf_plant is rf_plant - assert design.dispersion.bpms is bpms - assert design.dispersion.rf_plant is rf_plant + assert design.tool.dispersion.bpms is bpms + assert design.tool.dispersion.rf_plant is rf_plant hcorrectors = design.magnets.get("HCorr") vcorrectors = design.magnets.get("VCorr") - assert design.orbit.bpms is bpms - assert design.orbit.hcorrectors is hcorrectors - assert design.orbit.vcorrectors is vcorrectors - assert design.orbit.correctors.names() == hcorrectors.names() + vcorrectors.names() - assert design.orbit.rf_plant is rf_plant - assert design.orm.bpms is bpms - assert design.orm.hcorrectors is hcorrectors - assert design.orm.vcorrectors is vcorrectors + assert design.tool.orbit.bpms is bpms + assert design.tool.orbit.hcorrectors is hcorrectors + assert design.tool.orbit.vcorrectors is vcorrectors + assert design.tool.orbit.correctors.names() == hcorrectors.names() + vcorrectors.names() + assert design.tool.orbit.rf_plant is rf_plant + assert design.tool.orm.bpms is bpms + assert design.tool.orm.hcorrectors is hcorrectors + assert design.tool.orm.vcorrectors is vcorrectors for name in ("BBA-BPM_C04-04", "BBA2-BPM_C04-04"): - bba = design.get_bba(name) + bba = design.tool.get(name) assert bba.bpms is bpms - assert bba.bpm is design.bpm.get("BPM_C04-04") + assert bba.bpm is design.diagnostic.bpm.get("BPM_C04-04") assert bba.hcorrector is design.magnet.get("SF2E-C02-H") assert bba.vcorrector is design.magnet.get("SD1A-C26-V") assert bba.quadrupole is design.magnet.get("QF6B-C04") - assert design.get_bba("BBA2-BPM_C04-04").tune_correction is design.tune + assert design.tool.get("BBA2-BPM_C04-04").tune_correction is design.tool.tune + + +def test_tool_get_returns_named_tool(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + assert design.tool.get("DEFAULT_TUNE_CORRECTION") is design.tool.tune + assert design.tool.get("DEFAULT_ORBIT_RESPONSE_MATRIX") is design.tool.orm + + +def test_tool_get_with_no_name_returns_all_configured_tools(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + all_tools = design.tool.get() + assert design.tool.tune in all_tools + assert design.tool.trm in all_tools + assert design.tool.orbit in all_tools + assert design.tool.orm in all_tools + assert design.tool.chromaticity in all_tools + assert design.tool.crm in all_tools + assert design.tool.dispersion in all_tools + + +def test_tool_raises_when_default_missing(ebs_lattice_file): + holder = Simulator(name="empty", lattice=str(ebs_lattice_file)) + + with pytest.raises(PyAMLException) as exc: + _ = holder.tool.tune + assert "DEFAULT_TUNE_CORRECTION" in str(exc.value) + + +def test_tool_raises_when_default_wrong_type(): + design = Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + # Swap the registered default so it points to an object of the wrong type. + design._TOOLS["DEFAULT_TUNE_CORRECTION"] = design.tool.orbit + + with pytest.raises(PyAMLException) as exc: + _ = design.tool.tune + assert "DEFAULT_TUNE_CORRECTION" in str(exc.value) + assert "Tune" in str(exc.value) diff --git a/tests/tuning_tools/test_tool_holder.py b/tests/tuning_tools/test_tool_holder.py new file mode 100644 index 000000000..cd921940d --- /dev/null +++ b/tests/tuning_tools/test_tool_holder.py @@ -0,0 +1,47 @@ +import pytest + +from pyaml.accelerator import Accelerator +from pyaml.common.exception import PyAMLException + + +@pytest.fixture +def design(): + return Accelerator.load( + "tests/config/EBSOrbit.yaml", + ignore_external=True, + include_locations=False, + ).design + + +def test_tool_holder_getitem_exact_name_matches_get(design): + assert design.tool["DEFAULT_TUNE_CORRECTION"] is design.tool.get("DEFAULT_TUNE_CORRECTION") + + +def test_tool_holder_getitem_exact_name_miss_raises(design): + with pytest.raises(PyAMLException): + design.tool["UNKNOWN"] + + +def test_tool_holder_getitem_wildcard_returns_an_array(design): + matching = design.tool["DEFAULT_TUNE*"] + assert sorted(matching.names()) == ["DEFAULT_TUNE_CORRECTION", "DEFAULT_TUNE_RESPONSE_MATRIX"] + assert design.tool["MISSING*"].names() == [] + + +def test_tool_holder_getitem_list_of_patterns(design): + selected = design.tool[["DEFAULT_TUNE_CORRECTION", "DEFAULT_ORBIT_CORRECTION"]] + assert selected.names() == ["DEFAULT_TUNE_CORRECTION", "DEFAULT_ORBIT_CORRECTION"] + + +def test_tool_holder_getitem_list_selection_ignores_request_order(design): + """A list-of-patterns selection lands in configuration order, whatever order the names + were requested in, same as every other holder (see + test_every_accessor_returns_a_list_selection_in_configuration_order).""" + forward = design.tool[["DEFAULT_TUNE_CORRECTION", "DEFAULT_ORBIT_CORRECTION"]] + backward = design.tool[["DEFAULT_ORBIT_CORRECTION", "DEFAULT_TUNE_CORRECTION"]] + assert forward.names() == backward.names() == ["DEFAULT_TUNE_CORRECTION", "DEFAULT_ORBIT_CORRECTION"] + + +def test_tool_holder_getitem_regex(design): + matching = design.tool["re:^DEFAULT_(TUNE|ORBIT)_CORRECTION$"] + assert sorted(matching.names()) == ["DEFAULT_ORBIT_CORRECTION", "DEFAULT_TUNE_CORRECTION"] diff --git a/tests/tuning_tools/test_transfer_line.py b/tests/tuning_tools/test_transfer_line.py new file mode 100644 index 000000000..7c5b422c2 --- /dev/null +++ b/tests/tuning_tools/test_transfer_line.py @@ -0,0 +1,47 @@ +import numpy +import pytest + +from pyaml.accelerator import Accelerator + + +def test_transfer_line(): + tl2 = Accelerator.load("tests/config/tl2/tl2.yml") + tl2.design.tool.orm.measure() + orm_data = tl2.design.tool.orm.get() + mat = numpy.array(orm_data["matrix"]) + + orm_hv = mat[:9, 8:] + orm_vh = mat[9:, :8] + assert numpy.allclose(orm_hv, 0) + assert numpy.allclose(orm_vh, 0) + + orm_h = mat[:9, :8] + orm_v = mat[9:, 8:] + + assert numpy.allclose( + orm_h[8, :], [1.49217029, 3.11318219, 10.60494678, -0.82242986, -19.2814236, -14.92682822, 1.28503979, 1.60584401] + ) + assert numpy.allclose( + orm_v[8, :], [10.95203344, 10.56524176, 16.43659334, 32.50321299, 12.72373742, 10.3122307, 10.47365958, 2.61214668] + ) + + tl2.design.tool.orm.save("tl2.json") + tl2.design.tool.orbit.load("tl2.json") + + # Mangle the orbit + hcorr = tl2.design.magnets.get("HCORR") + vcorr = tl2.design.magnets.get("VCORR") + numpy.random.seed(1) + std_kick = 1e-6 # rad + hcorr.strengths.set(hcorr.strengths.get() + std_kick * numpy.random.normal(size=len(hcorr))) + vcorr.strengths.set(vcorr.strengths.get() + std_kick * numpy.random.normal(size=len(vcorr))) + + orbit = tl2.design.diagnostic.bpms.get("BPMS").positions + assert numpy.allclose(numpy.std(orbit.get(), axis=0), [1.78288459e-05, 3.57986943e-05]) + + tl2.design.tool.orbit.correct() + tl2.design.tool.orbit.correct() + + assert numpy.allclose(numpy.std(orbit.get(), axis=0), [7.51291713e-07, 7.24545959e-07]) + + assert numpy.allclose(orbit.get()[2], tl2.design.diagnostic.bpm.get("BPM_QD5").positions.get()) diff --git a/tests/tuning_tools/test_tune.py b/tests/tuning_tools/test_tune.py index a114230cf..fe23a48e1 100644 --- a/tests/tuning_tools/test_tune.py +++ b/tests/tuning_tools/test_tune.py @@ -14,7 +14,7 @@ def test_tune(): sr.design.get_lattice().disable_6d() quadForTuneDesign = sr.design.magnets.get("QForTune") - tune_monitor = sr.design.get_betatron_tune_monitor("BETATRON_TUNE") + tune_monitor = sr.design.diagnostic.get("BETATRON_TUNE") # Build tune response matrix tune = tune_monitor.tune.get() print(tune) diff --git a/tests/tuning_tools/test_tune_hardware.py b/tests/tuning_tools/test_tune_hardware.py index 8e83197df..e48ce2657 100644 --- a/tests/tuning_tools/test_tune_hardware.py +++ b/tests/tuning_tools/test_tune_hardware.py @@ -12,7 +12,7 @@ def test_tune(): # Build tune response matrix (hardware units) - tune_monitor = sr.design.get_betatron_tune_monitor("BETATRON_TUNE") + tune_monitor = sr.design.diagnostic.get("BETATRON_TUNE") tune = tune_monitor.tune.get() print(tune) tunemat = np.zeros((len(quadForTuneDesign), 2)) diff --git a/tests/tuning_tools/test_tune_monitor.py b/tests/tuning_tools/test_tune_monitor.py index 893f096ec..66694c370 100644 --- a/tests/tuning_tools/test_tune_monitor.py +++ b/tests/tuning_tools/test_tune_monitor.py @@ -11,7 +11,7 @@ def test_simulator_tune_monitor( ignore_external=True, ) sr.design.get_lattice().disable_6d() - tune_monitor = sr.design.get_betatron_tune_monitor("BETATRON_TUNE") + tune_monitor = sr.design.diagnostic.get("BETATRON_TUNE") assert tune_monitor.tune.get()[0] == sr.design.get_lattice().get_tune()[0] assert tune_monitor.tune.get()[1] == sr.design.get_lattice().get_tune()[1] assert np.abs(tune_monitor.frequency.get()[0] - 56834.22592393) < 1e-6 @@ -31,6 +31,6 @@ def test_controlsystem_tune_monitor( sr = accelerator_from_fragments( *tune_monitor_configuration_fragments, ) - tune_monitor = sr.live.get_betatron_tune_monitor("BETATRON_TUNE") + tune_monitor = sr.live.diagnostic.get("BETATRON_TUNE") assert tune_monitor.tune.get()[0] == 0.0 assert tune_monitor.tune.get()[1] == 0.0 diff --git a/tests/tuning_tools/test_tuning_dispersion.py b/tests/tuning_tools/test_tuning_dispersion.py index 16d2cd397..a2abcc430 100644 --- a/tests/tuning_tools/test_tuning_dispersion.py +++ b/tests/tuning_tools/test_tuning_dispersion.py @@ -12,12 +12,12 @@ def test_tuning_orm(): sr = Accelerator.load(config_path) element_holder = sr.design - dispersion = element_holder.dispersion + dispersion = element_holder.tool.dispersion dispersion.measure() dispersion_data = dispersion.get() - bpms = element_holder.bpms.get("BPM") + bpms = element_holder.diagnostic.bpms.get("BPM") assert len(dispersion_data["frequency_response_x"]) == len(bpms) assert len(dispersion_data["frequency_response_y"]) == len(bpms) diff --git a/tests/tuning_tools/test_tuning_orbit_correction.py b/tests/tuning_tools/test_tuning_orbit_correction.py index 4bf3b6a66..930d59e93 100644 --- a/tests/tuning_tools/test_tuning_orbit_correction.py +++ b/tests/tuning_tools/test_tuning_orbit_correction.py @@ -22,12 +22,12 @@ def test_tuning_orbit_correction(): std_kick = 1e-6 hcorr = element_holder.magnets.get("HCorr") vcorr = element_holder.magnets.get("VCorr") - bpms = element_holder.bpms.get("BPM") + bpms = element_holder.diagnostic.bpms.get("BPM") x, y = bpms.positions.get().T # get reference orbit reference = np.concat((x, y)) # there should be nothing to correct, but still work - element_holder.orbit.correct(reference=reference) + element_holder.tool.orbit.correct(reference=reference) h_strengths = hcorr.strengths.get() + std_kick * np.random.normal(size=len(hcorr)) v_strengths = vcorr.strengths.get() + std_kick * np.random.normal(size=len(vcorr)) @@ -43,7 +43,7 @@ def test_tuning_orbit_correction(): assert np.isclose(std_bc[0], original_H, rtol=0, atol=1e-14) assert np.isclose(std_bc[1], original_V, rtol=0, atol=1e-14) - element_holder.orbit.correct(reference=None) + element_holder.tool.orbit.correct(reference=None) positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) @@ -53,7 +53,7 @@ def test_tuning_orbit_correction(): # mangle orbit again, test gain_h/gain_v hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.correct(gain_h=0.5, gain_v=0.1) + element_holder.tool.orbit.correct(gain_h=0.5, gain_v=0.1) positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) @@ -63,7 +63,7 @@ def test_tuning_orbit_correction(): # mangle orbit again, test gain/gain_v hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.correct(gain=1, gain_v=0.1) + element_holder.tool.orbit.correct(gain=1, gain_v=0.1) positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) @@ -73,7 +73,7 @@ def test_tuning_orbit_correction(): # mangle orbit again, test singular_values_h hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.correct(singular_values_h=100) + element_holder.tool.orbit.correct(singular_values_h=100) positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) @@ -83,7 +83,7 @@ def test_tuning_orbit_correction(): # mangle orbit again, test singular_values_v hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.correct(singular_values_v=50) + element_holder.tool.orbit.correct(singular_values_v=50) positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) @@ -93,7 +93,7 @@ def test_tuning_orbit_correction(): # mangle orbit again, test plane=H hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.correct(plane="H") + element_holder.tool.orbit.correct(plane="H") positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) @@ -104,7 +104,7 @@ def test_tuning_orbit_correction(): # mangle orbit again, test plane=V hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.correct(plane="V") + element_holder.tool.orbit.correct(plane="V") positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) @@ -116,65 +116,65 @@ def test_tuning_orbit_correction(): hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.set_weight("SJ2A-C04-H", 2) - element_holder.orbit.correct() + element_holder.tool.orbit.set_weight("SJ2A-C04-H", 2) + element_holder.tool.orbit.correct() positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) assert np.isclose(std_ac[0], 5.057265926153962e-07, rtol=0, atol=1e-14) assert np.isclose(std_ac[1], 4.78927471675123e-07, rtol=0, atol=1e-14) - element_holder.orbit.set_weight("SJ2A-C04-H", 1) + element_holder.tool.orbit.set_weight("SJ2A-C04-H", 1) # mangle orbit again, test bpm weight hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.set_weight("BPM_C04-05", 2) - element_holder.orbit.correct() + element_holder.tool.orbit.set_weight("BPM_C04-05", 2) + element_holder.tool.orbit.correct() positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) assert np.isclose(std_ac[0], 5.056719006414065e-07, rtol=0, atol=1e-14) assert np.isclose(std_ac[1], 4.790610352466602e-07, rtol=0, atol=1e-14) - element_holder.orbit.set_weight("BPM_C04-05", 1) + element_holder.tool.orbit.set_weight("BPM_C04-05", 1) # mangle orbit again, test virtual weight hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) - element_holder.orbit.set_virtual_weight(2) - element_holder.orbit.correct() + element_holder.tool.orbit.set_virtual_weight(2) + element_holder.tool.orbit.correct() positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) assert np.isclose(std_ac[0], 5.05398857685373e-07, rtol=0, atol=1e-14) assert np.isclose(std_ac[1], 4.789270969888965e-07, rtol=0, atol=1e-14) - element_holder.orbit.set_virtual_weight(1000) + element_holder.tool.orbit.set_virtual_weight(1000) # mangle orbit again, test virtual target hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) virtual_target = 1e-8 - element_holder.orbit.correct(virtual_target=virtual_target) + element_holder.tool.orbit.correct(virtual_target=virtual_target) delta_h_strengths = hcorr.strengths.get() - h_strengths delta_h_strengths_sum = -np.sum(delta_h_strengths) assert np.isclose(delta_h_strengths_sum - virtual_target, 0, rtol=0, atol=1e-13) - element_holder.orbit.set_virtual_weight(1) + element_holder.tool.orbit.set_virtual_weight(1) # mangle orbit again, test reference hcorr.strengths.set(h_strengths) vcorr.strengths.set(v_strengths) reference = np.concatenate((positions_bc[:, 0], positions_bc[:, 1])) - element_holder.orbit.correct(reference=reference) + element_holder.tool.orbit.correct(reference=reference) positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) assert np.isclose(std_ac[0], original_H, rtol=0, atol=1e-14) assert np.isclose(std_ac[1], original_V, rtol=0, atol=1e-14) # no need to mangle orbit again, test reference/plane=H - element_holder.orbit.correct(reference=reference / 2, plane="H") + element_holder.tool.orbit.correct(reference=reference / 2, plane="H") positions_ac = bpms.positions.get() std_ac = np.std(positions_ac, axis=0) assert np.isclose(std_ac[0], 3.360429728849497e-05, rtol=0, atol=1e-14) @@ -187,7 +187,7 @@ def test_tuning_orbit_correction(): frf = element_holder.rf.frequency.get() element_holder.rf.frequency.set(frf + 100) for _ in range(3): - element_holder.orbit.correct( + element_holder.tool.orbit.correct( reference=reference_before_rf, plane="H", rf=True, @@ -202,12 +202,12 @@ def test_tuning_orbit_correction(): x, y = bpms.positions.get().T # get reference orbit reference_before_rf = np.concat((x, y)) - rf_weight = element_holder.orbit.get_rf_weight() - element_holder.orbit.set_rf_weight(1.1 * rf_weight) + rf_weight = element_holder.tool.orbit.get_rf_weight() + element_holder.tool.orbit.set_rf_weight(1.1 * rf_weight) frf = element_holder.rf.frequency.get() element_holder.rf.frequency.set(frf + 100) for _ in range(8): - element_holder.orbit.correct( + element_holder.tool.orbit.correct( reference=reference_before_rf, plane="H", rf=True, @@ -217,12 +217,12 @@ def test_tuning_orbit_correction(): frf_after = element_holder.rf.frequency.get() assert np.isclose(frf, frf_after, rtol=0, atol=1e-16) - element_holder.orbit.set_rf_weight(rf_weight) + element_holder.tool.orbit.set_rf_weight(rf_weight) # test getters of weights - assert np.isclose(element_holder.orbit.get_weight("BPM_C04-05", plane="H"), 1, rtol=0, atol=1e-16) - assert np.isclose(element_holder.orbit.get_virtual_weight(), 1, rtol=0, atol=1e-16) - assert np.isclose(element_holder.orbit.get_rf_weight(), rf_weight, rtol=0, atol=1e-16) + assert np.isclose(element_holder.tool.orbit.get_weight("BPM_C04-05", plane="H"), 1, rtol=0, atol=1e-16) + assert np.isclose(element_holder.tool.orbit.get_virtual_weight(), 1, rtol=0, atol=1e-16) + assert np.isclose(element_holder.tool.orbit.get_rf_weight(), rf_weight, rtol=0, atol=1e-16) def test_tuning_orbit_correction_config(): diff --git a/tests/tuning_tools/test_tuning_orm.py b/tests/tuning_tools/test_tuning_orm.py index 553bce161..3ea994f05 100644 --- a/tests/tuning_tools/test_tuning_orm.py +++ b/tests/tuning_tools/test_tuning_orm.py @@ -15,9 +15,9 @@ def test_tuning_orm(): sr = Accelerator.load(config_path) element_holder = sr.design - orm = element_holder.orm + orm = element_holder.tool.orm - bpms = element_holder.bpms.get("BPM") + bpms = element_holder.diagnostic.bpms.get("BPM") hcorr_names = element_holder.magnets.get("HCorr").names()[:4] vcorr_names = element_holder.magnets.get("VCorr").names()[:4] orm.measure(corrector_names=hcorr_names + vcorr_names) @@ -31,4 +31,4 @@ def test_tuning_orm(): orm.save(save_path=f.name) # load saved file - element_holder.orbit.load(f.name) + element_holder.tool.orbit.load(f.name) diff --git a/tests/tuning_tools/test_tuning_tools.py b/tests/tuning_tools/test_tuning_tools.py index 5c748b003..635142a2c 100644 --- a/tests/tuning_tools/test_tuning_tools.py +++ b/tests/tuning_tools/test_tuning_tools.py @@ -12,11 +12,11 @@ def callback(action: Action, data: dict): def test_tune_tool(): sr = Accelerator.load("tests/config/EBSTune.yaml", include_locations=False) sr.design.get_lattice().disable_6d() - sr.design.trm.measure(callback=callback) - sr.design.trm.save("tunemat.json") - sr.design.tune.load("tunemat.json") - sr.design.tune.set([0.17, 0.32], iter=2) - tune = sr.design.tune.readback() + sr.design.tool.trm.measure(callback=callback) + sr.design.tool.trm.save("tunemat.json") + sr.design.tool.tune.load("tunemat.json") + sr.design.tool.tune.set([0.17, 0.32], iter=2) + tune = sr.design.tool.tune.readback() assert np.abs(tune[0] - 0.17) < 1e-5 assert np.abs(tune[1] - 0.32) < 1e-5 @@ -24,20 +24,20 @@ def test_tune_tool(): def test_tune_add(): sr = Accelerator.load("tests/config/EBSTune.yaml", include_locations=False) sr.design.get_lattice().disable_6d() - sr.design.tune.load("tunemat.json") - tune_initial = sr.design.tune.readback() + sr.design.tool.tune.load("tunemat.json") + tune_initial = sr.design.tool.tune.readback() dtune = np.array([0.01, -0.01]) - sr.design.tune.add(dtune) - tune = sr.design.tune.readback() + sr.design.tool.tune.add(dtune) + tune = sr.design.tool.tune.readback() np.testing.assert_allclose(tune - tune_initial, dtune, atol=1e-5) def test_chroma_tool(): sr: Accelerator = Accelerator.load("tests/config/EBSOrbit.yaml", include_locations=False) sr.design.get_lattice().enable_6d() - sr.design.chromaticity.set([8.0, 5.0], iter=2) + sr.design.tool.chromaticity.set([8.0, 5.0], iter=2) QpAT = sr.design.get_lattice().get_chrom()[:-1] - Qp = sr.design.chromaticity.readback() + Qp = sr.design.tool.chromaticity.readback() assert np.abs(Qp[0] - 8.0) < 1e-3 assert np.abs(Qp[1] - 5.0) < 1e-3 assert np.abs(QpAT[0] - 8.0) < 1e-2 @@ -48,7 +48,7 @@ def test_chroma_add(): sr: Accelerator = Accelerator.load("tests/config/EBSOrbit.yaml", include_locations=False) sr.design.get_lattice().enable_6d() chromaAT = sr.design.get_lattice().get_chrom()[:-1] - sr.design.chromaticity.add([0.5, 0.4]) + sr.design.tool.chromaticity.add([0.5, 0.4]) chromaAT2 = sr.design.get_lattice().get_chrom()[:-1] chromaDiff = chromaAT2 - chromaAT assert np.abs(chromaDiff[0] - 0.5) < 5e-2