Hall-D Software  alpha
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DBeamCurrent_factory.cc
Go to the documentation of this file.
1 // $Id$
2 //
3 // File: DBeamCurrent_factory.cc
4 // Created: Tue Feb 21 04:25:04 EST 2017
5 // Creator: davidl (on Linux gluon48.jlab.org 2.6.32-431.20.3.el6.x86_64 x86_64)
6 //
7 
8 
9 #include <iostream>
10 #include <iomanip>
11 #include <algorithm>
12 #include <cmath>
13 #include <mutex>
14 using namespace std;
15 
16 #include <DAQ/DCODAEventInfo.h>
17 #include "DBeamCurrent_factory.h"
18 using namespace jana;
19 
20 
21 
22 //------------------
23 // init
24 //------------------
26 {
27  BEAM_ON_MIN_nA = 10.0; // nA
28  BEAM_TRIP_MIN_T = 3.0; // seconds
29 
30  gPARMS->SetDefaultParameter("BEAM_ON_MIN_nA", BEAM_ON_MIN_nA, "Minimum current in nA to consider the beam \"on\" by DBeamCurrent");
31  gPARMS->SetDefaultParameter("BEAM_TRIP_MIN_T", BEAM_TRIP_MIN_T, "Minimum amount of time in seconds that event is away from beam trips to be considered fiducial");
32 
33  ticks_per_sec = 250.011E6; // 250MHz clock (may be overwritten with calib constant in brun)
34  rcdb_start_time = 0; // unix time of when 250MHz clock was reset. (overwritten below)
35  rcdb_250MHz_offset_tics = 0; // offset between 250MHz clock zero and RCDB recorded start time of event (overwritten below)
36 
37  return NOERROR;
38 }
39 
40 //------------------
41 // brun
42 //------------------
43 jerror_t DBeamCurrent_factory::brun(jana::JEventLoop *loop, int32_t runnumber)
44 {
45  // Clear maps in case we are called more than once
46  boundaries.clear();
47  trip.clear();
48  recover.clear();
49 
50  // Data is stored in CCDB as a large ASCII string with
51  // pairs of values:
52  //
53  // t Ibeam
54  //
55  // where
56  // t = time in seconds since start of run
57  // Ibeam = beam current in nA
58  //
59 
60  // n.b. we have to do this by first getting the JCalibration
61  // object and then using it directly. If we use the GetCalib()
62  // method in JEventLoop, it will try parsing the string and
63  // return more than a 1 element map.
64  map<string,string> mstr;
65  loop->GetJCalibration()->GetCalib("/ELECTRON_BEAM/current_map_epics", mstr);
66  if(mstr.empty()) return NOERROR;
67  string &electron_beam_current = mstr.begin()->second;
68 
69  map<string,string> mcalib;
70  loop->GetJCalibration()->GetCalib("/ELECTRON_BEAM/timestamp_to_unix", mcalib);
71  if(mcalib.size() == 3){
72  //ticks_per_sec = atof(mcalib["tics_per_sec"].c_str());
73  rcdb_250MHz_offset_tics = stoull(mcalib["rcdb_250MHz_offset_tics"].c_str());
74  rcdb_start_time = stoull(mcalib["rcdb_start_time"].c_str());
75  }
76 
77 
78  // Parse text to create Boundary objects and maps of trip/recovery points
79  istringstream ss(electron_beam_current);
80  double last_Ibeam = 0.0;
81  for(string line; getline(ss, line, '\n'); ){
82  double t = atof(line.c_str());
83  double Ibeam = atof(line.substr(1+line.find(" ")).c_str());
84  Boundary b = {t, Ibeam, 0.0, 0.0};
85  boundaries.push_back(b);
86 
87  // Record trip/recovery points
88  if( fabs(Ibeam - last_Ibeam) > BEAM_ON_MIN_nA ){
89  if(Ibeam < BEAM_ON_MIN_nA){
90  trip.push_back(t);
91  }else if(last_Ibeam < BEAM_ON_MIN_nA){
92  recover.push_back(t);
93  }
94  }
95  last_Ibeam = Ibeam;
96  }
97 
98  // Loop through all boundaries and update the time to
99  // all trip points.
100  double t_max = IntegratedTime();
101  for(auto &b : boundaries){
102 
103  // Prev and next values should correspond appropriately
104  // to trip or recovery boundaries as to whether this
105  // boundary starts a "ON" or "OFF" period. i.e.
106  //
107  // If beam current is "OFF" then prev should be the
108  // previous trip time and next the next recovery time.
109  //
110  // If beam current is "ON" then prev should be the
111  // previous recovery time and next the next trip time.
112 
113  double t_prev = 0.0;
114  double t_next = t_max;
115  if(b.Ibeam < BEAM_ON_MIN_nA){
116  // beam "OFF"
117  for( double t : recover ) if( t>b.t ) {t_next = t; break;}
118  for( double t : trip ) if( t>b.t ) {break;} else {t_prev = t;}
119  }else{
120  // beam "ON"
121  for( double t : trip ) if( t>b.t ) {t_next = t; break;}
122  for( double t : recover ) if( t>b.t ) {break;} else {t_prev = t;}
123  }
124 
125  b.t_trip_prev = b.t - t_prev;
126  b.t_trip_next = t_next - b.t;
127  }
128 
129  // Print message only once per run number
130  static mutex mtx;
131  lock_guard<mutex> lck(mtx);
132  static set<int32_t> runs_loaded;
133  if(runs_loaded.find(runnumber) == runs_loaded.end()){
134  jout << "Electron beam current trip map for run " << runnumber << " loaded with " << boundaries.size() << " boundaries (" << trip.size() << " trips over " << t_max << " sec)" << endl;
135  runs_loaded.insert(runnumber);
136  }
137 
138  return NOERROR;
139 }
140 
141 //------------------
142 // evnt
143 //------------------
144 jerror_t DBeamCurrent_factory::evnt(JEventLoop *loop, uint64_t eventnumber)
145 {
146  if(boundaries.empty()) return NOERROR;
147 
148  // Get time of this event relative to start of run in seconds
149  // n.b. don't use loop->GetSingle() here. It results in infinite
150  // recursion.
151  vector<const DCODAEventInfo*> codainfos;
152  loop->Get(codainfos);
153  if(codainfos.empty()) return NOERROR;
154  const DCODAEventInfo *codainfo = codainfos[0];
155 
156  // Get tme relative to RCDB recorded start time of event
157  // (all times in trip map are recorded relative to this as well)
158  double t = (codainfo->avg_timestamp - (double)rcdb_250MHz_offset_tics)/ticks_per_sec;
159 
160  // Find closest entry given current time
161  auto it = boundaries.begin();
162  while(it!=boundaries.end()){
163  if(it->t > t) break;
164  it++;
165  }
166 
167  if(it != boundaries.begin() ){
168  it--;
169  Boundary &b = *it;
170  double t_rel = t - b.t; // time relative to previous boundary
171 
172  DBeamCurrent *bc = new DBeamCurrent;
173  bc->Ibeam = b.Ibeam;
174  bc->t = t;
175  bc->t_prev = b.t_trip_prev + t_rel;
176  bc->t_next = b.t_trip_next - t_rel;
177  bc->is_fiducial = false;
178  if(b.Ibeam >= BEAM_ON_MIN_nA){
179  if(bc->t_prev>=BEAM_TRIP_MIN_T){
180  if(bc->t_next>=BEAM_TRIP_MIN_T) bc->is_fiducial=true;
181  }
182  }
183 
184  _data.push_back(bc);
185  }
186 
187  return NOERROR;
188 }
189 
190 //------------------
191 // erun
192 //------------------
194 {
195  return NOERROR;
196 }
197 
198 //------------------
199 // fini
200 //------------------
202 {
203  return NOERROR;
204 }
205 
206 //------------------
207 // IntegratedFiducialTime
208 //------------------
209 double DBeamCurrent_factory::IntegratedFiducialTime(double t_start, double t_end)
210 {
211  /// Loop over all boundaries to find the total fiducial time
212  /// between the two given times. Both t_start and t_end should
213  /// be in seconds and relative to the start of the run (NOT
214  /// the start of this particular file!) The value returned is
215  /// in seconds. The fraction of the time the beam was on for
216  /// the entire run can be obtained with:
217  ///
218  /// IntegratedFiducialTime()/IntegratedTime()
219  ///
220 
221  // Find recovery before and after times
222  double t_recover_pre = 0.;
223  double t_recover_post = 0.;
224  for(double ttemp : recover){
225  if(ttemp < t_start)
226  t_recover_pre = ttemp;
227  else {
228  t_recover_post = ttemp;
229  break;
230  }
231  }
232  double t_trip_pre = 0.;
233  for(double ttemp : trip){
234  if(ttemp < t_start)
235  t_trip_pre = ttemp;
236  else
237  break;
238  }
239 
240  // Loop over start of "recover" regions
241  double t_fiducial = 0.0; // total fiducial time so far
242  double t = t_start; // point we have already integrated to
243  for(double t1 : recover){
244 
245  // if start in middle of run skip previous recoveries
246  if(t_trip_pre > t_recover_pre) { // start with "beam on"
247  if(t1 < t_recover_post)
248  continue;
249  }
250  else { // start with "beam off"
251  if(t1 < t_recover_pre)
252  continue;
253  }
254 
255  // check if next recovery region starts after where we are
256  //if(t1 > t)t = t1;
257 
258  // find start of next "tripped" region
259  double t2 = t_end;
260  for(double tt : trip)if(tt>t || tt>t_end){t2 = tt; break;}
261 
262  // At this point t is between t1 and t2 (possibly at t1)
263  // which is a beam "ON" region. Calculate time in this
264  // region excluding BEAM_TRIP_MIN_T seconds from edges.
265 
266  // move t to start of valid integration range
267  if( (t-t1)<BEAM_TRIP_MIN_T ) t = t1 + BEAM_TRIP_MIN_T;
268 
269  // make t3 the end of integration range being careful
270  // not to include time past t_end or within BEAM_TRIP_MIN_T
271  // of next trip.
272  double t3 = t2 - BEAM_TRIP_MIN_T;
273  if(t3>t_end) t3 = t_end;
274 
275  // Calculate how much fiducial time in this region is
276  // within our integration window and if it is positive,
277  // then add it.
278  double delta_t = t3-t;
279  if(delta_t > 0.0) t_fiducial += delta_t;
280 
281  // Move integration point
282  t = t2;
283 
284  // break early if we have included whole window
285  if(t >= t_end) break;
286  }
287 
288  return t_fiducial;
289 }
290 
291 //------------------
292 // IntegratedTime
293 //------------------
295 {
296  /// Return total integrated time for this run.
297  /// WARNING: This is NOT the time of only the
298  /// current file. See IntegratedFiducialTime
299  /// for more details.
300  if(boundaries.empty()) return 0.0;
301  return boundaries[boundaries.size()-1].t;
302 }
303 
304 
double BEAM_ON_MIN_nA
jerror_t fini(void)
Called after last event of last event source has been processed.
jerror_t evnt(jana::JEventLoop *eventLoop, uint64_t eventnumber)
Called every event.
jerror_t brun(jana::JEventLoop *eventLoop, int32_t runnumber)
Called everytime a new run number is detected.
uint64_t avg_timestamp
double IntegratedFiducialTime(double t_start=0.0, double t_end=0.0)
TLatex * t1
bool is_fiducial
Definition: DBeamCurrent.h:41
jerror_t erun(void)
Called everytime run number changes, provided brun has been called.
jerror_t init(void)
Called once at program start.
double Ibeam
Definition: DBeamCurrent.h:37
double t_prev
Definition: DBeamCurrent.h:39
double t_next
Definition: DBeamCurrent.h:40
Double_t t_max[NCHANNELS]
double BEAM_TRIP_MIN_T