trimEn now takes vector

This commit is contained in:
Erik Frojdh 2019-04-04 12:19:30 +02:00
parent c284b24397
commit 85516e42c0
14 changed files with 318 additions and 229 deletions

View File

@ -1355,16 +1355,15 @@ class multiSlsDetector : public virtual slsDetectorDefs {
* @param detPos -1 for all detectors in list or specific detector position
* @returns number of trim energies
*/
int setTrimEn(int nen, int *en = nullptr, int detPos = -1);
int setTrimEn(std::vector<int> energies, int detPos = -1);
/**
* Returns the number of trim energies and their value (Eiger)
*
* @param en array of energies
* @param detPos -1 for all detectors in list or specific detector position
* @returns number of trim energies
* @returns vector of trim energies
*/
int getTrimEn(int *en = nullptr, int detPos = -1);
std::vector<int> getTrimEn(int detPos = -1);
/**
* Pulse Pixel (Eiger)
@ -1953,6 +1952,8 @@ class multiSlsDetector : public virtual slsDetectorDefs {
*/
void processData();
void addSlsDetector(std::unique_ptr<slsDetector> det);
private:
/**
* Initialize (open/create) shared memory for the sharedMultiDetector
@ -1992,14 +1993,16 @@ class multiSlsDetector : public virtual slsDetectorDefs {
*/
void addSlsDetector(const std::string &hostname);
/**
* add gap pixels to the image (only for Eiger in 4 bit mode)
* @param image pointer to image without gap pixels
* @param gpImage poiner to image with gap pixels, if NULL, allocated inside
* function
* @returns number of data bytes of image with gap pixels
*/
int processImageWithGapPixels(char *image, char *&gpImage);
/**
* add gap pixels to the image (only for Eiger in 4 bit mode)
* @param image pointer to image without gap pixels
* @param gpImage poiner to image with gap pixels, if NULL, allocated
* inside function
* @returns number of data bytes of image with gap pixels
*/
int processImageWithGapPixels(char *image, char *&gpImage);
/**
* Set total progress (total number of frames/images in an acquisition)

View File

@ -1208,18 +1208,17 @@ class slsDetector : public virtual slsDetectorDefs{
* Sets the number of trim energies and their value (Eiger)
* \sa sharedSlsDetector
* @param nen number of energies
* @param en array of energies
* @param vector os trimmed energies
* @returns number of trim energies
*/
int setTrimEn(int nen, int *en = nullptr);
int setTrimEn(std::vector<int> energies={});
/**
* Returns the number of trim energies and their value (Eiger)
* \sa sharedSlsDetector
* @param en array of energies
* @returns number of trim energies
*/
int getTrimEn(int *en = nullptr);
* Returns a vector with the trimmed energies (Eiger)
* \sa sharedSlsDetector
* @returns vector with the trimmed energies
*/
std::vector<int> getTrimEn();
/**
* Pulse Pixel (Eiger)

View File

@ -426,6 +426,15 @@ void multiSlsDetector::addSlsDetector(const std::string &hostname) {
detectors[pos]->setOnline(true);
}
void multiSlsDetector::addSlsDetector(std::unique_ptr<slsDetector> det){
detectors.push_back(std::move(det));
multi_shm()->numberOfDetectors = detectors.size();
multi_shm()->dataBytes += detectors.back()->getDataBytes();
multi_shm()->dataBytesInclGapPixels +=
detectors.back()->getDataBytesInclGapPixels();
multi_shm()->numberOfChannels += detectors.back()->getTotalNumberOfChannels();
}
slsDetectorDefs::detectorType multiSlsDetector::getDetectorTypeAsEnum(int detPos) {
// single
if (detPos >= 0) {
@ -2524,25 +2533,19 @@ int multiSlsDetector::enableGapPixels(int val, int detPos) {
return ret;
}
int multiSlsDetector::setTrimEn(int ne, int *ene, int detPos) {
// single
int multiSlsDetector::setTrimEn(std::vector<int> energies, int detPos) {
if (detPos >= 0) {
return detectors[detPos]->setTrimEn(ne, ene);
return detectors[detPos]->setTrimEn(energies);
}
// multi
auto r = serialCall(&slsDetector::setTrimEn, ne, ene);
auto r = parallelCall(&slsDetector::setTrimEn, energies);
return sls::minusOneIfDifferent(r);
}
int multiSlsDetector::getTrimEn(int *ene, int detPos) {
// single
std::vector<int> multiSlsDetector::getTrimEn(int detPos) {
if (detPos >= 0) {
return detectors[detPos]->getTrimEn(ene);
return detectors[detPos]->getTrimEn();
}
// multi
auto r = serialCall(&slsDetector::getTrimEn, ene);
auto r = parallelCall(&slsDetector::getTrimEn);
return sls::minusOneIfDifferent(r);
}

View File

@ -3125,23 +3125,28 @@ int slsDetector::enableGapPixels(int val) {
return detector_shm()->gappixels;
}
int slsDetector::setTrimEn(int nen, int *en) {
if (en) {
for (int ien = 0; ien < nen; ++ien) {
detector_shm()->trimEnergies[ien] = en[ien];
}
detector_shm()->nTrimEn = nen;
int slsDetector::setTrimEn(std::vector<int> energies) {
if (energies.size()>MAX_TRIMEN){
std::ostringstream os;
os << "Size of trim energies: " << energies.size() << " exceeds what can "
<< "be stored in shared memory: " << MAX_TRIMEN << "\n";
throw RuntimeError(os.str());
}
for (int i = 0; i != energies.size(); ++i) {
detector_shm()->trimEnergies[i] = energies[i];
}
detector_shm()->nTrimEn = energies.size();
return (detector_shm()->nTrimEn);
}
int slsDetector::getTrimEn(int *en) {
if (en) {
for (int ien = 0; ien < detector_shm()->nTrimEn; ++ien) {
en[ien] = detector_shm()->trimEnergies[ien];
}
std::vector<int> slsDetector::getTrimEn() {
std::vector<int> energies;
energies.reserve(detector_shm()->nTrimEn);
for (int i = 0; i != detector_shm()->nTrimEn; ++i) {
energies.push_back(detector_shm()->trimEnergies[i]);
}
return (detector_shm()->nTrimEn);
return energies;
}
int slsDetector::pulsePixel(int n, int x, int y) {

View File

@ -2505,41 +2505,24 @@ std::string slsDetectorCommand::helpSettingsDir(int action) {
}
std::string slsDetectorCommand::cmdTrimEn(int narg, char *args[], int action, int detPos) {
int ival;
int ip;
char answer[1000];
if (action == HELP_ACTION)
std::vector<int> energies;
if (action == HELP_ACTION)
return helpTrimEn(action);
if (action == PUT_ACTION) {
if (sscanf(args[1], "%d", &ival)) {
int pos[ival];
for (ip = 0; ip < ival; ++ip) {
if ((2 + ip) < narg) {
if (sscanf(args[2 + ip], "%d", pos + ip)) {
} else
break;
}
}
myDet->setTrimEn(ip, pos, detPos);
energies.reserve(narg-1);
for(int i=1; i!=narg; ++i){
energies.push_back(std::stoi(args[i]));
}
myDet->setTrimEn(energies, detPos);
energies.clear();
}
int npos = myDet->getTrimEn(nullptr, detPos);
if (npos != -1) {
sprintf(answer, "%d", npos);
int opos[npos];
npos = myDet->getTrimEn(opos, detPos);
if (npos != -1) {
for (int ip = 0; ip < npos; ++ip) {
sprintf(answer, "%s %d", answer, opos[ip]);
}
}
energies = myDet->getTrimEn(detPos);
std::ostringstream os;
for(const auto& en : energies){
os << en << ' ';
}
if (npos == -1)
sprintf(answer, "%d", -1);
return std::string(answer);
return os.str();
}
std::string slsDetectorCommand::helpTrimEn(int action) {

View File

@ -1 +1,5 @@
target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-SharedMemory.cpp)
target_sources(tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test-SharedMemory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-slsDetector.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test-multiSlsDetector.cpp
)

View File

@ -0,0 +1,63 @@
#include "catch.hpp"
#include "container_utils.h"
#include "multiSlsDetector.h"
#include "slsDetector.h"
#include "string_utils.h"
#include <iostream>
using namespace sls;
SCENARIO("Multi detector operation", "[detector]") {
multiSlsDetector::freeSharedMemory(0, -1);
GIVEN("An empty multi detector") {
multiSlsDetector m(0);
THEN("the size is zero") {
CHECK(m.getNumberOfDetectors() == 0);
CHECK(m.getDataBytes() == 0);
CHECK(m.getTotalNumberOfChannels() == 0);
}
WHEN("we add a detector") {
m.addSlsDetector(sls::make_unique<slsDetector>(
slsDetectorDefs::detectorType::EIGER, 0, 0));
THEN("the size and number of detector changes") {
CHECK(m.getNumberOfDetectors() == 1);
CHECK(m.getTotalNumberOfChannels() == 256 * 1024);
}
WHEN("we add another detector") {
m.addSlsDetector(sls::make_unique<slsDetector>(
slsDetectorDefs::detectorType::EIGER, 0, 1));
THEN("the size and number of detector changes") {
CHECK(m.getNumberOfDetectors() == 2);
CHECK(m.getTotalNumberOfChannels() == 2 * 256 * 1024);
}
WHEN("We set the trimen") {
std::vector<int> energies{5000, 6000, 7000, 8000, 9000};
m.setTrimEn(energies);
THEN("we read back the same values") {
CHECK(m.getTrimEn() == energies);
}
}
WHEN("We set the trimen to different values") {
std::vector<int> en0{5000, 6000, 7000, 8000, 9000};
std::vector<int> en1{6000, 7000, 8000, 9000};
m.setTrimEn(en0, 0);
m.setTrimEn(en1, 1);
THEN("we read back the same values") {
CHECK(m.getTrimEn(0) == en0);
CHECK(m.getTrimEn(1) == en1);
CHECK(m.getTrimEn() == std::vector<int>{-1});
}
}
}
}
m.freeSharedMemory();
}
}

View File

@ -0,0 +1,49 @@
#include "catch.hpp"
#include "container_utils.h"
#include "slsDetector.h"
#include "string_utils.h"
#include <iostream>
using namespace sls;
TEST_CASE("Set and get trimen", "[detector]") {
// Free shared memory to be sure that we start in a clean state
slsDetector::freeSharedMemory(0, 0);
// Create a detector and check that the type is set correctly
slsDetector d(slsDetectorDefs::detectorType::EIGER, 0, 0);
CHECK(d.getDetectorTypeAsEnum() == slsDetectorDefs::detectorType::EIGER);
// At the beginning there should be no trimen set
auto res = d.getTrimEn();
CHECK(res.size() == 0);
std::vector<int> energies{5200, 6400, 8500, 9900, 12000};
d.setTrimEn(energies);
auto res2 = d.getTrimEn();
// Check that the size and every element matches what we set
CHECK(res2.size() == energies.size());
for (size_t i = 0; i != res2.size(); ++i)
CHECK(res2[i] == energies[i]);
// Setting trimen with too many vales throws an exception and keeps the
// old values
std::vector<int> too_many(150, 1000);
CHECK_THROWS(d.setTrimEn(too_many));
auto res3 = d.getTrimEn();
CHECK(res3.size() == energies.size());
for (size_t i = 0; i != res3.size(); ++i)
CHECK(res3[i] == energies[i]);
// Setting trimen without arguments resets to zero
d.setTrimEn();
CHECK(d.getTrimEn().size() == 0);
// Clean up before next test
d.freeSharedMemory();
}

View File

@ -1,3 +0,0 @@
// tests-main.cpp
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

View File

@ -2,17 +2,15 @@
#define CONTAINER_UTILS_H
#include <algorithm>
#include <memory>
#include <numeric>
#include <sstream>
#include <string>
#include <type_traits>
#include <vector>
#include <sstream>
#include <memory>
namespace sls {
// C++11 make_unique implementation for exception safety
// already available as std::make_unique in C++14
template <typename T, typename... Args>
@ -23,94 +21,88 @@ make_unique(Args &&... args) {
template <typename T>
typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
make_unique(std::size_t n)
{
make_unique(std::size_t n) {
typedef typename std::remove_extent<T>::type RT;
return std::unique_ptr<T>(new RT[n]);
}
template <typename T>
bool allEqual(const std::vector<T>& container)
{
template <typename T> bool allEqual(const std::vector<T> &container) {
if (container.empty())
return false;
const auto& first = container[0];
const auto &first = container[0];
return std::all_of(container.cbegin(), container.cend(),
[first](const T& element) { return element == first; });
[first](const T &element) { return element == first; });
}
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, bool>::type
allEqualWithTol(const std::vector<T>& container, const T tol)
{
allEqualWithTol(const std::vector<T> &container, const T tol) {
if (container.empty())
return false;
const auto& first = container[0];
const auto &first = container[0];
return std::all_of(container.cbegin(), container.cend(),
[first, tol](const T& element) {
return (std::abs(element - first) < tol);
});
[first, tol](const T &element) {
return (std::abs(element - first) < tol);
});
}
template <typename T>
bool allEqualTo(const std::vector<T>& container, const T value)
{
bool allEqualTo(const std::vector<T> &container, const T value) {
if (container.empty())
return false;
return std::all_of(container.cbegin(), container.cend(),
[value](const T& element) { return element == value; });
[value](const T &element) { return element == value; });
}
template <typename T>
bool allEqualToWithTol(const std::vector<T>& container, const T value,
const T tol)
{
bool allEqualToWithTol(const std::vector<T> &container, const T value,
const T tol) {
if (container.empty())
return false;
return std::all_of(container.cbegin(), container.cend(),
[value, tol](const T& element) {
return (std::abs(element - value) < tol);
});
[value, tol](const T &element) {
return (std::abs(element - value) < tol);
});
}
template <typename T>
bool anyEqualTo(const std::vector<T>& container, const T value)
{
bool anyEqualTo(const std::vector<T> &container, const T value) {
return std::any_of(container.cbegin(), container.cend(),
[value](const T& element) { return element == value; });
[value](const T &element) { return element == value; });
}
template <typename T>
bool anyEqualToWithTol(const std::vector<T>& container, const T value,
const T tol)
{
bool anyEqualToWithTol(const std::vector<T> &container, const T value,
const T tol) {
return std::any_of(container.cbegin(), container.cend(),
[value, tol](const T& element) { return (std::abs(element - value) < tol); });
[value, tol](const T &element) {
return (std::abs(element - value) < tol);
});
}
template <typename T>
typename std::enable_if<std::is_arithmetic<T>::value, T>::type
sum(const std::vector<T>& container)
{
return std::accumulate(container.cbegin(), container.cend(), T{ 0 });
sum(const std::vector<T> &container) {
return std::accumulate(container.cbegin(), container.cend(), T{0});
}
template <typename T> T minusOneIfDifferent(const std::vector<T> &container) {
if (allEqual(container))
return container.front();
return static_cast<T>(-1);
}
template <typename T>
T minusOneIfDifferent(const std::vector<T>& container)
{
if (allEqual(container)) {
std::vector<T>
minusOneIfDifferent(const std::vector<std::vector<T>> &container) {
if (allEqual(container))
return container.front();
} else {
return static_cast<T>(-1);
}
return std::vector<T>{-1};
}
} // namespace sls
#endif // CONTAINER_UTILS_H

View File

@ -47,17 +47,8 @@ std::string concatenateIfDifferent(const std::vector<T> &container) {
}
}
template std::string concatenateIfDifferent(const std::vector<IpAddr> &);
template std::string concatenateIfDifferent(const std::vector<MacAddr> &);
std::string stringIpToHex(const std::string &ip) {
std::istringstream iss(ip);
std::ostringstream oss;
std::string item;
while (std::getline(iss, item, '.')) {
oss << std::setw(2) << std::setfill('0') << std::hex << std::stoi(item);
}
return oss.str();
}
}; // namespace sls

View File

@ -4,103 +4,111 @@
#include <string>
#include <vector>
using sls::allEqual;
using sls::allEqualTo;
using sls::anyEqualTo;
using sls::allEqualToWithTol;
using sls::allEqualWithTol;
using sls::anyEqualToWithTol;
using namespace sls;
using sls::sum;
TEST_CASE("Equality of an empty vector") {
std::vector<int> v;
REQUIRE(v.empty());
REQUIRE_FALSE(allEqual(v));
REQUIRE_FALSE(allEqualWithTol(v, 2));
REQUIRE_FALSE(allEqualTo(v, 5));
REQUIRE_FALSE(anyEqualTo(v, 5));
REQUIRE_FALSE(anyEqualToWithTol(v, 5, 1));
}
TEST_CASE("Equality of a vector with one element") {
std::vector<int> v{5};
REQUIRE(v.size() == 1);
REQUIRE(allEqual(v));
REQUIRE(allEqualWithTol(v, 1));
REQUIRE(allEqualTo(v, 5));
REQUIRE(allEqualToWithTol(v, 5, 2));
REQUIRE(anyEqualTo(v, 5));
REQUIRE(anyEqualToWithTol(v, 5, 1));
}
TEST_CASE("A larger vector of the same elements") {
std::vector<int> v(101, 5);
REQUIRE(v.size() == 101);
REQUIRE(allEqual(v));
REQUIRE(allEqualWithTol(v, 1));
REQUIRE(allEqualTo(v, 5));
REQUIRE(anyEqualTo(v, 5));
SECTION(
"Push back another element to create a vector where not all are equal") {
v.push_back(7);
REQUIRE(v.size() == 102);
TEST_CASE("Equality of an empty vector", "[support]") {
std::vector<int> v;
REQUIRE(v.empty());
REQUIRE_FALSE(allEqual(v));
REQUIRE_FALSE(allEqualWithTol(v, 1));
REQUIRE(allEqualWithTol(v, 3));
REQUIRE_FALSE(allEqualWithTol(v, 2));
REQUIRE_FALSE(allEqualTo(v, 5));
REQUIRE_FALSE(allEqualToWithTol(v, 5, 1));
REQUIRE(allEqualToWithTol(v, 5, 3));
REQUIRE(anyEqualTo(v, 5));
}
REQUIRE_FALSE(anyEqualTo(v, 5));
REQUIRE_FALSE(anyEqualToWithTol(v, 5, 1));
}
TEST_CASE("A vector of double with different values") {
std::vector<double> v{1.2, 2., 4.2, 4, 1.1};
REQUIRE(allEqual(v) == false);
REQUIRE(allEqualWithTol(v, 0.3) == false);
REQUIRE(allEqualWithTol(v, 3.2));
}
TEST_CASE("Sum of empty vector") {
std::vector<float> v;
REQUIRE(sls::sum(v) == Approx(0));
}
TEST_CASE("Sum of vector") {
std::vector<double> v{1.2, 2., 4.2, 4, 1.13};
REQUIRE(sls::sum(v) == Approx(12.53));
}
TEST_CASE("Minus one if different") {
std::vector<double> v;
REQUIRE(v.empty());
double d = -1;
REQUIRE(sls::minusOneIfDifferent(v) == d);
SECTION("single element") {
v.push_back(7.3);
TEST_CASE("Equality of a vector with one element", "[support]") {
std::vector<int> v{5};
REQUIRE(v.size() == 1);
REQUIRE(sls::minusOneIfDifferent(v) == Approx(7.3));
}
SECTION("different elements") {
v.push_back(7.3);
v.push_back(1.0);
v.push_back(62.1);
REQUIRE(sls::minusOneIfDifferent(v) == Approx(-1.0));
}
REQUIRE(allEqual(v));
REQUIRE(allEqualWithTol(v, 1));
REQUIRE(allEqualTo(v, 5));
REQUIRE(allEqualToWithTol(v, 5, 2));
REQUIRE(anyEqualTo(v, 5));
REQUIRE(anyEqualToWithTol(v, 5, 1));
}
TEST_CASE("minus one does not have side effects"){
std::vector<int> v{1,1,1};
TEST_CASE("A larger vector of the same elements", "[support]") {
std::vector<int> v(101, 5);
REQUIRE(v.size() == 101);
REQUIRE(allEqual(v));
REQUIRE(allEqualWithTol(v, 1));
REQUIRE(allEqualTo(v, 5));
REQUIRE(anyEqualTo(v, 5));
SECTION("Push back another element to create a vector where not all are "
"equal") {
v.push_back(7);
REQUIRE(v.size() == 102);
REQUIRE_FALSE(allEqual(v));
REQUIRE_FALSE(allEqualWithTol(v, 1));
REQUIRE(allEqualWithTol(v, 3));
REQUIRE_FALSE(allEqualTo(v, 5));
REQUIRE_FALSE(allEqualToWithTol(v, 5, 1));
REQUIRE(allEqualToWithTol(v, 5, 3));
REQUIRE(anyEqualTo(v, 5));
}
}
TEST_CASE("A vector of double with different values", "[support]") {
std::vector<double> v{1.2, 2., 4.2, 4, 1.1};
REQUIRE(allEqual(v) == false);
REQUIRE(allEqualWithTol(v, 0.3) == false);
REQUIRE(allEqualWithTol(v, 3.2));
}
TEST_CASE("Sum of empty vector", "[support]") {
std::vector<float> v;
REQUIRE(sls::sum(v) == Approx(0));
}
TEST_CASE("Sum of vector", "[support]") {
std::vector<double> v{1.2, 2., 4.2, 4, 1.13};
REQUIRE(sls::sum(v) == Approx(12.53));
}
TEST_CASE("Minus one if different", "[support]") {
std::vector<double> v;
REQUIRE(v.empty());
double d = -1;
REQUIRE(sls::minusOneIfDifferent(v) == d);
SECTION("single element") {
v.push_back(7.3);
REQUIRE(v.size() == 1);
REQUIRE(sls::minusOneIfDifferent(v) == Approx(7.3));
}
SECTION("different elements") {
v.push_back(7.3);
v.push_back(1.0);
v.push_back(62.1);
REQUIRE(sls::minusOneIfDifferent(v) == Approx(-1.0));
}
}
TEST_CASE("minus one does not have side effects", "[support]") {
std::vector<int> v{1, 1, 1};
int i = sls::minusOneIfDifferent(v);
REQUIRE(i==1);
i=5;
REQUIRE(v[0]==1);
REQUIRE(i == 1);
i = 5;
REQUIRE(v[0] == 1);
}
TEST_CASE("Compare a vector containing two vectors", "[support]") {
std::vector<std::vector<int>> a{{0, 1, 2, 3, 4, 5}, {0, 1, 2, 3, 4, 5}};
std::vector<std::vector<int>> b{{0, 1, 2, 3, 4, 5}, {0, 1, 2, 3, 3, 5}};
std::vector<std::vector<int>> c{{0, 1, 2, 3, 4}, {0, 1, 2, 3, 3, 5}};
std::vector<std::vector<int>> d{
{0, 1, 2, 3, 4}, {0, 1, 2, 3, 4}, {0, 1, 2, 3, 4}};
std::vector<int> e{0, 1, 2, 3, 4, 5};
CHECK(minusOneIfDifferent(a) == a[0]);
CHECK(minusOneIfDifferent(a) == e);
CHECK(minusOneIfDifferent(b) == std::vector<int>{-1});
CHECK(minusOneIfDifferent(c) == std::vector<int>{-1});
CHECK(minusOneIfDifferent(d) == d[2]);
}

View File

@ -90,11 +90,6 @@ TEST_CASE("concatenate non empty strings with one element"){
REQUIRE(ret=="hej+");
}
TEST_CASE("Convert ip address"){
std::string address = "101.255.103.1";
REQUIRE(sls::stringIpToHex(address) == "65ff6701");
}
TEST_CASE("Remove char from string"){
char str[] = "sometest";

View File

@ -1,3 +0,0 @@
// tests-main.cpp
#define CATCH_CONFIG_MAIN
#include "catch.hpp"