LDMX Software
Public Member Functions | Private Attributes | List of all members
recon::ParticleFlow Class Reference

Public Member Functions

 ParticleFlow (const std::string &name, framework::Process &process)
 
virtual void configure (framework::config::Parameters &ps)
 Callback for the EventProcessor to configure itself from the given set of parameters.
 
virtual void produce (framework::Event &event)
 Process the event and put new data products into it.
 
virtual void onProcessEnd ()
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
void fillCandTrack (ldmx::PFCandidate &cand, const ldmx::SimTrackerHit &tk)
 
void fillCandEMCalo (ldmx::PFCandidate &cand, const ldmx::CaloCluster &em)
 
void fillCandHadCalo (ldmx::PFCandidate &cand, const ldmx::CaloCluster &had)
 
- Public Member Functions inherited from framework::Producer
 Producer (const std::string &name, Process &process)
 Class constructor.
 
virtual void beforeNewRun (ldmx::RunHeader &header)
 Handle allowing producers to modify run headers before the run begins.
 
- Public Member Functions inherited from framework::EventProcessor
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()
 Class destructor.
 
virtual void onNewRun (const ldmx::RunHeader &runHeader)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &eventFile)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &eventFile)
 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.
 
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 Attributes

TGraph * eCorr_ {0}
 
TGraph * hCorr_ {0}
 
std::string inputEcalCollName_
 
std::string inputHcalCollName_
 
std::string inputTrackCollName_
 
std::string outputCollName_
 
bool singleParticle_
 

Additional Inherited Members

- Static Public Member Functions inherited from framework::EventProcessor
static void declare (const std::string &classname, int classtype, EventProcessorMaker *)
 Internal function which is part of the PluginFactory machinery.
 
- Static Public Attributes inherited from framework::Producer
static const int CLASSTYPE {1}
 Constant used to track EventProcessor types by the PluginFactory.
 
- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from framework::EventProcessor
HistogramHelper histograms_
 Interface class for making and filling histograms.
 
NtupleManagerntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger theLog_
 The logger for this EventProcessor.
 

Detailed Description

Definition at line 28 of file ParticleFlow.h.

Constructor & Destructor Documentation

◆ ParticleFlow()

recon::ParticleFlow::ParticleFlow ( const std::string &  name,
framework::Process process 
)
inline

Definition at line 30 of file ParticleFlow.h.

31 : framework::Producer(name, process) {}
Base class for a module which produces a data product.

Member Function Documentation

◆ configure()

void recon::ParticleFlow::configure ( framework::config::Parameters parameters)
virtual

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 className equal to the EventProcessor class name.

For an example, look at MyProcessor.

Parameters
parametersParameters for configuration.

Reimplemented from framework::EventProcessor.

Definition at line 7 of file ParticleFlow.cxx.

7 {
8 // I/O
9 inputEcalCollName_ = ps.getParameter<std::string>("inputEcalCollName");
10 inputHcalCollName_ = ps.getParameter<std::string>("inputHcalCollName");
11 inputTrackCollName_ = ps.getParameter<std::string>("inputTrackCollName");
12 outputCollName_ = ps.getParameter<std::string>("outputCollName");
13 // Algorithm configuration
14 singleParticle_ = ps.getParameter<bool>("singleParticle");
15
16 // Calibration factors, from jason, temperary
17 std::vector<float> em1{250.0, 750.0, 1250.0, 1750.0, 2250.0, 2750.0,
18 3250.0, 3750.0, 4250.0, 4750.0, 5250.0, 5750.};
19 std::vector<float> em2{1.175, 1.02, 0.99, 0.985, 0.975, 0.975,
20 0.96, 0.94, 0.87, 0.8, 0.73, 0.665};
21 std::vector<float> h1{25.0, 75.0, 125.0, 175.0, 225.0,
22 275.0, 325.0, 375.0, 425.0};
23 std::vector<float> h2{8.44, 7.38, 7.76, 8.535, 9.47,
24 10.45, 10.47, 9.71, 8.87};
25 eCorr_ = new TGraph(em1.size(), em1.data(), em2.data());
26 hCorr_ = new TGraph(h1.size(), h1.data(), h2.data());
27}

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

◆ fillCandEMCalo()

void recon::ParticleFlow::fillCandEMCalo ( ldmx::PFCandidate cand,
const ldmx::CaloCluster em 
)

Definition at line 53 of file ParticleFlow.cxx.

54 {
55 float corr = 1.;
56 float e = em.getEnergy();
57 if (e < eCorr_->GetX()[0]) {
58 corr = eCorr_->GetX()[0];
59 } else if (e > eCorr_->GetX()[eCorr_->GetN() - 1]) {
60 corr = eCorr_->GetX()[eCorr_->GetN() - 1];
61 } else {
62 corr = eCorr_->Eval(e);
63 }
64 cand.setEcalEnergy(e * corr);
65 cand.setEcalRawEnergy(e);
66 cand.setEcalClusterXYZ(em.getCentroidX(), em.getCentroidY(),
67 em.getCentroidZ());
68 cand.setEcalClusterEXYZ(em.getRMSX(), em.getRMSY(), em.getRMSZ());
69 cand.setEcalClusterDXDZ(em.getDXDZ());
70 cand.setEcalClusterDYDZ(em.getDYDZ());
71 cand.setEcalClusterEDXDZ(em.getEDXDZ());
72 cand.setEcalClusterEDYDZ(em.getEDYDZ());
73 cand.setPID(cand.getPID() | 2); // OR with 010
74}

◆ fillCandHadCalo()

void recon::ParticleFlow::fillCandHadCalo ( ldmx::PFCandidate cand,
const ldmx::CaloCluster had 
)

Definition at line 76 of file ParticleFlow.cxx.

77 {
78 float corr = 1.;
79 float e = had.getEnergy();
80 if (e < hCorr_->GetX()[0]) {
81 corr = hCorr_->GetX()[0];
82 } else if (e > hCorr_->GetX()[hCorr_->GetN() - 1]) {
83 corr = hCorr_->GetX()[hCorr_->GetN() - 1];
84 } else {
85 corr = hCorr_->Eval(e);
86 }
87 cand.setHcalEnergy(e * corr);
88 cand.setHcalRawEnergy(e);
89 cand.setHcalClusterXYZ(had.getCentroidX(), had.getCentroidY(),
90 had.getCentroidZ());
91 cand.setHcalClusterEXYZ(had.getRMSX(), had.getRMSY(), had.getRMSZ());
92 cand.setHcalClusterDXDZ(had.getDXDZ());
93 cand.setHcalClusterDYDZ(had.getDYDZ());
94 cand.setHcalClusterEDXDZ(had.getEDXDZ());
95 cand.setHcalClusterEDYDZ(had.getEDYDZ());
96 cand.setPID(cand.getPID() | 4); // OR with 100
97}

◆ fillCandTrack()

void recon::ParticleFlow::fillCandTrack ( ldmx::PFCandidate cand,
const ldmx::SimTrackerHit tk 
)

Definition at line 30 of file ParticleFlow.cxx.

31 {
32 // TODO: smear
33 std::vector<float> xyz = tk.getPosition();
34 std::vector<double> pxyz = tk.getMomentum();
35 float ecalZ = 248;
36 float ecalX =
37 xyz[0] + pxyz[0] / pxyz[2] * (ecalZ - xyz[2]); // project onto ecal face
38 float ecalY = xyz[1] + pxyz[1] / pxyz[2] * (ecalZ - xyz[2]);
39 cand.setEcalPositionXYZ(ecalX, ecalY, ecalZ);
40 cand.setTrackPxPyPz(pxyz[0], pxyz[1], pxyz[2]);
41 // also use this object to set truth info
42 cand.setTruthEcalXYZ(ecalX, ecalY, ecalZ);
43 cand.setTruthPxPyPz(pxyz[0], pxyz[1], pxyz[2]);
44 float m2 = pow(tk.getEnergy(), 2) - pow(pxyz[0], 2) - pow(pxyz[1], 2) -
45 pow(pxyz[2], 2);
46 if (m2 < 0) m2 = 0;
47 cand.setTruthMass(sqrt(m2));
48 cand.setTruthEnergy(tk.getEnergy());
49 cand.setTruthPdgId(tk.getPdgID());
50 cand.setPID(cand.getPID() | 1); // OR with 001
51}
int getPdgID() const
Get the Sim particle track ID of the hit.
std::vector< float > getPosition() const
Get the XYZ position of the hit [mm].
float getEnergy() const
Get the energy.
std::vector< double > getMomentum() const
Get the XYZ momentum of the particle at the position at which the hit took place [MeV].

◆ onProcessEnd()

void recon::ParticleFlow::onProcessEnd ( )
virtual

Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.

Reimplemented from framework::EventProcessor.

Definition at line 398 of file ParticleFlow.cxx.

398 {
399 ldmx_log(debug) << "Process ends!";
400 delete eCorr_;
401 delete hCorr_;
402
403 return;
404}

◆ produce()

void recon::ParticleFlow::produce ( framework::Event event)
virtual

Process the event and put new data products into it.

Parameters
eventThe Event to process.

Implements framework::Producer.

Definition at line 100 of file ParticleFlow.cxx.

100 {
101 if (!event.exists(inputTrackCollName_)) return;
102 if (!event.exists(inputEcalCollName_)) return;
103 if (!event.exists(inputHcalCollName_)) return;
104 // get the track and clustering info
105 const auto ecalClusters =
106 event.getCollection<ldmx::CaloCluster>(inputEcalCollName_);
107 const auto hcalClusters =
108 event.getCollection<ldmx::CaloCluster>(inputHcalCollName_);
109 const auto tracks =
110 event.getCollection<ldmx::SimTrackerHit>(inputTrackCollName_);
111
112 std::vector<ldmx::PFCandidate> pfCands;
113 // multi-particle case
114 if (!singleParticle_) {
115 /*
116 1. Build links maps at the Tk/Ecal and Hcal/Hcal interfaces
117 2. Categorize tracks as: Ecal-matched, (Side) Hcal-matched, unmatched
118 3. Categorize Ecal clusters as: Hcal-matched, unmatched
119 4a. (Upstream?) Categorize tracks with dedx?
120 4b. (Upstream?) Categorize ecal clusters as: EM/Had-like
121 4c. (Upstream?) Categorize hcal clusters as: EM/Had-like
122 5. Build candidates by category, moving from Tk-Ecal-Hcal
123 */
124
125 //
126 // track-calo linking
127 //
128 std::map<int, std::vector<int> > tkCaloMap;
129 std::map<int, std::vector<int> > caloTkMap;
130 std::map<std::pair<int, int>, float> tkEMDist;
131 // std::vector<int> unmatchedTracks;
132 for (int i = 0; i < tracks.size(); i++) {
133 const auto& tk = tracks[i];
134 const std::vector<float> xyz = tk.getPosition();
135 const std::vector<double> pxyz = tk.getMomentum();
136 const float p = sqrt(pow(pxyz[0], 2) + pow(pxyz[1], 2) + pow(pxyz[2], 2));
137 // float bestMatchVal = 9e9;
138 for (int j = 0; j < ecalClusters.size(); j++) {
139 const auto& ecal = ecalClusters[j];
140 // Matching logic
141 const float ecalClusZ = ecal.getCentroidZ();
142 const float tkXAtClus =
143 xyz[0] + pxyz[0] / pxyz[2] * (ecalClusZ - xyz[2]); // extrapolation
144 const float tkYAtClus =
145 xyz[1] + pxyz[1] / pxyz[2] * (ecalClusZ - xyz[2]);
146 float dist = hypot(
147 (tkXAtClus - ecal.getCentroidX()) / std::max(1.0, ecal.getRMSX()),
148 (tkYAtClus - ecal.getCentroidY()) / std::max(1.0, ecal.getRMSY()));
149 tkEMDist[{i, j}] = dist;
150 bool isMatch =
151 (dist < 2) && (ecal.getEnergy() > 0.3 * p &&
152 ecal.getEnergy() < 2 * p); // matching criteria *
153 // if (isMatch && dist < bestMatchVal) bestMatchVal = dist;
154 if (isMatch) {
155 if (tkCaloMap.count(i))
156 tkCaloMap[i].push_back(j);
157 else
158 tkCaloMap[i] = {j};
159 if (caloTkMap.count(j))
160 caloTkMap[j].push_back(i);
161 else
162 caloTkMap[j] = {i};
163 }
164 }
165 }
166
167 // em-hadcalo linking
168 std::map<int, std::vector<int> > emHadCaloMap;
169 std::map<std::pair<int, int>, float> EMHadDist;
170 for (int i = 0; i < ecalClusters.size(); i++) {
171 const auto& ecal = ecalClusters[i];
172 for (int j = 0; j < hcalClusters.size(); j++) {
173 const auto& hcal = hcalClusters[j];
174 // TODO: matching logic
175 const float xAtHClus =
176 ecal.getCentroidX() +
177 ecal.getDXDZ() * (hcal.getCentroidZ() -
178 ecal.getCentroidZ()); // extrapolated position
179 const float yAtHClus =
180 ecal.getCentroidY() +
181 ecal.getDYDZ() * (hcal.getCentroidZ() - ecal.getCentroidZ());
182 float dist = sqrt(
183 pow(xAtHClus - hcal.getCentroidX(), 2) /
184 std::max(1.0, pow(hcal.getRMSX(), 2) + pow(ecal.getRMSX(), 2)) +
185 pow(yAtHClus - hcal.getCentroidY(), 2) /
186 std::max(1.0, pow(hcal.getRMSY(), 2) + pow(ecal.getRMSY(), 2)));
187 EMHadDist[{i, j}] = dist;
188 bool isMatch = (dist < 5); // matching criteria, was 2
189 if (isMatch) {
190 if (emHadCaloMap.count(i))
191 emHadCaloMap[i].push_back(j);
192 else
193 emHadCaloMap[i] = {j};
194 }
195 }
196 }
197
198 // NOT YET IMPLEMENTED...
199 // tk-hadcalo linking (Side HCal)
200 std::map<int, std::vector<int> > tkHadCaloMap;
201 // for(int i=0; i<tracks.size(); i++){
202 // const auto& tk = tracks[i];
203 // for(int j=0; j<hcalClusters.size(); j++){
204 // const auto& hcal = hcalClusters[j];
205 // // TODO: add the matching logic here...
206 // bool isMatch = true;
207 // if(isMatch){
208 // if (tkHadCaloMap.count(i)) tkHadCaloMap[i].push_back(j);
209 // else tkHadCaloMap[i] = {j};
210 // }
211 // }
212 // }
213
214 //
215 // track / ecal cluster arbitration
216 //
217 std::vector<bool> tkIsEMLinked(tracks.size(), false);
218 std::vector<bool> EMIsTkLinked(ecalClusters.size(), false);
219 std::map<int, int> tkEMPairs{};
220 for (int i = 0; i < tracks.size(); i++) {
221 if (tkCaloMap.count(i)) {
222 // pick first (highest-energy) unused matching cluster
223 for (int em_idx : tkCaloMap[i]) {
224 if (!EMIsTkLinked[em_idx]) {
225 EMIsTkLinked[em_idx] = true;
226 tkIsEMLinked[i] = true;
227 tkEMPairs[i] = em_idx;
228 break;
229 }
230 }
231 }
232 }
233
234 // track / hcal cluster arbitration
235 std::vector<bool> EMIsHadLinked(ecalClusters.size(), false);
236 std::vector<bool> HadIsEMLinked(hcalClusters.size(), false);
237 std::map<int, int> EMHadPairs{};
238 for (int i = 0; i < ecalClusters.size(); i++) {
239 if (emHadCaloMap.count(i)) {
240 // pick first (highest-energy) unused matching cluster
241 for (int had_idx : emHadCaloMap[i]) {
242 if (!HadIsEMLinked[had_idx]) {
243 HadIsEMLinked[had_idx] = true;
244 EMIsHadLinked[i] = true;
245 EMHadPairs[i] = had_idx;
246 break;
247 }
248 }
249 }
250 }
251
252 // can consider combining satellite clusters here...
253 // define some "primary cluster" ID criterion
254 // and can add fails to the primaries
255
256 //
257 // Begin building pf candidates from tracks
258 //
259
260 // std::vector<ldmx::PFCandidate> chargedMatch;
261 // std::vector<ldmx::PFCandidate> chargedUnmatch;
262 for (int i = 0; i < tracks.size(); i++) {
264 fillCandTrack(cand, tracks[i]); // append track info to candidate
265
266 if (!tkIsEMLinked[i]) {
267 // chargedUnmatch.push_back(cand);
268 } else { // if track is linked with ECal cluster
269 fillCandEMCalo(cand, ecalClusters[tkEMPairs[i]]);
270 if (EMIsHadLinked[tkEMPairs[i]]) { // if ECal is linked with HCal
271 // cluster
272 fillCandHadCalo(cand, hcalClusters[EMHadPairs[tkEMPairs[i]]]);
273 }
274 // chargedMatch.push_back(cand);
275 }
276 pfCands.push_back(cand);
277 }
278
279 // std::vector<ldmx::PFCandidate> emMatch;
280 // std::vector<ldmx::PFCandidate> emUnmatch;
281 for (int i = 0; i < ecalClusters.size(); i++) {
282 // already linked with ECal in the previous step
283 if (EMIsTkLinked[i]) continue;
284
286 fillCandEMCalo(cand, ecalClusters[i]);
287 if (EMIsHadLinked[tkEMPairs[i]]) {
288 fillCandHadCalo(cand, hcalClusters[EMHadPairs[i]]);
289 // emMatch.push_back(cand);
290 } else {
291 // emUnmatch.push_back(cand);
292 }
293 pfCands.push_back(cand);
294 }
295 std::vector<ldmx::PFCandidate> hadOnly;
296 for (int i = 0; i < hcalClusters.size(); i++) {
297 if (HadIsEMLinked[i]) continue;
299 fillCandHadCalo(cand, hcalClusters[i]);
300 // hadOnly.push_back(cand);
301 pfCands.push_back(cand);
302 }
303
304 // // track / ecal cluster arbitration
305 // std::vector<ldmx::PFCandidate> caloMatchedTks;
306 // std::vector<ldmx::PFCandidate> unmatchedTks;
307 // std::vector<bool> emUsed (ecalClusters.size(), false);
308 // for(int i=0; i<tracks.size(); i++){
309 // ldmx::PFCandidate cand;
310 // fillCandTrack(cand, tracks[i]);
311 // if( tkCaloMap.count(i)==0 ){
312 // unmatchedTks.push_back(cand);
313 // } else {
314 // // look for the first (highest-energy) unused matching cluster
315 // bool linked=false;
316 // for(int em_idx : tkCaloMap[i]){
317 // if(!emUsed[em_idx]){
318 // fillCandEMCalo(cand, tkCaloMap[i][0]);
319 // caloMatchedTks.push_back(cand);
320 // emUsed[ em_idx ] = true;
321 // linked = true;
322 // break;
323 // }
324 // }
325 // if (!linked) unmatchedTks.push_back(cand);
326 // }
327 // }
328
329 // // ecal / hcal cluster arbitration
330 // std::vector<bool> hadUsed (hcalClusters.size(), false);
331 // for(int i=0; i<ecalClusters.size(); i++){
332 // if( emHadCaloMap.count(i)==0 ){
333 // unmatchedTks.push_back(cand);
334 // } else {
335 // // look for the first (highest-energy) unused matching cluster
336 // bool linked=false;
337 // for(int em_idx : tkCaloMap[i]){
338 // if(!emUsed[em_idx]){
339 // fillCandEMCalo(cand, tkCaloMap[i][0]);
340 // caloMatchedTks.push_back(cand);
341 // emUsed[ em_idx ] = true;
342 // linked = true;
343 // break;
344 // }
345 // }
346 // if (!linked) unmatchedTks.push_back(cand);
347 // }
348 // }
349
350 // std::vector<ldmx::PFCandidate> unmatchedEMs;
351 // for(int i=0; i<ecalClusters.size(); i++){
352 // if(emUsed[i]) continue;
353 // ldmx::PFCandidate cand;
354 // fillCandEMCalo(cand, ecalClusters[i]);
355 // }
356
357 // }
358 // if( tkCaloMap[i].size()==1 ){
359 // if(!emUsed[ tkCaloMap[i][0] ]){
360 // fillCandEMCalo(cand, tkCaloMap[i][0]);
361 // caloMatchedTks.push_back(cand);
362 // emUsed[ tkCaloMap[i][0] ] = true;
363 // }
364 // }
365 // } else if( tkCaloMap[i].size()==1 ){
366 // if(!emUsed[ tkCaloMap[i][0] ]){
367 // fillCandEMCalo(cand, tkCaloMap[i][0]);
368 // caloMatchedTks.push_back(cand);
369 // emUsed[ tkCaloMap[i][0] ] = true;
370 // }
371 // }
372 // }
373
374 } else {
375 // Single-particle builder
377 int pid = 0; // initialize pid to add
378 if (tracks.size()) {
379 fillCandTrack(pf, tracks[0]);
380 pid += 1;
381 }
382 if (ecalClusters.size()) {
383 fillCandEMCalo(pf, ecalClusters[0]);
384 pid += 2;
385 }
386 if (hcalClusters.size()) {
387 fillCandHadCalo(pf, hcalClusters[0]);
388 pid += 4;
389 }
390 pf.setPID(pid);
391 pf.setEnergy(pf.getEcalEnergy() + pf.getHcalEnergy());
392 pfCands.push_back(pf);
393 }
394
395 event.add(outputCollName_, pfCands);
396}
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:92
Stores cluster information from the ECal.
Definition CaloCluster.h:26
Represents a reconstructed particle.
Definition PFCandidate.h:19
Represents a simulated tracker hit in the simulation.

References framework::Event::exists(), ldmx::SimTrackerHit::getMomentum(), and ldmx::SimTrackerHit::getPosition().

Member Data Documentation

◆ eCorr_

TGraph* recon::ParticleFlow::eCorr_ {0}
private

Definition at line 44 of file ParticleFlow.h.

44{0};

◆ hCorr_

TGraph* recon::ParticleFlow::hCorr_ {0}
private

Definition at line 45 of file ParticleFlow.h.

45{0};

◆ inputEcalCollName_

std::string recon::ParticleFlow::inputEcalCollName_
private

Definition at line 48 of file ParticleFlow.h.

◆ inputHcalCollName_

std::string recon::ParticleFlow::inputHcalCollName_
private

Definition at line 49 of file ParticleFlow.h.

◆ inputTrackCollName_

std::string recon::ParticleFlow::inputTrackCollName_
private

Definition at line 50 of file ParticleFlow.h.

◆ outputCollName_

std::string recon::ParticleFlow::outputCollName_
private

Definition at line 52 of file ParticleFlow.h.

◆ singleParticle_

bool recon::ParticleFlow::singleParticle_
private

Definition at line 54 of file ParticleFlow.h.


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