/* function.c ********************************************************************************
* function.c -- routines for generic function objects
*
* User routines:
* Pro_FuncValue(func,x) returns the value of a function at x.
* Pro_WindowFunc(func,x1,x2) creates a new function that duplicates
* another but over a new domain (x1,x2).
*
* Programmer routines:
* XPro_MakeFunc() used to create a new function object.
* XPro_FuncPtr() returns a pointer to the sub-object.
*
* Version 1.0: Original release.
* Mark Showalter & Neil Heather, PDS Ring-Moon Systems Node, March 1998.
* Version 1.1: QUICK compilation mode added.
* Mark Showalter, October 1999.
* Version 1.2: Corrected potential memory management error.
* Mark Showalter, September 2002.
*******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "profile.h"
#include "fortran.h"
/*************************
* Data type definitions *
*************************/
typedef struct ZPRO_FUNCTION_STRUCT {
XPRO_CLASS class;
RL_FLT8 x1, x2;
RL_FLT8 (*evalfunc) RL_PROTO((RL_VOID *pointer, RL_FLT8 x));
void (*freefunc) RL_PROTO((RL_VOID *pointer));
void (*printfunc) RL_PROTO((RL_VOID *pointer));
RL_BOOL is_windowed;
} ZPRO_FUNCTION;
/************************************
* Prototypes of internal functions *
************************************/
static void ZPro_FreeFunc RL_PROTO((RL_VOID * func));
static void ZPro_PrintFunc RL_PROTO((RL_VOID * pointer));
static ZPRO_FUNCTION *ZPro_GetFunc RL_PROTO((PRO_OBJECT * object));
/********************
* Static variables *
********************/
static RL_CHAR ZPRO_BLANK = '\0';
static XPRO_CLASS func_class = {XPRO_FUNCTION_CLASS, "function", NULL};
/*********************
* Macro definitions *
*********************/
#ifdef QUICK
#define ZPro_GetFunc(object) ((ZPRO_FUNCTION *) XPro_ObjectPtr(object))
#endif
/*
********************************************************************************
* EXPORTED USER ROUTINES
********************************************************************************
*$ Component_name:
* Pro_FuncValue (function.c)
*$ Abstract:
* This routine evaluates and returns the value of a function.
*$ Keywords:
* PROFILE, FUNCTION
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* RL_FLT8 Pro_FuncValue(object, x)
* PRO_OBJECT *object;
* RL_FLT8 x;
*$ Inputs:
* object pointer to the function object.
* x argument at which to evaluate function.
*$ Outputs:
* none
*$ Returns:
* value of function.
*$ Detailed_description:
* This routine evaluates and returns the value of a function.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* Suppose square is a function that returns x squared between -3. and 3.
*
* Then Pro_FuncValue(square, 2.) returns 4.;
* Pro_FuncValue(square, 3.) returns 9.;
* Pro_FuncValue(square, 4.) raises PRO_DOMAIN_ERROR and returns 9.
*$ Error_handling:
* Profile library error handling is in effect.
*
* Conditions raised:
* PRO_CLASS_ERROR if the object is NULL or not a function.
* PRO_DOMAIN_ERROR if x is outside the function domain.
* PRO_EVALUATION_FAILURE if function could not be evaluated.
*
* On a non-fatal PRO_DOMAIN_ERROR the value at the nearest endpoint is
* returned; on other non-fatal errors, 0. is returned.
*$ Limitations:
* none
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
* 1.1: October 1999
*$ Change_history:
* 1.1: QUICK mode compile option added.
*******************************************************************************/
RL_FLT8 Pro_FuncValue(object, x)
PRO_OBJECT *object;
RL_FLT8 x;
{
ZPRO_FUNCTION *func;
RL_FLT8 value;
func = ZPro_GetFunc(object);
#ifndef QUICK
if (func == NULL) return 0.;
#endif
/* Make sure x is inside domain */
if (x < func->x1 || x > func->x2) {
XPro_DomainError("x value", object, func->x1, func->x2, x);
if (x < func->x1) x = func->x1;
else x = func->x2;
}
/* Evaluate function */
value = (func->evalfunc) (func->class.pointer, x);
return value;
}
/*
********************************************************************************
*$ Component_name:
* Pro_WindowFunc (function.c)
*$ Abstract:
* This routine generates a new function object with a narrower domain than
* the original function.
*$ Keywords:
* PROFILE, FUNCTION
* C, PUBLIC, SUBROUTINE
*$ Declarations:
* PRO_OBJECT *Pro_WindowFunc(object, x1, x2)
* PRO_OBJECT *object;
* RL_FLT8 x1, x2;
*$ Inputs:
* object pointer to the function object.
* x1, x2 new lower and upper limits of domain (inclusive).
*$ Outputs:
* none
*$ Returns:
* pointer to a new function object, or NULL on non-fatal error.
*$ Detailed_description:
* This routine generates a new function object with a narrower domain than
* the original function.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* Memory is allocated. The new function object creates a link to the old.
*$ Examples:
* Suppose square is a function that returns x squared between -3. and 3.
*
* Then Pro_WindowFunc(square, -1., 5.) creates a fuction that returns x
* squared between -1. and 3.
*$ Error_handling:
* Profile library error handling is in effect.
*
* Conditions raised:
* PRO_CLASS_ERROR if the object is NULL or not a function.
* PRO_EMPTY_DOMAIN if the windowed function would have an empty
* domain.
* 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_WindowFunc(object, x1, x2)
PRO_OBJECT *object;
RL_FLT8 x1, x2;
{
ZPRO_FUNCTION *func;
PRO_OBJECT *new;
RL_FLT8 x1a, x2a;
func = ZPro_GetFunc(object);
if (func == NULL) return NULL;
/* Determine new domain */
x1a = x1;
x2a = x2;
if (x1a < func->x1) x1a = func->x1;
if (x2a > func->x2) x2a = func->x2;
/* Make sure domain is not empty */
if (x1a >= x2a) {
XPro_EmptyDomain("windowed function", object, NULL,
func->x1, func->x2, x1, x2);
return NULL;
}
/* Duplicate function object */
new = XPro_MakeFunc(x1a, x2a, func->evalfunc, func->freefunc,
func->printfunc, func->class.pointer);
/* Enslave original object and check for allocation errors */
if (new != NULL && XPro_EnslaveObject(new, object)) {
Pro_FreeObject(new);
new = NULL;
}
/* Transfer coordinate names to new object */
Pro_RenameObject(new, 1, Pro_ObjectName(object,1));
Pro_RenameObject(new, 2, Pro_ObjectName(object,2));
/* Mark function as windowed */
func = ZPro_GetFunc(new);
func->is_windowed = TRUE;
return new;
}
/*
********************************************************************************
* EXPORTED PROGRAMMER ROUTINES
********************************************************************************
* XPro_MakeFunc(x1, x2, evalfunc, freefunc, printfunc, pointer)
*
* This routine creates and initializes a function object.
*
* Inputs:
* x1, x2 domain limits.
* evalfunc routine to evaluate function.
* freefunc routine to free data structure.
* printfunc routine to print contents of data structure.
* pointer pointer to an arbitrary data structure describing the
* function.
*
* Returns: new function object.
*
* Errors:
* RL_MEMORY_ERROR on memory allocation error.
*******************************************************************************/
PRO_OBJECT *XPro_MakeFunc(x1, x2, evalfunc, freefunc, printfunc, pointer)
RL_FLT8 x1, x2;
RL_FLT8 (*evalfunc) RL_PROTO((RL_VOID *pointer, RL_FLT8 x));
void (*freefunc) RL_PROTO((RL_VOID *pointer));
void (*printfunc) RL_PROTO((RL_VOID *pointer));
RL_VOID *pointer;
{
ZPRO_FUNCTION *func;
PRO_OBJECT *new;
/* Allocate new function structure */
func = (ZPRO_FUNCTION *) XRL_Malloc(sizeof(ZPRO_FUNCTION));
if (func == NULL) return NULL;
/* Initialize structure */
func->class = func_class;
func->class.pointer = pointer;
func->x1 = x1;
func->x2 = x2;
func->evalfunc = evalfunc;
func->freefunc = freefunc;
func->printfunc = printfunc;
func->is_windowed = FALSE;
/* Create new object */
new = XPro_MakeObject(x1, x2, ZPro_FreeFunc, ZPro_PrintFunc, func);
return new;
}
/*
********************************************************************************
* XPro_FuncPtr(object)
*
* This routine returns a pointer to the function sub-object.
*
* Inputs:
* object function object.
*
* Return: pointer field of the object; NULL on error.
*
* Errors:
* PRO_CLASS_ERROR if the object is NULL or not a function.
****************************************************************************/
#ifndef QUICK /* In QUICK mode, this is defined as a macro in profile.h */
RL_VOID *XPro_FuncPtr(object)
PRO_OBJECT *object;
{
ZPRO_FUNCTION *func;
func = ZPro_GetFunc(object);
if (func == NULL) return NULL;
if (func->class.pointer == NULL)
XPro_NullError("function sub-object", object);
return func->class.pointer;
}
#endif
/*
********************************************************************************
* INTERNAL ROUTINES
********************************************************************************
* ZPro_FreeFunc(pointer)
*
* This internal routine deallocates the memory used by a generic function
* object. It is called by Pro_FreeObject().
*
* Input:
* pointer pointer to the ZPRO_FUNCTION structure.
*******************************************************************************/
static void ZPro_FreeFunc(pointer)
RL_VOID *pointer;
{
ZPRO_FUNCTION *func;
func = (ZPRO_FUNCTION *) pointer;
if (func == NULL) return;
if (func->class.pointer != NULL && !func->is_windowed)
(func->freefunc) (func->class.pointer);
XRL_Free(func);
}
/*
********************************************************************************
* ZPro_PrintFunc(pointer)
*
* This internal routine prints out information about a function. It is called
* by Pro_PrintObject() and is used mainly for debugging.
*
* Input:
* pointer pointer to the ZPRO_FUNCTION structure.
*******************************************************************************/
static void ZPro_PrintFunc(pointer)
RL_VOID *pointer;
{
ZPRO_FUNCTION *func;
func = (ZPRO_FUNCTION *) pointer;
/* Make sure object is not NULL */
if (func == NULL) {
printf("PRINT ERROR: Function pointer is NULL\n");
return;
}
/* Make sure object is a function */
if (func->class.id != XPRO_FUNCTION_CLASS) {
printf("PRINT ERROR: Object is not a function\n");
return;
}
/* Print object info... */
if (func->is_windowed) printf("\nDomain has been windowed\n");
(func->printfunc)(func->class.pointer);
}
/*
********************************************************************************
* ZPro_GetFunc(object)
*
* This internal routine returns a pointer to the object's ZPRO_FUNCTION data
* structure.
*
* Input:
* object function object.
*
* Return: pointer to ZPRO_FUNCTION structure, or NULL on error.
*
* Errors:
* PRO_CLASS_ERROR if object is NULL or not a function.
*******************************************************************************/
#ifndef QUICK /* In QUICK mode, this is defined as a macro above */
static ZPRO_FUNCTION *ZPro_GetFunc(object)
PRO_OBJECT *object;
{
ZPRO_FUNCTION *func;
/* Find function object pointer */
func = (ZPRO_FUNCTION *) XPro_ObjectPtr(object);
/* Make sure object is not NULL */
if (func == NULL) {
XPro_NullError("function", object);
return NULL;
}
/* Make sure object is a function */
if (func->class.id != XPRO_FUNCTION_CLASS) {
XPro_ClassError("function", object);
return NULL;
}
return func;
}
#endif
/*
********************************************************************************
* FORTRAN INTERFACE ROUTINES
********************************************************************************
*$ Component_name:
* FPro_FuncValue (function.c)
*$ Abstract:
* This routine evaluates and returns the value of a function.
*$ Keywords:
* PROFILE, FUNCTION
* FUNCTION, PUBLIC, SUBROUTINE
*$ Declarations:
* real*8 function Pro_FuncValue(object, x)
* integer*4 object
* real*8 x
*$ Inputs:
* object FORTRAN pointer to the function object.
* x argument at which to evaluate function.
*$ Outputs:
* none
*$ Returns:
* value of function.
*$ Detailed_description:
* This routine evaluates and returns the value of a function.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* none
*$ Examples:
* Suppose square is a function that returns x squared between -3.d0 and
* 3.d0.
*
* Then FPro_FuncValue(square, 2.d0) returns 4.d0;
* FPro_FuncValue(square, 3.d0) returns 9.d0;
* FPro_FuncValue(square, 4.d0) raises PRO_DOMAIN_ERROR, returns 9.d0.
*$ Error_handling:
* Profile library error handling is in effect.
*
* Conditions raised:
* PRO_CLASS_ERROR if the object is NULL or not a function.
* PRO_DOMAIN_ERROR if x is outside the function domain.
* PRO_EVALUATION_FAILURE if function could not be evaluated.
* FORTRAN_POINTER_ERROR if object is not a valid FORTRAN object pointer.
*
* On a non-fatal PRO_DOMAIN_ERROR the value at the nearest endpoint is
* returned; on other non-fatal errors, 0. is returned.
*$ Limitations:
* none
*$ Author_and_institution:
* Mark R. Showalter
* NASA/Ames Research Center
*$ Version_and_date:
* 1.0: March 1998
* 1.1: October 1999
*$ Change_history:
* 1.1: QUICK mode compile option added.
*******************************************************************************/
RL_FLT8 FORTRAN_NAME(fpro_funcvalue) (object, x)
RL_INT4 *object;
RL_FLT8 *x;
{
RL_VOID *ptr;
/* Look up function pointer */
ptr = FORT_GetPointer(*object);
#ifndef QUICK
if (ptr == NULL) return 0.;
#endif
/* Call function */
return Pro_FuncValue((PRO_OBJECT *) ptr, *x);
}
/*
********************************************************************************
*$ Component_name:
* FPro_WindowFunc (function.c)
*$ Abstract:
* This routine generates a new function object with a narrower domain than
* the original function.
*$ Keywords:
* PROFILE, FUNCTION
* FORTRAN, PUBLIC, SUBROUTINE
*$ Declarations:
* integer*4 function FPro_WindowFunc(object, x1, x2)
* integer*4 object
* real*8 x1, x2
*$ Inputs:
* object FORTRAN pointer to the function object.
* x1, x2 new lower and upper limits of domain (inclusive).
*$ Outputs:
* none
*$ Returns:
* FORTRAN pointer to a new function object, or 0 on non-fatal error.
*$ Detailed_description:
* This routine generates a new function object with a narrower domain than
* the original function.
*$ External_references:
* Profile toolkit
*$ Side_effects:
* Memory is allocated. The new function object creates a link to the old.
*$ Examples:
* Suppose square is a function that returns x squared between -3.d0 and
* 3.d0.
*
* Then FPro_WindowFunc(square, -1.d0, 5.d0) creates a fuction that returns
* x squared between -1.d0 and 3.d0.
*$ Error_handling:
* Profile library error handling is in effect.
*
* Conditions raised:
* PRO_CLASS_ERROR if the object is NULL or not a function.
* PRO_EMPTY_DOMAIN if the windowed function would have an empty
* domain.
* RL_MEMORY_ERROR on memory allocation error.
* FORTRAN_POINTER_ERROR if object 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_windowfunc) (object, x1, x2)
RL_INT4 *object;
RL_FLT8 *x1, *x2;
{
RL_VOID *ptr1, *ptr2;
RL_INT4 index;
/* Look up function pointer */
ptr1 = FORT_GetPointer(*object);
if (ptr1 == NULL) return 0;
/* Call function */
ptr2 = (RL_VOID *) Pro_WindowFunc((PRO_OBJECT *) ptr1, *x1, *x2);
if (ptr2 == NULL) return 0;
/* Save new pointer */
index = FORT_AddPointer(ptr2);
if (index == 0) Pro_FreeObject((PRO_OBJECT *) ptr2);
return index;
}
/*******************************************************************************
*/