From cd1242efbb664ac3d0d38135809bbaa531b13090 Mon Sep 17 00:00:00 2001
From: Wouter Deconinck <wdconinc@gmail.com>
Date: Sun, 13 Feb 2022 17:13:03 +0000
Subject: [PATCH] Master into deathvalley

---
 .gitlab-ci.yml                          |   2 +-
 CMakeLists.txt                          |  10 +-
 README.md                               |  36 +++---
 bin/make_images                         |   8 +-
 calibrations/ffi_zdc.json               |  16 +++
 compact/display.xml                     |   2 +-
 compact/display_detailed.xml            |   2 +-
 compact/display_geoviewer.xml           |   2 +-
 compact/optical_materials.xml           |  16 +--
 compact/{erich.xml => pfrich.xml}       | 104 ++++++++---------
 compact/pid_config_canyonlands.xml      |   2 +-
 compact/pid_config_deathvalley.xml      |   2 +-
 compact/subsystem_views/pfrich_only.xml |   4 +-
 compact/subsystem_views/tof_only.xml    |  71 ++++++++++++
 compact/tracking_config_deathvalley.xml |   1 +
 src/FieldMapBrBz.cpp                    |  19 ++--
 src/FileLoader.cpp                      |  45 +++++---
 src/FileLoaderHelper.h                  | 143 ++++++++++++++++++++++++
 src/{PfRICH_geo.cpp => PFRICH_geo.cpp}  |  11 +-
 19 files changed, 373 insertions(+), 123 deletions(-)
 create mode 100644 calibrations/ffi_zdc.json
 rename compact/{erich.xml => pfrich.xml} (58%)
 create mode 100644 compact/subsystem_views/tof_only.xml
 create mode 100644 src/FileLoaderHelper.h
 rename src/{PfRICH_geo.cpp => PFRICH_geo.cpp} (97%)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d92a00ba..0115879d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -125,7 +125,7 @@ dump_geometry:
         dd_web_display --output geo/${geo_name} ${DETECTOR_PATH}/geo.xml
       done
     ## Lower-resolution display of the pfRICH sensors for global views
-    - sed -i 's/_default"\/>/_lores"\/>/' ${DETECTOR_PATH}/compact/erich.xml
+    - sed -i 's/_default"\/>/_lores"\/>/' ${DETECTOR_PATH}/compact/pfrich.xml
     ## full geo with downstream beamline
     - dd_web_display --output geo/detector_geo_full.root ${DETECTOR_PATH}/athena.xml
     ## only central detector geo
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 36e9c1ee..4bb91368 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,13 +10,11 @@ PROJECT(athena
   )
 
 set(CMAKE_CXX_STANDARD 17)
-find_package( DD4hep REQUIRED COMPONENTS DDCore DDG4)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
 
+find_package(DD4hep REQUIRED COMPONENTS DDCore DDG4)
 find_package(Acts REQUIRED COMPONENTS Core PluginIdentification PluginTGeo PluginDD4hep )
-
-find_package(fmt)
-#find_library(FMT_LIBRARY fmt)
-
+find_package(fmt REQUIRED)
 
 #-----------------------------------------------------------------------------------
 set(a_lib_name athena)
@@ -32,7 +30,7 @@ dd4hep_add_plugin(${a_lib_name} SOURCES
   src/CylinderTrackerBarrel_geo.cpp
   src/DIRC_geo.cpp
   src/DRICH_geo.cpp
-  src/PfRICH_geo.cpp
+  src/PFRICH_geo.cpp
   src/FileLoader.cpp
   src/FieldMapBrBz.cpp
   src/GaseousRICH_geo.cpp
diff --git a/README.md b/README.md
index 709c5c25..a79d0de5 100644
--- a/README.md
+++ b/README.md
@@ -3,32 +3,34 @@ Overview
 The Athena Detector at IP6 for Electron-Ion Collider experiment.
 
 **Detector geometry viewer:**
-- [Central detector](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/detector_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
-- [Full Detector (including beamline)](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/detector_geo_full.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY290;ROTZ350;trz0;trr0;ctrl;all)
-- [Inner detector (without calorimetry)](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/inner_detector_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
+- [Central detector](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/detector_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
+- [Full Detector (including beamline)](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/detector_geo_full.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY290;ROTZ350;trz0;trr0;ctrl;all)
+- [Inner detector (without calorimetry)](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/inner_detector_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
 - Subsystem views:
-  - [Calorimetry](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/calorimeters_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
-  - [PID](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/pid_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
-    - [dRICH](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/drich_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY290;ROTZ350;trz0;trr0;ctrl;all)
-    - [pfRICH](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/pfrich_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom55;ROTY49;ROTZ350;trz0;trr0;ctrl;all&)
-    - [DIRC](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/dirc_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
-  - [Tracking](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/tracking_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
-    - [Vertex detector](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/vertex_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
-  - [Far-forward](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/ip6_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom40;ROTY290;ROTZ350;trz0;trr0;ctrl;all)
-
-<a href="https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/images/view01.pdf?job=report">
-<img src="https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/images/view01.png?job=report" width="400px" />
+  - [Calorimetry](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/calorimeters_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
+  - [PID](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/pid_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
+    - [dRICH](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/drich_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY290;ROTZ350;trz0;trr0;ctrl;all)
+    - [pfRICH](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/pfrich_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom55;ROTY49;ROTZ350;trz0;trr0;ctrl;all&)
+    - [DIRC](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/dirc_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
+    - [ToF](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/tof_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom55;ROTY49;ROTZ350;trz0;trr0;ctrl;all&)
+  - [Tracking](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/tracking_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom75;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
+    - [Vertex detector](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/vertex_only_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom120;ROTY320;ROTZ340;trz0;trr0;ctrl;all)
+  - [Far-forward](https://eic.phy.anl.gov/geoviewer/index.htm?nobrowser&file=https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/geo/ip6_geo.root?job=dump_geometry&item=default;1&opt=clipx;clipy;transp30;zoom40;ROTY290;ROTZ350;trz0;trr0;ctrl;all)
+
+<a href="https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/images/view01.pdf?job=report">
+<img src="https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/images/view01.png?job=report" width="400px" />
 </a>
 
 <br />
-<a href="https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/images/view01_top.pdf?job=report">
-<img src="https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/images/view01_top.png?job=report" width="400px" />
+<a href="https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/images/view01_top.pdf?job=report">
+<img src="https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/images/view01_top.png?job=report" width="400px" />
 </a>
 
 [Browse latest](https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/browse/images?job=report)
 
-[Detector views](views/detector_views.md)
+[Detector views](https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/doc/dawn_views.md?job=report)
 
+[Constants listing](https://eicweb.phy.anl.gov/EIC/detectors/athena/-/jobs/artifacts/master/raw/doc/constants.out?job=report)
 
 Getting Started
 ---------------
diff --git a/bin/make_images b/bin/make_images
index 29a4a40e..5c49fdd6 100755
--- a/bin/make_images
+++ b/bin/make_images
@@ -7,9 +7,15 @@ env = Environment(
     autoescape=select_autoescape(['html', 'xml'])
 )
 
+import os
 import glob
 
-base_url = "https://eicweb.phy.anl.gov/api/v4/projects/390/jobs/artifacts/master/raw"
+if "CI_PROJECT_ID" in os.environ:
+    CI_PROJECT_ID = str(os.environ["CI_PROJECT_ID"])
+else:
+    CI_PROJECT_ID = "473"
+
+base_url = f"https://eicweb.phy.anl.gov/api/v4/projects/{CI_PROJECT_ID}/jobs/artifacts/master/raw"
 
 #images = ["images/view2a.png","images/view2b.png", "images/view1.png"]
 images = glob.glob("images/*.png")
diff --git a/calibrations/ffi_zdc.json b/calibrations/ffi_zdc.json
new file mode 100644
index 00000000..40ba1d69
--- /dev/null
+++ b/calibrations/ffi_zdc.json
@@ -0,0 +1,16 @@
+{
+    "ffi_zdc_ecal": {
+        "sampling_fraction": 1.0,
+        "minClusterCenterEdep": "3.*MeV",
+        "minClusterHitEdep": "0.1*MeV",
+        "localDistXY": ["50*mm", "50*mm"],
+        "splitCluster": true
+    },
+    "ffi_zdc_hcal": {
+        "sampling_fraction": 1.0,
+        "minClusterCenterEdep": "1.*MeV",
+        "minClusterHitEdep": "0.1*MeV",
+        "localDistXY": ["200*mm", "200*mm"],
+        "splitCluster": false
+    }
+}
diff --git a/compact/display.xml b/compact/display.xml
index ff97364d..55e19d52 100644
--- a/compact/display.xml
+++ b/compact/display.xml
@@ -137,7 +137,7 @@
     <vis name="DRICH_filter_vis"  alpha="1.0" r="1.0" g="1.0" b="0.0" showDaughters="true" visible="true" />
     <vis name="DRICH_mirror_vis"  ref="AnlGray" showDaughters="true" visible="true" />
     <vis name="DRICH_sensor_vis"  ref="AnlBlue" showDaughters="true" visible="true" />
-    <vis name="ERICH_sensor_vis"  ref="AnlBlue" showDaughters="true" visible="true" />
+    <vis name="PFRICH_sensor_vis" ref="AnlBlue" showDaughters="true" visible="true" />
 
     <vis name="MRICH_aerogel_vis" ref="AnlTeal" showDaughters="true" visible="true" />
     <vis name="MRICH_frame_vis" ref="AnlGold" showDaughters="true" visible="true" />
diff --git a/compact/display_detailed.xml b/compact/display_detailed.xml
index 2bebee61..9a2ba137 100644
--- a/compact/display_detailed.xml
+++ b/compact/display_detailed.xml
@@ -134,7 +134,7 @@
     <vis name="DRICH_filter_vis"  alpha="1.0" r="1.0" g="1.0" b="0.0" showDaughters="true" visible="true" />
     <vis name="DRICH_mirror_vis"  ref="AnlGray" showDaughters="true" visible="true" />
     <vis name="DRICH_sensor_vis"  ref="AnlGreen" showDaughters="true" visible="true" />
-    <vis name="ERICH_sensor_vis"  ref="AnlGreen" showDaughters="true" visible="true" /> 
+    <vis name="PFRICH_sensor_vis" ref="AnlGreen" showDaughters="true" visible="true" /> 
 
     <vis name="MRICH_aerogel_vis" ref="AnlTeal" showDaughters="true" visible="true" />
     <vis name="MRICH_frame_vis" ref="AnlGold" showDaughters="true" visible="true" />
diff --git a/compact/display_geoviewer.xml b/compact/display_geoviewer.xml
index 3998698d..3ea9a820 100644
--- a/compact/display_geoviewer.xml
+++ b/compact/display_geoviewer.xml
@@ -133,7 +133,7 @@
     <vis name="DRICH_filter_vis"  alpha="1.0" r="1.0" g="1.0" b="0.0" showDaughters="true" visible="true" />
     <vis name="DRICH_mirror_vis"  ref="AnlGray" showDaughters="true" visible="true" />
     <vis name="DRICH_sensor_vis"  ref="AnlGreen" showDaughters="true" visible="true" />
-    <vis name="ERICH_sensor_vis"  ref="AnlGreen" showDaughters="true" visible="true" /> <!-- invisible, to speedup graphics -->
+    <vis name="PFRICH_sensor_vis" ref="AnlGreen" showDaughters="true" visible="true" /> <!-- invisible, to speedup graphics -->
 
     <vis name="MRICH_aerogel_vis" ref="AnlTeal" showDaughters="true" visible="true" />
     <vis name="MRICH_frame_vis" ref="AnlGold" showDaughters="true" visible="true" />
diff --git a/compact/optical_materials.xml b/compact/optical_materials.xml
index 552ba5c4..0f7be147 100644
--- a/compact/optical_materials.xml
+++ b/compact/optical_materials.xml
@@ -373,7 +373,7 @@
       1240*eV/210  10*mm
       1240*eV/200  0*mm
       "/>
-    <!-- BEGIN dRICh and eRICh material properties
+    <!-- BEGIN dRICh and pfRICh material properties
          - dumped from fun4all implementation
          - see https://github.com/cisbani/dRICh/blob/main/share/source/g4dRIChOptics.hh
          -->
@@ -402,8 +402,8 @@
       4.85156*eV  10.0*m
       6.19921*eV  10.0*m
       "/>
-    <!-- eRICh gas -->
-    <matrix name="RINDEX__C4F10_ERICH" coldim="2" values="
+    <!-- pfRICh gas -->
+    <matrix name="RINDEX__C4F10_PFRICH" coldim="2" values="
       1.7712*eV   1.0013
       1.92389*eV  1.0013
       2.10539*eV  1.00131
@@ -415,7 +415,7 @@
       4.85156*eV  1.0014
       6.19921*eV  1.00149
       "/>
-    <matrix name="ABSLENGTH__C4F10_ERICH" coldim="2" values="
+    <matrix name="ABSLENGTH__C4F10_PFRICH" coldim="2" values="
       1.7712*eV   6.0*m
       1.92389*eV  6.0*m
       2.10539*eV  6.0*m
@@ -894,7 +894,7 @@
       <property name="RINDEX" ref="RINDEX__Acrylic"/>
       <property name="ABSLENGTH" ref="ABSLENGTH__Acrylic"/>
     </material>
-    <!-- BEGIN dRICh and eRICh material definitions -->
+    <!-- BEGIN dRICh and pfRICh material definitions -->
     <material name="C2F6_DRICH">
       <D type="density" value="0.005734" unit="g/cm3"/>
       <composite n="2" ref="C"/>
@@ -902,12 +902,12 @@
       <property name="RINDEX"    ref="RINDEX__C2F6_DRICH"/>
       <property name="ABSLENGTH" ref="ABSLENGTH__C2F6_DRICH"/>
     </material>
-    <material name="C4F10_ERICH">
+    <material name="C4F10_PFRICH">
       <D type="density" value="0.009935" unit="g/cm3"/>
       <composite n="4" ref="C"/>
       <composite n="10" ref="F"/>
-      <property name="RINDEX"    ref="RINDEX__C4F10_ERICH"/>
-      <property name="ABSLENGTH" ref="ABSLENGTH__C4F10_ERICH"/>
+      <property name="RINDEX"    ref="RINDEX__C4F10_PFRICH"/>
+      <property name="ABSLENGTH" ref="ABSLENGTH__C4F10_PFRICH"/>
     </material>
     <material name="Aerogel_DRICH_OLD">
       <D type="density" value="0.100" unit="g/cm3"/>
diff --git a/compact/erich.xml b/compact/pfrich.xml
similarity index 58%
rename from compact/erich.xml
rename to compact/pfrich.xml
index 6c57d1b4..2dbf6213 100644
--- a/compact/erich.xml
+++ b/compact/pfrich.xml
@@ -3,36 +3,36 @@
 
 <define>
 <!-- vessel geometry -->
-<constant name="ERICH_Length"             value="BackwardRICHRegion_length"/>  <!-- vessel z-length -->
-<constant name="ERICH_zmin"               value="-BackwardRICHRegion_zmin"/> <!-- vessel front -->
-<constant name="ERICH_zmax"               value="ERICH_zmin - ERICH_Length"/>  <!-- vessel back -->
-<constant name="ERICH_rmin0"              value="BackwardPIDRegion_tan * BackwardRICHRegion_zmin"/>  <!-- bore radius at vessel frontplane -->
-<constant name="ERICH_rmin1"              value="BackwardPIDRegion_tan * (BackwardRICHRegion_zmin + BackwardRICHRegion_length)"/>  <!-- bore radius at vessel backplane -->
-<constant name="ERICH_rmax"               value="BackwardPIDRegion_rmax - 2*cm"/>  <!-- vessel backplane radius -->
-<constant name="ERICH_wall_thickness"     value="0.5*cm"/>  <!-- thickness of radial walls -->
-<constant name="ERICH_window_thickness"   value="0.1*cm"/>  <!-- thickness of entrance and exit walls -->
+<constant name="PFRICH_Length"             value="BackwardRICHRegion_length"/>  <!-- vessel z-length -->
+<constant name="PFRICH_zmin"               value="-BackwardRICHRegion_zmin"/> <!-- vessel front -->
+<constant name="PFRICH_zmax"               value="PFRICH_zmin - PFRICH_Length"/>  <!-- vessel back -->
+<constant name="PFRICH_rmin0"              value="BackwardPIDRegion_tan * BackwardRICHRegion_zmin"/>  <!-- bore radius at vessel frontplane -->
+<constant name="PFRICH_rmin1"              value="BackwardPIDRegion_tan * (BackwardRICHRegion_zmin + BackwardRICHRegion_length)"/>  <!-- bore radius at vessel backplane -->
+<constant name="PFRICH_rmax"               value="BackwardPIDRegion_rmax - 2*cm"/>  <!-- vessel backplane radius -->
+<constant name="PFRICH_wall_thickness"     value="0.5*cm"/>  <!-- thickness of radial walls -->
+<constant name="PFRICH_window_thickness"   value="0.1*cm"/>  <!-- thickness of entrance and exit walls -->
 <!-- additional parameters -->
-<constant name="ERICH_aerogel_thickness"  value="3.0*cm"/>  <!-- aerogel thickness -->
-<constant name="ERICH_sensor_active_size_default" value="24.0*mm"/> <!-- sensor side length (effective area) -->
-<constant name="ERICH_sensor_full_size_default"   value="25.8*mm"/> <!-- sensor side length (full size, with enclosure) -->
+<constant name="PFRICH_aerogel_thickness"  value="3.0*cm"/>  <!-- aerogel thickness -->
+<constant name="PFRICH_sensor_active_size_default" value="24.0*mm"/> <!-- sensor side length (effective area) -->
+<constant name="PFRICH_sensor_full_size_default"   value="25.8*mm"/> <!-- sensor side length (full size, with enclosure) -->
 <!-- lores values are used for global vizualizations _only_ -->
-<constant name="ERICH_sensor_active_size_lores" value="ERICH_sensor_active_size_default * 4"/>
-<constant name="ERICH_sensor_full_size_lores" value="ERICH_sensor_full_size_default * 4"/>
+<constant name="PFRICH_sensor_active_size_lores" value="PFRICH_sensor_active_size_default * 4"/>
+<constant name="PFRICH_sensor_full_size_lores"   value="PFRICH_sensor_full_size_default * 4"/>
 <!-- actual values used by the parametrization -->
-<constant name="ERICH_sensor_active_size" value="ERICH_sensor_active_size_default"/>
-<constant name="ERICH_sensor_full_size" value="ERICH_sensor_full_size_default"/>
+<constant name="PFRICH_sensor_active_size" value="PFRICH_sensor_active_size_default"/>
+<constant name="PFRICH_sensor_full_size"   value="PFRICH_sensor_full_size_default"/>
 
 
-<constant name="ERICH_sensor_thickness"   value="1.5*mm"/> <!-- sensor thickness -->
-<constant name="ERICH_sensor_dist"        value="40*cm"/> <!-- distance between aerogel exit plane and sensor entrance plane -->
-<constant name="ERICH_num_px"             value="8"/> <!-- number of pixels along one side of the sensor -->
+<constant name="PFRICH_sensor_thickness"   value="1.5*mm"/> <!-- sensor thickness -->
+<constant name="PFRICH_sensor_dist"        value="40*cm"/> <!-- distance between aerogel exit plane and sensor entrance plane -->
+<constant name="PFRICH_num_px"             value="8"/> <!-- number of pixels along one side of the sensor -->
 <!-- debugging switches -->
 <comment>
-- `ERICH_debug_optics`:  1 = all components become vacuum; test opticalphotons from IP
+- `PFRICH_debug_optics`:  1 = all components become vacuum; test opticalphotons from IP
                          2 = all components become vacuum, except for `gasvol`, test charged particles from IP
                          0 = off
 </comment>
-<constant name="ERICH_debug_optics"  value="0"/>
+<constant name="PFRICH_debug_optics"  value="0"/>
 </define>
 
 
@@ -41,18 +41,18 @@
 
 <!-- /detectors/detector -->
 <documentation level="10">
-### eRICH: Electron Endcap RICH (name TBD)
+### pfRICH: Proximity Focusing RICH
 </documentation>
 <detector
   id="BackwardRICH_ID"
-  name="ERICH"
-  type="athena_ERICH"
-  readout="ERICHHits"
-  gas="C4F10_ERICH"
+  name="PFRICH"
+  type="athena_PFRICH"
+  readout="PFRICHHits"
+  gas="C4F10_PFRICH"
   material="Aluminum"
   vis_vessel="DRICH_vessel_vis"
   vis_gas="DRICH_gas_vis"
-  debug_optics="ERICH_debug_optics"
+  debug_optics="PFRICH_debug_optics"
   >
 
 
@@ -68,15 +68,15 @@
   - `window_thickness`: thickness of entrance and exit disks
 </documentation>
 <dimensions
-  zmin="ERICH_zmin"
-  zmax="ERICH_zmax"
-  length="ERICH_Length"
-  rmin0="ERICH_rmin0"
-  rmin1="ERICH_rmin1"
-  rmax0="ERICH_rmax"
-  rmax1="ERICH_rmax"
-  wall_thickness="ERICH_wall_thickness"
-  window_thickness="ERICH_window_thickness"
+  zmin="PFRICH_zmin"
+  zmax="PFRICH_zmax"
+  length="PFRICH_Length"
+  rmin0="PFRICH_rmin0"
+  rmin1="PFRICH_rmin1"
+  rmax0="PFRICH_rmax"
+  rmax1="PFRICH_rmax"
+  wall_thickness="PFRICH_wall_thickness"
+  window_thickness="PFRICH_window_thickness"
   />
 
 
@@ -94,16 +94,16 @@
   - `pitch`: controls the angle of the radiator (0=vertical)
 </documentation>
 <radiator
-  frontplane="-ERICH_window_thickness"
-  rmin="ERICH_rmin0 + ERICH_wall_thickness + 0.2*cm"
-  rmax="(ERICH_rmax/ERICH_zmax)*ERICH_zmin + 8.0*cm"
+  frontplane="-PFRICH_window_thickness"
+  rmin="PFRICH_rmin0 + PFRICH_wall_thickness + 0.2*cm"
+  rmax="(PFRICH_rmax/PFRICH_zmax)*PFRICH_zmin + 8.0*cm"
   phiw="60*degree"
   pitch="0*degree"
   >
   <aerogel
     material="Aerogel_DRICH"
     vis="DRICH_aerogel_vis"
-    thickness="ERICH_aerogel_thickness"
+    thickness="PFRICH_aerogel_thickness"
     />
   <filter
     material="Acrylic_DRICH"
@@ -139,10 +139,10 @@
 <module
   material="Silicon"
   surface="SensorSurface_DRICH"
-  vis="ERICH_sensor_vis"
-  side="ERICH_sensor_active_size"
-  thickness="ERICH_sensor_thickness"
-  gap="0.5*(ERICH_sensor_full_size-ERICH_sensor_active_size) + 0.5*mm"
+  vis="PFRICH_sensor_vis"
+  side="PFRICH_sensor_active_size"
+  thickness="PFRICH_sensor_thickness"
+  gap="0.5*(PFRICH_sensor_full_size-PFRICH_sensor_active_size) + 0.5*mm"
   />
 
 
@@ -156,9 +156,9 @@
     - `rmax`: maximum radial position of a sensor's centroid
 </documentation>
 <plane
-  sensordist="ERICH_sensor_dist"
-  rmin="ERICH_rmin1 + 2*cm"
-  rmax="ERICH_rmax  - 4*cm"
+  sensordist="PFRICH_sensor_dist"
+  rmin="PFRICH_rmin1 + 2*cm"
+  rmax="PFRICH_rmax  - 4*cm"
   />
 
 <services>
@@ -187,20 +187,20 @@
 
   | indicator | offset | length |
   |-----------|--------|--------|
-  | eRICH ID  | 0      | 8      |
+  | pfRICH ID | 0      | 8      |
   | sensor    | 8      | 12     |
   | x pixel   | 20     | 16     |
   | y pixel   | 36     | 16     |
 
 </documentation>
 <readouts>
-  <readout name="ERICHHits">
+  <readout name="PFRICHHits">
     <segmentation
       type="CartesianGridXY"
-      grid_size_x="ERICH_sensor_active_size/(ERICH_num_px-1)"
-      grid_size_y="ERICH_sensor_active_size/(ERICH_num_px-1)"
-      offset_x="-ERICH_sensor_active_size/2.0"
-      offset_y="-ERICH_sensor_active_size/2.0"
+      grid_size_x="PFRICH_sensor_active_size/(PFRICH_num_px-1)"
+      grid_size_y="PFRICH_sensor_active_size/(PFRICH_num_px-1)"
+      offset_x="-PFRICH_sensor_active_size/2.0"
+      offset_y="-PFRICH_sensor_active_size/2.0"
       />
     <id>system:8,module:12,x:20:16,y:16</id>
   </readout>
diff --git a/compact/pid_config_canyonlands.xml b/compact/pid_config_canyonlands.xml
index 75b30477..361fdfd7 100644
--- a/compact/pid_config_canyonlands.xml
+++ b/compact/pid_config_canyonlands.xml
@@ -3,6 +3,6 @@
 <include ref="fake_dirc.xml"/>
 <!--include ref="dirc.xml"/-->
 <include ref="drich.xml"/>
-<include ref="erich.xml"/>
+<include ref="pfrich.xml"/>
 
 </lccdd>
diff --git a/compact/pid_config_deathvalley.xml b/compact/pid_config_deathvalley.xml
index c0427fdd..9a3f18f8 100644
--- a/compact/pid_config_deathvalley.xml
+++ b/compact/pid_config_deathvalley.xml
@@ -3,7 +3,7 @@
 <include ref="fake_dirc.xml"/>
 <!--include ref="dirc.xml"/-->
 <include ref="drich.xml"/>
-<include ref="erich.xml"/>
+<include ref="pfrich.xml"/>
 
 <!--include ref="tof_endcap.xml"/-->
 <include ref="tof_barrel.xml"/>
diff --git a/compact/subsystem_views/pfrich_only.xml b/compact/subsystem_views/pfrich_only.xml
index 11971d74..3fd28f92 100644
--- a/compact/subsystem_views/pfrich_only.xml
+++ b/compact/subsystem_views/pfrich_only.xml
@@ -63,9 +63,9 @@
   </display>
 
   <documentation level="10">
-    ## eRICH only
+    ## pfRICH only
   </documentation>
   <include ref="ip6/beampipe.xml" />
-  <include ref="compact/erich.xml" />
+  <include ref="compact/pfrich.xml" />
 
 </lccdd>
diff --git a/compact/subsystem_views/tof_only.xml b/compact/subsystem_views/tof_only.xml
new file mode 100644
index 00000000..4392434c
--- /dev/null
+++ b/compact/subsystem_views/tof_only.xml
@@ -0,0 +1,71 @@
+<lccdd xmlns:compact="http://www.lcsim.org/schemas/compact/1.0"
+       xmlns:xs="http://www.w3.org/2001/XMLSchema"
+       xs:noNamespaceSchemaLocation="http://www.lcsim.org/schemas/compact/1.0/compact.xsd">
+
+       <debug>
+         <type name="surface"       value="0"/>
+         <type name="material"      value="0"/>
+         <type name="readout"       value="0"/>
+         <type name="segmentation"  value="0"/>
+         <type name="limits"        value="0"/>
+         <type name="region"        value="0"/>
+         <type name="includes"      value="0"/>
+       </debug>
+
+  <documentation level="-1">
+  # Athena Detector 
+  - https://eicweb.phy.anl.gov/EIC/detectors/athena.git 
+  - https://eicweb.phy.anl.gov/EIC/detectors/ip6.git
+  </documentation>
+
+  <!-- Some information about detector  -->
+  <info name="Athena Detector" title="Athena Detector"
+        author="Athena Collaboration"
+	url="https://eicweb.phy.anl.gov/EIC/detectors/athena.git"
+	status="development"
+	version="v1 2021-03-16">
+  <comment> Athena </comment>
+  </info>
+  <define>
+  <documentation level="2">
+      ## Main Constant Definitions
+
+      The ip6 (or other ip) defines should be included first.
+      These files have only a define tags.
+  </documentation>
+    <include ref="ip6/ip6_defs.xml" /> 
+    <include ref="ip6/far_forward_fields_275.xml" />
+    <include ref="compact/definitions.xml" />
+  </define>
+
+  <includes>
+    <gdmlFile ref="compact/elements.xml"/>
+    <gdmlFile ref="compact/materials.xml"/>
+    <file     ref="compact/optical_materials.xml"/>
+  </includes>
+
+  <limits>
+    <limitset name="EICBeamlineLimits">
+      <limit name="step_length_max" particles="*" value="1.0" unit="mm" />
+      <limit name="track_length_max" particles="*" value="1.0" unit="mm" />
+      <limit name="time_max" particles="*" value="0.1" unit="ns" />
+      <limit name="ekin_min" particles="*" value="0.001" unit="MeV" />
+      <limit name="range_min" particles="*" value="0.1" unit="mm" />
+    </limitset>
+    <limitset name="cal_limits">
+      <limit name="step_length_max" particles="*" value="5.0" unit="mm"/>
+    </limitset>
+  </limits>
+
+  <display>
+  <include ref="compact/colors.xml" />
+  <include ref="compact/display_detailed.xml" />
+  </display>
+
+  <documentation level="10">
+    ## TOF only
+  </documentation>
+  <include ref="ip6/beampipe.xml" />
+  <include ref="compact/tof_barrel.xml" />
+
+</lccdd>
diff --git a/compact/tracking_config_deathvalley.xml b/compact/tracking_config_deathvalley.xml
index bd6d93ed..d3276b6f 100644
--- a/compact/tracking_config_deathvalley.xml
+++ b/compact/tracking_config_deathvalley.xml
@@ -100,6 +100,7 @@
   </documentation>
   <plugins>
     <plugin name="FileLoader">
+      <arg value="cache:$DETECTOR_PATH"/>
       <arg value="file:calibrations/materials-map.cbor"/>
       <arg value="url:https://eicweb.phy.anl.gov/EIC/detectors/athena/uploads/4a4e7c8eb6089b634d762d112c89bd5d/material-maps.cbor"/>
     </plugin>
diff --git a/src/FieldMapBrBz.cpp b/src/FieldMapBrBz.cpp
index ddac9a9f..b3c5af11 100644
--- a/src/FieldMapBrBz.cpp
+++ b/src/FieldMapBrBz.cpp
@@ -1,5 +1,6 @@
 #include <DD4hep/DetFactoryHelper.h>
 #include <DD4hep/FieldTypes.h>
+#include <DD4hep/Printout.h>
 #include <XML/Utilities.h>
 
 #include <cstdlib>
@@ -12,6 +13,8 @@
 #include <tuple>
 namespace fs = std::filesystem;
 
+#include "FileLoaderHelper.h"
+
 using namespace dd4hep;
 
 
@@ -19,7 +22,7 @@ using namespace dd4hep;
 class FieldMapBrBz : public dd4hep::CartesianField::Object
 {
 public:
-    FieldMapBrBz(const std::string &field_type);
+    FieldMapBrBz(const std::string &field_type = "magnetic");
     void Configure(double rmin, double rmax, double rstep, double zmin, double zmax, double zstep);
     void LoadMap(const std::string &map_file, double scale);
     void GetIndices(double r, double z, int &ir, int &iz, double &dr, double &dz);
@@ -35,7 +38,7 @@ private:
 };
 
 // constructor
-FieldMapBrBz::FieldMapBrBz(const std::string &field_type = "magnetic")
+FieldMapBrBz::FieldMapBrBz(const std::string &field_type)
 {
     std::string ftype = field_type;
     for (auto &c : ftype) { c = tolower(c); }
@@ -185,20 +188,16 @@ static Ref_t create_field_map_brbz(Detector & /*lcdd*/, xml::Handle_t handle)
     std::string field_map_file = x_par.attr<std::string>(_Unicode(field_map));
     std::string field_map_url = x_par.attr<std::string>(_Unicode(url));
 
+    EnsureFileFromURLExists(field_map_url,field_map_file);
+
     double field_map_scale = x_par.attr<double>(_Unicode(scale));
 
     if( !fs::exists(fs::path(field_map_file))  ) {
-      auto ret = std::system(("mkdir -p fieldmaps && "
-                             "curl --retry 5 -f " +
-                             field_map_url + " -o " + field_map_file).c_str());
-
-      if (!fs::exists(fs::path(field_map_file))) {
-        std::cerr << "ERROR: file, " << field_map_file << ", does not exist\n";
+        printout(ERROR, "FieldMapBrBz", "file " + field_map_file + " does not exist");
+        printout(ERROR, "FieldMapBrBz", "use a FileLoader plugin before the field element");
         std::quick_exit(1);
-      }
     }
 
-
     auto map = new FieldMapBrBz(field_type);
     map->Configure(r_dim.rmin(), r_dim.rmax(), r_dim.step(), z_dim.zmin(), z_dim.zmax(), z_dim.step());
 
diff --git a/src/FileLoader.cpp b/src/FileLoader.cpp
index 3ab9bdc6..5ec0a922 100644
--- a/src/FileLoader.cpp
+++ b/src/FileLoader.cpp
@@ -1,22 +1,28 @@
 #include <DD4hep/DetFactoryHelper.h>
+#include <DD4hep/Primitives.h>
 #include <DD4hep/Factories.h>
 #include <DD4hep/Printout.h>
 #include <XML/Utilities.h>
 
+#include <fmt/core.h>
+
 #include <filesystem>
 #include <iostream>
+#include <cstdlib>
 #include <string>
 
-namespace fs = std::filesystem;
+#include "FileLoaderHelper.h"
 
 using namespace dd4hep;
 
-void usage(int argc, char** argv)    {
+void usage(int argc, char** argv) {
   std::cout <<
     "Usage: -plugin <name> -arg [-arg]                                                  \n"
     "     name:   factory name     FileLoader                                           \n"
+    "     cache:<string>           cache location (may be read-only)                    \n"
     "     file:<string>            file location                                        \n"
     "     url:<string>             url location                                         \n"
+    "     cmd:<string>             download command with {0} for url, {1} for output    \n"
     "\tArguments given: " << arguments(argc,argv) << std::endl;
   std::exit(EINVAL);
 }
@@ -27,24 +33,33 @@ long load_file(
     int argc,
     char** argv
 ) {
-  std::string file, url;
+  // argument parsing
+  std::string cache, file, url;
+  std::string cmd("curl --retry 5 -f {0} -o {1}");
   for (int i = 0; i < argc && argv[i]; ++i) {
-    if      (0 == std::strncmp("file:",argv[i], 5)) file = (argv[i] + 5);
-    else if (0 == std::strncmp("url:", argv[i], 4)) url  = (argv[i] + 4);
+    if      (0 == std::strncmp("cache:", argv[i], 6)) cache = (argv[i] + 6);
+    else if (0 == std::strncmp("file:", argv[i], 5)) file = (argv[i] + 5);
+    else if (0 == std::strncmp("url:", argv[i], 4)) url = (argv[i] + 4);
+    else if (0 == std::strncmp("cmd:", argv[i], 4)) cmd = (argv[i] + 4);
     else usage(argc, argv);
   }
-  std::cout << "Loading " << file << " from " << url << std::endl;
-
-  if (!fs::exists(fs::path(file))) {
-    std::string parent_path = fs::path(file).parent_path();
-    auto ret = std::system(("mkdir -p " + parent_path + " && "
-                            "curl --retry 5 -f " + url + " -o " + file).c_str());
-    if (!fs::exists(fs::path(file))) {
-      std::cerr << "ERROR: file, " << file << ", does not exist\n";
-      std::quick_exit(1);
-    }
+  printout(DEBUG, "FileLoader", "arg cache: " + cache);
+  printout(DEBUG, "FileLoader", "arg file: " + file);
+  printout(DEBUG, "FileLoader", "arg url: " + url);
+  printout(DEBUG, "FileLoader", "arg cmd: " + cmd);
+
+  // if file or url is empty, do nothing
+  if (file.empty()) {
+    printout(WARNING, "FileLoader", "no file specified");
+    return 0;
+  }
+  if (url.empty()) {
+    printout(WARNING, "FileLoader", "no url specified");
+    return 0;
   }
 
+  EnsureFileFromURLExists(url, file, cache, cmd);
+
   return 0;
 }
 
diff --git a/src/FileLoaderHelper.h b/src/FileLoaderHelper.h
new file mode 100644
index 00000000..0d84d2cb
--- /dev/null
+++ b/src/FileLoaderHelper.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#include <DD4hep/DetFactoryHelper.h>
+#include <DD4hep/Primitives.h>
+#include <DD4hep/Factories.h>
+#include <DD4hep/Printout.h>
+
+#include <fmt/core.h>
+
+#include <filesystem>
+#include <iostream>
+#include <cstdlib>
+#include <string>
+
+namespace fs = std::filesystem;
+
+using namespace dd4hep;
+
+// Function to download files
+inline void
+EnsureFileFromURLExists(
+  std::string url,
+  std::string file,
+  std::string cache = "",
+  std::string cmd = "curl --retry 5 -f {0} -o {1}"
+) {
+  // parse cache for environment variables
+  auto pos = std::string::npos;
+  while ((pos = cache.find('$')) != std::string::npos) {
+    auto after = cache.find_first_not_of(
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+      "abcdefghijklmnopqrstuvwxyz"
+      "0123456789"
+      "_",
+      pos + 1);
+    if (after == std::string::npos) after = cache.size(); // cache ends on env var
+    const std::string env_name(cache.substr(pos + 1, after - pos - 1));
+    auto env_ptr = std::getenv(env_name.c_str());
+    const std::string env_value(env_ptr != nullptr ? env_ptr : "");
+    cache.erase(pos, after - pos);
+    cache.insert(pos, env_value);
+    printout(INFO, "FileLoader", "$" + env_name + " -> " + env_value);
+  }
+
+  // create file path
+  fs::path file_path(file);
+
+  // create hash from url, hex of unsigned long long
+  std::string hash = fmt::format("{:016x}", dd4hep::detail::hash64(url)); // TODO: Use c++20 std::fmt
+
+  // create file parent path, if not exists
+  fs::path parent_path = file_path.parent_path();
+  if (!fs::exists(parent_path)) {
+    if (fs::create_directories(parent_path) == false) {
+      printout(ERROR, "FileLoader", "parent path " + parent_path.string() + " cannot be created");
+      printout(ERROR, "FileLoader", "check permissions and retry");
+      std::quick_exit(1);
+    }
+  }
+
+  // if file exists and is symlink to correct hash
+  fs::path hash_path(parent_path / hash);
+  if (fs::exists(file_path)
+   && fs::equivalent(file_path, hash_path)) {
+    printout(INFO, "FileLoader", "Link " + file + " -> hash " + hash + " already exists");
+    return;
+  }
+
+  // if hash does not exist, we try to retrieve file from cache
+  if (!fs::exists(hash_path)) {
+    // recursive loop into cache directory
+    fs::path cache_path(cache);
+    printout(INFO, "FileLoader", "Cache " + cache_path.string());
+    if (fs::exists(cache_path)) {
+      for (auto const& dir_entry: fs::recursive_directory_iterator(cache_path)) {
+        if (!dir_entry.is_directory()) continue;
+        fs::path cache_dir_path = cache_path / dir_entry;
+        printout(INFO, "FileLoader", "Checking " + cache_dir_path.string());
+        fs::path cache_hash_path = cache_dir_path / hash;
+        if (fs::exists(cache_hash_path)) {
+          // symlink hash to cache/.../hash
+          printout(INFO, "FileLoader", "File " + file + " with hash " + hash + " found in " + cache_hash_path.string());
+          try {
+            fs::create_symlink(cache_hash_path, hash_path);
+          } catch (const fs::filesystem_error&) {
+            printout(ERROR, "FileLoader", "unable to link from " + hash_path.string() + " to " + cache_hash_path.string());
+            printout(ERROR, "FileLoader", "check permissions and retry");
+            std::quick_exit(1);
+          }
+          break;
+        }
+      }
+    }
+  }
+
+  // if hash does not exist, we try to retrieve file from url
+  if (!fs::exists(hash_path)) {
+    cmd = fmt::format(cmd, url, hash_path.c_str()); // TODO: Use c++20 std::fmt
+    printout(INFO, "FileLoader", "Downloading " + file + " as hash " + hash + " with " + cmd);
+    // run cmd
+    auto ret = std::system(cmd.c_str());
+    if (!fs::exists(hash_path)) {
+      printout(ERROR, "FileLoader", "unable to run cmd " + cmd);
+      printout(ERROR, "FileLoader", "check command and retry");
+      std::quick_exit(1);
+    }
+  }
+
+  // check if file already exists
+  if (fs::exists(file_path)) {
+    // file already exists
+    if (fs::is_symlink(file_path)) {
+      // file is symlink
+      if (fs::equivalent(hash_path, fs::read_symlink(file_path))) {
+        // link points to correct path
+        return;
+      } else {
+        // link points to incorrect path 
+        if (fs::remove(file_path) == false) {
+          printout(ERROR, "FileLoader", "unable to remove symlink " + file_path.string());
+          printout(ERROR, "FileLoader", "check permissions or remove manually");
+          std::quick_exit(1);
+        }
+      }
+    } else {
+      // file exists but not symlink
+      printout(ERROR, "FileLoader", "will not remove actual file " + file_path.string());
+      printout(ERROR, "FileLoader", "check content, remove manually, and retry");
+      std::quick_exit(1);
+    }
+  }
+  // file_path now does not exist
+
+  // symlink file_path to hash_path
+  try {
+    // use new path from hash so file link is local
+    fs::create_symlink(fs::path(hash), file_path);
+  } catch (const fs::filesystem_error&) {
+    printout(ERROR, "FileLoader", "unable to link from " + file_path.string() + " to " + hash_path.string());
+    printout(ERROR, "FileLoader", "check permissions and retry");
+    std::quick_exit(1);
+  }
+}
diff --git a/src/PfRICH_geo.cpp b/src/PFRICH_geo.cpp
similarity index 97%
rename from src/PfRICH_geo.cpp
rename to src/PFRICH_geo.cpp
index 0878cc04..a6f71956 100644
--- a/src/PfRICH_geo.cpp
+++ b/src/PFRICH_geo.cpp
@@ -1,5 +1,5 @@
 //----------------------------------
-//  eRICH: Electron endcap RICH
+//  pfRICH: Proximity Focusing RICH
 //  Author: C. Dilks
 //----------------------------------
 
@@ -79,7 +79,7 @@ static Ref_t createDetector(Detector& desc, xml::Handle_t handle, SensitiveDetec
   // if debugging optics, override some settings
   bool debug_optics = debug_optics_mode > 0;
   if (debug_optics) {
-    printout(WARNING, "ERich_geo", "DEBUGGING ERICH OPTICS");
+    printout(WARNING, "PFRICH_geo", "DEBUGGING PFRICH OPTICS");
     switch (debug_optics_mode) {
     case 1:
       vesselMat = aerogelMat = filterMat = sensorMat = gasvolMat = desc.material("VacuumOptical");
@@ -88,7 +88,7 @@ static Ref_t createDetector(Detector& desc, xml::Handle_t handle, SensitiveDetec
       vesselMat = aerogelMat = filterMat = sensorMat = desc.material("VacuumOptical");
       break;
     default:
-      printout(FATAL, "ERich_geo", "UNKNOWN debug_optics_mode");
+      printout(FATAL, "PFRICH_geo", "UNKNOWN debug_optics_mode");
       return det;
     };
     aerogelVis = sensorVis;
@@ -96,7 +96,7 @@ static Ref_t createDetector(Detector& desc, xml::Handle_t handle, SensitiveDetec
   };
 
   // BUILD VESSEL //////////////////////////////////////
-  /* - `vessel`: aluminum enclosure, the mother volume of the eRICh
+  /* - `vessel`: aluminum enclosure, the mother volume of the pfRICH
    * - `gasvol`: gas volume, which fills `vessel`; all other volumes defined below
    *   are children of `gasvol`
    */
@@ -313,5 +313,4 @@ static Ref_t createDetector(Detector& desc, xml::Handle_t handle, SensitiveDetec
 };
 
 // clang-format off
-DECLARE_DETELEMENT(athena_PfRICH, createDetector)
-DECLARE_DETELEMENT(athena_ERICH, createDetector)
+DECLARE_DETELEMENT(athena_PFRICH, createDetector)
-- 
GitLab