%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% set-up batch processing of RGB particle tracking data
function proc_rgblpt(run_id, clean)    
    addpath(genpath([pwd '/../core']));
    
    %% input parameters
    % where to save processing job
    job_dir					= strjoin(['/Volumes/home/test/jobs/' run_id clean], "");
    mkdir(job_dir);
    job_file				= strjoin([job_dir '/job.mat'], "");
    % execute batch processing job now?
    b_execute				= true;
    
    % path to calibration file
    cal_file				= strjoin(["/Volumes/home/test/calib/" run_id], "");
    % pattern to load source files
    if clean
        src_dir             = strjoin(["/Volumes/home/test/calib/" run_id "/clean/"], "");
    else
        src_dir             = strjoin(["/Volumes/home/test/calib/" run_id], "");
    end
    fprintf(src_dir);
    fprintf("\n");

    src_pat					= '%s/z%03d_t%03d.cam%d.tif';
    src_rng_z				= 1:1;
    src_rng_t				= 1:1;
    [iz,it]					= ndgrid(src_rng_z, src_rng_t);
    n_src					= numel(iz);
    src_file_fun			= @(icam,isamp) sprintf(src_pat, src_dir, iz(isamp), it(isamp), icam);
    
    % pattern to save 
    dst_dir					= src_dir;
    dst_pat				    = '%s/tracks/z%03d_t%03d.mat';
    
    dst_file_fun			= @(isamp) sprintf(dst_pat, dst_dir, iz(isamp), it(isamp));
    
    % particle matching and triangulation options
    mopts					= struct();
    mopts.img_threshold		= [50 50 40];
    mopts.R_search_obj		= 2.5;	% search radius for new particle
    mopts.R_tolerance_img	= 1.0;	% triangulation tolerance, px
    mopts.R_tolerance_obj	= 0.3;	% tolerance for projection error, mm
    mopts.K_feature			= [5 3];% feature size
    mopts.n_search			= 3;	% number of candidate particles to consider in search radius
    
    % general options
    opts					= struct();
    opts.matching			= mopts;
    opts.b_debug_plot		= 0;
    opts.precision          = 'single';
    
    %% load calibration
    fprintf('loading calibration...\n');
    setup					= load(cal_file);
    n_cameras				= length(setup.camera);
    
    %% define source files
    fprintf('defining source and destination files...\n');
    src_file_ary			= cell(n_cameras, n_src);
    dst_file_ary			= cell(1,n_src);
    for is = 1 : n_src
	    %% which image files to load
	    for ic = 1 : n_cameras
		    src_file_ary{ic,is} = src_file_fun(ic, is);
		    if exist(src_file_ary{ic,is}, 'file') == 0
			    warning('source image %s does not exist', src_file_ary{ic,is});
		    end
	    end
	    %% where to save
	    dst_file_ary{is}= dst_file_fun(is);
	    dst				= fileparts(dst_file_ary{is});
	    if exist(dst, 'dir') == 0
		    mkdir(dst);
	    end
    end
    
    %% define job structure
    job						= struct();
    job.cal_file			= cal_file;
    job.n_src				= n_src;
    job.n_cameras			= n_cameras;
    job.src_file_ary		= src_file_ary;
    job.dst_file_ary		= dst_file_ary;
    job.opts				= opts;
    
    fprintf('saving job to %s\n', job_file);
    save(job_file, '-struct', 'job');
    
    %% optionally execute job
    if b_execute
	    batch_rgblpt(job_file);
    end

