Skip to content

Project 2 Architecture🪶

Conceptual Overview🪶

Project 2 employs a coupled physics-informed architecture that jointly learns: $$ V_\theta(x) \, , \qquad \psi_n^\theta(x) \, , \qquad E_n^\theta \,. $$

This results in a model that behaves as a constrained operator-learning system whose goal is to identify physically consistent Hamiltonian structure rather than simply interpolate observed data.

Overall Architecture🪶

%%{ init: { "theme": "base", "themeVariables": { "background": "#0D1117", "primaryColor": "#14B5FF", "primaryTextColor": "#F0F6FC", "primaryBorderColor": "#14B5FF", "lineColor": "#4CC9F0", "secondaryColor": "#0070EB", "tertiaryColor": "#0D1117", "fontFamily": "'Aclonica', sans-serif", "fontSize": "16px", "clusterBkg": "rgba(20, 181, 255, 0.02)", "clusterBorder": "#14B5FF", "edgeLabelBackground":"#0D1117", "nodeSpacing": 81, "rankSpacing": 131, "borderRadius": "16" }, "themeCSS": ".node rect, .node circle, .node ellipse, .node polygon, .node path { stroke-width: 2.618px !important; filter: drop-shadow(0px 4px 6px rgba(0,0,0, 0.5)); } .node { filter: saturate(1.2) contrast(1.1); } .cluster rect { rx: 25.8; ry: 25.8; stroke-width: 1px; stroke-dasharray: 10,5; } .nodeLabel, .edgeLabel, .cluster-label, .label text, text, .katex, .katex *, .MathJax, .MathJax *, mjx-container, mjx-container * { color: #F0F6FC !important; fill: #F0F6FC !important; font-weight: 300; } #PIML .cluster-label { fill: #00FFFF !important; font-size: 20px; } #PIML rect { stroke: #00E8FF; fill: rgba(0, 232, 255, 0.04); } .marker, .arrowMarkerPath, .marker path, .marker polygon { fill: #4CC9F0 !important; stroke: #4CC9F0 !important; } .flowchart-link, .edgePaths .path { stroke: #4CC9F0; stroke-width: 1.618px; } .edge-thickness-thick:not([class*='LS-sanity']), [class*='LS-opt'] { stroke: #FE28A2 !important; stroke-width: 3.8px !important; filter: drop-shadow(0 0 6px #FE28A2) drop-shadow(0 0 12px rgba(254, 40, 162, 0.8)) !important; opacity: 1 !important; } [class*='LS-sanity'][class*='LE-pod'], .edge-thickness-invisible { stroke: transparent !important; stroke-width: 0 !important; filter: none !important; opacity: 0 !important; fill: none !important; } [class*='LE-opt'] { stroke: #00FFFF !important; stroke-width: 2.8px !important; filter: drop-shadow(0 0 5px #00FFFF) drop-shadow(0 0 10px rgba(0, 255, 255, 0.75)) !important; opacity: 1 !important; } [class*='LS-R'][class*='LE-Lp'] { stroke: #03E8BD !important; stroke-width: 2.8px !important; filter: drop-shadow(0 0 5px #03E8BD) drop-shadow(0 0 10px rgba(3, 232, 189, 0.75)) !important; opacity: 1 !important; } .node.opt rect, [id*='flowchart-opt-'] rect { stroke: #FE28A2 !important; stroke-width: 3.5px !important; filter: drop-shadow(0 0 8px #FE28A2) drop-shadow(0 0 16px rgba(254, 40, 162, 0.75)) !important; } .node.loss_terms rect, [id*='flowchart-L'] rect { stroke: #00FFFF !important; stroke-width: 3px !important; filter: drop-shadow(0 0 6px #00FFFF) drop-shadow(0 0 12px rgba(0, 255, 255, 0.7)) !important; } .node.physics rect, [id*='flowchart-R-'] rect { stroke: #03E8BD !important; stroke-width: 3.5px !important; filter: drop-shadow(0 0 8px #03E8BD) drop-shadow(0 0 16px rgba(3, 232, 189, 0.75)) !important; } .node.MLP rect, [id*='flowchart-MLP'] rect { stroke: #9A66FF !important; stroke-width: 3.2px !important; filter: drop-shadow(0 0 7px #9A66FF) drop-shadow(0 0 14px rgba(154, 102, 255, 0.7)) !important; } .node.energy rect, [id*='flowchart-E'] rect { stroke: #3B9EFF !important; stroke-width: 3.2px !important; filter: drop-shadow(0 0 7px #3B9EFF) drop-shadow(0 0 14px rgba(59, 158, 255, 0.7)) !important; }", "flowchart": { "curve": "basis", "useMaxWidth": false, "htmlLabels": true, "rankSpacing": 131, "nodeSpacing": 81 } } }%% flowchart TB %% ============================== %% COLOR CLASSES & STYLES %% ============================== %% Node colors preserved as requested, but with golden ratio radius (rx:16, ry:16) style step0 fill:#1c1033,stroke:#a855f7,stroke-width:3.5px,color:#FFF9D6,rx:16, ry:16; style PIML fill:#0b1020,stroke:#00FFFF,stroke-width:4px,color:#ffffff,stroke-dasharray:6 6,rx:16, ry:16; style potential fill:#11163a,stroke:#14B5FF,stroke-width:3.5px,color:#ffffff,rx:16, ry:16; style neural_ansatz fill:#0d1a30,stroke:#9A66FF,stroke-width:3px,color:#ffffff,stroke-dasharray:6 6,rx:16, ry:16; style energy_init fill:#1a233a,stroke:#3b82ff,stroke-width:2px,color:#ffffff,stroke-dasharray:5 5,rx:16,ry:16; style energy_eigenvalues fill:#071320,stroke:#3b9eff,stroke-width:3.5px,color:#ffffff,stroke-dasharray:6 6,rx:16,ry:16; style PINN fill:#131130,stroke:#9A66FF,stroke-width:3px,color:#ffffff,stroke-dasharray:6 6,rx:16, ry:16; style loss fill:#0a0f1a,stroke:#00FFFF,stroke-width:3px,color:#ffffff,stroke-dasharray:6 6,rx:16, ry:16; classDef MLP fill:#2a185c,stroke:#9a66ff,stroke-width:3.5px,color:#ffffff,rx:16, ry:16; classDef eigenfunctions fill:#153a55,stroke:#4ec9ff,stroke-width:2px,color:#ffffff,rx:16, ry:16; classDef energy fill:#0d2238,stroke:#3b9eff,stroke-width:3.5px,color:#ffffff,rx:16, ry:16; classDef loss_terms fill:#0b1326,stroke:#00FFFF,stroke-width:3px,color:#ffffff,rx:16, ry:16; style synthetic_data fill:#010209,stroke:#5D3FD3,stroke-width:2px,stroke-dasharray:6 6,color:#ffffff,rx:16,ry:16; style domain_norm fill:#0c0010,stroke:#750071,stroke-width:2px,color:#ffffff,rx:16,ry:16,stroke-dasharray:6 6; style observed_data fill:#142034,stroke:#5280ff,stroke-width:2px,color:#ffffff,rx:16,ry:16; style trap fill:#023e00,stroke:#57ffbc,color:#ffffff,stroke-width:2px,rx:16,ry:16; style raw_wavefunctions fill:#224261,stroke:#14B5FF,stroke-width:2px,stroke-dasharray:6 6,color:#ffffff,rx:16,ry:16; style normalization fill:#0f2335,stroke:#4b54ff,color:#ffffff,stroke-width:2px,stroke-dasharray:6 6,rx:16,ry:16; style normalized_wavefunctions fill:#112230,color:#ffffff,stroke:#4b54ff,stroke-width:2px,stroke-dasharray:6 6,rx:16,ry:16; style finite_difference fill:#011e00,stroke:#31ff48,color:#ffffff,stroke-width:2px,stroke-dasharray:6 6,rx:16,ry:16; style residual fill:#0d2827,stroke:#03E8BD,stroke-width:3px,color:#ffffff,stroke-dasharray:6 6,rx:16,ry:16; style diagnostics fill:#161b22,stroke:#FF66B3,stroke-dasharray:6 6,color:#ffffff,rx:16,ry:16; style pod fill:#0d1b2a,stroke:#00d4ff,color:#ffffff,stroke-width:2px,stroke-dasharray:6 6,rx:16,ry:16; classDef spatial_stencil fill:#2a0037,stroke:#750071,stroke-width:2px,color:#ffffff,rx:16,ry:16; classDef norm fill:#1e2b4e,stroke:#4b54ff,color:#ffffff,stroke-width:2px,rx:16,ry:16; classDef psiraw fill:#224261,stroke:#14B5FF,color:#ffffff,stroke-width:2.8px,rx:16,ry:16; classDef psinorm fill:#224261,stroke:#14B5FF,stroke-width:2.8px,color:#ffffff,rx:16,ry:16; classDef stencil fill:#023e00,stroke:#31ff48,color:#ffffff,stroke-width:2px,rx:16,ry:16; classDef physics fill:#1c5654,stroke:#03E8BD,color:#ffffff,stroke-width:3.5px,rx:16,ry:16; classDef opt fill:#2a071b,stroke:#FE28A2,color:#ffffff,stroke-width:3.5px,stroke-dasharray:6 6,rx:16,ry:16; classDef diag fill:#2f1616,stroke:#FF66B3,stroke-width:2px,stroke-dasharray:6 6,rx:16,ry:16; %% ============================== %% NODES %% ============================== potential(["$$V_\theta$$"]) psi0_raw(["$$ \psi_0^\theta $$"]):::psiraw psi1_raw(["$$\psi_1^\theta$$"]):::psiraw psi2_raw(["$$\psi_2^\theta$$"]):::psiraw psi0(["$$\hat{\psi}_0^\theta$$"]):::psinorm psi1(["$$\hat{\psi}_1^\theta$$"]):::psinorm psi2(["$$\hat{\psi}_2^\theta$$"]):::psinorm E0(["$$E_0^\theta$$"]):::energy E1(["$$E_1^\theta$$"]):::energy E2(["$$E_2^\theta$$"]):::energy %% ============================== %% PIPELINE %% ============================== subgraph PIML["PIML Framework"] direction LR subgraph synthetic_data["1️⃣ Synthetic Data"] direction LR subgraph domain_norm["Uniform Grid"] spatial_grid["$$x\in[-5, 5]$$"]:::spatial_stencil deltax["$$\Delta x$$"]:::spatial_stencil end trap["Trapezoidal weights"] observed_data("$$\rho_n^\text{obs}, \ E_n^\text{obs}$$") end subgraph neural_ansatz["2️⃣ Neural Ansatz"] direction TB subgraph energy_init["Linear Energy Initialization"] E_init["$$E_n = \text{linspace}(0.5, n-0.5, n)$$"]:::energy end subgraph energy_eigenvalues["Energy Eigenvalues"] E0 E1 E2 end E_init --> energy_eigenvalues subgraph PINN["2️⃣ PINN"] direction LR subgraph raw_wavefunctions["Raw Learned Wavefunctions"] direction TB psi0_raw psi1_raw psi2_raw end MLP1("MLP"):::MLP --> potential MLP2("MLP"):::MLP --> psi0_raw MLP3("MLP"):::MLP --> psi1_raw MLP4("MLP"):::MLP --> psi2_raw end end subgraph normalization["3️⃣A Orthonormalization"] direction TB apply_trapezoidal_weights["$$\int|\psi_n^\theta |^2 dx$$"]:::norm gs["GS+re-norm"]:::norm eps("$$+\epsilon \ \text{stability}$$"):::norm end subgraph normalized_wavefunctions["Normalized Wavefunctions"] direction TB psi0 psi1 psi2 end subgraph finite_difference["3️⃣B Finite difference"] direction TB eigenfunction_stencil("$$\frac{\partial^2}{dx^2}\hat{\psi}_n^\theta$$"):::stencil potential_stencil("$$V_\theta''(x)$$"):::stencil end subgraph residual["4️⃣ Physics Residual"] direction LR R["$$R_n(x)=-\frac{1}{2}\nabla^2\hat{\psi} + (V-E)\hat{\psi}$$"]:::physics end style R stroke-width:5px; subgraph loss["5️⃣ Total Loss"] direction TB Lp["Physics loss"]:::loss_terms Ln["Order"]:::loss_terms Ls["Smoothness"]:::loss_terms Ld["Data mismatch"]:::loss_terms end opt["6️⃣ Optimizer (Adam)"]:::opt %% FLOW spatial_grid --> MLP1 & MLP2 & MLP3 & MLP4 deltax & trap --> apply_trapezoidal_weights psi0_raw & psi1_raw & psi2_raw --> gs apply_trapezoidal_weights & eps --> gs gs --> psi0 & psi1 & psi2 psi0 & psi1 & psi2 --> eigenfunction_stencil & R potential --> potential_stencil & R eigenfunction_stencil --> R E0 & E1 & E2 --> R & Ln & Ld R --> Lp potential & potential_stencil --> Ls psi0 & psi1 & psi2 --> Ls & Ld observed_data --> Ld Lp & Ln & Ls & Ld --> opt opt ==> MLP1 opt ==> MLP2 opt ==> MLP3 opt ==> MLP4 opt ==> E0 opt ==> E1 opt ==> E2 end %% ============================== %% DIAGNOSTICS %% ============================== subgraph diagnostics["7️⃣ Diagnostics"] direction TB sanity["sanity checks"]:::diag pod["7️⃣ POD analysis"]:::pod sanity ~~~ pod end step0["0️⃣ Define TISE dynamics"]:::step0 --> PIML psi0 & psi1 & psi2 --> sanity & pod E0 & E1 & E2 --> sanity potential --> sanity deltax & trap --> pod %% ============================== %% LINKS %% ============================== linkStyle default stroke:#4CC9F0,stroke-width:1.618px,opacity:0.75 linkStyle 36 stroke:#03E8BD,stroke-width:2.8px,opacity:1 linkStyle 46,47,48,49 stroke:#00FFFF,stroke-width:2.8px,opacity:1 linkStyle 50,51,52,53,54,55,56 stroke:#FE28A2,stroke-width:3.8px,opacity:1 linkStyle 71 stroke:#A855F7,stroke-width:2.5px,opacity:0.95

End-to-end PIML pipeline

The diagram illustrates the physics-informed machine learning pipeline for solving the Schrödinger equation implemented in project 2.

Step # Descripition
0️⃣ Definition of the physical system (TISE).
1️⃣ Synthetic data generation on a uniform grid with trapezoidal weights.
2️⃣ Neual ansatz comprising MLPs for the potential \(V_\theta\) and wavefunctions \(\psi_n^\theta\), alongside trainable energy eigenvalues \(E_n^\theta\).
3️⃣ Wavefunction orthonormalization via Gram-Schmidt and finite-difference derivative calculation.
4️⃣ Calculation of the physics residual \(R_n(x)\) where the governing law is enforced.
5️⃣ Total loss computation combining physics, smoothness, and data mismatch terms.
6️⃣ Optimization via Adam, feeding back into the trainable parameters (thick arrows).
7️⃣ Parallel analysis including sanity checks and POD.

POD Diagnostics🪶

%%{ init: { "theme": "base", "themeVariables": { "background": "#0D1117", "primaryColor": "#14B5FF", "primaryTextColor": "#F0F6FC", "primaryBorderColor": "#14B5FF", "lineColor": "#4CC9F0", "secondaryColor": "#0070EB", "tertiaryColor": "#0D1117", "fontFamily": "'Aclonica', sans-serif", "fontSize": "16px", "clusterBkg": "rgba(20, 181, 255, 0.02)", "clusterBorder": "#14B5FF", "edgeLabelBackground":"#0D1117", "nodeSpacing": 81, "rankSpacing": 131, "borderRadius": "16" }, "themeCSS": ".node rect, .node circle, .node ellipse, .node polygon, .node path { stroke-width: 2.618px !important; filter: drop-shadow(0px 4px 6px rgba(0,0,0, 0.5)); } .node { filter: saturate(1.2) contrast(1.1); } .cluster rect { rx: 25.8; ry: 25.8; stroke-width: 1px; stroke-dasharray: 10,5; } .nodeLabel, .edgeLabel, .cluster-label, .label text, text, .katex, .katex *, .MathJax, .MathJax *, mjx-container, mjx-container * { color: #F0F6FC !important; fill: #F0F6FC !important; font-weight: 300; } #pod .cluster-label { fill: #00D4FF !important; font-size: 20px; } #pod rect { stroke: #00D4FF; fill: rgba(0, 212, 255, 0.04); }", "flowchart": { "curve": "basis", "useMaxWidth": false, "htmlLabels": true, "rankSpacing": 131, "nodeSpacing": 81 } } }%% flowchart TB %% ============================== %% COLOR CLASSES (your palette) %% ============================== style synthetic_data fill:#010209,stroke:#5D3FD3,stroke-width:2px,stroke-dasharray:6 6,color:#ffffff,rx:16,ry:16; style domain_norm fill:#0c0010,stroke:#ff00ff,stroke-width:2px,color:#ffffff,rx:16,ry:16,stroke-dasharray:6 6; style pod fill:#0d1b2a,stroke:#00d4ff,color:#ffffff,stroke-width:2px,stroke-dasharray:6 6,rx:16,ry:16; style trap fill:#002b11,stroke:#00ff88,color:#ffffff,stroke-width:2.5px,rx:16,ry:16; style normalized_wavefunctions fill:#112230,color:#ffffff,stroke:#14B5FF,stroke-width:2px,stroke-dasharray:6 1,rx:16,ry:16; style PsiMat fill:#112230,stroke:#14B5FF,color:#ffffff,stroke-width:2px,rx:16,ry:16; style trap_pod fill:#1a1a1a,stroke:#ffcc00,stroke-width:3px,color:#ffffff,rx:16,ry:16,stroke-dasharray:8 2; classDef spatial_modes fill:#2a185c,stroke:#9a66ff,stroke-width:4px,color:#ffffff,rx:16,ry:16; classDef temporal_modes fill:#003333,stroke:#00ffcc,stroke-width:4px,color:#ffffff,rx:16,ry:16; classDef spatial_stencil fill:#2a0037,stroke:#ff00ff,stroke-width:2px,color:#ffffff,rx:16,ry:16; classDef psinorm fill:#002244,stroke:#14B5FF,stroke-width:2px,color:#ffffff,rx:16,ry:16; classDef diag fill:#1a2b3c,stroke:#00e8ff,stroke-width:2.5px,rx:16,ry:16; %% ============================== %% INPUT BLOCKS %% ============================== subgraph synthetic_data["1️⃣ Synthetic Data"] direction LR subgraph domain_norm["Uniform Grid"] spatial_grid["$$x \in [-5, 5]$$"]:::spatial_stencil deltax["$$\Delta x$$"]:::spatial_stencil end trap["Trapezoidal weights"] end subgraph normalized_wavefunctions["Normalized Wavefunctions"] direction TB psi0(["$$\hat{\psi}_0^\theta$$"]):::psinorm psi1(["$$\hat{\psi}_1^\theta$$"]):::psinorm psi2(["$$\hat{\psi}_2^\theta$$"]):::psinorm end %% ============================== %% POD DIAGRAM %% ============================== subgraph pod["7️⃣ POD analysis"] PsiMat("Snapshot matrix construction<br/>$$\boldsymbol{\Psi}^\theta = [\hat{\psi}_0, \hat{\psi}_1, \hat{\psi}_2]$$") trap_pod("L² spatial weighting<br/>$$\boldsymbol{\Psi}_w = \sqrt{w \Delta x} \odot \boldsymbol{\Psi}$$") SVD("Euclidean SVD<br/>$$\boldsymbol{\Psi}_w = U \Sigma V^T$$"):::diag podscale("Physical mode recovery<br/>$$u_k^{\text{phys}} = u_k / \sqrt{w \Delta x}$$"):::spatial_modes align("Phase/Sign Alignment<br/>(Relative to Ground Truth)"):::spatial_modes spec("Singular values spectrum<br/>$$\sigma_k$$"):::diag modes("Physical Basis Functions<br/>$$u_k^{\text{phys}}$$"):::spatial_modes overlaps("Overlap matrix $$C_{kn}$$<br/>$$\langle u_k^{\text{phys}}, \hat{\psi}_n \rangle$$"):::spatial_modes temporal_scaling("Temporal mode projection<br/>$$V^T$$"):::temporal_modes temporal_alignment("Global $$U(1)$$ Phase Alignment"):::temporal_modes temporal_mode_heatmap("Composition Heatmap<br/>Matrix $$V_{nk}$$"):::temporal_modes temporal_overlap("Orthogonality Check<br/>$$\langle v_m, v_n \rangle = \delta_{mn}$$"):::temporal_modes cross_temporal("Cross-State Projections<br/>$$|\langle \mathbf{e}_n, v_k \rangle|$$"):::temporal_modes %% POD Companion Panels PsiMat --> trap_pod trap_pod --> SVD SVD --> spec SVD --> podscale SVD --> temporal_scaling podscale --> align align --> modes PsiMat --> overlaps temporal_scaling --> temporal_alignment temporal_alignment --> temporal_mode_heatmap temporal_alignment --> temporal_overlap temporal_alignment --> cross_temporal PsiMat --> cross_temporal end %% ============================== %% CONNECTIONS %% ============================== psi0 --> PsiMat psi1 --> PsiMat psi2 --> PsiMat deltax --> trap_pod trap --> trap_pod %% ============================== %% LINKS (styled) %% ============================== linkStyle default stroke:#4CC9F0,stroke-width:1.618px,opacity:0.6 linkStyle 0 stroke:#FFCC00,stroke-width:2.2px,opacity:0.95 linkStyle 1,2 stroke:#00E8FF,stroke-width:2.5px,opacity:0.95 linkStyle 3,5,6,7 stroke:#9A66FF,stroke-width:2.5px,opacity:0.95 linkStyle 4,8,9,10,11,12 stroke:#00FFCC,stroke-width:2.5px,opacity:0.95 linkStyle 13,14,15 stroke:#14B5FF,stroke-width:2.2px,opacity:0.95 linkStyle 16 stroke:#FF00FF,stroke-width:2.2px,opacity:0.95 linkStyle 17 stroke:#00FF88,stroke-width:2.2px,opacity:0.95

✅ To Do

  • Make sure \(\sqrt{w_i\Delta x}\) weighting is properly applied at all relevant steps.

Proper Orthogonal Decomposition (POD) Diagnostics

This figure details the weighted POD pipeline used for diagnostic verification.

  • Snapshot Matrix: Formed from normalized wavefunctions.
  • Weighting: Scaling with \(\sqrt{w_i \Delta x}\) ensures the L2 inner product maps to a Euclidean dot product for SVD.
  • Physical Scaling: Rescaling SVD modes back to physical space.
  • Overlaps: Calculation of the overlap matrix \(C_{kn}\) to assess mode orthogonality and alignment with learned states.

  • Write the mathematical expression for the inner product with the subscripts used.

\[\langle f, g \rangle_{\Delta x, w} = \sum_i w_i f(x_i)^* g(x_i) \Delta x\]