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