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;
        }
Example #3
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();
        }
Example #5
0
        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
        }
Example #6
0
        /// <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);
            }
        }
Example #7
0
        ///
        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();
        }
        /// <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();
        }
        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)  
        }
Example #10
0
        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;
            }
        }
        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)
        }
Example #14
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)
            {
            }
        }
        /// <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;
            }

        }
Example #16
0
        ///
        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;

        }
        /// <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;
        }
Example #18
0
        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
        }
        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>
        /// 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);

        }
Example #21
0
        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);
            }
        }
Example #23
0
        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);
        }