• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

ne_sim_cvode.c

00001 /*===========================================================================
00002  NetEvo Foundation Library
00003  Copyright (C) 2009, 2010 Thomas E. Gorochowski <tgorochowski@me.com>
00004  Bristol Centre for Complexity Sciences, University of Bristol, Bristol, UK
00005  ---------------------------------------------------------------------------- 
00006  NetEvo is a computing framework designed to allow researchers to investigate 
00007  evolutionary aspects of dynamical complex networks. By providing tools to 
00008  easily integrate each of these factors in a coherent way, it is hoped a 
00009  greater understanding can be gained of key attributes and features displayed 
00010  by complex systems.
00011  
00012  NetEvo is open-source software released under the Open Source Initiative 
00013  (OSI) approved Non-Profit Open Software License ("Non-Profit OSL") 3.0. 
00014  Detailed information about this licence can be found in the COPYING file 
00015  included as part of the source distribution.
00016  
00017  This library is distributed in the hope that it will be useful, but
00018  WITHOUT ANY WARRANTY; without even the implied warranty of
00019  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020  ============================================================================*/
00021 /*
00022  * EXPERIMENTAL... DO NOT USE.
00023  *
00024  * Simulator of dynamics for ODE models that uses the CVODE (Sundials) suite of
00025  * solvers. This is suitable for both non-stiff and stiff problems, however,
00026  * type should be specified in the parameters when allocating the solver.
00027  */
00028 
00029 
00030 #include "ne_sim_cvode.h"
00031 #include <string.h>
00032 
00033 
00034 #define Ith(v,i)    NV_Ith_S(v,i-1)       /* Ith numbers components 1..NEQ */
00035 #define IJth(A,i,j) DENSE_ELEM(A,i-1,j-1) /* IJth numbers rows,cols 1..NEQ */
00036 
00037 ne_vec_dyn_t * ne_sim_cvode_run (ne_system_t *system, void *params, double length, double *iy, 
00038                                  FILE *file)
00039 {
00040    /* TODO: Handle errors better during initialisation step */
00041    int dimension, flag, i;
00042    double *yCopy;
00043    realtype cvRelTol, cvAbsTol, t, tout;
00044    N_Vector y;
00045    void *cvode_mem;
00046    ne_vec_dyn_t *vecOut;
00047    ne_sim_cvode_params_t *cvodeParams;
00048    
00049    cvodeParams = (ne_sim_cvode_params_t *)params;
00050    y = NULL;
00051    cvode_mem = NULL;
00052    dimension = system->nodes * system->nodeStates;
00053    vecOut = ne_vec_dyn_alloc(dimension + 1);
00054 
00055    /* Create serial vector of length NEQ for I.C. and abstol */
00056    y = N_VNew_Serial(dimension);
00057    if (check_flag((void *)y, "N_VNew_Serial", 0)) return NULL;
00058    
00059    /* Set initial values */
00060    for (i=0; i<dimension; i++) {
00061       NV_Ith_S(y,i) = iy[i];
00062    }
00063       
00064    /* Call CVodeCreate to create the solver memory */
00065    if (cvodeParams->stiff == TRUE) {
00066       cvode_mem = CVodeCreate(CV_BDF, CV_NEWTON);
00067    }
00068    else {
00069       cvode_mem = CVodeCreate(CV_ADAMS, CV_FUNCTIONAL);
00070    }
00071    if (check_flag((void *)cvode_mem, "CVodeCreate", 0)) return NULL;
00072    
00073    /* Call CVodeInit to initialize the integrator memory and specify the
00074     * user's right hand side function in y'=f(t,y), the inital time T0, and
00075     * the initial dependent variable vector y. */
00076    flag = CVodeInit(cvode_mem, ne_sim_cvode_fn, 0.0, y);
00077    if (check_flag(&flag, "CVodeInit", 1)) return NULL;
00078    
00079    /* TODO: Allow for absTol to be specified as an array */
00080    /* Call CVodeSVtolerances to specify the scalar relative tolerance
00081     * and vector absolute tolerances */
00082    cvRelTol = (realtype)cvodeParams->relTol;
00083    cvAbsTol = (realtype)cvodeParams->absTol;
00084    flag = CVodeSStolerances(cvode_mem, cvRelTol, cvAbsTol);
00085    if (check_flag(&flag, "CVodeSStolerances", 1)) return NULL;
00086    
00087    /* Call CVDense to specify the CVDENSE dense linear solver */
00088    flag = CVDense(cvode_mem, dimension);
00089    if (check_flag(&flag, "CVDense", 1)) return NULL;
00090    
00091    tout = 0.0;
00092    do {
00093       if (flag == CV_SUCCESS) {
00094          tout += cvodeParams->step;
00095          if (tout > length) {
00096             tout = length;
00097          }
00098       }
00099       
00100       /* Run the solver to the next time step */
00101       flag = CVode(cvode_mem, tout, y, &t, CV_NORMAL);
00102       
00103       /* Make a copy of the results and append to the output vector */
00104       yCopy = (double*)malloc((sizeof(double)*dimension)+1);
00105       yCopy[0] = t;
00106       for (i=0; i<dimension; i++) {
00107          yCopy[i+1] = NV_Ith_S(y,i);
00108       }
00109       ne_vec_dyn_append_item(vecOut, yCopy);
00110       
00111       if (check_flag(&flag, "CVode", 1)) break;
00112       
00113    } while (tout < length);
00114    
00115    /* Free y */
00116    N_VDestroy_Serial(y);
00117    
00118    /* Free integrator memory */
00119    CVodeFree(&cvode_mem);
00120    
00121    return vecOut;
00122 }
00123 
00124 
00125 int ne_sim_cvode_fn (realtype t, N_Vector y, N_Vector ydot, void *params)
00126 {
00127    /* Function to calculate: ydot_i = F(x_i) + sum_{j \in E} G(x_i, x_j) */
00128    
00129    ne_int_t states, i, j, k;
00130    ne_system_t *system;
00131    double *ydotNew, *ydotCum;
00132    
00133    system = (ne_system_t *)params;
00134    states = ne_system_node_states(system);
00135    
00136    ydotNew = (double *)malloc(sizeof(double) * states);
00137    ydotCum = (double *)malloc(sizeof(double) * states);
00138    
00139    /* Calculate the node dynamics F(x) */
00140    for (i=0; i<system->nodes; i++) {
00141       (ne_system_dyn_node(system, i)->fn)(i, system, (double)t, 
00142                                           (double *)&NV_Ith_S(y, i*states), 
00143                                           (double *)&NV_Ith_S(ydot, i*states), 
00144                                           ne_system_dyn_node_params(system, i));
00145    }
00146    
00147    /* Calculate the edge dynamics G(x) */
00148    if (ne_system_node_param(system, i, NE_NODE_PARAM_EDGE_INT_TYPE) == NE_INT_SUM) {
00149       
00150       /* Sum along edges (NE_INT_SUM) */
00151       for (i=0; i<system->nodes; i++) {
00152          memset(ydotCum, 0, sizeof(double)*states);
00153          for (j=0; j<system->nodes; j++) {
00154             if (ne_system_edge_exists(system, i, j) == TRUE) {
00155                memset(ydotNew, 0, sizeof(double)*states);
00156                (ne_system_dyn_edge(system, i, j)->fn)(i, j, system, (double)t, 
00157                                                       (double *)NV_DATA_S(y), 
00158                                                       ydotNew, 
00159                                                       ne_system_dyn_edge_params(system, i, j));
00160                /* Keep track of the cumulative value */
00161                for (k=0; k<states; k++) {
00162                   ydotCum[k] += ydotNew[k];
00163                }
00164             }
00165          }
00166          /* Update the actual node values */
00167          for (k=0; k<states; k++) {
00168             NV_Ith_S(ydot, (i*states)+k) += ydotCum[k];
00169          }
00170       }
00171    }
00172    else if (ne_system_node_param(system, i, NE_NODE_PARAM_EDGE_INT_TYPE) == NE_INT_MUT) {
00173       
00174       /* Sum along edges (NE_INT_MUT) */
00175       for (i=0; i<system->nodes; i++) {
00176          memset(ydotCum, 1, sizeof(double)*states);
00177          for (j=0; j<system->nodes; j++) {
00178             if (ne_system_edge_exists(system, i, j) == TRUE) {
00179                memset(ydotNew, 0, sizeof(double)*states);
00180                (ne_system_dyn_edge(system, i, j)->fn)(i, j, system, (double)t, 
00181                                                       (double *)NV_DATA_S(y), 
00182                                                       ydotNew, 
00183                                                       ne_system_dyn_edge_params(system, i, j));
00184                /* Keep track of the cumulative value */
00185                for (k=0; k<states; k++) {
00186                   ydotCum[k] *= ydotNew[k];
00187                }
00188             }
00189          }
00190          /* Update the actual node values */
00191          for (k=0; k<states; k++) {
00192             NV_Ith_S(ydot, (i*states)+k) += ydotCum[k];
00193          }
00194       }
00195    }
00196    
00197    free(ydotNew);
00198    free(ydotCum);
00199    
00200    return 0;
00201 }
00202 
00203 
00204 
00205 /* 
00206  * Get and print some final statistics
00207  */
00208 /*
00209 static void PrintFinalStats(void *cvode_mem)
00210 {
00211    long int nst, nfe, nsetups, nje, nfeLS, nni, ncfn, netf, nge;
00212    int flag;
00213    
00214    flag = CVodeGetNumSteps(cvode_mem, &nst);
00215    check_flag(&flag, "CVodeGetNumSteps", 1);
00216    flag = CVodeGetNumRhsEvals(cvode_mem, &nfe);
00217    check_flag(&flag, "CVodeGetNumRhsEvals", 1);
00218    flag = CVodeGetNumLinSolvSetups(cvode_mem, &nsetups);
00219    check_flag(&flag, "CVodeGetNumLinSolvSetups", 1);
00220    flag = CVodeGetNumErrTestFails(cvode_mem, &netf);
00221    check_flag(&flag, "CVodeGetNumErrTestFails", 1);
00222    flag = CVodeGetNumNonlinSolvIters(cvode_mem, &nni);
00223    check_flag(&flag, "CVodeGetNumNonlinSolvIters", 1);
00224    flag = CVodeGetNumNonlinSolvConvFails(cvode_mem, &ncfn);
00225    check_flag(&flag, "CVodeGetNumNonlinSolvConvFails", 1);
00226    
00227    flag = CVDlsGetNumJacEvals(cvode_mem, &nje);
00228    check_flag(&flag, "CVDlsGetNumJacEvals", 1);
00229    flag = CVDlsGetNumRhsEvals(cvode_mem, &nfeLS);
00230    check_flag(&flag, "CVDlsGetNumRhsEvals", 1);
00231    
00232    flag = CVodeGetNumGEvals(cvode_mem, &nge);
00233    check_flag(&flag, "CVodeGetNumGEvals", 1);
00234    
00235    printf("\nFinal Statistics:\n");
00236    printf("nst = %-6ld nfe  = %-6ld nsetups = %-6ld nfeLS = %-6ld nje = %ld\n",
00237          nst, nfe, nsetups, nfeLS, nje);
00238    printf("nni = %-6ld ncfn = %-6ld netf = %-6ld nge = %ld\n \n",
00239          nni, ncfn, netf, nge);
00240 }
00241 */
00242 
00243 
00244 /*
00245  * Check function return value...
00246  *   opt == 0 means SUNDIALS function allocates memory so check if
00247  *            returned NULL pointer
00248  *   opt == 1 means SUNDIALS function returns a flag so check if
00249  *            flag >= 0
00250  *   opt == 2 means function allocates memory so check if returned
00251  *            NULL pointer 
00252  */
00253 
00254 static int check_flag(void *flagvalue, char *funcname, int opt)
00255 {
00256    int *errflag;
00257    
00258    /* Check if SUNDIALS function returned NULL pointer - no memory allocated */
00259    if (opt == 0 && flagvalue == NULL) {
00260       fprintf(stderr, "\nSUNDIALS_ERROR: %s() failed - returned NULL pointer\n\n",
00261             funcname);
00262       return(1); }
00263    
00264    /* Check if flag < 0 */
00265    else if (opt == 1) {
00266       errflag = (int *) flagvalue;
00267       if (*errflag < 0) {
00268          fprintf(stderr, "\nSUNDIALS_ERROR: %s() failed with flag = %d\n\n",
00269                funcname, *errflag);
00270          return(1); }}
00271    
00272    /* Check if function returned NULL pointer - no memory allocated */
00273    else if (opt == 2 && flagvalue == NULL) {
00274       fprintf(stderr, "\nMEMORY_ERROR: %s() failed - returned NULL pointer\n\n",
00275             funcname);
00276       return(1); }
00277    
00278    return(0);
00279 }
00280 
00281 
00282 

Generated on Thu Aug 26 2010 11:04:24 for NetEvo by  doxygen 1.7.1