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