public FastBackgroundAnalysis(UInt64 gateDeltaTimeInTics, UInt64 gateStartDeltaInTics) { int i; gateWidthInTics = gateDeltaTimeInTics; gateStepInTics = gateStartDeltaInTics; #if USE_SPINTIME spinTimeTotal = 0; spinTimeStart = 0; #endif //initialize the counts for (i = 0; i < RawAnalysisProperties.maxNeutronsPerMultiplicityGate; i++) { numGatesHavingNumNeutrons[i] = 0; } //initialize the event holders inputEventTime = new UInt64[RawAnalysisProperties.maxEventsPerBlock]; inputEventNumNeutrons = new UInt32[RawAnalysisProperties.maxEventsPerBlock]; numEventsThisBlock = 0; //starting from time = 0, then first gate will close in "delta time" timeNextGateWillOpenInTics = 0; timeNextGateWillCloseInTics = gateDeltaTimeInTics; //create the circular linked list theEventCircularLinkedList = new NeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new NeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; //initialize fast-background counters numFastBackgroundGates = 0; totalFastBackgroundObservationTime = 0; //set up the FA BackgroundWorker keepRunning = true; isReadyToAnalyze = false; FBWorker = new BackgroundWorker(); FBWorker.WorkerSupportsCancellation = false; FBWorker.DoWork += new DoWorkEventHandler(FBWorkerDoWork); FBWorker.RunWorkerAsync(); //pause until the FBWorker is working while (FBWorker.IsBusy == false) { Thread.Sleep(1); } }
/// <summary> /// ResetForConcatenation() clears metadata for a new experiment, /// but preserves present histogram dictionary so subsequent data can be added. /// </summary> public void ResetForConcatenation() { int i; #if USE_SPINTIME spinTimeTotal = 0; spinTimeReady = false; #endif //reset the closing time for the next gate to be the first gate starting from 0 timeNextGateWillOpenInTics = 0; timeNextGateWillCloseInTics = gateWidthInTics; //create the circular linked list theEventCircularLinkedList = new NeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new NeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; //initialize fast-background counters numFastBackgroundGates = 0; totalFastBackgroundObservationTime = 0; }
/// <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; NeutronEvent thisEvent, nextEvent; #if USE_SPINTIME spinTimeTotal = 0; spinTimeReady = false; #endif //empty the multiplicity array for (i = 0; i < RawAnalysisProperties.maxNeutronsPerMultiplicityGate; i++) { multiplicity[i] = 0; accidentals[i] = 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 NeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new NeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; isReadyToAnalyze = true; } }
/// <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; NeutronEvent thisEvent, nextEvent; #if USE_SPINTIME spinTimeTotal = 0; spinTimeReady = false; #endif totalMeasurementTime = 0.0; //Don't empty the multiplicity 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 NeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new NeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; isReadyToAnalyze = true; backgroundAnalyzer.ResetForConcatenation(); }
public void HandleAnArrayOfNeutronEvents(List<ulong> timeOfNewEvents, List<uint> neutronsOfNewEvents, int actualEventCount) { UInt32 numNeutrons, aNeutronEvent; int which, numEvents; if (timeOfNewEvents.Count != neutronsOfNewEvents.Count) // URGENT: new list semantics, was this conditional is unneeded now the actualEventCount param is in use { String theProblem = "Array lengths unequal: time[" + timeOfNewEvents.Count + "] neutrons[" + neutronsOfNewEvents.Count + "]"; FireBlockCountMismatchErrorEvent(theProblem); log.TraceEvent(LogLevels.Warning, (int)AnalyzerEventCode.AnalyzerHandlerEvent, theProblem); return; } else if (timeOfNewEvents.Count < 1) // skip these { log.TraceEvent(LogLevels.Warning, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "skipping empty event buffer"); return; } numEvents = actualEventCount; // timeOfNewEvents.Length; //count another event received whether processed or not, in case this event has a time that is out of sequence numNeutronEventsReceivedWhetherProcessedOrNot += (UInt64)numEvents; log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler received Neutron array with " + numEvents + " events. Time of first event=" + timeOfNewEvents[0]); //WAIT for permission to use the shared end-of-stack object PermissionToUseEndOfEventsWait(); for (which = 0; which < numEvents; which++) { if (timeOfNewEvents[which] <= timeOfLastNeutronEvent) { if (timeOfLastNeutronEvent == 0) //then everything is OK { } else //then we've received a neutron out of sequence - abort handling this neutron { String str; str = "Neutron event #" + numNeutronEventsReceivedWhetherProcessedOrNot + " out of sequence with time " + timeOfNewEvents[which] + " tics & " + timeOfLastNeutronEvent; FireNeutronOutOfSequenceErrorEvent(str); log.TraceEvent(LogLevels.Warning, (int)AnalyzerEventCode.AnalyzerHandlerEvent, str); } } else //...add this neutron to the list... { //count another event received numNeutronEventsReceived++; //record time of this event timeOfLastNeutronEvent = timeOfNewEvents[which]; //place the new neutron data in the data-holder at the end of the list aNeutronEvent = neutronsOfNewEvents[which]; endOfNeutronEventList.eventTime = timeOfNewEvents[which]; endOfNeutronEventList.eventNeutrons = aNeutronEvent; numNeutrons = 0; while (aNeutronEvent != 0) { numNeutrons++; aNeutronEvent &= (aNeutronEvent - 1); //Look at how this works: //suppose neutronsOfNewEvent is 01001000, so result should be two. //since event is non zero, count 1 bit and set event to // 01001000 (neutronsOfNewEvent) // &01000111 (neutronsOfNewEvent-1) // =01000000 //then still isn't zero, so count 1 more bit (now 2) and set event to // 01000000 // &00111111 // =00000000 // Done! and result is 2 as desired } endOfNeutronEventList.numNeutrons = numNeutrons; //check to see if the circular linked list would overflow ExtendListIfNeeded(); //move endOfNeutronEventList to the next empty struct endOfNeutronEventList = endOfNeutronEventList.next; //count the number of times around the circular list if (endOfNeutronEventList.serialNumber == 0) { numCircuits++; } } } //unblock the BackgroundWorker which will dispense events to the analyzers waitingForEvent.Set(); PermissionToUseEndOfEventsRelease("HandleAnArrayOfNeutronEvents"); //END OF WAIT to use the shared end-of-stack object }
/// <summary> /// MultiplicityAnalysisSlowBackground. /// 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 MultiplicityAnalysisSlowBackground(double theTicSizeInSeconds, UInt64 gateWidthInTics, UInt64 preDelayInTics, UInt64 accidentalsGateDelayInTics, double deadTimeCoefficientTinNanoSecs, double deadTimeCoefficientAinMicroSecs, double deadTimeCoefficientBinPicoSecs, double deadTimeCoefficientCinNanoSecs) : base(theTicSizeInSeconds) //tell the inherited SDTMultiplicityCounter the ticSize { int i; //store the initialization parameters multiplicityGateWidth = gateWidthInTics; multiplicityDeadDelay = preDelayInTics; multiplicityAccidentalsDelay = accidentalsGateDelayInTics; totalWindow = gateWidthInTics + accidentalsGateDelayInTics; realsWindow = gateWidthInTics + preDelayInTics; //store the SingleDoubleTriple-calculation parameters deadTimeCoeffTinNanoSecs = deadTimeCoefficientTinNanoSecs; deadTimeCoeffAinMicroSecs = deadTimeCoefficientAinMicroSecs; deadTimeCoeffBinPicoSecs = deadTimeCoefficientBinPicoSecs; deadTimeCoeffCinNanoSecs = deadTimeCoefficientCinNanoSecs; #if USE_SPINTIME spinTimeTotal = 0; spinTimeStart = 0; spinTimeReady = false; #endif //empty the multiplicity array for (i = 0; i < RawAnalysisProperties.maxNeutronsPerMultiplicityGate; i++) { multiplicity[i] = 0; accidentals[i] = 0; } totalMeasurementTime = 0.0; //initialize the event holders inputEventNumNeutrons = new UInt32[RawAnalysisProperties.maxEventsPerBlock]; inputEventTime = new UInt64[RawAnalysisProperties.maxEventsPerBlock]; numEventsThisBlock = 0; //create the circular linked list theEventCircularLinkedList = new NeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new NeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; //set up the MASB BackgroundWorker keepRunning = true; isReadyToAnalyze = false; MASBWorker = new BackgroundWorker(); MASBWorker.WorkerSupportsCancellation = false; MASBWorker.DoWork += new DoWorkEventHandler(MASBWorkerDoWork); MASBWorker.RunWorkerAsync(); //pause until the MASBWorker is working while (MASBWorker.IsBusy == false) { Thread.Sleep(1); } }
/// void InitializeEventList(int num) { AHGCCollect(); if (numEventsInCircularLinkedList == 0 || theEventCircularLinkedList == null) { //create stack of RawAnalysisProperties.circularListBlockIncrement neutron events, as a starting point theEventCircularLinkedList = new NeutronEvent(0); //make the first event in the list startOfNeutronEventList = theEventCircularLinkedList; //set pointer to start of list to this first event endOfNeutronEventList = theEventCircularLinkedList; //set pointer to end of list to this first event for (int i = 1; i < num; i++) { endOfNeutronEventList.next = new NeutronEvent(i); //after the present end of list, make a new event endOfNeutronEventList = endOfNeutronEventList.next; //move the pointer to the new end of list } endOfNeutronEventList.next = startOfNeutronEventList; //close the circular linked list, joining the end to the beginning //endOfNeutronEventList = startOfNeutronEventList; //now both the start and end point to the first empty structure numEventsInCircularLinkedList = num; log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler new " + numEventsInCircularLinkedList); } else if (numEventsInCircularLinkedList < num) // extend { ExtendListBy(num - numEventsInCircularLinkedList); } else if (numEventsInCircularLinkedList > num) // clear it, shrink it { startOfNeutronEventList = theEventCircularLinkedList; //set pointer to start of list to this first event endOfNeutronEventList = theEventCircularLinkedList; //set pointer to end of list to this first event theEventCircularLinkedList.Set(0); NeutronEvent ende = startOfNeutronEventList, two = startOfNeutronEventList; for (int i = 0; i < num; i++) { ende.Set(i); two = ende; ende = ende.next; } ende = two; // move back 1 endOfNeutronEventList = ende; endOfNeutronEventList.next = startOfNeutronEventList; //close the circular linked list, joining the end to the beginning //endOfNeutronEventList = startOfNeutronEventList; //now both the start and end point to the first empty structure log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler clear " + numEventsInCircularLinkedList + " (remove " + (numEventsInCircularLinkedList - num) + ")"); numEventsInCircularLinkedList = num; } else // same size just clear it { theEventCircularLinkedList.Set(0); NeutronEvent ende = startOfNeutronEventList.next; for (int i = 0; i < num; i++) { ende.Set(i); ende = ende.next; } log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler clear same size " + numEventsInCircularLinkedList); } AHGCCollect(); }
void MAFBWorkerDoWork(object sender, DoWorkEventArgs e) { String threadName = "MAFBAnalyzer_" + multiplicityGateWidth + "_" + multiplicityDeadDelay; 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 eventNumNeutrons; NeutronEvent anEvent; NeutronEvent nextEvent; NeutronEvent lastEvent; UInt32 totalNeutronsInGate; for (j = 0; j < numEventsThisBlock; j++) { eventTime = inputEventTime[j]; eventNumNeutrons = inputEventNumNeutrons[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. //NOTE: MuliplicityAnalysisFastBackground needs ONLY the numNeutrons, not the channels... endOfList.eventTime = eventTime; endOfList.numNeutrons = eventNumNeutrons; //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 NeutronEvent(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; startTime = startOfList.eventTime; totalNeutronsInGate = 0; 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 + multiplicityDeadDelay)) { totalNeutronsInGate += anEvent.numNeutrons; } //...but always continue to the next event... anEvent = anEvent.next; } UInt32 numIdenticalGatesForThisNeutronEvent; //store this gate having this many neutrons, once for each neutron in the triggering event //NOTE: we DO store the gates having zero neutrons numIdenticalGatesForThisNeutronEvent = startOfList.numNeutrons; if (totalNeutronsInGate < 999) { multiplicity[totalNeutronsInGate] += numIdenticalGatesForThisNeutronEvent; } else { //XXX need to fire an event here to announce a gate with too many neutrons multiplicity[999] += numIdenticalGatesForThisNeutronEvent; } //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) }
void AHWorkerDoWork(object sender, DoWorkEventArgs e) { int i, j; int numFeynmanAnalyzers; int numMultiplicityFastBackgroundAnalyzers; int numMultiplicitySlowBackgroundAnalyzers; int numFastBackgroundAnalyzers; int numRateAnalyzers; int numRossiAlphaAnalyzers; int numEventSpacingAnalyzers; int numCoincidenceSlowBackgroundAnalyzers; bool quittingAtEndOfList = false; UInt32[] eventNeutrons; UInt32[] eventNumNeutrons; UInt64[] eventTimes; int numEventsThisBlock; int maxEventsPerBlock = RawAnalysisProperties.maxEventsPerBlock; #if USE_SPINTIME bool spinTimeReady; #endif String threadName = "AnalyzerHandler"; Thread.CurrentThread.Name = threadName; eventNeutrons = new UInt32[maxEventsPerBlock]; eventNumNeutrons = new UInt32[maxEventsPerBlock]; eventTimes = new UInt64[maxEventsPerBlock]; #if USE_SPINTIME spinTimeReady = false; #endif while (AHWorkerStopNow == false) { #if USE_SPINTIME if (spinTimeReady) { StartSpinTime(); } #endif waitingForEvent.Wait(); //wait for a neutron or other signal log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "Beginning processing a neutron or other signal."); #if USE_SPINTIME if (spinTimeReady) { EndSpinTime(); } else { spinTimeReady = true; } #endif if ((AHWorkerStopNow == false)) //then process the next neutron { //first, see if we are at the end of the list already //Note that AHWorkerStopAtEndOfEvents is true only if the controlling thread //has called EndAnalysisWhenFinishedWithPresentEventQueue() to indicate //there will be no more neutron events, //giving permission for this worker to stop at the end of the queue. if (AHWorkerStopAtEndOfEvents == true) { PermissionToUseEndOfEventsWait(); //see if we have processed the last neutron... if (startOfNeutronEventList.serialNumber == endOfNeutronEventList.serialNumber) { quittingAtEndOfList = true; AHWorkerStopNow = true; log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler reached end of events and is setting flag to stop its background worker at location #1."); } PermissionToUseEndOfEventsRelease("AH AHWorkerStopAtEndOfEvents"); } if (quittingAtEndOfList == false) //...then haven't reached end of list...keep processing... { //process up to RawAnalysisProperties.maxEventsPerBlock neutron events numEventsThisBlock = 0; PermissionToUseEndOfEventsWait(); while ((numEventsThisBlock < maxEventsPerBlock) && (startOfNeutronEventList.serialNumber != endOfNeutronEventList.serialNumber)) { eventNeutrons[numEventsThisBlock] = startOfNeutronEventList.eventNeutrons; eventNumNeutrons[numEventsThisBlock] = startOfNeutronEventList.numNeutrons; eventTimes[numEventsThisBlock] = startOfNeutronEventList.eventTime; numEventsThisBlock++; startOfNeutronEventList = startOfNeutronEventList.next; } PermissionToUseEndOfEventsRelease("AH process maximum events"); //pass the events to all the RateAnalyzers. //XXX Since now handling blocks, is it time to multithread the RateAnalyzers?? for (j = 0; j < numEventsThisBlock; j++) { numRateAnalyzers = rateAnalyzers.Count; for (i = 0; i < numRateAnalyzers; i++) { rateAnalyzers[i].HandleANeutronEvent(eventTimes[j], eventNeutrons[j], eventNumNeutrons[j]); } } //pass the event to all the MultiplicityAnalyzers numMultiplicityFastBackgroundAnalyzers = multiplicityFastBackgroundAnalyzers.Count; for (i = 0; i < numMultiplicityFastBackgroundAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (multiplicityFastBackgroundAnalyzers[i].isReadyToAnalyze == false) { //spin until this MultiplicityFastBackgroundAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndFastMultiplicitySpinTime(); #endif //set the input for the ith MultiplicityFastBackgroundAnalyzer for (j = 0; j < numEventsThisBlock; j++) { multiplicityFastBackgroundAnalyzers[i].inputEventTime[j] = eventTimes[j]; multiplicityFastBackgroundAnalyzers[i].inputEventNumNeutrons[j] = eventNumNeutrons[j]; } multiplicityFastBackgroundAnalyzers[i].numEventsThisBlock = numEventsThisBlock; //clear the thread wait condition, so ith MultiplicityFastBackgroundAnalyzer will analyze multiplicityFastBackgroundAnalyzers[i].isReadyToAnalyze = false; //clear the flag because we're about to make this analyzer busy and no longer ready multiplicityFastBackgroundAnalyzers[i].waitingForMessage.Set(); //"put the ticket into the gate," so thread will do its analysis } //pass the event to all the SlowMultiplicityAnalyzers numMultiplicitySlowBackgroundAnalyzers = multiplicitySlowBackgroundAnalyzers.Count; for (i = 0; i < numMultiplicitySlowBackgroundAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (multiplicitySlowBackgroundAnalyzers[i].isReadyToAnalyze == false) { //spin until this MultiplicityFastBackgroundAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndSlowMultiplicitySpinTime(); #endif //set the input for the ith MultiplicitySlowBackgroundAnalyzer for (j = 0; j < numEventsThisBlock; j++) { multiplicitySlowBackgroundAnalyzers[i].inputEventTime[j] = eventTimes[j]; multiplicitySlowBackgroundAnalyzers[i].inputEventNumNeutrons[j] = eventNumNeutrons[j]; } multiplicitySlowBackgroundAnalyzers[i].numEventsThisBlock = numEventsThisBlock; //clear the thread wait condition, so ith MultiplicitySlowBackgroundAnalyzer will analyzer multiplicitySlowBackgroundAnalyzers[i].isReadyToAnalyze = false; //clear the flag because we're about to make this analyzer busy and no longer ready multiplicitySlowBackgroundAnalyzers[i].waitingForMessage.Set(); //"put the ticket into the gate," so thread will do its analysis } //pass the event to all the FastBackgroundAnalyzers numFastBackgroundAnalyzers = fastBackgroundAnalyzers.Count; for (i = 0; i < numFastBackgroundAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (fastBackgroundAnalyzers[i].isReadyToAnalyze == false) { //spin until this FastBackgroundAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndFastBackSpinTime(); #endif //set the input for the ith FastBackgroundAnalyzer for (j = 0; j < numEventsThisBlock; j++) { fastBackgroundAnalyzers[i].inputEventTime[j] = eventTimes[j]; fastBackgroundAnalyzers[i].inputEventNumNeutrons[j] = eventNumNeutrons[j]; } fastBackgroundAnalyzers[i].numEventsThisBlock = numEventsThisBlock; //clear the thread wait condition, so ith FastBackgroundAnalyzer will analyze fastBackgroundAnalyzers[i].isReadyToAnalyze = false; //clear the flag because we're about to make this analyzer busy and no longer ready fastBackgroundAnalyzers[i].waitingForMessage.Set(); //"put the ticket into the gate," so thread will do its analysis } //pass the event to all the CoincidenceSlowBackgroundAnalyzers numCoincidenceSlowBackgroundAnalyzers = coincidenceSlowBackgroundAnalyzers.Count; for (i = 0; i < numCoincidenceSlowBackgroundAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (coincidenceSlowBackgroundAnalyzers[i].isReadyToAnalyze == false) { //spin until this CoincidenceSlowBackgroundAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndSlowMultiplicitySpinTime(); #endif //set the input for the ith CoincidenceSlowBackgroundAnalyzer for (j = 0; j < numEventsThisBlock; j++) { coincidenceSlowBackgroundAnalyzers[i].inputEventTime[j] = eventTimes[j]; coincidenceSlowBackgroundAnalyzers[i].inputEventNeutrons[j] = eventNeutrons[j]; } coincidenceSlowBackgroundAnalyzers[i].numEventsThisBlock = numEventsThisBlock; //clear the thread wait condition, so ith CoincidenceSlowBackgroundAnalyzer will analyze coincidenceSlowBackgroundAnalyzers[i].isReadyToAnalyze = false; //clear the flag because we're about to make this analyzer busy and no longer ready coincidenceSlowBackgroundAnalyzers[i].waitingForMessage.Set(); //"put the ticket into the gate," so thread will do its analysis } //pass the event to all the FeynmanAnalyzers numFeynmanAnalyzers = feynmanAnalyzers.Count; for (i = 0; i < numFeynmanAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (feynmanAnalyzers[i].isReadyToAnalyze == false) { //spin until this FeynmanAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndFeynmanSpinTime(); #endif //set the input for the ith FeynmanAnalyzer for (j = 0; j < numEventsThisBlock; j++) { feynmanAnalyzers[i].inputEventTime[j] = eventTimes[j]; feynmanAnalyzers[i].inputEventNumNeutrons[j] = eventNumNeutrons[j]; } feynmanAnalyzers[i].numEventsThisBlock = numEventsThisBlock; //clear the thread wait condition, so ith FeynmanAnalyzer will analyze feynmanAnalyzers[i].isReadyToAnalyze = false; //clear the flag because we're about to make this analyzer busy and no longer ready feynmanAnalyzers[i].waitingForMessage.Set(); //"put the ticket into the gate," so thread will do its analysis } //pass the event to all the RossiAlphaAnalyzers numRossiAlphaAnalyzers = rossiAlphaAnalyzers.Count; for (i = 0; i < numRossiAlphaAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (rossiAlphaAnalyzers[i].isReadyToAnalyze == false) { //spin until this RossiAlphaAnalzyer has completed the last neutron it was given } #if USE_SPINTIME EndRossiAlphaSpinTime(); #endif //set the input for the ith RossiAlphaAnalyzer for (j = 0; j < numEventsThisBlock; j++) { rossiAlphaAnalyzers[i].inputEventTime[j] = eventTimes[j]; rossiAlphaAnalyzers[i].inputEventNeutrons[j] = eventNeutrons[j]; rossiAlphaAnalyzers[i].inputEventNumNeutrons[j] = eventNumNeutrons[j]; } rossiAlphaAnalyzers[i].numEventsThisBlock = numEventsThisBlock; //clear the thread wait condition, so ith RossiAlphaAnalyzer will analyze rossiAlphaAnalyzers[i].isReadyToAnalyze = false; //clear the flag because we're about to make this analyzer busy and no longer ready rossiAlphaAnalyzers[i].waitingForMessage.Set(); //"put the ticket into the gate," so thread will do its analysis } //pass the event to all the EventSpacingAnalyzers numEventSpacingAnalyzers = eventSpacingAnalyzers.Count; for (i = 0; i < numEventSpacingAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (eventSpacingAnalyzers[i].isReadyToAnalyze == false) { //spin until this EventSpacingAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndEventSpacingSpinTime(); #endif //set the input for the ith EventSpacingAnalyzer for (j = 0; j < numEventsThisBlock; j++) { eventSpacingAnalyzers[i].inputEventTime[j] = eventTimes[j]; eventSpacingAnalyzers[i].inputEventNumNeutrons[j] = eventNumNeutrons[j]; } eventSpacingAnalyzers[i].numEventsThisBlock = numEventsThisBlock; //clear the thread wait condition, so ith EventSpacingAnalyzer will analyze eventSpacingAnalyzers[i].isReadyToAnalyze = false; //clear the flag because we're about to make this analyzer busy and no longer ready eventSpacingAnalyzers[i].waitingForMessage.Set(); //"put the ticket into the gate," so thread will do its analysis } //FINISHED passing this neutron event to all the analyzers. numNeutronEventsCompleted += (UInt64)numEventsThisBlock; //See if there are any more neutron events PermissionToUseEndOfEventsWait(); //see if we have processed the last neutron... if (startOfNeutronEventList.serialNumber == endOfNeutronEventList.serialNumber) { //reset the ManualResetEventSlim, so the thread will wait for an event waitingForEvent.Reset(); //if already have been told to stop at the end, then have reached the end so stop now if (AHWorkerStopAtEndOfEvents == true) { AHWorkerStopNow = true; log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler reached end of events and is setting flag to stop its background worker at location #2."); } } PermissionToUseEndOfEventsRelease("AH remaining events processing"); } } //END of processing the next neutron else if (AHWorkerStopAtEndOfEvents == true) { AHWorkerStopNow = true; log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler reached end of events and is setting flag to stop its background worker at location #3."); } } //END of while (AHWorkerStopNow == false) log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler is exiting end of events and is waiting for Analyses to complete."); //MAKE SURE all analyzers have finished with the last buffer of neutrons before ending this AHWorkerDoWork() //Don't have to check RateGateAnalyzers - these are single threaded and have been completed by this thread //Check the MultiplicityFastBackgroundAnalyzers numMultiplicityFastBackgroundAnalyzers = multiplicityFastBackgroundAnalyzers.Count; for (i = 0; i < numMultiplicityFastBackgroundAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (multiplicityFastBackgroundAnalyzers[i].isReadyToAnalyze == false) { //spin until this MultiplicityFastBackgroundAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndFastMultiplicitySpinTime(); #endif } //Check the MultiplicitySlowBackgroundAnalyzers numMultiplicitySlowBackgroundAnalyzers = multiplicitySlowBackgroundAnalyzers.Count; for (i = 0; i < numMultiplicitySlowBackgroundAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (multiplicitySlowBackgroundAnalyzers[i].isReadyToAnalyze == false) { //spin until this MultiplicityFastBackgroundAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndSlowMultiplicitySpinTime(); #endif } //Check the FastBackgroundAnalyzers numFastBackgroundAnalyzers = fastBackgroundAnalyzers.Count; for (i = 0; i < numFastBackgroundAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (fastBackgroundAnalyzers[i].isReadyToAnalyze == false) { //spin until this FastBackgroundAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndFastBackSpinTime(); #endif } //Check the CoincidenceSlowBackgroundAnalyzers numCoincidenceSlowBackgroundAnalyzers = coincidenceSlowBackgroundAnalyzers.Count; for (i = 0; i < numCoincidenceSlowBackgroundAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (coincidenceSlowBackgroundAnalyzers[i].isReadyToAnalyze == false) { //spin until this MultiplicityFastBackgroundAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndSlowMultiplicitySpinTime(); #endif } //Check the FeynmanAnalyzers numFeynmanAnalyzers = feynmanAnalyzers.Count; for (i = 0; i < numFeynmanAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (feynmanAnalyzers[i].isReadyToAnalyze == false) { //spin until this FeynmanAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndFeynmanSpinTime(); #endif } //Check the RossiAlphaAnalyzers numRossiAlphaAnalyzers = rossiAlphaAnalyzers.Count; for (i = 0; i < numRossiAlphaAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (rossiAlphaAnalyzers[i].isReadyToAnalyze == false) { //spin until this RossiAlphaAnalzyer has completed the last neutron it was given } #if USE_SPINTIME EndRossiAlphaSpinTime(); #endif } //Check the EventSpacingAnalyzers numEventSpacingAnalyzers = eventSpacingAnalyzers.Count; for (i = 0; i < numEventSpacingAnalyzers; i++) { #if USE_SPINTIME StartSpinTime(); #endif while (eventSpacingAnalyzers[i].isReadyToAnalyze == false) { //spin until this FeynmanAnalyzer has completed the last neutron it was given } #if USE_SPINTIME EndEventSpacingSpinTime(); #endif } //FINISHED confirming all the analyzers have finished log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler has completed handling neutrons and is exiting."); } //END of AHWorkerDoWork()
void FBWorkerDoWork(object sender, DoWorkEventArgs e) { String threadName = "FastBackgroundAnalyzer_" + gateWidthInTics; 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 eventNumNeutrons; NeutronEvent anEvent; NeutronEvent nextEvent; NeutronEvent lastEvent; UInt32 totalNeutronsInGate; for (j = 0; j < numEventsThisBlock; j++) { eventTime = inputEventTime[j]; eventNumNeutrons = inputEventNumNeutrons[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. //NOTE: MuliplicityAnalysisFastBackground needs ONLY the numNeutrons, not the channels... endOfList.eventTime = eventTime; endOfList.numNeutrons = eventNumNeutrons; //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 NeutronEvent(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++; } while (lastEvent.eventTime > timeNextGateWillCloseInTics) { totalNeutronsInGate = 0; //throw out any expired events while ((startOfList.serialNumber != endOfList.serialNumber) && (startOfList.eventTime < timeNextGateWillOpenInTics)) { startOfList = startOfList.next; } //skip ahead past any empty gates if (startOfList.eventTime >= timeNextGateWillCloseInTics) { //This looks complicated, so bear with me... //Earliest a non-empty gate could open is next eventtime minus gateWidth, //but +1 because events are excluded if they occur at the time the gate would close. UInt64 timeNonEmptyGateCouldOpen = (startOfList.eventTime + 1) - gateWidthInTics; //emptyTimeSpan is the delta time between the time the present gate opened and this earliest time UInt64 emptyTimeSpan = timeNonEmptyGateCouldOpen - timeNextGateWillOpenInTics; //Then the number of empty time steps is this deltaTime divided by the gateStep UInt64 numEmptyTimesteps = emptyTimeSpan / gateStepInTics; //But if the remainder of this deltaTime/gateStep isn't 0, then "round up" to next gate, or +1 to numEmptysteps if ((emptyTimeSpan % gateStepInTics) > 0) { numEmptyTimesteps++; } //use this numEmpty gates to jump ahead to first non-empty gate timeNextGateWillOpenInTics += numEmptyTimesteps * gateStepInTics; timeNextGateWillCloseInTics = timeNextGateWillOpenInTics + gateWidthInTics; numGatesHavingNumNeutrons[0] += numEmptyTimesteps; numFastBackgroundGates += numEmptyTimesteps; } //check again, so non-empty gates will be counted only once, //to make sure the first non-empty gate is closed before we count in it... if (lastEvent.eventTime > timeNextGateWillCloseInTics) { //count neutrons in this gate anEvent = startOfList; while ((anEvent.serialNumber != endOfList.serialNumber) && (anEvent.eventTime < timeNextGateWillCloseInTics)) { //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 >= timeNextGateWillOpenInTics) { totalNeutronsInGate += anEvent.numNeutrons; } //...but always continue to the next event... anEvent = anEvent.next; } //store results if (totalNeutronsInGate < 999) { numGatesHavingNumNeutrons[totalNeutronsInGate]++; } else { //XXX need to fire an event here to announce a gate having population above limit supported (998) numGatesHavingNumNeutrons[999]++; } //move gate forward in time, until last event isn't after the gate-close time timeNextGateWillOpenInTics += gateStepInTics; timeNextGateWillCloseInTics += gateStepInTics; //count the completion of another gate numFastBackgroundGates++; } } //store the final observation time totalFastBackgroundObservationTime = timeNextGateWillOpenInTics; } //END of handling this NeutronEvent } //END of handling all the NeutronEvents 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 of while (keepRunning) }
/// <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; NeutronEvent thisEvent, nextEvent; #if USE_SPINTIME spinTimeTotal = 0; spinTimeReady = false; #endif //reset the closing time for the next gate to be the first gate starting from 0 timeNextGateWillOpenInTics = 0; timeNextGateWillCloseInTics = gateWidthInTics; //empty the dictionary of gate counts for (i = 0; i < RawAnalysisProperties.maxNeutronsPerMultiplicityGate; i++) { numGatesHavingNumNeutrons[i] = 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 NeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new NeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; //initialize fast-background counters numFastBackgroundGates = 0; totalFastBackgroundObservationTime = 0; } }
/// <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; NeutronEvent thisEvent, nextEvent; //pause until the current AHWorker is done ... while (AHWorker.IsBusy == true) { } //reset all the analyzers for (i = 0; i < feynmanAnalyzers.Count; i++) { feynmanAnalyzers[i].ResetCompletely(closeCounters); } for (i = 0; i < multiplicityFastBackgroundAnalyzers.Count; i++) { multiplicityFastBackgroundAnalyzers[i].ResetCompletely(closeCounters); } for (i = 0; i < multiplicitySlowBackgroundAnalyzers.Count; i++) { multiplicitySlowBackgroundAnalyzers[i].ResetCompletely(closeCounters); } for (i = 0; i < coincidenceSlowBackgroundAnalyzers.Count; i++) { coincidenceSlowBackgroundAnalyzers[i].ResetCompletely(closeCounters); } for (i = 0; i < rateAnalyzers.Count; i++) { rateAnalyzers[i].ResetCompletely(closeCounters); } for (i = 0; i < rossiAlphaAnalyzers.Count; i++) { rossiAlphaAnalyzers[i].ResetCompletely(closeCounters); } for (i = 0; i < fastBackgroundAnalyzers.Count; i++) { fastBackgroundAnalyzers[i].ResetCompletely(closeCounters); } for (i = 0; i < eventSpacingAnalyzers.Count; i++) { eventSpacingAnalyzers[i].ResetCompletely(closeCounters); } numNeutronEventsReceived = 0; numNeutronEventsReceivedWhetherProcessedOrNot = 0; numNeutronEventsCompleted = 0; numCircuits = 0; timeOfLastNeutronEvent = 0; #if USE_SPINTIME ResetSpinTime(); #endif //break the circular references, so garbage collector will do its thing nextEvent = theEventCircularLinkedList; while (nextEvent != null) { thisEvent = nextEvent; nextEvent = thisEvent.next; thisEvent.next = null; } thisEvent = null; theEventCircularLinkedList = null; startOfNeutronEventList = null; endOfNeutronEventList = null; // selectively invoke the garbage collector now AHGCCollect(); if (closeCounters) return; //create stack of RawAnalysisProperties.circularListBlockIncrement neutron events, as a starting point InitializeEventList(); //set up the AH BackgroundWorker waitingForEvent.Reset(); AHWorkerStopNow = false; AHWorkerHasCompleted = false; AHWorkerStopAtEndOfEvents = false; //pause until the previous AHWorker is done ... while (AHWorker.IsBusy == true) { } AHWorker = new BackgroundWorker(); AHWorker.WorkerSupportsCancellation = false; //parent will stop the worker with the boolean flags AHWorker.DoWork += new DoWorkEventHandler(AHWorkerDoWork); AHWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(AHWorkerRunWorkerCompleted); AHWorker.RunWorkerAsync(); //pause until the AHWorker is working... while (AHWorker.IsBusy == false) { } }
/// void InitializeEventList() { //create stack of RawAnalysisProperties.circularListBlockIncrement neutron events, as a starting point theEventCircularLinkedList = new NeutronEvent(0); //make the first event in the list startOfNeutronEventList = theEventCircularLinkedList; //set pointer to start of list to this first event endOfNeutronEventList = theEventCircularLinkedList; //set pointer to end of list to this first event for (int i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfNeutronEventList.next = new NeutronEvent(i); //after the present end of list, make a new event endOfNeutronEventList = endOfNeutronEventList.next; //move the pointer to the new end of list } endOfNeutronEventList.next = startOfNeutronEventList; //close the circular linked list, joining the end to the beginning endOfNeutronEventList = startOfNeutronEventList; //now both the start and end point to the first empty structure numEventsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; }
public void HandleANeutronEvent(UInt64 timeOfNewEvent, UInt32 neutronsOfNewEvent) { UInt32 numNeutrons; //count another event received whether processed or not, in case this event has a time that is out of sequence numNeutronEventsReceivedWhetherProcessedOrNot++; if (verboseTrace) log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler received Neutron event #" + numNeutronEventsReceivedWhetherProcessedOrNot + " at Time= " + timeOfNewEvent + " Neutrons=0x" + String.Format("{0:X8}", neutronsOfNewEvent)); if (timeOfNewEvent <= timeOfLastNeutronEvent) { if (timeOfLastNeutronEvent == 0) //then everything is OK { } else //then we've received a neutron out of sequence - abort handling this neutron { String str; str = "Neutron event #" + numNeutronEventsReceivedWhetherProcessedOrNot + " out of sequence with time " + timeOfNewEvent + " tics"; FireNeutronOutOfSequenceErrorEvent(str); log.TraceEvent(LogLevels.Warning, (int)AnalyzerEventCode.AnalyzerHandlerEvent, str); return; //abort handling this neutron } } //count another event received numNeutronEventsReceived++; //record time of this event timeOfLastNeutronEvent = timeOfNewEvent; //WAIT for permission to use the shared end-of-stack object PermissionToUseEndOfEventsWait(); //place the new neutron data in the data-holder at the end of the list endOfNeutronEventList.eventTime = timeOfNewEvent; endOfNeutronEventList.eventNeutrons = neutronsOfNewEvent; numNeutrons = 0; while (neutronsOfNewEvent != 0) { numNeutrons++; neutronsOfNewEvent &= (neutronsOfNewEvent - 1); //Look at how this works: //suppose neutronsOfNewEvent is 01001000, so result should be two. //since event is non zero, count 1 bit and set event to // 01001000 (neutronsOfNewEvent) // &01000111 (neutronsOfNewEvent-1) // =01000000 //then still isn't zero, so count 1 more bit (now 2) and set event to // 01000000 // &00111111 // =00000000 // Done! and result is 2 as desired } endOfNeutronEventList.numNeutrons = numNeutrons; //check to see if the circular linked list would overflow ExtendListIfNeeded(); //move endOfNeutronEventList to the next empty struct endOfNeutronEventList = endOfNeutronEventList.next; //count the number of times around the circular list if (endOfNeutronEventList.serialNumber == 0) { numCircuits++; } //unblock the BackgroundWorker which will dispense events to the analyzers waitingForEvent.Set(); PermissionToUseEndOfEventsRelease("HandleANeutronEvent"); //END OF WAIT to use the shared end-of-stack object }
/// <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; NeutronEvent thisEvent, nextEvent; #if USE_SPINTIME spinTimeTotal = 0; spinTimeReady = false; #endif //empty the multiplicity array for (i = 0; i < RawAnalysisProperties.maxNeutronsPerMultiplicityGate; i++) { multiplicity[i] = 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 NeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new NeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; isReadyToAnalyze = true; } backgroundAnalyzer.ResetCompletely(closeCounters); }
void MASBWorkerDoWork(object sender, DoWorkEventArgs e) { String threadName = "MASBAnalyzer_" + multiplicityGateWidth + "_" + multiplicityDeadDelay + "_" + multiplicityAccidentalsDelay; 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 eventNumNeutrons; NeutronEvent anEvent; NeutronEvent nextEvent; NeutronEvent lastEvent; UInt32 totalNeutronsInGate; UInt32 totalInAccidentalsGate; /////////////////////////////////////////////////////////// List <String> fileLines = new List <string>(); /////////////////////////////////////////////////////////// for (j = 0; j < numEventsThisBlock; j++) { eventTime = inputEventTime[j]; eventNumNeutrons = inputEventNumNeutrons[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. //NOTE: MuliplicityAnalysisFastBackground needs ONLY the numNeutrons, not the channels... endOfList.eventTime = eventTime; endOfList.numNeutrons = eventNumNeutrons; //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 NeutronEvent(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; startTime = startOfList.eventTime; totalNeutronsInGate = 0; totalInAccidentalsGate = 0; 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 + multiplicityDeadDelay)) && (anEvent.eventTime < (startTime + realsWindow))) { totalNeutronsInGate += anEvent.numNeutrons; } //now check for neurtons in the accidentals gate if (anEvent.eventTime >= (startTime + multiplicityAccidentalsDelay)) { totalInAccidentalsGate += anEvent.numNeutrons; } //...but always continue to the next event... anEvent = anEvent.next; } UInt32 numIdenticalGatesForThisNeutronEvent; //store this gate having this many neutrons, once for each neutron in the triggering event //NOTE: we DO store the gates having zero neutrons numIdenticalGatesForThisNeutronEvent = startOfList.numNeutrons; if (totalNeutronsInGate < 999) { multiplicity[totalNeutronsInGate] += numIdenticalGatesForThisNeutronEvent; } else { //XXX need to fire an event here to announce a gate with too many neutrons multiplicity[999] += numIdenticalGatesForThisNeutronEvent; } if (totalInAccidentalsGate < 999) { accidentals[totalInAccidentalsGate] += numIdenticalGatesForThisNeutronEvent; } else { //XXX need to fire an event here to announce a gate with too many neutrons accidentals[999] += numIdenticalGatesForThisNeutronEvent; } //record the time of this expiring event; this is the total measurement time totalMeasurementTime = ((double)(startOfList.eventTime + realsWindow)) * ticSizeInSeconds; //expire this now-too-old event, and continue until all expiring events are handled... startOfList = startOfList.next; /////////////////////////////////////////////////// fileLines.Add(j.ToString() + "," + lastEvent.eventTime.ToString() + "," + startOfList.eventTime.ToString() + "," + totalNeutronsInGate.ToString() + "," + totalInAccidentalsGate.ToString() + "," + multiplicity[totalNeutronsInGate].ToString() + "," + accidentals[totalNeutronsInGate].ToString() + "," + totalMeasurementTime.ToString() + "," + anEvent.serialNumber.ToString() + "," + endOfList.serialNumber.ToString() + "," + anEvent.eventTime.ToString() + "," ); /////////////////////////////////////////////////// } } //END of handling this NeutronEvent in this block /////////////////////////////////////////////////////////// //File.WriteAllLines("MultiplicityAnalysisSlowBackground.csv", fileLines.ToArray()); /////////////////////////////////////////////////////////// //This was blowing chunks. HN 5/1/2018 //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) }
public MultiplicityAnalysisFastBackground(double theTicSizeInSeconds, UInt64 gateWidthInTics, UInt64 preDelayInTics, FastBackgroundAnalysis fba, double deadTimeCoefficientTinNanoSecs, double deadTimeCoefficientAinMicroSecs, double deadTimeCoefficientBinPicoSecs, double deadTimeCoefficientCinNanoSecs) : base(theTicSizeInSeconds) //tell the inherited SDTMultiplicityCounter the ticSize { int i; //store the initialization parameters backgroundAnalyzer = fba; multiplicityGateWidth = gateWidthInTics; multiplicityDeadDelay = preDelayInTics; totalWindow = gateWidthInTics + preDelayInTics; //store the SingleDoubleTriple-calculation parameters deadTimeCoeffTinNanoSecs = deadTimeCoefficientTinNanoSecs; deadTimeCoeffAinMicroSecs = deadTimeCoefficientAinMicroSecs; deadTimeCoeffBinPicoSecs = deadTimeCoefficientBinPicoSecs; deadTimeCoeffCinNanoSecs = deadTimeCoefficientCinNanoSecs; #if USE_SPINTIME spinTimeTotal = 0; spinTimeStart = 0; spinTimeReady = false; #endif //empty the multiplicity array for (i = 0; i < RawAnalysisProperties.maxNeutronsPerMultiplicityGate; i++) { multiplicity[i] = 0; } totalMeasurementTime = 0.0; //initialize the event holders inputEventNumNeutrons = new UInt32[RawAnalysisProperties.maxEventsPerBlock]; inputEventTime = new UInt64[RawAnalysisProperties.maxEventsPerBlock]; numEventsThisBlock = 0; //create the circular linked list theEventCircularLinkedList = new NeutronEvent(0); startOfList = theEventCircularLinkedList; endOfList = theEventCircularLinkedList; for (i = 1; i < RawAnalysisProperties.circularListBlockIncrement; i++) { endOfList.next = new NeutronEvent(i); endOfList = endOfList.next; } numObjectsInCircularLinkedList = RawAnalysisProperties.circularListBlockIncrement; endOfList.next = startOfList; endOfList = startOfList; numCircuits = 0; //set up the MAFB BackgroundWorker keepRunning = true; isReadyToAnalyze = false; MAFBWorker = new BackgroundWorker(); MAFBWorker.WorkerSupportsCancellation = false; MAFBWorker.DoWork += new DoWorkEventHandler(MAFBWorkerDoWork); MAFBWorker.RunWorkerAsync(); //pause until the MAFBWorker is working while (MAFBWorker.IsBusy == false) { Thread.Sleep(1); } }
void ExtendListBy(int num) { int i; NeutronEvent anEvent; NeutronEvent nextEvent; anEvent = endOfNeutronEventList; nextEvent = endOfNeutronEventList.next; for (i = 0; i < num; i++) { anEvent.next = new NeutronEvent(i + numEventsInCircularLinkedList); anEvent = anEvent.next; } anEvent.next = nextEvent; //re-close the linked list, pointing the last new event back to the next event in list numEventsInCircularLinkedList += num; endOfNeutronEventList = anEvent; startOfNeutronEventList = theEventCircularLinkedList; log.TraceEvent(LogLevels.Verbose, (int)AnalyzerEventCode.AnalyzerHandlerEvent, "AnalyzerHandler extending CircularArraySize by " + num + " to " + numEventsInCircularLinkedList); }