static CALresult createLBTrigBuffers(MWCALInfo* ci,
                                     SeparationCALMem* cm,
                                     const AstronomyParameters* ap,
                                     const IntegralArea* ia)
{
    CALresult err = CAL_RESULT_OK;
    LTrigPair* lTrig;
    real* bTrig;

    getSplitLBTrig(ap, ia, &lTrig, &bTrig);

    err = createConstantBuffer2D(&cm->lTrig, ci, (CALdouble*) lTrig, formatReal2, CAL_FALSE, ia->nu_steps, ia->mu_steps);
    if (err != CAL_RESULT_OK)
    {
        cal_warn("Failed to create l trig buffer", err);
        goto fail;
    }

    err = createConstantBuffer2D(&cm->bTrig, ci, (CALdouble*) bTrig, formatReal1, CAL_FALSE, ia->nu_steps, ia->mu_steps);
    if (err != CAL_RESULT_OK)
        cal_warn("Failed to create b trig buffer", err);

fail:
    mwFreeA(lTrig);
    mwFreeA(bTrig);

    return err;
}
static cl_int createLBTrigBuffer(CLInfo* ci,
                                 SeparationCLMem* cm,
                                 const AstronomyParameters* ap,
                                 const IntegralArea* ia,
                                 const SeparationSizes* sizes,
                                 const cl_mem_flags constBufFlags)
{
    cl_int err = CL_SUCCESS;
    LTrigPair* lTrig = NULL;
    real* bSin = NULL;

    getSplitLBTrig(ap, ia, &lTrig, &bSin);

    cm->lTrig = clCreateBuffer(ci->clctx, constBufFlags, sizes->lTrig, lTrig, &err);
    if (err != CL_SUCCESS)
    {
        mwPerrorCL(err, "Error creating lTrig buffer of size "ZU, sizes->lTrig);
        return err;
    }

    cm->bSin = clCreateBuffer(ci->clctx, constBufFlags, sizes->bSin, bSin, &err);
    if (err != CL_SUCCESS)
    {
        mwPerrorCL(err, "Error creating bSin buffer of size "ZU, sizes->bSin);
        return err;
    }

    mwFreeA(lTrig);
    mwFreeA(bSin);

    return CL_SUCCESS;
}
void freeStreamGauss(StreamGauss sg)
{
    mwFreeA(sg.dx);
    mwFreeA(sg.qgaus_W);
#ifdef ANDROID
    mwFreeA(sg.dx_intfp);
#endif
}
static int worker(const SeparationFlags* sf)
{
    AstronomyParameters ap;
    BackgroundParameters bgp = EMPTY_BACKGROUND_PARAMETERS;
    Streams streams = EMPTY_STREAMS;
    IntegralArea* ias = NULL;
    StreamConstants* sc = NULL;
    SeparationResults* results = NULL;
    int rc;
    CLRequest clr;

    memset(&ap, 0, sizeof(ap));
    memset(&clr, 0, sizeof(clr));

    setCLReqFlags(&clr, sf);
    ias = prepareParameters(sf, &ap, &bgp, &streams);
    if (!ias)
        return 1;

    rc = setAstronomyParameters(&ap, &bgp);
    if (rc)
    {
        mwFreeA(ias);
        freeStreams(&streams);
        return 1;
    }

    setExpStreamWeights(&ap, &streams);
    sc = getStreamConstants(&ap, &streams);
    if (!sc)
    {
        mw_printf("Failed to get stream constants\n");
        mwFreeA(ias);
        freeStreams(&streams);
        return 1;
    }

    results = newSeparationResults(ap.number_streams);

    rc = evaluate(results, &ap, ias, &streams, sc, sf->star_points_file,
                  &clr, sf->do_separation, sf->ignoreCheckpoint, sf->separation_outfile);
    if (rc)
        mw_printf("Failed to calculate likelihood\n");

    printSeparationResults(results, ap.number_streams);

    mwFreeA(ias);
    mwFreeA(sc);
    freeStreams(&streams);
    freeSeparationResults(results);

    return rc;
}
void freeEvaluationState(EvaluationState* es)
{
    unsigned int i;

    for (i = 0; i < es->numberCuts; ++i)
        freeCut(&es->cuts[i]);
    mwFreeA(es->cuts);
    mwFreeA(es->streamSums);
    mwFreeA(es->streamTmps);
#ifdef ANDROID
    mwFreeA(es->streamTmpsIntFp);
#endif
    mwFreeA(es);
}
static void getSplitLBTrig(const AstronomyParameters* ap,
                           const IntegralArea* ia,
                           LTrigPair** lTrigOut,
                           real** bSinOut)
{
    cl_uint i, j;
    LTrigPair* lTrig;
    real* bSin;
    LBTrig* lbts;
    size_t idx;

    lbts = precalculateLBTrig(ap, ia, FALSE);

    lTrig = (LTrigPair*) mwMallocA(ia->mu_steps * ia->nu_steps * sizeof(LTrigPair));
    bSin = (real*) mwMallocA(ia->mu_steps * ia->nu_steps * sizeof(real));

    for (i = 0; i < ia->nu_steps; ++i)
    {
        for (j = 0; j < ia->mu_steps; ++j)
        {
            idx = i * ia->mu_steps + j;

            lTrig[idx].lCosBCos = lbts[idx].lCosBCos;
            lTrig[idx].lSinBCos = lbts[idx].lSinBCos;

            bSin[idx] = lbts[idx].bSin;
        }
    }

    mwFreeA(lbts);

    *lTrigOut = lTrig;
    *bSinOut = bSin;
}
StreamGauss getStreamGauss(const unsigned int convolve)
{
    unsigned int i;
    StreamGauss sg;
    real* qgaus_X;

    qgaus_X = (real*) mwMallocA(sizeof(real) * convolve);
    sg.qgaus_W = (real*) mwMallocA(sizeof(real) * convolve);

    gaussLegendre(-1.0, 1.0, qgaus_X, sg.qgaus_W, convolve);

    sg.dx = (real*) mwMallocA(sizeof(real) * convolve);

    for (i = 0; i < convolve; ++i)
        sg.dx[i] = 3.0 * stdev * qgaus_X[i];

    mwFreeA(qgaus_X);
    
#ifdef ANDROID
    sg.dx_intfp = (IntFp*) mwMallocA(sizeof(IntFp) * convolve);
    for (int i=0; i < convolve; i++)
        fp_to_intfp(sg.dx[i],&sg.dx_intfp[i]);
#endif

    return sg;
}
static IntegralArea* prepareParameters(const SeparationFlags* sf,
                                       AstronomyParameters* ap,
                                       BackgroundParameters* bgp,
                                       Streams* streams)
{
    IntegralArea* ias;

    ias = setupSeparation(ap, bgp, streams, sf);
    /* Try the new file first. If that doesn't work, try the old one. */
    if (!ias)
    {
        mw_printf("Error reading astronomy parameters from file '%s'\n"
                  "  Trying old parameters file\n", sf->ap_file);
        ias = readParameters(sf->ap_file, ap, bgp, streams);
    }

    if (!ias)
    {
        mw_printf("Failed to read parameters file\n");
        return NULL;
    }

    if (sf->numArgs && setParameters(ap, bgp, streams, sf->numArgs, sf->nForwardedArgs))
    {
        mwFreeA(ias);
        freeStreams(streams);
        return NULL;
    }

    return ias;
}
StreamConstants* getStreamConstants(const AstronomyParameters* ap, const Streams* streams)
{
    int i;
    StreamConstants* sc;
    real stream_sigma;
    real sigma_sq2;

    sc = (StreamConstants*) mwMallocA(streams->number_streams * sizeof(StreamConstants));

    for (i = 0; i < streams->number_streams; ++i)
    {
        stream_sigma = streams->parameters[i].sigma;

        if (stream_sigma == 0.0)
        {
            mw_printf("stream sigma 0.0 is invalid\n");
            mwFreeA(sc);
            return NULL;
        }

        sc[i].large_sigma = (stream_sigma > SIGMA_LIMIT || stream_sigma < -SIGMA_LIMIT);
        sigma_sq2 = 2.0 * sqr(stream_sigma);

        sc[i].sigma_sq2_inv = 1.0 / sigma_sq2;

        sc[i].a = streamA(&streams->parameters[i]);
        sc[i].c = streamC(ap,
                          ap->wedge,
                          streams->parameters[i].mu,
                          streams->parameters[i].r);
    }

    return sc;
}
/* Might be more convenient to split l and b stuff for CAL */
static void getSplitLBTrig(const AstronomyParameters* ap,
                           const IntegralArea* ia,
                           LTrigPair** lTrigBCosOut,
                           real** bTrigOut)
{
    CALuint i, j;
    LTrigPair* lTrigBCos;
    real* bTrig;
    LBTrig* lbts;
    size_t idx;
    CALboolean transpose = CAL_TRUE;

    lTrigBCos = (LTrigPair*) mwMallocA(ia->mu_steps * ia->nu_steps * sizeof(LTrigPair));
    bTrig = (real*) mwMallocA(ia->mu_steps * ia->nu_steps * sizeof(real));

    lbts = precalculateLBTrig(ap, ia, transpose);

    for (i = 0; i < ia->nu_steps; ++i)
    {
        for (j = 0; j < ia->mu_steps; ++j)
        {
            idx = transpose ? j * ia->nu_steps + i : i * ia->mu_steps + j;

            lTrigBCos[idx].lCosBCos = lbts[idx].lCosBCos;
            lTrigBCos[idx].lSinBCos = lbts[idx].lSinBCos;

            bTrig[idx] = lbts[idx].bSin;
        }
    }

    mwFreeA(lbts);

    *lTrigBCosOut = lTrigBCos;
    *bTrigOut = bTrig;
}
StreamGauss getStreamGauss(int convolve)
{
    int i;
    StreamGauss sg;
    real* qgaus_X;

    qgaus_X = (real*) mwMallocA(sizeof(real) * convolve);
    sg.qgaus_W = (real*) mwMallocA(sizeof(real) * convolve);

    gaussLegendre(-1.0, 1.0, qgaus_X, sg.qgaus_W, convolve);

    sg.dx = (real*) mwMallocA(sizeof(real) * convolve);

    /*Using old (single-sided gaussian stdev = 0.6) to spread points.  This is a small simplification when using 
    modfit, but does not cause any problems since it is parameter independent.  The weights will be calculated 
    later based on the two-sided gaussian.*/

    for (i = 0; i < convolve; ++i)
    {
        sg.dx[i] = 3.0 * stdev * qgaus_X[i];
    }

    mwFreeA(qgaus_X);

    return sg;
}
/* It will be easier to make this less chaotic in the next release
 * when we can dump the old parameters file */
IntegralArea* setupSeparation(AstronomyParameters* ap,
                              BackgroundParameters* bg,
                              Streams* streams,
                              const SeparationFlags* sf)
{
    int rc = 0;
    lua_State* luaSt;

    luaSt = separationOpenLuaStateWithScript(sf);
    if (!luaSt)
        return NULL;

    _ap = ap;
    _bg = bg;
    _streams = streams;

    rc |= evaluateGlobalName(luaSt, evaluateConstants, CONSTANTS_NAME);
    rc |= evaluateGlobalName(luaSt, evaluateIntegralAreas, AREAS_NAME);
    rc |= evaluateGlobalName(luaSt, evaluateBackground, BACKGROUND_NAME);
    rc |= evaluateGlobalName(luaSt, evaluateStreams, STREAMS_NAME);

    lua_close(luaSt);

    if (rc)
    {
        free(_streams->parameters);
        mwFreeA(_ias);
        return NULL;
    }

    setAPConstants(ap);
    return _ias;
}
static cl_int createRBuffers(CLInfo* ci,
                             SeparationCLMem* cm,
                             const AstronomyParameters* ap,
                             const IntegralArea* ia,
                             const StreamGauss sg,
                             const SeparationSizes* sizes,
                             cl_mem_flags constBufFlags)
{
    cl_int err;
    RPoints* r_pts;
    RConsts* rc;

    r_pts = precalculateRPts(ap, ia, sg, &rc, FALSE);

    cm->rPts = clCreateBuffer(ci->clctx, constBufFlags, sizes->rPts, r_pts, &err);

    if (err != CL_SUCCESS)
    {
        mwPerrorCL(err, "Error creating stream r points buffer of size "ZU, sizes->rPts);
        return err;
    }

    cm->rc = clCreateBuffer(ci->clctx, constBufFlags, sizes->rc, rc, &err);
    if (err != CL_SUCCESS)
    {
        mwPerrorCL(err, "Error creating stream r consts buffer of size "ZU, sizes->rc);
        return err;
    }

    cm->sg_dx = clCreateBuffer(ci->clctx, constBufFlags, sizes->sg_dx, sg.dx, &err);
    if (err != CL_SUCCESS)
    {
        mwPerrorCL(err, "Error creating stream sg_dx buffer of size "ZU, sizes->sg_dx);
        return err;
    }

    mwFreeA(r_pts);
    mwFreeA(rc);

    return CL_SUCCESS;
}
static void freeFreeCells(NBodyNode* freeCell)
{
    NBodyNode* p;
    NBodyNode* tmp;

    p = freeCell;
    while (p)
    {
        tmp = Next(p);
        mwFreeA(p);
        p = tmp;
    }
}
static CALresult createRBuffers(MWCALInfo* ci,
                                SeparationCALMem* cm,
                                const AstronomyParameters* ap,
                                const IntegralArea* ia,
                                const StreamGauss sg)
{
    RPoints* r_pts;
    RConsts* rc;
    CALresult err = CAL_RESULT_OK;

    r_pts = precalculateRPts(ap, ia, sg, &rc, TRUE);

    err = createConstantBuffer2D(&cm->rPts, ci, (CALdouble*) r_pts, formatReal2, CAL_FALSE, ia->r_steps, ap->convolve);
    if (err != CAL_RESULT_OK)
    {
        cal_warn("Failed to create r_pts buffer", err);
        goto fail;
    }

    err = createConstantBuffer1D(&cm->rc, ci, (CALdouble*) rc, formatReal2, ia->r_steps);
    if (err != CAL_RESULT_OK)
    {
        cal_warn("Failed to create rc buffer", err);
        goto fail;
    }

    err = createConstantBuffer1D(&cm->sg_dx, ci, sg.dx, constantFormatReal1, ap->convolve);
    if (err != CAL_RESULT_OK)
        cal_warn("Failed to create sg_dx buffer", err);

fail:
    mwFreeA(r_pts);
    mwFreeA(rc);

    return err;
}
static cl_int createSCBuffer(CLInfo* ci,
                             SeparationCLMem* cm,
                             const StreamConstants* sc,
                             const SeparationSizes* sizes,
                             const cl_mem_flags constBufFlags)
{
    cl_int err;
    real* buf;
    cl_int i;

    buf = mwCallocA(sizes->nStream * 8, sizeof(real));

    /* Pack into format used by kernel */
    for (i = 0; i < sizes->nStream; ++i)
    {
        buf[8 * i + 0] = X(sc[i].a);
        buf[8 * i + 1] = X(sc[i].c);

        buf[8 * i + 2] = Y(sc[i].a);
        buf[8 * i + 3] = Y(sc[i].c);

        buf[8 * i + 4] = Z(sc[i].a);
        buf[8 * i + 5] = Z(sc[i].c);

        buf[8 * i + 6] = sc[i].sigma_sq2_inv;
        buf[8 * i + 7] = 0.0;
    }

    cm->sc = clCreateBuffer(ci->clctx, constBufFlags, sizes->sc, (void*) buf, &err);
    mwFreeA(buf);

    if (err != CL_SUCCESS)
    {
        mwPerrorCL(err, "Error creating stream constants buffer of size "ZU, sizes->sc);
        return err;
    }

    return CL_SUCCESS;
}
static void freeNBodyTree(NBodyTree* t)
{
    NBodyNode* p;
    NBodyNode* tmp;

    p = (NBodyNode*) t->root;
    while (p != NULL)
    {
        if (isCell(p))
        {
            tmp = More(p);
            mwFreeA(p);
            p = tmp;
        }
        else                        /* skip over bodies */
        {
            p = Next(p);
        }
    }

    t->root = NULL;
    t->cellUsed = 0;
    t->maxDepth = 0;
}
int destroyNBodyState(NBodyState* st)
{
    int failed = FALSE;
    int nThread = nbGetMaxThreads();
    int i;

    freeNBodyTree(&st->tree);
    freeFreeCells(st->freeCell);
    mwFreeA(st->bodytab);
    mwFreeA(st->acctab);
    mwFreeA(st->orbitTrace);

    free(st->checkpointResolved);

    if (st->potEvalStates)
    {
        for (i = 0; i < nThread; ++i)
        {
            lua_close(st->potEvalStates[i]);
        }
        free(st->potEvalClosures);
        free(st->potEvalStates);
    }

  #if NBODY_OPENCL

    if (st->ci)
    {
        mwDestroyCLInfo(st->ci);
        free(st->ci);
        st->ci = NULL;
    }

    if (st->kernels)
    {
        cl_int err;

        err = nbReleaseKernels(st);
        free(st->kernels);
        failed |= (err != CL_SUCCESS);
    }

    if (st->workSizes)
    {
        free(st->workSizes);
    }

    if (st->nbb)
    {
        cl_int err;

        err = nbReleaseBuffers(st);
        free(st->nbb);
        st->nbb = NULL;
        failed |= (err != CL_SUCCESS);
    }

  #endif /* NBODY_OPENCL */


    failed |= nbDetachSharedScene(st);

    return failed;
}
int evaluate(SeparationResults* results,
             const AstronomyParameters* ap,
             const IntegralArea* ias,
             const Streams* streams,
             const StreamConstants* sc,
             const char* star_points_file,
             const CLRequest* clr,
             int do_separation,
             int ignoreCheckpoint,
             const char* separation_outfile)
{
    int rc = 0;
    EvaluationState* es;
    StreamGauss sg;
    GPUInfo ci;
    StarPoints sp = EMPTY_STAR_POINTS;
    int useImages = FALSE; /* Only applies to CL version */
#ifdef ANDROID
    StreamConstantsIntFp* sci;
    int armExt = mwDetectARMExt();
#endif
    
    memset(&ci, 0, sizeof(ci));

    probabilityFunctionDispatch(ap, clr);

    es = newEvaluationState(ap);
    sg = getStreamGauss(ap->convolve);

  #if SEPARATION_GRAPHICS
    if (separationInitSharedEvaluationState(es))
        warn("Failed to initialize shared evaluation state\n");
  #endif /* SEPARATION_GRAPHICS */

    if (!ignoreCheckpoint)
    {
        if (resolveCheckpoint())
            fail("Failed to resolve checkpoint file '%s'\n", CHECKPOINT_FILE);

        if (maybeResume(es))
            fail("Failed to resume checkpoint\n");
    }

  #if SEPARATION_OPENCL
    if (setupSeparationCL(&ci, ap, ias, clr, &useImages) != CL_SUCCESS)
        fail("Failed to setup CL\n");
  #elif SEPARATION_CAL
    if (separationCALInit(&ci, clr) != CAL_RESULT_OK)
        fail("Failed to setup CAL\n");
  #endif

#ifdef ANDROID
    if (armExt==ARM_CPU_NOVFP && ap->fast_h_prob)
    {
        int i=0;
        unsigned int nstreams = ap->number_streams;
        unsigned int convolve = ap->convolve;
        warn("Use IntFp Engine\n");
        sci = (StreamConstantsIntFp*) mwMallocA(sizeof(StreamConstantsIntFp) * ap->number_streams);
        for (i=0; i < nstreams; i++)
        {
            fp_to_intfp(sc[i].a.x,&(sci[i].a[0]));
            fp_to_intfp(sc[i].a.y,&sci[i].a[1]);
            fp_to_intfp(sc[i].a.z,&sci[i].a[2]);
            fp_to_intfp(sc[i].a.w,&sci[i].a[3]);
            fp_to_intfp(-sc[i].c.x,&sci[i].c[0]);
            fp_to_intfp(-sc[i].c.y,&sci[i].c[1]);
            fp_to_intfp(-sc[i].c.z,&sci[i].c[2]);
            fp_to_intfp(-sc[i].c.w,&sci[i].c[3]);
            fp_to_intfp(sc[i].sigma_sq2_inv,&sci[i].sigma_sq2_inv);
        }
    }
#endif
       
#ifdef ANDROID
    if (armExt == ARM_CPU_NOVFP && ap->fast_h_prob)
        calculateIntegralsIntFp(ap, ias, sci, sg, es, clr, &ci, useImages);
    else
        calculateIntegrals(ap, ias, sc, sg, es, clr, &ci, useImages);
#else
    calculateIntegrals(ap, ias, sc, sg, es, clr, &ci, useImages);
#endif

    if (!ignoreCheckpoint)
    {
        finalCheckpoint(es);
    }

    getFinalIntegrals(results, es, ap->number_streams, ap->number_integrals);
    freeEvaluationState(es);

    if (readStarPoints(&sp, star_points_file))
    {
        rc = 1;
        warn("Failed to read star points file\n");
    }
    else
    {
        /* TODO: likelihood on GPU with OpenCL. Make this less of a
         * mess. The different versions should appear to be the
         * same. */

      #if SEPARATION_CAL
        if (do_separation)
        {
            /* No separation on GPU */
            rc = likelihood(results, ap, &sp, sc, streams, sg, do_separation, separation_outfile);
        }
        else
        {
            //rc = likelihoodCAL(results, ap, &sp, sc, streams, sg, clr, &ci);
            rc = likelihood(results, ap, &sp, sc, streams, sg, do_separation, separation_outfile);
        }
      #else
#ifdef ANDROID
        if (armExt == ARM_CPU_NOVFP && ap->fast_h_prob)
            rc = likelihood_intfp(results, ap, &sp, sci, streams, sg, do_separation, separation_outfile);
        else
            rc = likelihood(results, ap, &sp, sc, streams, sg, do_separation, separation_outfile);
#else
        rc = likelihood(results, ap, &sp, sc, streams, sg, do_separation, separation_outfile);
#endif
      #endif /* SEPARATION_CAL */

        rc |= checkSeparationResults(results, ap->number_streams);
    }

    freeStarPoints(&sp);
    freeStreamGauss(sg);

  #if SEPARATION_OPENCL
    mwDestroyCLInfo(&ci);
  #elif SEPARATION_CAL
    mwCALShutdown(&ci);
  #endif

#ifdef ANDROID
    if (armExt == ARM_CPU_NOVFP && ap->fast_h_prob)
        mwFreeA(sci);
#endif
    
    return rc;
}
/* glut main loop never quits, so actually freeing these is a bad idea */
void nbodyGLCleanup()
{
    mwFreeA(color);
    color = NULL;
}
//Needs to loop to account for number of WUs being crunched
static int worker(const SeparationFlags* sf)
{
    AstronomyParameters ap;
    BackgroundParameters bgp = EMPTY_BACKGROUND_PARAMETERS;
    Streams streams = EMPTY_STREAMS;
    IntegralArea* ias = NULL;
    StreamConstants* sc = NULL;
    SeparationResults* results = NULL;
    int rc;
    CLRequest clr;

    memset(&ap, 0, sizeof(ap));
    memset(&clr, 0, sizeof(clr));

    ap.modfit = sf->modfit;

    if(sf->background)
    {
    	ap.background_profile = BROKEN_POWER_LAW;
    }
    else
    {
    	ap.background_profile = FAST_HERNQUIST;
    }

    setCLReqFlags(&clr, sf);
    /*Assume we are crunching at least 1 work unit (These numbers will be properly set in prepareParameters when the parameter file is read)*/

    ias = prepareParameters(sf, &ap, &bgp, &streams);
    if (!ias)
        return 1;

    if(sf->nForwardedArgs)
    {
        ap.totalWUs = sf->nForwardedArgs/ap.params_per_workunit;
    }
    else
    {
        ap.totalWUs = 1;
    }
    mw_printf("<number_WUs> %d </number_WUs>\n", ap.totalWUs);
    mw_printf("<number_params_per_WU> %d </number_params_per_WU>\n", ap.params_per_workunit);
    int ignoreCheckpoint = sf->ignoreCheckpoint;
    for(ap.currentWU = 0; ap.currentWU < ap.totalWUs; ap.currentWU++)
    {

        if (sf->numArgs && setParameters(&ap, &bgp, &streams, &(sf->numArgs[ap.params_per_workunit * ap.currentWU]), ap.params_per_workunit))
        {
            mwFreeA(ias);
            freeStreams(&streams);
            return 1;
        }

        rc = setAstronomyParameters(&ap, &bgp);
        if (rc)
        {
            mwFreeA(ias);
            freeStreams(&streams);
            return 1;
        }

        setExpStreamWeights(&ap, &streams);
        sc = getStreamConstants(&ap, &streams);
        if (!sc)
        {
            mw_printf("Failed to get stream constants\n");
            mwFreeA(ias);
            freeStreams(&streams);
            return 1;
        }

        results = newSeparationResults(ap.number_streams);
        int currentWU = ap.currentWU;
        rc = evaluate(results, &ap, ias, &streams, sc, sf->LikelihoodToText, sf->star_points_file,
                  &clr, sf->do_separation, &ignoreCheckpoint, sf->separation_outfile);
        if (rc)
            mw_printf("Failed to calculate likelihood\n");
    }
    
    mwFreeA(ias);
    mwFreeA(sc);
    freeStreams(&streams);
    if(results) freeSeparationResults(results);

    return rc;
}
static void freeCut(Cut* i)
{
    mwFreeA(i->streamIntegrals);
}
void freeStreamGauss(StreamGauss sg)
{
    mwFreeA(sg.dx);
    mwFreeA(sg.qgaus_W);
}
void freeRunSizes(RunSizes* sizes)
{
    mwFreeA(sizes->chunkBorders);
}