LDMX Software
ecal::EcalPnetVetoProcessor Class Reference

Determines if event is vetoable using ECAL hit information w/ a deep neural network. More...

#include <EcalPnetVetoProcessor.h>

Public Member Functions

 EcalPnetVetoProcessor (const std::string &name, framework::Process &process)
 
void configure (framework::config::Parameters &parameters) override
 Callback for the EventProcessor to configure itself from the given set of parameters.
 
void produce (framework::Event &event) override
 Process the event and put new data products into it.
 
- Public Member Functions inherited from framework::Producer
 Producer (const std::string &name, Process &process)
 Class constructor.
 
virtual void process (Event &event) final
 Processing an event for a Producer is calling produce.
 
- Public Member Functions inherited from framework::EventProcessor
 DECLARE_FACTORY (EventProcessor, EventProcessor *, const std::string &, Process &)
 declare that we have a factory for this class
 
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()=default
 Class destructor.
 
virtual void beforeNewRun (ldmx::RunHeader &run_header)
 Callback for Producers to add parameters to the run header before conditions are initialized.
 
virtual void onNewRun (const ldmx::RunHeader &run_header)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a event input ROOT file is closed.
 
virtual void onProcessStart ()
 Callback for the EventProcessor to take any necessary action when the processing of events starts, such as creating histograms.
 
virtual void onProcessEnd ()
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
template<class T >
const T & getCondition (const std::string &condition_name)
 Access a conditions object for the current event.
 
TDirectory * getHistoDirectory ()
 Access/create a directory in the histogram file for this event processor to create histograms and analysis tuples.
 
void setStorageHint (framework::StorageControl::Hint hint)
 Mark the current event as having the given storage control hint from this module_.
 
void setStorageHint (framework::StorageControl::Hint hint, const std::string &purposeString)
 Mark the current event as having the given storage control hint from this module and the given purpose string.
 
int getLogFrequency () const
 Get the current logging frequency from the process.
 
int getRunNumber () const
 Get the run number from the process.
 
std::string getName () const
 Get the processor name.
 
void createHistograms (const std::vector< framework::config::Parameters > &histos)
 Internal function which is used to create histograms passed from the python configuration @parma histos vector of Parameters that configure histograms to create.
 

Private Member Functions

void makeInputs (const ldmx::EcalGeometry &geom, const std::vector< ldmx::EcalHit > &ecalRecHits, std::array< double, 3 > etraj, std::array< double, 3 > enorm)
 Make inputs to the DNN from ECAL RecHits.
 
std::vector< float > logSoftmax (const std::vector< float > &logits)
 Transform logits to a probability.
 

Private Attributes

double disc_cut_logit_ {0}
 disc_cut as a logit difference, the probability saturates in float
 
std::vector< std::vector< float > > data_
 
std::unique_ptr< ldmx::ort::ONNXRuntime > rt_
 
std::string collection_name_ {"EcalPnetVeto"}
 Name of the collection which will containt the results.
 
std::string rec_coll_name_
 
std::string ecal_rec_hits_passname_
 
std::string ecal_sp_coll_name_
 
std::string ecal_sp_hits_passname_
 
std::string track_pass_name_
 
std::string track_collection_
 
bool recoil_from_tracking_
 

Static Private Attributes

static constexpr unsigned int MAX_NUM_HITS = 300
 Maximum number of hits allowed in ECAL.
 
static constexpr unsigned int N_COORDINATE_DIM = 3
 
static constexpr unsigned int COORDINATE_X_OFFSET = 0
 
static constexpr unsigned int COORDINATE_Y_OFFSET = MAX_NUM_HITS
 
static constexpr unsigned int COORDINATE_Z_OFFSET = 2 * MAX_NUM_HITS
 
static constexpr unsigned int N_FEATURE_DIM = 5
 
static constexpr unsigned int FEATURE_X_OFFSET = 0
 
static constexpr unsigned int FEATURE_Y_OFFSET = MAX_NUM_HITS
 
static constexpr unsigned int FEATURE_Z_OFFSET = 2 * MAX_NUM_HITS
 
static constexpr unsigned int FEATURE_ENERGY_OFFSET = 3 * MAX_NUM_HITS
 
static constexpr unsigned int FEATURE_LAYER_ID_OFFSET = 4 * MAX_NUM_HITS
 
static const std::vector< std::string > INPUT_NAMES
 
static const std::vector< unsigned int > INPUT_SIZES
 

Additional Inherited Members

- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from framework::EventProcessor
HistogramPool histograms_
 helper object for making and filling histograms
 
NtupleManager & ntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Determines if event is vetoable using ECAL hit information w/ a deep neural network.

Definition at line 25 of file EcalPnetVetoProcessor.h.

Constructor & Destructor Documentation

◆ EcalPnetVetoProcessor()

ecal::EcalPnetVetoProcessor::EcalPnetVetoProcessor ( const std::string & name,
framework::Process & process )

Definition at line 19 of file EcalPnetVetoProcessor.cxx.

21 : Producer(name, process) {
22 for (const auto& s : INPUT_SIZES) {
23 data_.emplace_back(s, 0);
24 }
25}
Producer(const std::string &name, Process &process)
Class constructor.
virtual void process(Event &event) final
Processing an event for a Producer is calling produce.

Member Function Documentation

◆ configure()

void ecal::EcalPnetVetoProcessor::configure ( framework::config::Parameters & parameters)
overridevirtual

Callback for the EventProcessor to configure itself from the given set of parameters.

The parameters a processor has access to are the member variables of the python class in the sequence that has class_name equal to the EventProcessor class name.

For an example, look at MyProcessor.

Parameters
parametersParameters for configuration.

Reimplemented from framework::EventProcessor.

Definition at line 27 of file EcalPnetVetoProcessor.cxx.

28 {
29 auto disc_cut = parameters.get<double>("disc_cut");
30 disc_cut_logit_ = disc_cut <= 0 ? -std::numeric_limits<double>::infinity()
31 : std::log(disc_cut / (1. - disc_cut));
32 rt_ = std::make_unique<ldmx::ort::ONNXRuntime>(
33 parameters.get<std::string>("model_path"));
34
35 // Set the collection name as defined in the configuration
36 collection_name_ = parameters.get<std::string>("collection_name");
37
38 rec_coll_name_ = parameters.get<std::string>("rec_coll_name");
39 ecal_rec_hits_passname_ =
40 parameters.get<std::string>("ecal_rec_hits_passname");
41 ecal_sp_coll_name_ = parameters.get<std::string>("ecal_sp_coll_name");
42 ecal_sp_hits_passname_ = parameters.get<std::string>("ecal_sp_hits_passname");
43 track_pass_name_ = parameters.get<std::string>("track_pass_name", "");
44 track_collection_ = parameters.get<std::string>("track_collection");
45 recoil_from_tracking_ = parameters.get<bool>("recoil_from_tracking");
46}
std::string collection_name_
Name of the collection which will containt the results.
double disc_cut_logit_
disc_cut as a logit difference, the probability saturates in float
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75

References framework::config::Parameters::get().

◆ logSoftmax()

std::vector< float > ecal::EcalPnetVetoProcessor::logSoftmax ( const std::vector< float > & logits)
private

Transform logits to a probability.

Parameters
logitsVector of logits
Returns
Vector of log softmax probabilities

Definition at line 218 of file EcalPnetVetoProcessor.cxx.

219 {
220 // Find max for numerical stability
221 auto max_val = *std::max_element(logits.begin(), logits.end());
222
223 // Compute shifted exponentials and their sum
224 std::vector<float> exp_vals(logits.size());
225 for (size_t i = 0; i < logits.size(); ++i) {
226 exp_vals[i] = std::exp(logits[i] - max_val);
227 }
228
229 float sum_exp = std::accumulate(exp_vals.begin(), exp_vals.end(), 0.0);
230 float log_sum_exp = max_val + std::log(sum_exp);
231
232 // Compute log_softmax
233 std::vector<float> result(logits.size());
234 for (size_t i = 0; i < logits.size(); ++i) {
235 result[i] = logits[i] - log_sum_exp;
236 }
237
238 return result;
239}

◆ makeInputs()

void ecal::EcalPnetVetoProcessor::makeInputs ( const ldmx::EcalGeometry & geom,
const std::vector< ldmx::EcalHit > & ecalRecHits,
std::array< double, 3 > etraj,
std::array< double, 3 > enorm )
private

Make inputs to the DNN from ECAL RecHits.

Parameters
ecalRecHitsThe EcalHit collection.

Definition at line 169 of file EcalPnetVetoProcessor.cxx.

172 {
173 // clear data
174 for (auto& v : data_) {
175 std::fill(v.begin(), v.end(), 0);
176 }
177
178 // Loop on the rechits
179 unsigned idx = 0;
180 for (const auto& hit : ecal_rec_hits) {
181 if (hit.getEnergy() <= 0) {
182 ldmx_log(warn)
183 << "Hit with zero energy found, should not happen, skipping it.";
184 continue;
185 }
186 ldmx::EcalID id(hit.getID());
187 auto [hit_x, hit_y, hit_z] = geom.getPosition(id);
188
189 double delta_z = hit_z - etraj[2];
190 double etraj_x = etraj[0] + enorm[0] * delta_z;
191 double etraj_y = etraj[1] + enorm[1] * delta_z;
192 data_[0].at(COORDINATE_X_OFFSET + idx) = hit_x - etraj_x;
193 data_[0].at(COORDINATE_Y_OFFSET + idx) = hit_y - etraj_y;
194 data_[0].at(COORDINATE_Z_OFFSET + idx) = hit_z;
195
196 data_[1].at(FEATURE_X_OFFSET + idx) = hit_x - etraj_x;
197 data_[1].at(FEATURE_Y_OFFSET + idx) = hit_y - etraj_y;
198 data_[1].at(FEATURE_Z_OFFSET + idx) = hit_z;
199 data_[1].at(FEATURE_LAYER_ID_OFFSET + idx) = id.layer();
200 data_[1].at(FEATURE_ENERGY_OFFSET + idx) = std::log(hit.getEnergy());
201
202 ++idx;
203 }
204
205 std::stringstream ss;
206 for (unsigned iname = 0; iname < INPUT_NAMES.size(); ++iname) {
207 ss << "=== " << INPUT_NAMES[iname] << " ===";
208 for (unsigned i = 0; i < INPUT_SIZES[iname]; ++i) {
209 ss << data_[iname].at(i) << ", ";
210 if ((i + 1) % MAX_NUM_HITS == 0) {
211 ss << "\n\n";
212 }
213 }
214 }
215 ldmx_log(trace) << ss.str();
216} // end of make inputs
static constexpr unsigned int MAX_NUM_HITS
Maximum number of hits allowed in ECAL.
std::tuple< double, double, double > getPosition(EcalID id) const
Get a cell's position from its ID number.
Extension of DetectorID providing access to ECal layers and cell numbers in a hex grid.
Definition EcalID.h:20

References ldmx::EcalGeometry::getPosition().

◆ produce()

void ecal::EcalPnetVetoProcessor::produce ( framework::Event & event)
overridevirtual

Process the event and put new data products into it.

Parameters
eventThe Event to process.

Implements framework::Producer.

Definition at line 48 of file EcalPnetVetoProcessor.cxx.

48 {
50 // Get the Ecal Geometry
51 const auto& ecal_geometry = getCondition<ldmx::EcalGeometry>(
52 ldmx::EcalGeometry::CONDITIONS_OBJECT_NAME);
53
54 // Get the collection of digitized Ecal hits_ from the event.
55 const auto ecal_rec_hits = event.getCollection<ldmx::EcalHit>(
56 rec_coll_name_, ecal_rec_hits_passname_);
57 auto nhits = std::count_if(
58 ecal_rec_hits.begin(), ecal_rec_hits.end(),
59 [](const ldmx::EcalHit& hit) { return hit.getEnergy() > 0; });
60
61 // check number of hits_
62 ldmx_log(debug) << "nhits = " << nhits << " MAX_NUM_HITS = " << MAX_NUM_HITS;
63 if (nhits < MAX_NUM_HITS) {
64 std::array<double, 3> etraj = {-999., -999., -999.};
65 std::array<double, 3> enorm = {-999., -999., -999.};
66 // Compute electron trajectory}
67 const ldmx::SimTrackerHit* electron_hit = nullptr;
68 // Use Scoring Plane or Tracking
69 if (!recoil_from_tracking_ &&
70 event.exists(ecal_sp_coll_name_, ecal_sp_hits_passname_)) {
71 auto const& ecal_sp_hits = event.getCollection<ldmx::SimTrackerHit>(
72 ecal_sp_coll_name_, ecal_sp_hits_passname_);
73 double electron_pz_max = -1.0;
74 for (auto const& hit : ecal_sp_hits) {
75 // Look at the electron only
76 if (hit.getPdgID() != 11) continue;
77 double electron_z = hit.getPosition()[2];
78 // Look at the SP in front of the ECAL
79 if (electron_z <= 239.0 || electron_z >= 240.0) continue;
80 double electron_pz = hit.getMomentum()[2];
81 // Find the highest pz electron
82 if (electron_pz > electron_pz_max) {
83 electron_pz_max = electron_pz;
84 electron_hit = &hit;
85 }
86 }
87 // If we found an electron hit at the scoring plane
88 if (electron_hit) {
89 // Get electron hit position/momentum at Ecal surface
90 ldmx_log(debug) << "Electron Found in the Ecal SP!";
91 auto pos = electron_hit->getPosition();
92 auto mom = electron_hit->getMomentum();
93 ldmx_log(debug) << "ECAL SP pos_=(" << pos[0] << "," << pos[1] << ","
94 << pos[2] << ")";
95 ldmx_log(debug) << "ECAL SP mom=(" << mom[0] << "," << mom[1] << ","
96 << mom[2] << ")";
97 etraj = {pos[0], pos[1], pos[2]};
98 double pz = mom[2];
99 if (pz != 0) {
100 // z_-normalized momentum
101 enorm = {mom[0] / pz, mom[1] / pz, 1.0};
102 }
103 }
104 } else if (recoil_from_tracking_) {
105 // Use tracking to get electron hit position/momentum at Ecal surface
106 auto recoil_tracks{event.getCollection<ldmx::Track>(track_collection_,
107 track_pass_name_)};
108 ldmx::TrackStateType ts_at_ecal = ldmx::AtECAL;
109 auto recoil_track_states_ecal =
110 ecal::trackProp(recoil_tracks, ts_at_ecal, "ecal");
111 if (!recoil_track_states_ecal.empty()) {
112 std::array<double, 3> pos = {recoil_track_states_ecal[0],
113 recoil_track_states_ecal[1],
114 recoil_track_states_ecal[2]};
115 std::array<double, 3> mom = {(recoil_track_states_ecal[3]),
116 (recoil_track_states_ecal[4]),
117 (recoil_track_states_ecal[5])};
118 ldmx_log(debug) << "Electron track pos_=(" << pos[0] << "," << pos[1]
119 << "," << pos[2] << ")";
120 ldmx_log(debug) << "Electron track mom=(" << mom[0] << "," << mom[1]
121 << "," << mom[2] << ")";
122 etraj = pos;
123 double pz = mom[2];
124 if (pz != 0) {
125 enorm = {mom[0] / pz, mom[1] / pz, 1.0};
126 }
127 } else {
128 ldmx_log(info) << " No recoil track at ECAL";
129 }
130 } else {
131 ldmx_log(fatal) << " No electron hit at scoring plane or no tracking";
132 }
133
134 if (etraj[0] == -999.) {
135 // no trajectory, the model was trained on tracked events only
136 result.setDiscValue(-99);
137 result.setVetoResult(false);
138 } else {
139 // make inputs
140 makeInputs(ecal_geometry, ecal_rec_hits, etraj, enorm);
141 // run the DNN
142 auto logits = rt_->run(INPUT_NAMES, data_)[0];
143 // make a log softmax of the logits then transform back
144 // to a probability with an exponential
145 auto prob = std::exp((logSoftmax(logits)[1]));
146 result.setDiscValue(prob);
147 // cut on the logit difference, prob is 1 in float above ~17
148 double logit_diff = logits[1] - logits[0];
149 ldmx_log(debug) << "ParticleNet logit difference = " << logit_diff;
150 result.setVetoResult(logit_diff > disc_cut_logit_);
151 }
152 } else {
153 result.setDiscValue(-99);
154 result.setVetoResult(false);
155 }
156
157 ldmx_log(debug) << "ParticleNet disc value = " << result.getDisc();
158
159 // If the event passes the veto, keep it. Otherwise, drop the event.
160 if (result.passesVeto()) {
162 } else {
164 }
165
166 event.add(collection_name_, result);
167}
std::vector< float > trackProp(const ldmx::Tracks &tracks, ldmx::TrackStateType ts_type, const std::string &ts_title)
Return a vector of parameters for a propagated recoil track.
Definition EcalHelper.cxx:8
std::vector< float > logSoftmax(const std::vector< float > &logits)
Transform logits to a probability.
void makeInputs(const ldmx::EcalGeometry &geom, const std::vector< ldmx::EcalHit > &ecalRecHits, std::array< double, 3 > etraj, std::array< double, 3 > enorm)
Make inputs to the DNN from ECAL RecHits.
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
void setStorageHint(framework::StorageControl::Hint hint)
Mark the current event as having the given storage control hint from this module_.
bool exists(const std::string &name, const std::string &passName, bool unique=true) const
Check for the existence of an object or collection with the given name and pass name in the event.
Definition Event.cxx:107
Stores reconstructed hit information from the ECAL.
Definition EcalHit.h:19
bool passesVeto() const
Checks if the event passes the Ecal veto.
Represents a simulated tracker hit in the simulation.
std::vector< float > getPosition() const
Get the XYZ position of the hit [mm].
std::vector< double > getMomentum() const
Get the XYZ momentum of the particle at the position at which the hit took place [MeV].
Implementation of a track object.
Definition Track.h:54
constexpr StorageControl::Hint HINT_SHOULD_DROP
storage control hint alias for backwards compatibility
constexpr StorageControl::Hint HINT_SHOULD_KEEP
storage control hint alias for backwards compatibility

References framework::Event::exists(), ldmx::SimTrackerHit::getMomentum(), ldmx::SimTrackerHit::getPosition(), framework::HINT_SHOULD_DROP, framework::HINT_SHOULD_KEEP, ldmx::EcalVetoResult::passesVeto(), and ecal::trackProp().

Member Data Documentation

◆ collection_name_

std::string ecal::EcalPnetVetoProcessor::collection_name_ {"EcalPnetVeto"}
private

Name of the collection which will containt the results.

Definition at line 74 of file EcalPnetVetoProcessor.h.

74{"EcalPnetVeto"};

◆ COORDINATE_X_OFFSET

unsigned int ecal::EcalPnetVetoProcessor::COORDINATE_X_OFFSET = 0
staticconstexprprivate

Definition at line 54 of file EcalPnetVetoProcessor.h.

◆ COORDINATE_Y_OFFSET

unsigned int ecal::EcalPnetVetoProcessor::COORDINATE_Y_OFFSET = MAX_NUM_HITS
staticconstexprprivate

Definition at line 55 of file EcalPnetVetoProcessor.h.

◆ COORDINATE_Z_OFFSET

unsigned int ecal::EcalPnetVetoProcessor::COORDINATE_Z_OFFSET = 2 * MAX_NUM_HITS
staticconstexprprivate

Definition at line 56 of file EcalPnetVetoProcessor.h.

◆ data_

std::vector<std::vector<float> > ecal::EcalPnetVetoProcessor::data_
private

Definition at line 70 of file EcalPnetVetoProcessor.h.

◆ disc_cut_logit_

double ecal::EcalPnetVetoProcessor::disc_cut_logit_ {0}
private

disc_cut as a logit difference, the probability saturates in float

Definition at line 69 of file EcalPnetVetoProcessor.h.

69{0};

◆ ecal_rec_hits_passname_

std::string ecal::EcalPnetVetoProcessor::ecal_rec_hits_passname_
private

Definition at line 77 of file EcalPnetVetoProcessor.h.

◆ ecal_sp_coll_name_

std::string ecal::EcalPnetVetoProcessor::ecal_sp_coll_name_
private

Definition at line 78 of file EcalPnetVetoProcessor.h.

◆ ecal_sp_hits_passname_

std::string ecal::EcalPnetVetoProcessor::ecal_sp_hits_passname_
private

Definition at line 79 of file EcalPnetVetoProcessor.h.

◆ FEATURE_ENERGY_OFFSET

unsigned int ecal::EcalPnetVetoProcessor::FEATURE_ENERGY_OFFSET = 3 * MAX_NUM_HITS
staticconstexprprivate

Definition at line 62 of file EcalPnetVetoProcessor.h.

◆ FEATURE_LAYER_ID_OFFSET

unsigned int ecal::EcalPnetVetoProcessor::FEATURE_LAYER_ID_OFFSET = 4 * MAX_NUM_HITS
staticconstexprprivate

Definition at line 63 of file EcalPnetVetoProcessor.h.

◆ FEATURE_X_OFFSET

unsigned int ecal::EcalPnetVetoProcessor::FEATURE_X_OFFSET = 0
staticconstexprprivate

Definition at line 59 of file EcalPnetVetoProcessor.h.

◆ FEATURE_Y_OFFSET

unsigned int ecal::EcalPnetVetoProcessor::FEATURE_Y_OFFSET = MAX_NUM_HITS
staticconstexprprivate

Definition at line 60 of file EcalPnetVetoProcessor.h.

◆ FEATURE_Z_OFFSET

unsigned int ecal::EcalPnetVetoProcessor::FEATURE_Z_OFFSET = 2 * MAX_NUM_HITS
staticconstexprprivate

Definition at line 61 of file EcalPnetVetoProcessor.h.

◆ INPUT_NAMES

const std::vector< std::string > ecal::EcalPnetVetoProcessor::INPUT_NAMES
staticprivate
Initial value:
{"points",
"features"}

Definition at line 65 of file EcalPnetVetoProcessor.h.

◆ INPUT_SIZES

const std::vector< unsigned int > ecal::EcalPnetVetoProcessor::INPUT_SIZES
staticprivate
Initial value:
{
N_COORDINATE_DIM * MAX_NUM_HITS, N_FEATURE_DIM* MAX_NUM_HITS}

Definition at line 66 of file EcalPnetVetoProcessor.h.

◆ MAX_NUM_HITS

unsigned int ecal::EcalPnetVetoProcessor::MAX_NUM_HITS = 300
staticconstexprprivate

Maximum number of hits allowed in ECAL.

Events with more hits will be marked as BKG directly without running ParticleNet.

Definition at line 51 of file EcalPnetVetoProcessor.h.

◆ N_COORDINATE_DIM

unsigned int ecal::EcalPnetVetoProcessor::N_COORDINATE_DIM = 3
staticconstexprprivate

Definition at line 53 of file EcalPnetVetoProcessor.h.

◆ N_FEATURE_DIM

unsigned int ecal::EcalPnetVetoProcessor::N_FEATURE_DIM = 5
staticconstexprprivate

Definition at line 58 of file EcalPnetVetoProcessor.h.

◆ rec_coll_name_

std::string ecal::EcalPnetVetoProcessor::rec_coll_name_
private

Definition at line 76 of file EcalPnetVetoProcessor.h.

◆ recoil_from_tracking_

bool ecal::EcalPnetVetoProcessor::recoil_from_tracking_
private

Definition at line 82 of file EcalPnetVetoProcessor.h.

◆ rt_

std::unique_ptr<ldmx::ort::ONNXRuntime> ecal::EcalPnetVetoProcessor::rt_
private

Definition at line 71 of file EcalPnetVetoProcessor.h.

◆ track_collection_

std::string ecal::EcalPnetVetoProcessor::track_collection_
private

Definition at line 81 of file EcalPnetVetoProcessor.h.

◆ track_pass_name_

std::string ecal::EcalPnetVetoProcessor::track_pass_name_
private

Definition at line 80 of file EcalPnetVetoProcessor.h.


The documentation for this class was generated from the following files: