/* Read project preferences and command line arguments */
static int parseParameters(int argc, const char** argv, SeparationFlags* sfOut)
{
    poptContext context;
    int argRead;
    static int version = FALSE;
    static int copyright = FALSE;
    static unsigned int numParams = 0;
    static int serverParams = 0;
    static const char** rest = NULL;
    static SeparationFlags sf;

    static const struct poptOption options[] =
        {
            {
                "astronomy-parameter-file", 'a',
                POPT_ARG_STRING, &sf.ap_file,
                0, "Astronomy parameter file", NULL
            },

            {
                "star-points-file", 's',
                POPT_ARG_STRING, &sf.star_points_file,
                0, "Star points files", NULL
            },

            {
                "output", 'o',
                POPT_ARG_STRING, &sf.separation_outfile,
                0, "Output file for separation (enables separation)", NULL
            },

            {
                "seed", 'e',
                POPT_ARG_INT, &sf.separationSeed,
                SEED_ARGUMENT, "Seed for random number generator", NULL
            },

            {
                "modfit", 'f',
                POPT_ARG_NONE, &sf.modfit,
                0, "Modified fit from Newby 2011", NULL
            },

            {
				"newbg", 'y',
				POPT_ARG_NONE, &sf.background,
				0, "Uses broken power law as background fit", NULL
			},

            {
                "ignore-checkpoint", 'i',
                POPT_ARG_NONE, &sf.ignoreCheckpoint,
                0, "Ignore the checkpoint file", NULL
            },

            {
                "cleanup-checkpoint", 'c',
                POPT_ARG_NONE, &sf.cleanupCheckpoint,
                0, "Delete checkpoint on successful", NULL
            },

            {
                "print-likelihood-text", 't',
                POPT_ARG_NONE, &sf.LikelihoodToText,
                0, "Create text file with likelihood for use in local MLE", NULL
            },

            {
                "debug-boinc", 'g',
                POPT_ARG_NONE, &sf.debugBOINC,
                0, "Init BOINC with debugging. No effect if not built with BOINC_APPLICATION", NULL
            },

            {
                "process-priority", 'b',
                POPT_ARG_INT, &sf.processPriority,
                0, "Set process priority. Set priority 0 (lowest) to 4 (highest)", NULL
            },

            {
                "device", 'd',
                POPT_ARG_INT, &sf.useDevNumber,
                0, "Device number passed by BOINC to use", NULL
            },

            {
                "non-responsive", 'r',
                POPT_ARG_NONE, &sf.nonResponsive,
                0, "Do not care about display responsiveness (use with caution)", NULL
            },

            {
                "gpu-target-frequency", 'q',
                POPT_ARG_DOUBLE, &sf.targetFrequency,
                0, "Target frequency for GPU tasks" , NULL
            },

            {
                "gpu-wait-factor", 'w',
                POPT_ARG_DOUBLE, &sf.waitFactor,
                0, "Wait correction factor when using high CPU workarounds" , NULL
            },

            {
                "gpu-polling-mode", 'm',
                POPT_ARG_INT, &sf.pollingMode,
                0, "Interval for polling GPU: (-2 (default): Use mode -1 unless working around high CPU driver issue.  -1: use clWaitForEvents(). 0: Use clWaitForEvents() with initial wait, >= 1: sets manual interval polling in ms)" , NULL
            },

            {
                "gpu-disable-checkpointing", 'k',
                POPT_ARG_NONE, &sf.disableGPUCheckpointing,
                0, "Disable checkpointing with GPUs" , NULL
            },

            {
                "platform", 'l',
                POPT_ARG_INT, &sf.usePlatform,
                0, "CL platform index to use", NULL
            },

            {
                "platform-vendor", '\0',
                POPT_ARG_STRING, &sf.preferredPlatformVendor,
                0, "CL Platform vendor name to try to use", NULL
            },

            {
                "verbose", '\0',
                POPT_ARG_NONE, &sf.verbose,
                0, "Print some extra debugging information", NULL
            },

            {
                "force-no-opencl", '\0',
                POPT_ARG_NONE, &sf.forceNoOpenCL,
                0, "Use regular CPU path instead of OpenCL if available", NULL
            },

            {
                "force-no-il-kernel", '\0',
                POPT_ARG_NONE, &sf.forceNoILKernel,
                0, "Do not use AMD IL replacement kernels if available", NULL
            },

            {
                "force-no-intrinsics", '\0',
                POPT_ARG_NONE, &sf.forceNoIntrinsics,
                0, "Use old default path", NULL
            },

            {
                "force-x87", '\0',
                POPT_ARG_NONE, &sf.forceX87,
                0, "Force to use x87 path (ignored if x86_64)", NULL
            },

            {
                "force-sse2", '\0',
                POPT_ARG_NONE, &sf.forceSSE2,
                0, "Force to use SSE2 path", NULL
            },

            {
                "force-sse3", '\0',
                POPT_ARG_NONE, &sf.forceSSE3,
                0, "Force to use SSE3 path", NULL
            },

            {
                "force-sse4.1", '\0',
                POPT_ARG_NONE, &sf.forceSSE41,
                0, "Force to use SSE4.1 path", NULL
            },

            {
                "force-avx", '\0',
                POPT_ARG_NONE, &sf.forceAVX,
                0, "Force to use AVX path", NULL
            },

            {
                "p", 'p',
                POPT_ARG_NONE, &serverParams,
                0, "Unused dummy argument to satisfy primitive arguments the server sends", NULL
            },

            {
                "np", '\0',
                POPT_ARG_INT | POPT_ARGFLAG_ONEDASH, &numParams,
                0, "Unused dummy argument to satisfy primitive arguments the server sends", NULL
            },

            {
                "version", 'v',
                POPT_ARG_NONE, &version,
                0, "Print version information", NULL
            },

            {
                "copyright", '\0',
                POPT_ARG_NONE, &copyright,
                0, "Print copyright information and exit", NULL
            },

            POPT_AUTOHELP
            POPT_TABLEEND
        };

    setInitialFlags(&sf);

    context = poptGetContext(argv[0], argc, argv, options, POPT_CONTEXT_POSIXMEHARDER);
    if (!context)
    {
        mw_printf("Failed to get popt context\n");
        exit(EXIT_FAILURE);
    }

    if (argc < 2)
    {
        poptPrintUsage(context, stderr, 0);
        poptFreeContext(context);
        exit(EXIT_FAILURE);
    }

    argRead = mwReadArguments(context);
    if (argRead < 0)
    {
        poptFreeContext(context);
        freeSeparationFlags(&sf);
        exit(EXIT_FAILURE);
    }

    if (version)
    {
        printVersion(FALSE, sf.verbose);
    }

    if (copyright)
    {
        printCopyright();
    }

    if (version || copyright)
    {
        exit(EXIT_SUCCESS);
    }

    sf.setSeed = !!(argRead & SEED_ARGUMENT); /* Check if these flags were used */

    sf.do_separation = (sf.separation_outfile && strcmp(sf.separation_outfile, ""));
    if (sf.do_separation)
        prob_ok_init(sf.separationSeed, sf.setSeed);

    rest = poptGetArgs(context);
    sf.forwardedArgs = mwGetForwardedArguments(rest, &sf.nForwardedArgs);
    sf.numArgs = mwReadRestArgs(rest, sf.nForwardedArgs); /* Temporary */

    poptFreeContext(context);
    setDefaults(&sf);
    *sfOut = sf;

    return 0;
}
void separation(const char* filename, double background_integral, double* stream_integrals)
{
    int q[ap->number_streams];
    double nstars[ap->number_streams];
    int total;
    double sprob[ap->number_streams];
    double prob_s[ap->number_streams];
    double prob_b;
    double pbx;
    double psg[ap->number_streams];
    double d;
    int twoPanel;
    double** cmatrix;
    double dnormal[3];
    double dortho[3];
    double xsun[3];
    double epsilon_s[ap->number_streams];
    double epsilon_b;
    double star_coords[3];
    double starxyz[3];
    double starxyzTransform[3];
    int s_ok = 0;
    int i, j, retval;
    FILE* file;
    double reff_xr_rp3, *qw_r3_N, *r_point;

    twoPanel = 1;
    for (j = 0; j < ap->number_streams; j++)
    {
        nstars[j] = 0;
        q[j] = 0;
    }
    total = 0;
    prob_ok_init();

    printf("Integral complete.\n Beginning probability calculations...\n");
    file = fopen(filename, "w");

    if (ap->sgr_coordinates == 0)
    {
        stripe_normal(ap->wedge, dnormal);
    }
    else if (ap->sgr_coordinates == 1)
    {
        sgr_stripe_normal(ap->wedge, dnormal);
    }
    else
    {
        printf("Error: ap->sgr_coordinates not valid");
    }

    free_star_points(sp);
    free(sp);
    sp = (STAR_POINTS*)malloc(sizeof(STAR_POINTS));
    retval = read_star_points(star_points_file, sp);
    if (retval)
    {
        fprintf(stderr, "APP: error reading star points: %d\n", retval);
        exit(1);
    }
    printf("read %d stars.\n", sp->number_stars);


    cmatrix = (double**)malloc(sizeof(double*) * 3);
    for (i = 0; i < 3; i++)
        cmatrix[i] = (double*)malloc(sizeof(double) * 3);
    dortho[0] = 0.0;
    dortho[1] = 0.0;
    dortho[2] = 1.0;
    get_transform(dnormal, dortho, cmatrix);

    printf("\nTransformation matrix:\n");
    printf("\t%lf %lf %lf\n", cmatrix[0][0], cmatrix[0][1], cmatrix[0][2]);
    printf("\t%lf %lf %lf\n", cmatrix[1][0], cmatrix[1][1], cmatrix[1][2]);
    printf("\t%lf %lf %lf\n\n", cmatrix[2][0], cmatrix[2][1], cmatrix[2][2]);

    xsun[0] = -8.5;
    xsun[1] = 0.0;
    xsun[2] = 0.0;
    d = dotp(dnormal, xsun);

    printf("==============================================\n");
    printf("bint: %lf", background_integral);
    for (j = 0; j < ap->number_streams; j++)
    {
        printf(", ");
        printf("sint[%d]: %lf", j, stream_integrals[j]);
    }
    printf("\n");

    /*get stream & background weight constants*/
    double denom = 1.0;
    for (j = 0; j < ap->number_streams; j++)
    {
        denom += exp(ap->stream_weights[j]);
    }

    for (j = 0; j < ap->number_streams; j++)
    {
        epsilon_s[j] = exp(ap->stream_weights[j]) / denom;
        printf("epsilon_s[%d]: %lf\n", j, epsilon_s[j]);
    }
    epsilon_b = 1.0 / denom;
    printf("epsilon_b:    %lf\n", epsilon_b);

    r_point = (double*)malloc(sizeof(double) * ap->convolve);
    qw_r3_N = (double*)malloc(sizeof(double) * ap->convolve);

    init_constants(ap);

    printf("initialized constants\n");

    for (i = 0; i < sp->number_stars; i++)
    {
        MW_DEBUG("[%d/%d] setting star coords\n", i, sp->number_stars);
        star_coords[0] = sp->stars[i][0];
        star_coords[1] = sp->stars[i][1];
        star_coords[2] = sp->stars[i][2];
        MW_DEBUG("star_coords: %g %g %g\n", star_coords[0], star_coords[1], star_coords[2]);

        MW_DEBUG("twoPanel: %d\n", twoPanel);

        if (twoPanel == 1)
        {
            MW_DEBUG("setting probability constants\n");
            set_probability_constants(ap->convolve, star_coords[2], r_point, qw_r3_N, &reff_xr_rp3);
            MW_DEBUG("calculating probabilities\n");
            calculate_probabilities(r_point, qw_r3_N, reff_xr_rp3, star_coords, ap, &prob_b, prob_s);
            MW_DEBUG("calculated probabilities\n");

            MW_DEBUG("prob_s: %lf\n", prob_s[0]);
            MW_DEBU("prob_b: %lf\n", prob_b);

            pbx = epsilon_b * prob_b / background_integral;

            for (j = 0; j < ap->number_streams; j++)
            {
                psg[j] = epsilon_s[j] * prob_s[j] / stream_integrals[j];
            }

            MW_DEBUG("pbx: %g\n", pbx);
            MW_DEBUG("psg: %g\n", psg[0]);

            double psgSum = 0;
            for (j = 0; j < ap->number_streams; j++)
            {
                psgSum += psg[j];
            }

            for (j = 0; j < ap->number_streams; j++)
            {
                sprob[j] = psg[j] / (psgSum + pbx);
            }

            MW_DEBUG("sprob: %g\n", sprob[0]);

            for (j = 0; j < ap->number_streams; j++)
            {
                nstars[j] += sprob[j];
            }

            MW_DEBUG("nstars: %g\n", nstars[0]);
        }
        else
        {
            for (j = 0; j < ap->number_streams; j++)
            {
                sprob[j] = 1.0;
                nstars[j] += 1.0;
            }
        }


        /*determine if star with sprob should be put into stream*/
        //for(j = 0; j < ap->number_streams; j++) {
        s_ok = prob_ok(ap->number_streams, sprob);
        //  if (s_ok == 1) {
        //      s_ok += j;
        //      break;
        //  }
        //}

        MW_DEBUG("s_ok: %d\n", s_ok);

        if (s_ok >= 1)
        {
            q[s_ok-1]++;
        }

        lbr2xyz(star_coords, starxyz);
        transform_point(starxyz, cmatrix, xsun, starxyzTransform);

        fprintf(file, "%d %lf %lf %lf\n", s_ok, starxyzTransform[0], starxyzTransform[1], starxyzTransform[2]);
        //free(starxyz);
        //free(starxyzTransform);

        total += 1;

        if ( (total % 10000) == 0 )
            printf("%d\n", total);
    }

    printf("%d total stars\n", total);
    for (j = 0; j < ap->number_streams; j++)
    {
        printf("%lf in stream[%d] (%lf%%)\n", nstars[j], j, (nstars[j] / total * 100));
    }

    for (j = 0; j < ap->number_streams; j++)
    {
        printf("%d stars separated into stream\n", q[j]);
    }
    fclose(file);
    printf("Output written to: %s\n", filename);
    free(r_point);
    free(qw_r3_N);
    free_constants(ap);
}