/* sinc.c
********************************************************************************
* sinc.c -- Sinc function objects
*
* User routines:
*	Pro_SincFunc()		creates a sinc function object.
*	Pro_SincInfo()		returns parameters of sinc function.
*
* Mark Showalter, PDS Ring-Moon Systems Node, March 1998
*******************************************************************************/
#include <stdio.h>
#include <math.h>
#include "profile.h"
#include "fortran.h"

#define PI 3.141592653589793238462643

/********************
 * Type definitions *
 ********************/

typedef struct ZPRO_SINC_STRUCT {
    RL_INT4	flag;
    RL_FLT8	height, step, halfwidth, shoulder, scale, threshold,
		shoulder_scale;
} ZPRO_SINC;

/**********************
 * Symbol definitions *
 **********************/

#define ZPRO_SINC_FLAG	'sinc'

/************************************
 * Prototypes of internal functions *
 ************************************/

static RL_FLT8 ZPro_SincCalc  RL_PROTO((RL_FLT8 x, RL_VOID *params));
static void    ZPro_PrintSinc RL_PROTO((RL_VOID *params));

/*
********************************************************************************
* EXPORTED USER ROUTINES
********************************************************************************
*$ Component_name:
*	Pro_SincFunc (sinc.c)
*$ Abstract:
*	This routine generates a sinc function object.  A sinc function returns
*	sin(pi*x)/(pi*x), scaled by an envelope function that goes smoothly to
*	zero outside its domain.
*$ Keywords:
*	PROFILE, FUNCTION, PSF
*	C, PUBLIC, SUBROUTINE
*$ Declarations:
*	PRO_OBJECT	*Pro_SincFunc(height, step, halfwidth, shoulder)
*	RL_FLT8         height, step, halfwidth, shoulder;
*$ Inputs:
*	height		peak y-value of function (at origin).
*	step		x-step between origin/zeroes of function.
*	halfwidth	x-value above which y-value is zero.
*	shoulder	x-width of truncation, modeled as a quarter-sinusoid.
*$ Outputs:
*	none
*$ Returns:
*	pointer to a new sinc function object, or NULL on non-fatal error.
*$ Detailed_description:
*	This routine generates a sinc function object.  A sinc function returns
*	sin(pi*x)/(pi*x), scaled by an envelope function that goes smoothly to
*	zero outside its domain.  The x and y coordinates are initially unnamed.
*
*	The envelope function used is as follows:
*		1		|x| < halfwidth - shoulder
*		0		|x| > halfwidth
*		(1 + cos((|x|-(halfwidth-shoulder)) * pi/shoulder))/2
*				otherwise
*	This particular form has the advantage of being smooth throughout the
*	domain.
*$ External_references:
*	Profile toolkit
*$ Side_effects:
*	Memory is allocated.
*$ Examples:
*	This line of code creates a sinc function with height 2 and with zeros
*	spaced by unity, with a full width of 10 and no shoulder transition
*	region.
*
*	sinc = Pro_SincFunc(2., 1., 5., 0.);
*$ Error_handling:
*	Profile toolkit error handling is in effect.
*
*	Conditions raised:
*	RL_MEMORY_ERROR		on memory allocation error.
*$ Limitations:
*	none
*$ Author_and_institution:
*	Mark R. Showalter
*	NASA/Ames Research Center
*$ Version_and_date:
*	1.0: March 1998
*$ Change_history:
*	none
*******************************************************************************/

PRO_OBJECT	*Pro_SincFunc(height, step, halfwidth, shoulder)
RL_FLT8         height, step, halfwidth, shoulder;
{
ZPRO_SINC	*params;
PRO_OBJECT	*func;
RL_INT4		paramsize;

    paramsize = sizeof(ZPRO_SINC);
    params = (ZPRO_SINC *) XRL_Malloc(paramsize);
    if (params == NULL) return NULL;

    params->flag      = ZPRO_SINC_FLAG;
    params->height    = height;
    params->step      = step;
    params->halfwidth = halfwidth;
    params->shoulder  = shoulder;

    params->scale          = PI / step;
    params->threshold      = halfwidth - shoulder;

    params->shoulder_scale = 0.;
    if (params->shoulder != 0.) params->shoulder_scale = PI / shoulder;

    func = Pro_SoftFunc(ZPro_SincCalc, -halfwidth, halfwidth,
		        (RL_VOID *) params, paramsize, TRUE, ZPro_PrintSinc);
    XRL_Free((RL_VOID *) params);

    return func;
}

/*
********************************************************************************
*$ Component_name:
*	Pro_SincInfo (sinc.c)
*$ Abstract:
*	This routine returns information about a sinc function object.
*$ Keywords:
*	PROFILE, FUNCTION, PSF
*	C, PUBLIC, SUBROUTINE
*$ Declarations:
*	RL_BOOL		Pro_SincInfo(sinc, height, step, halfwidth, shoulder)
*	PRO_OBJECT	*sinc;
*	RL_FLT8         *height, *step, *halfwidth, *shoulder;
*$ Inputs:
*	sinc		pointer to a sinc function object.
*$ Outputs:
*	*height		peak y-value of function (at origin);
*			not returned if height==NULL.
*	*step		x-step between origin/zeroes of function;
*			not returned if height==NULL.
*	*halfwidth	x-value above which y-value is zero;
*			not returned if height==NULL.
*	*shoulder	x-width of truncation, modeled as a half-sinusoid;
*			not returned if height==NULL.
*$ Returns:
*	TRUE if this is a sinc function; FALSE otherwise.
*$ Detailed_description:
*	This routine returns information about a sinc function object.
*$ External_references:
*	Profile toolkit
*$ Side_effects:
*	none
*$ Examples:
*	This snippet of code of code prints the step size in a sinc function.
*
*	PRO_OBJECT	*sinc;
*	RL_FLT8		step;
*
*	Pro_SincInfo(sinc, NULL, &step, NULL, NULL);
*	printf("Step size = %g\n", step);
*$ Error_handling:
*	Profile toolkit error handling is in effect.
*
*	Conditions raised:
*	PRO_CLASS_ERROR		if this is not a software function object.
*$ Limitations:
*	none
*$ Author_and_institution:
*	Mark R. Showalter
*	NASA/Ames Research Center
*$ Version_and_date:
*	1.0: March 1998
*$ Change_history:
*	none
*******************************************************************************/

RL_BOOL		Pro_SincInfo(sinc, height, step, halfwidth, shoulder)
PRO_OBJECT	*sinc;
RL_FLT8         *height, *step, *halfwidth, *shoulder;
{
ZPRO_SINC	*params;

    params = (ZPRO_SINC *) XPro_SoftParams(sinc);
    if (params == NULL) return FALSE;

    if (params->flag != ZPRO_SINC_FLAG) return FALSE;

    if (height    != NULL) *height    = params->height;
    if (step      != NULL) *step      = params->step;
    if (halfwidth != NULL) *halfwidth = params->halfwidth;
    if (shoulder  != NULL) *shoulder  = params->shoulder;

    return TRUE;
}

/*
********************************************************************************
* INTERNAL ROUTINES
********************************************************************************
* ZPro_SincCalc(x, params)
*
* This internal routine calculates the value of a sinc function.
*
* Inputs:
*	x		location at which to evaluate function.
*	params		pointer to the ZPRO_SINC data structure.
*
* Return:		value of function at x.
*******************************************************************************/

static RL_FLT8	ZPro_SincCalc(x, params)
RL_FLT8		x;
RL_VOID		*params;
{
ZPRO_SINC	*sincpar;
RL_FLT8		arg, value;

    sincpar = (ZPRO_SINC *) params;

    /* Handle mathematical singularity at origin */
    if (x == 0.) return sincpar->height;

    /* Evaluate sinc function */
    if (x < 0.) x = -x;
    arg = x * sincpar->scale;
    value = sincpar->height * sin(arg)/arg;

    /* If we're not in shoulder region, return */
    if (x <= sincpar->threshold) return value;

    /* Otherwise, scale by shoulder function and return */
    return value * 0.5 *
	(1. + cos((x - sincpar->threshold) * sincpar->shoulder_scale));
}

/*
********************************************************************************
* ZPro_PrintSinc(params)
*
* This internal routine prints information about a sinc function.
*
* Inputs:
*	params		pointer to the ZPRO_SINC data structure.
*******************************************************************************/

static void	ZPro_PrintSinc(params)
RL_VOID		*params;
{
ZPRO_SINC	*sincpar;

    sincpar = (ZPRO_SINC *) params;

    /* Print sinc object info... */
    printf("\nSinc software function parameters...\n");

    printf("   height = %#g\n", sincpar->height);
    printf("     step = %#g\n", sincpar->step);
    printf("halfwidth = %#g\n", sincpar->halfwidth);
    printf(" shoulder = %#g\n", sincpar->shoulder);
}

/*
********************************************************************************
* FORTRAN INTERFACE ROUTINES
********************************************************************************
*$ Component_name:
*	FPro_SincFunc (sinc.c)
*$ Abstract:
*	This routine generates a sinc function object.  A sinc function returns
*	sin(pi*x)/(pi*x), scaled by an envelope function that goes smoothly to
*	zero outside its domain.
*$ Keywords:
*	PROFILE, FUNCTION, PSF
*	FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
*	integer*4 function FPro_SincFunc(height, step, halfwidth, shoulder)
*	real*8		height, step, halfwidth, shoulder
*$ Inputs:
*	height		peak y-value of function (at origin).
*	step		x-step between origin/zeroes of function.
*	halfwidth	x-value above which y-value is zero.
*	shoulder	x-width of truncation, modeled as a quarter-sinusoid.
*$ Outputs:
*	none
*$ Returns:
*	FORTRAN pointer to a new sinc function object, or 0 on non-fatal error.
*$ Detailed_description:
*	This routine generates a sinc function object.  A sinc function returns
*	sin(pi*x)/(pi*x), scaled by an envelope function that goes smoothly to
*	zero outside its domain.  The x and y coordinates are initially unnamed.
*
*	The envelope function used is as follows:
*		1		|x| < halfwidth - shoulder
*		0		|x| > halfwidth
*		(1 + cos((|x|-(halfwidth-shoulder)) * pi/shoulder))/2
*				otherwise
*	This particular form has the advantage of being smooth throughout the
*	domain.
*$ External_references:
*	Profile toolkit
*$ Side_effects:
*	Memory is allocated.
*$ Examples:
*	This line of code creates a sinc function with height 2 and with zeros
*	spaced by unity, with a full width of 10 and no shoulder transition
*	region.
*
*	sinc = Pro_SincFunc(2.d0, 1.d0, 5.d0, 0.d0)
*$ Error_handling:
*	Profile toolkit error handling is in effect.
*
*	Conditions raised:
*	RL_MEMORY_ERROR		on memory allocation error.
*$ Limitations:
*	none
*$ Author_and_institution:
*	Mark R. Showalter
*	NASA/Ames Research Center
*$ Version_and_date:
*	1.0: March 1998
*$ Change_history:
*	none
*******************************************************************************/

RL_INT4	FORTRAN_NAME(fpro_sincfunc) (height, step, halfwidth, shoulder)
RL_FLT8	*height, *step, *halfwidth, *shoulder;
{
RL_VOID *ptr;
RL_INT4 index;

    ptr = (RL_VOID *) Pro_SincFunc(*height, *step, *halfwidth, *shoulder);
    if (ptr == NULL) return 0;

    index = FORT_AddPointer(ptr);
    if (index == 0) Pro_FreeObject((PRO_OBJECT *) ptr);

    return index;
}

/*
********************************************************************************
*$ Component_name:
*	FPro_SincInfo (sinc.c)
*$ Abstract:
*	This routine returns information about a sinc function object.
*$ Keywords:
*	PROFILE, FUNCTION, PSF
*	FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
*	logical*4 function FPro_SincInfo(sinc, height, step, halfwidth,
*					shoulder)
*	integer*4	sinc
*	real*8		height, step, halfwidth, shoulder
*$ Inputs:
*	sinc		FORTRAN pointer to a sinc function object.
*$ Outputs:
*	height		peak y-value of function (at origin).
*	step		x-step between origin/zeroes of function.
*	halfwidth	x-value above which y-value is zero.
*	shoulder	x-width of truncation, modeled as a half-sinusoid.
*$ Returns:
*	.TRUE. if this is a sinc function; .FALSE. otherwise.
*$ Detailed_description:
*	This routine returns information about a sinc function object.
*$ External_references:
*	Profile toolkit
*$ Side_effects:
*	none
*$ Examples:
*	This snippet of code of code prints the step size in a sinc function.
*
*	integer*4	sinc
*	real*8		height, step, halfwidth, shoulder
*
*	call FPro_SincInfo(sinc, height, step, halfwidth, shoulder)
*	write(*,*) 'Step size = ', step
*$ Error_handling:
*	Profile toolkit error handling is in effect.
*
*	Conditions raised:
*	PRO_CLASS_ERROR		if this is not a software function object.
*	FORTRAN_POINTER_ERROR	if sinc is not a valid FORTRAN object pointer.
*$ Limitations:
*	none
*$ Author_and_institution:
*	Mark R. Showalter
*	NASA/Ames Research Center
*$ Version_and_date:
*	1.0: March 1998
*$ Change_history:
*	none
*******************************************************************************/

RL_INT4	FORTRAN_NAME(fpro_sincinfo) (sinc, height, step, halfwidth, shoulder)
RL_INT4	*sinc;
RL_FLT8	*height, *step, *halfwidth, *shoulder;
{
RL_VOID *ptr;
RL_BOOL	status;

    /* Look up sinc function pointer */
    ptr = FORT_GetPointer(*sinc);
    if (ptr == NULL) return 0;

    /* Return info */
    status = Pro_SincInfo(ptr, height, step, halfwidth, shoulder);
    return status ? FTRUE:FFALSE;
}

/*******************************************************************************
*/