ICP  1
MuonDetectorCard.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 #include "MuonDetectorCard.h"
3 #include "isisvme.h"
4 
5 void MuonDetectorCard::printStatus(std::ostream& os, DAEstatus& status)
6 {
7  os << "This is a MUON DECTECTOR card" << std::endl;
8  os << "The card has " << m_detector_inputs_per_card << " inputs (" <<
9  m_num_dims << " dims, " << m_positions_per_dim << " positions," << " highest dim number = " << (m_num_dims - 1) * m_dim_step << ")\n";
10  DetectorCard::printStatus(os, status);
11 }
12 
13 
15 {
16  getSpectrumSize(ntc, status);
17  --(*ntc);
18  return 0;
19 }
20 
21 //clock pulses (one pulse = 0.5ns)
23 {
24  isisU32_t value;
25  if (ntc >= DCPOSLUTSIZE)
26  {
28  "too many time channels %d", ntc);
29  return ISISVME::Error;
30  }
31  if (tcb[0] != 0)
32  {
34  "invalid tcb start - must be 0 not %f ns", tcb[0] / 2.0);
35  return ISISVME::Error;
36  }
37  int clock_pulses = tcb[1] - tcb[0]; // in 0.5ns steps
38  if ( (tcb[ntc] - tcb[ntc-1]) != clock_pulses )
39  {
41  "The final time bin boundary %f ns must be a multiple of the step size %f ns", tcb[ntc]/2.0, clock_pulses/2.0);
42  return ISISVME::Error;
43  }
44  for(int i=0; i<ntc; ++i)
45  {
46  if ((tcb[i+1] - tcb[i]) != clock_pulses)
47  {
49  "invalid tcb step for bin %d - must be equally spaced and found %f ns(!= %f)", i, (tcb[i+1] - tcb[i])/2.0, clock_pulses/2.0);
50  return ISISVME::Error;
51  }
52  }
53  if (ntc * clock_pulses != 65536) // must be a 32768ns window
54  {
56  "The time window must be 32768 ns - %f ns is not allowed", ntc * clock_pulses / 2.0);
57  return ISISVME::Error;
58  }
59  value = clockPulsesToMuonStepSize(clock_pulses, status);
60  writeRegister(DCMUONSTEP, value, status);
61  for(int i=0; i < DCPOSLUTSIZE; ++i)
62  {
63  m_poslut[i] = i;
64  }
65  return writePOSLUTMemory(0, m_poslut, DCPOSLUTSIZE, status);
66 }
67 
70 {
71  int n = 0;
72  if (value < 1)
73  {
74  return false;
75  }
76  while(value > 1)
77  {
78  if ( (value % 2) != 0 )
79  {
80  return false;
81  }
82  value /= 2;
83  ++n;
84  }
85  return true;
86 }
87 
102 {
103  if (!isPowerOf2(clock_pulses))
104  {
106  "invalid tcb step - %d clock pulses is not a power of 2", clock_pulses);
107  return 0;
108  }
109  if (clock_pulses > 32)
110  {
112  "invalid tcb step %f - max tcb step is 16ns", clock_pulses / 2.0);
113  return 0;
114  }
115  return (clock_pulses == 1 ? 0 : clock_pulses / 2);
116 }
117 
121 {
122  return (step_size == 0 ? 1 : 2 * step_size);
123 }
124 
127 {
128  int i, j;
129  bool done;
130  isisU32_t time_to;
131  setNTimeChannels(ntc, status);
132  if ( (m_options & DetectorCard::Muon32Channel) != 0 )
133  {
134  return setTimeChannels32(tcb, ntc, status);
135  }
136  // chan_count store how many clock pulses per tcb channel
137  // we store "tcb 0" contribution from start and end separately
138  // hence ntc+2
139  int* chan_count = new int[ntc+2];
140  memset(chan_count, 0, (ntc+2)*sizeof(int));
141  i = 0;
142  // poslut location is "time to" i.e. upper bin boundary
143  done = false;
144  while( (i < DCPOSLUTSIZE) && !done )
145  {
146  time_to = i + 1;
147  if (time_to <= tcb[0])
148  {
149  m_poslut[i] = 0;
150  ++(chan_count[0]);
151  i++;
152  }
153  else
154  {
155  done = true;
156  }
157  }
158  // we are now inside the first bin tcb[0] to tcb[1]
159  j = 0;
160  while( (i < DCPOSLUTSIZE) && (j < ntc) )
161  {
162  time_to = i + 1;
163  if (time_to <= tcb[j+1])
164  {
165  m_poslut[i] = j + 1;
166  ++(chan_count[j+1]);
167  ++i;
168  }
169  else
170  {
171  ++j;
172  }
173  }
174  if (i == DCPOSLUTSIZE)
175  {
177  "Final TCB too big: ntc = %d (> %d), final tcb = %d", ntc, DCPOSLUTSIZE, tcb[ntc]);
178 
179  }
180  while(i < DCPOSLUTSIZE)
181  {
182  m_poslut[i] = 0;
183  ++(chan_count[ntc+1]);
184  ++i;
185  }
186  status.addDebugVa(FAC_DETCARD, "TCB0 contribution: first %d and last %d pulses",
187  chan_count[0], chan_count[ntc+1]);
188  delete[] chan_count;
189  return writePOSLUTMemory(0, m_poslut, DCPOSLUTSIZE, status);
190 }
191 
192 
194 {
195  isisU32_t value;
196  readRegister(DCMUONSTEP, &value, status);
197  int clock_pulses = muonStepSizeToClockPulses(value, status);
198  for(int i=0; i<ntc+1; ++i)
199  {
200  tcb[i] = i * clock_pulses;
201  }
202  return ISISVME::Success;
203 }
204 
205 
206 // in clock pulses
208 {
209  if ( (m_options & DetectorCard::Muon32Channel) != 0 )
210  {
211  return getTimeChannels32(tcb, ntc, status);
212  }
213  readPOSLUTMemory(0, m_poslut, DCPOSLUTSIZE, status);
214  memset(tcb, 0, (ntc+1)*sizeof(isisU32_t));
215  int time_from, time_to;
216  int i, j = 0, max_ntc = 0;
217  int* chan_count = new int[ntc]; // how many clock pulses per tcb channel
218  memset(chan_count, 0, ntc*sizeof(int));
219  i = 0;
220  while(i < DCPOSLUTSIZE)
221  {
222  time_from = i;
223  time_to = i + 1;
224  j = m_poslut[i]; // boundaries are (low <= t < high)
225  if ((j < 0) || (j > ntc ))
226  {
228  "Invalid TCB bin %d", j);
229  return ISISVME::Error;
230  }
231  max_ntc = (j > max_ntc ? j : max_ntc);
232  if (j == 1)
233  {
234  tcb[0] = time_from;
235  }
236  if (j > 0)
237  {
238  ++chan_count[j-1];
239  tcb[j] = time_to;
240  }
241  i++;
242  }
243  delete[] chan_count;
244  if (max_ntc != ntc)
245  {
246  status.addVa(FAC_DETCARD, SEV_INFO, ERRTYPE_INVCARD, "Invalid ntc %d", ntc);
247  return ISISVME::Error;
248  }
249  return 0;
250 }
251 
252 // In muons there is no posult and detctor inputs are hard coded
253 // to go to DAE2 spectrum 0 -> 31; thus we nede to map so we map DAE1 spectrum 0
254 // to the area after all the data we have collected
255 // there are 32 real spectra per card (DAE 0 -> 31) so we map DAE1 spectrum 0 -> DAE spec 32
257 {
258  int i, j, n;
259  std::ostringstream message;
261  m_dae1persize = 0;
262  m_dae2persize = 0;
263  m_nperiods = 1;
264  for(i=0; i<DAESPECMAX; i++)
265  {
268  }
269 // we may have junk in the POSLUT, so check value found
270  if (m_highspec >= DAESPECMAX)
271  {
272  m_highspec = DAESPECMAX - 1;
273  }
274  m_dae1specmap[0] = m_highspec; // map spectrum 0 to after data collected
275  m_dae2specmap[m_highspec] = 0; // map spectrum 0
276  // 32 inputs = 8 channels(position), 4 connectors (dims), dims going 0,1,2,3
277  // 128 inputs = 16 channels(position), 8 connectors (dims), BUT dims laballed 0,2,4,...,14
278  n = 0;
279  memset(m_poslut, 0, DCPOSLUTSIZE * sizeof(isisU32_t));
280  for(i=0; i < m_num_dims; i++)
281  {
282  for(j=0; j < m_positions_per_dim; j++)
283  {
284  m_poslut[DCPOSMAX * i * m_dim_step + j] = n++;
285  }
286  }
287 // m_dae2persize = m_highspec + 1;
288  message << "Highest DAE2 spectrum: " << m_highspec << "\n";
289  status.addInfo(FAC_DETCARD, message.str());
290  return 0;
291 }
292 
293 
294 // 8 channels on 4 connectors, arranged in four blocks of 8 = 32 spectra overall
295 // (call 8 positions on 4 dims)
296 int MuonDetectorCard::programPOSLUT(int cards[], int dims[], int pos_start[],
297  int npos[], int spec[], int spec_step[],
298  int nblocks, int nperiods, int dae1persize, DAEstatus& status)
299 {
301  "Invalid poslut bin %d", 1);
302  return ISISVME::Error;
303 }
304 
305 
306 // In muons there is no posult and detctor inputs are hard coded
307 // to go to DAE2 spectrum 0 -> 31; thus we nede to map so we map DAE1 spectrum 0
308 // to the area after all the data we have collected
309 // there are 32 real spectra per card (DAE 0 -> 31) so we map DAE1 spectrum 0 -> DAE spec 32
310 // so there are really 33 spectra per card
311 // 8 channels(positions) on 4 connectors(dims), arranged in four blocks of 8 = 32 spectra overall
312 int MuonDetectorCard::programDAE1POSLUT(int crat[], int modn[],
313  int mpos[], int spec[], int ndet,
314  int nperiods, int dae1persize, DAEstatus& status)
315 {
316  std::ostringstream message_i, message_e, message_w;
317  int i, j, s, dae1min, dae1max, npos, ngap;
318  bool card_used;
319  int modn_min=1000000, modn_max=-1, mpos_min=1000000, mpos_max=-1;
320  npos = 0;
321  m_dae1persize = dae1persize;
322  m_nperiods = nperiods;
323  for(i=0; i<DAESPECMAX; i++)
324  {
327  }
328  m_dae1specmap[0] = m_detector_inputs_per_card; // map spectrum 0 to unused spectrum on end
330 // find all DAE1 spectra on this card and
331 // assign dummy DAE2 spectrum number of 1
332  dae1max = -1;
333  dae1min=1000000;
334  card_used = false;
335  for(i=0; i<ndet; i++)
336  {
337  if (crat[i] == m_position)
338  {
339  card_used = true;
341  if (spec[i] > dae1max)
342  {
343  dae1max = spec[i];
344  }
345  if (spec[i] < dae1min)
346  {
347  dae1min = spec[i];
348  }
349  }
350  }
351  ngap = 0;
352  for(i=dae1min; i<=dae1max; i++)
353  {
355  {
356  ngap++;
357  }
358  }
359  if (ngap > 0)
360  {
361  message_i << "There is a gap of total size " << ngap << " in the DAE1 spectra on the card" << std::endl;
362  }
366 
367 // now assign them sequential DAE2 spectrum numbers
368 // 8 channels(positions) on 4 connectors(dims), arranged in four blocks of 8 = 32 spectra overall numbered 0 -> 31
369 // d2spec = 8 * dim + pos;
370  for(i=0; i<ndet; i++)
371  {
372  if (crat[i] == m_position)
373  {
374  npos++;
375  if (mpos[i] < mpos_min)
376  {
377  mpos_min = mpos[i];
378  }
379  if (modn[i] < modn_min)
380  {
381  modn_min = modn[i];
382  }
383  if (mpos[i] > mpos_max)
384  {
385  mpos_max = mpos[i];
386  }
387  if (modn[i] > modn_max)
388  {
389  modn_max = modn[i];
390  }
391  j = m_dae1specmap[spec[i]];
392  if (j == SPECTRUM_PLACEHOLDER)
393  {
394  if (calculateSpectrum(j, modn[i], mpos[i], status) == ISISVME::Success)
395  {
396  m_dae1specmap[spec[i]] = j;
397  m_dae2specmap[j] = spec[i];
398  }
399  else
400  {
401  message_e << "Error in calculateSpectrum" << std::endl;
402  }
403  }
404  else
405  {
406  message_e << "Error in spectrum mapping" << std::endl;
407  }
408  }
409  }
410 // now assign spectra for periods
411 // "spectrum 0" is at end of each spectrum block, so different from neutron card
412  for(i=0; i<m_dae2persize; i++)
413  {
414  s = m_dae2specmap[i];
415  if (s != NOSPECTRUM) // we need this test for muons as may be unassigned DAE2 spectra due to no POSLUT
416  {
417  for(j=1; j<m_nperiods; j++)
418  {
419  m_dae2specmap[i + j * m_dae2persize] = s + j * m_dae1persize;
420  m_dae1specmap[s + j * m_dae1persize] = i + j * m_dae2persize;
421  }
422  }
423  }
424  if (card_used)
425  {
426  message_i << "Card: " << m_position << " DAE2 Highest: " << m_highspec
427  << " DAE1 low: " << dae1min << " DAE1 high: " << dae1max
428  << " NPOS: " << npos << "\n";
429  message_i << "MPOS: " << mpos_min << " to " << mpos_max << "\n";
430  message_i << "MODN: " << modn_min << " to " << modn_max << "\n";
431  }
432  else
433  {
434  message_w << "*** Detector Card " << m_position << " not used" << std::endl;
435  }
436  status.addInfo(FAC_DETCARD, message_i.str());
437  status.add(FAC_DETCARD, SEV_WARNING, ERRTYPE_INVCARD, message_w.str());
438  status.add(FAC_DETCARD, SEV_WARNING, ERRTYPE_INVCARD, message_e.str());
439 // check enough memory on card
440  isisU32_t nchan, mem_needed;
441  getSpectrumSize(&nchan, status);
442  mem_needed = 4 * m_nperiods * m_dae2persize * nchan; // bytes
443  if (mem_needed > m_memsize)
444  {
446  "Detector Card %d has too little memory: %d < %d bytes",
447  m_position, m_memsize, mem_needed);
448  }
449  return ISISVME::Success;
450 }
451 
452 
453 MuonDetectorCard::MuonDetectorCard(int position, ISISVME* vme, int* specmap_array,
454  int specmap_len, DAEstatus& status)
455  : DetectorCard(position, vme, specmap_array, specmap_len, status)
456 {
457  std::ostringstream message;
458  setLoggerName("MuonDetectorCard");
459  isisU32_t value;
460  DAEstatus temp_status;
461  message << "Creating Muon Detector Card" << "\n";
462  // 32 inputs = 8 channels(position), 4 connectors (dims), dims going 0,1,2,3
463  // 128 inputs = 16 channels(position), 8 connectors (dims), BUT dims laballed 0,2,4,...,14
464  if (readRegister(DCOPMODE, &value, temp_status) == 1)
465  {
466  setRegisterBits(DCOPMODE, 0x2, true, status); // always run card in full 32 channel mode if supported
469  m_num_dims = 8;
470  m_dim_step = 2;
471  }
472  else
473  {
475  m_dim_step = 1;
476  m_num_dims = 4;
477  }
479  message << "The card has " << m_detector_inputs_per_card << " inputs (" <<
480  m_num_dims << " dims, " << m_positions_per_dim << " positions," << " highest dim number = " << (m_num_dims - 1) * m_dim_step << ")\n";
481  status.addInfo(FAC_ENVCARD, message.str());
482 }
483 
484 
485 // period 0 is the first period with detectors going into
486 // DAE2 spectra 0, 1, 2, 3 ... N (=m_highspec) etc
487 // period 1 will have it going into N+1, N+2, ..., 2*(N+1)-1
488 // period 2 will be 2*(N+1) ... 3*(N+1)-1
489 //
491 {
492  if (period >= m_nperiods)
493  {
494  status.addVa(FAC_DETCARD, SEV_ERROR, ERRTYPE_INVCARD, "Cannot change period to %d >= %d", period, m_nperiods);
495  return ISISVME::Error;
496  }
497  return setPeriodCounter(period, status);
498 }
499 
501 {
502 }
503 
506 int MuonDetectorCard::calculateModuleAndPosition(int dae2_spec, int& modn, int& mpos, DAEstatus& status)
507 {
508  modn = mpos = 0;
509  if (dae2_spec > m_detector_inputs_per_card)
510  {
512  "Detector Card %d has invalid spectrum %d", m_position, dae2_spec);
513  return ISISVME::Error;
514  }
515  if (dae2_spec == m_detector_inputs_per_card) // dummy spectrum 0
516  {
517  modn = mpos = 0;
518  }
519  else
520  {
521  int n = dae2_spec / m_positions_per_dim;
522  modn = n * m_dim_step;
523  mpos = dae2_spec % m_positions_per_dim;
524  }
525  return ISISVME::Success;
526 }
527 
530 int MuonDetectorCard::calculateSpectrum(int& dae2_spec, int modn, int mpos, DAEstatus& status)
531 {
532  dae2_spec = 0;
533  if (modn % m_dim_step != 0)
534  {
536  "Detector Card %d has invalid modn %d", m_position, modn);
537  return ISISVME::Error;
538  }
539  if ( modn > (m_dim_step * (m_num_dims - 1)) )
540  {
542  "Detector Card %d has invalid modn %d", m_position, modn);
543  return ISISVME::Error;
544  }
545  if (mpos >= m_positions_per_dim)
546  {
548  "Detector Card %d has invalid mpos %d", m_position, mpos);
549  return ISISVME::Error;
550  }
551  int n = modn / m_dim_step;
552  dae2_spec = n * m_positions_per_dim + mpos;
553  return ISISVME::Success;
554 }
555 
558 {
559  LOGSTR_INFORMATION("Nothing to do");
560  return ISISVME::Success;
561 // return DetectorCard::resetCardState(status);
562 }
unsigned long m_memsize
histogram memory in bytes
int addVa(int facility, int severity, int errtype, const char *format,...)
Definition: DAEstatus.cpp:54
#define SEV_WARNING
int calculateModuleAndPosition(int dae2_spec, int &modn, int &mpos, DAEstatus &status)
int getNTimeChannels(isisU32_t *ntc, DAEstatus &status)
int getTimeChannels32(isisU32_t *tcb, int ntc, DAEstatus &status)
int setTimeChannels32(isisU32_t *tcb, int ntc, DAEstatus &status)
int setRegisterBits(unsigned long address, isisU32_t mask, bool preserve, DAEstatus &status, bool little_endian=false)
Definition: dae2_card.cpp:183
unsigned long isisU32_t
Definition: isisvme_types.h:8
std::vector< int > m_dae1specmap
dae2spec = m_dae1specmap[dae1spec]
int add(DAEstatus &dstatus, bool clear)
Definition: DAEstatus.cpp:131
virtual void printStatus(std::ostream &os, DAEstatus &status)
int m_nperiods
number of software/DAQ periods
int m_highspec
highest DAE2 spectrum used
#define SEV_ERROR
int writeRegister(unsigned long address, isisU32_t value, DAEstatus &status, bool little_endian=false)
Definition: dae2_card.cpp:155
int m_dae1persize
number of dae1 spectra in a period
#define SEV_INFO
#define LOGSTR_INFORMATION(__arg)
Definition: IsisBase.h:78
int readRegister(unsigned long address, isisU32_t *value, DAEstatus &status, bool little_endian=false, bool retry=true)
Definition: dae2_card.cpp:23
virtual int resetCardState(DAEstatus &status)
This emulates Kelvin Gascoyne&#39;s Clear.
int addDebugVa(int facility, const char *format,...)
Definition: DAEstatus.cpp:121
int m_dae2persize
number of spectra in a dae2 period
static const int NOSPECTRUM
int programPOSLUT(int cards[], int dims[], int pos_start[], int npos[], int spec[], int spec_step[], int nblocks, int nperiods, int dae1persize, DAEstatus &status)
int changePeriod(int period, DAEstatus &status)
int readPOSLUTMemory(unsigned long start, isisU32_t *buffer, int len, DAEstatus &status)
int writePOSLUTMemory(unsigned long start, isisU32_t *buffer, int len, DAEstatus &status)
int readPOSLUT(DAEstatus &status)
#define ERRTYPE_INVCARD
#define FAC_ENVCARD
int getSpectrumSize(isisU32_t *value, DAEstatus &status)
void setLoggerName(const std::string &logger_name)
Definition: IsisBase.h:17
int clockPulsesToMuonStepSize(int clock_pulses, DAEstatus &status)
int programDAE1POSLUT(int crat[], int modn[], int mpos[], int spec[], int ndet, int nperiods, int dae1persize, DAEstatus &status)
int muonStepSizeToClockPulses(int step_size, DAEstatus &status)
static const int SPECTRUM_PLACEHOLDER
bool isPowerOf2(int value)
is value expressable as 2^n for some integer n
int addInfo(int facility, const std::string &text)
Definition: DAEstatus.cpp:86
void printStatus(std::ostream &os, DAEstatus &status)
int setPeriodCounter(int period, DAEstatus &status)
int setTimeChannels(isisU32_t *tcb, int ntc, DAEstatus &status)
set of ntc+1 time channel boundaries in clock pulses (one pulse = 0.5ns)
isisU32_t * m_poslut
temp workspace for POSLUT programming
#define FAC_DETCARD
std::vector< int > m_dae2specmap
dae1spec = m_dae2specmap[dae2spec]
virtual int setNTimeChannels(isisU32_t ntc, DAEstatus &status)
int getTimeChannels(isisU32_t *tcb, int ntc, DAEstatus &status)
int m_dim_step
are dims numbered 0,1,2,3... or 0,2,4,6... etc.
int m_position
Definition: dae2_card.h:89
int calculateSpectrum(int &dae2_spec, int modn, int mpos, DAEstatus &status)
int m_num_dims
totoal number of dims, not the highest dim number
MuonDetectorCard(int position, ISISVME *vme, int *specmap_array, int specmap_len, DAEstatus &status)