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