/*! * \file * Read Object Data * * This file contains the main mex code for reading object data into MATLAB memory. */ #include #include #include #include #include #include #include #include "precision.h" #include "env_helper.h" #include "mex.h" #include "mex_helper.h" #include "read_object_data.h" #include "debug_helper.h" #define USAGE "use: array = readObjectData(nProcesses, precision, [nrows, ncols], datasetPath, { filePaths, ... })" /*! * \brief MEX function readObjectData * * Input arguments: * 0 : Number of read processes * 1 : 'double' or 'single' precision * 2 : Output image size [nrows, ncolumns] (optional, default value = size of first image) * 3 : Input object dataset path within the HDF5 file * 4 : Input HDF5 file paths * * Output arguments: * 0 : Object data (3d, 4d[with modes], or 5d[with slices]) [nobjects, nslices*, nmodes*, nrows, ncolumns] * 1 : (Optional) 1d array of file indices that could not be read * * \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 int max_nprocs = 512; constexpr unsigned int min_inputs = 4; constexpr unsigned int max_inputs = 5; constexpr unsigned int min_outputs = 1; constexpr unsigned int max_outputs = 2; DEBUG_INIT; if ((nrhs < min_inputs) || (nrhs > max_inputs)) mexErrMsgIdAndTxt("psi:ptycho:arg:in:wrongNumber", "Wrong number of arguments, " USAGE); if ((nlhs < min_outputs) || (nlhs > max_outputs)) mexErrMsgIdAndTxt("psi:ptycho:arg:out:wrongNumber", "Wrong number of output arguments, " USAGE); unsigned int i = 0; int64_t nprocs = 1; { // 0 if (! mxIsScalar(prhs[i])) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongType:notScalar", "Argument %d must be scalar!", i+1); std::unique_ptr nt(get_numeric_trait(prhs[i])); if (! nt.get()) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongType:notScalar", "Argument %d must be numeric!", i+1); nprocs = nt->get_int64(prhs[i]); if (nprocs < 1) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:notPositive", "Number of processes must be positive!"); if (nprocs > max_nprocs) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:tooMany", "Too many processes, max is %d!", max_nprocs); i += 1; } precision::type prec = precision::type::Single; { // 1 if (mxGetM(prhs[i]) != 1) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongDimensions:notOne", "Argument %d must be one-dimensional character array!", i+1); std::unique_ptr> ct(get_char_trait(prhs[i])); if (! ct.get()) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongType:notChar", "Argument %d must be of type char!", i+1); std::string precString = ct->get_string(prhs[i]); if (precString == "double") { prec = precision::type::Double; } else if (precString != "single") { mexErrMsgIdAndTxt("psi:ptycho:arg:type", "Illegal type argument (%s): must be either 'single' or 'double'!", precString.c_str()); } i += 1; } std::array dims{0, 0}; do { // 2 optionial std::unique_ptr nt(get_numeric_trait(prhs[i])); if (! nt.get()) break; if ((mxGetN(prhs[i]) != 2) || (mxGetM(prhs[i]) != 1)) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongDimensions:oneByTwo", "Argument %d must be 2x1 numeric array!", i+1); dims[0] = nt->get_int64(prhs[i], 0); dims[1] = nt->get_int64(prhs[i], 1); if ((dims[0] < 1) || (dims[1] < 1)) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:illegalSize", "Size argument must be at least 1 in every dimension!"); i += 1; } while(false); std::string object_path; { // 3 if (mxGetM(prhs[i]) != 1) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongDimensions:notOne", "Argument %d must be one-dimensional character array!", i+1); std::unique_ptr> ct(get_char_trait(prhs[i])); if (! ct.get()) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongType:notChar", "Argument %d must be of type char!", i+1); object_path = ct->get_string(prhs[i]); if (! object_path.size()) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:empty", "Illegal object path argument!"); i += 1; } if (i == nrhs) mexErrMsgIdAndTxt("psi:ptycho:arg:in:wrongNumber", "Missing arguments, " USAGE); std::vector file_paths; { // 4 if (mxGetM(prhs[i]) != 1) mexErrMsgIdAndTxt("psi:ptycho:arg:wrongDimensions:notOne", "Argument %d must be a 1xN one-dimensional character or cell array!", i+1); std::unique_ptr> ct(get_char_trait(prhs[i])); if (ct.get()) { // char array file_paths.push_back(ct->get_string(prhs[i])); } else { // cell array if (! mxIsCell(prhs[i])) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:type", "Argument %d must be either character or cell array!", i+1); for (std::size_t j=0; jget_string(pa)); if (! file_paths.back().size()) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:empty", "Illegal file path argument!"); } if (! file_paths.size()) mexErrMsgIdAndTxt("psi:ptycho:arg:illegal:empty", "Empty file path argument!"); } i += 1; } if (i != nrhs) mexErrMsgIdAndTxt("psi:ptycho:arg:in:wrongNumber", "Superfluous arguments, " USAGE); bool verbose = env::is_enabled("PTYCHO_READ_VERBOSE"); if (verbose) { mexPrintf("precision: %s\n", precision::to_str(prec)); const char *debuglog = std::getenv("PTYCHO_READ_DEBUG"); mexPrintf("debuglog: %s - ", (debuglog ? debuglog : "not set")); DEBUG { mexPrintf("ok\n"); OUT << "----------- read object data ----------------\n"; } else { mexPrintf("not functional\n"); } mexPrintf("object_location: %s\n", object_path.c_str()); if (file_paths.size() == 1) { mexPrintf("data_location: %s\n", file_paths[0].c_str()); } else { mexPrintf("data_location first: %s\n", file_paths[0].c_str()); mexPrintf("data_location last : %s\n", file_paths.back().c_str()); } } data_prep::read_stat r_stat; plhs[0] = data_prep::read_object_data((int)nprocs, prec, dims, object_path, file_paths, (nlhs == 2) ? &plhs[1] : nullptr, verbose ? &r_stat : nullptr); if (verbose) mexPrintf("Read %fMB in %fs, bandwidth is %fMB/s\n", (r_stat.nbytes / 1000000.), r_stat.seconds, (r_stat.nbytes / (r_stat.seconds * 1000000.))); return; }