1 /* siminit.c
2 
3    Copyright (c) 1991-2017 Free Software Foundation, Inc.
4 
5    This file is part of GNU MCSim.
6 
7    GNU MCSim is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License
9    as published by the Free Software Foundation; either version 3
10    of the License, or (at your option) any later version.
11 
12    GNU MCSim is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GNU MCSim; if not, see <http://www.gnu.org/licenses/>
19 
20    Contains initialization routines for the simulation
21 */
22 
23 #include <stdlib.h>
24 
25 #include "lexerr.h"
26 #include "modelu.h"
27 #include "random.h"
28 #include "simi.h"
29 #include "siminit.h"
30 
31 
32 /* ----------------------------------------------------------------------------
33    GetModelInfo
34 
35    Gets information about the model that we are using for all of the
36    simulations.
37 */
38 
GetModelInfo(PMODELINFO pmi)39 void GetModelInfo (PMODELINFO pmi)
40 {
41   pmi->nModelVars = (long) GetNModelVars ();
42   pmi->pdModelVars = GetModelVector ();
43 
44   if ((pmi->nStates = (long) GetNStates()) != 0) { /* FB improved 28/07/97 */
45     if (!(pmi->pStateHvar = (HVAR*) malloc (pmi->nStates * sizeof(HVAR))))
46       ReportError(NULL, RE_OUTOFMEM | RE_FATAL, "GetModelInfo", NULL);
47 
48     GetStateHandles (pmi->pStateHvar);
49   }
50   else {
51     pmi->pStateHvar = NULL;
52   }
53 
54 } /* GetModelInfo */
55 
56 
57 /* ----------------------------------------------------------------------------
58    InitIntegratorSpec
59 */
60 
InitIntegratorSpec(PINTSPEC pis)61 void InitIntegratorSpec (PINTSPEC pis)
62 {
63   pis->iAlgo = IAL_DEFAULT;
64 
65   pis->dRtol = RTOL_DEFAULT;
66   pis->dAtol = ATOL_DEFAULT;
67 
68   /* Lsodes specific */
69   pis->iopt  = IOPT_DEFAULT;
70   pis->itask = ITASK_DEFAULT;
71   pis->itol  = ITOL_DEFAULT;
72   pis->iMf   = IMF_DEFAULT;
73   pis->liw   = LSODES_IWORKSIZE;
74   pis->lrw   = LSODES_RWORKSIZE;
75 
76   /* Cvodes specific */
77   pis->maxsteps = MXSTEPS_DEFAULT;
78   pis->maxnef   = MAXNEF_DEFAULT;
79   pis->maxcor   = MAXCOR_DEFAULT;
80   pis->maxncf   = MAXNCF_DEFAULT;
81   pis->nlscoef  = NLSCOEF_DEFAULT;
82 
83   if ( !(pis->iwork = InitlVector (pis->liw)) ||
84        !(pis->rwork = InitdVector (pis->lrw)))
85     ReportError (NULL, RE_OUTOFMEM | RE_FATAL,
86                  "InitIntegratorSpec()", NULL);
87 
88   /* Euler specific */
89   pis->dTStep = TSTEP_DEFAULT;
90 
91 } /* InitIntegratorSpec */
92 
93 
94 /* ----------------------------------------------------------------------------
95    InitOutputSpec
96 */
97 
InitOutputSpec(POUTSPEC pos)98 void InitOutputSpec (POUTSPEC pos)
99 {
100   pos->nOutputs         = 0;
101   pos->pszOutputNames   = NULL;
102   pos->phvar_out        = NULL;
103 
104   pos->nData            = 0;
105   pos->pszDataNames     = NULL;
106   pos->phvar_dat        = NULL;
107 
108   pos->plistPrintRecs   = NULL;    /* List of Print() records read in */
109   pos->plistDataRecs    = NULL;    /* List of Data() records read in */
110 
111   pos->pcOutputTimes    = NULL;    /* Count of output times for each var */
112   pos->piCurrentOut     = NULL;    /* Index to current output for each var */
113   pos->prgdOutputTimes  = NULL;    /* Array of output times for each var */
114   pos->prgdOutputVals   = NULL;    /* Array of output values for each var */
115 
116   pos->pcData           = NULL;
117   pos->prgdDataVals     = NULL;    /* Array of data values for each var */
118 
119   pos->cDistinctTimes   = 0;       /* Init output times list to empty */
120   pos->rgdDistinctTimes = NULL;
121 
122 } /* InitOutputSpec */
123 
124 
125 /* ----------------------------------------------------------------------------
126     InitExperiment
127 
128 */
129 
InitExperiment(PEXPERIMENT pexp,PMODELINFO pmodelinfo)130 void InitExperiment (PEXPERIMENT pexp, PMODELINFO pmodelinfo)
131 {
132   pexp->iExp = 0; /* Number of current experiment */
133   pexp->dT0 = T0_DEFAULT; /* Simulation times */
134   pexp->dTfinal = TFINAL_DEFAULT;
135 
136   pexp->dTime = 0.0; /* Current time, not used for global */
137 
138   pexp->pmodelinfo = pmodelinfo; /* Same model for all experiments */
139   pexp->plistParmMods = InitList(); /* List of parameter modifications */
140 
141   InitIntegratorSpec (&pexp->is);
142   InitOutputSpec (&pexp->os);
143 
144 } /* InitExperiment */
145 
146 
147 /* ----------------------------------------------------------------------------
148    InitMonteCarlo
149 
150 */
151 
InitMonteCarlo(PMONTECARLO pmc)152 void InitMonteCarlo (PMONTECARLO pmc)
153 {
154   pmc->nRuns = NSIMULATIONS_DEFAULT;
155 
156   pmc->szMCOutfilename = NULL;   /* File name for Monte Carlo output */
157   pmc->pfileMCOut = NULL;        /* Output file for Monte Carlo */
158 
159   pmc->szSetPointsFilename = NULL;
160   pmc->pfileSetPoints = NULL;
161 
162   pmc->plistMCVars   = NULL;
163   pmc->rgdParms = NULL;
164   pmc->rghvar = NULL;
165   pmc->rgpMCVar = NULL;
166 
167 } /* InitMonteCarlo */
168 
169 
170 /* ----------------------------------------------------------------------------
171    InitGibbs
172 */
173 
InitGibbs(PGIBBSDATA pgd)174 void InitGibbs (PGIBBSDATA pgd)
175 {
176   pgd->nMaxIter        = NSIMULATIONS_DEFAULT;
177   pgd->nSimTypeFlag    = 0;
178   pgd->nPrintIter      = NSIMULATIONS_DEFAULT;
179   pgd->nPrintFreq      = 1;
180   pgd->nMaxPerkSetIter = 300000;
181 
182   pgd->szGout = NULL;        /* Filename for Gibbs output */
183   pgd->pfileOut = NULL;      /* File for Gibbs output */
184 
185   pgd->szGrestart = NULL;    /* Parm file  for restarting Gibbs */
186   pgd->pfileRestart = NULL;  /* File for Gibbs restart */
187 
188   pgd->szGdata = NULL;       /* Filename for Gibbs input data */
189 
190   /* for tempered MCMC */
191   pgd->nPerks = 0;           /* number of perks (inverse temperatures) */
192   pgd->indexT = 0;           /* start at hot temperature */
193   pgd->dCZero = 100;
194   pgd->dNZero = 100;         /* must be > 0 */
195   pgd->startT = 0;
196   pgd->endT   = 0;
197 
198   pgd->rglTransAttempts = NULL;
199   pgd->rglTransAccepts  = NULL;
200 
201 } /* InitGibbs */
202 
203 
204 /* ----------------------------------------------------------------------------
205    InitAnalysis
206 
207    Initializes an analysis structure and its associated
208    sub-structures for integration, output, experiments, and
209    Monte Carlo.
210 */
211 
InitAnalysis(PANALYSIS panal)212 void InitAnalysis (PANALYSIS panal)
213 {
214   int i;
215 
216   if (!panal) return;
217 
218   /* those will eventually be changed by command-line options */
219   panal->bDependents       = FALSE;
220   panal->bOutputIter       = FALSE;
221   panal->nOutputFreq       = 0;
222   panal->bPrintConvergence = FALSE;
223 
224   panal->iType = AT_DEFAULTSIM; /* Type of analysis, default to simple sim */
225 
226   panal->dSeed = SEED_DEFAULT; /* The random generator seed for everybody */
227 
228   panal->wContext = CN_GLOBAL; /* Begin in global context */
229   panal->pexpCurrent = &panal->expGlobal;
230 
231   GetModelInfo (&panal->modelinfo); /* The model we are using */
232 
233   /* Global experiment settings */
234   InitExperiment (&panal->expGlobal, &panal->modelinfo);
235 
236   panal->szOutfilename      = NULL;
237   panal->pfileOut           = NULL;
238   panal->bCommandLineSpec   = FALSE;
239   panal->bAllocatedFileName = FALSE;
240 
241   /* Init all experiments NULL */
242   panal->iExpts = 0;
243   for (i = 0; i < MAX_INSTANCES; i++) panal->rgpExps[i] = NULL;
244 
245   InitMonteCarlo (&panal->mc); /* Monte Carlo specifications */
246   InitGibbs (&panal->gd); /* Gibbs specifications */
247 
248 } /* InitAnalysis */
249 
250 
251 /* ----------------------------------------------------------------------------
252    InitOutputs
253 
254    Returns TRUE if ok, FALSE otherwise.
255 */
256 
InitOutputs(PEXPERIMENT pexp,PINT piOut,PDOUBLE pdTout)257 BOOL InitOutputs (PEXPERIMENT pexp, PINT piOut, PDOUBLE pdTout)
258 {
259   int j;
260   BOOL bReturn = FALSE;
261 
262   if (!pexp->os.nOutputs)
263     ReportError (NULL, RE_NOOUTPUTS, (PSTR) &pexp->iExp, NULL);
264 
265   else {
266     *piOut = 0; /* Keep track of out times */
267     *pdTout = pexp->os.rgdDistinctTimes[0];
268     for (j = 0; j < pexp->os.nOutputs; j++)
269       pexp->os.piCurrentOut[j] = 0;
270 
271     bReturn = TRUE;
272   } /* else */
273 
274   return (bReturn);
275 
276 } /* InitOutputs */
277 
278 
279 /* ----------------------------------------------------------------------------
280    InitOneOutVar
281 
282    Initializes information for one output to be printed.  Creates space
283    for outputs.
284 */
285 
InitOneOutVar(PVOID pData,PVOID pInfo)286 int InitOneOutVar (PVOID pData, PVOID pInfo)
287 {
288   PPRINTREC ppr = (PPRINTREC) pData;
289   POUTSPEC pos = (POUTSPEC) pInfo;
290   int i = pos->nOutputs++; /* Index of current cell */
291 
292   pos->pszOutputNames[i] = ppr->szOutputName;
293   pos->phvar_out[i]      = ppr->hvar;
294   pos->pcOutputTimes[i]  = ppr->cTimes;
295   pos->piCurrentOut[i]   = 0;
296 
297   pos->prgdOutputTimes[i] = ppr->pdTimes;
298   pos->prgdOutputVals[i]  = InitdVector (ppr->cTimes);
299   if (pos->prgdOutputTimes[i] == NULL || pos->prgdOutputVals[i] == NULL)
300     ReportError (NULL, RE_OUTOFMEM | RE_FATAL, "InitOneOutVar()", NULL);
301 
302   return 0;
303 
304 } /* InitOneOutVar */
305 
306 
307 /* ----------------------------------------------------------------------------
308    InitOneDataVar
309 
310    Initializes information for one data specification.
311 */
312 
InitOneDataVar(PVOID pData,PVOID pInfo)313 int InitOneDataVar (PVOID pData, PVOID pInfo)
314 {
315 
316   PDATAREC pda = (PDATAREC) pData;
317   POUTSPEC pos = (POUTSPEC) pInfo;
318   int i = pos->nData++; /* Index of current cell */
319 
320   pos->prgdDataVals[i] = pda->pdData; /* point to the data read in */
321   pos->pcData[i] = pda->cData;
322   pos->phvar_dat[i] = pda->hvar;
323   pos->pszDataNames[i] = pda->szDataName;
324 
325   return 0;
326 
327 } /* InitOneDataVar */
328 
329 
330 /* ----------------------------------------------------------------------------
331    FindNewPoint
332 
333    Finds the new point.  Return FALSE if the sort is finished, i.e. no
334    new point can be found.
335 */
336 
FindNewPoint(POUTSPEC pos,PINT piPoint)337 BOOL FindNewPoint (POUTSPEC pos, PINT piPoint)
338 {
339   for (*piPoint = 0; *piPoint < pos->nOutputs; (*piPoint)++)
340     if (pos->piCurrentOut[*piPoint] < pos->pcOutputTimes[*piPoint])
341       break;
342 
343   return (*piPoint < pos->nOutputs ? TRUE : FALSE);
344 
345 } /* FindNewPoint */
346 
347 
348 /* ----------------------------------------------------------------------------
349    CreateOutputSchedule
350 
351    Creates a single output time array from the individual times.  This
352    will be used to efficiently schedule the outputs.
353 
354    This routines sorts n sorted arrays into 1 array of undetermined
355    length omitting duplicate entries.
356 
357    The algorithm works as follows.  A counter is kept into each
358    array.  A current test "point" is found as the element of the
359    first array whose counter is not past the end.  Thus, we start
360    with the point at the first element of the first array.
361 
362    Looping through the list of arrays, if another array is found
363    whose counter element is less than the point, then the point is
364    switched to this element.  If no such element is found, the point
365    is added to the new list.  If an array element found which is equal
366    to the point the counter for that array is incremented.
367 
368    The pos->piCurrentOut fields are used for counters.  They are not
369    reset, since InitOutputs() must be called before running the
370    simulation anyway.
371 */
372 
CreateOutputSchedule(POUTSPEC pos)373 void CreateOutputSchedule (POUTSPEC pos)
374 {
375   int i, cTimes = 0, iPoint;
376   BOOL bCont = TRUE;
377 
378   for (i = 0; i < pos->nOutputs; i++) /* Find max size of array */
379     cTimes += pos->pcOutputTimes[i];
380 
381   if ( !(pos->rgdDistinctTimes = InitdVector (cTimes)))
382     ReportError (NULL, RE_OUTOFMEM | RE_FATAL, "CreateOutputSchedule()",NULL);
383 
384   cTimes = 0;
385   FindNewPoint (pos, &iPoint);
386   while (bCont) {
387 
388     for (i = 0; i < pos->nOutputs; i++)
389       if (i != iPoint && pos->piCurrentOut[i] < pos->pcOutputTimes[i]) {
390 
391         if (pos->prgdOutputTimes[i][pos->piCurrentOut[i]]
392             < pos->prgdOutputTimes[iPoint][pos->piCurrentOut[iPoint]])
393           iPoint = i;
394 
395          else if (pos->prgdOutputTimes[i][pos->piCurrentOut[i]]
396                   == pos->prgdOutputTimes[iPoint][pos->piCurrentOut[iPoint]])
397                 pos->piCurrentOut[i]++;
398       } /* if */
399 
400     pos->rgdDistinctTimes[cTimes++] =
401     pos->prgdOutputTimes[iPoint][pos->piCurrentOut[iPoint]];
402 
403     if (++pos->piCurrentOut[iPoint] >= pos->pcOutputTimes[iPoint])
404       bCont = FindNewPoint (pos, &iPoint);
405 
406   } /* while */
407 
408   pos->cDistinctTimes = cTimes; /* Save number of distinct times */
409 
410 } /* CreateOutputSchedule */
411 
412 
413 /* ----------------------------------------------------------------------------
414    PrepareOutSpec
415 
416    Prepares an output spec determined by the plistPrintRecs
417    and plistDataRecs specifications.
418    Adjusts final time eventually to match the last output time
419 */
420 
PrepareOutSpec(PEXPERIMENT pexp)421 BOOL PrepareOutSpec (PEXPERIMENT pexp)
422 {
423   POUTSPEC pos  = &pexp->os;
424   BOOL bReturn = FALSE;
425   int cDat = ListLength(pos->plistDataRecs);
426   int cOut = ListLength(pos->plistPrintRecs);
427 
428   if (!cOut)
429     ReportError (NULL, RE_NOOUTPUTS, (PSTR) &pexp->iExp, NULL);
430   else { /* ok, cOut is not null */
431     pos->pszOutputNames  = (PSTR *) malloc (cOut * sizeof(PSTR));
432     pos->phvar_out       = (HVAR *) malloc (cOut * sizeof(HVAR));
433     pos->pcOutputTimes   = InitiVector (cOut);
434     pos->piCurrentOut    = InitiVector (cOut);
435     pos->prgdOutputTimes = InitpdVector (cOut);
436     pos->prgdOutputVals  = InitpdVector (cOut);
437 
438     if (pos->pszOutputNames  == NULL || pos->phvar_out == NULL    ||
439         pos->pcOutputTimes   == NULL || pos->piCurrentOut == NULL ||
440         pos->prgdOutputTimes == NULL || pos->prgdOutputVals == NULL)
441       ReportError (NULL, RE_OUTOFMEM | RE_FATAL, "PrepareOutSpec()", NULL);
442     else {
443       pos->nOutputs = 0; /* Current cell counter in callback */
444       ForAllList (pos->plistPrintRecs, InitOneOutVar, (PVOID) &pexp->os);
445       pos->nOutputs = cOut; /* Set count of outputs for real */
446 
447       CreateOutputSchedule (pos); /* Create single output time list */
448 
449       /* Adjust the final time to match the last output time */
450       pexp->dTfinal = pos->rgdDistinctTimes[pos->cDistinctTimes - 1];
451 
452       if (pexp->dTfinal == pexp->dT0) {
453         printf ("\nError: starting and final times are equal in Simulation %d "
454                 "- Exiting.\n\n", pexp->iExp);
455         exit(0);
456       }
457 
458       bReturn = TRUE;
459 
460     } /* else */
461   } /* else */
462 
463   if (!cDat)
464     ; /* cDat is null, but it's allowed */
465   else { /* ok, cDat is not null */
466     pos->prgdDataVals = InitpdVector (cDat);
467     pos->pcData       = InitiVector (cDat);
468     pos->pszDataNames = (PSTR *) malloc (cDat * sizeof(PSTR));
469     pos->phvar_dat    = (HVAR *) malloc (cDat * sizeof(HVAR));
470 
471     if (pos->prgdDataVals == NULL || pos->phvar_dat == NULL ||
472         pos->pszDataNames == NULL || pos->pcData    == NULL)
473       ReportError (NULL, RE_OUTOFMEM | RE_FATAL, "PrepareOutSpec()", NULL);
474     else {
475       pos->nData = 0; /* Current cell counter in callback */
476       ForAllList (pos->plistDataRecs, InitOneDataVar, (PVOID) &pexp->os);
477       pos->nData = cDat;  /* Set count of data for real */
478 
479       /* ForAllList(pos->plistDataRecs, &FreeDataRec, NULL); */
480       FreeList (&pos->plistDataRecs, NULL, FALSE);
481     } /* else */
482   } /* else */
483 
484   return (bReturn);
485 
486 } /* PrepareOutSpec */
487 
488 
489 /* ----------------------------------------------------------------------------
490    PrintOutSpec
491 
492 */
493 
PrintOutSpec(PEXPERIMENT pexp)494 BOOL PrintOutSpec (PEXPERIMENT pexp)
495 {
496   POUTSPEC pos = &pexp->os;
497   int j, i, cOut = pos->nOutputs;
498 
499   printf ("%d Outputs:\n", cOut);
500 
501   for (i = 0; i < cOut; i++) {
502     printf ("  %#0lx  %s: ", pos->phvar_out[i], pos->pszOutputNames[i]);
503     for (j = 0; j < pos->pcOutputTimes[i]; j++)
504       printf ("%g ", pos->prgdOutputTimes[i][j]);
505     printf ("\n");
506   }
507 
508   return 0;
509 
510 } /* PrintOutSpec */
511 
512 /* End */
513