26 #include "art/Utilities/ToolConfigTable.h"
27 #include "art/Utilities/ToolMacros.h"
28 #include "canvas/Utilities/Exception.h"
29 #include "fhiclcpp/types/OptionalAtom.h"
30 #include "fhiclcpp/types/Atom.h"
31 #include "cetlib/search_path.h"
32 #include "cetlib_except/exception.h"
40 namespace icarus::opdet {
struct SampledWaveformFunctionTool; }
108 Name(
"WaveformData"),
109 Comment(
"Path to the data file with the SPR information")
114 Comment(
"peak time from the beginning of the waveform [ns]")
117 fhicl::OptionalAtom<float>
Gain {
119 Comment(
"PMT amplification gain factor")
157 (std::string
const&
path);
172 std::ifstream srcFile { path };
173 if (!srcFile.is_open()) {
175 throw art::Exception{ art::errors::FileReadError }
176 <<
"Can't open single photoelectron response file '" << path <<
"'\n";
187 auto makeException = [
path]()
189 return cet::exception{
"SampledWaveformFunctionTool" }
190 <<
"in '" << path <<
"': ";
195 if (
auto const* item = data.findItem(
"Name")) {
196 if (item->nValues() != 1) {
197 throw makeException() <<
"'Name' must have exactly 1 entry, not "
198 << item->nValues() <<
"!\n";
200 specs.
name = item->value();
203 if (
auto const* item = data.findItem(
"Description")) {
204 if (item->nValues() != 1) {
205 throw makeException()
206 <<
"'Description' must have exactly 1 entry (possibly quoted), not "
207 << item->nValues() <<
"!\n";
212 if (
auto const* item = data.findItem(
"Date")) {
213 if (item->nValues() != 1) {
214 throw makeException()
215 <<
"'Date' must have exactly 1 entry (possibly quoted), not "
216 << item->nValues() <<
"!\n";
218 specs.
date = item->value();
221 if (
auto const* item = data.findItem(
"Version")) {
222 if (item->nValues() != 1) {
223 throw makeException()
224 <<
"'Version' must have exactly 1 entry, not " << item->nValues()
228 specs.
version = item->getNumber<
unsigned int>(0);
231 throw makeException() <<
"value in 'Version' ('" << item->value()
232 <<
"') can't be interpreted as version number (unsigned int):\n"
237 if (
auto const* item = data.findItem(
"Tick")) {
238 if (item->nValues() != 1) {
239 throw makeException()
240 <<
"'Date' must have exactly 1 entry (possibly quoted), not "
241 << item->nValues() <<
"!\n";
245 = util::quantities::makeQuantity<nanoseconds>(item->value());
247 catch(std::runtime_error
const&
e) {
248 throw makeException()
249 <<
"Failed to parse 'Tick' ('" << item->value() <<
"') as a time:\n"
253 else throw makeException() <<
"'Tick' entry is mandatory.\n";
255 if (
auto const* item = data.findItem(
"Gain")) {
256 if (item->nValues() != 1) {
257 throw makeException()
258 <<
"'Gain' must have exactly 1 entry, not " << item->nValues() <<
"!\n";
261 specs.
gain = item->getNumber<
float>(0);
264 throw makeException() <<
"value in 'Gain' ('" << item->value()
265 <<
"') can't be interpreted as a gain factor:\n"
271 if (
auto const* item = data.findItem(
"Samples")) {
272 if (item->nValues() < 2) {
273 throw makeException()
274 <<
"'Samples' has only " << item->nValues() <<
" values!!\n";
277 specs.
samples = item->getVector<
float>();
280 throw makeException()
281 <<
"Error converting values in 'Samples' into voltage:\n"
285 else throw makeException() <<
"'Samples' entry is mandatory.\n";
288 if (
auto const* item = data.findItem(
"NSamples")) {
289 if (item->nValues() != 1) {
290 throw makeException()
291 <<
"'NSamples' must have exactly 1 entry, not " << item->nValues()
294 unsigned int nSamples;
296 nSamples = item->getNumber<
unsigned int>(0);
299 throw makeException() <<
"value in 'NSamples' ('" << item->value()
300 <<
"') can't be interpreted as a sample number (unsigned int):\n"
303 if (specs.
samples.size() != nSamples) {
304 throw makeException() <<
"'Samples' has " << specs.
samples.size()
305 <<
" values, but according to 'NSamples' there should be " << nSamples
316 (
Config const& config) -> std::unique_ptr<PulseFunction_t>
322 cet::search_path searchPath{
"FW_SEARCH_PATH" };
323 std::string waveformSpecsPath;
325 waveformSpecsPath = searchPath.find_file(config.
WaveformData());
327 catch (cet::exception&
e) {
328 throw art::Exception{ art::errors::Configuration,
"", e }
329 <<
"Error looking for the waveform data file '" << config.
WaveformData()
330 <<
"' (configured via: '" << config.
WaveformData.name() <<
"')\n";
334 = extractWaveformSpecification(waveformSpecsPath);
339 if ((config.
Gain().value_or(0.0) != 0.0) && (waveformSpecs.
gain == 0.0)) {
340 throw art::Exception(art::errors::Configuration)
341 <<
"The single photoelectron response '" << waveformSpecs.
name
342 <<
"' at '" << waveformSpecsPath
343 <<
"' does not specify a base gain, so it can't be rescaled to "
344 << config.
Gain().value()
345 <<
" ('" << config.
Gain.name() <<
"' parameter)\n";
347 float const reqGain = (config.
Gain().value_or(0.0) != 0.0)
348 ? config.
Gain().value(): waveformSpecs.
gain;
353 return std::make_unique<MyFunction_t>(
354 std::move(waveformSpecs)
Simple parser for "key: value" text.
Dimensioned variables representing electromagnetic quantities.
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
Simple parsed data format.
Utilities to read and write quantities in FHiCL configuration.
Collection of items with key/values structure.
Parser to fill a KeyValuesData structure out of a character buffer.
BEGIN_PROLOG vertical distance to the surface Name
Test of util::counter and support utilities.
Numeric variable proxies with embedded unit of measurement.