/* * ProfilerPlaneSimulatorV.cpp * * Created on: Oct 19, 2015 * Author: Hovanes Egiyan */ #include "ProfilerPlaneSimulatorV.hh" using namespace std; unsigned ProfilerPlaneSimulatorV::ppsvSleepTime = 1000000; // Main constructor ProfilerPlaneSimulatorV::ProfilerPlaneSimulatorV( ProfilerDetector* det, const bool reversedAxis ) : MutexedClass(), ProfilerPlaneData( reversedAxis ), ProfilerDetComponent( det ) { std::cout << " Entering " << __FUNCTION__ << std::endl; // Set the efficiency to a random number between 0.7 and 1.0 and use this // efficiency for this slice in the simulations. TRandom randGenerator; struct timespec tms; clock_gettime( CLOCK_REALTIME, &tms ); randGenerator.SetSeed( tms.tv_nsec ); for( unsigned iFibr = 0; iFibr < getChanNumber(); iFibr++ ) { ppdEffcCorr[iFibr] = randGenerator.Uniform( 1.0, 1.3 ); // ppdEffcCorr[iFibr] = 1; } return; } // Copy constructor ProfilerPlaneSimulatorV::ProfilerPlaneSimulatorV( const ProfilerPlaneSimulatorV& p ) : MutexedClass( p ), ProfilerPlaneData( p ), ProfilerDetComponent( p ) { std::cout << " Entering " << __FUNCTION__ << std::endl; return; } // class destructor ProfilerPlaneSimulatorV::~ProfilerPlaneSimulatorV() { return; } // Assignment operator ProfilerPlaneSimulatorV& ProfilerPlaneSimulatorV::operator=( const ProfilerPlaneSimulatorV& p ) { MutexedClass::operator=( p ); ProfilerPlaneData::operator=( p ); ProfilerDetComponent::operator =( p ); return *this; } // Override the setPVs method so that it is followed by changing the number of // slices for the simulators to the length of FIFO. It is different from the // actual data collector. inline ProfilerPVs* ProfilerPlaneSimulatorV::setPVs( ProfilerPVs* pv ) { ProfilerDetComponent::setPVs( pv ); cout << "Setting number of slices for simulator " << getName() << " to " << getNFIFO() << endl; // Change the number of slices to be equal to the FIFO length modifyNumberOfSlices( getNFIFO() ); return pv; } // Instantiate the time slices void ProfilerPlaneSimulatorV::createSlices() { cout << "Creating " << ppdSlices.size() << " slices for simulator " << getName() << endl; MtxLock objLock( mcMutex ); // First define the integrated slice. The integrated slice does not get simulated // independently, but is the sum of all individual time-slices. const std::string name = ppdName + ":" + "Integrated"; const vector yAxis( ppdAxis.size(), 0.0 ); ProfilerPlaneSliceSimulator* intedSlice = new ProfilerPlaneSliceSimulator( name, ppdAxis, yAxis ); intedSlice->setAmpl( 500. ); intedSlice->setMean( 3.0 ); intedSlice->setWidth( 7.0 ); intedSlice->setBkgLevel( 25.0 ); intedSlice->setBkgSlope( 0.005 ); intedSlice->defineHistogram(); intedSlice->defineDistFunc(); ppdIntegratedSlice = intedSlice; // Loop over slices and create slices. The vector size should have already been set in the // constructor. for ( unsigned iSlice = 0; iSlice < ppdSlices.size(); iSlice++ ) { stringstream ssName; ssName << ppdName << ":" << iSlice; const std::string name = ssName.str(); const vector yAxis( ppdAxis.size(), 0.0 ); // Create the simulator objects ProfilerPlaneSliceSimulator* simSlice = new ProfilerPlaneSliceSimulator( name, ppdAxis, yAxis ); // Set the parameters for amplitude, central location, width and background. simSlice->setAmpl( ppdIntegratedSlice->getAmplitude() ); simSlice->setMean( ppdIntegratedSlice->getMean() ); simSlice->setWidth( ppdIntegratedSlice->getWidth() ); simSlice->setBkgLevel( ppdIntegratedSlice->getBkg() ); ppdSlices[iSlice] = simSlice; // Create the histogram and function simSlice->defineHistogram(); simSlice->defineDistFunc(); } return; } // Simulate values in each time slice inline void ProfilerPlaneSimulatorV::simulateValues() { // Get the integrate slice and the reference to its vector of values. ProfilerPlaneSliceSimulator* intedSlice = dynamic_cast( ppdIntegratedSlice ); vector& intedVecRef = const_cast&>( intedSlice->getValues() ); intedVecRef.assign( intedVecRef.size(), 0.0 ); for ( unsigned iSlice = 0; iSlice < ppdSlices.size(); iSlice++ ) { // Redefine some of the parameters for individual slices. ProfilerPlaneSliceSimulator* simSlice = dynamic_cast( ppdSlices[iSlice] ); // Set Amplitude // double deltaAmp = 0.2 * sin( iSlice * 4 * acos( 0 ) * 60 / ppdSlices.size() ); double deltaAmp = 0; double amplInst = 500 * ( 1.0 + deltaAmp ); simSlice->setAmpl( amplInst ); simSlice->getFunc()->SetParameter( "Amplitude", simSlice->getAmplitude() ); // Set the mean value // double deltaX = 0.2 * sin( iSlice * 4 * acos( 0 ) * 210 / ppdSlices.size() ) //// + 0.4 * sin( iSlice * 4 * acos( 0 ) * 140 / ppdSlices.size() ) // + 1.0 * sin( iSlice * 4 * acos( 0 ) * 60 / ppdSlices.size() ) // + 2.0 * sin( iSlice * 4 * acos( 0 ) * 7 / ppdSlices.size() ); double deltaX = 0.2 * sin( iSlice * 4 * acos( 0 ) * 60 / ppdSlices.size() ); // double deltaX = 0; double meanInst = 3.0 + deltaX; simSlice->setMean( meanInst ); simSlice->getFunc()->SetParameter( "Mean", simSlice->getMean() ); // Set width // double deltaW = 1.0 * sin( iSlice * 4 * acos( 0 ) * 60 / ppdSlices.size() ); double deltaW = 0; double widthInst = 7.0 + deltaW; simSlice->setWidth( widthInst ); simSlice->getFunc()->SetParameter( "Width", simSlice->getWidth() ); // Set background level // double deltaB = 0.2 * sin( iSlice * 4 * acos( 0 ) * 60 / ppdSlices.size() ); double deltaB = 0; double bkgInst = 25.0 * ( 1.0 + deltaB ); simSlice->setBkgLevel( bkgInst ); simSlice->getFunc()->SetParameter( "Background", simSlice->getBkg() ); // Set background slope simSlice->setBkgSlope( 0.005 ); simSlice->getFunc()->SetParameter( "BkgSlope", simSlice->getBkgSlope() ); simSlice->simulateValues( ppdEffcCorr ); // get the reference to the vector of values for this slice vector& vecRef = const_cast&>( simSlice->getValues() ); // and add them to the values of the integrated slice std::transform( vecRef.begin(), vecRef.end(), intedVecRef.begin(), intedVecRef.begin(), std::plus() ); } // intedSlice->simulateValues( ppdEffcCorr ); return; } // Method to launch the main thread that will simulate the EPICS waveform records // from a beam profiler plane so that ProfilerPlane objects can read and analyze. void ProfilerPlaneSimulatorV::startMainThread() { MtxLock objMutex( mcMutex ); // Launch the thread pthread_t thID; int thStat = pthread_create( &thID, NULL, (void* (*)( void* ))ProfilerPlaneSimulatorV::threadFunc, (void*) this ); // If fails to create the threat throw and exception if ( thStat != 0 ) { std::stringstream errStream; errStream << "ProfilerPlaneSimulatorV::startMainThread: Failed to create thread " << hex << showbase << thID << dec << " for profiler plane " << getName(); throw std::runtime_error( errStream.str() ); } return; } // Function that executes in a separate thread and checks if the PVs have changed // and sets the signal for SNL code to process PVs. void* ProfilerPlaneSimulatorV::threadFunc( void* argPtr ) { ProfilerPlaneSimulatorV* simPtr = reinterpret_cast( argPtr ); // infinite loop while ( true ) { // Generate the random values for this plane simPtr->simulateValues(); // Publish values for this plane simPtr->publishValues(); // sleep a short time (in us) before the next update usleep( simPtr->getSleepTime() ); } return 0; }