dirac_solver 0.0.1
A Dirac ecuation Solver
Cargando...
Buscando...
Nada coincide
TimeIntegrator.h
Ir a la documentación de este archivo.
1#pragma once
2
3#include <iostream>
4#include <string>
5#include <vector>
6#include <stdexcept>
7#include <memory>
8#include <pybind11/pybind11.h>
9#include <pybind11/numpy.h>
10
11#include "Grid.h"
14#include "DiracMatrices.h"
15
16namespace py = pybind11;
17
30public:
31 virtual ~TimeIntegrator() = default;
32
39 virtual void step() = 0;
40
45 virtual std::string get_name() const = 0;
46};
47
70public:
88 py::array_t<std::complex<double>, py::array::c_style | py::array::forcecast> initial_psi,
89 const Grid& grid,
90 std::shared_ptr<Potential> potential,
91 std::shared_ptr<BoundaryCondition> boundary_condition,
92 double dt,
93 double mass)
94 : grid_(grid), potential_(potential), boundary_condition_(boundary_condition), dt_(dt), mass_(mass)
95 {
96 // Validación de dimensiones de entrada
97 py::buffer_info psi_info = initial_psi.request();
98 if (psi_info.ndim != 2 || psi_info.shape[1] != 4) {
99 throw std::runtime_error("El psi inicial debe ser un array de NumPy de forma (N, 4)");
100 }
101 if (static_cast<size_t>(psi_info.shape[0]) != grid_.get_total_points()) {
102 throw std::runtime_error("El número de puntos en psi debe coincidir con el total de puntos de la malla.");
103 }
104
105 // Asignación de memoria
106 size_t n_points = grid_.get_total_points();
107 psi_curr_.resize(n_points);
108 psi_prev_.resize(n_points);
109 psi_next_.resize(n_points);
110
111 // Copiar datos desde el array de NumPy a psi_curr_
112 auto ptr = static_cast<Dirac::complex*>(psi_info.ptr);
113 for (size_t i = 0; i < n_points; ++i)
114 for (size_t j = 0; j < 4; ++j)
115 psi_curr_[i].components[j] = ptr[i * 4 + j];
116
117 // Inicialización básica del buffer previo
118 psi_prev_ = psi_curr_;
119 }
120
133 void step() override {
134 size_t n_points = grid_.get_total_points();
135 const auto& shape = grid_.get_shape();
136 const auto& spacing = grid_.get_spacing();
137 bool is_periodic = (boundary_condition_->get_name() == "PeriodicBoundary");
138
139 for (size_t i = 0; i < n_points; ++i) {
140 Dirac::Spinor h_spatial_psi;
141
142 // --- Operador diferencial espacial según la dimensionalidad ---
143 if (grid_.get_dim() == 1) {
144 size_t i_prev = (is_periodic && i == 0) ? n_points - 1 : i - 1;
145 size_t i_next = (is_periodic && i == n_points - 1) ? 0 : i + 1;
146 h_spatial_psi = Dirac::multiply(Dirac::alpha_z, psi_curr_[i_next] - psi_curr_[i_prev]);
147 h_spatial_psi = (Dirac::complex(0, -1.0) / (2.0 * spacing[0])) * h_spatial_psi;
148 }
149 else if (grid_.get_dim() == 2) {
150 size_t nx = shape[0];
151 size_t ny = shape[1];
152 size_t ix = i % nx;
153 size_t iy = i / nx;
154 size_t ix_prev = (is_periodic && ix == 0) ? nx - 1 : ix - 1;
155 size_t ix_next = (is_periodic && ix == nx - 1) ? 0 : ix + 1;
156 size_t iy_prev = (is_periodic && iy == 0) ? ny - 1 : iy - 1;
157 size_t iy_next = (is_periodic && iy == ny - 1) ? 0 : iy + 1;
158
159 Dirac::Spinor dx_psi = Dirac::multiply(Dirac::alpha_x, psi_curr_[iy * nx + ix_next] - psi_curr_[iy * nx + ix_prev]);
160 Dirac::Spinor dy_psi = Dirac::multiply(Dirac::alpha_y, psi_curr_[iy_next * nx + ix] - psi_curr_[iy_prev * nx + ix]);
161 h_spatial_psi = (Dirac::complex(0, -1.0) / (2.0 * spacing[0])) * dx_psi +
162 (Dirac::complex(0, -1.0) / (2.0 * spacing[1])) * dy_psi;
163 }
164 else if (grid_.get_dim() == 3) {
165 size_t nx = shape[0];
166 size_t ny = shape[1];
167 size_t nz = shape[2];
168 size_t ix = i % nx;
169 size_t iy = (i / nx) % ny;
170 size_t iz = i / (nx * ny);
171
172 size_t ix_prev = (is_periodic && ix == 0) ? nx - 1 : ix - 1;
173 size_t ix_next = (is_periodic && ix == nx - 1) ? 0 : ix + 1;
174 size_t iy_prev = (is_periodic && iy == 0) ? ny - 1 : iy - 1;
175 size_t iy_next = (is_periodic && iy == ny - 1) ? 0 : iy + 1;
176 size_t iz_prev = (is_periodic && iz == 0) ? nz - 1 : iz - 1;
177 size_t iz_next = (is_periodic && iz == nz - 1) ? 0 : iz + 1;
178
179 Dirac::Spinor dx_psi = Dirac::multiply(Dirac::alpha_x, psi_curr_[iz * nx * ny + iy * nx + ix_next] - psi_curr_[iz * nx * ny + iy * nx + ix_prev]);
180 Dirac::Spinor dy_psi = Dirac::multiply(Dirac::alpha_y, psi_curr_[iz * nx * ny + iy_next * nx + ix] - psi_curr_[iz * nx * ny + iy_prev * nx + ix]);
181 Dirac::Spinor dz_psi = Dirac::multiply(Dirac::alpha_z, psi_curr_[(iz_next * nx * ny) + iy * nx + ix] - psi_curr_[(iz_prev * nx * ny) + iy * nx + ix]);
182 h_spatial_psi = (Dirac::complex(0, -1.0) / (2.0 * spacing[0])) * dx_psi +
183 (Dirac::complex(0, -1.0) / (2.0 * spacing[1])) * dy_psi +
184 (Dirac::complex(0, -1.0) / (2.0 * spacing[2])) * dz_psi;
185 }
186
187 // --- Término local del Hamiltoniano ---
188 std::vector<double> coords = grid_.get_coords(i);
189 double v_at_i = potential_->evaluate(coords);
190 Dirac::Spinor h_local_psi = mass_ * Dirac::multiply(Dirac::beta, psi_curr_[i]) + v_at_i * psi_curr_[i];
191
192 // --- Actualización temporal ---
193 Dirac::Spinor h_psi = h_spatial_psi + h_local_psi;
194 psi_next_[i] = psi_prev_[i] - (Dirac::complex(0, 2.0) * dt_) * h_psi;
195 }
196
197 // Aplicar condición de frontera
198 boundary_condition_->apply(psi_next_, grid_);
199
200 // Rotar buffers de tiempo
201 psi_prev_ = psi_curr_;
202 psi_curr_ = psi_next_;
203 }
204
209 std::string get_name() const override {
210 return "FDTDLeapfrogIntegrator";
211 }
212
221 py::array_t<std::complex<double>> get_psi() const {
222 py::array_t<std::complex<double>> result({grid_.get_total_points(), 4ul});
223 auto buf = result.request();
224 auto* ptr = static_cast<std::complex<double>*>(buf.ptr);
225
226 for (size_t i = 0; i < grid_.get_total_points(); ++i)
227 for (size_t j = 0; j < 4; ++j)
228 ptr[i * 4 + j] = psi_curr_[i].components[j];
229
230 return result;
231 }
232
233private:
234 Grid grid_;
235 std::shared_ptr<Potential> potential_;
236 std::shared_ptr<BoundaryCondition> boundary_condition_;
237 double dt_;
238 double mass_;
240 std::vector<Dirac::Spinor> psi_prev_;
241 std::vector<Dirac::Spinor> psi_curr_;
242 std::vector<Dirac::Spinor> psi_next_;
243};
Implementación concreta de TimeIntegrator mediante el esquema FDTD de salto de rana (Leapfrog).
Definition TimeIntegrator.h:69
void step() override
Avanza un paso de tiempo completo según el esquema FDTD Leapfrog.
Definition TimeIntegrator.h:133
std::string get_name() const override
Devuelve el nombre del integrador.
Definition TimeIntegrator.h:209
FDTDLeapfrogIntegrator(py::array_t< std::complex< double >, py::array::c_style|py::array::forcecast > initial_psi, const Grid &grid, std::shared_ptr< Potential > potential, std::shared_ptr< BoundaryCondition > boundary_condition, double dt, double mass)
Constructor principal del integrador Leapfrog.
Definition TimeIntegrator.h:87
py::array_t< std::complex< double > > get_psi() const
Devuelve la función de onda actual en formato NumPy.
Definition TimeIntegrator.h:221
Representa una malla espacial (1D, 2D o 3D) para la simulación.
Definition Grid.h:16
size_t get_dim() const
Definition Grid.h:39
std::vector< double > get_coords(size_t index) const
Obtiene las coordenadas espaciales para un índice de malla plano dado.
Definition Grid.h:60
size_t get_total_points() const
Calcula el número total de puntos en la malla.
Definition Grid.h:47
const std::vector< double > & get_spacing() const
Definition Grid.h:41
const std::vector< size_t > & get_shape() const
Definition Grid.h:40
Clase base abstracta para algoritmos de evolución temporal (patrón Strategy).
Definition TimeIntegrator.h:29
virtual void step()=0
Realiza un único paso de evolución temporal.
virtual ~TimeIntegrator()=default
virtual std::string get_name() const =0
Devuelve el nombre del integrador.
Spinor multiply(const Matrix4x4 &M, const Spinor &s)
Definition DiracMatrices.h:63
const Matrix4x4 alpha_y
Definition DiracMatrices.h:48
const Matrix4x4 alpha_z
Definition DiracMatrices.h:55
const Matrix4x4 alpha_x
Definition DiracMatrices.h:41
std::complex< double > complex
Definition DiracMatrices.h:9
const Matrix4x4 beta
Definition DiracMatrices.h:33
Definition DiracMatrices.h:12