/** @file  pmModelUtils.c
 *
 *  Functions to manipulate object models
 *
 *  @author EAM, IfA
 *
 *  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
 *  @date $Date: 2007-12-15 01:22:11 $
 *
 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <pslib.h>
#include "pmHDU.h"
#include "pmFPA.h"
#include "pmResiduals.h"
#include "pmGrowthCurve.h"
#include "pmTrend2D.h"
#include "pmPSF.h"
#include "pmModel.h"
#include "pmErrorCodes.h"
#include "pmModelUtils.h"

/*****************************************************************************
pmModelFromPSF (*modelEXT, *psf):  use the model position parameters to
construct a realization of the PSF model at the object coordinates
 *****************************************************************************/
pmModel *pmModelFromPSF (pmModel *modelEXT, const pmPSF *psf)
{
    PS_ASSERT_PTR_NON_NULL(psf, NULL);
    PS_ASSERT_PTR_NON_NULL(modelEXT, NULL);

    // allocate a new pmModel to hold the PSF version
    pmModel *modelPSF = pmModelAlloc (psf->type);

    // set model parameters for this source based on PSF information
    if (!modelEXT->modelFromPSF (modelPSF, modelEXT, psf)) {
        psError(PM_ERR_PSF, false, "Failed to set model params from PSF");
        psFree(modelPSF);
        return NULL;
    }
    // XXX note that model->residuals is just a reference
    modelPSF->residuals = psf->residuals;

    return (modelPSF);
}

// instantiate a model for the PSF at this location with peak flux
// NOTE: psf and (Xo,Yo) are defined wrt chip coordinates
pmModel *pmModelFromPSFforXY (const pmPSF *psf, float Xo, float Yo, float Io)
{
    PS_ASSERT_PTR_NON_NULL(psf, NULL);

    // allocate a new pmModel to hold the PSF version
    pmModel *modelPSF = pmModelAlloc (psf->type);

    // set model parameters for this source based on PSF information
    if (!modelPSF->modelParamsFromPSF (modelPSF, psf, Xo, Yo, Io)) {
        psError(PM_ERR_PSF, false, "Failed to set model params from PSF");
        psFree(modelPSF);
        return NULL;
    }

    // XXX note that model->residuals is just a reference
    modelPSF->residuals = psf->residuals;

    return (modelPSF);
}

// set this model to have the requested flux
bool pmModelSetFlux (pmModel *model, float flux) {
    PS_ASSERT_PTR_NON_NULL(model, NULL);
    PS_ASSERT_PTR_NON_NULL(model->params, NULL);

    // set Io to be 1.0
    model->params->data.F32[PM_PAR_I0] = 1.0;

    // determine the normalized flux
    float normFlux = model->modelFlux (model->params);
    assert (isfinite(normFlux));
    assert (normFlux > 0);

    // set the desired normalization
    model->params->data.F32[PM_PAR_I0] = flux / normFlux;

    return true;
}
