int main (int argc, char *argv[]) { Config mcxconfig; unsigned int activedev=0; float *fluence=NULL,totalenergy=0.f; mcx_initcfg(&mcxconfig); // parse command line options to initialize the configurations mcx_parsecmd(argc,argv,&mcxconfig); // identify gpu number and set one gpu active if(!mcx_set_gpu(&mcxconfig,&activedev)){ mcx_error(-1,"No compute platform was found\n",__FILE__,__LINE__); } if(activedev==0) return 0; mcx_createfluence(&fluence,&mcxconfig); // this launches the MC simulation mcx_run_simulation(&mcxconfig,fluence,&totalenergy); // clean up the allocated memory in the config mcx_clearfluence(&fluence); mcx_clearcfg(&mcxconfig); return 0; }
void mcx_loadvolume(char *filename,Config *cfg){ int datalen,res; FILE *fp=fopen(filename,"rb"); if(fp==NULL){ mcx_error(-5,"the specified binary volume file does not exist",__FILE__,__LINE__); } if(cfg->vol){ free(cfg->vol); cfg->vol=NULL; } datalen=cfg->dim.x*cfg->dim.y*cfg->dim.z; cfg->vol=(unsigned char*)malloc(sizeof(unsigned char)*datalen); res=fread(cfg->vol,sizeof(unsigned char),datalen,fp); fclose(fp); if(res!=datalen){ mcx_error(-6,"file size does not match specified dimensions",__FILE__,__LINE__); } }
void mcx_writeconfig(const char *fname, Config *cfg){ if(fname[0]==0) mcx_saveconfig(stdout,cfg); else{ FILE *fp=fopen(fname,"wt"); if(fp==NULL) mcx_error(-2,"can not write to the specified config file",__FILE__,__LINE__); mcx_saveconfig(fp,cfg); fclose(fp); } }
int main (int argc, char *argv[]) { /*! structure to store all simulation parameters */ Config mcxconfig; /** mcxconfig: structure to store all simulation parameters */ GPUInfo *gpuinfo=NULL; /** gpuinfo: structure to store GPU information */ unsigned int activedev=0; /** activedev: count of total active GPUs to be used */ /** To start an MCX simulation, we first create a simulation configuration and set all elements to its default settings. */ mcx_initcfg(&mcxconfig); /** Then, we parse the full command line parameters and set user specified settings */ mcx_parsecmd(argc,argv,&mcxconfig); /** The next step, we identify gpu number and query all GPU info */ if(!(activedev=mcx_list_gpu(&mcxconfig,&gpuinfo))){ mcx_error(-1,"No GPU device found\n",__FILE__,__LINE__); } #ifdef _OPENMP /** Now we are ready to launch one thread for each involked GPU to run the simulation */ omp_set_num_threads(activedev); #pragma omp parallel { #endif /** This line runs the main MCX simulation for each GPU inside each thread */ mcx_run_simulation(&mcxconfig,gpuinfo); #ifdef _OPENMP } #endif /** Once simulation is complete, we clean up the allocated memory in config and gpuinfo, and exit */ mcx_cleargpuinfo(&gpuinfo); mcx_clearcfg(&mcxconfig); return 0; }
int mcx_readarg(int argc, char *argv[], int id, void *output,const char *type){ /* when a binary option is given without a following number (0~1), we assume it is 1 */ if(strcmp(type,"char")==0 && (id>=argc-1||(argv[id+1][0]<'0'||argv[id+1][0]>'9'))){ *((char*)output)=1; return id; } if(id<argc-1){ if(strcmp(type,"char")==0) *((char*)output)=atoi(argv[id+1]); else if(strcmp(type,"int")==0) *((int*)output)=atoi(argv[id+1]); else if(strcmp(type,"float")==0) *((float*)output)=atof(argv[id+1]); else if(strcmp(type,"string")==0) strcpy((char *)output,argv[id+1]); else if(strcmp(type,"bytenumlist")==0){ char *nexttok,*numlist=(char *)output; int len=0,i; nexttok=strtok(argv[id+1]," ,;"); while(nexttok){ numlist[len++]=(char)(atoi(nexttok)); /*device id<256*/ for(i=0;i<len-1;i++) /* remove duplicaetd ids */ if(numlist[i]==numlist[len-1]){ numlist[--len]='\0'; break; } nexttok=strtok(NULL," ,;"); /*if(len>=MAX_DEVICE) break;*/ } }else if(strcmp(type,"floatlist")==0){ char *nexttok; float *numlist=(float *)output; int len=0; nexttok=strtok(argv[id+1]," ,;"); while(nexttok){ numlist[len++]=atof(nexttok); /*device id<256*/ nexttok=strtok(NULL," ,;"); } } }else{ mcx_error(-1,"incomplete input",__FILE__,__LINE__); } return id+1; }
void mcx_readconfig(const char *fname, Config *cfg){ if(fname[0]==0){ mcx_loadconfig(stdin,cfg); if(cfg->session[0]=='\0'){ strcpy(cfg->session,"default"); } } else{ FILE *fp=fopen(fname,"rt"); if(fp==NULL) mcx_error(-2,"can not load the specified config file",__FILE__,__LINE__); mcx_loadconfig(fp,cfg); fclose(fp); if(cfg->session[0]=='\0'){ strcpy(cfg->session,fname); } } }
void mcx_savedata(float *dat, int len, int doappend, const char *suffix, Config *cfg){ FILE *fp; char name[MAX_PATH_LENGTH]; sprintf(name,"%s.%s",cfg->session,suffix); if(doappend){ fp=fopen(name,"ab"); }else{ fp=fopen(name,"wb"); } if(fp==NULL){ mcx_error(-2,"can not save data to disk",__FILE__,__LINE__); } if(strcmp(suffix,"mch")==0){ fwrite(&(cfg->his),sizeof(History),1,fp); } fwrite(dat,sizeof(float),len,fp); fclose(fp); }
int main (int argc, char *argv[]) { Config mcxconfig; mcx_initcfg(&mcxconfig); // parse command line options to initialize the configurations mcx_parsecmd(argc,argv,&mcxconfig); // identify gpu number and set one gpu active if(!mcx_set_gpu(&mcxconfig)){ mcx_error(-1,"No GPU device found\n",__FILE__,__LINE__); } // this launches the MC simulation mcx_run_simulation(&mcxconfig); // clean up the allocated memory in the config mcx_clearcfg(&mcxconfig); return 0; }
void mcx_parsecmd(int argc, char* argv[], Config *cfg){ int i=1,isinteractive=1,issavelog=0; char filename[MAX_PATH_LENGTH]={0}; char logfile[MAX_PATH_LENGTH]={0}; float np=0.f; if(argc<=1){ mcx_usage(argv[0]); exit(0); } while(i<argc){ if(argv[i][0]=='-'){ if(argv[i][1]=='-'){ if(mcx_remap(argv[i])){ mcx_error(-2,"unknown verbose option",__FILE__,__LINE__); } } switch(argv[i][1]){ case 'h': mcx_usage(argv[0]); exit(0); case 'i': if(filename[0]){ mcx_error(-2,"you can not specify both interactive mode and config file",__FILE__,__LINE__); } isinteractive=1; break; case 'f': isinteractive=0; i=mcx_readarg(argc,argv,i,filename,"string"); break; case 'm': mcx_error(-2,"specifying photon move is not supported any more, please use -n",__FILE__,__LINE__); i=mcx_readarg(argc,argv,i,&(cfg->nphoton),"int"); break; case 'n': i=mcx_readarg(argc,argv,i,&(np),"float"); cfg->nphoton=(int)np; break; case 't': i=mcx_readarg(argc,argv,i,&(cfg->nthread),"int"); break; case 'T': i=mcx_readarg(argc,argv,i,&(cfg->nblocksize),"int"); break; case 's': i=mcx_readarg(argc,argv,i,cfg->session,"string"); break; case 'a': i=mcx_readarg(argc,argv,i,&(cfg->isrowmajor),"char"); break; case 'g': i=mcx_readarg(argc,argv,i,&(cfg->maxgate),"int"); break; case 'b': i=mcx_readarg(argc,argv,i,&(cfg->isreflect),"char"); break; case 'B': i=mcx_readarg(argc,argv,i,&(cfg->isref3),"char"); break; case 'd': i=mcx_readarg(argc,argv,i,&(cfg->issavedet),"char"); break; case 'r': i=mcx_readarg(argc,argv,i,&(cfg->respin),"int"); break; case 'S': i=mcx_readarg(argc,argv,i,&(cfg->issave2pt),"char"); break; case 'p': i=mcx_readarg(argc,argv,i,&(cfg->printnum),"int"); break; case 'e': i=mcx_readarg(argc,argv,i,&(cfg->minenergy),"float"); break; case 'U': i=mcx_readarg(argc,argv,i,&(cfg->isnormalized),"char"); break; case 'R': i=mcx_readarg(argc,argv,i,&(cfg->sradius),"float"); break; case 'l': issavelog=1; break; case 'L': cfg->isgpuinfo=2; break; case 'I': cfg->isgpuinfo=1; break; case 'c': cfg->iscpu=1; break; case 'v': cfg->isverbose=1; break; case 'o': i=mcx_readarg(argc,argv,i,cfg->rootpath,"string"); break; case 'k': i=mcx_readarg(argc,argv,i,cfg->kernelfile,"string"); break; case 'J': i=mcx_readarg(argc,argv,i,cfg->compileropt,"string"); break; case 'D': i=mcx_readarg(argc,argv,i,cfg->deviceid,"bytenumlist"); break; case 'G': i=mcx_readarg(argc,argv,i,cfg->deviceid,"string"); break; case 'W': i=mcx_readarg(argc,argv,i,cfg->workload,"floatlist"); break; case 'z': i=mcx_readarg(argc,argv,i,&(cfg->issrcfrom0),"char"); break; } } i++; } if(issavelog && cfg->session){ sprintf(logfile,"%s.log",cfg->session); cfg->flog=fopen(logfile,"wt"); if(cfg->flog==NULL){ cfg->flog=stdout; fprintf(cfg->flog,"unable to save to log file, will print from stdout\n"); } } if(cfg->clsource==NULL && cfg->isgpuinfo!=2){ FILE *fp=fopen(cfg->kernelfile,"rb"); int srclen; if(fp==NULL){ mcx_error(-10,"the specified OpenCL kernel file does not exist!",__FILE__,__LINE__); } fseek(fp,0,SEEK_END); srclen=ftell(fp); cfg->clsource=(char *)malloc(srclen+1); fseek(fp,0,SEEK_SET); MCX_ASSERT((fread(cfg->clsource,srclen,1,fp)==1)); cfg->clsource[srclen]='\0'; fclose(fp); } if(cfg->isgpuinfo!=2){ /*print gpu info only*/ if(isinteractive){ mcx_readconfig("",cfg); }else{ mcx_readconfig(filename,cfg); } } }
void mcx_maskdet(Config *cfg){ uint d,dx,dy,dz,idx1d,zi,yi; float x,y,z,ix,iy,iz; unsigned char *padvol; dx=cfg->dim.x+2; dy=cfg->dim.y+2; dz=cfg->dim.z+2; /*handling boundaries in a volume search is tedious, I first pad vol by a layer of zeros, then I don't need to worry about boundaries any more*/ padvol=(unsigned char*)calloc(dx*dy,dz); for(zi=1;zi<=cfg->dim.z;zi++) for(yi=1;yi<=cfg->dim.y;yi++) memcpy(padvol+zi*dy*dx+yi*dx+1,cfg->vol+(zi-1)*cfg->dim.y*cfg->dim.x+(yi-1)*cfg->dim.x,cfg->dim.x); for(d=0;d<cfg->detnum;d++) /*loop over each detector*/ for(z=-cfg->detpos[d].w;z<=cfg->detpos[d].w;z++){ /*search in a sphere*/ iz=z+cfg->detpos[d].z; /*1.5=1+0.5, 1 comes from the padding layer, 0.5 move to voxel center*/ for(y=-cfg->detpos[d].w;y<=cfg->detpos[d].w;y++){ iy=y+cfg->detpos[d].y; for(x=-cfg->detpos[d].w;x<=cfg->detpos[d].w;x++){ ix=x+cfg->detpos[d].x; if(iz<0||ix<0||iy<0||ix>=cfg->dim.x||iy>=cfg->dim.y||iz>=cfg->dim.z|| x*x+y*y+z*z > (cfg->detpos[d].w+1.f)*(cfg->detpos[d].w+1.f)) continue; idx1d=(int)((iz+1.f)*dy*dx+(iy+1.f)*dx+(ix+1.f)); if(padvol[idx1d]) /*looking for a voxel on the interface or bounding box*/ if(!(padvol[idx1d+1]&&padvol[idx1d-1]&&padvol[idx1d+dx]&&padvol[idx1d-dx]&&padvol[idx1d+dy*dx]&&padvol[idx1d-dy*dx]&& padvol[idx1d+dx+1]&&padvol[idx1d+dx-1]&&padvol[idx1d-dx+1]&&padvol[idx1d-dx-1]&& padvol[idx1d+dy*dx+1]&&padvol[idx1d+dy*dx-1]&&padvol[idx1d-dy*dx+1]&&padvol[idx1d-dy*dx-1]&& padvol[idx1d+dy*dx+dx]&&padvol[idx1d+dy*dx-dx]&&padvol[idx1d-dy*dx+dx]&&padvol[idx1d-dy*dx-dx]&& padvol[idx1d+dy*dx+dx+1]&&padvol[idx1d+dy*dx+dx-1]&&padvol[idx1d+dy*dx-dx+1]&&padvol[idx1d+dy*dx-dx-1]&& padvol[idx1d-dy*dx+dx+1]&&padvol[idx1d-dy*dx+dx-1]&&padvol[idx1d-dy*dx-dx+1]&&padvol[idx1d-dy*dx-dx-1])){ cfg->vol[(int)(iz*cfg->dim.y*cfg->dim.x+iy*cfg->dim.x+ix)]|=(1<<7);/*set the highest bit to 1*/ } } } } if(cfg->isdumpmask){ char fname[MAX_PATH_LENGTH]; FILE *fp; sprintf(fname,"%s.mask",cfg->session); if((fp=fopen(fname,"wb"))==NULL){ mcx_error(-10,"can not save mask file",__FILE__,__LINE__); } if(fwrite(cfg->vol,cfg->dim.x*cfg->dim.y,cfg->dim.z,fp)!=cfg->dim.z){ mcx_error(-10,"can not save mask file",__FILE__,__LINE__); } fclose(fp); free(padvol); exit(0); } free(padvol); }
void mcx_loadconfig(FILE *in, Config *cfg){ int i,idx1d; unsigned int gates,itmp; char filename[MAX_PATH_LENGTH]={0}, comment[MAX_PATH_LENGTH],*comm; if(in==stdin) fprintf(stdout,"Please specify the total number of photons: [1000000]\n\t"); MCX_ASSERT(fscanf(in,"%d", &(i) )==1); if(cfg->nphoton==0) cfg->nphoton=i; comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%d\nPlease specify the random number generator seed: [1234567]\n\t",cfg->nphoton); MCX_ASSERT(fscanf(in,"%d", &(cfg->seed) )==1); comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%d\nPlease specify the position of the source: [10 10 5]\n\t",cfg->seed); MCX_ASSERT(fscanf(in,"%f %f %f", &(cfg->srcpos.x),&(cfg->srcpos.y),&(cfg->srcpos.z) )==3); comm=fgets(comment,MAX_PATH_LENGTH,in); if(cfg->issrcfrom0==0 && comm!=NULL && sscanf(comm,"%u",&itmp)==1) cfg->issrcfrom0=itmp; if(in==stdin) fprintf(stdout,"%f %f %f\nPlease specify the normal direction of the source fiber: [0 0 1]\n\t", cfg->srcpos.x,cfg->srcpos.y,cfg->srcpos.z); if(!cfg->issrcfrom0){ cfg->srcpos.x--;cfg->srcpos.y--;cfg->srcpos.z--; /*convert to C index, grid center*/ } MCX_ASSERT(fscanf(in,"%f %f %f", &(cfg->srcdir.x),&(cfg->srcdir.y),&(cfg->srcdir.z) )==3); comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%f %f %f\nPlease specify the time gates in seconds (start end and step) [0.0 1e-9 1e-10]\n\t", cfg->srcdir.x,cfg->srcdir.y,cfg->srcdir.z); MCX_ASSERT(fscanf(in,"%f %f %f", &(cfg->tstart),&(cfg->tend),&(cfg->tstep) )==3); comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%f %f %f\nPlease specify the path to the volume binary file:\n\t", cfg->tstart,cfg->tend,cfg->tstep); if(cfg->tstart>cfg->tend || cfg->tstep==0.f){ mcx_error(-9,"incorrect time gate settings",__FILE__,__LINE__); } gates=(unsigned int)((cfg->tend-cfg->tstart)/cfg->tstep+0.5); if(cfg->maxgate>gates) cfg->maxgate=gates; MCX_ASSERT(fscanf(in,"%s", filename)==1); if(cfg->rootpath[0]){ #ifdef WIN32 sprintf(comment,"%s\\%s",cfg->rootpath,filename); #else sprintf(comment,"%s/%s",cfg->rootpath,filename); #endif strncpy(filename,comment,MAX_PATH_LENGTH); } comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%s\nPlease specify the x voxel size (in mm), x dimension, min and max x-index [1.0 100 1 100]:\n\t",filename); MCX_ASSERT(fscanf(in,"%f %u %u %u", &(cfg->steps.x),&(cfg->dim.x),&(cfg->crop0.x),&(cfg->crop1.x))==4); comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%f %u %u %u\nPlease specify the y voxel size (in mm), y dimension, min and max y-index [1.0 100 1 100]:\n\t", cfg->steps.x,cfg->dim.x,cfg->crop0.x,cfg->crop1.x); MCX_ASSERT(fscanf(in,"%f %u %u %u", &(cfg->steps.y),&(cfg->dim.y),&(cfg->crop0.y),&(cfg->crop1.y))==4); comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%f %u %u %u\nPlease specify the z voxel size (in mm), z dimension, min and max z-index [1.0 100 1 100]:\n\t", cfg->steps.y,cfg->dim.y,cfg->crop0.y,cfg->crop1.y); MCX_ASSERT(fscanf(in,"%f %u %u %u", &(cfg->steps.z),&(cfg->dim.z),&(cfg->crop0.z),&(cfg->crop1.z))==4); comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%f %u %u %u\nPlease specify the total types of media:\n\t", cfg->steps.z,cfg->dim.z,cfg->crop0.z,cfg->crop1.z); MCX_ASSERT(fscanf(in,"%u", &(cfg->medianum))==1); cfg->medianum++; comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%d\n",cfg->medianum); cfg->prop=(Medium*)malloc(sizeof(Medium)*cfg->medianum); cfg->prop[0].mua=0.f; /*property 0 is already air*/ cfg->prop[0].mus=0.f; cfg->prop[0].g=0.f; cfg->prop[0].n=1.f; for(i=1;i<(int)cfg->medianum;i++){ if(in==stdin) fprintf(stdout,"Please define medium #%d: mus(1/mm), anisotropy, mua(1/mm) and refractive index: [1.01 0.01 0.04 1.37]\n\t",i); MCX_ASSERT(fscanf(in, "%f %f %f %f", &(cfg->prop[i].mus),&(cfg->prop[i].g),&(cfg->prop[i].mua),&(cfg->prop[i].n))==4); comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%f %f %f %f\n",cfg->prop[i].mus,cfg->prop[i].g,cfg->prop[i].mua,cfg->prop[i].n); } if(in==stdin) fprintf(stdout,"Please specify the total number of detectors and fiber diameter (in mm):\n\t"); MCX_ASSERT(fscanf(in,"%u %f", &(cfg->detnum), &(cfg->detradius))==2); comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%d %f\n",cfg->detnum,cfg->detradius); cfg->detpos=(float4*)malloc(sizeof(float4)*cfg->detnum); if(cfg->issavedet && cfg->detnum==0) cfg->issavedet=0; for(i=0;i<(int)cfg->detnum;i++){ if(in==stdin) fprintf(stdout,"Please define detector #%d: x,y,z (in mm): [5 5 5 1]\n\t",i); MCX_ASSERT(fscanf(in, "%f %f %f", &(cfg->detpos[i].x),&(cfg->detpos[i].y),&(cfg->detpos[i].z))==3); cfg->detpos[i].w=cfg->detradius*cfg->detradius; if(!cfg->issrcfrom0){ cfg->detpos[i].x--;cfg->detpos[i].y--;cfg->detpos[i].z--; /*convert to C index*/ } comm=fgets(comment,MAX_PATH_LENGTH,in); if(in==stdin) fprintf(stdout,"%f %f %f\n",cfg->detpos[i].x,cfg->detpos[i].y,cfg->detpos[i].z); } if(filename[0]){ mcx_loadvolume(filename,cfg); if(cfg->isrowmajor){ /*from here on, the array is always col-major*/ mcx_convertrow2col(&(cfg->vol), &(cfg->dim)); cfg->isrowmajor=0; } if(cfg->issavedet) mcx_maskdet(cfg); if(cfg->srcpos.x<0.f || cfg->srcpos.y<0.f || cfg->srcpos.z<0.f || cfg->srcpos.x>=cfg->dim.x || cfg->srcpos.y>=cfg->dim.y || cfg->srcpos.z>=cfg->dim.z) mcx_error(-4,"source position is outside of the volume",__FILE__,__LINE__); idx1d=((int)floor(cfg->srcpos.z)*cfg->dim.y*cfg->dim.x+(int)floor(cfg->srcpos.y)*cfg->dim.x+(int)floor(cfg->srcpos.x)); /* if the specified source position is outside the domain, move the source along the initial vector until it hit the domain */ if(cfg->vol && cfg->vol[idx1d]==0){ printf("source (%f %f %f) is located outside the domain, vol[%d]=%d\n", cfg->srcpos.x,cfg->srcpos.y,cfg->srcpos.z,idx1d,cfg->vol[idx1d]); while(cfg->vol[idx1d]==0){ cfg->srcpos.x+=cfg->srcdir.x; cfg->srcpos.y+=cfg->srcdir.y; cfg->srcpos.z+=cfg->srcdir.z; printf("fixing source position to (%f %f %f)\n",cfg->srcpos.x,cfg->srcpos.y,cfg->srcpos.z); idx1d=cfg->isrowmajor?(int)(floor(cfg->srcpos.x)*cfg->dim.y*cfg->dim.z+floor(cfg->srcpos.y)*cfg->dim.z+floor(cfg->srcpos.z)):\ (int)(floor(cfg->srcpos.z)*cfg->dim.y*cfg->dim.x+floor(cfg->srcpos.y)*cfg->dim.x+floor(cfg->srcpos.x)); } } }else{ mcx_error(-4,"one must specify a binary volume file in order to run the simulation",__FILE__,__LINE__); } }
void mcx_assess(const int err,const char *msg,const char *file,const int linenum){ if(!err){ mcx_error(err,msg,file,linenum); } }
void mcx_validate_config(Config *cfg){ int i,gates,idx1d; if(!cfg->issrcfrom0){ cfg->srcpos.x--;cfg->srcpos.y--;cfg->srcpos.z--; /*convert to C index, grid center*/ } if(cfg->tstart>cfg->tend || cfg->tstep==0.f){ mexErrMsgTxt("incorrect time gate settings"); } if(ABS(cfg->srcdir.x*cfg->srcdir.x+cfg->srcdir.y*cfg->srcdir.y+cfg->srcdir.z*cfg->srcdir.z - 1.f)>1e-5) mexErrMsgTxt("field 'srcdir' must be a unitary vector"); if(cfg->steps.x==0.f || cfg->steps.y==0.f || cfg->steps.z==0.f) mexErrMsgTxt("field 'steps' can not have zero elements"); if(cfg->tend<=cfg->tstart) mexErrMsgTxt("field 'tend' must be greater than field 'tstart'"); gates=(int)((cfg->tend-cfg->tstart)/cfg->tstep+0.5); if(cfg->maxgate>gates) cfg->maxgate=gates; if(cfg->sradius>0.f){ cfg->crop0.x=MAX((int)(cfg->srcpos.x-cfg->sradius),0); cfg->crop0.y=MAX((int)(cfg->srcpos.y-cfg->sradius),0); cfg->crop0.z=MAX((int)(cfg->srcpos.z-cfg->sradius),0); cfg->crop1.x=MIN((int)(cfg->srcpos.x+cfg->sradius),cfg->dim.x-1); cfg->crop1.y=MIN((int)(cfg->srcpos.y+cfg->sradius),cfg->dim.y-1); cfg->crop1.z=MIN((int)(cfg->srcpos.z+cfg->sradius),cfg->dim.z-1); }else if(cfg->sradius==0.f){ memset(&(cfg->crop0),0,sizeof(uint3)); memset(&(cfg->crop1),0,sizeof(uint3)); } if(cfg->medianum==0) mexErrMsgTxt("you must define the 'prop' field in the input structure"); if(cfg->dim.x==0||cfg->dim.y==0||cfg->dim.z==0) mexErrMsgTxt("the 'vol' field in the input structure can not be empty"); if(cfg->steps.x!=1.f && cfg->unitinmm==1.f){ cfg->unitinmm=cfg->steps.x; cfg->steps.x=1.f;cfg->steps.y=1.f;cfg->steps.z=1.f; } if(cfg->unitinmm!=1.f){ for(i=1;i<cfg->medianum;i++){ cfg->prop[i].mus*=cfg->unitinmm; cfg->prop[i].mua*=cfg->unitinmm; } } if(cfg->issavedet && cfg->detnum==0) cfg->issavedet=0; for(i=0;i<cfg->detnum;i++){ if(!cfg->issrcfrom0){ cfg->detpos[i].x--;cfg->detpos[i].y--;cfg->detpos[i].z--; /*convert to C index*/ } } if(1){ cfg->isrowmajor=0; /*matlab is always col-major*/ if(cfg->isrowmajor){ /*from here on, the array is always col-major*/ mcx_convertrow2col(&(cfg->vol), &(cfg->dim)); cfg->isrowmajor=0; } if(cfg->issavedet) mcx_maskdet(cfg); if(cfg->srcpos.x<0.f || cfg->srcpos.y<0.f || cfg->srcpos.z<0.f || cfg->srcpos.x>=cfg->dim.x || cfg->srcpos.y>=cfg->dim.y || cfg->srcpos.z>=cfg->dim.z) mexErrMsgTxt("source position is outside of the volume"); idx1d=(int)(int(cfg->srcpos.z)*cfg->dim.y*cfg->dim.x+int(cfg->srcpos.y)*cfg->dim.x+int(cfg->srcpos.x)); /* if the specified source position is outside the domain, move the source along the initial vector until it hit the domain */ if(cfg->vol && cfg->vol[idx1d]==0){ printf("source (%f %f %f) is located outside the domain, vol[%d]=%d\n", cfg->srcpos.x,cfg->srcpos.y,cfg->srcpos.z,idx1d,cfg->vol[idx1d]); while(cfg->vol[idx1d]==0){ cfg->srcpos.x+=cfg->srcdir.x; cfg->srcpos.y+=cfg->srcdir.y; cfg->srcpos.z+=cfg->srcdir.z; if(cfg->srcpos.x<0.f || cfg->srcpos.y<0.f || cfg->srcpos.z<0.f || cfg->srcpos.x>=cfg->dim.x || cfg->srcpos.y>=cfg->dim.y || cfg->srcpos.z>=cfg->dim.z) mcx_error(-4,"searching non-zero voxel failed along the incident vector",__FILE__,__LINE__); idx1d=(int)(int(cfg->srcpos.z)*cfg->dim.y*cfg->dim.x+int(cfg->srcpos.y)*cfg->dim.x+int(cfg->srcpos.x)); } printf("fixing source position to (%f %f %f)\n",cfg->srcpos.x,cfg->srcpos.y,cfg->srcpos.z); } } cfg->his.maxmedia=cfg->medianum-1; /*skip medium 0*/ cfg->his.detnum=cfg->detnum; cfg->his.colcount=cfg->medianum+1; /*column count=maxmedia+2*/ }