![]() |
dirac_solver 0.0.1
A Dirac ecuation Solver
|
Este documento describe la arquitectura de software de la librería dirac_solver. El diseño se basa en un conjunto de patrones de diseño canónicos para garantizar que el código sea modular, extensible, mantenible y fácil de usar. El objetivo principal es lograr una clara separación de conceptos (Separation of Concerns): la definición del problema físico se mantiene desacoplada de los algoritmos numéricos utilizados para resolverlo. Tabla de Contenidos
| Patrón | Problema que resuelve |
|---|---|
| Builder | Construcción de objetos complejos sin constructores con demasiados parámetros. |
| Strategy | Permite intercambiar algoritmos (ej. integradores, condiciones de frontera) sin modificar el cliente. |
| Template + Factory Method | Extender nuevos componentes físicos de forma coherente y centralizada. |
| Observer | Desacoplar la simulación de la visualización y el monitoreo de datos. |
| Facade | Ocultar la complejidad del sistema de entrada/salida detrás de una interfaz sencilla. |
| Decorator | Extender funcionalidades dinámicamente (ej. logging, validaciones, profiling). |
| Adapter | Interoperar con librerías externas que tienen APIs diferentes. |
Propósito: Construir un objeto complejo (SimulationProblem) paso a paso, proporcionando una API fluida y legible que separa la construcción de la representación.
Aplicación: El usuario final define un problema completo ensamblando sus partes constituyentes (geometría, potencial, condiciones, etc.) sin necesidad de un constructor con múltiples y confusos argumentos. Un DiracProblemBuilder es el punto de entrada principal para el usuario. Este objeto guía la creación de una simulación válida y cohesiva.
Código de Ejemplo (examples/hydrogen_atom.py):
Propósito: Definir una familia de algoritmos, encapsular cada uno y hacerlos intercambiables. Permite que el algoritmo varíe independientemente del cliente que lo utiliza.
Aplicación: Este es el patrón más importante para el núcleo numérico en solvers/. Permite al usuario cambiar el método de integración temporal (ej. CrankNicolson vs. SplitOperator) o las condiciones de frontera (ej. Dirichlet vs. Absorbing) sin modificar el código del bucle de simulación principal.
Propósito:
Aplicación: Se combinan en el módulo potentials/ (y análogamente en geometry/ y conditions/).
Propósito: Definir una dependencia uno-a-muchos entre objetos, de modo que cuando un objeto (Subject) cambia de estado, todos sus dependientes (Observers) son notificados y actualizados automáticamente.
Aplicación: Desacopla el motor de la simulación de los componentes de visualización y registro de datos. El objeto Simulation (Subject) no necesita saber nada sobre cómo se muestran los datos. Simplemente notifica a sus observadores (ej. WavefunctionPlotter, EnergyLogger) en cada paso de tiempo.
Propósito: Proporcionar una interfaz unificada y simplificada a un conjunto de interfaces en un subsistema.
Aplicación: El módulo io/ puede contener lógica compleja para guardar en diferentes formatos (HDF5, npz), cargar, y parsear archivos de configuración. El patrón Facade oculta esta complejidad detrás de una única clase IOManager con métodos sencillos como save(simulation, path) y load(path).
Propósito: Añadir responsabilidades a un objeto de manera dinámica sin modificar su estructura.
Aplicación: Permite extender solvers o visualizadores sin cambiar su código base. Por ejemplo:
Potential o Solver ya existente.Esto permite una instrumentación ligera y flexible, útil para depuración y optimización.
Ejemplo hipotético:
Propósito: Convertir la interfaz de una clase existente en otra que el cliente espera, permitiendo la colaboración entre clases incompatibles.
Aplicación: El solver puede necesitar interoperar con bibliotecas externas (SciPy, PETSc, CuPy, PyTorch). Cada una tiene interfaces distintas para vectores, matrices y rutinas de eigenvalores.
El Adapter proporciona una capa intermedia que traduce entre la API de dirac_solver y la API de la librería de backend. Así, el código cliente no depende de la librería específica.
Ejemplo hipotético:
Esto facilita ofrecer múltiples backends (NumPy, SciPy, GPU) sin que el usuario final deba cambiar su código.
Los patrones no funcionan de forma aislada; se complementan para mantener la arquitectura coherente:
DiracProblemBuilder ensambla la simulación seleccionando estrategias numéricas y componentes físicos generados mediante fábricas.EnergyLogger.IOManager (Facade) puede usar adaptadores internos para guardar datos en distintos backends (HDF5, NumPy, etc.).Solver puede envolverse con decoradores para medir tiempos de ejecución de cada algoritmo concreto.if/else en el bucle principal.saver, loader, parser.LoggingSolverWithValidation).El uso de patrones de diseño en dirac_solver asegura:
Esto permite que la librería crezca de manera ordenada y soporte tanto investigación académica como aplicaciones en entornos de alto rendimiento.