Corrected some strings for tension_model_utils.
[sawsim.git] / src / sawsim.nw
1 %%%%%%%%%%%%%%%%%%%%%%%%% Start LaTeX boilerplate %%%%%%%%%%%%%%%%%%%%%%%%%%%
2 % we have our own preamble, 
3 % use `noweave -delay` to not print noweb's automatic one
4 % -*- mode: Noweb; noweb-code-mode: c-mode -*-
5 \documentclass[letterpaper, 11pt]{article}
6 \usepackage{noweb}
7 \pagestyle{noweb}
8 \noweboptions{smallcode}
9
10 \usepackage{url}    % needed for natbib for underscores in urls?
11 \usepackage[breaklinks,colorlinks]{hyperref} % for internal links, \phantomsection
12 % breaklinks breaks long links
13 % colorlinks colors link text instead of boxing it
14 \usepackage{amsmath}  % for \text{}, \xrightarrow[sub]{super}
15 \usepackage{amsthm}  % for theorem and proof environments
16 \newtheorem{theorem}{Theorem}
17
18 \usepackage{doc}    % BibTeX
19 \usepackage[super,sort&compress]{natbib} % fancy citation extensions
20 % super selects citations in superscript mode
21 % sort&compress automatically sorts and compresses compound citations (\cite{a,b,...})
22
23 \usepackage[mathletters]{ucs} % use math fonts to allow Greek UTF-8 in the text
24 \usepackage[utf8x]{inputenc}  % allow UTF-8 characters
25
26 %\bibliographystyle{ieeetr} % pick the bibliography style, short and sweet
27 %\bibliographystyle{plain} % pick the bibliography style, includes dates
28 \bibliographystyle{plainnat}
29 \defcitealias{sw:noweb}{{\tt noweb}}
30 \defcitealias{galassi05}{GSL}
31 \defcitealias{sw:check}{{\tt check}}
32 \defcitealias{sw:python}{Python}
33
34 \topmargin -1.0in
35 \headheight 0.5in
36 \headsep 0.5in
37 \textheight 9.5in % leave a bit of extra room for page numbers (at top of page)
38 \oddsidemargin -0.5in
39 \textwidth 7.5in
40 \setlength{\parindent}{0pt}
41 \setlength{\parskip}{5pt}
42
43 % For some reason, the \maketitle wants to go on it's own page
44 % so we'll just hardcode the following in our first page.
45 %\title{Sawsim: a sawtooth protein unfolding simulator}
46 %\author{W.~Trevor King}
47 %\date{\today}
48
49 \newcommand{\prog}{[[sawsim]]}
50 \newcommand{\lang}{[[C]]}
51 \newcommand{\p}[3]{\left#1 #2 \right#3}   % e.g. \p({complicated expr})
52 \newcommand{\Th}{\ensuremath{\sup{\text{th}}}}   % ordinal th
53 \newcommand{\U}[1]{\ensuremath{\text{ #1}}}      % units: $1\U{m/s}$
54
55 % single spaced lists, from Alvin Alexander
56 % http://www.devdaily.com/blog/post/latex/control-line-spacing-in-itemize-enumerate-tags/
57 \newenvironment{packed_item}{
58 \begin{itemize}
59   \setlength{\itemsep}{1pt}
60   \setlength{\parskip}{0pt}
61   \setlength{\parsep}{0pt}
62 }{\end{itemize}}
63
64 \begin{document}
65 \nwfilename{sawsim.nw}
66 \nwbegindocs{0}
67
68 %\maketitle
69 \begin{centering}
70   Sawsim: a sawtooth protein unfolding simulator \\
71   W.~Trevor King \\
72   \today \\
73 \end{centering}
74 \bigskip
75 %%%%%%%%%%%%%%%%%%%%%%%%%%%% End LaTeX boilerplate %%%%%%%%%%%%%%%%%%%%%%%%%%%%
76
77 \section{Introduction}
78
79 The unfolding of multi-globular protein strings is a stochastic
80 process.  In the \prog\ program, we use Monte Carlo methods to
81 simulate this unfolding through an explicit time-stepping approach.
82 We develop a program in \lang\ to simulate probability of unfolding
83 under a constant extension velocity of a chain of globular domains.
84
85 In order to extract physical meaning from many mechanical unfolding
86 simulations, it is necessary to compare the experimental results
87 against the results of simulations using different models and
88 parameters.  The model and parameters that best match the experimental
89 data provide the ‘best’ model for that experiment.
90
91 Previous mechanical unfolding studies have rolled their own
92 simulations for modelling their experiment, and there has been little
93 exchange and standardization of these simulations between groups.
94 The \prog\ program attempts to fill this gap, providing a flexible,
95 extensible, \emph{community} program, to make it easier for groups
96 to share the burden and increase the transparency of data analysis.
97
98 ‘Sawsim’ is blend of ‘sawtooth simulation’.
99
100 \subsection{Related work}
101
102 TODO References
103
104 \subsection{About this document}
105
106 This document was written in \citetalias{sw:noweb} with code blocks in
107 \lang\ and comment blocks in \LaTeX.
108
109 \subsection{System Requirements and Dependencies}
110
111
112 \subsection{Change Log}
113
114 Version 0.0 used only the unfolded domain WLC to determine the tension
115 and had a fixed timestep $dt$.
116
117 Version 0.1 added adaptive timesteps, adjusting so that the unfolding
118 probability for a given domain was constant.
119
120 Version 0.2 added Kramers' model unfolding rate calculations, and a
121 switch to select Bell's or Kramers' model.  This induced a major
122 rewrite, introducing the tension group abstraction, and a split to
123 multiple \lang\ source files.  Also added a unit-test suites for
124 sanity checking, and switched to SI units throughout.
125
126 Version 0.3 added integrated Kramers' model unfolding rate
127 calculations.  Also replaced some of my hand-coded routines with GNU
128 Scientific Library \citepalias{galassi05} calls.
129
130 Version 0.4 added Python evaluation for the saddle-point Kramers'
131 model unfolding rate calculations, so that the model functions could
132 be controlled from the command line.  Also added interpolating lookup
133 tables to accelerate slow unfolding rate model evaluation, and command
134 line control of tension groups.
135
136 <<version definition>>=
137 #define VERSION "0.4"
138
139
140 \subsection{License}
141
142 <<license>>=
143  sawsim - program for simulating single molecule mechanical unfolding.
144  Copyright (C) 2008, William Trevor King
145
146  This program is free software; you can redistribute it and/or
147  modify it under the terms of the GNU General Public License as
148  published by the Free Software Foundation; either version 3 of the
149  License, or (at your option) any later version.
150
151  This program is distributed in the hope that it will be useful, but
152  WITHOUT ANY WARRANTY; without even the implied warranty of
153  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
154  See the GNU General Public License for more details.
155
156  You should have received a copy of the GNU General Public License
157  along with this program; if not, write to the Free Software
158  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
159  02111-1307, USA.
160
161  The author may be contacted at <wking@drexel.edu> on the Internet, or
162  write to Trevor King, Drexel University, Physics Dept., 3141 Chestnut St.,
163  Philadelphia PA 19104, USA.
164
165
166 <<license comment>>=
167 /*
168  <<license>>
169  */
170
171
172
173 \section{Main}
174
175 The unfolding system is stored as a chain of \emph{domains}.  Domains
176 can be folded, globular protein domains, unfolded protein linkers, AFM
177 cantilevers, or other stretchable system components.
178
179 Each domain contributes to the total tension, which depends on the
180 chain extension.  The particular model for the tension as a function
181 of extension is handled generally with function pointers.  So far the
182 following models have been implemented:
183 \begin{packed_item}
184  \item  Null (Appendix \ref{sec.null_tension}),
185  \item  Constant (Appendix \ref{sec.const_tension}),
186  \item  Hookean spring (Appendix \ref{sec.hooke}),
187  \item  Worm-like chain (WLC, Appendix \ref{sec.wlc}), and
188  \item  Freely-jointed chain (FJC, Appendix \ref{sec.fjc}).
189 \end{packed_item}
190
191 The tension model and parameters used for a particular domain depend
192 on whether the domain is folded or unfolded.  The transition rate from
193 the folded state to the unfolded state is also handled generally with
194 function pointers, with implementations for
195 \begin{packed_item}
196  \item  Null (Appendix \ref{sec.null_k}),
197  \item  Bell's model (Appendix \ref{sec.bell}),
198  \item  Kramers' integral model (Appendix \ref{sec.kramers_integ}), and
199  \item  Kramers' saddle point model (Appendix \ref{sec.kramers}).
200 \end{packed_item}
201
202 The unfolding of the chain domains is modeled in two stages.  First
203 the tension of the chain is calculated.  Then the tension (assumed to
204 be constant over the length of the chain), is applied to each folded
205 domain, and used to calculate the probability of that subdomain
206 unfolding in the next timestep $dt$.  Then the time is stepped
207 forward, and the process is repeated.
208
209 <<main program>>=
210 int main(int argc, char **argv)
211 {
212   <<tension model getopt array definition>>
213   <<k model getopt array definition>>
214   list_t *domain_list=NULL;    /* variables initialized in get_options() */
215   environment_t env={0};
216   double P, dt_max, v, xstep;
217   int num_folded=0, unfolding;
218   double x=0, dt, F;           /* variables used in the simulation loop */
219   get_options(argc, argv, &P, &dt_max, &v, &xstep, &env, NUM_TENSION_MODELS,
220             tension_models, NUM_K_MODELS, k_models, &domain_list, &num_folded);
221   setup();
222   if (flags & FLAG_OUTPUT_FULL_CURVE) printf("#Position (m)\tForce (N)\n");
223   if (flags & FLAG_OUTPUT_UNFOLDING_FORCES) printf("#Unfolding Force (N)\n");
224   while (num_folded > 0) {
225     F = find_tension(NUM_TENSION_MODELS, tension_handlers, domain_list, &env, x, unfolding);
226     if (xstep == 0)
227       dt = determine_dt(NUM_TENSION_MODELS, tension_handlers, domain_list, &env, x, P, dt_max, v);
228     else
229       dt = determine_dt(NUM_TENSION_MODELS, tension_handlers, domain_list, &env, x, P, dt_max, 0);
230     unfolding=random_unfoldings(domain_list, F, dt, &env, &num_folded);
231     if (flags & FLAG_OUTPUT_FULL_CURVE) printf("%g\t%g\n", x, F);
232     if (xstep == 0) {
233       x += v*dt;
234     } else {
235       if (dt == dt_max) { /* step completed */
236         x += xstep;
237         dt_max = xstep / v;
238       } else { /* still working on this step */
239         dt_max -= dt;
240       }
241     }
242   }
243   destroy_domain_list(domain_list);
244   free_accels();
245   return 0;
246 }
247 @ The meat of the simulation is bundled into the three functions
248 [[find_tension]], [[determine_dt]], and [[random_unfoldings]].
249 [[find_tension]] is discussed in Section \ref{sec.find_tension},
250 [[determine_dt]] in Section \ref{sec.adaptive_dt}, and
251 [[random_unfoldings]] in Section \ref{sec.unfolding_rate}.
252
253 The stretched distance is extended in one of two modes depending on
254 [[xstep]].  If [[xstep == 0]], then the pulling is continuous, at
255 least within the limits of the inherent discretization of a time
256 stepped approach.  At any rate, the timestep is limited by the maximum
257 allowed timestep [[dt_max]] and the maximum allowed unfolding
258 probability in a given step [[P]].  In the second mode [[xstep > 0]],
259 and the end to end distance increases in discrete steps of that
260 length.  The time between steps is chosen to maintain an average
261 unfolding velocity [[v]].  This approach is less work to simulate than
262 smooth pulling and also closer to the reality of many experiments, but
263 it is practically impossible to treat analytically.  With both pulling
264 styles implemented, the effects of the discretization can be easily
265 calculated, bridging the gap between theory and experiment.
266
267 Environmental parameters important in determining reaction rates and
268 tensions (e.g. temperature, pH) are stored in a single structure to
269 facilitate extension to more complicated models in the future.
270 <<environment definition>>= 
271 typedef struct environment_struct {
272   double T;
273 } environment_t;
274
275
276 <<global.h>>=
277 #ifndef GLOBAL_H
278 #define GLOBAL_H
279 <<environment definition>>
280 <<one dimensional function definition>>
281 <<create/destroy definitions>>
282 <<model globals>>
283 #endif /* GLOBAL_H */
284
285 Where the [[GLOBAL_H]] defines are protecting [[global.h]] from being
286 included multiple times.
287
288 \section{Simulation functions}
289
290 <<simulation functions>>=
291 <<find tension>>
292 <<determine dt>>
293 <<happens>>
294 <<does domain unfold>>
295 <<randomly unfold domains>>
296
297
298 \subsection{Tension}
299 \label{sec.find_tension}
300
301 Because the stretched system may be made up of several parts (folded
302 domains, unfolded domains, spring-like cantilever, \ldots), we will
303 assign the domains to models and groups.  The models are used to
304 determine a domain's tension (Hookean spring, WLC, \ldots).  Groups
305 will represent collections of domains which the model should treat as
306 a single entity.  A domain may belong to different groups or models
307 depending on its state.  For example, a domain might be modeled as a
308 freely-jointed chain when it is folded and as a worm-like chain when
309 it is unfolded.  The domains are assumed to be commutative, so
310 ordering is ignored.  The interactions between the groups are assumed
311 to be linear, but the interactions between domains of the same group
312 need not be.  This allows for non-linear group models such as th
313 worm-like or freely-jointed chains.  Each model has a tension handler
314 function, which gives the tension $F$ needed to stretch a given group
315 of domains a distance $x$.
316
317 To understand the purpose of groups, consider a chain of proteins
318 where two folded proteins $A$ and $B$ are modeled as WLCs with
319 persistence length $p_f$ and two unfolded proteins $C$ and $D$ are
320 modeled as WLCs with persistence length $p_u$.  The proteins are
321 attached to a cantilever $E$ qof spring constant $κ$.  The string
322 would get split into three lists:
323 \begin{center}
324   \begin{tabular}{llll}
325     Model & Group &    List & Tension \\
326     WLC   &     0 & $[A,B]$ & $F_\text{WLC}(x, p_f, L_A+L_B)$ \\
327     WLC   &     1 & $[C,D]$ & $F_\text{WLC}(x, p_u, L_C+L_D)$ \\
328     Hooke &     0 & $[E]$   & $F_\text{Hooke}(x, κ)$ \\
329   \end{tabular}
330 \end{center}
331 Note that group numbers only matter \emph{within} model classes, since
332 grouping domains with seperate models doesn't make sense.
333
334 <<find tension definitions>>=
335 #define NUM_TENSION_MODELS 5
336
337
338
339 <<tension handler array global declaration>>=
340 extern one_dim_fn_t *tension_handlers[];
341 @
342
343 <<tension handler array global>>= 
344 one_dim_fn_t *tension_handlers[] = {
345               NULL,
346               &const_tension_handler,
347               &hooke_handler,
348               &wlc_handler,
349               &fjc_handler,
350               };
351
352
353
354 <<tension model global declarations>>=
355 <<tension handler array global declaration>>
356
357
358 <<tension handler types>>=
359 typedef struct tension_handler_data_struct {
360   /* int            num_domains; */
361   /* domain_t      *domains;     */
362   list_t        *group;
363   environment_t *env;
364   void          *persist;
365 } tension_handler_data_t;
366
367
368
369 After sorting the chain into separate groups $G_i$, with tension
370 handlers $F_i(G_i; x_i)$, we need to balance the extension $x_i$ of
371 each group to get a consistent tension $F_i(x_i) = F_j(x_j) \;\;
372 \forall i,j$.  Note that there may be several groups within each model
373 class.  [[find_tension]] is basically a wrapper to feed proper input
374 into the [[tension_balance]] function.  [[unfolding]] should be set to
375 0 if there were no unfoldings since the previous call to
376 [[find_tension]].
377 <<find tension>>=
378 double find_tension(int num_tension_handlers, one_dim_fn_t **tension_handlers, list_t *domain_list, environment_t *env, double x, int unfolding)
379 {
380   static int num_active_groups=0;
381   static one_dim_fn_t **per_group_handlers = NULL;
382   static void **per_group_params = NULL;
383   static double last_x;
384   tension_handler_data_t *tdata;
385   double F;
386   int i;
387
388 #ifdef DEBUG
389   fprintf(stderr, "finding tension at distance %g%s\n", x, unfolding ? " after an unfolding" : "");
390   list_print(stderr, domain_list, "domain list");
391 #endif
392
393   if (unfolding != 0 || num_active_groups == 0) { /* setup statics */  
394     /* free old statics */
395     if (per_group_handlers != NULL)
396       free(per_group_handlers);
397     if (per_group_params != NULL) {
398       for (i=0; i < num_active_groups; i++) {
399         assert(per_group_params[i] != NULL);
400         free(per_group_params[i]);
401       }
402       free(per_group_params);
403     }
404
405     /* get new statics */
406     get_active_groups(domain_list, num_tension_handlers, tension_handlers, &num_active_groups, &per_group_handlers, &per_group_params);
407
408     /* fill in the group handlers and params */
409     for (i=0; i<num_active_groups; i++) {
410       tdata = (tension_handler_data_t *) per_group_params[i];
411 #ifdef DEBUG
412       fprintf(stderr, "active group %d of %d", i, num_active_groups);
413       list_print(stderr, tdata->group, " parameters");
414 #endif
415       tdata->env = env;
416       /* tdata->persist continues unchanged */
417     }
418     last_x = -1.0;
419   } /* else roll with the current statics */
420
421   F = tension_balance(num_active_groups, per_group_handlers, (void **)per_group_params, last_x, x);
422   last_x = x;
423   return F;
424 }
425 @ For the moment, we will restrict our group boundaries to a single
426 dimension, so $\sum_i x_i = x$, our total extension (it is this
427 restriction that causes the groups to interact linearly).  We'll also
428 restrict our extensions to all be positive.  With these restrictions,
429 the problem of balancing the tensions reduces to solving a system of
430 $N+1$ possibly non-linear equations with $N$ unknowns, where $N$ is
431 the number of active groups.  In general this can be fairly
432 complicated, but without much loss of practicality we can restrict
433 ourselves to strictly monotonically increasing, non-negative tension
434 functions $F_i(x)$, with $F_i(0)=0$, which makes the situation much
435 simpler.  For example, it guarantees the existence of a unique, real
436 solution for finite forces.  See Appendix \ref{app.tension_balance}
437 for the tension balancing implementation.
438
439 Each group must define a parameter structure if the tension model is
440 parametrized,
441  a function to create the parameter structure,
442  a function to destroy the parameter structure, and
443  a tension function of type [[one_dim_fn_t]] that receives a [[tension_handler_data_t *]] as it's data argument.
444 The tension-specific parameter structures are contained in the domain
445 group field.  See the Section \ref{app.model_selection} for a
446 discussion on the command line framework.  See the worm-like chain
447 implementation for an example (Section \ref{sec.wlc}).
448
449 The major limitation of our approach is that all of our tension models
450 are Markovian (memory-less), which is not really a problem for the
451 chains (see \citet{evans99} for WLC thermalization rate calculations).
452
453 \subsection{Unfolding rate}
454 \label{sec.unfolding_rate}
455
456 Each folded domain is modeled as unimolecular, first order reaction
457 $$
458   \text{Folded} \xrightarrow{k}  % in tex: X atop Y
459   \text{Unfolded}
460 $$
461 With the rate constant $k$ defined by
462 $$
463   \frac{d[\text{Folded}]}{dt} = -k [\text{Folded}].
464 $$
465 So the probability of a given protein unfolding in a short time $dt$
466 is given by
467 $$
468   P = k \cdot dt.
469 $$
470
471 <<does domain unfold>>=
472 int domain_unfolds(double F, double dt, environment_t *env, domain_t *domain)
473 { /* returns 1 or 0, F in N, dt in s, pointer to env. data, pointer to a folded domain */
474   double k;
475   k = accel_k(domain->k, F, env, domain->k_params);
476   //(*domain->k)(F, env, domain->k_params);
477   //printf("k = %g,\tdt = %g,\tk dt = %g\n", k, dt, k*dt);
478   return happens(k*dt); /* dice roll for prob. k*dt event */
479 }
480 @ [[happens]] is a random decision making function defined in Appendix \ref{app.utils}.
481
482 Only one domain can unfold in each timestep, because the timescale of
483 a domain unfolding $dt_u$ is assumed to be less than the simulation
484 timestep $dt$, so a domain will completely unfold in a single
485 timestep.  We adapt our timesteps to keep the probability of a single
486 domain unfolding low, so the probability of two domains unfolding in
487 the same timestep is negligible.  This approach breaks down as the
488 adaptive timestep scheme approaches $dt \sim dt_u$, but $dt_u \sim
489 1\U{$\mu$s}$ for Ig27-like proteins \citep{klimov00}, so this
490 shouldn't be a problem.  To reassure yourself, you can ask the
491 simulator to print the smallest timestep that was used with TODO.
492 <<randomly unfold domains>>=
493 int random_unfoldings(list_t *domain_list, double tension, 
494                       double dt, environment_t *env,
495                       int *num_folded_domains)
496 { /* returns 1 if there was an unfolding and 0 otherwise */
497   while (domain_list != NULL) {
498     if (D(domain_list)->state == DS_FOLDED 
499         && domain_unfolds(tension, dt, env, D(domain_list))) {
500       if (flags & FLAG_OUTPUT_UNFOLDING_FORCES)
501         fprintf(stdout, "%g\n", tension);
502       D(domain_list)->state = DS_UNFOLDED;
503       (*num_folded_domains)--;
504       return 1; /* our one domain has unfolded, stop looking for others */
505     }
506     domain_list = domain_list->next;
507   }
508   return 0;
509 }
510
511
512 \subsection{Adaptive timesteps}
513 \label{sec.adaptive_dt}
514
515 We'd like to pick $dt$ so the probability of unfolding in the next
516 timestep is small.  If we don't adapt our timestep, we risk breaking
517 our approximation that $F(x' \in [x, x+v \cdot dt]) = F(x)$ or that
518 only one domain unfolds in a given timestep.  Because $F(x)$ is
519 monotonically increasing, excessively large timesteps will lead to
520 erroneously large unfolding forces.  The simulation would have been
521 accurate for sufficiently small fixed timesteps, but adaptive
522 timesteps will allow us to move through low tension regions in fewer
523 steps, leading to a more efficient simulation.
524
525 The actual adaptive timestep implementation is not particularly
526 interesting, since we are only required to reduce $dt$ to somewhere
527 below a set threshold, so I've removed it to Appendix
528 \ref{app.adaptive_dt}.
529
530 \section{Models}
531  
532 TODO: model intro.
533
534 The models provide the physics of the simulation, but the simulation
535 allows interchangeable models, and we are currently focusing on the
536 simulation itself, so we remove the actual model implementation to the
537 appendices.
538
539 The tension models are defined in Appendix \ref{sec.tension_models}
540 and unfolding models are defined in Appendix \ref{sec.k_models}.
541
542 <<model globals>>=
543 #define k_B   1.3806503e-23  /* J/K */
544
545
546
547 \section{Command line interface}
548
549 <<get option functions>>=
550 <<help>>
551 <<index tension model>>
552 <<index k model>>
553 <<generate domain>>
554 <<get options>>
555
556
557 \subsection{Model selection}
558 \label{app.model_selection}
559
560 The main difficulty with the command line interface in \prog\ is
561 developing an intuitive method for accessing the possibly large number
562 of available models.  We'll treat this generally by defining an array
563 of available models, containing their important parameters.
564
565 <<get options definitions>>=
566 <<model getopt definitions>>
567
568
569 <<create/destroy definitions>>=
570 typedef void *create_data_func_t(char **param_strings);
571 typedef void destroy_data_func_t(void *param_struct);
572
573
574 <<model getopt definitions>>=
575 <<tension model getopt definitions>>
576 <<k model getopt definitions>>
577
578
579
580 \subsubsection{Tension}
581
582 To access the various tension models from the command line, we define
583 a structure that contains all the neccessary information about the
584 model.
585 <<tension model getopt definitions>>=
586 typedef struct tension_model_getopt_struct {
587   one_dim_fn_t      *handler;     /* fn implementing the model on a group */
588   char                *name;        /* name string identifying the model    */
589   char                *description; /* a brief description of the model     */
590   int                  num_params;  /* number of extra params for the model */
591   char               **param_descriptions; /* descriptions of extra params  */
592   char                *params;      /* default values for the extra params  */
593   create_data_func_t  *creator;     /* param-string -> model-data-struct fn */
594   destroy_data_func_t *destructor;  /* fn to free the model data structure  */
595 } tension_model_getopt_t;
596
597
598 <<tension model getopt array definition>>=
599 tension_model_getopt_t tension_models[NUM_TENSION_MODELS] = {
600   <<null tension model getopt>>,
601   <<constant tension model getopt>>,
602   <<hooke tension model getopt>>,
603   <<worm-like chain tension model getopt>>,
604   <<freely-jointed chain tension model getopt>>
605 };
606
607
608 \subsubsection{Unfolding rate}
609
610 <<k model getopt definitions>>=
611 #define NUM_K_MODELS 5
612
613 typedef struct k_model_getopt_struct {
614   char *name;
615   char *description;
616   k_func_t *k;
617   int num_params;
618   char **param_descriptions;
619   char *params;
620   create_data_func_t *creator;
621   destroy_data_func_t *destructor;
622 } k_model_getopt_t;
623
624
625 <<k model getopt array definition>>=
626 k_model_getopt_t k_models[NUM_K_MODELS] = {
627   <<null k model getopt>>,
628   <<const k model getopt>>,
629   <<bell k model getopt>>,
630   <<kramers k model getopt>>,
631   <<kramers integ k model getopt>>
632 };
633
634
635 \subsection{help}
636
637 <<help>>=
638 void help(char *prog_name, double P, double dt_max, double v, double xstep,
639           environment_t *env,
640           int n_tension_models, tension_model_getopt_t *tension_models,
641           int folded_tension_model, int unfolded_tension_model,
642           int n_k_models, k_model_getopt_t *k_models,
643           int k_model)
644 {
645   int i, j;
646   printf("usage: %s [options]\n", prog_name);
647   printf("Version %s\n\n", VERSION);
648   printf("Monte Carlo simulation of a multi-globular domain protein unfolding\n\n");
649   printf("Simulation options:\n");
650   printf("-P P\tTarget probability for dt (currently %g)\n", P);
651   printf("-t dt\tMaximum allowed timestep dt (currently %g)\n", dt_max);
652   printf("-v v\tPulling velocity v (currently %g nm/s)\n", v);
653   printf("-x dx\tPulling step size (currently %g m)\n", xstep);
654   printf("\tWhen dx = 0, the pulling is continuous\n");
655   printf("\tWhen dx > 0, the pulling occurs in discrete steps\n");
656   printf("Environmental options:\n");
657   printf("-T T\tTemperature T (currently %g K)\n", env->T);
658   printf("-C T\tYou can also set the temperature T in Celsius\n");
659   printf("Model options:\n");
660   printf("The domains exist in either the folded or unfolded state\n");
661   printf("The following options change the default behavior in each state.\n");
662   printf("-m model[,group]\tFolded tension model (currently %s)\n",
663          tension_models[folded_tension_model].name);
664   printf("-a args\tFolded tension model argument string (currently %s)\n",
665          tension_models[folded_tension_model].params);
666   printf("-M model[,group]\tUnfolded tension model (currently %s)\n",
667          tension_models[unfolded_tension_model].name);
668   printf("-A args\tUnfolded tension model argument string (currently %s)\n",
669          tension_models[unfolded_tension_model].params);
670   printf("The following options change the unfolding rate.\n");
671   printf("-k model\tTransition rate model (currently %s)\n",
672          k_models[k_model].name);
673   printf("-K args\tTransition rate model argument string (currently %s)\n",
674          k_models[k_model].params);
675   printf("Domain creation options:\n");
676   printf("Once you've set up the appropriate default models, you need to add the domains\n");
677   printf("-F n\tAdd n folded domains with the current models\n");
678   printf("-U n\tAdd n unfolded domains with the current models\n");
679   printf("Output mode options:\n");
680   printf("There are two output modes.  In standard mode, only the unfolding\n");
681   printf("events are printed.  For example:\n");
682   printf("  #Unfolding Force (N)\n");
683   printf("  123.456e-12\n");
684   printf("  ...\n");
685   printf("In verbose mode, the entire Force-vs-distance curve is output:\n");
686   printf("  #Position (m)\tForce (N)\n");
687   printf("  0.001\t0.0023\n");
688   printf("  ...\n");
689   printf("-V\tChange output to verbose mode\n");
690   printf("-h\tPrint this help and exit\n");
691   printf("\n");
692   printf("Tension models:\n");
693   for (i=0; i<n_tension_models; i++) {
694     printf("\t%s\t%s\n", tension_models[i].name, tension_models[i].description);
695     for (j=0; j < tension_models[i].num_params ; j++)
696       printf("\t\t\t%s\n", tension_models[i].param_descriptions[j]);
697     printf("\t\tdefaults: %s\n", tension_models[i].params);
698   }
699   printf("Unfolding rate models:\n");
700   for (i=0; i<n_k_models; i++) {
701     printf("\t%s\t%s\n", k_models[i].name, k_models[i].description);
702     for (j=0; j < k_models[i].num_params ; j++)
703       printf("\t\t\t%s\n", k_models[i].param_descriptions[j]);
704     printf("\t\tdefaults: %s\n", k_models[i].params);
705   }
706   printf("Examples:\n");
707   printf("1 spring and 8 folded domains of titin I27 only stretchable when unfolded\n");
708   printf(" $ %s -v1e-6 -Mhooke -A.05 -U1 -kbell -K3.3e-4,.25e-9 -mnull -Mwlc -A0.39e-9,28e-9 -F8\n", prog_name);
709   printf("1 spring and 8 folded domains of ubiquitin with different WLC parameters when folded or unfolded\n");
710   printf(" $ %s -v1e-6 -Mhooke -A.05 -U1 -kbell -K5e-5,.225e-9 -mwlc -a1e-8,4e-10 -Mwlc,1 -A0.4e-9,28.1e-9 -F8\n", prog_name);
711 }
712
713
714 \subsection{Get options}
715
716 <<get options>>=
717 void get_options(int argc, char **argv,
718                  double *pP, double *pDt_max, double *pV, double *pXstep,
719                  environment_t *env,
720                  int n_tension_models, tension_model_getopt_t *tension_models,
721                  int n_k_models, k_model_getopt_t *k_models,
722                  list_t **pDomain_list, int *pNum_folded)
723 {
724   char *prog_name = NULL;
725   char c, options[] = "P:t:v:x:T:C:m:a:M:A:k:K:F:U:Vh";
726   int ftension_model=0, utension_model=0, k_model=0;
727   char *ftension_params=NULL, *utension_params=NULL;
728   int i, n, ftension_group=0, utension_group=0;
729   int num_strings;
730   char **strings;
731   extern char *optarg;
732   extern int optind, optopt, opterr;
733
734   assert (argc > 0);
735
736 #ifdef DEBUG
737   for (i=0; i<n_tension_models; i++) {
738     fprintf(stderr, "tension model %i %s:\t model's handler %p\n",
739             i, tension_models[i].name, tension_models[i].handler);
740     assert(tension_models[i].handler == tension_handlers[i]);
741   }
742 #endif
743
744   /* setup defaults */
745   flags = FLAG_OUTPUT_UNFOLDING_FORCES;
746   prog_name = argv[0];
747   *pP = 1e-3;       /* % pop per s */
748   *pDt_max = 0.001; /* s           */
749   *pV = 1e-6;       /* m/s         */
750   *pXstep = 0.0;    /* m           */
751   env->T = 300.0;   /* K           */
752
753   while ((c=getopt(argc, argv, options)) != -1) {
754     switch(c) {
755     case 'P':  *pP      = atof(optarg);           break;
756     case 't':  *pDt_max = atof(optarg);           break;
757     case 'v':  *pV      = atof(optarg);           break;
758     case 'x':  *pXstep  = atof(optarg);           break;
759     case 'T':  env->T   = atof(optarg);           break;
760     case 'C':  env->T   = atof(optarg)+273.15;    break;
761     case 'm':
762       parse_list_string(optarg, SEP, '{', '}', &num_strings, &strings);
763       assert(num_strings == 1 || num_strings == 2);
764       if (num_strings == 1)
765         ftension_group = 0;
766       else
767         ftension_group = atoi(strings[1]);
768       ftension_model = index_tension_model(n_tension_models, tension_models, strings[0]);
769       ftension_params = tension_models[ftension_model].params;
770       free_parsed_list(num_strings, strings);
771       break;
772     case 'a':
773       ftension_params = optarg;
774       break;
775     case 'M':
776       parse_list_string(optarg, SEP, '{', '}', &num_strings, &strings);
777       assert(num_strings == 1 || num_strings == 2);
778       if (num_strings == 1)
779         utension_group = 0;
780       else
781         utension_group = atoi(strings[1]);
782       utension_model = index_tension_model(n_tension_models, tension_models, strings[0]);
783       utension_params = tension_models[utension_model].params;
784       free_parsed_list(num_strings, strings);
785       break;
786     case 'A':
787       utension_params = optarg;
788       break;
789     case 'k':
790       k_model = index_k_model(n_k_models, k_models, optarg);
791       break;
792     case 'K':
793       k_models[k_model].params = optarg;
794       break;
795     case 'F':
796       n = atoi(optarg);
797       assert(n > 0);
798       for (i=0; i<n; i++) {
799         push(pDomain_list, generate_domain(DS_FOLDED,
800                                            tension_models+ftension_model,
801                                            ftension_group,
802                                            ftension_params,
803                                            tension_models+utension_model,
804                                            utension_group,
805                                            utension_params,
806                                            k_models+k_model), 1);
807       }
808       *pNum_folded += n;
809       break;
810     case 'U':
811       n = atoi(optarg);
812       assert(n > 0);
813       for (i=0; i<n; i++) {
814         push(pDomain_list, generate_domain(DS_UNFOLDED,
815                                            tension_models+ftension_model,
816                                            ftension_group,
817                                            ftension_params,
818                                            tension_models+utension_model,
819                                            utension_group,
820                                            utension_params,
821                                            k_models+k_model), 1);
822       }
823       break;
824     case 'V':
825       flags = FLAG_OUTPUT_FULL_CURVE;
826       break;
827     case '?':
828       fprintf(stderr, "unrecognized option '%c'\n", optopt);
829       /* fall through to default case */
830     default:
831       help(prog_name, *pP, *pDt_max, *pV, *pXstep, env, n_tension_models, tension_models, ftension_model, utension_model, n_k_models, k_models, k_model);
832       exit(1);
833     }
834   }
835   /* check the arguments */
836   assert(*pDomain_list != NULL); /* no domains! */
837   assert(*pP > 0.0); assert(*pP < 1.0);
838   assert(*pDt_max > 0.0);
839   assert(*pV > 0.0);
840   assert(env->T > 0.0);
841   return;
842 }
843
844
845 <<index tension model>>=
846 int index_tension_model(int n_models, tension_model_getopt_t *models, char *name)
847 {
848   int i;
849   for (i=0; i<n_models; i++)
850     if (STRMATCH(models[i].name, name))
851       break;
852   if (i == n_models) {
853     fprintf(stderr, "Unrecognized tension model '%s'\n", name);
854     exit(1);
855   }
856   return i;
857 }
858
859
860 <<index k model>>=
861 int index_k_model(int n_models, k_model_getopt_t *models, char *name)
862 {
863   int i;
864   for (i=0; i<n_models; i++)
865     if (STRMATCH(models[i].name, name))
866       break;
867   if (i == n_models) {
868     fprintf(stderr, "Unrecognized unfolding rate model '%s'\n", name);
869     exit(1);
870   }
871   return i;
872 }
873
874
875 <<initialize model definition>>=
876 /* requires int num_param_args and char **param_args in the current scope
877  * usage:
878  *  INIT_MODEL("folded", folded_model, folded_param_string, folded_params);
879  * defined as a macro, so it can work on both tension_model_getopt_t and k_model_getopt_t types.
880  */
881 #define INIT_MODEL(role, model, param_string, param_pointer) \
882   do {                                                       \
883     parse_list_string(param_string, SEP, '{', '}',           \
884                       &num_param_args, &param_args);         \
885     if (num_param_args != model->num_params) {               \
886       fprintf(stderr,                                        \
887               "%s model %s expected %d params,\n",           \
888               role, model->name, model->num_params);         \
889       fprintf(stderr,                                        \
890               "not the %d params in '%s'\n",                 \
891               num_param_args, param_string);                 \
892       assert(num_param_args == model->num_params);           \
893     }                                                        \
894     if (model->creator)                                      \
895       param_pointer = (*model->creator)(param_args);         \
896     else                                                     \
897       param_pointer = NULL;                                  \
898     free_parsed_list(num_param_args, param_args);            \
899   } while (0);
900
901
902 <<generate domain>>=
903 void *generate_domain(enum domain_state_t state,
904                       tension_model_getopt_t *folded_model,
905                       int folded_group,
906                       char *folded_param_string,
907                       tension_model_getopt_t *unfolded_model,
908                       int unfolded_group,
909                       char *unfolded_param_string,
910                       k_model_getopt_t *k_model)
911 {
912   void *folded_params, *unfolded_params, *k_params;
913   int num_param_args; /* for INIT_MODEL() */
914   char **param_args;  /* for INIT_MODEL() */
915
916 #ifdef DEBUG
917   fprintf(stderr, "generating %s ", state==DS_FOLDED ? "folded" : "unfolded");
918   fprintf(stderr, "domain (k: \"%s\", \"%s\", f: \"%s\" (%p) group %d \"%s\", u: \"%s\" (%p) group %d \"%s\")\n",
919           k_model->name, k_model->params,
920           folded_model->name, folded_model->handler, folded_group, folded_param_string,
921           unfolded_model->name, unfolded_model->handler, unfolded_group, unfolded_param_string);
922 #endif
923   INIT_MODEL("folded", folded_model, folded_param_string, folded_params);
924   INIT_MODEL("unfolded", unfolded_model, unfolded_param_string, unfolded_params);
925   INIT_MODEL("k", k_model, k_model->params, k_params);
926   return create_domain(state,
927                        k_model->k, k_params, k_model->destructor,
928                        folded_model->handler, folded_group, folded_params, folded_model->destructor,
929                        unfolded_model->handler, unfolded_group, unfolded_params, unfolded_model->destructor
930                        );
931 }
932
933
934 \phantomsection
935 \appendix
936 \addcontentsline{toc}{section}{Appendicies}
937
938 \section{sawsim.c details}
939
940 \subsection{Layout}
941
942 The general layout of our simulation code is:
943 <<*>>=
944 <<license comment>>
945 <<includes>>
946 <<definitions>>
947 <<globals>>
948 <<functions>>
949 <<main program>>
950
951
952 We include [[math.h]], so don't forget to link to the libm with `-lm'.
953 <<includes>>=
954 #include <assert.h> /* assert()                                */
955 #include <stdlib.h> /* malloc(), free(), rand()                */
956 #include <stdio.h>  /* fprintf(), stdout                       */
957 #include <string.h> /* strlen, strtok()                        */
958 #include <math.h>   /* exp(), M_PI, sqrt()                     */
959 #include <sys/types.h> /* pid_t (returned by getpid())         */
960 #include <unistd.h> /* getpid() (for seeding rand()), getopt() */
961 #include "global.h"
962 #include "list.h"
963 #include "tension_balance.h"
964 #include "k_model.h"
965 #include "tension_model.h"
966 #include "parse.h"
967 #include "accel_k.h"
968
969
970 <<definitions>>=
971 <<version definition>>
972 <<flag definitions>>
973 <<max/min definitions>>
974 <<string comparison definition and globals>>
975 <<initialize model definition>>
976 <<get options definitions>>
977 <<domain definitions>>
978
979
980 <<globals>>=
981 <<flag globals>>
982 <<model globals>>
983
984
985 <<functions>>=
986 <<create/destroy domain>>
987 <<destroy domain list>>
988 <<group functions>>
989 <<simulation functions>>
990 <<boilerplate functions>>
991
992
993 <<boilerplate functions>>=
994 <<setup>>
995 <<get option functions>>
996
997
998 <<setup>>=
999 void setup(void)
1000 {
1001   srand(getpid()*time(NULL)); /* seed rand() */
1002 }
1003
1004
1005 <<flag definitions>>=
1006 /* in octal b/c of prefixed '0' */
1007 #define FLAG_OUTPUT_FULL_CURVE       01
1008 #define FLAG_OUTPUT_UNFOLDING_FORCES 02
1009 @
1010
1011 <<flag globals>>=
1012 static unsigned long int flags = 0;
1013 @
1014
1015 \subsection{Utilities}
1016 \label{app.utils}
1017
1018 <<max/min definitions>>=
1019 #define MAX(a,b) ((a)>(b) ? (a) : (b))
1020 #define MIN(a,b) ((a)<(b) ? (a) : (b))
1021
1022
1023 Note that [[STRMATCH]] chokes if one of the strings is [[NULL]].
1024 <<string comparison definition and globals>>=
1025 // Check if two strings match, return 1 if they do
1026 static char *temp_string_A;
1027 static char *temp_string_B;
1028 #define STRMATCH(a,b)   (temp_string_A=a, temp_string_B=b, \
1029         strlen(temp_string_A) != strlen(temp_string_B) ? 0 : \
1030         !strncmp(temp_string_A,temp_string_B,strlen(temp_string_B)+1) )
1031         /* +1 to also compare the '\0' */
1032
1033
1034 We also define a macro for our [[check]] unit testing
1035 <<check relative error>>=
1036 #define CHECK_ERR(max_err, expected, received)                               \
1037   do {                                                                       \
1038     fail_unless( (received-expected)/expected < max_err,                     \
1039                  "relative error %g >= %g in %s (Expected %g, received %g)", \
1040                  (received-expected)/expected, max_err, #received,           \
1041                  expected, received);                                        \
1042     fail_unless(-(received-expected)/expected < max_err,                     \
1043                  "relative error %g >= %g in %s (Expected %g, received %g)", \
1044                 -(received-expected)/expected, max_err, #received,           \
1045                  expected, received);                                        \
1046   } while(0)
1047
1048
1049 <<happens>>=
1050 int happens(double probability)
1051 {
1052   assert(probability >= 0.0); assert(probability <= 1.0);
1053   return (double)rand()/RAND_MAX < probability; /* TODO: replace with GSL rand http://www.gnu.org/software/gsl/manual/html_node/Random-number-generator-algorithms.html x*/
1054 }
1055 @
1056
1057
1058 \subsection{Adaptive timesteps}
1059 \label{app.adaptive_dt}
1060
1061 $F(x)$ increases with $x$, possibly exploding, as in the worm-like chain model,
1062 so basing the timestep on the the unfolding probability at the current tension
1063 is dangerous, and we need to search for a $dt$ for which
1064 $P(F(x+v*dt)) < P_\text{target}$.
1065 There are two cases to consider.
1066 In the most common, no domains have unfolded since the last step,
1067 and we expect the next step to be slightly shorter than the previous one.
1068 In the less common, domains did unfold in the last step,
1069 and we expect the next step to be considerably longer than the previous one.
1070 <<search dt>>=
1071 double search_dt(int num_tension_handlers, one_dim_fn_t **tension_handlers,
1072                  list_t *domain_list, 
1073                  environment_t *env, double x,
1074                  double target_prob, double max_dt, double v)
1075 { /* Returns the timestep dt in seconds for the current folded domain.
1076    * Takes a list of tension handlers, the list of domains,
1077    * a pointer env to the environmental data, a starting separation x in m,
1078    * a target_prob between 0 and 1,
1079    * max_dt in s, stretching velocity v in m/s.
1080    */
1081   double F, k, dtCur, dtU, dtUCur, dtL, dt;
1082
1083   /* get upper bound using the current position */
1084   F = find_tension(num_tension_handlers, tension_handlers, domain_list, env, x, 0); /* BUG. repeated calculation */
1085   //printf("Start with x = %g (F = %g)\n", x, F);
1086   k = accel_k(D(domain_list)->k, F, env, D(domain_list)->k_params);
1087   //printf("x %g\tF %g\tk %g\n", x, F, k);
1088   dtU = target_prob / k;    /* P = k dt, dtU is an upper bound on dt */
1089   if (dtU > max_dt) {
1090     //printf("overshot max_dt\n");  
1091     dtU = max_dt;
1092   }
1093   if (v == 0) /* discrete stepping, so force is temporatily constant */
1094     return dtU;
1095
1096   /* set a lower bound on dt too */
1097   dtL = 0.0;
1098
1099   /* The dt determined above may produce illegitimate forces or ks.
1100    * Reduce the upper bound until we have valid ks. */
1101   dt = dtU;
1102   F = find_tension(num_tension_handlers, tension_handlers, domain_list, env, x+v*dt, 0);
1103   while (F == HUGE_VAL) { /* reduce step until we hit a valid force */
1104     dtU /= 2.0;
1105     dt = dtU;
1106     F = find_tension(num_tension_handlers, tension_handlers, domain_list, env, x+v*dt, 0);
1107   }
1108   //printf("Try for dt = %g (F = %g)\n", dt, F);
1109   k = accel_k(D(domain_list)->k, F, env, D(domain_list)->k_params);
1110   /* returned k may be -1.0 */
1111   //printf("x %g\tF %g\tdt %g\tv dt %g\tk %g\n", x, F, dt, v*dt, k); 
1112   while (k == -1.0) { /* reduce step until we hit a valid k */
1113     dtU /= 2.0;
1114     dt = dtU; /* hopefully, we can use the max dt, see if it works */
1115     F = find_tension(num_tension_handlers, tension_handlers, domain_list, env, x+v*dt, 0);
1116     //printf("Try for dt = %g (F = %g)\n", dt, F);
1117     k = accel_k(D(domain_list)->k, F, env, D(domain_list)->k_params);
1118     //printf("x %g\tF %g\tdt %g\tv dt %g\tk %g\n", x, F, dt, v*dt, k); 
1119   }
1120   assert(dtU > 1e-14);      /* timestep to valid k too small */
1121   dtUCur = target_prob / k; /* safe timestep back from x+dtU */
1122   if (dtUCur >= dt)
1123     return dt; /* dtU is safe. */
1124
1125   /* dtU wasn't safe, lets see what would be. */
1126   while (dtU > 1.1*dtL) { /* until the range is reasonably small */
1127     dt = (dtU + dtL) / 2.0;
1128     F = find_tension(num_tension_handlers, tension_handlers, domain_list, env, x+v*dt, 0);
1129     //printf("Try for dt = %g (F = %g) (dt bounds %g, %g)\n", dt, F, dtL, dtU);
1130     k = accel_k(D(domain_list)->k, F, env, D(domain_list)->k_params);
1131     dtCur = target_prob / k;
1132     //printf("x %g\tF %g\tdt %g\tv dt %g\tk %g\tdtCur = %g\n", x, F, dt, v*dt, k, dtCur);
1133     if (dtCur > dt) /* safe timestep back from x+dt covers dt */
1134       dtL = dt;
1135     else if (dtCur < dt) {  /* unsafe timestep back from x+dt, but...    */
1136       dtU = dt;             /* ... stepping out only dtCur would be safe */ 
1137       dtUCur = dtCur;
1138     } else
1139       break; /* dtCur = dt */
1140   }
1141   return MAX(dtUCur, dtL);
1142 }
1143
1144
1145 To determine $dt$ for an array of potentially different folded domains,
1146 we need to find the maximum $dt$ that satisfies $k dt < P$ for all domains.
1147 <<determine dt>>=
1148 <<search dt>>
1149 double determine_dt(int num_tension_handlers, one_dim_fn_t **tension_handlers, list_t *domain_list,
1150                     environment_t *env, double x,
1151                     double target_prob, double dt_max, double v)
1152 { /* Returns the timestep dt in seconds.
1153    * Takes the list of folded domains, target_prob between 0 and 1,
1154    * F in N, and T in K. */
1155   double dt=dt_max, new_dt;
1156   assert(target_prob > 0.0); assert(target_prob < 1.0);
1157   assert(dt_max > 0.0);
1158   
1159   while (domain_list != NULL) {
1160     if (D(domain_list)->state == DS_FOLDED) {
1161       new_dt = search_dt(num_tension_handlers, tension_handlers, domain_list, env, x, target_prob, dt, v);
1162       dt = MIN(dt, new_dt);
1163     }
1164     domain_list = domain_list->next;
1165   }
1166   return dt;
1167 }
1168
1169
1170 \subsection{Domain data}
1171
1172 Currently domains exist in two states, folded and unfolded, and the
1173 only allowed transitions are folded $\rightarrow$ unfolded.  Of
1174 course, it wouldn't be too complicated to extent this to a multi-state
1175 system, with an array containing the domains group for each possible
1176 state, and a matrix of transition-rate-calculating functions.
1177 However, at this point such generality seems unnecessary at this
1178 point.
1179 <<domain definitions>>=
1180 enum domain_state_t {DS_FOLDED,
1181                      DS_UNFOLDED
1182 };
1183
1184 typedef struct domain_struct {
1185   enum domain_state_t state;
1186   one_dim_fn_t       *folded_handler;
1187   int                   folded_group;
1188   one_dim_fn_t       *unfolded_handler;
1189   int                   unfolded_group;
1190   k_func_t *k;           /* function returning unfolding rate */
1191   void *folded_params;   /* pointer to folded parameters   */
1192   void *unfolded_params; /* pointer to unfolded parameters */
1193   void *k_params;        /* pointer to k parameters        */
1194   destroy_data_func_t *destroy_folded;
1195   destroy_data_func_t *destroy_unfolded;
1196   destroy_data_func_t *destroy_k;
1197 } domain_t;
1198
1199 /* get the domain data for the current list node */
1200 #define D(list) ((domain_t *)(list)->d)
1201 /* get the tension params for the current list node */
1202 #define D_TP(list) (((domain_t *)(list)->d)->state == DS_FOLDED \
1203                      ? ((domain_t *)(list)->d)->folded_params   \
1204                      : ((domain_t *)(list)->d)->unfolded_params)
1205
1206 [[k]] is a pointer to the function determining the unfolding rate for a given tension.
1207 [[folded_params]] is a pointer to the parameters used by the function pointed to by [[k]].
1208 [[unfolded_params]] is a pointer to the parameters used by the group-appropriate handler function when determining the tension.
1209 The [[destroy_*]] pointers point to functions for freeing the memory [[*_params]].
1210 We store them with the domain data so that [[destroy_domain]] doesn't have to know which type of domain it's cleaning up after.
1211
1212 [[create_]] and [[destroy_domain]] are simple wrappers around [[malloc]] and [[free]].
1213 <<create/destroy domain>>=
1214 domain_t *create_domain(enum domain_state_t state,
1215                         k_func_t *k,
1216                         void *k_params,
1217                         destroy_data_func_t *destroy_k,
1218                         one_dim_fn_t *folded_handler,
1219                         int folded_group,
1220                         void *folded_params,
1221                         destroy_data_func_t *destroy_folded,
1222                         one_dim_fn_t *unfolded_handler,
1223                         int unfolded_group,
1224                         void *unfolded_params,
1225                         destroy_data_func_t *destroy_unfolded)
1226 {
1227   domain_t *ret = (domain_t *)malloc(sizeof(domain_t));
1228   assert(ret != NULL);
1229   if (state == DS_FOLDED) {
1230     assert(k != NULL);  /* the pointer points somewhere valid  */
1231     assert(*k != NULL); /* and there is something useful there */
1232   } else
1233     assert(state == DS_UNFOLDED);
1234   ret->state = state;
1235   ret->folded_handler = folded_handler;
1236   ret->folded_group = folded_group;
1237   ret->unfolded_handler = unfolded_handler;
1238   ret->unfolded_group = unfolded_group;
1239   ret->k = k;
1240   ret->folded_params = folded_params;
1241   ret->unfolded_params = unfolded_params;
1242   ret->k_params = k_params;
1243   ret->destroy_folded = destroy_folded;
1244   ret->destroy_unfolded = destroy_unfolded;
1245   ret->destroy_k = destroy_k;
1246 #ifdef DEBUG
1247   fprintf(stderr, "generated domain %p. state %d\n", ret, ret->state);
1248 #endif
1249   return ret;
1250 }
1251
1252 void destroy_domain(domain_t *domain)
1253 {
1254   if (domain) {
1255     //printf("domain %p & %p\n", *domain, domain);
1256     if (domain->destroy_folded)
1257       (*domain->destroy_folded)(domain->folded_params);
1258     if (domain->destroy_unfolded)
1259       (*domain->destroy_unfolded)(domain->unfolded_params);
1260     if (domain->destroy_k)
1261       (*domain->destroy_k)(domain->k_params);
1262     free(domain);
1263   }
1264 }
1265 @
1266
1267 <<destroy domain list>>=
1268 void destroy_domain_list(list_t *domain_list)
1269 {
1270   domain_list = head(domain_list);
1271   while (domain_list != NULL)
1272     destroy_domain((domain_t *) pop(&domain_list));
1273 }
1274 @
1275
1276 \subsection{Domain model and group handling}
1277
1278 <<group functions>>=
1279 <<get tension handler>>
1280 <<get group>>
1281 <<int comparison function>>
1282 <<find possible groups>>
1283 <<is group active>>
1284 <<get group list>>
1285 <<get active groups>>
1286
1287
1288 <<get tension handler>>=
1289 one_dim_fn_t *get_tension_handler(domain_t *domain)
1290 {
1291   if (domain->state == DS_FOLDED)
1292     return domain->folded_handler;
1293   else {
1294     if (domain->state != DS_UNFOLDED)
1295       fprintf(stderr, "oops, domain %p state %d\n", domain, domain->state);
1296     assert(domain->state == DS_UNFOLDED);
1297     return domain->unfolded_handler;
1298   }
1299 }
1300
1301
1302 <<get group>>=
1303 int get_group(domain_t *domain)
1304 {
1305   if (domain->state == DS_FOLDED)
1306     return domain->folded_group;
1307   else {
1308     if (domain->state != DS_UNFOLDED)
1309       fprintf(stderr, "oops, domain %p state %d\n", domain, domain->state);
1310     assert(domain->state == DS_UNFOLDED);
1311     return domain->unfolded_group;
1312   }
1313 }
1314
1315
1316 We already know all possible tension classes, since they are all
1317 hardcoded into \prog.  However, there may be any number of possible
1318 groups.  We define a function [[find_possible_groups]] to search for
1319 possible (not neccessarily active) groups.  It can search for
1320 subgroups of a single [[handler]], or by setting [[handler]] to
1321 [[NULL]], subgroups of \emph{any} handler.  It returns a list of group
1322 integers.
1323 <<find possible groups>>=
1324 list_t *find_possible_groups(list_t *list, one_dim_fn_t *handler) {
1325   list_t *ret = NULL;
1326   list = head(list);
1327   while (list != NULL) {
1328     if (handler == NULL || get_tension_handler(D(list)) == handler) {
1329       push(&ret, &D(list)->folded_group, 1);
1330       push(&ret, &D(list)->unfolded_group, 1);
1331     }
1332     list = list->next;
1333   }
1334
1335   if (ret == NULL)
1336     return ret; /* no groups with this handler, no processing needed */
1337
1338   /* sort the ret list, and remove duplicates */
1339   sort(&ret, &int_comparison);
1340   unique(&ret, &int_comparison);
1341 #ifdef DEBUG
1342   fprintf(stderr, "handler %p possible groups:", handler);
1343   list = head(ret);
1344   while (list != NULL) {
1345     fprintf(stderr, " %d", *((int *)list->d));
1346     list = list->next;
1347   }
1348   fprintf(stderr, "\n");
1349 #endif
1350   return ret;
1351 }
1352
1353
1354 Search a [[list]] of domains, and determine whether a particular model
1355 class and group number combination is active.
1356 <<is group active>>=
1357 int is_group_active(list_t *list, one_dim_fn_t *handler, int group)
1358 {
1359   list = head(list);
1360   while (list != NULL) {
1361     if (get_tension_handler(D(list)) == handler && get_group(D(list)) == group)
1362       return 1;
1363     list = list->next;
1364   }
1365   return 0;
1366 }
1367
1368
1369 Search a [[list]] of domains, and return all domains matching a
1370 particular model class and group number.
1371 <<get group list>>=
1372 list_t *get_group_list(list_t *list, one_dim_fn_t *handler, int group)
1373 {
1374   list_t *ret = NULL;
1375   list = head(list);
1376   while (list != NULL) {
1377     if (get_tension_handler(D(list)) == handler && get_group(D(list)) == group) {
1378       push(&ret, D_TP(list), 1); /* add a pointer to the appropriate tension parameters to our new list. */
1379 #ifdef DEBUG
1380       fprintf(stderr, "push domain %p %s tension parameters %p onto active group %p %d list %p\n", D(list), D(list)->state == DS_FOLDED ? "folded" : "unfolded", D_TP(list), handler, group, ret);
1381 #endif
1382     }
1383     list = list->next;
1384   }
1385   return ret;
1386 }
1387
1388 Because all the node data in lists returned by [[get_group_list]] is
1389 also in the main domain list, you shouldn't destroy the node data
1390 popped off when destroying the group lists.  It will all get cleaned
1391 up when the main domain list is destroyed.
1392
1393 Put all this together to scan through a list of domains and construct
1394 an array of all the active groups.
1395 <<get active groups>>=
1396 void get_active_groups(list_t *list,
1397                      int num_tension_handlers, one_dim_fn_t **tension_handlers,
1398                      int *pNum_active_groups, one_dim_fn_t ***pPer_group_handlers, void ***pActive_groups)
1399 {
1400   void **active_groups=NULL;
1401   one_dim_fn_t *handler, **per_group_handlers=NULL;
1402   int i, num_active_groups, *group;
1403   list_t *possible_group_numbers,  *active_group_list, *active_groups_list=NULL, *per_group_handlers_list=NULL;
1404
1405   /* get all the active groups in a list */
1406   for (i=0; i<num_tension_handlers; i++) {
1407     handler = tension_handlers[i];
1408     if (handler == NULL) continue; /* tensionless handler */
1409     possible_group_numbers = head(find_possible_groups(list, handler));
1410     while (possible_group_numbers != NULL) {
1411       group = (int *)pop(&possible_group_numbers);
1412       if (is_group_active(list, handler, *group) == 1) {
1413         active_group_list = get_group_list(list, handler, *group);
1414         push(&active_groups_list, active_group_list, 1);
1415         push(&per_group_handlers_list, handler, 1);
1416 #ifdef DEBUG
1417         fprintf(stderr, "active group %p for %p %d headed by tension parameters %p\n", active_group_list, handler, *group, head(active_group_list)->d);
1418         list_print(stderr, active_group_list, "active group");
1419 #endif
1420       }
1421     }
1422   }
1423
1424   /* allocate the array we'll be returning */  
1425   num_active_groups = list_length(active_groups_list);
1426   active_groups = (void **) malloc(sizeof(void *)*num_active_groups);
1427   assert(active_groups != NULL);
1428   per_group_handlers = (one_dim_fn_t **)malloc(sizeof(one_dim_fn_t *)*num_active_groups);
1429   assert(per_group_handlers != NULL);
1430
1431   /* populate the array we'll be returning */
1432   active_groups_list = head(active_groups_list);
1433   for (i=0; i<num_active_groups; i++) {
1434     handler = pop(&per_group_handlers_list);
1435     per_group_handlers[i] = handler;
1436
1437     active_groups[i] = (void *) malloc(sizeof(tension_handler_data_t));
1438     assert(active_groups[i] != NULL);
1439     active_group_list = pop(&active_groups_list);
1440     ((tension_handler_data_t *)active_groups[i])->group = active_group_list;
1441     ((tension_handler_data_t *)active_groups[i])->env = NULL;
1442     ((tension_handler_data_t *)active_groups[i])->persist = NULL;
1443   }
1444   assert(active_groups_list == NULL);
1445   assert(per_group_handlers_list == NULL);
1446
1447   *pNum_active_groups = num_active_groups;
1448   *pPer_group_handlers = per_group_handlers;
1449   *pActive_groups = active_groups;
1450 }
1451
1452
1453
1454 \section{String parsing}
1455
1456 For handling command line arguments, we need parse delimited strings (e.g. [["param1,param2,param3..."]]).
1457 The model handling in getopt is set up to handle a fixed number of arguments for each model,
1458 so models (like [[kramers_integ]]) that have complicated parameters (location of spline knots)
1459 need to take care of parsing those parameters themselves.
1460 We implement this parsing in [[parse.c]], define the interface in [[parse.h]], and the the unit testing in [[check_parse.c]].
1461
1462 <<parse.h>>=
1463 #ifndef PARSE
1464 #define PARSE
1465 <<license comment>>
1466 <<parse definitions>>
1467 <<parse declarations>>
1468 #endif /* PARSE */
1469
1470
1471 <<parse module makefile lines>>=
1472 NW_SAWSIM_MODS += parse
1473 CHECK_BINS += check_parse
1474 check_parse_MODS = 
1475
1476
1477 <<parse definitions>>=
1478 #define SEP ',' /* argument separator character */
1479
1480
1481 <<parse declarations>>=
1482 extern void parse_list_string(char *string, char sep, char deeper, char shallower,
1483                        int *num, char ***string_array);
1484 extern void free_parsed_list(int num, char **string_array);
1485
1486
1487 [[parse_list_string]] allocates memory, don't forget to free it
1488 afterward with [[free_parsed_list]].  It does not alter the original.
1489
1490 The string may start off with a [[deeper]] character
1491 (i.e. [["{x,y}"]]), and when it does, brace stripping will set leave
1492 [[x,y]], where the pointer is one character in on the copied string.
1493 However, when we go to free the memory, we need a pointer to the
1494 beginning of the string.  In order to accommodate this for a string
1495 with $N$ argument, allocate a pointer array with $N+1$ elements, let
1496 the first $N$ elements point to the separated arguments, and let the
1497 last element point to the start of the copied string regardless of
1498 braces.
1499 <<parse delimited list string functions>>=
1500 /* TODO, split out into parse.hc */
1501 static int next_delim_index(char *string, char sep, char deeper, char shallower)
1502 {
1503   int i=0, depth = 0;
1504   while (string[i] != '\0' && !(string[i] == sep && depth == 0)) {
1505     if (string[i] == deeper) {depth++;}
1506     else if (string[i] == shallower) {depth--; assert(depth >= 0);}
1507     i++;
1508   }
1509   return i;
1510 }
1511
1512 void parse_list_string(char *string, char sep, char deeper, char shallower,
1513                        int *num, char ***string_array)
1514 {
1515   char *str=NULL, **ret=NULL;
1516   int i, j, n;
1517   if (string==NULL || strlen(string) == 0) {    /* handle the trivial cases */
1518     *num = 0;
1519     *string_array = NULL;
1520     return;
1521   }
1522   /* make a copy of the string, so we don't change the original */
1523   str = (char *)malloc(sizeof(char)*(strlen(string)+1));
1524   assert(str != NULL);
1525   strcpy(str, string); /* we know str is long enough */
1526   /* count the number of regions, so we can allocate pointers to them */
1527   i=-1; n=0;
1528   do {
1529     n++; i++; /* move on to next argument */
1530     i += next_delim_index(str+i, sep, deeper, shallower);
1531     //fprintf( stderr, "delim at %d (%d) ('%s' -> '%s')\n", i, (int)str[i], str, str+i+1); fflush(stderr);
1532   } while (str[i] != '\0');
1533   ret = (char **)malloc(sizeof(char *)*(n+1));
1534   assert(ret != NULL);
1535   /* replace the separators with '\0' & assign pointers */
1536   ret[n] = str; /* point to the front of the copied string */
1537   j=0;
1538   ret[0] = str;
1539   for(i=1; i<n; i++) {
1540     j += next_delim_index(str+j, sep, deeper, shallower);
1541     str[j++] = '\0';
1542     ret[i] = str+j; /* point to the separated arguments */
1543   }
1544   /* strip off bounding braces, if any */
1545   for(i=0; i<n; i++) {
1546     if (ret[i][0] == deeper) {
1547       ret[i][0] = '\0';
1548       ret[i]++;
1549     }
1550     if (ret[i][strlen(ret[i])-1] == shallower)
1551       ret[i][strlen(ret[i])-1] = '\0';
1552   }
1553   *num = n;
1554   *string_array = ret;
1555 }
1556
1557 void free_parsed_list(int num, char **string_array)
1558 {
1559   if (string_array) {
1560     /* frees all items, since they were allocated as a single string*/
1561     free(string_array[num]);
1562     /* and free the array of pointers */
1563     free(string_array);
1564   }
1565 }
1566 @
1567
1568 \subsection{Parsing implementation}
1569
1570 <<parse.c>>=
1571 <<license comment>>
1572 <<parse includes>>
1573 #include "parse.h"
1574 <<parse delimited list string functions>>
1575
1576
1577 <<parse includes>>=
1578 #include <assert.h> /* assert()                */
1579 #include <stdlib.h> /* NULL                    */
1580 #include <stdio.h>  /* fprintf(), stdout       *//*!!*/
1581 #include <string.h> /* strlen()                */
1582 #include "parse.h"
1583
1584
1585 \subsection{Parsing unit tests}
1586
1587 Here we check to make sure the various functions work as expected, using \citetalias{sw:check}.
1588 <<check-parse.c>>=
1589 <<parse check includes>>
1590 <<string comparison definition and globals>>
1591 <<check relative error>>
1592 <<parse test suite>>
1593 <<main check program>>
1594
1595
1596 <<parse check includes>>=
1597 #include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE, atof() */
1598 #include <stdio.h>  /* printf()                              */
1599 #include <assert.h> /* assert()                              */
1600 #include <string.h> /* strlen()                              */
1601 <<check includes>>
1602 #include "parse.h"
1603
1604
1605 <<parse test suite>>=
1606 <<parse list string tests>>
1607 <<parse suite definition>>
1608
1609
1610 <<parse suite definition>>=
1611 Suite *test_suite (void)
1612 {
1613   Suite *s = suite_create ("k model");
1614   <<parse list string test case defs>>
1615
1616   <<parse list string test case add>>
1617   return s;
1618 }
1619
1620
1621 <<parse list string tests>>=
1622
1623 /*
1624 START_TEST(test_next_delim_index)
1625 {
1626   fail_unless(next_delim_index("", ',', '{', '}')==0, NULL);
1627   fail_unless(next_delim_index(",arg,{str,ing},test", ',', '{', '}')==0, NULL);
1628   fail_unless(next_delim_index("arg,{str,ing},test", ',', '{', '}')==3, NULL);
1629   fail_unless(next_delim_index("{str,ing},test", ',', '{', '}')==9, NULL);
1630   fail_unless(next_delim_index("test", ',', '{', '}')==4, NULL);
1631 }
1632 END_TEST
1633 */
1634 START_TEST(test_parse_list_null)
1635 {
1636   int num_param_args;
1637   char **param_args;
1638   parse_list_string(NULL, SEP, '{', '}',
1639                     &num_param_args, &param_args);
1640   fail_unless(num_param_args == 0, NULL);
1641   fail_unless(param_args == NULL, NULL);
1642 }
1643 END_TEST
1644 START_TEST(test_parse_list_single_simple)
1645 {
1646   int num_param_args;
1647   char **param_args;
1648   parse_list_string("arg", SEP, '{', '}',
1649                     &num_param_args, &param_args);
1650   fail_unless(num_param_args == 1, NULL);
1651   fail_unless(STRMATCH(param_args[0],"arg"), NULL);
1652 }
1653 END_TEST
1654 START_TEST(test_parse_list_single_compound)
1655 {
1656   int num_param_args;
1657   char **param_args;
1658   parse_list_string("{x,y,z}", SEP, '{', '}',
1659                     &num_param_args, &param_args);
1660   fail_unless(num_param_args == 1, NULL);
1661   fail_unless(STRMATCH(param_args[0],"x,y,z"), "got '%s', expected '%s'", param_args[0], "x,y,z");
1662 }
1663 END_TEST
1664 START_TEST(test_parse_list_double_simple)
1665 {
1666   int num_param_args;
1667   char **param_args;
1668   parse_list_string("abc,def", SEP, '{', '}',
1669                     &num_param_args, &param_args);
1670   fail_unless(num_param_args == 2, NULL);
1671   fail_unless(STRMATCH(param_args[0],"abc"), NULL);
1672   fail_unless(STRMATCH(param_args[1],"def"), NULL);
1673 }
1674 END_TEST
1675 @
1676 <<parse list string test case defs>>=
1677 TCase *tc_parse_list_string = tcase_create("parse list string");
1678 @
1679 <<parse list string test case add>>=
1680 //tcase_add_test(tc_parse_list_string, test_next_delim_index);
1681 tcase_add_test(tc_parse_list_string, test_parse_list_null);
1682 tcase_add_test(tc_parse_list_string, test_parse_list_single_simple);
1683 tcase_add_test(tc_parse_list_string, test_parse_list_single_compound);
1684 tcase_add_test(tc_parse_list_string, test_parse_list_double_simple);
1685 suite_add_tcase(s, tc_parse_list_string);
1686 @
1687
1688
1689 \section{Unit tests}
1690
1691 Here we check to make sure the various functions work as expected, using \citetalias{sw:check}.
1692 <<checks>>=
1693 <<includes>>
1694 <<check includes>>
1695 <<definitions>>
1696 <<globals>>
1697 <<check globals>>
1698 <<check relative error>>
1699 <<functions>>
1700 <<test suite>>
1701 <<main check program>>
1702
1703
1704 <<check includes>>=
1705 #include <check.h>
1706
1707
1708 <<check globals>>=
1709
1710
1711 <<test suite>>=
1712 <<F tests>>
1713 <<determine dt tests>>
1714 <<happens tests>>
1715 <<does domain unfold tests>>
1716 <<randomly unfold domains tests>>
1717 <<suite definition>>
1718
1719
1720 <<suite definition>>=
1721 Suite *test_suite (void)
1722 {
1723   Suite *s = suite_create ("sawsim");
1724   <<F test case defs>>
1725   <<determine dt test case defs>>
1726   <<happens test case defs>>
1727   <<does domain unfold test case defs>>
1728   <<randomly unfold domains test case defs>>
1729
1730   <<F test case add>>
1731   <<determine dt test case add>>
1732   <<happens test case add>>
1733   <<does domain unfold test case add>>
1734   <<randomly unfold domains test case add>>
1735
1736 /*
1737   tcase_add_checked_fixture(tc_strip_address,
1738                             setup_strip_address,
1739                             teardown_strip_address);
1740 */
1741   return s;
1742 }
1743
1744
1745 <<main check program>>=
1746 int main(void)
1747 {
1748   int number_failed;
1749   Suite *s = test_suite();
1750   SRunner *sr = srunner_create(s);
1751   srunner_run_all(sr, CK_ENV);
1752   number_failed = srunner_ntests_failed(sr);
1753   srunner_free(sr);
1754   return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
1755 }
1756
1757
1758 \subsection{F tests}
1759 <<F tests>>=
1760 <<worm-like chain tests>>
1761
1762 <<F test case defs>>=
1763 <<worm-like chain test case def>>
1764
1765 <<F test case add>>=
1766 <<worm-like chain test case add>>
1767
1768
1769 <<worm-like chain tests>>=
1770 extern double wlc(double x, double T, double p, double L);
1771 START_TEST(test_wlc_at_zero)
1772 {
1773   double T=1.0, L=1.0, p=0.1, x=0.0, lim=1e-30;
1774   fail_unless(abs(wlc(x, T, p, L)) < lim, \
1775               "abs(wlc(x=%g,T=%g,p=%g,L=%g)) = %g >= %g",
1776               x, T, p, L, abs(wlc(x, T, p, L)), lim);
1777 }
1778 END_TEST
1779
1780 START_TEST(test_wlc_at_half)
1781 {
1782   double T=1.0, L=1.0, p=0.1*k_B, x=0.5;
1783   /* prefactor = k_B T / p = k_B 1.0 / (k_B*0.1) = 10.0 J/nm = 10.0e21 pN
1784    * nonlinear term = 0.25 (1/(1-x/L)^2-1) = 0.25(1/.25 - 1)
1785    *                = 0.25 * 3 = 3/4
1786    * linear term = x/L = 0.5
1787    * nonlinear + linear = 0.75 + 0.5 = 1.25
1788    * wlc = 10e21*1.25 = 12.5e21 
1789    */
1790   fail_unless(wlc(x, T, p, L)-12.5e21 < 1e16,
1791               "wlc(%g, %g, %g, %g) = %g != %g",
1792                x, T, p, L, wlc(x, T, p, L), 12.5e21);
1793 }
1794 END_TEST
1795
1796 <<worm-like chain test case def>>=
1797 TCase *tc_wlc = tcase_create("WLC");
1798
1799
1800 <<worm-like chain test case add>>=
1801 tcase_add_test(tc_wlc, test_wlc_at_zero);
1802 tcase_add_test(tc_wlc, test_wlc_at_half);
1803 suite_add_tcase(s, tc_wlc);
1804
1805
1806 \subsection{Model tests}
1807
1808 Check the searching with [[linear_k]].
1809 Check overwhelming force treatment with the heavyside-esque step [[?]].
1810 <<determine dt tests>>=
1811 double linear_k(double F, environment_t *env, void *params)
1812 {
1813   double Fnot = *(double *)params;
1814   return Fnot+F;
1815 }
1816
1817 START_TEST(test_determine_dt_linear_k)
1818 {
1819   environment_t env;
1820   double dt_max=3.0, Fnot=3.0;
1821   double F[]={0,1,2,3,4,5,6};
1822   domain_t dom; /* use both parts at once for folded/unfolded */
1823   int i;
1824   env.T = 300.0;
1825 /*
1826   dom->next = dom->prev = NULL;
1827   dom->k_func_t = linear_k;
1828   dom->folded_params = &Fnot;
1829   dom->unfolded_params = !!!!!!!!!
1830   dom->destroy_folded = dom->destroy_unfolded = NULL;
1831   for( i=0; i < sizeof(F)/sizeof(double); i++) {
1832     fail_unless(determine_dt(folded, unfolded, targ_p, dt_max, v, x, T)==1, NULL);
1833   }
1834 */
1835 }
1836 END_TEST
1837 @
1838 <<determine dt test case defs>>=
1839 TCase *tc_determine_dt = tcase_create("Determine dt");
1840 @
1841 <<determine dt test case add>>=
1842 tcase_add_test(tc_determine_dt, test_determine_dt_linear_k);
1843 suite_add_tcase(s, tc_determine_dt);
1844 @
1845
1846 <<happens tests>>=
1847 @
1848 <<happens test case defs>>=
1849 @
1850 <<happens test case add>>=
1851 @
1852
1853 <<does domain unfold tests>>=
1854 @
1855 <<does domain unfold test case defs>>=
1856 @
1857 <<does domain unfold test case add>>=
1858 @
1859
1860 <<randomly unfold domains tests>>=
1861 @
1862 <<randomly unfold domains test case defs>>=
1863 @
1864 <<randomly unfold domains test case add>>=
1865 @
1866
1867
1868 \section{Balancing group extensions}
1869 \label{app.tension_balance}
1870
1871 For a given total extension $x$ (of the piezo), the various domain
1872 models (WLC, FJC, Hookean springs, \ldots) and groups extend different
1873 amounts, and we need to tweak the portion that each extends to balance
1874 the tension amongst the active groups.  Since the tension balancing is
1875 separable from the bulk of the simulation, we break it out into a
1876 separate module.  The interface is defined in [[tension_balance.h]],
1877 the implementation in [[tension_balance.c]], and the unit testing in
1878 [[check_tension_balance.c]]
1879
1880 <<tension-balance.h>>=
1881 #ifndef TENSION_BALANCE_H
1882 #define TENSION_BALANCE_H
1883 <<license comment>>
1884 <<tension balance function declaration>>
1885 #endif /* TENSION_BALANCE_H */
1886
1887
1888 <<tension balance functions>>=
1889 <<one dimensional bracket>>
1890 <<one dimensional solve>>
1891 <<x of x0>>
1892 <<tension balance function>>
1893
1894
1895 <<tension balance module makefile lines>>=
1896 NW_SAWSIM_MODS += tension_balance
1897 CHECK_BINS += check_tension_balance
1898 check_tension_balance_MODS = 
1899
1900
1901 The entire force balancing problem reduces to a solving two nested
1902 one-dimensional root-finding problems.  First we define the one
1903 dimensional tension $F(x_0)$ (where $i=0$ is the index of the first
1904 non-empty group).  $x(x_0)$ is also strictly monotonically increasing,
1905 so we can solve for $x_0$ such that $\sum_i x_i = x$.  [[last_x]]
1906 stores the last successful value of $x$, since we expect to be taking
1907 small steps ($x \approx$ [[last_x]]).  Setting [[last_x = -1]]
1908 indicates that the groups have changed.
1909 <<tension balance function declaration>>=
1910 double tension_balance(int num_tension_groups,
1911                        one_dim_fn_t **tension_handlers,
1912                        void **params,
1913                        double last_x,
1914                        double x);
1915
1916 <<tension balance function>>=
1917 double tension_balance(int num_tension_groups,
1918                        one_dim_fn_t **tension_handlers,
1919                        void **params,
1920                        double last_x,
1921                        double x)
1922 {
1923   static x_of_xo_data_t x_xo_data = {0,NULL,NULL,NULL};
1924   double F, xo_guess, xo, lb, ub;
1925   double min_relx=1e-6, min_rely=1e-6;
1926   int max_steps=200, i;
1927
1928   assert(num_tension_groups > 0);
1929   assert(tension_handlers != NULL);
1930   assert(params != NULL);
1931   assert(num_tension_groups > 0);
1932
1933   if (num_tension_groups == 1) { /* only one group, no balancing required */
1934     xo = x;
1935   } else {
1936     //fprintf(stderr, "balancing for x = %g with ", x);
1937     //for(i=0; i<num_tension_groups; i++) fprintf(stderr, " %d: %g\t", i, x_xo_data.xi[i]);
1938     //fprintf(stderr, "\n");
1939     if (last_x == -1) { /* new group setup, reset x_xo_data */
1940       /* x_xo_data tension_handler and handler_data arrays freed by find_tension() */
1941       if (x_xo_data.xi != NULL)
1942         free(x_xo_data.xi);
1943       /* construct new x_xo_data */
1944       x_xo_data.n_groups = num_tension_groups;
1945       x_xo_data.tension_handler = tension_handlers;
1946       x_xo_data.handler_data = params;
1947       x_xo_data.xi = (double *) malloc(sizeof(double)*num_tension_groups);
1948       for (i=0; i<num_tension_groups; i++)
1949         x_xo_data.xi[i] = -1.0;
1950     }
1951     if (last_x == -1 || 1) { /* take a rough guess and attempt boundary conditions. */
1952       if (x == 0) xo_guess = length_scale;
1953       else        xo_guess = x/num_tension_groups;
1954 #ifdef DEBUG
1955       fprintf(stderr, "%s:\tfind a bracket for x = %g with guess of x0 = %g\n", __FUNCTION__, x, xo_guess);
1956 #endif
1957       oneD_bracket(x_of_xo, &x_xo_data, x, xo_guess, &lb, &ub);
1958     } else { /* work off the last balanced point */
1959 #ifdef DEBUG
1960       fprintf(stderr, "%s:\tstep off the old bracketing x %g + %g = %g\n", __FUNCTION__, last_x, x-last_x, x);
1961 #endif
1962       if (x > last_x) {
1963         lb = x_xo_data.xi[0];
1964         ub = x_xo_data.xi[0]+ x-last_x;   /* apply all change to x0 */
1965       } else if (x < last_x) {
1966         lb = x_xo_data.xi[0]- (x-last_x); /* apply all change to x0 */
1967         ub = x_xo_data.xi[0];
1968       } else { /* x == last_x */
1969         fprintf(stderr, "not moving\n");
1970         lb= x_xo_data.xi[0];
1971         ub= x_xo_data.xi[0];
1972       }
1973     }
1974 #ifdef DEBUG
1975     fprintf(stderr, "%s:\tsolve x(x0) so x = %g with bounds x0 in [%g, %g]\n",
1976             __FUNCTION__, x, lb, ub);
1977 #endif
1978     xo = oneD_solve(x_of_xo, &x_xo_data, x, lb, ub, min_relx, min_rely, max_steps, NULL);
1979     F = x_of_xo(xo, &x_xo_data); /* HACK, bonus call to setup x_xo_data.xi */
1980 #ifdef DEBUG
1981     if (num_tension_groups > 1) {
1982       fprintf(stderr, "%s:\tbalanced for x = %g with ", __FUNCTION__, x);
1983       for(i=0; i<num_tension_groups; i++) fprintf(stderr, " %d: %g\t", i, x_xo_data.xi[i]);
1984       fprintf(stderr, "\n");
1985     }
1986 #endif
1987   }
1988   F = (*tension_handlers[0])(xo, params[0]);
1989   return F;
1990 }
1991
1992
1993 <<tension balance internal definitions>>=
1994 <<x of x0 definitions>>
1995
1996
1997 <<x of x0 definitions>>=
1998 typedef struct x_of_xo_data_struct {
1999   int n_groups;
2000   one_dim_fn_t **tension_handler; /* array of fn pointers */
2001   void **handler_data;            /* array of void* pointers */
2002   double *xi;
2003 } x_of_xo_data_t;
2004
2005
2006 <<x of x0>>=
2007 double x_of_xo(double xo, void *pdata)
2008 {
2009   x_of_xo_data_t *data = (x_of_xo_data_t *)pdata;
2010   double F, x=0, xi, xi_guess, lb, ub;
2011   int i;
2012   double min_relx=1e-6, min_rely=1e-6;
2013   int max_steps=200;
2014   assert(data->n_groups > 0);
2015   data->xi[0] = xo;
2016   F = (*data->tension_handler[0])(xo, data->handler_data[0]);
2017 #ifdef DEBUG
2018   fprintf(stderr, "%s: finding x(x0=%g).  F0(x0) = %g\n", __FUNCTION__, xo, F);
2019 #endif
2020   x += xo;
2021   if (data->xi)  data->xi[0] = xo;
2022   for (i=1; i < data->n_groups; i++) {
2023     if (data->xi[i] == -1) xi_guess = length_scale; /* HACK */
2024     else                   xi_guess = data->xi[i];
2025 #ifdef DEBUG
2026   fprintf(stderr, "%s: searching for proper x[%d] for F[%d](x[%d]) = %g N\n", __FUNCTION__, i, i, i, F);
2027 #endif
2028     oneD_bracket(data->tension_handler[i], data->handler_data[i], F,  xi_guess, &lb, &ub);
2029     xi = oneD_solve(data->tension_handler[i], data->handler_data[i], F, lb, ub, min_relx, min_rely, max_steps, NULL);
2030 #ifdef DEBUG
2031   fprintf(stderr, "%s: found F[%d](x[%d]=%g) = %g N\n", __FUNCTION__, i, i, xi, F);
2032 #endif
2033     data->xi[i] = xi;
2034     x += xi;
2035     if (data->xi)  data->xi[i] = xi;
2036   }
2037 #ifdef DEBUG
2038   fprintf(stderr, "%s: found x(x0=%g) = %g\n", __FUNCTION__, xo, x);
2039 #endif
2040   return x;
2041 }
2042
2043
2044 Solve $f(x) = y$ to a certain precision in $x$ or $y$ in a limited
2045 number of steps for monotonically increasing $f(x)$.  Simple
2046 bisection, so it's robust and converges fairly quickly.  You can set
2047 the maximum number of steps to take, but if you have enough processor
2048 power, it's better to limit your precision with the relative limits
2049 [[min_relx]] and [[y]].  These ensure that the width of the bracket is
2050 small on the length scale of it's larger side.  Note that \emph{both}
2051 relative limits must be satisfied for the search to stop.
2052 <<one dimensional function definition>>=
2053 /* equivalent to gsl_func_t */
2054 typedef double one_dim_fn_t(double x, void *params);
2055
2056 <<one dimensional solve declaration>>=
2057 double oneD_solve(one_dim_fn_t *f, void *params, double y, double lb, double ub,
2058                   double min_relx, double min_rely, int max_steps, 
2059                   double *pYx);
2060
2061
2062 <<one dimensional solve>>=
2063 /* TODO, replace with GSL one d root finder http://www.gnu.org/software/gsl/manual/html_node/One-dimensional-Root_002dFinding.html */
2064 double oneD_solve(one_dim_fn_t *f, void *params, double y, double lb, double ub,
2065                   double min_relx, double min_rely, int max_steps, 
2066                   double *pYx)
2067 {
2068   double yx, ylb, yub, x;
2069   int i=0;
2070   assert(ub >= lb);
2071   ylb = (*f)(lb, params);
2072   yub = (*f)(ub, params);
2073   
2074   /* check some simple cases */
2075   if (ylb == yub) {
2076     if (ylb != y)  return HUGE_VAL; /* error! f(x)=y not bounded */
2077     else           return lb; /* any x on the range [lb, ub] would work */
2078   }
2079   if (ylb == y) { x=lb; yx=ylb; goto end; }
2080   if (yub == y) { x=ub; yx=yub; goto end; }
2081
2082 #ifdef DEBUG
2083   fprintf(stderr, "%s:\tstarting bracket: lb %g, x ~, ub %g\tylb %g, y %g, yub %g\n", __FUNCTION__, lb, ub, ylb, y, yub);
2084 #endif
2085   assert(ylb < y); assert(yub > y);
2086   for (i=0; i<max_steps; i++) {
2087     x = (lb+ub)/2.0;
2088     yx = (*f)(x, params);
2089 #ifdef DEBUG
2090   fprintf(stderr, "%s:\tbracket: lb %g, x %g, ub %g\tylb %g, yx %g, yub %g\t(y %g)\n", __FUNCTION__, lb, x, ub, ylb, yx, yub, y);
2091 #endif
2092     if (yx == y || ((ub-lb)/ub < min_relx && (yub-ylb)/yub < min_rely)) break;
2093     else if (yx > y)  { ub=x; yub=yx; }
2094     else /* yx < y */ { lb=x; ylb=yx; }
2095   }
2096  end:
2097   if (pYx) *pYx = yx;
2098 #ifdef DEBUG
2099   fprintf(stderr, "%s:\tsolved f(%g) = %g ~= %g\n", __FUNCTION__, x, yx, y);
2100 #endif
2101   return x;
2102 }
2103
2104
2105 The one dimensional solver needs a bracketed solution, which sometimes we don't have.
2106 Generate bracketing $x$ values through bisection or exponential growth.
2107 <<one dimensional bracket declaration>>=
2108 void oneD_bracket(one_dim_fn_t *f, void *params, double y, double xguess, double *lb, double *ub);
2109
2110
2111 <<one dimensional bracket>>=
2112 void oneD_bracket(one_dim_fn_t *f, void *params, double y, double xguess, double *lb, double *ub)
2113 {
2114   double yx, step, x=xguess;
2115   int i=0;
2116   yx = (*f)(x, params);
2117 #ifdef DEBUG
2118   fprintf(stderr, "%s:\tbracketing %g, start at f(%g) = %g guessing x = %g (params %p)\n", __FUNCTION__, y, x, yx, xguess, params);
2119 #endif
2120   if (yx > y) {
2121     assert(x > 0.0);
2122     *ub = x;
2123     *lb = 0;
2124 #ifdef DEBUG
2125     fprintf(stderr, "%s:\tbracketted by [0, guess = %g]\n", __FUNCTION__, x);
2126 #endif
2127   } else {
2128     *lb = x;
2129     if (x == 0) x = length_scale/2.0; /* HACK */
2130     while (yx < y) {
2131       x *= 2.0;
2132       yx = (*f)(x, params);
2133 #ifdef DEBUG
2134       fprintf(stderr, "%s:\tincreasing to f(%g) = %g\n", __FUNCTION__, x, yx);
2135 #endif
2136     }
2137     *ub = x;
2138 #ifdef DEBUG
2139     fprintf(stderr, "%s:\tbracketted ouput %g by [guess = %g, %g]\n", __FUNCTION__, y, xguess, x);
2140 #endif
2141   }
2142   //fprintf(stdout, "ub %g, %g lb\n", *ub, *lb);
2143 }
2144
2145
2146 \subsection{Balancing implementation}
2147
2148 <<tension-balance.c>>=
2149 //#define DEBUG
2150 <<license comment>>
2151 <<tension balance includes>>
2152 #include "tension_balance.h"
2153
2154 double length_scale = 1e-10; /* HACK */
2155
2156 <<tension balance internal definitions>>
2157 <<tension balance functions>>
2158
2159
2160 <<tension balance includes>>=
2161 #include <assert.h> /* assert()          */
2162 #include <stdlib.h> /* NULL              */
2163 #include <math.h>   /* HUGE_VAL, macro constant, so don't need to link to math */
2164 #include <stdio.h>  /* fprintf(), stdout */
2165 #include "global.h"
2166
2167
2168 \subsection{Balancing unit tests}
2169
2170 Here we check to make sure the various functions work as expected, using \citetalias{sw:check}.
2171 <<check-tension-balance.c>>=
2172 <<tension balance check includes>>
2173 <<tension balance test suite>>
2174 <<main check program>>
2175
2176
2177 <<tension balance check includes>>=
2178 #include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE */
2179 #include <assert.h> /* assert()                      */
2180 <<check includes>>
2181 #include "global.h"
2182 #include "tension_balance.h"
2183
2184
2185 <<tension balance test suite>>=
2186 <<tension balance function tests>>
2187 <<tension balance suite definition>>
2188
2189
2190 <<tension balance suite definition>>=
2191 Suite *test_suite (void)
2192 {
2193   Suite *s = suite_create ("tension balance");
2194   <<tension balance function test case defs>>
2195
2196   <<tension balance function test case adds>>
2197   return s;
2198 }
2199
2200
2201 <<tension balance function tests>>=
2202 <<check relative error>>
2203
2204 double hooke(double x, void *pK)
2205 {
2206   assert(x >= 0);
2207   return *((double*)pK) * x;
2208 }
2209
2210 START_TEST(test_single_function)
2211 {
2212   double k=5, x=3, last_x=2.0, F;
2213   one_dim_fn_t *handlers[] = {&hooke};
2214   void *data[] =             {&k};
2215   F = tension_balance(1, handlers, data, last_x, x);
2216   fail_unless(F = k*x, NULL);
2217 }
2218 END_TEST
2219
2220
2221 We can also test balancing two springs with different spring constants.
2222 The analytic solution for a general number of springs is given in Appendix \ref{app.math_hooke}.
2223 <<tension balance function tests>>=
2224 START_TEST(test_double_hooke)
2225 {
2226   double k1=5, k2=4, x=3, last_x=-1.0, F, Fe, x1e, x2e;
2227   one_dim_fn_t *handlers[] = {&hooke, &hooke};
2228   void *data[] =             {&k1,    &k2};
2229   F = tension_balance(2, handlers, data, last_x, x);
2230   x1e = x*k2/(k1+k2);
2231   Fe = k1*x1e;
2232   x2e = x1e*k1/k2;
2233   //fail_unless(-(F-Fe)/Fe < 1e-6, "relative error %g > 1e-6 (Expected %g, got %g)",-(F-Fe)/Fe, Fe, F);
2234   //CHECK_ERR(1e-6, x1e, xi[0]);
2235   //CHECK_ERR(1e-6, x2e, xi[1]);
2236   CHECK_ERR(1e-6, Fe, F);
2237 }
2238 END_TEST
2239
2240 TODO: test [[tension_balance()]] with another balance after the [[x_of_xo_data]] initializing balance we ran above.
2241
2242 <<tension balance function test case defs>>=
2243 TCase *tc_tbfunc = tcase_create("tension balance function");
2244
2245
2246 <<tension balance function test case adds>>=
2247 tcase_add_test(tc_tbfunc, test_single_function);
2248 tcase_add_test(tc_tbfunc, test_double_hooke);
2249 suite_add_tcase(s, tc_tbfunc);
2250
2251
2252 \section{Lists}
2253
2254 The globular domains (and cantilever params, etc.) are saved in bi-directional lists.
2255 Since the list handling is so general, and separable from the bulk of the simulation, we break it out into a separate module.
2256 The interface is defined in [[list.h]], the implementation in [[list.c]], and the unit testing in [[check_list.c]]
2257
2258 <<list.h>>=
2259 #ifndef LIST_H
2260 #define LIST_H
2261 <<license comment>>
2262 <<list definitions>>
2263 <<list declarations>>
2264 #endif /* LIST_H */
2265
2266
2267 <<list declarations>>=
2268 <<head and tail declarations>>
2269 <<list length declaration>>
2270 <<push declaration>>
2271 <<pop declaration>>
2272 <<list destroy declaration>>
2273 <<list to array declaration>>
2274 <<move declaration>>
2275 <<sort declaration>>
2276 <<unique declaration>>
2277 <<list print declaration>>
2278
2279
2280 <<list functions>>=
2281 <<create and destroy node>>
2282 <<head and tail>>
2283 <<list length>>
2284 <<push>>
2285 <<pop>>
2286 <<list destroy>>
2287 <<list to array>>
2288 <<move>>
2289 <<sort>>
2290 <<unique>>
2291 <<list print>>
2292
2293
2294 <<list module makefile lines>>=
2295 NW_SAWSIM_MODS += list
2296 CHECK_BINS += check_list
2297 check_list_MODS = 
2298
2299
2300 <<list definitions>>=
2301 typedef struct list_struct {
2302   struct list_struct *next;
2303   struct list_struct *prev;
2304   void *d; /* data */
2305 } list_t;
2306
2307 <<comparison function typedef>>
2308
2309
2310 [[head]] and [[tail]] return pointers to the head and tail nodes of the list:
2311 <<head and tail declarations>>=
2312 list_t *head(list_t *list);
2313 list_t *tail(list_t *list);
2314
2315 <<head and tail>>=
2316 list_t *head(list_t *list)
2317 {
2318   if (list == NULL)
2319     return list;
2320   while (list->prev != NULL) {
2321     list = list->prev;
2322   }
2323   return list;
2324 }
2325
2326 list_t *tail(list_t *list)
2327 {
2328   if (list == NULL)
2329     return list;
2330   while (list->next != NULL) {
2331     list = list->next;
2332   }
2333   return list;
2334 }
2335
2336
2337 <<list length declaration>>=
2338 int list_length(list_t *list);
2339
2340 <<list length>>=
2341 int list_length(list_t *list)
2342 {
2343   int i;
2344   if (list == NULL)
2345     return 0;
2346   list = head(list);
2347   i = 1;
2348   while (list->next != NULL) {
2349     list = list->next;
2350     i += 1;
2351   }
2352   return i;
2353 }
2354
2355
2356 [[push]] inserts a node relative to the current position in the list
2357 without changing the current position.
2358 However, if the list we're pushing onto is [[NULL]], the current position isn't defined
2359 so we set it to that of the pushed domain.
2360 If below is zero, we insert above the current node (push(a>B>c,d,0) -> a>d>B>c),
2361 otherwise we insert below the current node (push(a>B>c,d,1) -> a>B>d>c).
2362 <<push declaration>>=
2363 void push(list_t **pList, void *data, int below);
2364
2365 <<push>>=
2366 void push(list_t **pList, void *data, int below)
2367 {  
2368   list_t *list, *new_node;
2369   assert(pList != NULL);
2370   list = *pList;
2371   new_node = create_node(data);
2372   if (list == NULL)
2373     *pList = new_node;
2374   else if (below==0) { /* insert above */
2375     if (list->prev != NULL)
2376       list->prev->next = new_node;
2377     new_node->prev = list->prev;
2378     list->prev = new_node;
2379     new_node->next = list;
2380   } else {         /* insert below */
2381     if (list->next != NULL)
2382       list->next->prev = new_node;
2383     new_node->next = list->next;
2384     list->next = new_node;
2385     new_node->prev = list;
2386   }
2387 }
2388
2389
2390 [[pop]] removes the current domain node, moving the current position
2391 to the node after it, unless that node is [[NULL]], in which case move
2392 the current position to the node before it.
2393 <<pop declaration>>=
2394 void *pop(list_t **pList);
2395
2396 <<pop>>=
2397 void *pop(list_t **pList)
2398 {
2399   list_t *list, *popped;
2400   void *data;
2401   assert(pList != NULL);
2402   list = *pList;
2403   assert(list != NULL); /* not an empty list */
2404   popped = list;
2405   /* bypass the popped node */
2406   if (list->prev != NULL)
2407      list->prev->next = list->next;
2408   if (list->next != NULL) {
2409      list->next->prev = list->prev;
2410      *pList = list->next;
2411   } else
2412      *pList = list->prev; /* note: list->prev may == NULL. that's ok ;) */
2413   data = popped->d;
2414   destroy_node(popped);
2415   return data;
2416 }
2417
2418
2419 [[list_destroy]] just pops all the nodes off a list, possibly excuting a clean-up function on their each node's data.
2420 If the cleanup function is [[NULL]], no cleanup function is called.
2421 The nodes are not popped in any particular order.
2422 <<list destroy declaration>>=
2423 void list_destroy(list_t **pList, destroy_data_func_t *destroy);
2424
2425 <<list destroy>>=
2426 void list_destroy(list_t **pList, destroy_data_func_t *destroy)
2427 {
2428   list_t *list;
2429   void *data;
2430   assert(pList != NULL);
2431   list = *pList;
2432   *pList = NULL;
2433   assert(list != NULL); /* not an empty list */
2434   while (list != NULL) {
2435     data = pop(&list);
2436     if (destroy != NULL)
2437       destroy(data);
2438   }
2439 }
2440
2441
2442 [[list_to_array]] converts a list to an array of pointers, preserving order.
2443 <<list to array declaration>>=
2444 void list_to_array(list_t *list, int *length, void ***array);
2445
2446 <<list to array>>=
2447 void list_to_array(list_t *list, int *pLength, void ***pArray)
2448 {
2449   void **array;
2450   int i,length;
2451   assert(list != NULL);
2452   assert(pLength != NULL);
2453   assert(pArray != NULL);
2454
2455   length = list_length(list);
2456   array = (void **)malloc(sizeof(void *)*length);
2457   assert(array != NULL);
2458   list = head(list);
2459   i=0;
2460   while (list != NULL) {
2461     array[i++] = list->d;
2462     list = list->next;
2463   }
2464   *pLength = length;
2465   *pArray = array;
2466 }
2467
2468
2469 [[move]] moves the current element along the list in either direction.
2470 <<move declaration>>=
2471 void move(list_t **pList, int downstream);
2472
2473 <<move>>=
2474 void move(list_t **pList, int downstream)
2475 {
2476   list_t *list, *flipper;
2477   void *data;
2478   assert(pList != NULL);
2479   list = *pList;          /* a>B>c>d */
2480   assert(list != NULL); /* not an empty list */
2481   if (downstream == 0)
2482     flipper = list->prev; /* flipper is A */
2483   else
2484     flipper = list->next; /* flipper is C */
2485   /* ensure there is somewhere to go in the direction we're heading */
2486   assert(flipper != NULL);
2487   /* remove the current element */
2488   data = pop(&list);      /* data=B, a>C>d */
2489   /* and put it back in in the correct spot */
2490   list = flipper;
2491   if (downstream == 0) {
2492     push(&list, data, 0); /* b>A>c>d */
2493     list = list->prev;    /* B>a>c>d   */    
2494   } else {
2495     push(&list, data, 1); /* a>C>b>d */
2496     list = list->next;    /* a>c>B>d */
2497   }
2498   *pList = list;
2499 }
2500
2501
2502 [[sort]] sorts a list from smallest to largest according to a user
2503 specified comparison.
2504 <<comparison function typedef>>=
2505 typedef int (comparison_fn_t)(void *A, void *B);
2506
2507 For example
2508 <<int comparison function>>=
2509 int int_comparison(void *A, void *B)
2510 {
2511   int a,b;
2512   a = *((int *)A);
2513   b = *((int *)B);
2514   if (a > b) return 1;
2515   else if (a == b) return 0;
2516   else return -1;
2517 }
2518
2519 <<sort declaration>>=
2520 void sort(list_t **pList, comparison_fn_t *comp);
2521
2522 Here we use the bubble sort algorithm.
2523 <<sort>>=
2524 void sort(list_t **pList, comparison_fn_t *comp)
2525 {
2526   list_t *list;
2527   int stable=0;
2528   assert(pList != NULL);
2529   list = *pList;
2530   assert(list != NULL); /* not an empty list */
2531   while (stable == 0) {
2532     stable = 1;
2533     list = head(list);
2534     while (list->next != NULL) {
2535       if ((*comp)(list->d, list->next->d) > 0) {
2536         stable = 0;
2537         move(&list, 1 /* downstream */);
2538       } else
2539         list = list->next;
2540     }
2541   }
2542   *pList = list;
2543 }
2544
2545
2546 [[unique]] removes duplicates from a sorted list according to a user
2547 specified comparison.  Don't do this unless you have other pointers
2548 any dynamically allocated data in your list, because [[unique]] just
2549 drops any non-unique data without freeing it.
2550 <<unique declaration>>=
2551 void unique(list_t **pList, comparison_fn_t *comp);
2552
2553 <<unique>>=
2554 void unique(list_t **pList, comparison_fn_t *comp)
2555 {
2556   list_t *list;
2557   assert(pList != NULL);
2558   list = *pList;
2559   assert(list != NULL); /* not an empty list */
2560   list = head(list);
2561   while (list->next != NULL) {
2562     if ((*comp)(list->d, list->next->d) == 0) {
2563       pop(&list);
2564     } else
2565       list = list->next;
2566   }
2567   *pList = list;
2568 }
2569
2570
2571 [[list_print]] prints a list to a [[FILE *]] stream.
2572 <<list print declaration>>=
2573 void list_print(FILE *file, list_t *list, char *list_name);
2574
2575 <<list print>>=
2576 void list_print(FILE *file, list_t *list, char *list_name)
2577 {
2578   fprintf(file, "%s:", (list_name==NULL) ? "list" : list_name);
2579   list = head(list);
2580   while (list != NULL) {
2581     fprintf(file, " %p", list->d);
2582     list = list->next;
2583   }
2584   fprintf(file, "\n");
2585 }
2586
2587
2588 [[create_]] and [[destroy_node]] are simple wrappers around [[malloc]] and [[free]].
2589 <<create and destroy node>>=
2590 list_t *create_node(void *data)
2591 {
2592   list_t *ret = (list_t *)malloc(sizeof(list_t));
2593   assert(ret != NULL);
2594   ret->prev = NULL;
2595   ret->next = NULL;
2596   ret->d = data;
2597   return ret;
2598 }
2599
2600 void destroy_node(list_t *node)
2601 {
2602   if (node)
2603     free(node);
2604 }
2605 @
2606 The user must free the data pointed to by the node on their own.
2607
2608 \subsection{List implementation}
2609
2610 <<list.c>>=
2611 <<license comment>>
2612 <<list includes>>
2613 #include "list.h"
2614 <<list functions>>
2615
2616
2617 <<list includes>>=
2618 #include <assert.h> /* assert()                                */
2619 #include <stdlib.h> /* malloc(), free(), rand()                */
2620 #include <stdio.h>  /* fprintf(), stdout, FILE                 */
2621 #include "global.h" /* destroy_data_func_t */
2622
2623
2624 \subsection{List unit tests}
2625
2626 Here we check to make sure the various functions work as expected, using \citetalias{sw:check}.
2627 <<check-list.c>>=
2628 <<list check includes>>
2629 <<list test suite>>
2630 <<main check program>>
2631
2632
2633 <<list check includes>>=
2634 #include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE */
2635 #include <stdio.h>  /* FILE                          */
2636 <<check includes>>
2637 #include "global.h"
2638 #include "list.h"
2639
2640
2641 <<list test suite>>=
2642 <<push tests>>
2643 <<pop tests>>
2644 <<list suite definition>>
2645
2646
2647 <<list suite definition>>=
2648 Suite *test_suite (void)
2649 {
2650   Suite *s = suite_create ("list");
2651   <<push test case defs>>
2652   <<pop test case defs>>
2653
2654   <<push test case adds>>
2655   <<pop test case adds>>
2656   return s;
2657 }
2658
2659
2660 <<push tests>>=
2661 START_TEST(test_push)
2662 {
2663   list_t *list=NULL;
2664   int i, p, e, n=3;
2665   for (i=0; i<n; i++)
2666     push(&list, (void *)i, 1);
2667   fail_unless(list == head(list), NULL);
2668   fail_unless( (int)list->d == 0 );
2669   for (i=0; i<n; i++) {
2670     /* we expect 0, n-1, n-2, ..., 1 */
2671     if (i == 0) e = 0;
2672     else        e = n-i;
2673     fail_unless((p=(int)pop(&list)) == e, "popped %d != %d expected", p, e);
2674   }
2675 }
2676 END_TEST
2677
2678
2679 <<push test case defs>>=
2680 TCase *tc_push = tcase_create("push");
2681
2682
2683 <<push test case adds>>=
2684 tcase_add_test(tc_push, test_push);
2685 suite_add_tcase(s, tc_push);
2686
2687
2688 <<pop tests>>=
2689
2690 <<pop test case defs>>=
2691
2692 <<pop test case adds>>=
2693
2694
2695 \section{Function string evaluation}
2696
2697 For the saddle-point approximated Kramers' model (Section \ref{sec.kramers}) we need the ability to evaluate user-supplied functions ($E(x)$, $x_{ts}(F)$, \ldots).
2698 We want the ability to handle fairly general functions, but don't want to reinvent the wheel by writing our own parser/evaluator.
2699 The solution is to run a scripting language as a subprocess accessed via pipes.
2700 We use \citetalias{sw:python} here, but it would be a simple matter to replace it with another evaluator if so desired.
2701
2702 We spawn the subprocess using the standard [[pipe]], [[fork]], [[exec]] idiom.
2703 This is one of the more complicated software ideas in \prog, so we'll go into more detail than we have been.
2704 Most of this is also POSIX-specific (as far as I know), so you'll have to do some legwork to port it to non-POSIX systems.
2705 We persevere despite the difficulties, because without command-line access to new functions, the saddle-point Kramers' approximation is of very limited utiltiy.
2706
2707 If you feel the benefits do \emph{not} outweigh the costs, or you are on a non-POSIX system (e.g. MS Windows without Cygwin), you should probably hardcode your functions in \lang.
2708 Then you can either statically or dynamically link to those hardcoded functions.
2709 While much less flexible, this approach would be a fairly simple-to-implement fallback.
2710
2711 Because this functionality is independent of the rest of the simulation, we'll split its definition out into its own set of files.
2712 The interface is defined in [[string_eval.h]], the implementation in [[string_eval.c]], and the unit testing in [[check_string_eval.c]].
2713
2714 <<string-eval.h>>=
2715 #ifndef STRING_EVAL_H
2716 #define STRING_EVAL_H
2717 <<license comment>>
2718 <<string eval setup declaration>>
2719 <<string eval function declaration>>
2720 <<string eval teardown declaration>>
2721 #endif /* STRING_EVAL_H */
2722
2723
2724 <<string eval module makefile lines>>=
2725 NW_SAWSIM_MODS += string_eval
2726 CHECK_BINS += check_string_eval
2727 check_string_eval_MODS = 
2728
2729
2730 For an introduction to POSIX process control, see\\
2731  \url{http://www.ibm.com/developerworks/aix/library/au-speakingunix8/} (very simple, but a good intro.), \\
2732  \url{http://www.ibm.com/developerworks/aix/library/au-unixprocess.html} (more detail),
2733  and of course, the relavent [[man]] pages.
2734
2735 We start our subprocess with [[execvp]], one of the [[exec]] family of functions.
2736 [[execvp]] replaces the calling process' program with a new program.
2737 The [[p]] in [[execvp]] signifies that the new program will be found by searching the the paths listed in the [[PATH]] environment variable
2738 (this may be a security hole if someone messes about with [[PATH]] before you run \prog,
2739  but if they had the ability to change [[PATH]], the security of \prog\ is the least of your worries).
2740 The new program needs command line arguments, just like it would if you were running it from a shell.
2741 The [[v]] in [[execvp]] signifies that these command line arguments will be provided as an array of [[NULL]] terminated strings,
2742 with the final array entry being a [[NULL]] pointer.
2743
2744 Now that we know how [[execvp]] works, we store it's arguments in some definitions,
2745 to make it easy to change the evaluating subprocess to, say, Ruby, or the users personal evaluation language.
2746 <<string eval subprocess definitions>>=
2747 #define SUBPROCESS "python"
2748 //#define SUBPROCESS_ARGS {SUBPROCESS, "-ic", "import sys;sys.ps1='';sys.ps2=''", (char *)NULL}
2749 static char *SUBPROCESS_ARGS[] = {SUBPROCESS, "-ic", "import sys;sys.ps1='';sys.ps2=''", (char *)NULL};
2750 //static char *SUBPROCESS_ARGS[] = {SUBPROCESS, "-ic", "pass", (char *)NULL};
2751
2752 The [[i]] option lets Python know that it should run in interactive mode.
2753 In it's standard mode, python reads all of the supplied instructions, and then acts on them in a single pass.
2754 In interactive mode, python acts on every instruction as soon as it is recieved.
2755 The [[c]] option signals a command line instruction for Python to execute on startup, which in our case simply turns off the default prompting ([[ps1]] and [[ps2]]), since that is mostly for human users, and our program doesn't need it. 
2756 %The [[c]] option signals a command line instruction for Python to execute on startup, which in our case simply [[pass]]es so that the silly Python header information is not printed.  We leave the prompts in, because we scan for them to determine when the output has completed.
2757
2758 Since the call to [[execvp]] replaces the calling program, we need to split out original program in half useing [[fork]].
2759 The parent half of the program can continue on to run our simulation, while the child half [[exec]]s and turns into Python.
2760 [[fork]] returns two copies of the same program, executing the original code.
2761 In the child process [[fork]] returns 0, and in the parent it returns the process ID of the child.
2762 We use this difference allows to write seperate parent/child code in the section immediately following the [[fork]].
2763
2764 We communicate with the child (Python) process using \emph{pipes}, with one process writing data into one end of the pipe, and the other process reading the data out of the other end.
2765 The [[pipe]] function creates an unnamed pipe, and returns the file descriptors for reading and writing into the new pipe.
2766 We need two pipes, one for the subprocess's [[stdin]] and one for its [[stdout]].
2767 We store the pipe file descriptors in an array of 4 [[int]]s, and use the following definitions for access.
2768 <<string eval pipe definitions>>=
2769 #define PIPE_READ  0   /* the end you read from */
2770 #define PIPE_WRITE 1   /* the end you write to */
2771
2772 #define STDIN      0   /* initial index of stdin pair  */
2773 #define STDOUT     2   /* initial index of stdout pair */
2774
2775
2776 So [[pfd[STDIN+PIPE_READ]]] is the file descriptor you would read from for the [[stdin]] pipe, and similarly for the other combinations.
2777
2778 As a finishing touch, we can promote the POSIX file descriptors ([[read]]/[[write]] interface) into the more familiar [[stdio.h]] \emph{streams} ([[fprintf]]/[[fgetc]] interface) using [[fdopen]], which creates a stream from an open file descriptor.
2779
2780 <<string eval setup declaration>>=
2781 extern void string_eval_setup(FILE **pIn, FILE **pOut);
2782
2783 <<string eval setup definition>>=
2784 void string_eval_setup(FILE **pIn, FILE **pOut)
2785 {
2786   pid_t pid;
2787   int pfd[4]; /* file descriptors for stdin and stdout */
2788   int rc;
2789   assert(pipe(pfd+STDIN)  != -1); /* stdin pair  (in, out) */
2790   assert(pipe(pfd+STDOUT) != -1); /* stdout pair (in, out) */
2791   
2792   pid = fork(); /* split process into two copies */
2793
2794   if (pid == -1) { /* fork error */
2795     perror("fork error");
2796     exit(1);
2797   } else if (pid == 0) { /* child */
2798     close(pfd[STDIN+PIPE_WRITE]); /* close stdin pipe input   */
2799     close(pfd[STDOUT+PIPE_READ]); /* close stdout pipe output */
2800     dup2(pfd[STDIN+PIPE_READ],0); /* wire stdin pipe output to stdin  (closes original stdin) */
2801     dup2(pfd[STDOUT+PIPE_WRITE],1); /* wire stdout pipe input to stdout (closes original stdout) */
2802     execvp(SUBPROCESS, SUBPROCESS_ARGS); /* run subprocess */
2803     perror("exec error"); /* exec shouldn't return */
2804     _exit(1);
2805   } else { /* parent */
2806     close(pfd[STDIN+PIPE_READ]);   /* close stdin pipe output */
2807     close(pfd[STDOUT+PIPE_WRITE]); /* close stdout pipe input */
2808     *pIn = fdopen(pfd[STDIN+PIPE_WRITE], "w"); /* 'upgrade' our file descriptors to streams */
2809     if ( *pIn == NULL ) {
2810       perror("fdopen (in)");
2811       exit(1);
2812     }
2813     *pOut = fdopen(pfd[STDOUT+PIPE_READ], "r");
2814     if ( *pOut == NULL ) {
2815       perror("fdopen (out)");
2816       exit(1);
2817     }
2818   }
2819 }
2820 @
2821
2822 To use the evaluating subprocess, we just pipe in our command, and read out the results.
2823 For the simple cases we expect here, we restrict ourselves to a single line of returned text.
2824 <<string eval function declaration>>=
2825 extern void string_eval(FILE *in, FILE *out, char *input, int buflen, char *output);
2826 @
2827 <<string eval function definition>>=
2828 void string_eval(FILE *in, FILE *out, char *input, int buflen, char *output)
2829 {
2830   int rc;
2831   rc = fprintf(in, "%s", input);
2832   assert(rc == strlen(input));
2833   fflush(in);
2834   fflush(out);
2835   alarm(1); /* set a one second timeout on the read */
2836   assert( fgets(output, buflen, out) != NULL );
2837   alarm(0); /* cancel the timeout */
2838   //fprintf(stderr, "eval: %s ----> %s", input, output);
2839 }
2840 @
2841 The [[alarm]] calls set and clear a timeout on the returned output.
2842 If the timeout expires, the process would get a [[SIGALRM]], but it doesn't have a [[SIGALRM]] handler, so it gets a [[SIGKILL]] and dies.
2843 This protects against invalid input for which a line of output is not printed to [[stdout]].
2844 Other invalid inputs (e.g. those generating multiple lines on [[stdout]] or a single line on [[stdout]] and more in [[stderr]]) are silently ignored.
2845 If you are getting strange results, check your python code seperately. TODO, better error handling.
2846
2847 Cleanup is fairly straightforward, we just close the connecting streams from the parent side.
2848 With the stdin pipe close on the parent side, the reading child will recive the broken pipe signal [[SIGPIPE]], and closes.
2849 The parent waits to confirm the child closing, recieves the child's exit status, and cleans up to prevent zombies.
2850 As an added touch, we redirect Python's [[stderr]] before closing the pipes, otherwise it prints a blank line when it exits.
2851 <<string eval teardown declaration>>=
2852 extern void string_eval_teardown(FILE **pIn, FILE **pOut);
2853
2854
2855 <<string eval teardown definition>>=
2856 void string_eval_teardown(FILE **pIn, FILE **pOut)
2857 {
2858   pid_t pid=0;
2859   int stat_loc;
2860
2861   /* redirect Python's stderr */
2862   fprintf(*pIn, "sys.stderr = open('/dev/null', 'w')\n");
2863   fflush(*pIn);
2864
2865   /* close pipes */
2866   assert( fclose(*pIn) == 0 );
2867   *pIn = NULL;
2868   assert( fclose(*pOut) == 0 );
2869   *pOut = NULL;
2870
2871   /* wait for python to exit */
2872   while (pid <= 0) {
2873     pid = wait(&stat_loc);
2874     if (pid < 0) {
2875       perror("pid");
2876     }
2877   }
2878
2879   /*
2880   if (WIFEXITED(stat_loc)) {
2881     printf("child exited with status %d\n", WEXITSTATUS(stat_loc));
2882   } else if (WIFSIGNALED(stat_loc)) {
2883     printf("child terminated with signal %d\n", WTERMSIG(stat_loc));
2884   }
2885   */
2886 }
2887
2888 The [[while]] loop around [[wait]] protects [[wait]] from interrupting signals.
2889
2890 \subsection{String evaluation implementation}
2891
2892 <<string-eval.c>>=
2893 <<license comment>>
2894 <<string eval includes>>
2895 #include "string_eval.h"
2896 <<string eval internal definitions>>
2897 <<string eval functions>>
2898
2899
2900 <<string eval includes>>=
2901 #include <assert.h> /* assert()                    */
2902 #include <stdlib.h> /* NULL                        */
2903 #include <stdio.h>  /* fprintf(), stdout, fdopen() */
2904 #include <string.h> /* strlen()                    */
2905 #include <sys/types.h> /* pid_t                    */
2906 #include <unistd.h> /* pipe(), fork(), execvp(), alarm()    */
2907 #include <wait.h>   /* wait()                      */
2908
2909
2910 <<string eval internal definitions>>=
2911 <<string eval subprocess definitions>>
2912 <<string eval pipe definitions>>
2913
2914
2915 <<string eval functions>>=
2916 <<string eval setup definition>>
2917 <<string eval function definition>>
2918 <<string eval teardown definition>>
2919
2920
2921 \subsection{String evaluation unit tests}
2922
2923 Here we check to make sure the various functions work as expected, using \citetalias{sw:check}.
2924 <<check-string-eval.c>>=
2925 <<string eval check includes>>
2926 <<string comparison definition and globals>>
2927 <<string eval test suite>>
2928 <<main check program>>
2929
2930
2931 <<string eval check includes>>=
2932 #include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE, atof() */
2933 #include <stdio.h>  /* printf()                              */
2934 #include <assert.h> /* assert()                              */
2935 #include <string.h> /* strlen()                              */
2936 #include <signal.h> /* SIGKILL                               */
2937 <<check includes>>
2938 #include "string_eval.h"
2939
2940
2941 <<string eval test suite>>=
2942 <<string eval tests>>
2943 <<string eval suite definition>>
2944
2945
2946 <<string eval suite definition>>=
2947 Suite *test_suite (void)
2948 {
2949   Suite *s = suite_create ("string eval");
2950   <<string eval test case defs>>
2951
2952   <<string eval test case add>>
2953   return s;
2954 }
2955
2956
2957 <<string eval tests>>=
2958 START_TEST(test_setup_teardown)
2959 {
2960   FILE *in, *out;
2961   string_eval_setup(&in, &out);
2962   string_eval_teardown(&in, &out);
2963 }
2964 END_TEST
2965 START_TEST(test_invalid_command)
2966 {
2967   FILE *in, *out;
2968   char input[80], output[80]={};
2969   string_eval_setup(&in, &out);
2970   sprintf(input, "print ABCDefg\n");
2971   string_eval(in, out, input, 80, output); 
2972   string_eval_teardown(&in, &out);
2973 }
2974 END_TEST
2975 START_TEST(test_simple_eval)
2976 {
2977   FILE *in, *out;
2978   char input[80], output[80]={};
2979   string_eval_setup(&in, &out);
2980   sprintf(input, "print 3+4*5\n");
2981   string_eval(in, out, input, 80, output); 
2982   fail_unless(STRMATCH(output,"23\n"), NULL);
2983   string_eval_teardown(&in, &out);
2984 }
2985 END_TEST
2986 START_TEST(test_multiple_evals)
2987 {
2988   FILE *in, *out;
2989   char input[80], output[80]={};
2990   string_eval_setup(&in, &out);
2991   sprintf(input, "print 3+4*5\n");
2992   string_eval(in, out, input, 80, output); 
2993   fail_unless(STRMATCH(output,"23\n"), NULL);
2994   sprintf(input, "print (3**2 + 4**2)**0.5\n");
2995   string_eval(in, out, input, 80, output); 
2996   fail_unless(STRMATCH(output,"5.0\n"), NULL);
2997   string_eval_teardown(&in, &out);
2998 }
2999 END_TEST
3000 START_TEST(test_eval_with_state)
3001 {
3002   FILE *in, *out;
3003   char input[80], output[80]={};
3004   string_eval_setup(&in, &out);
3005   sprintf(input, "print 3+4*5\n");
3006   fprintf(in, "A = 3\n");
3007   sprintf(input, "print A*3\n");
3008   string_eval(in, out, input, 80, output); 
3009   fail_unless(STRMATCH(output,"9\n"), NULL);
3010   string_eval_teardown(&in, &out);
3011 }
3012 END_TEST
3013 @
3014 <<string eval test case defs>>=
3015 TCase *tc_string_eval = tcase_create("string_eval");
3016 @
3017 <<string eval test case add>>=
3018 tcase_add_test(tc_string_eval, test_setup_teardown);
3019 tcase_add_test_raise_signal(tc_string_eval, test_invalid_command, SIGKILL);
3020 tcase_add_test(tc_string_eval, test_simple_eval);
3021 tcase_add_test(tc_string_eval, test_multiple_evals);
3022 tcase_add_test(tc_string_eval, test_eval_with_state);
3023 suite_add_tcase(s, tc_string_eval);
3024 @
3025
3026
3027 \section{Accelerating function evaluation}
3028
3029 My first version-0.3 code was running very slowly.
3030 With the options suggested in the help 
3031 ([[-v1e-6 -Mhooke -A.05 -U1 -kbell -K3.3e-4,.25e-9 -mnull -Mwlc -A0.39e-9,28e-9 -F8]]), 
3032 the program spent almost all of it's time in the functions [[oneD_solve]], [[wlc]], and [[wlc_handler]],
3033 making 0.66 million calls to [[oneD_solve]] and [[9.6]] million calls each to the WLC functions.
3034 That's only 15 calls per solution, so the search algorithm seems reasonable.
3035 The number of evaluation calls could be drastically reduced, however, by implementing an $x(x_0)$ lookup table.
3036
3037 <<accel-k.h>>=
3038 #ifndef ACCEL_K_H
3039 #define ACCEL_K_H
3040 double accel_k(k_func_t *k, double F, environment_t *env, void *params);
3041 void free_accels();
3042 #endif /* ACCEL_K_H */
3043
3044
3045 <<accel k module makefile lines>>=
3046 NW_SAWSIM_MODS += accel_k
3047 #CHECK_BINS += check_accel_k
3048 check_accel_k_MODS =  
3049
3050
3051 <<accel-k.c>>=
3052 #include <assert.h>  /* assert()                */
3053 #include <stdlib.h>  /* realloc(), free(), NULL */
3054 #include "global.h"  /* environment_t           */
3055 #include "k_model.h" /* k_func_t                */
3056 #include "interp.h"  /* interp_*                */
3057 #include "accel_k.h"
3058
3059 typedef struct accel_k_struct {
3060   interp_table_t *itable;
3061   k_func_t *k;
3062   environment_t *env;
3063   void *params;
3064 } accel_k_t;
3065
3066 /* keep an array of all the ks we accelerate, so the caller doesn't have to worry */
3067 static int num_accels = 0;
3068 static accel_k_t *accels=NULL;
3069
3070 /* Wrap k in the standard f(x) acceleration form */
3071 static double k_wrap(double F, void *params)
3072 {
3073   accel_k_t *p = (accel_k_t *)params;
3074   return (*p->k)(F, p->env, p->params);
3075 }
3076
3077 static int k_tol(double FA, double kA, double FB, double kB)
3078 {
3079   assert(FB > FA);
3080   if (FB-FA > 1e-12) {
3081     //printf("unacceptable tol (x %g > 1 (y %g)\n", fabs(xA-xB), fabs(yA-yB));
3082     return 1; /* unnacceptable */
3083   } else {
3084     //printf("acceptable tol\n");
3085     return 0; /* acceptable */
3086   }
3087 }
3088
3089 static int add_accel_k(k_func_t *k, environment_t *env, void *params)
3090 {
3091   int i=num_accels;
3092   accels = (accel_k_t *)realloc(accels, sizeof(accel_k_t) * ++num_accels);
3093   assert(accels != NULL);  
3094   accels[i].itable = interp_table_allocate(&k_wrap, &k_tol);
3095   accels[i].k = k;
3096   accels[i].env = env;
3097   accels[i].params = params;
3098   return i;
3099 }
3100
3101 void free_accels()
3102 {
3103   int i;
3104   for (i=0; i<num_accels; i++)
3105     interp_table_free(accels[i].itable);
3106   num_accels=0;
3107   if (accels) free(accels);
3108   accels = NULL;
3109 }
3110
3111 double accel_k(k_func_t *k, double F, environment_t *env, void *params)
3112 {
3113   int i;
3114   for (i=0; i<num_accels; i++) {
3115     if (accels[i].k == k && accels[i].env == env && accels[i].params == params) {
3116       /* We've already setup this function.
3117        * WARNING: we're assuming param and env are the same. */
3118       return interp_table_eval(accels[i].itable, accels+i, F);
3119     }
3120   }      
3121   /* set up a new acceleration environment */
3122   i = add_accel_k(k, env, params);
3123   return interp_table_eval(accels[i].itable, accels+i, F);
3124 }
3125
3126
3127 \section{Tension models}
3128 \label{sec.tension_models}
3129
3130 TODO: tension model intro.
3131 See \url{http://web.mit.edu/course/3/3.11/www/pset03/Rec9.pdf} for a quick introduction to worm-like and freely-jointed chain models.
3132
3133 Because these models are independent of the rest of the simulation, we'll split their definitions out into their own set of files.
3134 The interface is defined in [[tension_model.h]], the implementation in [[tension_model.c]], the unit testing in [[check_k_model.c]], and some other tidbits in [[tension_model_utils.c]].
3135
3136 <<tension-model.h>>=
3137 #ifndef TENSION_MODEL_H
3138 #define TENSION_MODEL_H
3139 <<license comment>>
3140 <<tension handler types>>
3141 <<constant tension model declarations>>
3142 <<hooke tension model declarations>>
3143 <<worm-like chain tension model declarations>>
3144 <<freely-jointed chain tension model declarations>>
3145 <<find tension definitions>>
3146 <<tension model global declarations>>
3147 #endif /* TENSION_MODEL_H */
3148
3149
3150 <<tension model module makefile lines>>=
3151 NW_SAWSIM_MODS += tension_model
3152 #CHECK_BINS += check_tension_model
3153 check_tension_model_MODS = 
3154
3155 <<tension model utils makefile lines>>=
3156 TENSION_MODEL_MODS = tension_model parse list tension_balance
3157 TENSION_MODEL_SRC = $(BUILD_DIR)/tension_model_utils.c $(BUILD_DIR)/global.h \
3158         $(TENSION_MODEL_MODS:%=$(BUILD_DIR)/%.c) \
3159         $(TENSION_MODEL_MODS:%=$(BUILD_DIR)/%.h)
3160 $(BUILD_DIR)/tension_model_utils.c : $(SRC_DIR)/sawsim.nw | $(BUILD_DIR)
3161         notangle -Rtension-model-utils.c $< > $@
3162 $(BIN_DIR)/tension_model_utils : $(TENSION_MODEL_SRC) | $(BIN_DIR)
3163         gcc -g -o $@ $< $(TENSION_MODEL_MODS:%=$(BUILD_DIR)/%.c) $(LIBS:%=-l%)
3164 clean_tension_model_utils :
3165         rm -f $(BUILD_DIR)/tension_model_utils.c $(BIN_DIR)/tension_model_utils
3166 @ The pipe symbol [[|]] marks the prerequisits following it (in this
3167 case, the directories) as ‘order-only’ prerequisites.  The timestamp
3168 on these prerequisits does not effect whether the rules are executed.
3169 This is appropriate for directories, where we don't need to recompile
3170 after an unrelated has been added to the directory, but only when the
3171 source prerequisites change.  See the [[make]] documentation for more
3172 details
3173 (\url{http://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html}).
3174
3175 \subsection{Null}
3176 \label{sec.null_tension}
3177
3178 For unstretchable domains.
3179
3180 <<null tension model getopt>>=
3181 {NULL, "null", "an unstretchable domain", 0, NULL, NULL, NULL, NULL}
3182
3183
3184 \subsection{Constant}
3185 \label{sec.const_tension}
3186
3187 <<constant tension functions>>=
3188 <<constant tension function>>
3189 <<constant tension parameter create/destroy functions>>
3190
3191
3192 <<constant tension model declarations>>=
3193 <<constant tension function declaration>>
3194 <<constant tension parameter create/destroy function declarations>>
3195 <<constant tension model global declarations>>
3196
3197
3198
3199 An infinitely stretchable domain providing a constant tension.
3200
3201 <<constant tension function declaration>>=
3202 extern double const_tension_handler(double x, void *pdata);
3203
3204 <<constant tension function>>=
3205 double const_tension_handler(double x, void *pdata)
3206 {
3207   tension_handler_data_t *data = (tension_handler_data_t *)pdata;
3208   list_t *list = data->group;
3209   double F;
3210
3211   assert (x >= 0.0);
3212   list = head(list);
3213   assert(list != NULL); /* empty active group?! */
3214   F = ((const_tension_param_t *)list->d)->F;
3215 #ifdef DEBUG
3216   fprintf(stderr, "%s: tension %g N\n", __FUNCTION__, F);
3217 #endif
3218   while (list != NULL) {
3219     assert(((const_tension_param_t *)list->d)->F == F);
3220     list = list->next;
3221   }
3222   return F;
3223 }
3224
3225
3226
3227 <<constant tension structure>>=
3228 typedef struct const_tension_param_struct {
3229   double F; /* tension (force) in N */
3230 } const_tension_param_t;
3231
3232
3233
3234 <<constant tension parameter create/destroy function declarations>>=
3235 extern void *string_create_const_tension_param_t(char **param_strings);
3236 extern void destroy_const_tension_param_t(void *p);
3237
3238
3239 <<constant tension parameter create/destroy functions>>=
3240 const_tension_param_t *create_const_tension_param_t(double F)
3241 {
3242   const_tension_param_t *ret
3243     = (const_tension_param_t *) malloc(sizeof(const_tension_param_t));
3244   assert(ret != NULL);
3245   ret->F = F;
3246   return ret;
3247 }
3248
3249 void *string_create_const_tension_param_t(char **param_strings)
3250 {
3251   return create_const_tension_param_t(atof(param_strings[0]));
3252 }
3253
3254 void destroy_const_tension_param_t(void *p)
3255 {
3256   if (p)
3257     free(p);
3258 }
3259
3260 @
3261
3262 <<constant tension model global declarations>>=
3263 extern int num_const_tension_params;
3264 extern char *const_tension_param_descriptions[];
3265 extern char const_tension_param_string[];
3266
3267
3268 <<constant tension model globals>>=
3269 int num_const_tension_params = 1;
3270 char *const_tension_param_descriptions[] = {"tension F, N"};
3271 char const_tension_param_string[] = "0";
3272
3273
3274 <<constant tension model getopt>>=
3275 {&const_tension_handler, "const", "an infinitely stretchable domain with constant tension", 1, const_tension_param_descriptions, const_tension_param_string, &string_create_const_tension_param_t, &destroy_const_tension_param_t}
3276
3277
3278 \subsection{Hooke}
3279 \label{sec.hooke}
3280
3281 <<hooke functions>>=
3282 <<hooke function>>
3283 <<hooke parameter create/destroy functions>>
3284
3285
3286 <<hooke tension model declarations>>=
3287 <<hooke tension function declaration>>
3288 <<hooke tension parameter create/destroy function declarations>>
3289 <<hooke tension model global declarations>>
3290
3291
3292
3293 The tension of a single spring is given by $F=kx$ for some spring constant $k$.
3294 The behavior of a series of springs $k_i$ in series is given by
3295 $$
3296   F = \p({\sum_i \frac{1}{k_i}})^{-1} x
3297 $$
3298 For a simple proof, see Appendix \ref{app.math_hooke}.
3299
3300 <<hooke tension function declaration>>=
3301 extern double hooke_handler(double x, void *pdata);
3302
3303
3304 <<hooke function>>=
3305 double hooke_handler(double x, void *pdata)
3306 {
3307   tension_handler_data_t *data = (tension_handler_data_t *)pdata;
3308   list_t *list = data->group;
3309   double k=0.0;
3310
3311   assert (x >= 0.0);
3312   list = head(list);
3313   assert(list != NULL); /* empty active group?! */
3314   while (list != NULL) {
3315     assert( ((hooke_param_t *)list->d)->k > 0 );
3316     k += 1.0/ ((hooke_param_t *)list->d)->k;
3317 #ifdef DEBUG
3318     fprintf(stderr, "%s: Hooke spring %g N/m in series\n",
3319             __FUNCTION__, ((hooke_param_t *)list->d)->k);
3320 #endif
3321     list = list->next;
3322   }
3323   k = 1.0 / k;
3324 #ifdef DEBUG
3325   fprintf(stderr, "%s: effective Hooke spring %g N/m at %g m -> F = %g N\n",
3326           __FUNCTION__, k, x, k*x);
3327 #endif
3328   return k*x;
3329 }
3330
3331
3332 <<hooke structure>>=
3333 typedef struct hooke_param_struct {
3334   double k; /* spring constant in N/m */
3335 } hooke_param_t;
3336
3337
3338 <<hooke tension parameter create/destroy function declarations>>=
3339 extern void *string_create_hooke_param_t(char **param_strings);
3340 extern void destroy_hooke_param_t(void *p);
3341
3342
3343 <<hooke parameter create/destroy functions>>=
3344 hooke_param_t *create_hooke_param_t(double k)
3345 {
3346   hooke_param_t *ret = (hooke_param_t *) malloc(sizeof(hooke_param_t));
3347   assert(ret != NULL);
3348   ret->k = k;
3349   return ret;
3350 }
3351
3352 void *string_create_hooke_param_t(char **param_strings)
3353 {
3354   return create_hooke_param_t(atof(param_strings[0]));
3355 }
3356
3357 void destroy_hooke_param_t(void *p)
3358 {
3359   if (p)
3360     free(p);
3361 }
3362 @
3363
3364 <<hooke tension model global declarations>>=
3365 extern int num_hooke_params;
3366 extern char *hooke_param_descriptions[];
3367 extern char hooke_param_string[];
3368
3369
3370 <<hooke tension model globals>>=
3371 int num_hooke_params = 1;
3372 char *hooke_param_descriptions[] = {"spring constant k, N/m"};
3373 char hooke_param_string[]="0.05";
3374
3375
3376 <<hooke tension model getopt>>=
3377 {hooke_handler, "hooke", "a Hookean spring (F=kx)", num_hooke_params, hooke_param_descriptions, (char *)hooke_param_string, &string_create_hooke_param_t, &destroy_hooke_param_t}
3378
3379
3380 \subsection{Worm-like chain}
3381 \label{sec.wlc}
3382
3383 We can model several unfolded domains with a single worm-like chain.
3384 <<worm-like chain functions>>=
3385 <<worm-like chain function>>
3386 <<worm-like chain handler>>
3387 <<worm-like chain create/destroy functions>>
3388
3389
3390 <<worm-like chain tension model declarations>>=
3391 <<worm-like chain handler declaration>>
3392 <<worm-like chain create/destroy function declarations>>
3393 <<worm-like chain tension model global declarations>>
3394
3395
3396
3397 The combination of all unfolded domains is modeled as a worm like chain,
3398 with the force $F_{\text{WLC}}$ approximately given by
3399 $$
3400   F_{\text{WLC}} \approx \frac{k_B T}{p}
3401                \p[{\frac{1}{4} \p({\frac{1}{(1-x/L)^2} - 1}) +\frac{x}{L}}],
3402 $$
3403 where $x$ is the distance between the fixed ends,
3404 $k_B$ is Boltzmann's constant,
3405 $T$ is the absolute temperature,
3406 $p$ is the persistence length, and
3407 $L$ is the total contour length of all unfolded domains\citep{bustamante94,marko95,hatfield99}.
3408 <<worm-like chain function>>=
3409 double wlc(double x, double T, double p, double L)
3410 {/* N             m         K         m         m */ 
3411   double xL=0.0;               /* uses global k_B */
3412   assert(x >= 0);
3413   assert(T > 0); assert(p > 0); assert(L > 0);
3414   if (x >= L) return HUGE_VAL;
3415   xL = x/L; /* unitless */
3416   //printf("T %g\tp %g\tL %g\tx/L %g\tk %g\n", T, p, L, x/L,
3417   //       k_B*T/p * ( 0.25*(1.0/((1-xL)*(1-xL))-1) + xL ));
3418   return k_B*T/p * ( 0.25*(1.0/((1-xL)*(1-xL))-1) + xL );
3419 }
3420
3421 This model assumes that each unfolded domain has the same persistence length.
3422
3423 <<worm-like chain handler declaration>>=
3424 extern double wlc_handler(double x, void *pdata);
3425
3426
3427 <<worm-like chain handler>>=
3428 double wlc_handler(double x, void *pdata)
3429 {
3430   tension_handler_data_t *data = (tension_handler_data_t *)pdata;
3431   list_t *list = data->group;
3432   double p, L=0.0;
3433
3434   list = head(list);
3435   assert(list != NULL); /* empty active group?! */
3436   p = ((wlc_param_t *)list->d)->p;
3437   while (list != NULL) {
3438     /* enforce consistent p */
3439     assert( ((wlc_param_t *)list->d)->p == p);
3440     L += ((wlc_param_t *)list->d)->L;
3441 #ifdef DEBUG
3442     fprintf(stderr, "%s: WLC section %g m long in series\n",
3443             __FUNCTION__, ((wlc_param_t *)list->d)->L);
3444 #endif
3445     list = list->next;
3446   }
3447 #ifdef DEBUG
3448   fprintf(stderr, "%s: WLC(x=%g m, T=%g K, p=%g m, L=%g m) = %g N\n",
3449           __FUNCTION__, x, data->env->T, p, L, wlc(x, data->env->T, p, L));
3450 #endif
3451   return wlc(x, data->env->T, p, L);
3452 }
3453
3454
3455 <<worm-like chain structure>>=
3456 typedef struct wlc_param_struct {
3457   double p;      /* WLC persistence length (m) */
3458   double L;      /* WLC contour length (m)     */
3459 } wlc_param_t;
3460
3461
3462 <<worm-like chain create/destroy function declarations>>=
3463 extern void *string_create_wlc_param_t(char **param_strings);
3464 extern void destroy_wlc_param_t(void *p /* wlc_param_t * */);
3465
3466
3467 <<worm-like chain create/destroy functions>>=
3468 wlc_param_t *create_wlc_param_t(double p, double L)
3469 {
3470   wlc_param_t *ret = (wlc_param_t *) malloc(sizeof(wlc_param_t));
3471   assert(ret != NULL);
3472   ret->p = p;
3473   ret->L = L;
3474   return ret;
3475 }
3476
3477 void *string_create_wlc_param_t(char **param_strings)
3478 {
3479   return create_wlc_param_t(atof(param_strings[0]), atof(param_strings[1]));
3480 }
3481
3482 void destroy_wlc_param_t(void *p /* wlc_param_t * */)
3483 {
3484   if (p)
3485     free(p);
3486 }
3487 @
3488
3489 We define [[wlc_param_string]] as a global array because hard-coding the values into the tension model getopt structure gives a read-only version.
3490 TODO (now we copy the string before parsing, but still do this for clarity).
3491 For example,
3492 <<valid string write code>>=
3493 char string[] = "abc";
3494 string[1] = 'x';
3495 @ works, but
3496 <<valid string write code>>=
3497 char *string = "abc";
3498 string[1] = 'x';
3499 @ segfaults.
3500
3501 <<worm-like chain tension model global declarations>>=
3502 extern int num_wlc_params;
3503 extern char *wlc_param_descriptions[];
3504 extern char wlc_param_string[];
3505
3506 <<worm-like chain tension model globals>>=
3507 int num_wlc_params = 2;
3508 char *wlc_param_descriptions[] = {"persistence length p, m", "contour length L, m"};
3509 char wlc_param_string[]="0.39e-9,28.4e-9";
3510
3511
3512 <<worm-like chain tension model getopt>>=
3513 {wlc_handler, "wlc", "a worm-like chain (F=kbT/p{.25[(1-x/L)^-2 -1] + x/L})", num_wlc_params, wlc_param_descriptions, (char *)wlc_param_string, &string_create_wlc_param_t, &destroy_wlc_param_t}
3514
3515 Titin parameters from Carrion-Vazquez 1999, PNAS USA 96, 3696.
3516
3517 \subsection{Freely-jointed chain}
3518 \label{sec.fjc}
3519
3520 <<freely-jointed chain functions>>=
3521 <<freely-jointed chain function>>
3522 <<freely-jointed chain handler>>
3523 <<freely-jointed chain create/destroy functions>>
3524
3525
3526 <<freely-jointed chain tension model declarations>>=
3527 <<freely-jointed chain handler declaration>>
3528 <<freely-jointed chain create/destroy function declarations>>
3529 <<freely-jointed chain tension model global declarations>>
3530
3531
3532
3533 The freely jointed chain model approximates the protein as a series of rigid links of length $l$ with freely rotating joints.
3534 The tension of a chain of $N$ such links is given by
3535 $$
3536   F(x) = \frac{k_B T}{l} \mathcal{L}^{-1}\p({\frac{x}{L}}) \;,
3537 $$
3538 where $L=Nl$ is the total length of the chain, and $\mathcal{L}(\alpha) \equiv \coth{\alpha} - \frac{1}{\alpha}$ is the Langevin function\citep{hatfield99}.
3539 <<freely-jointed chain function>>=
3540 double langevin(double x, void *params)
3541 {
3542   if (x==0) return 0;
3543   return 1.0/tanh(x) - 1/x;
3544 }
3545 <<one dimensional bracket declaration>>
3546 <<one dimensional solve declaration>>
3547 double inv_langevin(double x)
3548 {
3549   double lb=0.0, ub=1.0, ret;
3550   oneD_bracket(&langevin, NULL, x, 1.0, &lb, &ub);
3551   ret = oneD_solve(&langevin, NULL, x, lb, ub, 1e-6, 1e-6, 300, NULL); /* TODO, break out oneD_* to own file */
3552   return ret;
3553 }
3554
3555 double fjc(double x, double T, double l, int N)
3556 {
3557   double L = l*(double)N;
3558   if (x == 0) return 0;
3559   //printf("x %g\tL%g\tx/L %g\n", x, L, x/L);
3560   return k_B*T/l * inv_langevin(x/L);
3561 }
3562
3563
3564 <<freely-jointed chain handler declaration>>=
3565 extern double fjc_handler(double x, void *pdata);
3566
3567 <<freely-jointed chain handler>>=
3568 double fjc_handler(double x, void *pdata)
3569 {
3570   tension_handler_data_t *data = (tension_handler_data_t *)pdata;
3571   list_t *list = data->group;
3572   double l;
3573   int N=0;
3574
3575   list = head(list);
3576   assert(list != NULL); /* empty active group?! */
3577   l = ((fjc_param_t *)list->d)->l;
3578   while (list != NULL) {
3579     /* enforce consistent l */
3580     assert( ((fjc_param_t *)list->d)->l == l);
3581     N += ((fjc_param_t *)list->d)->N;
3582 #ifdef DEBUG
3583     fprintf(stderr, "%s: FJC section %d links long in series\n",
3584             __FUNCTION__, ((fjc_param_t *)list->d)->N);
3585 #endif
3586     list = list->next;
3587   }
3588 #ifdef DEBUG
3589   fprintf(stderr, "%s: FJC(x=%g m, T=%g K, l=%g m, N=%d m) = %g N\n",
3590           __FUNCTION__, x, data->env->T, l, N, fjc(x, data->env->T, l, N));
3591 #endif
3592   return fjc(x, data->env->T, l, N);
3593 }
3594
3595
3596 <<freely-jointed chain structure>>=
3597 typedef struct fjc_param_struct {
3598   double l;      /* FJC link length (m) */
3599   int N;         /* FJC number of links */
3600 } fjc_param_t;
3601
3602
3603 <<freely-jointed chain create/destroy function declarations>>=
3604 extern void *string_create_fjc_param_t(char **param_strings);
3605 extern void destroy_fjc_param_t(void *p);
3606
3607
3608 <<freely-jointed chain create/destroy functions>>=
3609 fjc_param_t *create_fjc_param_t(double l, double N)
3610 {
3611   fjc_param_t *ret = (fjc_param_t *) malloc(sizeof(fjc_param_t));
3612   assert(ret != NULL);
3613   ret->l = l;
3614   ret->N = N;
3615   return ret;
3616 }
3617
3618 void *string_create_fjc_param_t(char **param_strings)
3619 {
3620   return create_fjc_param_t(atof(param_strings[0]), atof(param_strings[1]));
3621 }
3622
3623 void destroy_fjc_param_t(void *p)
3624 {
3625   if (p)
3626     free(p);
3627 }
3628
3629
3630 <<freely-jointed chain tension model global declarations>>=
3631 extern int num_fjc_params;
3632 extern char *fjc_param_descriptions[];
3633 extern char fjc_param_string[];
3634
3635
3636 <<freely-jointed chain tension model globals>>=
3637 int num_fjc_params = 2;
3638 char *fjc_param_descriptions[] = {"link length l, m", "link count N, unitless integer"};
3639 char fjc_param_string[]="0.5e-9,200";
3640
3641
3642 <<freely-jointed chain tension model getopt>>=
3643 {fjc_handler, "fjc", "a freely-jointed chain [F=kbT/l L^-1(x/L)]", num_fjc_params, fjc_param_descriptions, (char *)fjc_param_string, &string_create_fjc_param_t, &destroy_fjc_param_t}
3644
3645
3646 \subsection{Tension model implementation}
3647
3648 <<tension-model.c>>=
3649 //#define DEBUG
3650 <<license comment>>
3651 <<tension model includes>>
3652 #include "tension_model.h"
3653 <<tension model internal definitions>>
3654 <<tension model globals>>
3655 <<tension model functions>>
3656
3657
3658 <<tension model includes>>=
3659 #include <assert.h> /* assert()                */
3660 #include <stdlib.h> /* NULL                    */
3661 #include <math.h>   /* HUGE_VAL, sqrt(), exp() */
3662 #include <stdio.h>  /* fprintf(), stdout       */
3663 #include "global.h"
3664 #include "list.h"
3665 #include "tension_balance.h" /* oneD_*() */
3666
3667
3668 <<tension model internal definitions>>=
3669 <<constant tension structure>>
3670 <<hooke structure>>
3671 <<worm-like chain structure>>
3672 <<freely-jointed chain structure>>
3673
3674
3675 <<tension model globals>>=
3676 <<tension handler array global>>
3677 <<constant tension model globals>>
3678 <<hooke tension model globals>>
3679 <<worm-like chain tension model globals>>
3680 <<freely-jointed chain tension model globals>>
3681
3682
3683 <<tension model functions>>=
3684 <<constant tension functions>>
3685 <<hooke functions>>
3686 <<worm-like chain functions>>
3687 <<freely-jointed chain functions>>
3688
3689
3690
3691 \subsection{Utilities}
3692
3693 The tension models can get complicated, and users may want to reassure
3694 themselves that this portion of the input physics are functioning properly. The
3695 stand-alone program [[tension_model_utils]] demonstrates the tension model
3696 interface without the overhead of having to understand a full simulation.
3697 [[tension_model_utils]] takes command line model arguments like the full
3698 simulation, and prints $F(x)$ data to the screen for the selected model over a
3699 range of $x$.
3700
3701 <<tension-model-utils.c>>=
3702 <<license comment>>
3703 <<tension model utility includes>>
3704 <<tension model utility definitions>>
3705 <<tension model utility getopt functions>>
3706 <<setup>>
3707 <<tension model utility main>>
3708
3709
3710 <<tension model utility main>>=
3711 int main(int argc, char **argv)
3712 {
3713   <<tension model getopt array definition>>
3714   tension_model_getopt_t *model = NULL;
3715   void *params;
3716   environment_t env;
3717   unsigned int flags;
3718   one_dim_fn_t *tension_handler[NUM_TENSION_MODELS] = {0};
3719   tension_handler_data_t tdata;
3720   int num_param_args; /* for INIT_MODEL() */
3721   char **param_args;  /* for INIT_MODEL() */
3722   double Fmax,Xmax;
3723   get_options(argc, argv, &env, NUM_TENSION_MODELS, tension_models, &model,
3724               &Fmax, &Xmax, &flags);
3725   setup();
3726   if (flags & VFLAG) {
3727     printf("#initializing model %s with parameters %s\n", model->name, model->params);
3728   }
3729   INIT_MODEL("utility", model, model->params, params);
3730   tdata.group = NULL;
3731   push(&tdata.group, params, 1);
3732   tdata.env = &env;
3733   tdata.persist = NULL;
3734   if (model->handler == NULL) {
3735     printf("No tension function for model %s\n", model->name);
3736     exit(0);
3737   }
3738   {
3739     int i,N=200;
3740     double x=0, F=0;
3741     printf("#Distance (m)\tForce (N)\n");
3742     for (i=0; i<=N; i++) {
3743       x = Xmax*i/(double)N;
3744       F = (*model->handler)(x, &tdata);
3745       if (F < 0 || F > Fmax) break;
3746       printf("%g\t%g\n", x, F);
3747     }
3748   }
3749   params = pop(&tdata.group);
3750   if (model->destructor)
3751     (*model->destructor)(params);
3752   return 0;
3753 }
3754
3755
3756 <<tension model utility includes>>=
3757 #include <stdlib.h>
3758 #include <stdio.h>
3759 #include <string.h> /* strlen() */
3760 #include <assert.h> /* assert() */
3761 #include "global.h"
3762 #include "parse.h"
3763 #include "list.h"
3764 #include "tension_model.h"
3765
3766
3767 <<tension model utility definitions>>=
3768 <<version definition>>
3769 #define VFLAG 1 /* verbose */
3770 <<string comparison definition and globals>>
3771 <<tension model getopt definitions>>
3772 <<initialize model definition>>
3773
3774
3775
3776 <<tension model utility getopt functions>>=
3777 <<index tension model>>
3778 <<tension model utility help>>
3779 <<tension model utility get options>>
3780
3781
3782 <<tension model utility help>>=
3783 void help(char *prog_name,
3784           environment_t *env,
3785           int n_tension_models, tension_model_getopt_t *tension_models,
3786           int tension_model, double Fmax, double Xmax)
3787 {
3788   int i, j;
3789   printf("usage: %s [options]\n", prog_name);
3790   printf("Version %s\n\n", VERSION);
3791   printf("A utility for understanding the available tension models\n\n");
3792   printf("Environmental options:\n");
3793   printf("-T T\tTemperature T (currently %g K)\n", env->T);
3794   printf("-C T\tYou can also set the temperature T in Celsius\n");
3795   printf("Model options:\n");
3796   printf("-m model\tFolded tension model (currently %s)\n",
3797          tension_models[tension_model].name);
3798   printf("-a args\tFolded tension model argument string (currently %s)\n",
3799          tension_models[tension_model].params);
3800   printf("F(x) is calculated for a range of x and printed\n");
3801   printf("For example:\n");
3802   printf("  #Distance (m)\tForce (N)\n");
3803   printf("  123.456\t7.89\n");
3804   printf("  ...\n");
3805   printf("-F\tSet the maximum F value for the standard mode F(x) output (currently %g)\n", Fmax);
3806   printf("-X\tSet the maximum x value for the standard mode F(x) output (currently %g)\n", Xmax);
3807   printf("-V\tChange output to verbose mode\n");
3808   printf("-h\tPrint this help and exit\n");
3809   printf("\n");
3810   printf("Tension models:\n");
3811   for (i=0; i<n_tension_models; i++) {
3812     printf("\t%s\t%s\n", tension_models[i].name, tension_models[i].description);
3813     for (j=0; j < tension_models[i].num_params ; j++)
3814       printf("\t\t\t%s\n", tension_models[i].param_descriptions[j]);
3815     printf("\t\tdefaults: %s\n", tension_models[i].params);
3816   }
3817 }
3818
3819
3820 <<tension model utility get options>>=
3821 void get_options(int argc, char **argv, environment_t *env,
3822                  int n_tension_models, tension_model_getopt_t *tension_models,
3823                  tension_model_getopt_t **model, double *Fmax, double *Xmax,
3824                  unsigned int *flags)
3825 {
3826   char *prog_name = NULL;
3827   char c, options[] = "T:C:m:a:F:X:Vh";
3828   int tension_model=0, num_strings;
3829   extern char *optarg;
3830   extern int optind, optopt, opterr;
3831
3832   assert (argc > 0);
3833
3834   /* setup defaults */
3835
3836   prog_name = argv[0];
3837   env->T = 300.0;   /* K           */
3838   *Fmax = 1e5;
3839   *Xmax = 1e-6;
3840   *flags = 0;
3841   *model = tension_models;
3842
3843   while ((c=getopt(argc, argv, options)) != -1) {
3844     switch(c) {
3845     case 'T':  env->T   = atof(optarg);           break;
3846     case 'C':  env->T   = atof(optarg)+273.15;    break;
3847     case 'm':
3848       tension_model = index_tension_model(n_tension_models, tension_models, optarg);
3849       *model = tension_models+tension_model;
3850       break;
3851     case 'a':
3852       tension_models[tension_model].params = optarg;
3853       break;
3854     case 'F': *Fmax = atof(optarg); break;
3855     case 'X': *Xmax = atof(optarg); break;
3856     case 'V': *flags |= VFLAG;      break;
3857     case '?':
3858       fprintf(stderr, "unrecognized option '%c'\n", optopt);
3859       /* fall through to default case */
3860     default:
3861       help(prog_name, env, n_tension_models, tension_models, tension_model, *Fmax, *Xmax);
3862       exit(1);
3863     }
3864   }
3865   return;
3866 }
3867
3868
3869
3870 \section{Unfolding rate models}
3871 \label{sec.k_models}
3872
3873 We have two main choices for determining $k$: Bell's model, which assumes the
3874 folded domains exist in a single `folded' state and make instantaneous,
3875 stochastic transitions over a free energy barrier; and Kramers' model, which
3876 treats the unfolding as a thermalized diffusion process.
3877 We deal with these options like we dealt with the different tension models: by bundling all model-specific 
3878 parameters into structures, with model specific functions for determining $k$.
3879
3880 <<k func definition>>=
3881 typedef double k_func_t(double F, environment_t *env, void *params);
3882
3883
3884 Because these models are independent of the rest of the simulation, we'll split their definitions out into their own set of files.
3885 The interface is defined in [[k_model.h]], the implementation in [[k_model.c]], the unit testing in [[check_k_model.c]], and some other tidbits in [[k_model_utils.c]].
3886
3887 We go against [[noweb]]'s suggested naming scheme of $\langle \text{\emph{filename}} \rangle$,
3888 because \LaTeX\ doesn't like underscores outside math mode.
3889 Instead we replace the underscores (`\verb+_+') with hyphens (`\verb+-+').
3890 You could use spaces instead (`\verb+ +'),
3891 but then your [[notangle]]s would look like [[notangle -R'k model.h']],
3892 which I don't like as much.
3893
3894 <<k-model.h>>=
3895 #ifndef K_MODEL_H
3896 #define K_MODEL_H
3897 <<license comment>>
3898 <<k func definition>>
3899 <<null k declarations>>
3900 <<const k declarations>>
3901 <<bell k declarations>>
3902 <<kramers k declarations>>
3903 <<kramers integ k declarations>>
3904 #endif /* K_MODEL_H */
3905
3906
3907 <<k model module makefile lines>>=
3908 NW_SAWSIM_MODS += k_model
3909 CHECK_BINS += check_k_model
3910 check_k_model_MODS = parse string_eval
3911
3912 [[check_k_model]] also depends on the parse module.
3913
3914 <<k model utils makefile lines>>=
3915 K_MODEL_MODS = k_model parse string_eval
3916 K_MODEL_SRC = $(BUILD_DIR)/k_model_utils.c $(BUILD_DIR)/global.h \
3917         $(K_MODEL_MODS:%=$(BUILD_DIR)/%.c) $(K_MODEL_MODS:%=$(BUILD_DIR)/%.h)
3918 $(BUILD_DIR)/k_model_utils.c : $(SRC_DIR)/sawsim.nw | $(BUILD)
3919         notangle -Rk-model-utils.c $< > $@
3920 $(BIN_DIR)/k_model_utils : $(K_MODEL_SRC) | $(BIN_DIR)
3921         gcc -g -o $@ $< $(K_MODEL_MODS:%=$(BUILD_DIR)/%.c) $(LIBS:%=-l%)
3922 clean_k_model_utils :
3923         rm -f $(BUILD_DIR)/k_model_utils.c $(BIN_DIR)/k_model_utils
3924
3925
3926 \subsection{Null}
3927 \label{sec.null_k}
3928
3929 For domains that are never folded.
3930
3931 <<null k declarations>>=
3932
3933 <<null k functions>>=
3934
3935 <<null k globals>>=
3936
3937
3938 <<null k model getopt>>=
3939 {"null", "a permanently unfolded domain", NULL, 0, NULL, NULL, NULL, NULL}
3940
3941
3942 \subsection{Constant rate model}
3943 \label{sec.k_const}
3944
3945 This is a pretty boring model, but it is usefull for testing the engine.
3946 $$
3947   k = k_0\;,
3948 $$
3949 where $k_0$ is the constant unfolding rate.
3950
3951 <<const k functions>>=
3952 <<const k function>>
3953 <<const k structure create/destroy functions>>
3954
3955
3956 <<const k declarations>>=
3957 <<const k function declaration>>
3958 <<const k structure create/destroy function declarations>>
3959 <<const k global declarations>>
3960
3961
3962
3963 <<const k structure>>=
3964 typedef struct const_k_param_struct {
3965   double knot;   /* transition rate k_0 (frac population per s) */
3966 } const_k_param_t;
3967
3968
3969 <<const k function declaration>>=
3970 double const_k(double F, environment_t *env, void *const_k_params);
3971
3972 <<const k function>>=
3973 double const_k(double F, environment_t *env, void *const_k_params)
3974 { /* Returns the rate constant k in frac pop per s. */
3975   const_k_param_t *p = (const_k_param_t *) const_k_params;
3976   assert(p != NULL);
3977   assert(p->knot > 0);
3978   return p->knot;
3979 }
3980
3981
3982 <<const k structure create/destroy function declarations>>=
3983 void *string_create_const_k_param_t(char **param_strings);
3984 void destroy_const_k_param_t(void *p);
3985
3986
3987 <<const k structure create/destroy functions>>=
3988 const_k_param_t *create_const_k_param_t(double knot)
3989 {
3990   const_k_param_t *ret = (const_k_param_t *) malloc(sizeof(const_k_param_t));
3991   assert(ret != NULL);
3992   ret->knot = knot;
3993   return ret;
3994 }
3995
3996 void *string_create_const_k_param_t(char **param_strings)
3997 {
3998   return create_const_k_param_t(atof(param_strings[0]));
3999 }
4000
4001 void destroy_const_k_param_t(void *p /* const_k_param_t * */)
4002 {
4003   if (p)
4004     free(p);
4005 }
4006 @
4007
4008 <<const k global declarations>>=
4009 extern int num_const_k_params;
4010 extern char *const_k_param_descriptions[];
4011 extern char const_k_param_string[];
4012 @
4013
4014 <<const k globals>>=
4015 int num_const_k_params = 1;
4016 char *const_k_param_descriptions[] = {"unforced unfolding rate knot, % pop per s"};
4017 char const_k_param_string[]="1";
4018 @
4019
4020 <<const k model getopt>>=
4021 {"const", "constant rate transitions", &const_k, num_const_k_params, const_k_param_descriptions, (char *)const_k_param_string, &string_create_const_k_param_t, &destroy_const_k_param_t}
4022
4023
4024 \subsection{Bell's model}
4025 \label{sec.bell}
4026
4027 Quantitatively, Bell's model gives $k$ as 
4028 $$
4029   k = k_0 \cdot e^{F dx / k_B T} \;,
4030 $$
4031 where $k_0$ is the unforced unfolding rate,
4032 $F$ is the applied unfolding force,
4033 $dx$ is the distance to the transition state, and
4034 $k_B T$ is the thermal energy\citep{schlierf06}.
4035
4036 <<bell k functions>>=
4037 <<bell k function>>
4038 <<bell k structure create/destroy functions>>
4039
4040
4041 <<bell k declarations>>=
4042 <<bell k function declaration>>
4043 <<bell k structure create/destroy function declarations>>
4044 <<bell k global declarations>>
4045
4046
4047
4048 <<bell k structure>>=
4049 typedef struct bell_param_struct {
4050   double knot;   /* transition rate k_0 (frac population per s) */
4051   double dx;     /* `distance to transition state' (nm) */
4052 } bell_param_t;
4053
4054
4055 <<bell k function declaration>>=
4056 double bell_k(double F, environment_t *env, void *bell_params);
4057
4058 <<bell k function>>=
4059 double bell_k(double F, environment_t *env, void *bell_params)
4060 { /* Returns the rate constant k in frac pop per s.
4061    * Takes F in N, T in K, knot in frac pop per s, and dx in m.
4062    * uses global k_B in J/K */
4063   bell_param_t *p = (bell_param_t *) bell_params;
4064   assert(F >= 0); assert(env->T > 0);
4065   assert(p != NULL);
4066   assert(p->knot > 0); assert(p->dx >= 0);
4067 /*
4068   printf("F %g\tT %g\tknot %g\tdx %g\tFdx/kbT %g\tk %g\n",
4069          F, env->T, p->knot, p->dx, F*p->dx/(k_B*env->T),
4070          p->knot * exp(F*p->dx / (k_B*env->T) ));
4071   printf("Fdx %g, kbT %g\n", F*p->dx, k_B*env->T);
4072 */
4073   return p->knot * exp(F*p->dx / (k_B*env->T) );
4074 }
4075
4076
4077 <<bell k structure create/destroy function declarations>>=
4078 void *string_create_bell_param_t(char **param_strings);
4079 void destroy_bell_param_t(void *p);
4080
4081
4082 <<bell k structure create/destroy functions>>=
4083 bell_param_t *create_bell_param_t(double knot, double dx)
4084 {
4085   bell_param_t *ret = (bell_param_t *) malloc(sizeof(bell_param_t));
4086   assert(ret != NULL);
4087   ret->knot = knot;
4088   ret->dx = dx;
4089   return ret;
4090 }
4091
4092 void *string_create_bell_param_t(char **param_strings)
4093 {
4094   return create_bell_param_t(atof(param_strings[0]), atof(param_strings[1]));
4095 }
4096
4097 void destroy_bell_param_t(void *p /* bell_param_t * */)
4098 {
4099   if (p)
4100     free(p);
4101 }
4102 @
4103
4104 <<bell k global declarations>>=
4105 extern int num_bell_params;
4106 extern char *bell_param_descriptions[];
4107 extern char bell_param_string[];
4108 @
4109
4110 <<bell k globals>>=
4111 int num_bell_params = 2;
4112 char *bell_param_descriptions[] = {"unforced unfolding rate knot, % pop per s", "distance to transition state, m"};
4113 char bell_param_string[]="3.3e-4,0.25e-9";
4114 @
4115
4116 <<bell k model getopt>>=
4117 {"bell", "thermalized, two-state transitions", &bell_k, num_bell_params, bell_param_descriptions, (char *)bell_param_string, &string_create_bell_param_t, &destroy_bell_param_t}
4118
4119 Initialized with Titin I27 parameters\citep{carrion-vazquez99b}.
4120 % Titin I27 parameters from Carrion-Vazquez 1999, PNAS USA 96, 3696
4121
4122 \subsection{Kramer's model}
4123 \label{sec.kramers}
4124
4125 Kramer's model gives $k$ as
4126 %$$
4127 %  \frac{1}{k} = \frac{1}{D}
4128 %                \int_{x_\text{min}}^{x_\text{max}}
4129 %                     e^{\frac{-U_F(x)}{k_B T}}
4130 %                     \int_0^x e^{\frac{-U_F(x')}{k_B T}} dx'
4131 %                     dx,
4132 %$$
4133 %where $D$ is the diffusion constant,
4134 %$U_F(x)$ is the free energy along the unfolding coordinate, and
4135 %$x_\text{min}$ and $x_\text{max}$ are arbitrarily chosen to be $6 k_B T$
4136 % before the minimum and after the maximum, respectively \citep{schlierf06}.
4137 $$
4138   k \approx \frac{D}{l_c l_{ts}} e^{-E_b/k_B T},
4139 $$
4140 where $D$ is the diffusion constant,
4141 $$
4142   l_a = \sqrt{\frac{2\pi k_B T}{(\partial^2 E(x') / \partial x'^2)_{x_a}}},
4143 $$
4144 are length scales where
4145 $x_c(F)$ is the location of the bound state and
4146 $x_{ts}(F)$ is the location of the transition state,
4147 $E(F,x)$ is the free energy, and
4148 $E_b(F) = E(F, x_{ts}(F)) - E(F, x_c(F))$ is the barrier energy
4149 (\citet{vanKampen07} Eqn. XIII.2.2, \citet{hanggi90} Eqn.~4.56c,
4150  \citet{evans97} Eqn.~3).
4151
4152 <<kramers k functions>>=
4153 <<kramers k function>>
4154 <<kramers k structure create/destroy functions>>
4155
4156
4157 <<kramers k declarations>>=
4158 <<kramers k function declaration>>
4159 <<kramers k structure create/destroy function declarations>>
4160 <<kramers k global declarations>>
4161
4162
4163
4164 <<kramers k structure>>=
4165 //typedef double kramers_x_func_t(double F, double T, double *E_params, int n);
4166 //typedef double kramers_E_func_t(double F, double T, double *E_params, int n, double x);
4167
4168 typedef struct kramers_param_struct {
4169   double D;                 /* diffusion rate (um/s)                 */
4170   char *xc;
4171   char *xts;
4172   char *ddEdxx;
4173   char *E;
4174   FILE *in;
4175   FILE *out;
4176   //kramers_x_func_t *xc;     /* function returning metastable x (nm)  */
4177   //kramers_x_func_t *xts;    /* function returning transition x (nm)  */
4178   //kramers_E_func_t *ddEdxx; /* function returning d^2E/dx^2 (J/nm^2) */
4179   //kramers_E_func_t *E;      /* function returning E (J)              */
4180   //double *E_params;         /* parametrize the energy landscape     */
4181   //int n_E_params;           /* length of E_params array              */
4182 } kramers_param_t;
4183
4184
4185 <<kramers k function declaration>>=
4186 extern double kramers_E(double F, environment_t *env, void *kramers_params, double x); /* for k_model_utils */
4187 extern double kramers_k(double F, environment_t *env, void *kramers_params);
4188
4189 <<kramers k function>>=
4190 double kramers_x_fn(FILE *in, FILE *out, char *fn, double F, double T)
4191 {
4192   static char input[160]={0};
4193   static char output[80]={0};
4194   /* setup the environment */
4195   fprintf(in, "F = %g; T = %g\n", F, T);
4196   sprintf(input, "print repr(%s)\n", fn); /* repr() to keep full precision */
4197   string_eval(in, out, input, 80, output);
4198   return atof(output);
4199 }
4200
4201 double kramers_E_fn(FILE *in, FILE *out, char *fn, double F, double T, double x)
4202 {
4203   static char input[160]={0};
4204   static char output[80]={0};
4205   /* setup the environment */
4206   fprintf(in, "F = %g;T = %g;x = %g\n", F, T, x);
4207   sprintf(input, "print repr(%s)\n", fn); /* repr() to keep full precision */
4208   string_eval(in, out, input, 80, output);
4209   return atof(output);
4210 }
4211
4212 double kramers_E(double F, environment_t *env, void *kramers_params, double x)
4213 {
4214   kramers_param_t *p = (kramers_param_t *) kramers_params;
4215   return kramers_E_fn(p->in, p->out, p->E, F, env->T, x);
4216 }
4217
4218 double kramers_k(double F, environment_t *env, void *kramers_params)
4219 { /* Returns the rate constant k in frac pop per s.
4220    * Takes F in N, T in K, knot in frac pop per s, and dx in m.
4221    * uses global k_B in J/K */
4222   kramers_param_t *p = (kramers_param_t *) kramers_params;
4223   double kbT, xc, xts, lc, lts, Eb;
4224   assert(F >= 0); assert(env->T > 0);
4225   assert(p != NULL);
4226   assert(p->D > 0);
4227   assert(p->xc != NULL); assert(p->xts != NULL);
4228   assert(p->ddEdxx != NULL); assert(p->E != NULL);
4229   assert(p->in != NULL); assert(p->out != NULL);
4230   kbT = k_B*env->T;
4231   xc = kramers_x_fn(p->in, p->out, p->xc, F, env->T);
4232   if (xc == -1.0) return -1.0; /* error (Too much force) */
4233   xts = kramers_x_fn(p->in, p->out, p->xts, F, env->T);
4234   if (xc == -1.0) return -1.0; /* error (Too much force) */
4235   lc = sqrt(2.0*M_PI*kbT /
4236             kramers_E_fn(p->in, p->out, p->ddEdxx, F, env->T, xc));
4237   lts = sqrt(-2.0*M_PI*kbT/
4238             kramers_E_fn(p->in, p->out, p->ddEdxx, F, env->T, xts));
4239   Eb = kramers_E_fn(p->in, p->out, p->E, F, env->T, xts)
4240      - kramers_E_fn(p->in, p->out, p->E, F, env->T, xc);
4241   //fprintf(stderr,"D = %g, lc = %g, lts = %g, Eb = %g, kbT = %g, k = %g\n", p->D, lc, lts, Eb, kbT, p->D/(lc*lts) * exp(-Eb/kbT));
4242   return p->D/(lc*lts) * exp(-Eb/kbT);
4243 }
4244
4245
4246 <<kramers k structure create/destroy function declarations>>=
4247 void *string_create_kramers_param_t(char **param_strings);
4248 void destroy_kramers_param_t(void *p);
4249
4250
4251 <<kramers k structure create/destroy functions>>=
4252 kramers_param_t *create_kramers_param_t(double D,
4253                                         char *xc_fn, char *xts_fn,
4254                                         char *E_fn, char *ddEdxx_fn,
4255                                         char *global_define_string)
4256 //                              kramers_x_func_t *xc, kramers_x_func_t *xts,
4257 //                            kramers_E_func_t *ddEdxx, kramers_E_func_t *E,
4258 //                            double *E_params, int n_E_params)
4259 {
4260   kramers_param_t *ret = (kramers_param_t *) malloc(sizeof(kramers_param_t));
4261   assert(ret != NULL);
4262   ret->xc = (char *) malloc(sizeof(char)*(strlen(xc_fn)+1));
4263   assert(ret->xc != NULL);
4264   ret->xts = (char *) malloc(sizeof(char)*(strlen(xc_fn)+1));
4265   assert(ret->xts != NULL);
4266   ret->E = (char *) malloc(sizeof(char)*(strlen(E_fn)+1));
4267   assert(ret->E != NULL);
4268   ret->ddEdxx = (char *) malloc(sizeof(char)*(strlen(ddEdxx_fn)+1));
4269   assert(ret->ddEdxx != NULL);
4270   ret->D = D;
4271   strcpy(ret->xc, xc_fn);
4272   strcpy(ret->xts, xts_fn);
4273   strcpy(ret->E, E_fn);
4274   strcpy(ret->ddEdxx, ddEdxx_fn);
4275   //ret->E_params = E_params;
4276   //ret->n_E_params = n_E_params;
4277   string_eval_setup(&ret->in, &ret->out);
4278   fprintf(ret->in, "kB = %g\n", k_B);
4279   fprintf(ret->in, "%s\n", global_define_string);
4280   return ret;
4281 }
4282
4283 /* takes an array of 4 functions: {"(1,2),(2,0),..."} */
4284 void *string_create_kramers_param_t(char **param_strings)
4285 {
4286   return create_kramers_param_t(atof(param_strings[0]),
4287                                 param_strings[2],
4288                                 param_strings[3],
4289                                 param_strings[4],
4290                                 param_strings[5],
4291                                 param_strings[1]);
4292 }
4293
4294 void destroy_kramers_param_t(void *p /* kramers_param_t * */)
4295 {
4296   kramers_param_t *pk = (kramers_param_t *)p;
4297   if (pk) {
4298     string_eval_teardown(&pk->in, &pk->out);
4299     //if (pk->E_params)
4300     //  free(pk->E_params);
4301     free(pk);
4302   }
4303 }
4304 @
4305
4306 For our defaults, we'll follow \citet{schlierf06} and study ddFLN4.
4307 Schlierf and Rief used a cubic-spline interpolation routine and the double integral form of Kramers' theory, so we get to pick an actual function to approximate the energy landscape.
4308 We follow \citet{shillcock98} and use
4309 $$ 
4310   E(F,E_b,x,x_s) \equiv \frac{27}{4} E_b
4311                          \p({\frac{x}{x_s}})^2 \p({2-3\frac{x}{x_s}})
4312                         -F x
4313 $$
4314 where TODO, variable meanings.%\citep{shillcock98}.
4315 The first and second derivatives of $E(F,E_b,x,x_s)$ are
4316 \begin{align}
4317   E'(F,E_b,x,x_s) &=\frac{27 E_b}{4 x_s}\frac{x}{x_s}\p({4-9\frac{x}{x_s}})-F\\
4318   E''(F,E_b,x,x_s)&=\frac{27 E_b}{2 x_s^2}\p({2-9\frac{x}{x_s}}).
4319 \end{align}
4320 $E' = ax^2 + bx + c$, with $a=\frac{-243 E_b}{4 x_s^3}$,
4321 $b=\frac{27 E_b}{x_s^2}$, and $c=-F$.
4322 The roots are therefor at
4323 \begin{align}
4324   x_\pm &= -\frac{b}{2a}\pm\sqrt{\p({\frac{b}{2a}})^2 - \frac{c}{a}} \\
4325         &= \frac{2 x_s}{9}\pm\sqrt{\p({\frac{2 x_s}{9}})^2-\frac{4Fx_s^3}{243E_b}}\\
4326         &= \frac{2 x_s}{9} \p({1 \pm \sqrt{1-\frac{F x_s}{3 E_b}}})
4327 \end{align}
4328
4329 <<kramers k global declarations>>=
4330 extern int num_kramers_params;
4331 extern char *kramers_param_descriptions[];
4332 extern char kramers_param_string[];
4333 @
4334
4335 <<kramers k globals>>=
4336 int num_kramers_params = 6;
4337 char *kramers_param_descriptions[] = {"Diffusion constant D, m^2/s", "constant parameter declarations", "bound position xc, m", "transition state xts, m","energy E, J", "d^2E/dx^2, J/m^2"};
4338 char kramers_param_string[]="0.2e-12,{Eb = 20*300*kB;xs = 1.5e-9},{(F*xs > 3*Eb) and (-1) or (2*xs/9.0*(1 - (1 - F*xs/(3*Eb))**0.5))},{2*xs/9.0*(1 + (1 - F*xs/(3*Eb))**0.5)},{27.0/4 * Eb * (x/xs)**2 * (2-3*x/xs) - F*x},{27.0*Eb/(2*xs**2) * (2-9*x/xs)}";
4339 @
4340 Which we initialized with parameters for ddFLN4\citep{schlierf06}.
4341 There is a bit of funny buisness in the $x_c$ definition to handle high force cases.
4342 When $F x_s > 3 E_b$, the root will be complex (negative energy barrier), and the saddle point analysis breaks down.
4343 Returning an $x_c$ position of $-1\U{m}$ lets the simulation know that the rate is poorly defined for that force, and the timestepping algorithm in Section \ref{app.adaptive_dt} reduces it's timestep appropriately.
4344 The [[(cond) and (val_1) or (val_2)]] construction is Python hackery to simulate [[C]]'s ternary operator [[(cond) ? (val_1) : (val_2)]].
4345 It works so long as [[val_1]] is not [[false]].
4346
4347 <<kramers k model getopt>>=
4348 {"kramers", "thermalized, diffusion-limited transitions (function parameters are parsed by Python.  For distances, the environment variables force 'F' and temperature 'T' are defined, as well as the Boltzmann constant 'kB'.  For energies, the position 'x' is also defined.  Functions must evaluate to a float representing their output and produce no output on stdout.", &kramers_k, num_kramers_params, kramers_param_descriptions, (char *)kramers_param_string, &string_create_kramers_param_t, &destroy_kramers_param_t}
4349
4350
4351 \subsection{Kramer's model (natural cubic splines)}
4352 \label{sec.kramers_integ}
4353
4354 Alternatively, we could skip the gaussian approximation and evaluate the double-integral form of Kramers' overdamped model,
4355 (\citet{hanggi90} Eqn.~4.56b, \citet{vanKampen07} Eqn.~XIII.2.1,
4356 \citet{schlierf06} Eqn.~2)
4357 $$
4358   \frac{1}{k} = \frac{1}{D}
4359                 \int_{x_\text{min}}^{x_\text{max}}
4360                      e^{\frac{U_F(x)}{k_B T}}
4361                      \int_0^x e^{\frac{-U_F(x')}{k_B T}} dx'
4362                      dx,
4363 $$
4364 where $D$ is the diffusion constant,
4365 $U_F(x)$ is the free energy along the unfolding coordinate, and
4366 $x_\text{min}$ and $x_\text{max}$ are arbitrarily chosen to be $6 k_B T$
4367  before the minimum and after the maximum, respectively (note: there is a sign difference from Schlierf)\citep{schlierf06,hanggi90}.
4368
4369 We can parametrize the energy unforced landscape $U(x)$ by $N$ \emph{knots} (anchor points),
4370 interpolating between them with cubic splines.
4371 We'll let the \citetalias{galassi05} natural cubic spline implementation do the heavy lifting here.
4372
4373 <<kramers integ k functions>>=
4374 <<spline functions>>
4375 <<kramers integ A k functions>>
4376 <<kramers integ B k functions>>
4377 <<kramers integ k function>>
4378 <<kramers integ k structure create/destroy functions>>
4379
4380
4381 <<kramers integ k declarations>>=
4382 <<kramers integ k function declaration>>
4383 <<kramers integ k structure create/destroy function declarations>>
4384 <<kramers integ k global declarations>>
4385
4386
4387
4388 <<kramers integ k structure>>=
4389 typedef double func_t(double x, void *params);
4390 typedef struct kramers_integ_param_struct {
4391   double D;            /* diffusion rate (um/s)                 */
4392   double x_min;        /* integration bounds                    */
4393   double x_max;
4394   func_t *E;           /* function returning E (J)              */
4395   void *E_params;      /* parametrize the energy landscape     */
4396   destroy_data_func_t *destroy_E_params;
4397
4398   double F;            /* for passing into GSL evaluations      */
4399   environment_t *env;
4400 } kramers_integ_param_t;
4401
4402
4403 <<spline param structure>>=
4404 typedef struct spline_param_struct {
4405   int n_knots;            /* natural cubic spline knots for U(x)   */
4406   double *x;
4407   double *y;
4408   gsl_spline *spline;    /* GSL spline parameters               */
4409   gsl_interp_accel *acc; /* GSL spline acceleration data        */
4410 } spline_param_t;
4411
4412
4413 We break the evaluation of $k$ into the two integrals, and use the \citetalias{galassi05} to do the heavy lifting.
4414 $$
4415   \text{Integral}_A(x) \equiv \int_0^x e^{\frac{-U_F(x')}{k_B T}} dx'
4416 $$
4417 <<kramers integ A k functions>>=
4418 double kramers_integ_k_integrandA(double x, void *params)
4419 {
4420   kramers_integ_param_t *p = (kramers_integ_param_t *)params;
4421   double U = (*p->E)(x, p->E_params);
4422   double Fx = p->F * x;
4423   double kbT = k_B * p->env->T;
4424   //fprintf(stderr, "integrandA(%g) = %g\n", x, exp((U-Fx)/kbT));
4425   return exp(-(U-Fx)/kbT);
4426 }
4427 double kramers_integ_k_integralA(double x, void *params)
4428 {
4429   kramers_integ_param_t *p = (kramers_integ_param_t *)params;
4430   gsl_function f;
4431   double result, abserr;
4432   size_t neval; /* for qng */
4433   static gsl_integration_workspace *w = NULL;
4434   if (w == NULL) w = gsl_integration_workspace_alloc(500); /* for qag */
4435   f.function = &kramers_integ_k_integrandA;
4436   f.params = params;
4437   //assert(gsl_integration_qng(&f, p->x_min, x, 0 /* epsabs */, 1e-6, &result, &abserr, &neval) == 0);
4438   assert(gsl_integration_qag(&f, p->x_min, x, 0 /* epsabs */, 1e-6, 500, 6/* key */, w, &result, &abserr) == 0);
4439   //fprintf(stderr, "integralA = %g\n", result);
4440   return result;
4441 }
4442
4443
4444 $$
4445   \text{Integral}_B(x_\text{min}, x_\text{max}) \equiv
4446                 \int_{x_\text{min}}^{x_\text{max}}
4447                      e^{\frac{U_F(x)}{k_B T}}
4448                      \text{Integral}_A(x)
4449                      dx,
4450 $$
4451 <<kramers integ B k functions>>=
4452 double kramers_integ_k_integrandB(double x, void *params)
4453 {
4454   kramers_integ_param_t *p = (kramers_integ_param_t *)params;
4455   double U = (*p->E)(x, p->E_params);
4456   double Fx = p->F * x;
4457   double kbT = k_B * p->env->T;
4458   double intA = kramers_integ_k_integralA(x, params);
4459   //fprintf(stderr, "integrandB(%g) = %g\n", x, exp(-(U-Fx)/kbT))*intA;
4460   return exp((U-Fx)/kbT)*intA;
4461 }
4462 double kramers_integ_k_integralB(double F, environment_t *env, void *params)
4463 {
4464   kramers_integ_param_t *p = (kramers_integ_param_t *)params;
4465   gsl_function f;
4466   double result, abserr;
4467   size_t neval; /* for qng */
4468   static gsl_integration_workspace *w = NULL;
4469   if (w == NULL) w = gsl_integration_workspace_alloc(500); /* for qag */
4470   f.function = &kramers_integ_k_integrandB;
4471   f.params = params;
4472   p->F = F;
4473   p->env = env;
4474   //assert(gsl_integration_qng(&f, p->x_min, p->x_max, 0 /* epsabs */, 1e-6, &result, &abserr, &neval) == 0);
4475   assert(gsl_integration_qag(&f, p->x_min, p->x_max, 0 /* epsabs */, 1e-6, 500, 6/* key */, w, &result, &abserr) == 0);
4476   //fprintf(stderr, "integralB = %g\n", result);
4477   return result;
4478 }
4479
4480
4481 With the integrals taken care of, evaluating $k$ is simply
4482 $$
4483   k = \frac{D}{\text{Integral}_B(x_\text{min}, x_\text{max})}
4484 $$
4485 <<kramers integ k function declaration>>=
4486 double kramers_integ_k(double F, environment_t *env, void *kramers_params);
4487
4488 <<kramers integ k function>>=
4489 double kramers_integ_k(double F, environment_t *env, void *kramers_params)
4490 { /* Returns the rate constant k in frac pop per s. Takes F in N. */
4491   kramers_integ_param_t *p = (kramers_integ_param_t *) kramers_params;
4492   return p->D/kramers_integ_k_integralB(F, env, kramers_params);
4493 }
4494
4495
4496 <<kramers integ k structure create/destroy function declarations>>=
4497 void *string_create_kramers_integ_param_t(char **param_strings);
4498 void destroy_kramers_integ_param_t(void *p);
4499
4500
4501 <<kramers integ k structure create/destroy functions>>=
4502 kramers_integ_param_t *create_kramers_integ_param_t(double D,
4503                               double xmin, double xmax, func_t *E,
4504                               void *E_params,
4505                               destroy_data_func_t *destroy_E_params)
4506 {
4507   kramers_integ_param_t *ret = (kramers_integ_param_t *) malloc(sizeof(kramers_integ_param_t));
4508   assert(ret != NULL);
4509   ret->D = D;
4510   ret->x_min = xmin;
4511   ret->x_max = xmax;
4512   ret->E = E;
4513   ret->E_params = E_params;
4514   ret->destroy_E_params = destroy_E_params;
4515   return ret;
4516 }
4517
4518 void *string_create_kramers_integ_param_t(char **param_strings)
4519 {
4520   //printf("create kramers integ.  D: %s, knots: %s, x in [%s, %s]\n",
4521   //       param_strings[0],param_strings[1],param_strings[2],param_strings[3]);
4522   void *E_params = string_create_spline_param_t(param_strings+1);
4523   return create_kramers_integ_param_t(atof(param_strings[0]),
4524                                       atof(param_strings[2]),
4525                                       atof(param_strings[3]),
4526                                       &spline_eval, E_params,
4527                                       destroy_spline_param_t);
4528 }
4529
4530 void destroy_kramers_integ_param_t(void *params)
4531 {
4532   kramers_integ_param_t *p = (kramers_integ_param_t *)params;
4533   if (p) {
4534     if (p->E_params)
4535       (*p->destroy_E_params)(p->E_params);
4536     free(p);
4537   }
4538 }
4539 @
4540
4541 Finally we have the GSL spline wrappers:
4542 <<spline functions>>=
4543 <<spline function>>
4544 <<create/destroy spline>>
4545
4546
4547 <<spline function>>=
4548 double spline_eval(double x, void *spline_params)
4549 {
4550   spline_param_t *p = (spline_param_t *)(spline_params);
4551   return gsl_spline_eval(p->spline, x, p->acc);
4552 }
4553
4554
4555 <<create/destroy spline>>=
4556 spline_param_t *create_spline_param_t(int n_knots, double *x, double *y)
4557 {
4558   spline_param_t *ret = (spline_param_t *) malloc(sizeof(spline_param_t));
4559   assert(ret != NULL);
4560   ret->n_knots = n_knots;
4561   ret->x = x;
4562   ret->y = y;
4563   ret->acc = gsl_interp_accel_alloc();
4564   ret->spline = gsl_spline_alloc(gsl_interp_cspline, n_knots);
4565   gsl_spline_init(ret->spline, x, y, n_knots);
4566   return ret;
4567 }
4568
4569 /* takes an (array of strings) of length one: {"(1,2),(2,0),..."} */
4570 void *string_create_spline_param_t(char **param_strings)
4571 {
4572   char **knot_coords;
4573   int i, num_knots;
4574   double *x=NULL, *y=NULL;
4575   /* break into ordered pairs */
4576   parse_list_string(param_strings[0], SEP, '(', ')',
4577                     &num_knots, &knot_coords);
4578   x = (double *)malloc(sizeof(double)*num_knots);
4579   assert(x != NULL);
4580   y = (double *)malloc(sizeof(double)*num_knots);
4581   assert(x != NULL);
4582   for (i=0; i<num_knots; i++) {
4583     if (sscanf(knot_coords[i], "%lg,%lg", x+i, y+i) != 2) {
4584       fprintf(stderr, "Could not parse pair %d, \"%s\"\n", i, knot_coords[i]);
4585       exit(1);
4586     }
4587     //fprintf(stderr, "%d : scanned '%s' -> (%g, %g)\n", i, knot_coords[i], x[i], y[i]);
4588   }
4589   free_parsed_list(num_knots, knot_coords);
4590   return create_spline_param_t(num_knots, x, y);
4591 }
4592
4593 void destroy_spline_param_t(void *params)
4594 {
4595   spline_param_t *p = (spline_param_t *)params;
4596   if (p) {
4597     if (p->spline)
4598       gsl_spline_free(p->spline);
4599     if (p->acc)
4600       gsl_interp_accel_free(p->acc);
4601     if (p->x)
4602       free(p->x);
4603     if (p->y)
4604       free(p->y);
4605     free(p);
4606   }
4607 }
4608
4609
4610 <<kramers integ k global declarations>>=
4611 extern int num_kramers_integ_params;
4612 extern char *kramers_integ_param_descriptions[];
4613 extern char kramers_integ_param_string[];
4614 @
4615
4616 <<kramers integ k globals>>=
4617 int num_kramers_integ_params = 4;
4618 char *kramers_integ_param_descriptions[] = {
4619                            "diffusion D, m^2 / s",
4620                            "spline knots, {(x1,y1),(x2,y2),...}, (m,J)",
4621                            "starting integration bound x_min, m",
4622                            "ending integration bound x_max, m"};
4623 //char kramers_integ_param_string[]="0.2e-12,{(3.5e-9,-5*k_B*300),(4e-9,-20*k_B*300),(4.25e-9,-8*k_B*300),(5e-9,0),(5.5e-9,-10*k_B*300)},3e-9,6e-9";
4624 //char kramers_integ_param_string[]="0.2e-12,{(3.5e-9,-2.1e-20),(4e-9,-8.3e-20),(4.25e-9,-3.3e-20),(5e-9,0),(5.5e-9,-4.1e-20)},3e-9,6e-9";
4625 char kramers_integ_param_string[]="0.2e-12,{(2e-9,0),(2.1e-9,-3.7e-20),(2.2e-9,-4.4e-20),(2.35e-9,-2.5e-20),(2.41e-9,-7e-21),(2.45e-9,8e-22),(2.51e-9,6.9e-21),(2.64e-9,1.39e-20),(2.9e-9,2.55e-20),(3.52e-9,2.9e-20),(3.7e-9,1.45e-20),(4e-9,-1.7e-20),(6e-9,-2e-20),(9e-9,-3e-20),(1e-8,-3e-20)},2e-9,6e-9";
4626 /* D from Schlierf 2006, Biophys 90, 4, L33, sup.
4627  * Anchor points from private communication with Schlierf, Apr 9th, 2008.
4628  * other parameters from from Schlierf 2006, Biophys 90, 4, L33, figure 1. */
4629 @
4630
4631 <<kramers integ k model getopt>>=
4632 {"kramers_integ", "thermalized, diffusion-limited transitions", &kramers_integ_k, num_kramers_integ_params, kramers_integ_param_descriptions, (char *)kramers_integ_param_string, &string_create_kramers_integ_param_t, &destroy_kramers_integ_param_t}
4633
4634 Initialized with Titin I27 parameters\citep{carrion-vazquez99b}.
4635 % Titin I27 parameters from Carrion-Vazquez 1999, PNAS USA 96, 3696
4636
4637 \subsection{Unfolding model implementation}
4638
4639 <<k-model.c>>=
4640 <<license comment>>
4641 <<k model includes>>
4642 #include "k_model.h"
4643 <<k model internal definitions>>
4644 <<k model globals>>
4645 <<k model functions>>
4646
4647
4648 <<k model includes>>=
4649 #include <assert.h> /* assert()                */
4650 #include <stdlib.h> /* NULL, malloc()          */
4651 #include <math.h>   /* HUGE_VAL, sqrt(), exp() */
4652 #include <stdio.h>  /* fprintf(), stdout       */
4653 #include <string.h> /* strlen(), strcpy()      */
4654 #include <gsl/gsl_integration.h>
4655 #include <gsl/gsl_spline.h>
4656 #include "global.h"
4657 #include "parse.h"
4658
4659
4660 <<k model internal definitions>>=
4661 <<const k structure>>
4662 <<bell k structure>>
4663 <<kramers k structure>>
4664 <<kramers integ k structure>>
4665 <<spline param structure>>
4666
4667
4668 <<k model globals>>=
4669 <<null k globals>>
4670 <<const k globals>>
4671 <<bell k globals>>
4672 <<kramers k globals>>
4673 <<kramers integ k globals>>
4674
4675
4676 <<k model functions>>=
4677 <<null k functions>>
4678 <<const k functions>>
4679 <<bell k functions>>
4680 <<kramers k functions>>
4681 <<kramers integ k functions>>
4682
4683
4684 \subsection{Unfolding model unit tests}
4685
4686 Here we check to make sure the various functions work as expected, using \citetalias{sw:check}.
4687 <<check-k-model.c>>=
4688 <<k model check includes>>
4689 <<check relative error>>
4690 <<model globals>>
4691 <<k model test suite>>
4692 <<main check program>>
4693
4694
4695 <<k model check includes>>=
4696 #include <stdlib.h> /* EXIT_SUCCESS and EXIT_FAILURE, atof() */
4697 #include <stdio.h>  /* sprintf()                             */
4698 #include <assert.h> /* assert()                              */
4699 #include <math.h>   /* exp()                                 */
4700 <<check includes>>
4701 #include "global.h"
4702 #include "k_model.h"
4703
4704
4705 <<k model test suite>>=
4706 <<const k tests>>
4707 <<bell k tests>>
4708 <<k model suite definition>>
4709
4710
4711 <<k model suite definition>>=
4712 Suite *test_suite (void)
4713 {
4714   Suite *s = suite_create ("k model");
4715   <<const k test case defs>>
4716   <<bell k test case defs>>
4717
4718   <<const k test case adds>>
4719   <<bell k test case adds>>
4720   return s;
4721 }
4722
4723
4724 \subsubsection{Constant}
4725
4726 <<const k test case defs>>=
4727 TCase *tc_const_k = tcase_create("Constant k");
4728
4729
4730 <<const k test case adds>>=
4731 tcase_add_test(tc_const_k, test_const_k_create_destroy);
4732 tcase_add_test(tc_const_k, test_const_k_over_range);
4733 suite_add_tcase(s, tc_const_k);
4734
4735
4736
4737 <<const k tests>>=
4738 START_TEST(test_const_k_create_destroy)
4739 {
4740   char *knot[] = {"1","2","3","4","5","6"};
4741   char *params[] = {knot[0]};
4742   void *p = NULL;
4743   int i;
4744   for( i=0; i < sizeof(knot)/sizeof(char *); i++) {
4745     params[0] = knot[i];
4746     p = string_create_const_k_param_t(params); 
4747     destroy_const_k_param_t(p);
4748   }
4749 }
4750 END_TEST
4751
4752 START_TEST(test_const_k_over_range)
4753 {
4754   double F, Fm=0.0, FM=10, dF=.1, T=300.0;
4755   char *knot[] = {"1","2","3","4","5","6"};
4756   char *params[] = {knot[0]};
4757   void *p = NULL;
4758   environment_t env;
4759   char param_string[80];
4760   int i;
4761   env.T = T;
4762   for( i=0; i < sizeof(knot)/sizeof(char *); i++) {
4763     params[0] = knot[i];
4764     p = string_create_const_k_param_t(params); 
4765     for ( F=Fm; F<FM; F+=dF ) {
4766       fail_unless(const_k(F, &env, p)==atof(knot[i]),
4767           "const_k(%g, %g, &{%s}) = %g != %s",
4768           F, T, knot[i], const_k(F, &env, p), knot[i]);
4769     }
4770     destroy_const_k_param_t(p);
4771   }
4772 }
4773 END_TEST
4774
4775
4776 \subsubsection{Bell}
4777
4778 <<bell k test case defs>>=
4779 TCase *tc_bell = tcase_create("Bell's k");
4780
4781
4782 <<bell k test case adds>>=
4783 tcase_add_test(tc_bell, test_bell_k_create_destroy);
4784 tcase_add_test(tc_bell, test_bell_k_at_zero);
4785 tcase_add_test(tc_bell, test_bell_k_at_one);
4786 suite_add_tcase(s, tc_bell);
4787
4788
4789 <<bell k tests>>=
4790 START_TEST(test_bell_k_create_destroy)
4791 {
4792   char *knot[] = {"1","2","3","4","5","6"};
4793   char *dx="1";
4794   char *params[] = {knot[0], dx};
4795   void *p = NULL;
4796   int i;
4797   for( i=0; i < sizeof(knot)/sizeof(char *); i++) {
4798     params[0] = knot[i];
4799     p = string_create_bell_param_t(params); 
4800     destroy_bell_param_t(p);
4801   }
4802 }
4803 END_TEST
4804
4805 START_TEST(test_bell_k_at_zero)
4806 {
4807   double F=0.0, T=300.0;
4808   char *knot[] = {"1","2","3","4","5","6"};
4809   char *dx="1";
4810   char *params[] = {knot[0], dx};
4811   void *p = NULL;
4812   environment_t env;
4813   char param_string[80];
4814   int i;
4815   env.T = T;
4816   for( i=0; i < sizeof(knot)/sizeof(char *); i++) {
4817     params[0] = knot[i];
4818     p = string_create_bell_param_t(params); 
4819     fail_unless(bell_k(F, &env, p)==atof(knot[i]),
4820                 "bell_k(%g, %g, &{%s,%s}) = %g != %s",
4821                 F, T, knot[i], dx, bell_k(F, &env, p), knot[i]);
4822     destroy_bell_param_t(p);
4823   }
4824 }
4825 END_TEST
4826
4827 START_TEST(test_bell_k_at_one)
4828 {
4829   double T=300.0;
4830   char *knot[] = {"1","2","3","4","5","6"};
4831   char *dx="1";
4832   char *params[] = {knot[0], dx};
4833   double F= k_B*T/atof(dx);
4834   void *p = NULL;
4835   environment_t env;
4836   char param_string[80];
4837   int i;
4838   env.T = T;
4839   for( i=0; i < sizeof(knot)/sizeof(char *); i++) {
4840     params[0] = knot[i];
4841     p = string_create_bell_param_t(params); 
4842     CHECK_ERR(1e-6, atof(knot[i])*exp(1.0), bell_k(F, &env, p));
4843     //fail_unless(bell_k(F, &env, p)==atof(knot[i])*exp(1.0),
4844     //            "bell_k(%g, %g, &{%s,%s}) = %g != %g",
4845     //            F, T, knot[i], dx, bell_k(F, &env, p), atof(knot[i])*exp(1.0));
4846     destroy_bell_param_t(p);
4847   }
4848 }
4849 END_TEST
4850
4851
4852 <<kramers k tests>>=
4853
4854
4855 <<kramers k test case def>>=
4856
4857
4858 <<kramers k test case add>>=
4859
4860
4861 <<k model function tests>>=
4862 <<check relative error>>
4863
4864 START_TEST(test_something)
4865 {
4866   double k=5, x=3, last_x=2.0, F;
4867   one_dim_fn_t *handlers[] = {&hooke};
4868   void *data[] =               {&k};
4869   double xi[] =                {0.0};
4870   int active[] =               {1};
4871   int new_active_groups = 1;
4872   F = k_model(1, handlers, data, active, new_active_groups, xi, last_x, x);
4873   fail_unless(F = k*x, NULL);
4874 }
4875 END_TEST
4876
4877
4878 \subsection{Utilities}
4879
4880 The unfolding models can get complicated, and are sometimes hard to explain to others.
4881 The stand-alone program [[k_model_utils]] demonstrates the unfolding model interface without
4882 the overhead of having to understand a full simulation.
4883 [[k_model_utils]] can operate in a general mode, where it prints $k(F)$ data to the screen,
4884 or special mode, where the operation depends on the specific model selected.
4885
4886 <<k-model-utils.c>>=
4887 <<license comment>>
4888 <<k model utility includes>>
4889 <<k model utility definitions>>
4890 <<k model utility getopt functions>>
4891 <<k model utility multi model E>>
4892 <<k model utility main>>
4893
4894
4895 <<k model utility main>>=
4896 int main(int argc, char **argv)
4897 {
4898   <<k model getopt array definition>>
4899   k_model_getopt_t *model = NULL;
4900   void *params;
4901   enum mode_t mode;
4902   environment_t env;
4903   unsigned int flags;
4904   int num_param_args; /* for INIT_MODEL() */
4905   char **param_args;  /* for INIT_MODEL() */
4906   double Fmax;
4907   double special_xmin;
4908   double special_xmax;
4909   get_options(argc, argv, &env, NUM_K_MODELS, k_models, &mode, &model,
4910               &Fmax, &special_xmin, &special_xmax, &flags);
4911   if (flags & VFLAG) {
4912     printf("#initializing model %s with parameters %s\n", model->name, model->params);
4913   }
4914   INIT_MODEL("utility", model, model->params, params);
4915   switch (mode) {
4916     case M_K_OF_F :
4917       if (model->k == NULL) {
4918         printf("No k function for model %s\n", model->name);
4919         exit(0);
4920       }
4921       if (Fmax <= 0) {
4922         printf("Fmax = %g <= 0\n", Fmax);
4923         exit(1);
4924       }
4925       {
4926         double F, k=1.0;
4927         int i, N=200;
4928         printf("#F (N)\tk (%% pop. per s)\n");
4929         for (i=0; i<=N; i++) {
4930           F = Fmax*i/(double)N;
4931           k = (*model->k)(F, &env, params);
4932           if (k < 0) break;
4933           printf("%g\t%g\n", F, k);
4934         }
4935       }
4936       break;
4937     case M_SPECIAL :
4938       if (model->k == NULL || model->k == &bell_k) {
4939         printf("No special mode for model %s\n", model->name);
4940         exit(1);
4941       }
4942       if (special_xmax <= special_xmin) {
4943         printf("Xmax = %g <= %g = Xmin\n", special_xmax, special_xmin);
4944         exit(1);
4945       }
4946       {
4947         double Xrng=(special_xmax-special_xmin), x, E;
4948         int i, N=500;
4949         printf("#x (m)\tE (J)\n");
4950         for (i=0; i<=N; i++) {
4951           x = special_xmin + Xrng*i/(double)N;
4952           E = multi_model_E(model->k, params, &env, x);
4953           printf("%g\t%g\n", x, E);
4954         }
4955       }
4956       break;
4957     default :
4958       break;
4959   }
4960   if (model->destructor)
4961     (*model->destructor)(params);
4962   return 0;
4963 }
4964
4965
4966 <<k model utility multi model E>>=
4967 double multi_model_E(k_func_t *k, void *model_params, environment_t *env, double x)
4968 {
4969   kramers_integ_param_t *p = (kramers_integ_param_t *)model_params;
4970   double E;
4971   if (k == kramers_integ_k)
4972     E = (*p->E)(x, p->E_params);
4973   else 
4974     E = kramers_E(0, env, model_params, x);
4975   return E;
4976 }
4977
4978
4979
4980 <<k model utility includes>>=
4981 #include <stdlib.h>
4982 #include <stdio.h>
4983 #include <string.h> /* strlen() */
4984 #include <assert.h> /* assert() */
4985 #include "global.h"
4986 #include "parse.h"
4987 #include "string_eval.h"
4988 #include "k_model.h"
4989
4990
4991 <<k model utility definitions>>=
4992 <<version definition>>
4993 #define VFLAG 1 /* verbose */
4994 enum mode_t {M_K_OF_F, M_SPECIAL};
4995 <<string comparison definition and globals>>
4996 <<k model getopt definitions>>
4997 <<initialize model definition>>
4998 <<kramers k structure>>
4999 <<kramers integ k structure>>
5000
5001
5002
5003 <<k model utility getopt functions>>=
5004 <<index k model>>
5005 <<k model utility help>>
5006 <<k model utility get options>>
5007
5008
5009 <<k model utility help>>=
5010 void help(char *prog_name,
5011           environment_t *env,
5012           int n_k_models, k_model_getopt_t *k_models,
5013           int k_model, double Fmax, double special_xmin, double special_xmax)
5014 {
5015   int i, j;
5016   printf("usage: %s [options]\n", prog_name);
5017   printf("Version %s\n\n", VERSION);
5018   printf("A utility for understanding the available unfolding models\n\n");
5019   printf("Environmental options:\n");
5020   printf("-T T\tTemperature T (currently %g K)\n", env->T);
5021   printf("-C T\tYou can also set the temperature T in Celsius\n");
5022   printf("Model options:\n");
5023   printf("-k model\tTransition rate model (currently %s)\n",
5024          k_models[k_model].name);
5025   printf("-K args\tTransition rate model argument string (currently %s)\n",
5026          k_models[k_model].params);
5027   printf("There are two output modes.  In standard mode, k(F) is printed\n");
5028   printf("For example:\n");
5029   printf("  #Force (N)\tk (% pop. per s)\n");
5030   printf("  123.456\t7.89\n");
5031   printf("  ...\n");
5032   printf("In special mode, the output depends on the model.\n");
5033   printf("For models defining an energy function E(x), that function is printed\n");
5034   printf("  #Position (m)\tE (J)\n");
5035   printf("  0.0012\t0.0034\n");
5036   printf("  ...\n");
5037   printf("-m\tChange output to standard mode\n");
5038   printf("-M\tChange output to special mode\n");
5039   printf("-F\tSet the maximum F value for the standard mode k(F) output (currently %g)\n", Fmax);
5040   printf("-x\tSet the minimum x value for the special mode E(x) output (currently %g)\n", special_xmin);
5041   printf("-X\tSet the maximum x value for the special mode E(x) output (currently %g)\n", special_xmax);
5042   printf("-V\tChange output to verbose mode\n");
5043   printf("-h\tPrint this help and exit\n");
5044   printf("\n");
5045   printf("Unfolding rate models:\n");
5046   for (i=0; i<n_k_models; i++) {
5047     printf("\t%s\t%s\n", k_models[i].name, k_models[i].description);
5048     for (j=0; j < k_models[i].num_params ; j++)
5049       printf("\t\t\t%s\n", k_models[i].param_descriptions[j]);
5050     printf("\t\tdefaults: %s\n", k_models[i].params);
5051   }
5052 }
5053
5054
5055 <<k model utility get options>>=
5056 void get_options(int argc, char **argv, environment_t *env,
5057                  int n_k_models, k_model_getopt_t *k_models,
5058                  enum mode_t *mode, k_model_getopt_t **model,
5059                  double *Fmax, double *special_xmin, double *special_xmax,
5060                  unsigned int *flags)
5061 {
5062   char *prog_name = NULL;
5063   char c, options[] = "T:C:k:K:mMF:x:X:Vh";
5064   int k_model=0;
5065   extern char *optarg;
5066   extern int optind, optopt, opterr;
5067
5068   assert (argc > 0);
5069
5070   /* setup defaults */
5071
5072   prog_name = argv[0];
5073   env->T = 300.0;   /* K           */
5074   *mode = M_K_OF_F;
5075   *flags = 0;
5076   *model = k_models;
5077   *Fmax = 1e-9;
5078   *special_xmax = 1e-8;
5079   *special_xmin = 0.0;
5080
5081   while ((c=getopt(argc, argv, options)) != -1) {
5082     switch(c) {
5083     case 'T':  env->T   = atof(optarg);           break;
5084     case 'C':  env->T   = atof(optarg)+273.15;    break;
5085     case 'k':
5086       k_model = index_k_model(n_k_models, k_models, optarg);
5087       *model = k_models+k_model;
5088       break;
5089     case 'K':
5090       k_models[k_model].params = optarg;
5091       break;
5092     case 'm': *mode = M_K_OF_F;             break;
5093     case 'M': *mode = M_SPECIAL;            break;
5094     case 'F': *Fmax = atof(optarg);         break;
5095     case 'x': *special_xmin = atof(optarg); break;
5096     case 'X': *special_xmax = atof(optarg); break;
5097     case 'V': *flags |= VFLAG;              break;
5098     case '?':
5099       fprintf(stderr, "unrecognized option '%c'\n", optopt);
5100       /* fall through to default case */
5101     default:
5102       help(prog_name, env, n_k_models, k_models, k_model, *Fmax, *special_xmin, *special_xmax);
5103       exit(1);
5104     }
5105   }
5106   return;
5107 }
5108
5109
5110
5111 \section{\LaTeX\ documentation}
5112
5113 The comment blocks in this [[noweb]] file are in \LaTeX\ with \BibTeX\ citations.
5114 The comment blocks are extracted (with nicely formatted code blocks), using
5115 <<latex makefile lines>>=
5116 $(BUILD_DIR)/sawsim.tex : $(SRC_DIR)/sawsim.nw | $(BUILD_DIR)
5117         noweave -latex -index -delay $< > $@
5118 $(BUILD_DIR)/sawsim.bib : $(SRC_DIR)/sawsim.bib | $(BUILD_DIR)
5119         cp -f $< $@
5120
5121 and compiled using
5122 <<latex makefile lines>>=
5123 $(DOC_DIR)/sawsim.pdf : $(BUILD_DIR)/sawsim.tex $(BUILD_DIR)/sawsim.bib \
5124                 | $(DOC_DIR)
5125         $(SHELL) -e -c "cd $(BUILD_DIR) && pdflatex sawsim"
5126         $(SHELL) -e -c "cd $(BUILD_DIR) && bibtex sawsim"
5127         $(SHELL) -e -c "cd $(BUILD_DIR) && pdflatex sawsim"
5128         $(SHELL) -e -c "cd $(BUILD_DIR) && pdflatex sawsim"
5129         mv $(BUILD_DIR)/sawsim.pdf $@
5130 @
5131 The first [[pdflatex]] pass reads through the \TeX\ source and extracts citation information,
5132 the \BibTeX\ pass looks through the \BibTeX\ databases for the cited works, and
5133 the remaining two [[pdflatex]] passes insert the citations and finalize the various indices and numberings.
5134
5135 [[bibtex]] and [[pdflatex]] produce quite a few intermediate files, so provide a means to clean them up.
5136 <<latex makefile lines>>=
5137 semi-clean_latex : 
5138         rm -f $(BUILD_DIR)/sawsim.aux $(BUILD_DIR)/sawsim.bbl \
5139                 $(BUILD_DIR)/sawsim.blg $(BUILD_DIR)/sawsim.log \
5140                 $(BUILD_DIR)/sawsim.out $(BUILD_DIR)/sawsim.tex \
5141                 $(BUILD_DIR)/sawsim.bib
5142 clean_latex : semi-clean_latex
5143         rm -f $(DOC_DIR)/sawsim.pdf
5144
5145
5146 \section{Makefile}
5147
5148 [[make]] is a common utility on *nix systems for managing dependencies while building software.
5149 In this case, we have several \emph{targets} that we'd like to build:
5150  the main simulation program \prog;
5151  the testing programs [[check_sawsim]], [[check_tension_balance]], and [[check_list]];
5152  the documentation [[sawsim.pdf]];
5153  and the [[Makefile]] itself.
5154 Besides the generated files, there is the utility target
5155  [[clean]] for removing all generated files except [[Makefile]].
5156 % and
5157 % [[dist]] for generating a distributable tar file.
5158
5159 Extract the makefile with
5160 `[[notangle -Rmakefile src/sawsim.nw | sed 's/        /\t/' > Makefile]]'.
5161 The sed is needed because notangle replaces tabs with eight spaces,
5162 but [[make]] needs tabs.
5163 <<makefile>>=
5164 # Decide what directories to put things in
5165 SRC_DIR = src
5166 BUILD_DIR = build
5167 BIN_DIR = bin
5168 DOC_DIR = doc
5169 # Note: Cannot use, for example, `./build', because make eats the `./' 
5170 # and then $(BUILD_DIR) doesn't match in $$(subst $(BUILD_DIR), ...) 
5171
5172 # Modules (X.c, X.h) defined in the noweb file
5173 NW_SAWSIM_MODS = 
5174 CHECK_BINS = 
5175 # Modules defined outside the noweb file
5176 FREE_SAWSIM_MODS = interp tavl
5177
5178 <<list module makefile lines>>
5179 <<tension balance module makefile lines>>
5180 <<tension model module makefile lines>>
5181 <<k model module makefile lines>>
5182 <<parse module makefile lines>>
5183 <<string eval module makefile lines>>
5184 <<accel k module makefile lines>>
5185
5186 SAWSIM_MODS = $(NW_SAWSIM_MODS) $(FREE_SAWSIM_MODS)
5187
5188 # Everything needed for sawsim under one roof.  sawsim.c must come first
5189 SAWSIM_SRC = $(BUILD_DIR)/sawsim.c $(BUILD_DIR)/global.h \
5190         $(SAWSIM_MODS:%=$(BUILD_DIR)/%.c) $(SAWSIM_MODS:%=$(BUILD_DIR)/%.h)
5191 # Libraries needed to compile sawsim
5192 LIBS = gsl gslcblas m
5193 CHECK_LIBS = gsl gslcblas m check
5194 # The non-check binaries generated
5195 BINS = sawsim tension_model_utils k_model_utils sawsim_profile
5196 DOCS = sawsim.pdf
5197
5198 # Define the major targets
5199 all : ./Makefile $(BINS:%=$(BIN_DIR)/%) $(DOCS:%=$(DOC_DIR)/%) ;
5200
5201 view : $(DOC_DIR)/sawsim.pdf
5202         xpdf $< &
5203 profile : $(BIN_DIR)/sawsim_profile | $(BIN_DIR)
5204         $(BIN_DIR)/sawsim_profile -v1e-6 -Mhooke -A.05 -U1 -kkramers_integ \
5205                 -mnull -Mwlc -A0.39e-9,28e-9 -F8
5206         gprof $(BIN_DIR)/sawsim_profile gmon.out > $@
5207 check : $(CHECK_BINS:%=$(BIN_DIR)/%) $(BIN_DIR)/check_sawsim
5208         $(SHELL) -e -c 'for B in $^; do ./$$B; done'
5209 clean : $(CHECK_BINS:%=clean_%) $(SAWSIM_MODS:%=clean_%) \
5210                 clean_tension_model_utils \
5211                 clean_k_model_utils clean_latex clean_check_sawsim
5212         rm -f $(BIN_DIR)/sawsim $(BIN_DIR)/sawsim_static \
5213                 $(BIN_DIR)/sawsim_profile $(BUILD_DIR)/sawsim.c \
5214                 $(BUILD_DIR)/interp.c $(BUILD_DIR)/interp.h \
5215                 $(BUILD_DIR)/tavl.c $(BUILD_DIR)/tavl.h \
5216                 $(BUILD_DIR)/global.h ./gmon.out
5217         $(SHELL) -e -c "rmdir $(BUILD_DIR) $(BIN_DIR) $(DOC_DIR)"
5218
5219 # Various builds of sawsim
5220 $(BIN_DIR)/sawsim : $(SAWSIM_SRC) | $(BIN_DIR)
5221         gcc -g -o $@ $< $(SAWSIM_MODS:%=$(BUILD_DIR)/%.c) $(LIBS:%=-l%)
5222 $(BIN_DIR)/sawsim_static : $(SAWSIM_SRC) | $(BIN_DIR)
5223         gcc -g -static -o $@ $< $(SAWSIM_MODS:%=$(BUILD_DIR)/%.c) $(LIBS:%=-l%)
5224 $(BIN_DIR)/sawsim_profile : $(SAWSIM_SRC) | $(BIN_DIR)
5225         gcc -g -pg -o $@ $< $(SAWSIM_MODS:%=$(BUILD_DIR)/%.c) $(LIBS:%=-l%)
5226
5227 # Create the directories
5228 $(BUILD_DIR) $(BIN_DIR) $(DOC_DIR) :
5229         mkdir $@
5230
5231 # Copy over the source external to sawsim
5232 # Note: Cannot use, for example, `./build', because make eats the `./' 
5233 # and then $(BUILD_DIR) doesn't match in $$(subst $(BUILD_DIR), ...) 
5234 .SECONDEXPANSION:
5235 $(FREE_SAWSIM_MODS:%=$(BUILD_DIR)/%.h) : $$(subst $(BUILD_DIR),$(SRC_DIR),$$@)\
5236                 | $(BUILD_DIR)
5237         cp -f $< $@
5238 .SECONDEXPANSION:
5239 $(FREE_SAWSIM_MODS:%=$(BUILD_DIR)/%.c) : $$(subst $(BUILD_DIR),$(SRC_DIR),$$@)\
5240                 | $(BUILD_DIR)
5241         cp -f $< $@
5242
5243 ## Basic source generated with noweb
5244 # The central files sawsim.c and global.h...
5245 $(BUILD_DIR)/sawsim.c : $(SRC_DIR)/sawsim.nw | $(BUILD_DIR)
5246         notangle $< > $@
5247 $(BUILD_DIR)/global.h : $(SRC_DIR)/sawsim.nw | $(BUILD_DIR)
5248         notangle -Rglobal.h $< > $@
5249 # ... and the modules
5250 $(NW_SAWSIM_MODS:%=$(BUILD_DIR)/%.h) : $(SRC_DIR)/sawsim.nw | $(BUILD_DIR)
5251         notangle -R$(subst _,-,$(@:$(BUILD_DIR)/%=%)) $< > $@
5252 $(NW_SAWSIM_MODS:%=$(BUILD_DIR)/%.c) : $(SRC_DIR)/sawsim.nw | $(BUILD_DIR)
5253         notangle -R$(subst _,-,$(@:$(BUILD_DIR)/%=%)) $< > $@
5254 $(CHECK_BINS:%=$(BUILD_DIR)/%.c) : $(SRC_DIR)/sawsim.nw | $(BUILD_DIR)
5255         notangle -R$(subst _,-,$(@:$(BUILD_DIR)/%=%)) $< > $@
5256 # Note: I use `_' as a space in my file names, but noweb doesn't like
5257 # that so we use `-' to name the noweb roots and substitute here.
5258
5259 ## Building the unit-test programs
5260 # for sawsim.c...
5261 $(BUILD_DIR)/check_sawsim.c : $(SRC_DIR)/sawsim.nw
5262         notangle -Rchecks $< > $@
5263 $(BIN_DIR)/check_sawsim : $(BUILD_DIR)/check_sawsim.c $(BUILD_DIR)/global.h \
5264                 $(SAWSIM_MODS:%=$(BUILD_DIR)/%.c) \
5265                 $(SAWSIM_MODS:%=$(BUILD_DIR)/%.h) | $(BIN_DIR)
5266         gcc -g -o $@ $< $(SAWSIM_MODS:%=$(BUILD_DIR)/%.c) $(CHECK_LIBS:%=-l%)
5267 clean_check_sawsim :
5268         rm -f $(BIN_DIR)/check_sawsim $(BUILD_DIR)/check_sawsim.c
5269 # ... and the modules
5270 .SECONDEXPANSION:
5271 $(CHECK_BINS:%=$(BIN_DIR)/%) : $$(subst $(BIN_DIR),$(BUILD_DIR),$$@).c \
5272                 $$(subst $(BIN_DIR)/check_,$(BUILD_DIR)/,$$@).c \
5273                 $$(subst $(BIN_DIR)/check_,$(BUILD_DIR)/,$$@).h \
5274                 $$(patsubst %,$(BUILD_DIR)/%.c,$$($$(subst $(BIN_DIR)/,,$$@_MODS)))\
5275                 $$(patsubst %,$(BUILD_DIR)/%.h,$$($$(subst $(BIN_DIR)/,,$$@_MODS)))\
5276                 $$(BUILD_DIR)/global.h | $(BIN_DIR)
5277         gcc -g -o $@ $< $(@:$(BIN_DIR)/check_%=$(BUILD_DIR)/%.c) \
5278                 $(patsubst %,$(BUILD_DIR)/%.c,$($(subst $(BIN_DIR)/,,$@_MODS)))\
5279                 $(CHECK_LIBS:%=-l%)
5280 # todo: clean up the required modules to
5281 $(CHECK_BINS:%=clean_%) :
5282         rm -f $(@:clean_%=$(BIN_DIR)/%) $(@:clean_%=$(BUILD_DIR)/%.c)
5283
5284 # Cleaning up the modules
5285 .SECONDEXPANSION:
5286 $(SAWSIM_MODS:%=clean_%) :
5287         rm -f $(@:clean_%=$(BUILD_DIR)/%.c) $(@:clean_%=$(BUILD_DIR)/%.h)
5288
5289 <<tension model utils makefile lines>>
5290 <<k model utils makefile lines>>
5291 <<latex makefile lines>>
5292
5293 Makefile : $(SRC_DIR)/sawsim.nw
5294         notangle -Rmakefile $< | sed 's/        /\t/' > $@
5295
5296 This is fairly self-explanatory.  We compile a dynamically linked
5297 version ([[sawsim]]) and a statically linked version
5298 ([[sawsim_static]]).  The static version is about 9 times as big, but
5299 it runs without needing dynamic GSL libraries to link to, so it's a
5300 better format for distributing to a cluster for parallel evaluation.
5301
5302 \section{Math}
5303
5304 \subsection{Hookean springs in series}
5305 \label{app.math_hooke}
5306
5307 \begin{theorem}
5308 The effective spring constant for $n$ springs $k_i$ in series is given by
5309 $$
5310   k_\text{eff} = \p({\sum_{i \le n}\frac{1}{k_i}})^{-1}.
5311 $$
5312 \end{theorem}
5313
5314 \begin{proof}
5315 \begin{align}
5316   F &= k_i x_i &&\forall i \le n \\
5317   x_i &= \frac{k_j}{k_i} x_j &&\forall i,j \le n \\
5318   x &= \sum_i x_i = x_1 \sum_i \frac{k_1}{k_i} \\
5319   F &= k_1 x_1 = k_\text{eff} x \\
5320   k_\text{eff} &= k_1 \frac{x_1}{x} = \frac{k_1}{\sum_i \frac{k_1}{k_i}} 
5321                 = \p({\sum_{i \le n}\frac{1}{k_i}})^{-1}.
5322 \end{align}
5323 \end{proof}
5324
5325 \phantomsection
5326 \addcontentsline{toc}{section}{References}
5327 \bibliography{sawsim}
5328
5329 \end{document}
5330