/// <summary> /// ResetForConcatenation() clears metadata for a new experiment, /// but preserves present histogram array so subsequent data can be added. /// </summary> public void ResetForConcatenation() { int i; CoincidenceNeutronEvent thisEvent, nextEvent; #if USE_SPINTIME spinTimeTotal = 0; spinTimeReady = false; #endif totalMeasurementTime = 0.0; //Don't empty the coincidence dictionary //break the circular references, so garbage collector will do its thing nextEvent = theEventCircularLinkedList; while (nextEvent != null) { thisEvent = nextEvent; nextEvent = thisEvent.next; thisEvent.next = null; } //create the circular linked list theEventCircularLinkedList = new CoincidenceNeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new CoincidenceNeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; isReadyToAnalyze = true; }
/// <summary> /// CoincidenceAnalysisSlowBackground. /// Note that accidentalsGateDelayInTics is the time between the trigger and the OPENING of the accidentals gate. /// Similarly, preDelayInTics is the time between the trigger and the OPENING of the R+A gate (the "dead time") /// </summary> public CoincidenceAnalysisSlowBackground(UInt64 gateWidthInTics, UInt64 preDelayInTics, UInt64 accidentalsGateDelayInTics, double theTicSizeInSeconds) { //store the initialization parameters ticSizeInSeconds = theTicSizeInSeconds; coincidenceGateWidth = gateWidthInTics; coincidenceDeadDelay = preDelayInTics; coincidenceAccidentalsDelay = accidentalsGateDelayInTics; totalWindow = gateWidthInTics + accidentalsGateDelayInTics; realsWindow = gateWidthInTics + preDelayInTics; chnmask = new UInt32[RawAnalysisProperties.ChannelCount]; for (int i = 0; i < RawAnalysisProperties.ChannelCount; i++) { chnmask[i] = (uint)1 << i; } #if USE_SPINTIME spinTimeTotal = 0; spinTimeStart = 0; spinTimeReady = false; #endif //create the coincidence arrays RAcoincidence = new UInt64[RawAnalysisProperties.ChannelCount][]; Acoincidence = new UInt64[RawAnalysisProperties.ChannelCount][]; for (int i = 0; i < RawAnalysisProperties.ChannelCount; i++) { RAcoincidence[i] = new UInt64[RawAnalysisProperties.ChannelCount]; Acoincidence[i] = new UInt64[RawAnalysisProperties.ChannelCount]; } totalMeasurementTime = 0.0; //initialize the event holders inputEventNeutrons = new UInt32[RawAnalysisProperties.maxEventsPerBlock]; inputEventTime = new UInt64[RawAnalysisProperties.maxEventsPerBlock]; numEventsThisBlock = 0; //create the circular linked list theEventCircularLinkedList = new CoincidenceNeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (int i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new CoincidenceNeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; //set up the MASB BackgroundWorker keepRunning = true; isReadyToAnalyze = false; CASBWorker = new BackgroundWorker(); CASBWorker.WorkerSupportsCancellation = false; CASBWorker.DoWork += new DoWorkEventHandler(MASBWorkerDoWork); CASBWorker.RunWorkerAsync(); //pause until the CASBWorker is working while (CASBWorker.IsBusy == false) { Thread.Sleep(1); } }
/// <summary> /// ResetCompletely() clears results and sets metadata for new data, /// such as running a new experiment or reading a new NCD file /// </summary> public void ResetCompletely(bool closeCounters) { int i, j; CoincidenceNeutronEvent thisEvent, nextEvent; #if USE_SPINTIME spinTimeTotal = 0; spinTimeReady = false; #endif //empty the coincidence array for (i = 0; i < RawAnalysisProperties.ChannelCount; i++) { for (j = 0; j < RawAnalysisProperties.ChannelCount; j++) { RAcoincidence[i][j] = 0; Acoincidence[i][j] = 0; } } totalMeasurementTime = 0.0; //break the circular references, so garbage collector will do its thing nextEvent = theEventCircularLinkedList; while (nextEvent != null) { thisEvent = nextEvent; nextEvent = thisEvent.next; thisEvent.next = null; } theEventCircularLinkedList = null; startOfList = null; endOfList = null; numObjectsInCircularLinkedList = 0; if (closeCounters) { keepRunning = false; isReadyToAnalyze = false; waitingForMessage.Set(); } else { //create the circular linked list theEventCircularLinkedList = new CoincidenceNeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new CoincidenceNeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; isReadyToAnalyze = true; } }
void MASBWorkerDoWork(object sender, DoWorkEventArgs e) { String threadName = "CASBAnalyzer_" + coincidenceGateWidth + "_" + coincidenceDeadDelay + "_" + coincidenceAccidentalsDelay; Thread.CurrentThread.Name = threadName; #if USE_SPINTIME spinTimeReady = false; #endif while (keepRunning == true) { isReadyToAnalyze = true; #if USE_SPINTIME if (spinTimeReady) { StartSpinCount(); } #endif waitingForMessage.Wait(); //wait for some other thread to send data or send quit signal #if USE_SPINTIME if (spinTimeReady) { EndSpinCount(); } else { spinTimeReady = true; } #endif if (keepRunning == true) { int i, j; UInt64 eventTime; UInt32 eventNeutrons; CoincidenceNeutronEvent anEvent; CoincidenceNeutronEvent nextEvent; CoincidenceNeutronEvent lastEvent; for (j = 0; j < numEventsThisBlock; j++) { eventTime = inputEventTime[j]; eventNeutrons = inputEventNeutrons[j]; //fill in these new data at the tail of the circular linked list, //remembering that endOfList points to the next EMPTY struct in the list //INCLUDING at the beginning when the head and tail point to the same struct. endOfList.eventTime = eventTime; endOfList.eventNeutrons.Clear(); //clear the list to remove any left-over neutrons from previous use of this object for (i = 0; i < RawAnalysisProperties.ChannelCount; i++) { if ((eventNeutrons & chnmask[i]) != 0) { endOfList.eventNeutrons.Add(i); } } //check to see if the circular list will overflow if (endOfList.next.serialNumber == startOfList.serialNumber) { //if stack would overflow, add RawAnalysisProperties.circularListBlockIncrement neutron events at this spot in the stack... anEvent = endOfList; nextEvent = endOfList.next; for (i = 0; i < RawAnalysisProperties.circularListBlockIncrement; i++) { anEvent.next = new CoincidenceNeutronEvent(i + numObjectsInCircularLinkedList); anEvent = anEvent.next; } anEvent.next = nextEvent; //patch the circular linked list back together numObjectsInCircularLinkedList += RawAnalysisProperties.circularListBlockIncrement; //increase the record of the number of structs in the circular list } //remember this new last event lastEvent = endOfList; //move endOfList to the next empty struct endOfList = endOfList.next; //for fun, count how many times we have lapped the circular list in this experiment if (endOfList.serialNumber == 0) { numCircuits++; } //produce counts for all the expiring events at beginning of stack, and remove these events // NEXT: should this be >= instead of > ?????? might be related to A/S issue #51 while ((lastEvent.eventTime - startOfList.eventTime) > totalWindow) { UInt64 startTime; int aindex, bindex; int numa, numb; int neutronA, neutronB; startTime = startOfList.eventTime; numa = startOfList.eventNeutrons.Count; anEvent = startOfList.next; //skip the neutrons of the triggering event //count the number of neutrons in the stack within the allowed deltaTimes //NOTE: logic for these gates are: start <= included < end //That is, an event equal to gate-open time is inside the gate // but an event equal to gate-end time is outside the gate while ((anEvent != null) && (anEvent.serialNumber != endOfList.serialNumber) && (anEvent.eventTime < (startTime + totalWindow))) { //LOGIC NOTE: can't check for eventTime against gate opening in the while() test, //else a discriminated event would terminate before later events were counted... if ((anEvent.eventTime >= (startTime + coincidenceDeadDelay)) && (anEvent.eventTime < (startTime + realsWindow))) { //for each pair of neutrons "a" in the expiring event and "b" in the event in the window, //increment the coincidence element "a,b"... numb = anEvent.eventNeutrons.Count; for (aindex = 0; aindex < numa; aindex++) { neutronA = startOfList.eventNeutrons[aindex]; for (bindex = 0; bindex < numb; bindex++) { neutronB = anEvent.eventNeutrons[bindex]; RAcoincidence[neutronA][neutronB]++; } } } //now check for neutrons in the accidentals gate if (anEvent.eventTime >= (startTime + coincidenceAccidentalsDelay)) { numb = anEvent.eventNeutrons.Count; for (aindex = 0; aindex < numa; aindex++) { neutronA = startOfList.eventNeutrons[aindex]; for (bindex = 0; bindex < numb; bindex++) { neutronB = anEvent.eventNeutrons[bindex]; Acoincidence[neutronA][neutronB]++; } } } //...but always continue to the next event... anEvent = anEvent.next; } //record the time of this expiring event; this is the total measurement time totalMeasurementTime = ((double)(startOfList.eventTime + totalWindow)) * ticSizeInSeconds; //expire this now-too-old event, and continue until all expiring events are handled... startOfList = startOfList.next; } } //END of handling this NeutronEvent in this block //prepare this thread's wait condition so will wait for a message //before telling master thread this thread's analysis is complete waitingForMessage.Reset(); } //END handling this block of events } //END of while (keepRunning) }