예제 #1
0
PropagationCK::PropagationCK(ref_ptr<MagneticField> field, double tolerance,
		double minStep, double maxStep) :
		minStep(0) {
	setField(field);
	setTolerance(tolerance);
	setMaximumStep(maxStep);
	setMinimumStep(minStep);

	// load Cash-Karp coefficients
	a.assign(cash_karp_a, cash_karp_a + 36);
	b.assign(cash_karp_b, cash_karp_b + 6);
	bs.assign(cash_karp_bs, cash_karp_bs + 6);
}
BioXASSideM1MirrorBendControl::BioXASSideM1MirrorBendControl(const QString &name, const QString &units, QObject *parent, const QString &description) :
	BioXASMirrorBendControl(name, units, parent, description)
{
	// Initialize inherited variables.

	setMinimumValue( calculateBendRadius(12, 12) );
	setMaximumValue( calculateBendRadius(0.0001, 0.0001) );
	setTolerance(50);

	// Current settings.

	updateStates();
}
예제 #3
0
AMPVControl::AMPVControl(const QString& name, const QString& readPVname, const QString& writePVname, const QString& stopPVname, QObject* parent, double tolerance, double completionTimeoutSeconds, int stopValue, const QString &description)
	: AMReadOnlyPVControl(name, readPVname, parent, description)
{
	setTolerance(tolerance);
	allowsMovesWhileMoving_ = true;

	//not moving yet:
	moveInProgress_ = false;

	// not connected:
	wasConnected_ = false;

	// setpoint is initialized:
	setpoint_ = 0;

	// this is what to use for our timeout:
	completionTimeout_ = completionTimeoutSeconds;

	// connect the timer to the timeout handler:
	connect(&completionTimer_, SIGNAL(timeout()), this, SLOT(onCompletionTimeout()));

	// process variable:
	writePV_ = new AMProcessVariable(writePVname, true, this);
	// instead of connected(), use writeRead: connect(writePV_, SIGNAL(connected(bool)), this, SLOT(onPVConnected(bool)))
	connect(writePV_, SIGNAL(writeReadyChanged(bool)), this, SLOT(onPVConnected(bool)));
	connect(writePV_, SIGNAL(error(int)), this, SLOT(onWritePVError(int)));
	connect(writePV_, SIGNAL(connectionTimeout()), this, SIGNAL(writeConnectionTimeoutOccurred()));
	connect(writePV_, SIGNAL(connectionTimeout()), this, SLOT(onConnectionTimeout()));
	connect(writePV_, SIGNAL(valueChanged(double)), this, SLOT(onSetpointChanged(double)));
	connect(writePV_, SIGNAL(initialized()), this, SLOT(onWritePVInitialized()));

	// We now need to monitor the feedback position ourselves, to see if we get where we want to go:
	connect(readPV_, SIGNAL(valueChanged(double)), this, SLOT(onNewFeedbackValue(double)));

	// Do we have a stopPV?
	noStopPV_ = stopPVname.isEmpty();
	if(noStopPV_) {
		stopPV_ = 0;
	}
	else {
		stopPV_ = new AMProcessVariable(stopPVname, false, this);
		connect(stopPV_, SIGNAL(error(int)), this, SLOT(onReadPVError(int)));	/// \todo Does this need separate error handling? What if the stop write fails? That's really important.
	}
	stopValue_ = stopValue;


	// If any PVs are already connected [possible if they're sharing an existing connection]:
	wasConnected_ = (readPV_->readReady() && writePV_->writeReady());	// equivalent to isConnected(), but we cannot call virtual functions inside a constructor, that will break subclasses.
	if(writePV_->isInitialized())
		onWritePVInitialized();
}
예제 #4
0
AMPVwStatusControl::AMPVwStatusControl(const QString& name, const QString& readPVname, const QString& writePVname, const QString& movingPVname, const QString& stopPVname, QObject* parent, double tolerance, double moveStartTimeoutSeconds, AMAbstractControlStatusChecker* statusChecker, int stopValue, const QString &description)
	: AMReadOnlyPVwStatusControl(name, readPVname, movingPVname, parent, statusChecker, description) {

	// Initialize:
	moveInProgress_ = false;
	stopInProgress_ = false;
	startInProgress_ = false;
	settlingInProgress_ = false;
	settlingTime_ = 0.0;	/// \todo Once tested, this should maybe be enabled by default. All systems with separate status and feedback PVs will need it. How much time?
	setTolerance(tolerance);
	setpoint_ = 0;
	moveStartTimeout_ = moveStartTimeoutSeconds;
	hardwareWasMoving_ = false;

	// create new setpoint PV. Monitor it, in case someone else changes it
	writePV_ = new AMProcessVariable(writePVname, true, this);

	// connect:
	// use writeReadyChanged() instead of connected() here: connect(writePV_, SIGNAL(connected(bool)), this, SLOT(onPVConnected(bool)))
	connect(writePV_, SIGNAL(writeReadyChanged(bool)), this, SLOT(onPVConnected(bool)));
	connect(writePV_, SIGNAL(error(int)), this, SLOT(onWritePVError(int)));
	connect(writePV_, SIGNAL(connectionTimeout()), this, SIGNAL(writeConnectionTimeoutOccurred()));
	connect(writePV_, SIGNAL(connectionTimeout()), this, SLOT(onConnectionTimeout()));
	connect(writePV_, SIGNAL(valueChanged(double)), this, SLOT(onSetpointChanged(double)));
	connect(writePV_, SIGNAL(initialized()), this, SLOT(onWritePVInitialized()));

	// connect the timer to the timeout handler:
	connect(&moveStartTimer_, SIGNAL(timeout()), this, SLOT(onMoveStartTimeout()));
	connect(&settlingTimer_, SIGNAL(timeout()), this, SLOT(onSettlingTimeFinished()));

	// Do we have a stopPV?
	noStopPV_ = stopPVname.isEmpty();
	if(noStopPV_) {
		stopPV_ = 0;
	}
	else {
		stopPV_ = new AMProcessVariable(stopPVname, false, this);
		connect(stopPV_, SIGNAL(error(int)), this, SLOT(onReadPVError(int)));	/// \todo Does this need separate error handling? What if the stop write fails? That's really important.
	}
	stopValue_ = stopValue;


	// If any PVs were already connected on creation [possible if sharing an existing connection]:
	wasConnected_ = (readPV_->readReady() && writePV_->writeReady() && movingPV_->readReady());	// equivalent to isConnected(), but we cannot call virtual functions from the constructor, potentially breaks subclasses.
	if(writePV_->isInitialized())
		setMoveEnumStates(writePV_->enumStrings());
	if(movingPV_->readReady())
		hardwareWasMoving_ = (*statusChecker_)((int)movingPV_->lastValue());

}
예제 #5
0
파일: event_time.cpp 프로젝트: psfu/ULib
UEventTime::UEventTime(long sec, long micro_sec) : UTimeVal(sec, micro_sec)
{
   U_TRACE_REGISTER_OBJECT(0, UEventTime, "%ld,%ld", sec, micro_sec)

   setTolerance();

   xtime.tv_sec =
   xtime.tv_usec = 0L;

#ifdef USE_LIBEVENT
   if (u_ev_base == 0) u_ev_base = (struct event_base*) U_SYSCALL_NO_PARAM(event_base_new);

   U_INTERNAL_ASSERT_POINTER(u_ev_base)

   U_NEW(UTimerEv<UEventTime>, pevent, UTimerEv<UEventTime>(*this));

   (void) UDispatcher::add(*pevent, *(UTimeVal*)this);
#endif
}
BioXASCarbonFilterFarmActuatorPositionControl::BioXASCarbonFilterFarmActuatorPositionControl(const QString &name, const QString &units, QObject *parent) :
	AMPseudoMotorControl(name, units, parent)
{
	// Initialize local variables.

	position_ = 0;
	status_ = 0;

	// Initialize inherited variables.

	value_ = 0;
	setpoint_ = 0;
	minimumValue_ = -1000;
	maximumValue_ = 1000;

	setTolerance(0.05);
	setContextKnownDescription("Actuator Control");
	setAllowsMovesWhileMoving(false);
}
예제 #7
0
BioXASZebraTimeSeconds::BioXASZebraTimeSeconds(const QString &name, QObject *parent) :
	AMPseudoMotorControl(name, "s", parent)
{
	// Initialize inherited variables.

	setTolerance(0.001);
	setContextKnownDescription("ZebraTime");

	// Initialize class variables.

	timeValue_ = 0;
	timeUnits_ = 0;

	// Current settings.

	setMinimumValue(BIOXASZEBRATIMESECONDS_VALUE_MIN);
	setMaximumValue(BIOXASZEBRATIMESECONDS_VALUE_MAX);

	updateStates();
}
예제 #8
0
TEST(MathLibCVodeTest, ExponentialWithJacobianNewton)
{
	// initial values
	const double y0 = 1.0;
	const double t0 = 0.0;

	boost::property_tree::ptree tree;
	tree.put("linear_multistep_method", "BDF");
	tree.put("nonlinear_solver_iteration", "Newton");
	auto ode_solver = make_ode_solver<1>(tree);

	ASSERT_EQ(any_ode_solver_libs_available(), !!ode_solver);
	// Don't run the test if the ODE solver could not be constructed.
	if (!ode_solver) return;

	ode_solver->setFunction(f, df);
	ode_solver->setTolerance(abs_tol, rel_tol);

	ode_solver->setIC(t0, {y0});

	ode_solver->preSolve();

	const double dt = 1e-1;

	for (unsigned i = 1; i <= 10; ++i)
	{
		const double time = dt * i;

		ASSERT_TRUE(ode_solver->solve(time));

		auto const y = ode_solver->getSolution();
		auto const time_reached = ode_solver->getTime();
		auto const y_dot = ode_solver->getYDot(time_reached, y);

		auto const y_ana = exp(-15.0 * time);
		auto const y_dot_ana = -15.0 * exp(-15.0 * time);

		check(time_reached, y[0], y_dot[0], time, y_ana, y_dot_ana);
	}
}
CornerDetector::CornerDetector(double tolerance)
{
    setTolerance(tolerance);
}
예제 #10
0
/*!
   Constructor

   \param tolerance Tolerance
   \sa setTolerance(), tolerance()
*/
QwtWeedingCurveFitter::QwtWeedingCurveFitter( double tolerance )
{
    d_data = new PrivateData;
    setTolerance( tolerance );
}
예제 #11
0
void SimulationMainWindow1D::createActions(){
  
   exitAct = new QAction(tr("E&xit"), this);
   exitAct->setShortcuts(QKeySequence::Quit);
   exitAct->setStatusTip(tr("Exit the application"));
   connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
  
   aboutAct = new QAction(tr("&About"), this);
   aboutAct->setStatusTip(tr("Show the application's About box"));
   connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
  
   aboutQtAct = new QAction(tr("About &Qt"), this);
   aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
   connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
   connect(aboutQtAct, SIGNAL(triggered()), this, SLOT(aboutQt()));

   // Simulation menu actions 
   runAct = new QAction(tr("&Run"), this);
   runAct->setShortcut(tr("Ctrl+Alt+R"));
   runAct->setStatusTip(tr("Running the simulation"));
   connect(runAct, SIGNAL(triggered()), this, SLOT(runSimulation()));
  
   pauseAct = new QAction(tr("&Pause"), this);
   pauseAct->setShortcut(tr("Ctrl+Alt+P"));
   pauseAct->setStatusTip(tr("Pause the simulation"));
   connect(pauseAct, SIGNAL(triggered()), this, SLOT(pauseSimulation()));
  
   restartAct = new QAction(tr("&Restart"), this);
   restartAct->setShortcut(tr("Ctrl+Alt+N"));
   restartAct->setStatusTip(tr("Restart the simulation"));
   connect(restartAct, SIGNAL(triggered()), this, SLOT(restartSimulation()));
  
   // Input manu actions
   gridSizeAct = new QAction(tr("&Grid Size"), this);
   connect(gridSizeAct, SIGNAL(triggered()), this, SLOT(setGridSize()));
  
   toleranceAct = new QAction(tr("&Error Tolerance"), this);
   connect(toleranceAct, SIGNAL(triggered()), this, SLOT(setTolerance()));

   delaySecAct = new QAction(tr("&Animation Delay"), this);
   connect(delaySecAct, SIGNAL(triggered()), this, SLOT(setDelaySec()));
  
   realizationTimeStepAct = new QAction(tr("&Realization Time Step"), this);
   connect(realizationTimeStepAct, SIGNAL(triggered()),
           this, SLOT(setRealizationTimeStep()));
  
   // Setting the initial condition
   setICSinAct = new QAction(tr("&Sin"), this);
   setICSinAct->setCheckable(true);
   connect(setICSinAct, SIGNAL(triggered()), this, SLOT(setICSin()));

   setICStepAct = new QAction(tr("&Step"), this);
   setICStepAct->setCheckable(true);
   connect(setICStepAct, SIGNAL(triggered()), this, SLOT(setICStep()));

   setICRndNoiseAct = new QAction(tr("&Random Noise"), this);
   setICRndNoiseAct->setCheckable(true);
   connect(setICRndNoiseAct, SIGNAL(triggered()), this, SLOT(setICRndNoise()));

   icGroup = new QActionGroup(this);
   icGroup->addAction(setICSinAct);
   icGroup->addAction(setICStepAct);
   icGroup->addAction(setICRndNoiseAct);
   setICSinAct->setChecked(true);
  
   // Setting main solver
   setLaxFriedrichsAct = new QAction(tr("Lax-FriedRichs Scheme"), this);
   setLaxFriedrichsAct->setCheckable(true);
   connect(setLaxFriedrichsAct, SIGNAL(triggered()), this,
            SLOT(setLaxFriedrichsScheme()));

   setRK4Act = new QAction(tr("RK4 Scheme"), this);
   setRK4Act->setCheckable(true);
   connect(setRK4Act, SIGNAL(triggered()), this,SLOT(setRK4Scheme()));

   setMacCormackAct = new QAction(tr("MacCormack Scheme"), this);
   setMacCormackAct->setCheckable(true);
   connect(setMacCormackAct, SIGNAL(triggered()), this,
            SLOT(setMacCormackScheme()));

   setForwardEulerAct = new QAction(tr("Forward Euler Scheme"), this);
   setForwardEulerAct->setCheckable(true);
   connect(setForwardEulerAct, SIGNAL(triggered()), this,
            SLOT(setForwardEulerScheme()));
  
   setKurganovTadmor2000Act = new QAction(tr("Kurganov-Tadmor Scheme"), this);
   setKurganovTadmor2000Act->setCheckable(true);
   connect(setKurganovTadmor2000Act, SIGNAL(triggered()), this,
            SLOT(setKurganovTadmor2000Scheme()));

   setRK4KurganovTadmor2000Act = 
           new QAction(tr("RK4 Kurganov-Tadmor Scheme"), this);
   setRK4KurganovTadmor2000Act->setCheckable(true);
   connect(setRK4KurganovTadmor2000Act, SIGNAL(triggered()), this,
            SLOT(setRK4KurganovTadmor2000Scheme()));

   setKurganovTadmor2ndOrder2000Act = 
           new QAction(tr("2nd Order Kurganov-Tadmor Scheme"), this);
   setKurganovTadmor2ndOrder2000Act->setCheckable(true);
   connect(setKurganovTadmor2ndOrder2000Act, SIGNAL(triggered()), this,
            SLOT(setKurganovTadmor2ndOrder2000Scheme()));
 
   solverGroup = new QActionGroup(this);
   solverGroup->addAction(setMacCormackAct);
   solverGroup->addAction(setForwardEulerAct);
   solverGroup->addAction(setLaxFriedrichsAct);
   solverGroup->addAction(setKurganovTadmor2000Act);
   solverGroup->addAction(setRK4KurganovTadmor2000Act);
   solverGroup->addAction(setKurganovTadmor2ndOrder2000Act);
   solverGroup->addAction(setRK4Act);
   setRK4Act->setChecked(true);
 
   // Setting flux solver
   setMUSCLSAct = new QAction(tr("MUSCL Scheme"), this);
   setMUSCLSAct->setCheckable(true);
   connect(setMUSCLSAct, SIGNAL(triggered()), this, SLOT(setMUSCLSScheme()));

   setLinearReconstructionAct = 
             new QAction(tr("Linear Reconstruction Scheme"), this);
   setLinearReconstructionAct->setCheckable(true);
   connect(setLinearReconstructionAct, SIGNAL(triggered()), this,
             SLOT(setLinearReconstructionScheme()));

   setPiecewiseParabolicReconstructionAct = 
             new QAction(tr("Piecewise Parabolic Reconstruction Scheme"), this);
   setPiecewiseParabolicReconstructionAct->setCheckable(true);
   connect(setPiecewiseParabolicReconstructionAct, SIGNAL(triggered()), this,
             SLOT(setPiecewiseParabolicReconstructionScheme()));

   fluxGroup = new QActionGroup(this);
   fluxGroup->addAction(setMUSCLSAct);
   fluxGroup->addAction(setPiecewiseParabolicReconstructionAct);
   fluxGroup->addAction(setLinearReconstructionAct);
   setLinearReconstructionAct->setChecked(true);
 
}
예제 #12
0
TEST(MathLibCVodeTest, ExponentialExtraData)
{
	// initial values
	const double y0 = 1.0;
	const double t0 = 0.0;

	auto tree = boost::property_tree::ptree{};
	auto ode_solver = make_ode_solver<1>(tree);

	ASSERT_EQ(any_ode_solver_libs_available(), !!ode_solver);
	// Don't run the test if the ODE solver could not be constructed.
	if (!ode_solver) return;

	ExtraData data;
	auto f_lambda = [&](double t,
	                    MathLib::ODE::MappedConstVector<1> const& y,
	                    MathLib::ODE::MappedVector<1>& ydot)
	{
		return f_extra(t, y, ydot, data);
	};

	ode_solver->setFunction(f_lambda, nullptr);

	ode_solver->setTolerance(abs_tol, rel_tol);
	ode_solver->setIC(t0, {y0});
	ode_solver->preSolve();

	const double dt = 1e-1;

	for (unsigned i = 1; i <= 10; ++i)
	{
		const double time = dt * i;

		ASSERT_TRUE(ode_solver->solve(time));

		auto const y = ode_solver->getSolution();
		auto const time_reached = ode_solver->getTime();
		auto const y_dot = ode_solver->getYDot(time_reached, y);

		auto const y_ana = exp(-data.value * time);
		auto const y_dot_ana = -data.value * exp(-data.value * time);

		check(time_reached, y[0], y_dot[0], time, y_ana, y_dot_ana);
	}

	ode_solver->setFunction(f_lambda, nullptr);
	ode_solver->preSolve();
	for (unsigned i = 11; i <= 15; ++i)
	{
		const double time = dt * i;

		ASSERT_TRUE(ode_solver->solve(time));

		auto const y = ode_solver->getSolution();
		auto const time_reached = ode_solver->getTime();
		auto const y_dot = ode_solver->getYDot(time_reached, y);

		auto const y_ana = exp(-data.value * time);
		auto const y_dot_ana = -data.value * exp(-data.value * time);

		check(time_reached, y[0], y_dot[0], time, y_ana, y_dot_ana);
	}
}
예제 #13
0
SGMGratingAngleControl::SGMGratingAngleControl(QObject *parent) :
    AMPseudoMotorControl("Grating Angle Encoder", "Count", parent, "SGM Monochromator Grating Angle")
{
	encoderControl_ = new AMPVwStatusControl("Grating Angle Encoder",
	                                         "SMTR16114I1002:enc:fbk",
	                                         "SMTR16114I1002:encTarget",
	                                         "SMTR16114I1002:status",
	                                         "SMTR16114I1002:stop",
	                                         this,
	                                         5,
	                                         2.0,
	                                         new CLSMAXvControlStatusChecker(),
	                                         1);

	stepMotorControl_ = new AMPVwStatusControl("Grating Angle Step",
	                                           "SMTR16114I1002:step:sp",
	                                           "SMTR16114I1002:step",
	                                           "SMTR16114I1002:status",
	                                           "SMTR16114I1002:stop",
	                                           this,
	                                           5,
	                                           2.0,
	                                           new CLSMAXvControlStatusChecker());

	stepVelocityControl_ = new AMPVControl("Grating Angle Step Velocity",
	                                       "SMTR16114I1002:velo:sp",
	                                       "SMTR16114I1002:velo",
	                                       QString(),
	                                       this,
	                                       1);

	stepAccelerationControl_ = new AMPVControl("Grating Angle Step Acceleration",
	                                           "SMTR16114I1002:accel:sp",
	                                           "SMTR16114I1002:accel",
	                                           QString(),
	                                           this,
	                                           0.1);

	stepsPerEncoderCountControl_ = new AMSinglePVControl("Grating Angle Steps Per Encoder Pulse",
	                                                     "SMTR16114I1002:softRatio",
	                                                     this,
	                                                     0.1);

	movementTypeControl_ = new AMSinglePVControl("Grating Angle Move Type",
	                                             "SMTR16114I1002:encMoveType",
	                                             this,
	                                             0.5);

	AMControlSet* allControls = new AMControlSet(this);
	allControls->addControl(encoderControl_);
	allControls->addControl(stepMotorControl_);
	allControls->addControl(stepVelocityControl_);
	allControls->addControl(stepAccelerationControl_);
	allControls->addControl(stepsPerEncoderCountControl_);
	allControls->addControl(movementTypeControl_);
	connect(allControls, SIGNAL(connected(bool)), this, SLOT(onControlSetConnectionChanged(bool)));

	addChildControl(encoderControl_);
	addChildControl(stepMotorControl_);
	setMinimumValue(encoderControl_->minimumValue());
	setMaximumValue(encoderControl_->maximumValue());
	setTolerance(encoderControl_->tolerance());
	setAttemptMoveWhenWithinTolerance(true);

	updateStates();
}
예제 #14
0
REIXSSpectrometer::REIXSSpectrometer(QObject *parent)
	: AMCompositeControl("spectrometer", "eV", parent) {

	setDescription("XES Detector Energy");

	spectrometerRotationDrive_ = new AMPVwStatusControl("spectrometerRotationDrive",
								"SMTR1610-4-I21-01:mm:fbk",
								"SMTR1610-4-I21-01:mm",
								"SMTR1610-4-I21-01:status",
								"SMTR1610-4-I21-01:stop", this, 1.0);
	spectrometerRotationDrive_->setDescription("XES Spectrometer Lift");
	spectrometerRotationDrive_->setSettlingTime(1.0);


	detectorTranslation_ = new AMPVwStatusControl("detectorTranslation",
							  "SMTR1610-4-I21-04:mm:fbk",
							  "SMTR1610-4-I21-04:mm",
							  "SMTR1610-4-I21-04:status",
							  "SMTR1610-4-I21-04:stop", this, 2.0);

	detectorTranslation_->setDescription("XES Detector Translation");
	detectorTranslation_->setSettlingTime(1.0);

	detectorTiltDrive_ = new AMPVwStatusControl("detectorTiltDrive",
							"SMTR1610-4-I21-02:mm:sp",
							"SMTR1610-4-I21-02:mm",
							"SMTR1610-4-I21-02:status",
							"SMTR1610-4-I21-02:stop", this, 0.05);
	detectorTiltDrive_->setDescription("XES Detector Tilt Stage");
	detectorTiltDrive_->setSettlingTime(0.5);

	endstationTranslation_ = new AMPVwStatusControl("endstationTranslation",
							"SMTR1610-4-I21-05:mm:fbk",
							"SMTR1610-4-I21-05:mm",
							"SMTR1610-4-I21-05:status",
							"SMTR1610-4-I21-05:stop", this, 0.05);  //DAVID ADDED
	endstationTranslation_->setDescription("Endstation Translation");
	endstationTranslation_->setSettlingTime(0.2);

	gratingMask_ = new AMPVwStatusControl("gratingMask",
						  "SMTR1610-4-I21-03:mm:sp",
						  "SMTR1610-4-I21-03:mm",
						  "SMTR1610-4-I21-03:status",
						  "SMTR1610-4-I21-03:stop",this,0.01); //DAVID ADDED 005
	gratingMask_->setDescription("Grating Mask Position");
	gratingMask_->setSettlingTime(0.2);


	hexapod_ = new REIXSHexapod(this);

	tmMCPPreamp_ = new AMReadOnlyPVControl("MCPPreampTemp", "TM1610-4-I21-03", this, "MCP Preamp Temperature");
	tmSOE_ = new AMReadOnlyPVControl("SOETemp", "TM1609-01", this, "SOE Temperature");


	if(addChildControl(spectrometerRotationDrive_))
		connect(spectrometerRotationDrive_, SIGNAL(valueChanged(double)), this, SLOT(scheduleReviewValueChanged()));
	if(addChildControl(detectorTranslation_))
		connect(detectorTranslation_, SIGNAL(valueChanged(double)), this, SLOT(scheduleReviewValueChanged()));
	if(addChildControl(endstationTranslation_))  //DAVID ADDED
		connect(endstationTranslation_, SIGNAL(valueChanged(double)), this, SLOT(scheduleReviewValueChanged()));  //DAVID ADDED

	addChildControl(detectorTiltDrive_);
	addChildControl(hexapod_);
	addChildControl(gratingMask_);  //DAVID ADDED 005
	addChildControl(tmMCPPreamp_);
	addChildControl(tmSOE_);

	currentGrating_ = -1; specifiedGrating_ = 0;
	currentFocusOffset_ = 0; specifiedFocusOffset_ = 0;
	currentDetectorTiltOffset_ = 0; specifiedDetectorTiltOffset_ = 0;

	specifiedEV_ = 395;

	moveAction_ = 0;
	setTolerance(0.1);

	// valueChanged(): if the optical origin is at the rotation point and everything is perfect, then only the spectrometerRotationDrive_ motor will affect the energy value.  But in the non-perfect-aligned general math situation, the translation can also affect eV.  And of course gratings...
	// Here we make the connections to get our valueChanged() signal:
	connect(this, SIGNAL(gratingChanged(int)), this, SLOT(scheduleReviewValueChanged()));
	connect(&reviewValueChangedFunction_, SIGNAL(executed()), this, SLOT(reviewValueChanged()));
	connect(this, SIGNAL(connected(bool)), this, SLOT(onConnected(bool)));

}