2 Particle collision with a Gaussian bump.
4 Copyright (C) 2013 W. Trevor King
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stdlib.h> /* for exit(), EXIT_*, malloc(), free() */
21 #include <stdio.h> /* for stderr, *printf() */
22 #include <getopt.h> /* for getopt_long() */
23 #include <assert.h> /* for assert() */
24 #include <math.h> /* for exp(), sqrt() */
25 #include "config.h" /* enabling safe_strtoc() */
26 #include "safe-strto.h" /* for safe_strtol() and safe_strtoc() */
28 static struct option long_options[] = {
29 {"max-time", required_argument, 0, 't' },
30 {"time-step", required_argument, 0, 'd' },
31 {"x0", required_argument, 0, 'x' },
32 {"y0", required_argument, 0, 'y' },
33 {"vx0", required_argument, 0, 'X' },
34 {"vx0-energy", required_argument, 0, 'E' },
35 {"vy0", required_argument, 0, 'Y' },
36 {"mass", required_argument, 0, 'm' },
37 {"bump-magnitude", required_argument, 0, 'k' },
38 {"bump-width", required_argument, 0, 'b' },
42 static char *short_options = "t:d:x:y:X:E:Y:m:k:b:";
44 /* dynamic system parameters */
45 typedef struct state_struct {
47 size_t n; /* number of phase space parameters */
48 double *x; /* position in phase space [x, y, v_x, v_y] */
51 /* function type for phase space derivatives dx_i/dt */
52 typedef void (*dx_dt_fn_t)(state_t *state, void *system, double *dx_dt);
54 /* static potential parameters */
55 typedef struct gaussian_state_struct {
56 double k; /* magnitude */
60 /* static system parameters */
61 typedef struct system_struct {
62 double m; /* particle mass */
63 dx_dt_fn_t dx_dt_fn; /* &singe_gaussian_dx_dt, etc. */
64 void *dx_dt_state; /* gaussian_state_t, etc. */
67 /* Potential: V(r) = 1/2 kb^2 exp(-r^2/b^2)
68 * Force: F(r) = -Divergence(V)
69 * = -1/2 kb^2 * -2r/b^2 * exp(-r^2/b^2)
71 * = k exp(-r^2/b^2) * (x ihat + y jhat)
72 * Acceleration: a(r) = F(r)/m
73 * = k/m * exp(-r^2/b^2) * (x ihat + y jhat)
75 void gaussian_acceleration(gaussian_state_t *state, double m,
77 double *dx_dt, double *dy_dt)
81 double mag = k/m * exp(-(x*x+y*y)/b*b);
87 void single_gaussian_dx_dt(state_t *state, void *system, double *dx_dt)
89 system_t *s = (system_t *)system;
91 assert(state->n == 4);
92 dx_dt[0] = state->x[2]; /* dx/dt = v_x */
93 dx_dt[1] = state->x[3]; /* dy/dt = v_y */
97 gaussian_acceleration((gaussian_state_t *)s->dx_dt_state, s->m,
98 state->x[0], state->x[1],
99 &dx_dt[2], &dx_dt[3]);
102 void step(state_t *state, system_t *system, double dt)
104 double *dx_dt = NULL;
107 dx_dt = malloc(sizeof(double) * state->n);
108 assert(dx_dt); /* check for successful malloc() */
109 (*system->dx_dt_fn)(state, (void *)system, dx_dt);
110 for (i = 0; i < state->n; i++)
111 state->x[i] += dx_dt[i] * dt;
116 /* prints "t\tx[0]\tx[1]\t...\tx[n-1]\n" */
117 void print_state(state_t *state)
121 printf("%g", state->t);
122 for (i = 0; i < state->n; i++)
123 printf("\t%g", state->x[i]);
127 void parse_args(int argc, char **argv, double *dt, double *t_max,
128 state_t *state, system_t *system)
131 gaussian_state_t *gstate = (gaussian_state_t *)system->dx_dt_state;
134 ch = getopt_long(argc, argv, short_options, long_options, NULL);
139 *t_max = safe_strtod(optarg, "max-time");
142 *dt = safe_strtod(optarg, "time-step");
145 state->x[0] = safe_strtod(optarg, "x0");
148 state->x[1] = safe_strtod(optarg, "y0");
151 state->x[2] = safe_strtod(optarg, "vx0");
154 state->x[2] = -sqrt(2*safe_strtod(optarg, "vx0-energy")/system->m);
157 state->x[3] = safe_strtod(optarg, "vy0");
160 system->m = safe_strtod(optarg, "mass");
163 gstate->k = safe_strtod(optarg, "bump-magnitude");
166 gstate->b = safe_strtod(optarg, "bump-width");
171 printf("?? getopt returned character code 0%o ??\n", ch);
177 int main(int argc, char **argv) {
181 double x[4] = {3.5, 0, 0, 0};
182 system_t system = {};
183 gaussian_state_t gaussian = {};
185 state.x = (double *)x;
186 state.n = sizeof(x) / sizeof(double);
188 system.dx_dt_fn = &single_gaussian_dx_dt;
189 system.dx_dt_state = (void *)&gaussian;
192 state.x[2] = -sqrt(2*0.5/system.m); /* v = -sqrt(2E/m), with E = 0.5 */
194 parse_args(argc, argv, &dt, &t_max, &state, &system);
197 while (state.t < t_max) {
198 step(&state, &system, dt);