CountWithSpectro.cpp 10.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * Nomad Instrument Control Software
 *
 * Copyright 2011 Institut Laue-Langevin
 *
 * Licensed under the EUPL, Version 1.1 only (the "License");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 */
#include "CountWithSpectro.h"
#include "controllers/common/family/Families.h"
20
#include "controllers/common/datafile/NexusDataFile.h"
21
22
#include <boost/date_time/posix_time/posix_time.hpp>
#include <common/base/Date.h>
23
24
25
26
27
28
29

namespace d22special {

const std::string CountWithSpectro::TYPE = "count_with_spectro";
const int32 CountWithSpectro::XSIZE = 1044; //should be retrieved directly from the driver...
const int32 CountWithSpectro::YSIZE = 1044;

30
31
const int32 CountWithSpectro::USB_DELAY_MILLISEC = 50; //Empirical value obtained from tests

32
33
34
35
36
37
38
39
40
CountWithSpectro::CountWithSpectro(const std::string & name) :
		ExperimentController(name), controller::Stoppable(this) {

	setFamily(family::SAMPLE_ENVIRONMENT);

	registerFunction(TYPE);

	spectro.init(this, "spectro");
	count.init(this, "count");
41
	spectroSwitcher.init(this, "spectro_switcher");
42

43
	integrationTime.init(this, SAVE, "integration_time"); //in microseconds!
44
	numSpectroMeasures.init(this, SAVE, "num_spectro");
45
	numTotalMeasures.init(this, SAVE, "num_total_measures");
46
47
	timeType.init(this, SAVE, "time_type");
	countTime.init(this, SAVE, "count_time");
48
	scansToAverage.init(this, SAVE, "scans_average");
49
50
51
52
53

	xSize.init(this, SAVE, "x_size");
	ySize.init(this, SAVE, "y_size");
	zSize.init(this, SAVE, "z_size");

54
55
56
57
	subtitle.init(this, SAVE, "subtitle");
	useSwitcher.init(this, SAVE, "use_switcher");

	yDataArray.init(this, NOSAVE, "yData_array");
58
59
	initialTime.init(this, NOSAVE, "initial_time");
	measureDuration.init(this, NOSAVE, "measure_duration");
60
61

	yDataArraySecondChannel.init(this, NOSAVE, "yDataArray_secondChannel");
62
63
64
65

	//initialize pointers
	m_yDataArray = NULL;
	m_yDataArraySecondChannel = NULL;
66
67
68
69
70
71
72
}

CountWithSpectro::~CountWithSpectro() {

}

void CountWithSpectro::postConfiguration() {
73
	xSize = spectro->size();
74
75
	ySize = numSpectroMeasures();
	zSize = 1;
76
	subtitle = count->subtitle();
77
78

	registerRefresher(numSpectroMeasures, &CountWithSpectro::refreshNumSpectroMeasures, this);
79
	registerRefresher(useSwitcher, &CountWithSpectro::refreshUseSwitcher, this);
80
	registerUpdater(count->subtitle, &CountWithSpectro::updateSubtitle, this);
81
82
83
84
85
86
	registerProgression(count, &CountWithSpectro::updateProgression, this);
}

void CountWithSpectro::refreshNumSpectroMeasures(int32 number) {
	ySize = number; //This property is only used to save the data in nexus file

87
	//initialize here the dynamic properties
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
	if (useSwitcher()) {
		measureDuration.resize(number * 2);
		numTotalMeasures = number * 2;
	} else {
		measureDuration.resize(number);
		numTotalMeasures = number;
	}
}

void CountWithSpectro::refreshUseSwitcher(bool value) {
	if (value) {
		numTotalMeasures = numSpectroMeasures() * 2; //using switcher
	} else {
		numTotalMeasures = numSpectroMeasures();
	}
	measureDuration.resize(numTotalMeasures());
104
105
106
107
108
109
}

void CountWithSpectro::updateProgression() {
	commandProgression = count->commandProgression();
}

110
111
112
113
void CountWithSpectro::updateSubtitle() {
	subtitle = count->subtitle();
}

114
115
void CountWithSpectro::start() {

116
117
118
	//to avoid problems of synchronization, get the xSize any time we do a measure
	xSize = spectro->size();
	spectro->scansToAverage = scansToAverage();
119

120
121
	if (spectro->isConnected()) {
		if (!useSwitcher()) {
122

123
124
			//Time already in microseconds!
			spectro->integrationTime = integrationTime();
125

126
127
128
			//check the total time of spectro measurement is smaller than the count time (comparison in seconds!)
			float64 spectroTime = integrationTime() * 0.000001 * numSpectroMeasures() * scansToAverage();
			float64 countTime = getCountTimeInSec();
129

130
			if (spectroTime <= countTime) {
131

132
				setupCountParams();
133

134
				initArrays(); //before initArray()
135

136
137
				commandStatus.setRunning();
				spectro->mode = QE65000Controller::COUNT_SINGLE;
138

139
140
141
				//Launch count and spectro at the same time
				// Run the threads in parallel in a group
				boost::thread_group group;
142

143
144
				group.create_thread(boost::bind(&CountWithSpectro::startCount, this));
				group.create_thread(boost::bind(&CountWithSpectro::startSpectro, this));
145

146
147
				// Wait for the termination of the threads
				group.join_all();
148

149
150
				//Get data
				saveSpectroData();
151

152
153
154
				commandStatus.setIdle();
				spectro->mode = QE65000Controller::IDLE;
			}
155

156
157
158
159
160
		} else {

			//Suppose here we also keep the same rule as before (but now is double)
			spectroSwitcher->numberOfCycles = 1; //even if it is not clear, the number of cycles will be established by this controller
			spectroSwitcher->integrationTime = integrationTime();
161

162
163
164
			//check the total time of spectro measurement is smaller than the count time
			float64 spectroTime = integrationTime() * 0.000001 * numSpectroMeasures() * scansToAverage() * 2; //left and right measure
			float64 countTime = getCountTimeInSec();
165

166
			if (spectroTime <= countTime) {
167

168
				setupCountParams();
169

170
				initArrays();
171

172
173
				commandStatus.setRunning();
				spectro->mode = QE65000Controller::COUNT_SWITCHER;
174

175
176
177
				//Launch count and spectro at the same time
				// Run the threads in parallel in a group
				boost::thread_group group;
178

179
180
				group.create_thread(boost::bind(&CountWithSpectro::startCount, this));
				group.create_thread(boost::bind(&CountWithSpectro::startSwitcher, this));
181

182
183
				// Wait for the termination of the threads
				group.join_all();
184

185
186
187
188
189
190
				//Get data
				saveSwitcherSpectroData();

				commandStatus.setIdle();
				spectro->mode = QE65000Controller::IDLE;
			}
191
		}
192
193
194

		//clean arrays
		initArrays();
195
	}
196
197
198
199
}

void CountWithSpectro::stop() {
	if (commandStatus.isRunning()) {
200
201
		count->stopParallel();
		spectro->stopParallel();
202
		spectroSwitcher->stopParallel();
203
204
205
206
207
208
209
210
211
212
213
	}
	commandStatus.setWarning();

}

void CountWithSpectro::startCount() {
	count->startCommand();
}

void CountWithSpectro::startSpectro() {

214
215
216
217
	common::Date startTime = common::Date();
	initialTime = startTime.toString("%H:%M:%S");
	common::Date formerTime = startTime;

218
219
	int32 sleepTime = calculateWaitingTimeInSec();

220
	for (int i = 0; i < numSpectroMeasures(); i++) {
221
		if (commandStatus.isRunning()) {
222

223
224
225
226
			common::Date time = common::Date();
			common::Duration duration = time - formerTime;
			measureDuration.set(i, duration.getMilliseconds());

227
			spectro->startCommand();
228

229
			int32 ySize = spectro->size();
230
231
			float64* tempYData = spectro->yData();
			for (int32 j = 0; j < ySize; j++) {
232
233
234
235
				m_yDataArray[ySize * i + j] = tempYData[j];
			}

			formerTime = time;
Cristina Cocho's avatar
Cristina Cocho committed
236
			sleep(sleepTime);
237
238
239
240
241
		}
	}
}

void CountWithSpectro::startSwitcher() {
242

243
244
	common::Date startTime = common::Date();
	initialTime = startTime.toString("%H:%M:%S");
245
246
247
248

	int32 sleepTime = calculateWaitingTimeInSec();

	common::Date initialTime = common::Date();
249
250
251
252

	for (int i = 0; i < numSpectroMeasures(); i++) {
		if (commandStatus.isRunning()) {

253
			spectroSwitcher->setInitialTime(initialTime);
254
255
256

			spectroSwitcher->startCommand();

257
			int32 ySize = spectro->size();
258
259
260
261
262
263
264
265
			float64* tempLeftYData = spectroSwitcher->yLeftData();
			for (int32 j = 0; j < ySize; j++) {
				m_yDataArray[ySize * i + j] = tempLeftYData[j];
			}

			float64* tempRightYData = spectroSwitcher->yRightData();
			for (int32 j = 0; j < ySize; j++) {
				m_yDataArraySecondChannel[ySize * i + j] = tempRightYData[j];
266
			}
267

268
269
270
271
272
			measureDuration.set((i * 2), spectroSwitcher->durationLeft());
			measureDuration.set((i * 2 + 1), spectroSwitcher->durationRight());

			initialTime = common::Date();
			sleep(sleepTime);
273
274
275
276
277
278
279
		}
	}
}

void CountWithSpectro::setupCountParams() {
	count->time.setpoint = countTime();
	count->timeType = timeType();
280
	count->subtitle = subtitle();
281
282
}

283
284
285
286
287
void CountWithSpectro::initArrays() {
	if (m_yDataArray) {
		delete[] m_yDataArray;
	} else if (m_yDataArraySecondChannel) {
		delete[] m_yDataArraySecondChannel;
288
289
	}

290
	int32 totalSize = spectro->size() * numSpectroMeasures();
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
	m_yDataArray = new int32[totalSize];
	memset(m_yDataArray, 0, totalSize * sizeof(int32)); //set to zero
	yDataArray.update(m_yDataArray);
	yDataArray.setSize(totalSize);

	m_yDataArraySecondChannel = new int32[totalSize];
	memset(m_yDataArraySecondChannel, 0, totalSize * sizeof(int32)); //set to zero
	yDataArraySecondChannel.update(m_yDataArraySecondChannel);
	yDataArraySecondChannel.setSize(totalSize);

}

void CountWithSpectro::saveSpectroData() {
	int32 totalSize = YSIZE * numSpectroMeasures();
	yDataArray.update(m_yDataArray);
	yDataArray.setSize(totalSize);

	int32 numor = any_cast<int32>(count->getValue("numor"));
	NexusDataFile::appendTo(numor, "NxD22SpecialServerFile.xml", "NxD22SpecialClientFile.xml");
}

void CountWithSpectro::saveSwitcherSpectroData() {
313

314
315
316
317
318
319
320
321
322
	int32 totalSize = YSIZE * numSpectroMeasures();
	yDataArray.update(m_yDataArray);
	yDataArray.setSize(totalSize);

	yDataArraySecondChannel.update(m_yDataArraySecondChannel);
	yDataArraySecondChannel.setSize(totalSize);

	int32 numor = any_cast<int32>(count->getValue("numor"));
	NexusDataFile::appendTo(numor, "NxD22SpecialServerFile.xml", "NxD22SpecialClientFile.xml");
323
324
325
326
327
328
329
330
331
332
333
334
335
336
}

float64 CountWithSpectro::getCountTimeInSec() {
	float64 time;
	if (timeType() == "h") {
		time = countTime() * 3600.;
	} else if (timeType() == "m") {
		time = countTime() * 60.;
	} else if (timeType() == "s") {
		time = countTime();
	}
	return time;
}

337
338
339
340
341
342
343
344
345
346
347
348
349
/**
 * This method calculates the waiting time necessary to distribute the spectrometer measures (in both single or switcher mode) equally through the acquisition time
 */
float64 CountWithSpectro::calculateWaitingTimeInSec() {
	//Convert all units into seconds
	float64 totalSpectroTime;
	float64 switcherSleep = (spectroSwitcher->SLEEP_TIME_MICROSEC) * 0.000001;//0.0001;
	float64 singleWaitTime = 0.0;

	if (numSpectroMeasures() > 1) {
		int32 scansToAverage = spectro->scansToAverage();

		if (useSwitcher()) {
350
351
			float64 measureTime = integrationTime() * 0.000001 + USB_DELAY_MILLISEC * 0.001;
			totalSpectroTime = 2 * (measureTime * numSpectroMeasures() * scansToAverage + switcherSleep);
352
		} else {
353
354
			float64 measureTime = integrationTime() * 0.000001 + USB_DELAY_MILLISEC * 0.001;
			totalSpectroTime = measureTime * numSpectroMeasures() * scansToAverage;
355
356
357
358
359
360
361
362
363
		}

		float64 countTime = getCountTimeInSec();
		float64 totalWaitTime = (countTime - totalSpectroTime);
		singleWaitTime = 0.95 * (totalWaitTime / (numSpectroMeasures() - 1)); //0.95 -> factor to avoid having spectro measures just at the end
	}
	return singleWaitTime;
}

Cristina Cocho's avatar
Cristina Cocho committed
364
365
366
367
368
369
370
371
372

/*
 * setDisabled
 */
void CountWithSpectro::setDisabled(bool all) {
	addExcludeSetEnableController(count.getRole());
	ExperimentController::setDisabled(all);
}

373
374
}