diff --git a/fcl/caf/cafmaker_add_detsim2d_icarus.fcl b/fcl/caf/cafmaker_add_detsim2d_icarus.fcl index f766c1f57..969eb4e7a 100644 --- a/fcl/caf/cafmaker_add_detsim2d_icarus.fcl +++ b/fcl/caf/cafmaker_add_detsim2d_icarus.fcl @@ -10,5 +10,8 @@ physics.producers.mcreco.G4ModName: @erase physics.producers.mcreco.MCParticleLabel: "largeant" physics.producers.mcreco.SimChannelLabel: "daq:simpleSC" -this_cal_constants: [1.343e-2, 1.338e-2, 0.01227] +# Mini production, pre signal shape tuning +# this_cal_constants: [1.343e-2, 1.338e-2, 0.01227] +# Post signal shape tuning +this_cal_constants: [1.343e-2, 1.338e-2, 0.01285] #include "set_caf_calconst.fcl" diff --git a/fcl/detsim/detsim_2d_icarus_fitFR.fcl b/fcl/detsim/detsim_2d_icarus_fitFR.fcl new file mode 100644 index 000000000..0efb5f5af --- /dev/null +++ b/fcl/detsim/detsim_2d_icarus_fitFR.fcl @@ -0,0 +1,3 @@ +#include "detsim_2d_icarus.fcl" + +physics.producers.daq: @local::icarus_simwire_wirecell_fitSR diff --git a/icaruscode/TPC/ICARUSWireCell/detsimmodules_wirecell_ICARUS.fcl b/icaruscode/TPC/ICARUSWireCell/detsimmodules_wirecell_ICARUS.fcl index 4a801d6f6..9c6993c62 100644 --- a/icaruscode/TPC/ICARUSWireCell/detsimmodules_wirecell_ICARUS.fcl +++ b/icaruscode/TPC/ICARUSWireCell/detsimmodules_wirecell_ICARUS.fcl @@ -34,6 +34,7 @@ icarus_simwire_wirecell: // Make available parameters via Jsonnet's std.extVar() params: { files_fields: "garfield-icarus-fnal-rev1.json.bz2" + file_rcresp: "" # use the RCResponse by default } structs: { # load values from simulationservices_icarus.fcl @@ -49,9 +50,35 @@ icarus_simwire_wirecell: # Scaling Parameters from int and coh noise components int_noise_scale: 1.0 coh_noise_scale: 1.09 + + # Gain and shaping time + gain0: 14.9654 # mV/fC + gain1: 14.9654 # mV/fC + gain2: 14.9654 # mV/fC + + shaping0: 1.3 # us + shaping1: 1.3 # us + shaping2: 1.3 # us + + # Time offsets for truth matching + time_offset_u: 1.0 # us + time_offset_v: 1.0 # us + time_offset_y: 1.0 # us + } } } +icarus_simwire_wirecell_fitSR: @local::icarus_simwire_wirecell +# Add in the ER tail +icarus_simwire_wirecell_fitSR.wcls_main.params.file_rcresp: "icarus_fnal_rc_tail.json" +# Add in the tuned field responses +icarus_simwire_wirecell_fitSR.wcls_main.params.files_fields: "icarus_fnal_fit_ks.json.bz2" +# futz with shaping+gain values (note these are really just scale factors and should not be taken literally) +icarus_simwire_wirecell_fitSR.wcls_main.structs.gain0: 10.2636323 # mV/fC +icarus_simwire_wirecell_fitSR.wcls_main.structs.gain1: 12.1420344 # mV/fC +icarus_simwire_wirecell_fitSR.wcls_main.structs.gain2: 13.0261362 # mV/fC +icarus_simwire_wirecell_fitSR.wcls_main.structs.shaping1: 1.45 # us + END_PROLOG diff --git a/icaruscode/TPC/ICARUSWireCell/icarus/icarus_tools.jsonnet b/icaruscode/TPC/ICARUSWireCell/icarus/icarus_tools.jsonnet new file mode 100644 index 000000000..2e0d72a04 --- /dev/null +++ b/icaruscode/TPC/ICARUSWireCell/icarus/icarus_tools.jsonnet @@ -0,0 +1,171 @@ +// This file provides a function which takes a params object (see +// ../params/) and returns a data structure with a number of +// sub-objects that may configure various WCT "tool" type componets +// which are not INodes. + +// Some attributes are merely default and you may wish to override +// them. For example, the default IDFT FftwDFT and to instead ues +// TorchDFT you may do something like: +// +// local default_tools = tools_maker(params) +// local tools = std.mergePatch(default_tools, +// {dft: {type: "TorchDFT", data: {device: "gpu"}}}); +// + +local wc = import "wirecell.jsonnet"; + +function(params) +{ + // The IRandom pRNG + random : { + type: "Random", + data: { + generator: "default", + seeds: [0,1,2,3,4], + } + }, + // The IDFT FFT implementation + dft : { + type: "FftwDFT", + }, + + // One FR per field file. + fields : std.mapWithIndex(function (n, fname) { + type: "FieldResponse", + name: "field%d"%n, + data: { filename: fname } + }, params.files.fields), + + field: $.fields[0], // the nominal field + + // The number of ticks for response waveforms. For simulation + // this must be enlarged beyond what is wanted in the output + // readout in order to accept catch early activity into the first + // few readout ticks. When responses are used to deconvolve then + // this should best be shortened. Note: sigproc at time of + // writing did not use components for Elec or RC so are not + // currently subject to this config. + local sim_response_binning = { + tick: params.daq.tick, + nticks: params.sim.ductor.nticks, // MUST match ductor + }, + + perchanresp : { + type: "PerChannelResponse", + data: { + filename: params.files.chresp, + } + }, + // It's a little awkward to NOT use PerChannelResponse because you + // need to give an empty string to a component that wants to use + // it an an empty list to the "uses". Here we package that little + // "if" branch. It's a general pattern not specific to this + // object. Might want to make wc.tn() convert "null" into "" and + // g.uses() convert [null] into []. + perchanresp_nameuses : if std.type(params.files.chresp) == 'null' + then {name:"", uses:[]} + else {name:wc.tn(self.perchanresp), uses:[self.perchanresp]}, + + + wires : { + type: "WireSchemaFile", + data: { filename: params.files.wires } + }, + + elec_resp : std.mapWithIndex(function (n, e) { + type: if std.objectHas(e, "type") + then e.type + else "ColdElecResponse", // default + name: "Plane%iElectronicsResponse" % n, + data: sim_response_binning { + shaping: e.shaping, + gain: e.gain, + postgain: e.postgain, + filename: if std.objectHas(e, "filename") + then e.filename + else "" + }, + }, params.elec), + + rc_resp : { + type: if std.objectHas(params, 'rc_resp') && std.objectHas(params.rc_resp, "type") + then params.rc_resp.type + else "RCResponse", // default + data: std.prune(sim_response_binning { + width: if std.objectHas(params, 'rc_resp') && std.objectHas(params.rc_resp, 'width') + then params.rc_resp.width else null, + + filename: if std.objectHas(params, 'rc_resp') && std.objectHas(params.rc_resp, 'filename') + then params.rc_resp.filename else null, + + postgain: if std.objectHas(params, 'rc_resp') && std.objectHas(params.rc_resp, 'postgain') + then params.rc_resp.postgain else null, + + start: if std.objectHas(params, 'rc_resp') && std.objectHas(params.rc_resp, 'start') + then params.rc_resp.start else null, + }) + }, + + + sys_resp : { + type: "ResponseSys", + data: sim_response_binning { + start: params.sys_resp.start, + magnitude: params.sys_resp.magnitude, + time_smear: params.sys_resp.time_smear, + } + }, + + // there is one trio of PIRs (one per wire plane in a face) for + // each field response. WARNING/fixme: this sets the default DFT + // with no way to override! This config structure needs a redo! + pirs : std.mapWithIndex(function (n, fr) [ + { + type: "PlaneImpactResponse", + name : "PIR%splane%d" % [fr.name, plane], + data : sim_response_binning { + plane: plane, + dft: wc.tn($.dft), + field_response: wc.tn(fr), + // note twice we give rc so we have rc^2 in the final convolution + short_responses: if params.sys_status == false + then [wc.tn($.elec_resp[plane])] + else [wc.tn($.elec_resp[plane]), wc.tn($.sys_resp)], + overall_short_padding: if std.objectHas(params, 'overall_short_padding') + then params.overall_short_padding + else if params.sys_status == false + then 0.1*wc.ms + // cover the full time range of the convolved short responses + else 0.1*wc.ms - params.sys_resp.start, + // long_responses: [wc.tn($.rc_resp), wc.tn($.rc_resp)], + long_responses: if std.objectHas(params, 'rc_resp') + then std.makeArray(params.rc_resp.rc_layers, function(x) wc.tn($.rc_resp)) + else [wc.tn($.rc_resp), wc.tn($.rc_resp)], + long_padding: 1.5*wc.ms, + }, + uses: [$.dft, fr, $.elec_resp[plane], $.rc_resp, $.sys_resp], + } for plane in [0,1,2]], $.fields), + + // One anode per detector "volume" + anodes : [{ + type : "AnodePlane", + name : vol.name, + data : { + // This ID is used to pick out which wires in the + // WireSchema belong to this anode plane. + ident : vol.wires, + nimpacts: params.sim.nimpacts, + // The wire schema file + wire_schema: wc.tn($.wires), + + faces : vol.faces, + }, + uses: [$.wires], + } for vol in params.det.volumes], + + // Arbitrarily call out the first anode to make single-anode + // detector config slightly cleaner. + anode: $.anodes[0], + +} + diff --git a/icaruscode/TPC/ICARUSWireCell/icarus/params.jsonnet b/icaruscode/TPC/ICARUSWireCell/icarus/params.jsonnet index 8c14af849..9acd1faba 100644 --- a/icaruscode/TPC/ICARUSWireCell/icarus/params.jsonnet +++ b/icaruscode/TPC/ICARUSWireCell/icarus/params.jsonnet @@ -84,15 +84,16 @@ base { fullscale: [0.8*wc.millivolt, 3.3*wc.volt], }, - elec: super.elec { + elec: [super.elec { type: "WarmElecResponse", - // gain: 17.8075*wc.mV/wc.fC, // 0.027 fC/(ADC*us) - // Set gain to (roughly) match data ADC values (docdb 25161) + // Old values: + // ICARUS nominal: 17.8075*wc.mV/wc.fC // 0.027 fC/(ADC*us) + // Match data ADC values (docdb 25161): 14.9654*wc.mV/wc.fC, // 0.0321 fC/(ADC*us) gain: 14.9654*wc.mV/wc.fC, // 0.0321 fC/(ADC*us) shaping: 1.3*wc.us, postgain: 1.0, start: 0, - }, + }, for _ in [0, 1, 2]], sim: super.sim { diff --git a/icaruscode/TPC/ICARUSWireCell/icarus/simparams.jsonnet b/icaruscode/TPC/ICARUSWireCell/icarus/simparams.jsonnet index 80e53eebb..dd9b0619b 100644 --- a/icaruscode/TPC/ICARUSWireCell/icarus/simparams.jsonnet +++ b/icaruscode/TPC/ICARUSWireCell/icarus/simparams.jsonnet @@ -39,15 +39,6 @@ base { // chresp: null, //}, - // This sets a relative gain at the input to the ADC. Note, if - // you are looking to fix SimDepoSource, you are in the wrong - // place. See the "scale" parameter of wcls.input.depos() defined - // in pgrapher/common/ui/wcls/nodes.jsonnet. - elec: super.elec { - // postgain: 1.0, - // shaping: 2.2 * wc.us, - }, - sys_status: false, sys_resp: { // overall_short_padding should take into account this offset "start". @@ -56,8 +47,8 @@ base { time_smear: 1.0 * wc.us, }, - rc_resp: { - width: 1.1*wc.ms, - rc_layers: 1, - } + rc_resp: { + width: 1.1*wc.ms, + rc_layers: 1, + } } diff --git a/icaruscode/TPC/ICARUSWireCell/icarus/wcls-decode-to-sig.jsonnet b/icaruscode/TPC/ICARUSWireCell/icarus/wcls-decode-to-sig.jsonnet index 5fe7ec897..f7ecc2f79 100644 --- a/icaruscode/TPC/ICARUSWireCell/icarus/wcls-decode-to-sig.jsonnet +++ b/icaruscode/TPC/ICARUSWireCell/icarus/wcls-decode-to-sig.jsonnet @@ -41,7 +41,7 @@ local params = params_init { }, }; -local tools_maker = import 'pgrapher/common/tools.jsonnet'; +local tools_maker = import 'pgrapher/experiment/icarus/icarus_tools.jsonnet'; local tools = tools_maker(params); local wcls_maker = import 'pgrapher/ui/wcls/nodes.jsonnet'; diff --git a/icaruscode/TPC/ICARUSWireCell/icarus/wcls-multitpc-sim-drift-simchannel-omit-noise.jsonnet b/icaruscode/TPC/ICARUSWireCell/icarus/wcls-multitpc-sim-drift-simchannel-omit-noise.jsonnet index 0fd6b5521..de5bbfdd9 100644 --- a/icaruscode/TPC/ICARUSWireCell/icarus/wcls-multitpc-sim-drift-simchannel-omit-noise.jsonnet +++ b/icaruscode/TPC/ICARUSWireCell/icarus/wcls-multitpc-sim-drift-simchannel-omit-noise.jsonnet @@ -7,7 +7,7 @@ local f = import 'pgrapher/common/funcs.jsonnet'; local wc = import 'wirecell.jsonnet'; local io = import 'pgrapher/common/fileio.jsonnet'; -local tools_maker = import 'pgrapher/common/tools.jsonnet'; +local tools_maker = import 'pgrapher/experiment/icarus/tools.jsonnet'; // local params = import 'pgrapher/experiment/icarus/simparams.jsonnet'; local base = import 'pgrapher/experiment/icarus/simparams.jsonnet'; local params = base { diff --git a/icaruscode/TPC/ICARUSWireCell/icarus/wcls-multitpc-sim-drift-simchannel.jsonnet b/icaruscode/TPC/ICARUSWireCell/icarus/wcls-multitpc-sim-drift-simchannel.jsonnet index 0d90c1e46..1ed8feb43 100644 --- a/icaruscode/TPC/ICARUSWireCell/icarus/wcls-multitpc-sim-drift-simchannel.jsonnet +++ b/icaruscode/TPC/ICARUSWireCell/icarus/wcls-multitpc-sim-drift-simchannel.jsonnet @@ -7,9 +7,28 @@ local f = import 'pgrapher/common/funcs.jsonnet'; local wc = import 'wirecell.jsonnet'; local io = import 'pgrapher/common/fileio.jsonnet'; -local tools_maker = import 'pgrapher/common/tools.jsonnet'; +local tools_maker = import 'pgrapher/experiment/icarus/icarus_tools.jsonnet'; // local params = import 'pgrapher/experiment/icarus/simparams.jsonnet'; local base = import 'pgrapher/experiment/icarus/simparams.jsonnet'; + +// load the electronics response parameters +local er_params = [ + { + gain: std.extVar('gain0')*wc.mV/wc.fC, + shaping: std.extVar('shaping0')*wc.us, + }, + + { + gain: std.extVar('gain1')*wc.mV/wc.fC, + shaping: std.extVar('shaping1')*wc.us, + }, + + { + gain: std.extVar('gain2')*wc.mV/wc.fC, + shaping: std.extVar('shaping2')*wc.us, + }, +]; + local params = base { lar: super.lar { // Longitudinal diffusion constant @@ -24,6 +43,25 @@ local params = base { files: super.files { fields: [ std.extVar('files_fields'), ], }, + + rc_resp: if std.extVar('file_rcresp') != "" then + { + // "icarus_fnal_rc_tail.json" + filename: std.extVar('file_rcresp'), + postgain: 1.0, + start: 0.0, + tick: 0.4*wc.us, + nticks: 4255, + type: "JsonElecResponse", + rc_layers: 1 + } + else super.rc_resp, + + elec: std.mapWithIndex(function (n, eparam) + super.elec[n] + { + gain: eparam.gain, + shaping: eparam.shaping, + }, er_params), }; local tools = tools_maker(params); @@ -181,15 +219,15 @@ local wcls_simchannel_sink = g.pnode({ // GP: The shaping time of the electronics response (1.3us) shifts the peak // of the field response time. Eyeballing simulation times, it does this - // by a bit less than the 1.3us. + // by a bit less than the 1.3us (1us). // // N.B. for future: there is likely an additional offset on the two induction // planes due to where the deconvolution precisely defines where the "peak" // of the pulse is. One may want to refine these parameters to account for that. // This perturbation shouldn't be more than a tick or two. - u_time_offset: 1.0 * wc.us, - v_time_offset: 1.0 * wc.us, - y_time_offset: 1.0 * wc.us, + u_time_offset: std.extVar('time_offset_u') * wc.us, + v_time_offset: std.extVar('time_offset_v') * wc.us, + y_time_offset: std.extVar('time_offset_y') * wc.us, g4_ref_time: -1500 * wc.us, // G4RefTime from detectorclocks_icarus.fcl use_energy: true, diff --git a/icaruscode/TPC/ICARUSWireCell/icarus/wcls-sim-drift-simchannel.jsonnet b/icaruscode/TPC/ICARUSWireCell/icarus/wcls-sim-drift-simchannel.jsonnet index 3c67b55ab..9571169b4 100644 --- a/icaruscode/TPC/ICARUSWireCell/icarus/wcls-sim-drift-simchannel.jsonnet +++ b/icaruscode/TPC/ICARUSWireCell/icarus/wcls-sim-drift-simchannel.jsonnet @@ -11,7 +11,7 @@ local f = import 'pgrapher/common/funcs.jsonnet'; local wc = import 'wirecell.jsonnet'; local io = import 'pgrapher/common/fileio.jsonnet'; -local tools_maker = import 'pgrapher/common/tools.jsonnet'; +local tools_maker = import 'pgrapher/experiment/icarus/tools.jsonnet'; local params = import 'pgrapher/experiment/icarus/simparams.jsonnet'; local tools = tools_maker(params); diff --git a/icaruscode/TPC/ICARUSWireCell/icarus/wct-sim-check.jsonnet b/icaruscode/TPC/ICARUSWireCell/icarus/wct-sim-check.jsonnet index d474dd0b4..5d1e26576 100644 --- a/icaruscode/TPC/ICARUSWireCell/icarus/wct-sim-check.jsonnet +++ b/icaruscode/TPC/ICARUSWireCell/icarus/wct-sim-check.jsonnet @@ -7,7 +7,7 @@ local f = import 'pgrapher/common/funcs.jsonnet'; local wc = import 'wirecell.jsonnet'; local io = import 'pgrapher/common/fileio.jsonnet'; -local tools_maker = import 'pgrapher/common/tools.jsonnet'; +local tools_maker = import 'pgrapher/experiment/icarus/icarus_tools.jsonnet'; local params = import 'pgrapher/experiment/icarus/simparams.jsonnet'; local tools = tools_maker(params);