+\subsection{Tension model unit tests}
+
+Here we check to make sure the various functions work as expected, using \citetalias{sw:check}.
+<<check-tension-model.c>>=
+<<license comment>>
+<<tension model check includes>>
+<<check relative error>>
+<<model globals>>
+<<tension model test suite>>
+<<main check program>>
+@
+
+<<tension model check includes>>=
+#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
+#include <stdio.h> /* sprintf() */
+#include <assert.h> /* assert() */
+#include <math.h> /* exp() */
+#include <errno.h> /* errno, ERANGE */
+<<check includes>>
+#include "global.h"
+#include "list.h"
+#include "tension_balance.h" /* oneD_*() */
+#include "tension_model.h"
+@
+
+<<tension model test suite>>=
+<<safe strto*>>
+<<const tension tests>>
+<<hooke tests>>
+<<worm-like chain tests>>
+<<freely-jointed chain tests>>
+<<piston tests>>
+<<tension model suite definition>>
+@
+
+<<tension model suite definition>>=
+Suite *test_suite (void)
+{
+ Suite *s = suite_create ("tension model");
+ <<const tension test case defs>>
+ <<hooke test case defs>>
+ <<worm-like chain test case defs>>
+ <<freely-jointed chain test case defs>>
+ <<piston test case defs>>
+
+ <<const tension test case adds>>
+ <<hooke test case adds>>
+ <<worm-like chain test case adds>>
+ <<freely-jointed chain test case adds>>
+ <<piston test case adds>>
+ return s;
+}
+@
+
+\subsubsection{Constant}
+
+<<const tension test case defs>>=
+TCase *tc_const_tension = tcase_create("Constant tension");
+@
+
+<<const tension test case adds>>=
+tcase_add_test(tc_const_tension, test_const_tension_create_destroy);
+suite_add_tcase(s, tc_const_tension);
+@
+
+<<const tension tests>>=
+START_TEST(test_const_tension_create_destroy)
+{
+ char *tension[] = {"1","2.2", "3"};
+ char *params[] = {tension[0]};
+ void *p = NULL;
+ int i;
+ for( i=0; i < sizeof(tension)/sizeof(char *); i++) {
+ params[0] = tension[i];
+ p = string_create_const_tension_param_t(params);
+ destroy_const_tension_param_t(p);
+ }
+}
+END_TEST
+
+@ TODO: In order to test the constant tension handler itself, we'd
+have to construct a group.
+
+
+\subsubsection{Hooke}
+
+<<hooke test case defs>>=
+TCase *tc_hooke = tcase_create("Hooke");
+@
+
+<<hooke test case adds>>=
+tcase_add_test(tc_hooke, test_hooke_create_destroy);
+suite_add_tcase(s, tc_hooke);
+
+@
+
+<<hooke tests>>=
+START_TEST(test_hooke_create_destroy)
+{
+ char *k[] = {"1","2.2", "3"};
+ char *params[] = {k[0]};
+ void *p = NULL;
+ int i;
+ for( i=0; i < sizeof(k)/sizeof(char *); i++) {
+ params[0] = k[i];
+ p = string_create_hooke_param_t(params);
+ destroy_hooke_param_t(p);
+ }
+}
+END_TEST
+
+@ TODO: In order to test the Hooke tension handler itself, we'd
+have to construct a group.
+
+
+\subsubsection{Worm-like chain}
+
+<<worm-like chain test case defs>>=
+TCase *tc_wlc = tcase_create("WLC");
+@
+
+<<worm-like chain test case adds>>=
+tcase_add_test(tc_wlc, test_wlc_at_zero);
+tcase_add_test(tc_wlc, test_wlc_at_half);
+suite_add_tcase(s, tc_wlc);
+
+@
+
+<<worm-like chain tests>>=
+<<worm-like chain function>>
+START_TEST(test_wlc_at_zero)
+{
+ double T=1.0, L=1.0, p=0.1, x=0.0, lim=1e-30;
+ fail_unless(abs(wlc(x, T, p, L)) < lim, \
+ "abs(wlc(x=%g,T=%g,p=%g,L=%g)) = %g >= %g",
+ x, T, p, L, abs(wlc(x, T, p, L)), lim);
+}
+END_TEST
+
+START_TEST(test_wlc_at_half)
+{
+ double T=1.0, L=1.0, p=0.1*k_B, x=0.5;
+ /* prefactor = k_B T / p = k_B 1.0 / (k_B*0.1) = 10.0 J/nm = 10.0e21 pN
+ * nonlinear term = 0.25 (1/(1-x/L)^2-1) = 0.25(1/.25 - 1)
+ * = 0.25 * 3 = 3/4
+ * linear term = x/L = 0.5
+ * nonlinear + linear = 0.75 + 0.5 = 1.25
+ * wlc = 10e21*1.25 = 12.5e21
+ */
+ fail_unless(wlc(x, T, p, L)-12.5e21 < 1e16,
+ "wlc(%g, %g, %g, %g) = %g != %g",
+ x, T, p, L, wlc(x, T, p, L), 12.5e21);
+}
+END_TEST
+
+@
+
+
+\subsubsection{Freely-jointed chain}
+
+<<freely-jointed chain test case defs>>=
+TCase *tc_fjc = tcase_create("FJC");
+@
+
+<<freely-jointed chain test case adds>>=
+tcase_add_test(tc_fjc, test_fjc_at_zero);
+tcase_add_test(tc_fjc, test_fjc_at_half);
+suite_add_tcase(s, tc_fjc);
+
+@
+
+<<freely-jointed chain tests>>=
+<<freely-jointed chain function>>
+START_TEST(test_fjc_at_zero)
+{
+ int N=10;
+ double T=1.0, l=1.0, p=0.1, x=0.0, lim=1e-30;
+ fail_unless(abs(fjc(x, T, l, N)) < lim, \
+ "abs(fjc(x=%g,T=%g,l=%g,N=%d)) = %g >= %g",
+ x, T, l, N, abs(fjc(x, T, l, N)), lim);
+}
+END_TEST
+
+START_TEST(test_fjc_at_half)
+{
+ int N = 10;
+ double T=1.0/k_B, l=1.0, x=5.0;
+ /* prefactor = k_B T / l = k_B (1.0/k_B) / 1.0 = 1.0 J/nm = 1.0e21 pN
+ * nonlinear term = 0.25 (1/(1-x/L)^2-1) = 0.25(1/.25 - 1)
+ * = 0.25 * 3 = 3/4
+ * linear term = x/L = 0.5
+ * nonlinear + linear = 0.75 + 0.5 = 1.25
+ * fjc = 10e21*1.25 = 12.5e21
+ */
+ fail_unless(fjc(x, T, l, N)-12.5e21 < 1e16,
+ "fjc(%g, %g, %g, %d) = %g != %g",
+ x, T, l, N, fjc(x, T, l, N), 12.5e21);
+}
+END_TEST
+
+@
+
+
+\subsubsection{Piston}
+
+<<piston test case defs>>=
+TCase *tc_piston = tcase_create("Piston");
+@
+
+<<piston test case adds>>=
+tcase_add_test(tc_piston, test_piston_create_destroy);
+suite_add_tcase(s, tc_piston);
+
+@
+
+<<piston tests>>=
+START_TEST(test_piston_create_destroy)
+{
+ char *L[] = {"1","2.2", "3"};
+ char *params[] = {L[0]};
+ void *p = NULL;
+ int i;
+ for( i=0; i < sizeof(L)/sizeof(char *); i++) {
+ params[0] = L[i];
+ p = string_create_piston_tension_param_t(params);
+ destroy_piston_tension_param_t(p);
+ }
+}
+END_TEST
+
+@ TODO: In order to test the piston tension handler itself, we'd
+have to construct a group.
+