//AnyOption for command-line processing //#include "anyoption.h" #include "rts/optics/material.h" #include "nearfield.h" #include "microscope.h" #include "rts/visualization/colormap.h" #include "fileout.h" //extern nearfieldStruct* NF; extern microscopeStruct* SCOPE; extern fileoutStruct gFileOut; //default values #include "defaults.h" #include #include #include #include using namespace std; #include namespace po = boost::program_options; extern bool verbose; extern bool gui; static void lNearfield(po::variables_map vm) { //test to see if we are running a vector field simulation bool vectorField = false; if(vm.count("vector")) vectorField = true; SCOPE->scalarSim = !vectorField; //test to see if we are simulating a plane wave bool planeWave = DEFAULT_PLANEWAVE; if(vm.count("plane-wave")) planeWave = !planeWave; SCOPE->nf.planeWave = planeWave; //get the incident field amplitude SCOPE->nf.A = vm["amplitude"].as(); //get the condenser parameters SCOPE->nf.condenser[0] = DEFAULT_CONDENSER_MIN; SCOPE->nf.condenser[1] = DEFAULT_CONDENSER_MAX; if(vm.count("condenser")) { vector cparams = vm["condenser"].as< vector >(); if(cparams.size() == 1) SCOPE->nf.condenser[1] = cparams[0]; else { SCOPE->nf.condenser[0] = cparams[0]; SCOPE->nf.condenser[1] = cparams[1]; } } //get the focal rtsPoint position SCOPE->nf.focus[0] = DEFAULT_FOCUS_X; SCOPE->nf.focus[1] = DEFAULT_FOCUS_Y; SCOPE->nf.focus[2] = DEFAULT_FOCUS_Z; if(vm.count("focus")) { vector fpos = vm["focus"].as< vector >(); if(fpos.size() != 3) { cout<<"BIMSIM Error - the incident focal point is incorrectly specified; it must have three components."<nf.focus[0] = fpos[0]; SCOPE->nf.focus[1] = fpos[1]; SCOPE->nf.focus[2] = fpos[2]; } //get the incident light direction (k-vector) bsVector spherical(1, 0, 0); //if a k-vector is specified if(vm.count("k")) { vector kvec = vm["k"].as< vector >(); if(kvec.size() != 2) { cout<<"BIMSIM Error - k-vector is not specified correctly: it must contain two elements"<nf.k = spherical.sph2cart(); //incident field order SCOPE->nf.m = vm["field-order"].as(); //number of Monte-Carlo samples SCOPE->nf.nWaves = vm["samples"].as(); //random number seed for Monte-Carlo samples if(vm.count("seed")) srand(vm["seed"].as()); } static void loadOutputParams(po::variables_map vm) { //append simulation results to previous binary files gFileOut.append = DEFAULT_APPEND; if(vm.count("append")) gFileOut.append = true; //image parameters //component of the field to be saved std::string fieldStr; fieldStr = vm["output-type"].as(); if(fieldStr == "magnitude") gFileOut.field = fileoutStruct::fieldMag; else if(fieldStr == "intensity") gFileOut.field = fileoutStruct::fieldIntensity; else if(fieldStr == "polarization") gFileOut.field = fileoutStruct::fieldPolar; else if(fieldStr == "imaginary") gFileOut.field = fileoutStruct::fieldImag; else if(fieldStr == "real") gFileOut.field = fileoutStruct::fieldReal; else if(fieldStr == "angular-spectrum") gFileOut.field = fileoutStruct::fieldAngularSpectrum; //image file names gFileOut.intFile = vm["intensity"].as(); gFileOut.absFile = vm["absorbance"].as(); gFileOut.transFile = vm["transmittance"].as(); gFileOut.nearFile = vm["near-field"].as(); gFileOut.farFile = vm["far-field"].as(); //colormap std::string cmapStr; cmapStr = vm["colormap"].as(); if(cmapStr == "brewer") gFileOut.colormap = rts::cmBrewer; else if(cmapStr == "gray") gFileOut.colormap = rts::cmGrayscale; else cout<<"color-map value not recognized (using default): "<nf.lut_us = false; SCOPE->nf.lut_uf = false; } else if(vm.count("recursive-us")) { SCOPE->nf.lut_us = false; } else if(vm.count("lut-uf")) { SCOPE->nf.lut_uf = true; } //gui if(vm.count("gui")) gui = true; } void lWavelength(po::variables_map vm) { //load the wavelength if(vm.count("nu")) { //wavelength is given in wavenumber - transform and flag SCOPE->nf.lambda = 10000/vm["nu"].as(); gFileOut.wavenumber = true; } //otherwise we are using lambda = wavelength else { SCOPE->nf.lambda = vm["lambda"].as(); gFileOut.wavenumber = false; } } static void lSpheres(string sphereList) { /*This function loads a list of sphere given in the string sphereList The format is: x y z a m where x, y, z = sphere position (required) a = sphere radius (required) m = material ID (optional) */ std::stringstream ss(sphereList); while(!ss.eof()) { //create a new sphere sphere newS; //get the sphere data ss>>newS.p[0]; ss>>newS.p[1]; ss>>newS.p[2]; ss>>newS.a; if(ss.peek() != '\n') ss>>newS.iMaterial; //add the new sphere to the sphere vector SCOPE->nf.sVector.push_back(newS); //ignore the rest of the line ss.ignore(std::numeric_limits::max(), '\n'); //check out the next element (this should set the EOF error flag) ss.peek(); } } void lSpheres(po::variables_map vm) { //if a sphere is specified at the command line if(vm.count("spheres")) { //convert the sphere to a string vector sdesc = vm["spheres"].as< vector >(); //compute the number of spheres specified unsigned int nS; if(sdesc.size() <= 5) nS = 1; else { //if the number of parameters is divisible by 4, compute the number of spheres if(sdesc.size() % 5 == 0) nS = sdesc.size() / 5; else { cout<<"BIMSIM Error: Invalid number of sphere parameters."< filenames = vm["sphere-file"].as< vector >(); //load each file for(unsigned int iS=0; iS(ifs)), std::istreambuf_iterator()); //load the list of spheres from a string lSpheres(instr); } } //make sure the appropriate materials are loaded unsigned int nS = SCOPE->nf.sVector.size(); //for each sphere for(unsigned int s = 0; snf.sVector[s].iMaterial + 1 > SCOPE->nf.mVector.size()) { //otherwise output an error cout<<"BIMSIM Error - A material is not loaded for sphere "<nf.sVector[s].iMaterial + 1<nf.mVector.size()< matVec = vm["materials"].as< vector >(); if(matVec.size() == 1) { rts::material newM(SCOPE->nf.lambda, matVec[0], 0); SCOPE->nf.mVector.push_back(newM); } else if(matVec.size() %2 != 0) { cout<<"BIMSim Error: materials must be specified in n, k pairs"< newM(SCOPE->nf.lambda, matVec[i], matVec[i+1]); SCOPE->nf.mVector.push_back(newM); } } } //if file names are specified, load the materials if(vm.count("material-file")) { vector filenames = vm["material-file"].as< vector >(); for(unsigned int i=0; i(ifs)), std::istreambuf_iterator()); //load the list of spheres from a string rts::material newM(filenames[i].c_str()); //newM.fromStr(instr, ""); SCOPE->nf.mVector.push_back(newM); } } } static void lOptics(po::variables_map vm) { SCOPE->objective[0] = DEFAULT_OBJECTIVE_MIN; SCOPE->objective[1] = DEFAULT_OBJECTIVE_MAX; if(vm.count("objective")) { vector oparams = vm["objective"].as< vector >(); if(oparams.size() == 1) SCOPE->objective[1] = oparams[0]; else { SCOPE->objective[0] = oparams[0]; SCOPE->objective[1] = oparams[1]; } } } static void lImagePlane(po::variables_map vm) { bsPoint pMin(DEFAULT_PLANE_MIN_X, DEFAULT_PLANE_MIN_Y, DEFAULT_PLANE_MIN_Z); bsPoint pMax(DEFAULT_PLANE_MAX_X, DEFAULT_PLANE_MAX_Y, DEFAULT_PLANE_MAX_Z); bsVector normal(DEFAULT_PLANE_NORM_X, DEFAULT_PLANE_NORM_Y, DEFAULT_PLANE_NORM_Z); //set the default values for the slice position and orientation if(vm.count("plane-lower-left") && vm.count("plane-upper-right") && vm.count("plane-normal")) { vector ll = vm["plane-lower-left"].as< vector >(); if(ll.size() != 3) { cout<<"BIMSIM Error - The lower-left corner of the image plane is incorrectly specified."< ur = vm["plane-lower-left"].as< vector >(); if(ur.size() != 3) { cout<<"BIMSIM Error - The upper-right corner of the image plane is incorrectly specified."< norm = vm["plane-lower-left"].as< vector >(); if(norm.size() != 3) { cout<<"BIMSIM Error - The normal of the image plane is incorrectly specified."< xy = vm["xy"].as< vector >(); if(xy.size() >= 1) s = xy[0]; if(xy.size() >= 2) pos = xy[1]; //calculate the plane corners and normal based on the size and position pMin = bsPoint(-s/2, -s/2, pos); pMax = bsPoint(s/2, s/2, pos); normal = bsVector(0, 0, 1); } else if(vm.count("xz")) { //default plane size in microns ptype size = DEFAULT_PLANE_SIZE; ptype pos = DEFAULT_PLANE_POSITION; vector xz = vm["xz"].as< vector >(); if(xz.size() >= 1) size = xz[0]; if(xz.size() >= 2) pos = xz[1]; //calculate the plane corners and normal based on the size and position pMin = bsPoint(-size/2, pos, -size/2); pMax = bsPoint(size/2, pos, size/2); normal = bsVector(0, -1, 0); } else if(vm.count("yz")) { //default plane size in microns ptype size = DEFAULT_PLANE_SIZE; ptype pos = DEFAULT_PLANE_POSITION; vector yz = vm["yz"].as< vector >(); if(yz.size() >= 1) size = yz[0]; if(yz.size() >= 2) pos = yz[1]; //calculate the plane corners and normal based on the size and position pMin = bsPoint(pos, -size/2, -size/2); pMax = bsPoint(pos, size/2, size/2); normal = bsVector(1, 0, 0); } SCOPE->setPos(pMin, pMax, normal); //resolution SCOPE->setRes(vm["resolution"].as(), vm["resolution"].as(), vm["padding"].as(), vm["supersample"].as()); SCOPE->setNearfield(); } static void OutputOptions() { cout<toStr(); cout<<"# of source points: "<focalPoints.size()< test; static void SetOptions(po::options_description &desc) { desc.add_options() ("help", "prints this help") ("gui", "run using the Qt GUI") ("verbose", "verbose output\n\nOutput Parameters\n--------------------------") ("vector", "run a vector field simulation") ("intensity", po::value()->default_value(DEFAULT_INTENSITY_FILE), "output measured intensity (filename)") ("absorbance", po::value()->default_value(DEFAULT_ABSORBANCE_FILE), "output measured absorbance (filename)") ("transmittance", po::value()->default_value(DEFAULT_TRANSMITTANCE_FILE), "output measured transmittance (filename)") ("far-field", po::value()->default_value(DEFAULT_FAR_FILE), "output far-field at detector (filename)") ("near-field", po::value()->default_value(DEFAULT_NEAR_FILE), "output field at focal plane (filename)") ("extended-source", po::value()->default_value(DEFAULT_EXTENDED_SOURCE), "image of source at focus (filename)") ("output-type", po::value()->default_value(DEFAULT_FIELD_TYPE), "output field value:\n magnitude, polarization, real, imaginary, angular-spectrum") ("colormap", po::value()->default_value(DEFAULT_COLORMAP), "colormap: gray, brewer") ("append", "append result to an existing file\n (binary files only)\n\nSphere Parameters\n--------------------------") ("spheres", po::value< vector >()->multitoken(), "sphere position: x y z a m") ("sphere-file", po::value< vector >()->multitoken(), "sphere file:\n [x y z radius material]") ("materials", po::value< vector >()->multitoken(), "refractive indices as n, k pairs:\n ex. -m n0 k0 n1 k1 n2 k2") ("material-file", po::value< vector >()->multitoken(), "material file:\n [lambda n k]\n\nOptics\n--------------------------") ("lambda", po::value()->default_value(DEFAULT_LAMBDA), "incident wavelength") ("nu", po::value(), "incident frequency (in cm^-1)\n(if specified, lambda is ignored)") ("k", po::value< vector >()->multitoken(), "k-vector direction: -k theta phi\n theta = [0 2*pi], phi = [0 pi]") ("amplitude", po::value()->default_value(DEFAULT_AMPLITUDE), "incident field amplitude") ("condenser", po::value< vector >()->multitoken(), "condenser numerical aperature\nA pair of values can be used to specify an inner obscuration: -c NAin NAout") ("objective", po::value< vector >()->multitoken(), "objective numerical aperature\nA pair of values can be used to specify an inner obscuration: -c NAin NAout") ("focus", po::value< vector >()->multitoken(), "focal position for the incident point source\n (default = --focus 0 0 0)") ("plane-wave", "simulates an incident plane wave\n\n\nImaging Parameters\n--------------------------") ("resolution", po::value()->default_value(DEFAULT_SLICE_RES), "resolution of the detector") ("plane-lower-left", po::value< vector >()->multitoken(), "lower-left position of the image plane") ("plane-upper-right", po::value< vector >()->multitoken(), "upper-right position of the image plane") ("plane-normal", po::value< vector >()->multitoken(), "normal for the image plane") ("xy", po::value< vector >()->multitoken(), "specify an x-y image plane\n (standard microscope)") ("xz", po::value< vector >()->multitoken(), "specify a x-z image plane\n (cross-section of the focal volume)") ("yz", po::value< vector >()->multitoken(), "specify a y-z image plane\n (cross-section of the focal volume)\n\nSampling Parameters\n--------------------------") ("samples", po::value()->default_value(DEFAULT_SAMPLES), "Monte-Carlo samples used to compute Us") ("padding", po::value()->default_value(DEFAULT_PADDING), "FFT padding for the objective bandpass") ("supersample", po::value()->default_value(DEFAULT_SUPERSAMPLE), "super-sampling rate for the detector field") ("field-order", po::value()->default_value(DEFAULT_FIELD_ORDER), "order of the incident field") ("seed", po::value(), "seed for the Monte-Carlo random number generator") ("recursive", "evaluate all Bessel functions recursively\n") ("recursive-us", "evaluate scattered-field Bessel functions recursively\n") ("lut-uf", "evaluate the focused-field using a look-up table\n") ; } static void LoadParameters(int argc, char *argv[]) { //create an option description po::options_description desc("BimSim arguments"); //fill it with options SetOptions(desc); po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc, po::command_line_style::unix_style ^ po::command_line_style::allow_short), vm); po::notify(vm); //load flags (help, verbose output) lFlags(vm, desc); //load the wavelength lWavelength(vm); //load materials lMaterials(vm); //load the sphere data lSpheres(vm); //load the optics lOptics(vm); //load the position and orientation of the image plane lImagePlane(vm); lNearfield(vm); loadOutputParams(vm); //if an extended source will be used if(vm["extended-source"].as() != "") { //load the point sources string filename = vm["extended-source"].as(); SCOPE->LoadExtendedSource(filename); } }