OPALX (Object Oriented Parallel Accelerator Library for Exascal) master (dc2a29eed580)
OPALX
Loading...
Searching...
No Matches
LaserProfile.cpp
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2// $RCSfile: LaserProfile.cpp,v $
3// ------------------------------------------------------------------------
4// $Revision: 1.3.4.1 $
5// ------------------------------------------------------------------------
6// Copyright: see Copyright.readme
7// ------------------------------------------------------------------------
8//
9// Class: LaserProfile
10//
11// ------------------------------------------------------------------------
12
17#include "Utilities/Util.h"
18#include "Utility/Inform.h"
19
20#include <filesystem>
21
22#include <cmath>
23#include <cstdio>
24#include <fstream>
25#include <iostream>
26
27// #define TESTLASEREMISSION
28
30 const std::string& fileName, const std::string& imageName, double intensityCut, short flags)
31 : sizeX_m(0),
32 sizeY_m(0),
33 hist2d_m(nullptr),
34 rng_m(nullptr),
35 pdf_m(nullptr),
36 centerMass_m(0.0),
37 standardDeviation_m(0.0) {
38 unsigned short* image = readFile(fileName, imageName);
39 // saveData("originalLaserProfile", image);
40
41 if (flags & FLIPX) flipX(image);
42 if (flags & FLIPY) flipY(image);
43 if (flags & ROTATE90) {
44 swapXY(image);
45 flipX(image);
46 }
47 if (flags & ROTATE180) {
48 flipX(image);
49 flipY(image);
50 }
51 if (flags & ROTATE270) {
52 swapXY(image);
53 flipY(image);
54 }
55
56 filterSpikes(image);
57 normalizeProfileData(intensityCut, image);
59 // saveData("processedLaserProfile", image);
60 fillHistrogram(image);
61
62 delete[] image;
63
64 setupRNG();
65
66#ifdef TESTLASEREMISSION
68 sampleDist();
69#endif
70
71 printInfo();
72}
73
79
80unsigned short* LaserProfile::readFile(const std::string& fileName, const std::string& imageName) {
81 namespace fs = std::filesystem;
82 if (!fs::exists(fileName)) {
83 throw OpalException(
84 "LaserProfile::readFile", "given file '" + fileName + "' does not exist");
85 }
86
87 size_t npos = fileName.find_last_of('.');
88 std::string ext = fileName.substr(npos + 1);
89
90 unsigned short* image;
91 if (ext == "pgm") {
92 image = readPGMFile(fileName);
93 } else {
94 image = readHDF5File(fileName, imageName);
95 }
96
97 return image;
98}
99
100unsigned short* LaserProfile::readPGMFile(const std::string& fileName) {
101 PortableGraymapReader reader(fileName);
102
103 sizeX_m = reader.getWidth();
104 sizeY_m = reader.getHeight();
105
106 unsigned short* image = new unsigned short[sizeX_m * sizeY_m];
107 unsigned int idx = 0;
108 for (unsigned int i = 0; i < sizeX_m; ++i) {
109 for (unsigned int j = 0; j < sizeY_m; ++j, ++idx) {
110 image[idx] = reader.getPixel(j, i);
111 }
112 }
113
114 return image;
115}
116
118 const std::string& fileName, const std::string& imageName) {
119 hid_t h5 = H5Fopen(fileName.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
120 hid_t group = H5Gopen2(h5, imageName.c_str(), H5P_DEFAULT);
121
122 if (group < 0) {
123 throw OpalException(
124 "LaserProfile::readFile", "given image name '" + imageName + "' does not exist");
125 }
126
127 hsize_t dim[2];
128 hid_t dataSet = H5Dopen2(group, "CameraData", H5P_DEFAULT);
129
130 if (dataSet < 0) {
131 throw OpalException("LaserProfile::readFile", "data set 'CameraData' does not exist");
132 }
133
134 hid_t dataSetSpace = H5Dget_space(dataSet);
135 H5Sget_simple_extent_dims(dataSetSpace, dim, nullptr);
136 hid_t filespace = H5Screate_simple(2, dim, nullptr);
137
138 sizeX_m = dim[0];
139 sizeY_m = dim[1];
140
141 hsize_t startHyperslab[] = {0, 0};
142 hsize_t blockCount[] = {sizeX_m, sizeY_m};
143
144 H5Sselect_hyperslab(filespace, H5S_SELECT_SET, startHyperslab, nullptr, blockCount, nullptr);
145
146 unsigned short* image = new unsigned short[sizeX_m * sizeY_m];
147 hid_t mem = H5Screate_simple(2, blockCount, nullptr);
148
149 H5Dread(dataSet, H5T_NATIVE_USHORT, mem, filespace, H5P_DEFAULT, image);
150
151 H5Sclose(mem);
152 H5Sclose(filespace);
153 H5Dclose(dataSetSpace);
154 H5Dclose(dataSet);
155 H5Gclose(group);
156 H5Fclose(h5);
157
158 return image;
159}
160
161void LaserProfile::flipX(unsigned short* image) {
162 unsigned int col2 = sizeX_m - 1;
163 for (unsigned int col1 = 0; col1 < col2; ++col1, --col2) {
164 unsigned int pixel1 = col1 * sizeY_m;
165 unsigned int pixel2 = col2 * sizeY_m;
166 for (unsigned int row = 0; row < sizeY_m; ++row) {
167 std::swap(image[pixel1++], image[pixel2++]);
168 }
169 }
170}
171
172void LaserProfile::flipY(unsigned short* image) {
173 for (unsigned int col = 0; col < sizeX_m; ++col) {
174 unsigned int pixel1 = col * sizeY_m;
175 unsigned int pixel2 = (col + 1) * sizeY_m - 1;
176
177 unsigned int row2 = sizeY_m - 1;
178 for (unsigned int row1 = 0; row1 < row2; ++row1, --row2) {
179 std::swap(image[pixel1++], image[pixel2--]);
180 }
181 }
182}
183
184void LaserProfile::swapXY(unsigned short* image) {
185 unsigned short* copy = new unsigned short[sizeX_m * sizeY_m];
186 for (unsigned int col = 0; col < sizeX_m; ++col) {
187 for (unsigned int row = 0; row < sizeY_m; ++row) {
188 unsigned int pixel1 = col * sizeY_m + row;
189 unsigned int pixel2 = row * sizeX_m + col;
190
191 copy[pixel2] = image[pixel1];
192 }
193 }
194
195 for (unsigned int pixel = 0; pixel < sizeX_m * sizeY_m; ++pixel) {
196 image[pixel] = copy[pixel];
197 }
198
199 delete[] copy;
200
201 std::swap(sizeX_m, sizeY_m);
202}
203
204void LaserProfile::filterSpikes(unsigned short* image) {
205 hsize_t idx = sizeY_m + 1;
206 hsize_t idxN = idx - sizeY_m;
207 hsize_t idxNW = idxN - 1, idxNE = idxN + 1;
208 hsize_t idxW = idx - 1, idxE = idx + 1;
209 hsize_t idxS = idx + sizeY_m;
210 hsize_t idxSW = idxS - 1, idxSE = idxS + 1;
211
212 for (hsize_t i = 1; i < sizeX_m - 1; ++i) {
213 for (hsize_t j = 1; j < sizeY_m - 1; ++j) {
214 if (image[idx] > 0) {
215 if (image[idxNW] == 0 && image[idxN] == 0 && image[idxNE] == 0 && image[idxW] == 0
216 && image[idxE] == 0 && image[idxSW] == 0 && image[idxS] == 0
217 && image[idxSE] == 0) {
218 image[idx] = 0;
219 }
220 }
221
222 ++idxNW;
223 ++idxN;
224 ++idxNE;
225 ++idxW;
226 ++idx;
227 ++idxE;
228 ++idxSW;
229 ++idxS;
230 ++idxSE;
231 }
232 }
233}
234
235void LaserProfile::normalizeProfileData(double intensityCut, unsigned short* image) {
236 unsigned short int profileMax = getProfileMax(image);
237
238 unsigned int pixel = 0;
239 for (unsigned int col = 0; col < sizeX_m; ++col) {
240 for (unsigned int row = 0; row < sizeY_m; ++row, ++pixel) {
241 double val = (double(image[pixel]) / profileMax - intensityCut) / (1.0 - intensityCut);
242
243 val = std::max(0.0, val);
244 image[pixel] = std::round(val * profileMax);
245 }
246 }
247}
248
249void LaserProfile::computeProfileStatistics(unsigned short* image) {
250 double totalMass = 0.0;
253
254 unsigned int pixel = 0;
255 for (unsigned int col = 0; col < sizeX_m; ++col) {
256 for (unsigned int row = 0; row < sizeY_m; ++row, ++pixel) {
257 double val = image[pixel];
258
259 centerMass_m(0) += val * col;
260 centerMass_m(1) += val * row;
261 standardDeviation_m(0) += val * col * col;
262 standardDeviation_m(1) += val * row * row;
263 totalMass += val;
264 }
265 }
266
267 centerMass_m = centerMass_m / totalMass;
269 std::sqrt(standardDeviation_m(0) / totalMass - centerMass_m(0) * centerMass_m(0));
271 std::sqrt(standardDeviation_m(1) / totalMass - centerMass_m(1) * centerMass_m(1));
272}
273
274void LaserProfile::fillHistrogram(unsigned short* image) {
275 unsigned int histSizeX = sizeX_m;
276 unsigned int histSizeY = sizeY_m;
277 double histRangeX = histSizeX / standardDeviation_m(0) / 2;
278 double histRangeY = histSizeY / standardDeviation_m(1) / 2;
279 double binSizeX = 1.0 / standardDeviation_m(0);
280 double binSizeY = 1.0 / standardDeviation_m(1);
281
282 hist2d_m = gsl_histogram2d_alloc(histSizeX, histSizeY);
283 gsl_histogram2d_set_ranges_uniform(hist2d_m, -histRangeX, histRangeX, -histRangeY, histRangeY);
284
285 unsigned int pixel = 0;
286 for (unsigned int col = 0; col < sizeX_m; ++col) {
287 double x = (col - 0.5 * sizeX_m) / standardDeviation_m(0);
288 x = x + 0.5 * binSizeX;
289 // std::cout << "x = " << x << std::endl;
290
291 for (unsigned int row = 0; row < sizeY_m; ++row, ++pixel) {
292 double val = image[pixel];
293 double y = -(row - 0.5 * sizeY_m) / standardDeviation_m(1);
294 y = y + 0.5 * binSizeY;
295 // if (col == 0)
296 // std::cout << "y = " << y << std::endl;
297
299 }
300 }
302}
303
306
309
311 static_cast<unsigned int>(hist2d_m->nx()), static_cast<unsigned int>(hist2d_m->ny()));
313}
314
316 *ippl::Info << level3
317 << "* "
318 "*******************************************************************************"
319 "***\n";
320 *ippl::Info << level3 << "* LASER PROFILE \n";
321 *ippl::Info << level3 << "* size = " << sizeX_m << " x " << sizeY_m << " pixels \n";
322 *ippl::Info << level3 << "* center of mass: x = " << centerMass_m(0)
323 << ", y = " << centerMass_m(1) << "\n";
324 *ippl::Info << level3 << "* standard deviation: x = " << standardDeviation_m(0)
325 << ", y = " << standardDeviation_m(1) << "\n";
326 *ippl::Info
327 << level3
328 << "* "
329 "**********************************************************************************"
330 << endl;
331}
332
333void LaserProfile::saveData(const std::string& fname, unsigned short* image) {
334 std::ofstream out(
336 {OpalData::getInstance()->getAuxiliaryOutputDirectory(), fname + ".pgm"}));
337
338 out << "P2" << std::endl;
339 out << sizeX_m << " " << sizeY_m << std::endl;
340 out << getProfileMax(image) << std::endl;
341
342 for (unsigned int j = 0; j < sizeY_m; ++j) {
343 for (unsigned int i = 0; i < sizeX_m; ++i) {
344 out << image[i * sizeY_m + j] << " ";
345 }
346 out << std::endl;
347 }
348}
349
351 std::string fname = Util::combineFilePath(
352 {OpalData::getInstance()->getAuxiliaryOutputDirectory(), "LaserHistogram.dat"});
353 FILE* fh = std::fopen(fname.c_str(), "w");
354 gsl_histogram2d_fprintf(fh, hist2d_m, "%g", "%g");
355 std::fclose(fh);
356}
357
359 std::string fname = Util::combineFilePath(
360 {OpalData::getInstance()->getAuxiliaryOutputDirectory(), "LaserEmissionSampled.dat"});
361
362 std::ofstream fh(fname);
363 double x, y;
364
365 for (int i = 0; i < 1000000; i++) {
366 getXY(x, y);
367 fh << x << "\t" << y << "\n";
368 }
369
370 fh.close();
371}
372
373void LaserProfile::getXY(double& x, double& y) {
374 double u = gsl_rng_uniform(rng_m);
375 double v = gsl_rng_uniform(rng_m);
376 gsl_histogram2d_pdf_sample(pdf_m, u, v, &x, &y);
377}
378
379unsigned short LaserProfile::getProfileMax(unsigned short* image) {
380 unsigned int numberPixels = sizeX_m * sizeY_m;
381
382 unsigned short maxIntensity = 0;
383
384 for (unsigned int i = 0; i < numberPixels; i++) {
385 if (image[i] > maxIntensity) maxIntensity = image[i];
386 }
387
388 return maxIntensity;
389}
ippl::Vector< T, Dim > Vector_t
gsl_histogram2d * gsl_histogram2d_alloc(size_t nx, size_t ny)
Allocate a 2D histogram with nx by ny bins.
void gsl_histogram2d_pdf_free(gsl_histogram2d_pdf *p)
Free a 2D histogram PDF.
void gsl_histogram2d_fprintf(FILE *fh, const gsl_histogram2d *h, const char *xformat, const char *yformat)
Print the 2D histogram in a simple text table.
void gsl_histogram2d_accumulate(gsl_histogram2d *h, double x, double y, double weight)
Accumulate a weighted sample into the 2D histogram.
void gsl_histogram2d_pdf_init(gsl_histogram2d_pdf *p, const gsl_histogram2d *h)
Initialize a PDF from a histogram.
void gsl_histogram2d_pdf_sample(const gsl_histogram2d_pdf *p, double u, double v, double *x, double *y)
Sample from the PDF using two uniform variates.
void gsl_histogram2d_set_ranges_uniform(gsl_histogram2d *h, double xmin, double xmax, double ymin, double ymax)
Set uniform x/y bin edges.
gsl_histogram2d_pdf * gsl_histogram2d_pdf_alloc(size_t, size_t)
Allocate a 2D histogram PDF.
void gsl_histogram2d_free(gsl_histogram2d *h)
Free a 2D histogram.
double T
Definition OPALTypes.h:8
double gsl_rng_uniform(gsl_rng *rng)
Definition Random.h:64
#define gsl_rng_default
Definition Random.h:73
void gsl_rng_free(gsl_rng *rng)
Definition Random.h:62
void gsl_rng_env_setup()
Definition Random.h:56
gsl_rng * gsl_rng_alloc(const gsl_rng_type *)
Definition Random.h:60
hsize_t sizeY_m
void normalizeProfileData(double intensityCut, unsigned short *image)
Vector_t< double, 3 > centerMass_m
void getXY(double &x, double &y)
void saveData(const std::string &fname, unsigned short *image)
void fillHistrogram(unsigned short *image)
void flipY(unsigned short *image)
LaserProfile(const std::string &fileName, const std::string &imageName, double intensityCut, short flags)
void flipX(unsigned short *image)
gsl_histogram2d * hist2d_m
unsigned short * readPGMFile(const std::string &fileName)
unsigned short * readFile(const std::string &fileName, const std::string &imageName)
gsl_rng * rng_m
void swapXY(unsigned short *image)
unsigned short getProfileMax(unsigned short *image)
hsize_t sizeX_m
unsigned short * readHDF5File(const std::string &fileName, const std::string &imageName)
void computeProfileStatistics(unsigned short *image)
gsl_histogram2d_pdf * pdf_m
void filterSpikes(unsigned short *image)
Vector_t< double, 3 > standardDeviation_m
static OpalData * getInstance()
Definition OpalData.cpp:193
std::string getAuxiliaryOutputDirectory() const
get the name of the the additional data directory
Definition OpalData.cpp:567
unsigned int getWidth() const
unsigned int getHeight() const
unsigned short getPixel(unsigned int i, unsigned int j) const
size_t nx() const
Number of x bins.
size_t ny() const
Number of y bins.
std::string combineFilePath(std::initializer_list< std::string > ilist)
Definition Util.cpp:193