82int main(
int argc,
char* argv[]) {
83 int N_arg = (argc > 1) ? std::atoi(argv[1]) : 256;
84 if (N_arg < 32 || N_arg > 512) {
85 std::fprintf(stderr,
"N must be in [32, 512]; got %d\n", N_arg);
90 const double L = 10.0;
91 const double dt = 0.004;
104 double kx_init = 5.0;
107 SetConfigFlags(FLAG_MSAA_4X_HINT);
108 InitWindow(WIN, WIN,
"TDSE -- 2D Quantum Wavepacket [P pot E eigenmodes 1-8 mode SPACE pause R reset LClick place Scroll kx]");
111 std::vector<Color> pixels(N * N);
112 Image img = {pixels.data(), N, N, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8};
113 Texture2D tex = LoadTextureFromImage(img);
116 std::vector<Color> pot_pixels(N * N);
117 Image pot_img = {pot_pixels.data(), N, N, 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8};
118 Texture2D pot_tex = LoadTextureFromImage(pot_img);
119 bool pot_dirty =
true;
123 float sim_time = 0.0f;
124 bool phase_mode =
true;
125 int active_mode = -1;
126 bool computing_modes =
false;
128 auto rebuild_potential_tex = [&]() {
130 for (
int i = 0; i < N; ++i) {
131 for (
int j = 0; j < N; ++j) {
132 double v = solver.
V[solver.
at(i, j)];
133 unsigned char a = (v > V0 * 0.5) ? 200 : 0;
135 pot_pixels[j * N + i] = {220, 220, 255, a};
138 UpdateTexture(pot_tex, pot_pixels.data());
141 rebuild_potential_tex();
143 while (!WindowShouldClose()) {
145 if (IsKeyPressed(KEY_SPACE)) paused = !paused;
146 if (IsKeyPressed(KEY_Q))
break;
147 if (IsKeyPressed(KEY_D)) phase_mode = !phase_mode;
148 if (IsKeyPressed(KEY_EQUAL) || IsKeyPressed(KEY_KP_ADD))
149 substeps = std::min(substeps + 1, 8);
150 if (IsKeyPressed(KEY_MINUS) || IsKeyPressed(KEY_KP_SUBTRACT))
151 substeps = std::max(substeps - 1, 1);
154 float scroll = GetMouseWheelMove();
155 if (std::abs(scroll) > 0.1f) {
156 kx_init = std::clamp(kx_init + scroll * 0.5, 0.5, 20.0);
160 if (IsKeyPressed(KEY_P)) {
161 pot_idx = (pot_idx + 1) % 5;
164 solver.
init_gaussian(L * 0.2, L * 0.5, kx_init, 0.0, L * 0.06);
171 if (IsKeyPressed(KEY_R)) {
172 solver.
init_gaussian(L * 0.2, L * 0.5, kx_init, 0.0, L * 0.06);
178 if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
179 Vector2 mp = GetMousePosition();
180 double x0 = (mp.x / WIN) * L;
181 double y0 = (mp.y / WIN) * L;
188 if (IsKeyPressed(KEY_E)) {
189 computing_modes =
true;
191 computing_modes =
false;
197 for (
int k = 0; k < 8; ++k) {
198 if (IsKeyPressed(KEY_ONE + k)) {
208 for (
int s = 0; s < substeps; ++s) {
210 sim_time +=
static_cast<float>(dt);
214 if (pot_dirty) rebuild_potential_tex();
217 double max_prob = 1e-20;
218 for (
int i = 0; i < N; ++i)
219 for (
int j = 0; j < N; ++j)
220 max_prob = std::max(max_prob, solver.
prob(i, j));
223 for (
int i = 0; i < N; ++i) {
224 for (
int j = 0; j < N; ++j) {
225 double p = solver.
prob(i, j);
228 int screen_j = N - 1 - j;
229 px = screen_j * N + i;
232 pixels[px] = phase_color(p, solver.
phase_ang(i, j), max_prob);
234 pixels[px] = density_color(p, max_prob);
237 UpdateTexture(tex, pixels.data());
240 ClearBackground(BLACK);
243 Rectangle src = {0, 0,
static_cast<float>(N),
static_cast<float>(N)};
244 Rectangle dst = {0, 0,
static_cast<float>(WIN),
static_cast<float>(WIN)};
245 DrawTexturePro(tex, src, dst, {0, 0}, 0.0f, WHITE);
248 DrawTexturePro(pot_tex, src, dst, {0, 0}, 0.0f, WHITE);
250 DrawFPS(WIN - 90, 8);
255 DrawText(TextFormat(
"Grid %dx%d t = %.3f substeps %d [+/-]",
256 N, N, sim_time, substeps), 8, y, FS, RAYWHITE);
260 8, y, FS, {100, 220, 255, 255});
263 DrawText(TextFormat(
"kx = %.1f [scroll] | Colourmap: %s [D]",
264 kx_init, phase_mode ?
"phase-HSV" :
"density"),
265 8, y, FS2, {180, 255, 180, 255});
269 DrawText(TextFormat(
"step %.2f ms norm %.5f E = %.4f",
273 8, y, FS2, {220, 200, 100, 255});
278 DrawText(TextFormat(
"Eigenmodes [%d] (1-8 to view):", solver.
stats.
n_modes),
279 8, y, FS2, {255, 200, 100, 255});
281 int show = std::min(8,
static_cast<int>(solver.
modes.size()));
282 for (
int k = 0; k < show; ++k) {
283 const auto& m = solver.
modes[k];
284 Color c = (k == active_mode) ? Color{255, 255, 100, 255}
285 : Color{180, 180, 180, 255};
286 if (m.exact_energy >= 0)
287 DrawText(TextFormat(
" [%d] E=%.4f exact=%.4f", k+1, m.energy, m.exact_energy),
290 DrawText(TextFormat(
" [%d] E=%.4f", k+1, m.energy), 8, y, FS2, c);
294 DrawText(
"Press E to compute eigenmodes (Lanczos)", 8, y, FS2, {180, 180, 180, 255});
298 if (active_mode >= 0)
299 DrawText(TextFormat(
"Eigenmode %d (SPACE to evolve, R to reset)", active_mode + 1),
300 8, WIN - 40, FS2, {255, 255, 100, 255});
303 DrawText(
"PAUSED", WIN/2 - 48, WIN/2, 32, YELLOW);
305 DrawText(
"SPACE pause P pot E modes 1-8 mode R reset LClick place D color ESC quit",
306 8, WIN - 20, 12, {130, 130, 130, 200});
316 UnloadTexture(pot_tex);