/* ASCEND modelling environment Copyright (C) 2006 Carnegie Mellon University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *//** @file black box semantics test. *//* by Ben Allan Created: July 4, 2006 Version: $Revision: 1.5 $ Date last modified: $Date: 1997/07/18 12:20:07 $ */ #include #include #include #include #include /* next 4 needed only because we use RealAtomValue on the DATA instance. */ #include #include #include /* #define BBOXTEST_DEBUG */ ExtBBoxInitFunc bboxtest_preslv; ExtBBoxFunc bboxtest_fex; ExtBBoxFunc bboxtest_jex; ExtBBoxFinalFunc bboxtest_final; #define N_INPUT_ARGS 1 /* formal arg count */ #define N_OUTPUT_ARGS 1 /* formal arg count */ extern ASC_EXPORT int bboxtest_register(void){ double epsilon = 1.0e-14; char bboxtest_help[] = "This tests a simple black box y=k*x." " The value 'k' is provided to the blackbox as a data argument."; return CreateUserFunctionBlackBox("bboxtest" ,&bboxtest_preslv ,&bboxtest_fex, &bboxtest_jex ,NULL, &bboxtest_final ,N_INPUT_ARGS, N_OUTPUT_ARGS ,bboxtest_help ,epsilon ); } /*------------------------------------------------------------------------------ forward decls */ struct BBOXTEST_problem { double coef; /* coef in y=coef*x*/ int n; /* number of inputs passed to this bbox? */ }; static int GetCoef( struct Instance *data, struct BBOXTEST_problem *problem); static int CheckArgsOK(struct Instance *data ,struct gl_list_t *arglist, struct BBOXTEST_problem *problem ); static int DoCalculation(struct BBoxInterp *interp ,int ninputs, int noutputs ,double *inputs, double *outputs ); int DoDeriv(struct BBoxInterp *interp, int ninputs, double *jacobian); #ifndef EXTERNAL_EPSILON #define EXTERNAL_EPSILON 1.0e-12 #endif /*----------------------------------------------------------------------------*/ /** This function is one of the registered functions. It operates in mode 'last_call'. In 'last_call' mode, the memory associated with the problem is released. */ void bboxtest_final(struct BBoxInterp *interp){ struct BBOXTEST_problem *problem; if(interp->task != bb_last_call){ ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unexpected call to last_call fn"); return; } if(interp->user_data != NULL) { problem = (struct BBOXTEST_problem *)interp->user_data; problem->coef *= -1; problem->n *= -1; ASC_FREE(problem); interp->user_data = NULL; } } /** This function is one of the registered functions. It operates in mode first_call. It creates a BBOXTEST_problem and calls a number of routines to check the arguments (data and arglist) and to cache the information processed away in the BBOXTEST_problem structure. In last_call mode, the memory associated with the problem is released. @return 0 on success */ int bboxtest_preslv(struct BBoxInterp *interp, struct Instance *data, struct gl_list_t *arglist ){ struct BBOXTEST_problem *problem; if(interp->task != bb_first_call){ ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unexpected call to first_call fn"); return -1; } if(interp->user_data!=NULL){ #ifdef BBOXTEST_DEBUG CONSOLE_DEBUG("user_data has already been allocated, no need to reallocate"); #endif return 0; } problem = ASC_NEW(struct BBOXTEST_problem); if(CheckArgsOK(data,arglist,problem)){ CONSOLE_DEBUG("Problem with arguments"); ASC_FREE(problem); return -2; } /* store the BBTEST_problem in the user_data pointer */ interp->user_data = (void *)problem; return 0; /* success */ } /*----------------------------------------------------------------------------*/ /** Evaluate residuals @return 0 on success */ int bboxtest_fex(struct BBoxInterp *interp, int ninputs, int noutputs, double *inputs, double *outputs, double *jacobian ){ (void)jacobian; return DoCalculation(interp, ninputs, noutputs, inputs, outputs); } /* Evaluate jacobian @return 0 on success */ int bboxtest_jex(struct BBoxInterp *interp, int ninputs, int noutputs, double *inputs, double *outputs, double *jacobian ){ (void)noutputs; (void)outputs; (void)inputs; return DoDeriv(interp, ninputs, jacobian); } /*------------------------------------------------------------------------------ utility routines */ static int GetCoef( struct Instance *data, struct BBOXTEST_problem *problem){ if(!data){ ERROR_REPORTER_HERE(ASC_USER_ERROR,"expecting a data instance to be provided"); return 5; } if(InstanceKind(data)!=REAL_CONSTANT_INST) { ERROR_REPORTER_HERE(ASC_USER_ERROR,"expecting a real constant instance."); return 6; } problem->coef = RealAtomValue(data); return 0; } static int CheckArgsOK(struct Instance *data, struct gl_list_t *arglist, struct BBOXTEST_problem *problem ){ unsigned long len,ninputs,noutputs; if (!arglist) { ERROR_REPORTER_HERE(ASC_USER_ERROR,"External function argument list does not exist."); return 1; } len = gl_length(arglist); if (!len) { ERROR_REPORTER_HERE(ASC_USER_ERROR,"No arguments to external function statement."); return 2; } if ((len!=(N_INPUT_ARGS+N_OUTPUT_ARGS))) { ERROR_REPORTER_HERE(ASC_USER_ERROR,"Number of arguments does not match" " the external function" " prototype(array_of_realatom[set],array_of_realatom[set],real_constant" ); return 3; } ninputs = CountNumberOfArgs(arglist,1,N_INPUT_ARGS); noutputs = CountNumberOfArgs(arglist,N_INPUT_ARGS+1, N_INPUT_ARGS+N_OUTPUT_ARGS); if (ninputs != noutputs) { ERROR_REPORTER_HERE(ASC_USER_ERROR,"Length of input, output arguments mismatched."); return 4; } problem->n = (int)ninputs; return GetCoef(data,problem); /* get the coef, return 0 on success means all was ok */ } /* This function provides support to bboxtest_fex which is one of the registered functions. The input variables are x[set] The output variables are y[set]. We do our loop based on the ascend standard that sets are arbitrarily but consistently ordered if they contain the same values. */ static int DoCalculation(struct BBoxInterp *interp, int ninputs, int noutputs, double *inputs, double *outputs ){ struct BBOXTEST_problem *problem; int c; double coef; if(ninputs != noutputs){ ERROR_REPORTER_HERE(ASC_PROG_ERR,"ninputs != noutputs"); return -1; } if(interp->user_data == NULL){ ERROR_REPORTER_HERE(ASC_PROG_ERR,"user_data not supplied"); return -2; } problem = (struct BBOXTEST_problem *)interp->user_data; coef = problem->coef; for (c=0; c < ninputs; c++) { outputs[c] = coef * inputs[c]; } #ifdef BBOXTEST_DEBUG CONSOLE_DEBUG("instance = %p",interp->user_data); for(c=0;cstatus = calc_all_ok; return 0; } int DoDeriv(struct BBoxInterp *interp, int ninputs, double *jacobian){ int i; int len; double coef; if(interp==NULL){ ERROR_REPORTER_HERE(ASC_PROG_ERR,"interp==NULL"); return -1; } if(interp->user_data==NULL){ ERROR_REPORTER_HERE(ASC_PROG_ERR,"interp->user_data==NULL"); return -2; } coef = ((struct BBOXTEST_problem *)interp->user_data)->coef; len = ninputs*ninputs; #ifdef BBOXTEST_DEBUG CONSOLE_DEBUG("instance = %p",interp->user_data); #endif for (i = 0; i< len; i++) { jacobian[i] = 0; } for (i = 0; i< ninputs; i++) { jacobian[i*ninputs+i] = coef; } #ifdef BBOXTEST_DEBUG for(i=0; i