/*! * \file * Read Measurement Data * * This file contains the main mex code for reading measurement data into MATLAB memory. */ #include #include #include #include #include #include "mex.h" #include "precision.h" #include "read_eiger_data.h" #include "read_data_threaded.h" #include "debug_helper.h" namespace { namespace p { constexpr char format[] = "extension"; //!< extension field constexpr char image_size[] = "asize"; //!< image size field constexpr char roi_center[] = "ctr"; //!< ROI center field constexpr char scan_number[] = "scan_number"; //!< scan number field constexpr char data_path[] = "data_path"; //!< data path field constexpr char data_location[] = "data_location"; //!< data location field constexpr char data_prefix[] = "data_prefix"; //!< data prefix field constexpr char scan_string_format[] = "scan_string_format"; //!< scan string format field constexpr char precision[] = "precision"; //!< precision string ('single' or 'double') constexpr char nthreads[] = "nthreads"; //!< number of parallel threads or processes } // namespace p #include "env_helper.h" #include "mex_helper.h" /*! * \brief Get field from struct * * \param pa Pointer to MATLAB struct array * \param field_name Field name * \return Pointer to MATALAB array of field value */ mxArray* getField(const mxArray *pa, const char *field_name) { mxArray *field = mxGetField(pa, 0, field_name); if (! field) throw std::invalid_argument(std::string("Field ")+field_name+" not found in structure!"); return field; } /*! * \brief Get char field * * \param pa MATLAB struct array * \param field_name field name * \return field string value */ std::string getCharField(const mxArray *pa, const char *field_name) { mxArray *field = getField(pa, field_name); if (! mxIsChar(field)) mexErrMsgIdAndTxt("psi:ptycho:arg:field:type:notchar", "Field %s not a char array!", field_name); if (mxGetNumberOfDimensions(field)!=2 || mxGetM(field)!=1) mexErrMsgIdAndTxt("psi:ptycho:arg:field:dim", "Field %s is not a single char array!", field_name); std::size_t nchars = mxGetN(field); char buf[nchars+1]; if (mxGetString(field, buf, nchars+1)) mexErrMsgIdAndTxt("psi:ptycho:string:extract", "Unable to extract characters of field %s!", field_name); return buf; } /*! * \brief Assign values to vector * * \param a Vector of length at least nelements * \param b Pointer to at least nelements values * \param nelements number of elements to assign * \tparam A Vector element type * \tparam B Value type */ template void assign(std::vector &a, const B *b, std::size_t nelements) { if (b == nullptr) mexErrMsgIdAndTxt("psi:ptycho:arg:field:retrieval", "Unable to extract values from numeric vector field!"); for (std::size_t i=0; i std::vector getVectorField(const mxArray *pa, const char *field_name, unsigned int nelements=0) { mxArray *field = getField(pa, field_name); if (! mxIsNumeric(field)) mexErrMsgIdAndTxt("psi:ptycho:arg:field:type:notnumeric", "Field %s not a numeric array!", field_name); if (mxGetNumberOfDimensions(field)!=2 || mxGetM(field)!=1) mexErrMsgIdAndTxt("psi:ptycho:arg:field:dim", "Field %s is not a single numeric array!", field_name); std::size_t N = mxGetN(field); if (nelements && N != nelements) mexErrMsgIdAndTxt("psi:ptycho:arg:field:length", "Field %s doesn't have %u elements!", field_name, nelements); mxClassID mx_class = mxGetClassID(field); std::vector buf(N); switch (mx_class) { case mxINT8_CLASS: assign(buf, mxGetInt8s(field), N); break; case mxUINT8_CLASS: assign(buf, mxGetUint8s(field), N); break; case mxINT16_CLASS: assign(buf, mxGetInt16s(field), N); break; case mxUINT16_CLASS: assign(buf, mxGetUint16s(field), N); break; case mxINT32_CLASS: assign(buf, mxGetInt32s(field), N); break; case mxUINT32_CLASS: assign(buf, mxGetUint32s(field), N); break; case mxINT64_CLASS: assign(buf, mxGetInt64s(field), N); break; case mxUINT64_CLASS: assign(buf, mxGetUint64s(field), N); break; case mxSINGLE_CLASS: assign(buf, mxGetSingles(field), N); break; case mxDOUBLE_CLASS: assign(buf, mxGetDoubles(field), N); break; default: std::string class_name(mxGetClassName(field)); mexErrMsgIdAndTxt("psi:ptycho:arg:field:class", "Field %s doesn't contain integer elements (it has class %s)!", field_name, class_name.c_str()); } return buf; } std::vector getStrings(const mxArray *pa, const char *field_name, unsigned int nelements=0) { mxArray *field = getField(pa, field_name); if (mxGetM(field) != 1) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongDimensions:notOne", "Argument %s must be a 1xN one-dimensional character or cell array!", field_name); std::unique_ptr> ct(get_char_trait(field)); if (ct.get()) { // char array return std::vector({ ct->get_string(field) }); } else { // cell array if (! mxIsCell(field)) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:type", "Argument %s must be either character or cell array!", field_name); std::vector result_vec; for (std::size_t j=0; jget_string(pa)); if (! result_vec.back().size()) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:empty", "Empty string in %s argument!", field_name); } if (! result_vec.size()) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:empty", "Empty %s argument!", field_name); return result_vec; } } } // namespace /*! * \brief MEX function readMeasurementData * * Input arguments: * 0 : csax p structure * * Output arguments: * 0 : Measurement data (3d or 4d array [cols, rows, n_bursts, n_positions], n_burst is optional and only used if the HHDF5 dataset is 4d) * * \param nlhs Number of left hand side (result) arguments * \param plhs Pointer array to left hand side arguments * \param nrhs Number of right hand side (input) arguments * \param prhs Pointer array to right hand side arguments */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { constexpr unsigned int ninputs = 1; constexpr unsigned int noutputs = 1; DEBUG_INIT; if (nrhs != ninputs) mexErrMsgIdAndTxt("psi:ptycho:arg:in:wrongNumber", "Wrong number of arguments, use: array = readMeasurementData(argument structure)"); if (nlhs != noutputs) mexErrMsgIdAndTxt("psi:ptycho:arg:out:wrongNumber", "Wrong number of output arguments, use: array = readObjectData(argument structure)"); if (! mxIsStruct(prhs[0])) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongType:notStruct", "Argument must be of type struct!"); if (mxGetNumberOfDimensions(prhs[0])!=2 || mxGetM(prhs[0])!=1 || mxGetN(prhs[0])!=1) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongDimensions:notOne", "Argument must be a 1x1 struct array!"); bool verbose = env::is_enabled("PTYCHO_READ_VERBOSE"); precision::type prec = precision::type::Single; try { prec = precision::from_str(getCharField(prhs[0], p::precision)); } catch (std::exception &ex) { mexErrMsgIdAndTxt("psi:ptycho:arg:precision", "Precision field error: %s", ex.what()); } try { std::string format(getCharField(prhs[0], p::format)); std::vector image_size; try { image_size = getVectorField(prhs[0], p::image_size, 2); } catch (std::invalid_argument &ex) {} std::vector roi_center; try { roi_center = getVectorField(prhs[0], p::roi_center, 2); } catch (std::invalid_argument &ex) {} std::vector nthreads(getVectorField(prhs[0], p::nthreads, 1)); std::vector data_path(getStrings(prhs[0], p::data_path)); // std::string scan_string_format(getCharField(prhs[0], p::scan_string_format)); // std::string data_prefix(getCharField(prhs[0], p::data_prefix)); // std::vector scan_number(getVectorField(prhs[0], p::scan_number)); // Format dependent arguments std::vector data_location; if (format == "h5") data_location = getStrings(prhs[0], p::data_location); if (verbose) { mexPrintf("extension: %s\n", format.c_str()); if (data_path.size() == 1) { mexPrintf("data_path: %s\n", data_path[0].c_str()); } else { mexPrintf("data_path first: %s\n", data_path[0].c_str()); mexPrintf("data_path last : %s\n", data_path.back().c_str()); } mexPrintf("roi_center: "); if (roi_center.empty()) { mexPrintf("from data\n"); } else { mexPrintf("%ld %ld\n", roi_center[0], roi_center[1]); } mexPrintf("image_size: "); if (image_size.empty()) { mexPrintf("from data\n"); } else { mexPrintf("%ld %ld\n", image_size[0], image_size[1]); } mexPrintf("precision: %s\n", precision::to_str(prec)); // mexPrintf("data_prefix: %s\n", data_prefix.c_str()); // mexPrintf("scan_number: [ "); // for (long l : scan_number) // mexPrintf("%ld ", l); // mexPrintf("]\n"); const char *debuglog = std::getenv("PTYCHO_READ_DEBUG"); mexPrintf("debuglog: %s - ", (debuglog ? debuglog : "not set")); DEBUG { mexPrintf("ok\n"); OUT << "----------- read measurement data ----------------\n"; } else { mexPrintf("not functional\n"); } // Format dependend verbose output if (format == "h5") { if (data_location.size() == 1) { mexPrintf("data_location: %s\n", data_location[0].c_str()); } else { mexPrintf("data_location first: %s\n", data_location[0].c_str()); mexPrintf("data_location last : %s\n", data_location.back().c_str()); } } } if (format == "h5") { DEBUG { OUT << "Reading Eiger data..." << std::endl; } plhs[0] = data_prep::read_eiger_data(nthreads[0], data_path, data_location, image_size, roi_center, prec); } else if (format == "cbf") { DEBUG { OUT << "Reading Pilatus data..." << std::endl; } plhs[0] = data_prep::read_data_threaded("pilatus", nthreads[0], data_path, image_size, roi_center, prec); } else if (format == "tiff") { DEBUG { OUT << "Reading Moench data..." << std::endl; } plhs[0] = data_prep::read_data_threaded("moench", nthreads[0], data_path, image_size, roi_center, prec); } else { mexErrMsgIdAndTxt("psi:ptycho:format:unknown", "Unknown extension: %s", format.c_str()); } } catch (std::exception &ex) { mexErrMsgIdAndTxt("psi:ptycho:struct:arg", "%s", ex.what()); } return; }