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