cct-cli 0.7.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- calc_terminal/__init__.py +14 -0
- calc_terminal/__main__.py +14 -0
- calc_terminal/activity.py +1334 -0
- calc_terminal/agent.py +3387 -0
- calc_terminal/agent_runtime.py +519 -0
- calc_terminal/ai_context.py +447 -0
- calc_terminal/ai_modes.py +752 -0
- calc_terminal/ai_personalization.py +286 -0
- calc_terminal/ai_preview_feedback.py +213 -0
- calc_terminal/aicore.py +2572 -0
- calc_terminal/anim.py +367 -0
- calc_terminal/app.py +3685 -0
- calc_terminal/art.py +639 -0
- calc_terminal/atomsim.py +368 -0
- calc_terminal/attachments.py +743 -0
- calc_terminal/benchmark_system.py +414 -0
- calc_terminal/browser/__init__.py +36 -0
- calc_terminal/browser/browser_state.py +346 -0
- calc_terminal/browser/devserver.py +176 -0
- calc_terminal/browser/engine.py +494 -0
- calc_terminal/browser/navigation.py +84 -0
- calc_terminal/browser/preview.py +429 -0
- calc_terminal/browser/preview_entry.py +95 -0
- calc_terminal/browser/project_detector.py +144 -0
- calc_terminal/browser/server.py +449 -0
- calc_terminal/browser/state.py +75 -0
- calc_terminal/browser/watcher.py +99 -0
- calc_terminal/browser_gui/__init__.py +1 -0
- calc_terminal/browser_gui/__main__.py +3 -0
- calc_terminal/browser_gui/launcher.py +173 -0
- calc_terminal/browser_gui/playwright_browser.py +117 -0
- calc_terminal/browser_gui/qt_browser.py +1501 -0
- calc_terminal/browser_gui/webview_browser.py +57 -0
- calc_terminal/capabilities/__init__.py +35 -0
- calc_terminal/capabilities/adapters/__init__.py +33 -0
- calc_terminal/capabilities/adapters/bioinformatics.py +204 -0
- calc_terminal/capabilities/adapters/browser_adapter.py +205 -0
- calc_terminal/capabilities/adapters/filesystem.py +206 -0
- calc_terminal/capabilities/adapters/git_adapter.py +202 -0
- calc_terminal/capabilities/adapters/jupyter_adapter.py +138 -0
- calc_terminal/capabilities/adapters/ml_frameworks.py +158 -0
- calc_terminal/capabilities/adapters/platforms.py +200 -0
- calc_terminal/capabilities/adapters/python_exec.py +93 -0
- calc_terminal/capabilities/adapters/quantum_adapter.py +150 -0
- calc_terminal/capabilities/adapters/scientific_comp.py +123 -0
- calc_terminal/capabilities/adapters/structural_bio.py +161 -0
- calc_terminal/capabilities/adapters/terminal.py +99 -0
- calc_terminal/capabilities/bus.py +178 -0
- calc_terminal/capabilities/discovery.py +207 -0
- calc_terminal/capabilities/schema.py +221 -0
- calc_terminal/cat.ico +0 -0
- calc_terminal/cat_browser.py +2018 -0
- calc_terminal/chat_store.py +703 -0
- calc_terminal/cli.py +1178 -0
- calc_terminal/code_editor.py +640 -0
- calc_terminal/collaboration.py +723 -0
- calc_terminal/commands_data.py +139 -0
- calc_terminal/compatibility_engine.py +352 -0
- calc_terminal/compute/__init__.py +31 -0
- calc_terminal/compute/fabric.py +350 -0
- calc_terminal/config.py +227 -0
- calc_terminal/core/__init__.py +41 -0
- calc_terminal/core/checkpoint.py +156 -0
- calc_terminal/core/input/__init__.py +45 -0
- calc_terminal/core/mode_registry.py +300 -0
- calc_terminal/core/project_graph.py +172 -0
- calc_terminal/core/recovery.py +129 -0
- calc_terminal/core/security_layer.py +112 -0
- calc_terminal/core/task_graph.py +202 -0
- calc_terminal/core/unified_runtime.py +184 -0
- calc_terminal/core/verification.py +257 -0
- calc_terminal/customization.py +1566 -0
- calc_terminal/derivations.py +153 -0
- calc_terminal/device_control.py +263 -0
- calc_terminal/diagnostics/__init__.py +27 -0
- calc_terminal/diagnostics/doctor_engine.py +382 -0
- calc_terminal/diagnostics/self_test.py +247 -0
- calc_terminal/doctor.py +519 -0
- calc_terminal/easter_eggs.py +274 -0
- calc_terminal/editor/__init__.py +1 -0
- calc_terminal/editor/actions.py +263 -0
- calc_terminal/editor/commands.py +160 -0
- calc_terminal/editor/shortcuts.py +226 -0
- calc_terminal/engine.py +259 -0
- calc_terminal/errors.py +120 -0
- calc_terminal/event_stream.py +146 -0
- calc_terminal/eventbus.py +133 -0
- calc_terminal/extensions.py +733 -0
- calc_terminal/fallback_cli.py +1321 -0
- calc_terminal/first_run.py +265 -0
- calc_terminal/fomoji_auth.py +1043 -0
- calc_terminal/formulas.py +82 -0
- calc_terminal/fs_cache.py +121 -0
- calc_terminal/fs_watcher.py +277 -0
- calc_terminal/game.py +193 -0
- calc_terminal/gen1.py +5 -0
- calc_terminal/generators.py +245 -0
- calc_terminal/gestures/__init__.py +42 -0
- calc_terminal/gestures/bindings.py +175 -0
- calc_terminal/gestures/manager.py +477 -0
- calc_terminal/goodbye.py +363 -0
- calc_terminal/gpu3d.py +290 -0
- calc_terminal/graphs.py +358 -0
- calc_terminal/hardware_analyzer.py +440 -0
- calc_terminal/host/__init__.py +30 -0
- calc_terminal/host/browser_manager.py +187 -0
- calc_terminal/host/desktop.py +1386 -0
- calc_terminal/host/launcher.py +395 -0
- calc_terminal/host/terminal.py +279 -0
- calc_terminal/identity.py +216 -0
- calc_terminal/input/__init__.py +54 -0
- calc_terminal/input/capabilities.py +258 -0
- calc_terminal/input/focus.py +87 -0
- calc_terminal/input/gestures.py +64 -0
- calc_terminal/input/pointer.py +114 -0
- calc_terminal/input/touch.py +345 -0
- calc_terminal/keys.py +84 -0
- calc_terminal/live_automation.py +165 -0
- calc_terminal/mathtext.py +433 -0
- calc_terminal/mcp.py +386 -0
- calc_terminal/memory.py +337 -0
- calc_terminal/memory_v2.py +479 -0
- calc_terminal/metrics.py +333 -0
- calc_terminal/mode_detection.py +146 -0
- calc_terminal/model.py +2431 -0
- calc_terminal/model_router.py +665 -0
- calc_terminal/models/__init__.py +0 -0
- calc_terminal/models/active_state.py +187 -0
- calc_terminal/models/dynamic_registry.py +584 -0
- calc_terminal/models/manager.py +781 -0
- calc_terminal/models/model_metadata.json +3526 -0
- calc_terminal/models/profiles.py +194 -0
- calc_terminal/models/registry.py +265 -0
- calc_terminal/models/schema.py +197 -0
- calc_terminal/models/validator.py +287 -0
- calc_terminal/models/verification_engine.py +368 -0
- calc_terminal/native_picker.py +215 -0
- calc_terminal/ollama_catalog.py +279 -0
- calc_terminal/ollama_download.py +233 -0
- calc_terminal/orchestrator.py +304 -0
- calc_terminal/package_research.py +322 -0
- calc_terminal/packages.py +1024 -0
- calc_terminal/pc_specs.py +116 -0
- calc_terminal/permissions.py +334 -0
- calc_terminal/pet.py +106 -0
- calc_terminal/pipeline.py +505 -0
- calc_terminal/platform/__init__.py +491 -0
- calc_terminal/platform/desktop.py +491 -0
- calc_terminal/platform/web.py +781 -0
- calc_terminal/preview/__init__.py +1 -0
- calc_terminal/preview/dev_server.py +303 -0
- calc_terminal/preview/diagnostics.py +131 -0
- calc_terminal/preview/live_reload.py +66 -0
- calc_terminal/preview/manager.py +129 -0
- calc_terminal/project_stats.py +209 -0
- calc_terminal/projects.py +328 -0
- calc_terminal/providers/__init__.py +0 -0
- calc_terminal/providers/adapters/__init__.py +80 -0
- calc_terminal/providers/adapters/anthropic_adapter.py +127 -0
- calc_terminal/providers/adapters/base.py +106 -0
- calc_terminal/providers/adapters/chinese_adapters.py +420 -0
- calc_terminal/providers/adapters/gemini_adapter.py +101 -0
- calc_terminal/providers/adapters/ollama_adapter.py +83 -0
- calc_terminal/providers/adapters/openai_adapter.py +159 -0
- calc_terminal/providers/adapters/other_adapters.py +246 -0
- calc_terminal/providers/anthropic_provider.py +172 -0
- calc_terminal/providers/auto_update.py +416 -0
- calc_terminal/providers/base_provider.py +105 -0
- calc_terminal/providers/discovery_manager.py +207 -0
- calc_terminal/providers/gemini_provider.py +178 -0
- calc_terminal/providers/lifecycle.py +767 -0
- calc_terminal/providers/ollama_adapter.py +707 -0
- calc_terminal/providers/openai_provider.py +254 -0
- calc_terminal/providers/provider_manager.py +1827 -0
- calc_terminal/providers/providers.json +4075 -0
- calc_terminal/reactionsim.py +279 -0
- calc_terminal/registry.py +337 -0
- calc_terminal/report.py +162 -0
- calc_terminal/research/__init__.py +45 -0
- calc_terminal/research/artifact_intel.py +126 -0
- calc_terminal/research/data_lineage.py +123 -0
- calc_terminal/research/experiment_ledger.py +303 -0
- calc_terminal/research/reproducibility.py +131 -0
- calc_terminal/resilience/__init__.py +47 -0
- calc_terminal/resilience/agent_state.py +121 -0
- calc_terminal/resilience/capability_matcher.py +174 -0
- calc_terminal/resilience/circuit_breaker.py +158 -0
- calc_terminal/resilience/failover_engine.py +230 -0
- calc_terminal/resilience/health_monitor.py +192 -0
- calc_terminal/resilience/ollama_adapter.py +125 -0
- calc_terminal/resilience/orchestrator.py +312 -0
- calc_terminal/resilience/types.py +134 -0
- calc_terminal/sandbox.py +98 -0
- calc_terminal/scires.py +558 -0
- calc_terminal/security_scanner.py +126 -0
- calc_terminal/session.py +294 -0
- calc_terminal/sim3d.py +206 -0
- calc_terminal/solver.py +276 -0
- calc_terminal/sound.py +127 -0
- calc_terminal/task_reports.py +287 -0
- calc_terminal/terminal_host.py +201 -0
- calc_terminal/terminal_identity.py +411 -0
- calc_terminal/test_ai_mode_reliability.py +344 -0
- calc_terminal/test_browser.py +368 -0
- calc_terminal/test_code_editor_upgrade.py +485 -0
- calc_terminal/test_customization.py +1148 -0
- calc_terminal/test_customization_ui.py +612 -0
- calc_terminal/test_dynamic_registry.py +304 -0
- calc_terminal/test_extensions.py +436 -0
- calc_terminal/test_overhaul.py +557 -0
- calc_terminal/test_project_detect.py +255 -0
- calc_terminal/test_root_cause_fix.py +527 -0
- calc_terminal/test_stability.py +532 -0
- calc_terminal/test_terminal_identity.py +132 -0
- calc_terminal/test_v079_speed.py +460 -0
- calc_terminal/theme.py +1107 -0
- calc_terminal/timeline.py +139 -0
- calc_terminal/todos.py +246 -0
- calc_terminal/tool_call_normalizer.py +419 -0
- calc_terminal/tui.py +104 -0
- calc_terminal/ui/__init__.py +8 -0
- calc_terminal/ui/activity_panel.py +231 -0
- calc_terminal/ui/activity_stream_panel.py +238 -0
- calc_terminal/ui/animations.py +122 -0
- calc_terminal/ui/app.py +7271 -0
- calc_terminal/ui/attach_panel.py +597 -0
- calc_terminal/ui/attachments.py +424 -0
- calc_terminal/ui/backup_panel.py +810 -0
- calc_terminal/ui/browser_shell.py +887 -0
- calc_terminal/ui/cat_agent.py +357 -0
- calc_terminal/ui/chats_panel.py +899 -0
- calc_terminal/ui/command_palette.py +125 -0
- calc_terminal/ui/command_palette_modal.py +166 -0
- calc_terminal/ui/composer.py +1141 -0
- calc_terminal/ui/context_menu.py +197 -0
- calc_terminal/ui/conversation.py +1435 -0
- calc_terminal/ui/customization_panel.py +1229 -0
- calc_terminal/ui/dashboard.py +404 -0
- calc_terminal/ui/design_system.py +557 -0
- calc_terminal/ui/diff_panel.py +213 -0
- calc_terminal/ui/editor.py +2102 -0
- calc_terminal/ui/empty_state.py +302 -0
- calc_terminal/ui/events.py +487 -0
- calc_terminal/ui/extensions_panel.py +815 -0
- calc_terminal/ui/footer.py +166 -0
- calc_terminal/ui/gestures_panel.py +383 -0
- calc_terminal/ui/goodbye_screen.py +100 -0
- calc_terminal/ui/header.py +1034 -0
- calc_terminal/ui/help_panel.py +254 -0
- calc_terminal/ui/live_activities.py +914 -0
- calc_terminal/ui/mcp_panel.py +570 -0
- calc_terminal/ui/memory_center.py +524 -0
- calc_terminal/ui/mode_colors_panel.py +525 -0
- calc_terminal/ui/nav_screens.py +747 -0
- calc_terminal/ui/ollama_panel.py +536 -0
- calc_terminal/ui/palette.py +221 -0
- calc_terminal/ui/permission_panel.py +269 -0
- calc_terminal/ui/personalization_panel.py +517 -0
- calc_terminal/ui/personalize_center.py +1568 -0
- calc_terminal/ui/preview_panel.py +441 -0
- calc_terminal/ui/resizers.py +402 -0
- calc_terminal/ui/sidebar.py +1285 -0
- calc_terminal/ui/statusbar.py +168 -0
- calc_terminal/ui/theme_css.py +1396 -0
- calc_terminal/ui/thinking.py +226 -0
- calc_terminal/ui/timeline_panel.py +102 -0
- calc_terminal/ui/todo_panel.py +193 -0
- calc_terminal/ui/viewport.py +136 -0
- calc_terminal/ui/vision_panel.py +489 -0
- calc_terminal/ui/welcome_modal.py +343 -0
- calc_terminal/ui/widgets.py +160 -0
- calc_terminal/ui/workspace.py +831 -0
- calc_terminal/viewers/__init__.py +1 -0
- calc_terminal/viewers/document_viewer.py +252 -0
- calc_terminal/viewers/image_viewer.py +241 -0
- calc_terminal/viewers/pdf_viewer.py +203 -0
- calc_terminal/viewers/presentation_viewer.py +164 -0
- calc_terminal/viewers/registry.py +120 -0
- calc_terminal/viewers/spreadsheet_viewer.py +204 -0
- calc_terminal/vision/__init__.py +89 -0
- calc_terminal/vision/analysis.py +194 -0
- calc_terminal/vision/annotations.py +297 -0
- calc_terminal/vision/capture.py +171 -0
- calc_terminal/vision/context.py +231 -0
- calc_terminal/vision/correlation.py +169 -0
- calc_terminal/vision/cursor.py +258 -0
- calc_terminal/vision/events.py +66 -0
- calc_terminal/vision/frame_pipeline.py +259 -0
- calc_terminal/vision/priority.py +218 -0
- calc_terminal/vision/provider.py +180 -0
- calc_terminal/vision/safety.py +149 -0
- calc_terminal/vision/session.py +281 -0
- calc_terminal/vision/verify.py +162 -0
- calc_terminal/vision.py +514 -0
- calc_terminal/vscode_integration.py +113 -0
- calc_terminal/web/__init__.py +8 -0
- calc_terminal/web/cat_runtime.py +710 -0
- calc_terminal/web/server.py +2891 -0
- calc_terminal/web/static/css/app.css +3152 -0
- calc_terminal/web/static/icons/badge-72.png +0 -0
- calc_terminal/web/static/icons/cat.ico +0 -0
- calc_terminal/web/static/icons/icon-128.png +0 -0
- calc_terminal/web/static/icons/icon-144.png +0 -0
- calc_terminal/web/static/icons/icon-152.png +0 -0
- calc_terminal/web/static/icons/icon-192.png +0 -0
- calc_terminal/web/static/icons/icon-384.png +0 -0
- calc_terminal/web/static/icons/icon-512.png +0 -0
- calc_terminal/web/static/icons/icon-72.png +0 -0
- calc_terminal/web/static/icons/icon-96.png +0 -0
- calc_terminal/web/static/icons/icon.svg +34 -0
- calc_terminal/web/static/icons/new-project.png +0 -0
- calc_terminal/web/static/icons/open-project.png +0 -0
- calc_terminal/web/static/index.html +734 -0
- calc_terminal/web/static/js/app.js +2403 -0
- calc_terminal/web/static/manifest.json +88 -0
- calc_terminal/web/static/sw.js +230 -0
- calc_terminal/workflow_engine.py +769 -0
- calc_terminal/workspace.py +593 -0
- calc_terminal/workspace_index.py +385 -0
- cct_cli-0.7.9.0.dist-info/METADATA +210 -0
- cct_cli-0.7.9.0.dist-info/RECORD +325 -0
- cct_cli-0.7.9.0.dist-info/WHEEL +5 -0
- cct_cli-0.7.9.0.dist-info/entry_points.txt +4 -0
- cct_cli-0.7.9.0.dist-info/licenses/LICENSE +21 -0
- cct_cli-0.7.9.0.dist-info/top_level.txt +1 -0
calc_terminal/atomsim.py
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Live atom & electron simulation, rendered as real-time ASCII/ANSI
|
|
3
|
+
animation in the terminal (redrawn in-place, no external GUI needed).
|
|
4
|
+
|
|
5
|
+
Two simulators:
|
|
6
|
+
|
|
7
|
+
atom_simulation(z) -- Bohr planetary-model animation: a nucleus of
|
|
8
|
+
Z protons + N neutrons, with electrons
|
|
9
|
+
orbiting real K/L/M/N/... shells at
|
|
10
|
+
shell-dependent angular speed.
|
|
11
|
+
|
|
12
|
+
orbital_simulation(key) -- a Monte-Carlo "electron cloud" builder for
|
|
13
|
+
real hydrogen-like orbitals (1s..3d), using
|
|
14
|
+
the actual radial/angular probability
|
|
15
|
+
density |psi|^2, accumulated dot-by-dot
|
|
16
|
+
live, the way textbooks describe orbitals
|
|
17
|
+
being "probability clouds" rather than
|
|
18
|
+
fixed paths.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import math
|
|
22
|
+
import random
|
|
23
|
+
import sys
|
|
24
|
+
import time
|
|
25
|
+
|
|
26
|
+
from . import theme
|
|
27
|
+
from . import keys
|
|
28
|
+
from . import scires
|
|
29
|
+
|
|
30
|
+
# ------------------------------------------------------------- elements --
|
|
31
|
+
# Simplified Bohr-Bury shell model (K, L, M, N...) — the standard
|
|
32
|
+
# teaching model. Transition-metal shells (Z=21-30) are approximate.
|
|
33
|
+
ELEMENTS = {
|
|
34
|
+
1: ("H", "Hydrogen", [1], 1), 2: ("He", "Helium", [2], 4),
|
|
35
|
+
3: ("Li", "Lithium", [2, 1], 7), 4: ("Be", "Beryllium", [2, 2], 9),
|
|
36
|
+
5: ("B", "Boron", [2, 3], 11), 6: ("C", "Carbon", [2, 4], 12),
|
|
37
|
+
7: ("N", "Nitrogen", [2, 5], 14), 8: ("O", "Oxygen", [2, 6], 16),
|
|
38
|
+
9: ("F", "Fluorine", [2, 7], 19), 10: ("Ne", "Neon", [2, 8], 20),
|
|
39
|
+
11: ("Na", "Sodium", [2, 8, 1], 23), 12: ("Mg", "Magnesium", [2, 8, 2], 24),
|
|
40
|
+
13: ("Al", "Aluminium", [2, 8, 3], 27), 14: ("Si", "Silicon", [2, 8, 4], 28),
|
|
41
|
+
15: ("P", "Phosphorus", [2, 8, 5], 31), 16: ("S", "Sulfur", [2, 8, 6], 32),
|
|
42
|
+
17: ("Cl", "Chlorine", [2, 8, 7], 35), 18: ("Ar", "Argon", [2, 8, 8], 40),
|
|
43
|
+
19: ("K", "Potassium", [2, 8, 8, 1], 39), 20: ("Ca", "Calcium", [2, 8, 8, 2], 40),
|
|
44
|
+
21: ("Sc", "Scandium", [2, 8, 9, 2], 45), 22: ("Ti", "Titanium", [2, 8, 10, 2], 48),
|
|
45
|
+
23: ("V", "Vanadium", [2, 8, 11, 2], 51), 24: ("Cr", "Chromium", [2, 8, 13, 1], 52),
|
|
46
|
+
25: ("Mn", "Manganese", [2, 8, 13, 2], 55), 26: ("Fe", "Iron", [2, 8, 14, 2], 56),
|
|
47
|
+
27: ("Co", "Cobalt", [2, 8, 15, 2], 59), 28: ("Ni", "Nickel", [2, 8, 16, 2], 59),
|
|
48
|
+
29: ("Cu", "Copper", [2, 8, 18, 1], 64), 30: ("Zn", "Zinc", [2, 8, 18, 2], 65),
|
|
49
|
+
31: ("Ga", "Gallium", [2, 8, 18, 3], 70), 32: ("Ge", "Germanium", [2, 8, 18, 4], 73),
|
|
50
|
+
33: ("As", "Arsenic", [2, 8, 18, 5], 75), 34: ("Se", "Selenium", [2, 8, 18, 6], 79),
|
|
51
|
+
35: ("Br", "Bromine", [2, 8, 18, 7], 80), 36: ("Kr", "Krypton", [2, 8, 18, 8], 84),
|
|
52
|
+
}
|
|
53
|
+
SYMBOL_TO_Z = {v[0].lower(): k for k, v in ELEMENTS.items()}
|
|
54
|
+
SHELL_NAMES = ["K", "L", "M", "N", "O", "P"]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def resolve_element(query):
|
|
58
|
+
q = str(query).strip().lower()
|
|
59
|
+
if q.isdigit() and int(q) in ELEMENTS:
|
|
60
|
+
return int(q)
|
|
61
|
+
return SYMBOL_TO_Z.get(q)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# --------------------------------------------------------- bohr display --
|
|
65
|
+
def _plot(grid, x, y, ch, color_fn):
|
|
66
|
+
w, h = len(grid[0]), len(grid)
|
|
67
|
+
xi, yi = int(round(x)), int(round(y))
|
|
68
|
+
if 0 <= yi < h and 0 <= xi < w:
|
|
69
|
+
grid[yi][xi] = color_fn(ch)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _render_bohr_frame(z, angle, width=64, height=22):
|
|
73
|
+
sym, name, shells, mass = ELEMENTS[z]
|
|
74
|
+
neutrons = mass - z
|
|
75
|
+
cx, cy = width // 2, height // 2
|
|
76
|
+
grid = [[" "] * width for _ in range(height)]
|
|
77
|
+
|
|
78
|
+
max_shell_r = min(cx - 3, cy - 2)
|
|
79
|
+
n_shells = len(shells)
|
|
80
|
+
radii = [max_shell_r * (i + 1) / n_shells for i in range(n_shells)]
|
|
81
|
+
|
|
82
|
+
# orbit rings (faint dotted circles), x-scaled 2:1 for terminal char aspect
|
|
83
|
+
for si, radius in enumerate(radii):
|
|
84
|
+
steps = int(radius * 10) + 12
|
|
85
|
+
for k in range(steps):
|
|
86
|
+
th = 2 * math.pi * k / steps
|
|
87
|
+
x = cx + radius * 2 * math.cos(th)
|
|
88
|
+
y = cy + radius * math.sin(th)
|
|
89
|
+
_plot(grid, x, y, "\u00b7", lambda c: theme.faint(c))
|
|
90
|
+
|
|
91
|
+
# nucleus: protons (red) + neutrons (gray) packed in a tiny cluster
|
|
92
|
+
random.seed(z * 7)
|
|
93
|
+
cluster = []
|
|
94
|
+
total_nucleons = z + neutrons
|
|
95
|
+
pack_r = max(1.4, math.sqrt(total_nucleons) * 0.55)
|
|
96
|
+
for i in range(min(total_nucleons, 40)):
|
|
97
|
+
ang = random.uniform(0, 2 * math.pi)
|
|
98
|
+
rr = random.uniform(0, pack_r)
|
|
99
|
+
cluster.append((cx + rr * 2 * math.cos(ang) * 0.6, cy + rr * math.sin(ang) * 0.6, i < z))
|
|
100
|
+
for x, y, is_proton in cluster:
|
|
101
|
+
ch = "P" if is_proton else "n"
|
|
102
|
+
color = (lambda c: theme.red(c, bold=True)) if is_proton else (lambda c: theme.dim(c))
|
|
103
|
+
_plot(grid, x, y, ch, color)
|
|
104
|
+
|
|
105
|
+
# electrons orbiting each shell — inner shells move faster (higher w)
|
|
106
|
+
electron_positions = []
|
|
107
|
+
for si, (count, radius) in enumerate(zip(shells, radii)):
|
|
108
|
+
speed = 1.0 / (si + 1) ** 0.7
|
|
109
|
+
for e in range(count):
|
|
110
|
+
phase = 2 * math.pi * e / max(count, 1)
|
|
111
|
+
th = angle * speed + phase
|
|
112
|
+
x = cx + radius * 2 * math.cos(th)
|
|
113
|
+
y = cy + radius * math.sin(th)
|
|
114
|
+
electron_positions.append((x, y, si))
|
|
115
|
+
_plot(grid, x, y, "\u25cf", lambda c: theme.cyan(c, bold=True))
|
|
116
|
+
|
|
117
|
+
lines = ["".join(row) for row in grid]
|
|
118
|
+
|
|
119
|
+
info = [
|
|
120
|
+
theme.purple(f"{name} ({sym})", bold=True) + theme.dim(f" Z={z} mass number \u2248 {mass}"),
|
|
121
|
+
theme.dim("Protons: ") + theme.red(str(z), bold=True) + " " +
|
|
122
|
+
theme.dim("Neutrons: ") + theme.fg(str(neutrons), theme.FAINT, bold=True) + " " +
|
|
123
|
+
theme.dim("Electrons: ") + theme.cyan(str(z), bold=True),
|
|
124
|
+
theme.dim("Shells (Bohr-Bury): ") + " ".join(
|
|
125
|
+
f"{SHELL_NAMES[i]}={c}" for i, c in enumerate(shells)),
|
|
126
|
+
]
|
|
127
|
+
return lines, info
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _snapshot_bohr(z, angle):
|
|
131
|
+
"""Save a scientific-style matplotlib PNG snapshot (glow-density
|
|
132
|
+
nucleus + electron shells on black) via calc_terminal.scires.
|
|
133
|
+
Returns the saved path, or None if matplotlib/numpy/scipy are
|
|
134
|
+
unavailable. `angle` is accepted for backward compatibility with
|
|
135
|
+
existing call sites but no longer affects the static snapshot."""
|
|
136
|
+
if z not in ELEMENTS:
|
|
137
|
+
return None
|
|
138
|
+
sym, name, shells, mass = ELEMENTS[z]
|
|
139
|
+
return scires.render_atom(z, sym, name, shells, mass,
|
|
140
|
+
out_name=f"atom_{sym.lower()}_snapshot.png")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def atom_simulation(z, out=sys.stdout, max_frames=600, frame_delay=0.06):
|
|
144
|
+
"""Runs the live Bohr-model animation. Returns cleanly on 'q', on
|
|
145
|
+
frame limit, or on KeyboardInterrupt -- never crashes the app."""
|
|
146
|
+
if z not in ELEMENTS:
|
|
147
|
+
print(theme.red(f" No shell data for element Z={z} (supported: 1-36)."))
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
angle = 0.0
|
|
151
|
+
speed = 0.35
|
|
152
|
+
paused = False
|
|
153
|
+
status_msg = ""
|
|
154
|
+
interactive = keys.stdin_is_interactive()
|
|
155
|
+
theme.hide_cursor()
|
|
156
|
+
try:
|
|
157
|
+
theme.clear_screen()
|
|
158
|
+
frame = 0
|
|
159
|
+
while frame < max_frames:
|
|
160
|
+
lines, info = _render_bohr_frame(z, angle)
|
|
161
|
+
theme.cursor_home()
|
|
162
|
+
out.write(theme.panel(info + [""] + lines, title="atom · live simulation",
|
|
163
|
+
color=theme.CYAN, width=70))
|
|
164
|
+
out.write("\n" + theme.faint(
|
|
165
|
+
" [q] quit [space] pause [+/-] speed [n/p] next/prev [s] snapshot"
|
|
166
|
+
f" speed={speed:.2f}{' (paused)' if paused else ''}") + "\n")
|
|
167
|
+
if status_msg:
|
|
168
|
+
out.write(" " + theme.green(status_msg) + "\n")
|
|
169
|
+
status_msg = ""
|
|
170
|
+
if not interactive:
|
|
171
|
+
out.write(theme.dim(
|
|
172
|
+
" (no interactive terminal detected — showing a single "
|
|
173
|
+
"frame instead of the live view)\n"))
|
|
174
|
+
out.flush()
|
|
175
|
+
|
|
176
|
+
if not paused:
|
|
177
|
+
angle += speed
|
|
178
|
+
frame += 1
|
|
179
|
+
|
|
180
|
+
if not interactive:
|
|
181
|
+
break
|
|
182
|
+
|
|
183
|
+
k = keys.read_key() if keys.key_available() else ""
|
|
184
|
+
if k == "q":
|
|
185
|
+
break
|
|
186
|
+
elif k == " ":
|
|
187
|
+
paused = not paused
|
|
188
|
+
elif k == "+":
|
|
189
|
+
speed = min(3.0, speed + 0.1)
|
|
190
|
+
elif k == "-":
|
|
191
|
+
speed = max(0.05, speed - 0.1)
|
|
192
|
+
elif k == "n":
|
|
193
|
+
nxt = min(36, z + 1)
|
|
194
|
+
if nxt in ELEMENTS:
|
|
195
|
+
z = nxt
|
|
196
|
+
elif k == "p":
|
|
197
|
+
prv = max(1, z - 1)
|
|
198
|
+
if prv in ELEMENTS:
|
|
199
|
+
z = prv
|
|
200
|
+
elif k == "r":
|
|
201
|
+
angle = 0.0
|
|
202
|
+
elif k == "s":
|
|
203
|
+
path = _snapshot_bohr(z, angle)
|
|
204
|
+
status_msg = f"Saved: {path}" if path else "matplotlib not installed — snapshot skipped."
|
|
205
|
+
|
|
206
|
+
time.sleep(frame_delay)
|
|
207
|
+
except KeyboardInterrupt:
|
|
208
|
+
pass
|
|
209
|
+
finally:
|
|
210
|
+
theme.show_cursor()
|
|
211
|
+
print()
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
# ------------------------------------------------------ quantum orbitals --
|
|
215
|
+
# Real (unnormalized, relative) hydrogen-like radial & angular probability
|
|
216
|
+
# density functions. a0 units. Good enough for a live, correctly-shaped
|
|
217
|
+
# probability-cloud visualization keyed by real quantum numbers n, l, m.
|
|
218
|
+
ORBITALS = {
|
|
219
|
+
"1s": (1, 0, 0), "2s": (2, 0, 0), "2p": (2, 1, 0),
|
|
220
|
+
"3s": (3, 0, 0), "3p": (3, 1, 0), "3d": (3, 2, 0),
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _radial_density(n, l, r):
|
|
225
|
+
# r in units of a0. Standard hydrogen radial shapes (unnormalized).
|
|
226
|
+
if (n, l) == (1, 0):
|
|
227
|
+
R = math.exp(-r)
|
|
228
|
+
elif (n, l) == (2, 0):
|
|
229
|
+
R = (2 - r) * math.exp(-r / 2)
|
|
230
|
+
elif (n, l) == (2, 1):
|
|
231
|
+
R = r * math.exp(-r / 2)
|
|
232
|
+
elif (n, l) == (3, 0):
|
|
233
|
+
R = (27 - 18 * r + 2 * r * r) * math.exp(-r / 3)
|
|
234
|
+
elif (n, l) == (3, 1):
|
|
235
|
+
R = r * (6 - r) * math.exp(-r / 3)
|
|
236
|
+
elif (n, l) == (3, 2):
|
|
237
|
+
R = r * r * math.exp(-r / 3)
|
|
238
|
+
else:
|
|
239
|
+
R = math.exp(-r)
|
|
240
|
+
return (R * R) * (r * r) # include r^2 volume-element weighting
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _angular_density(l, m, theta):
|
|
244
|
+
if l == 0:
|
|
245
|
+
return 1.0
|
|
246
|
+
if l == 1:
|
|
247
|
+
return math.cos(theta) ** 2 # 2pz-type lobe, x-z cross-section
|
|
248
|
+
if l == 2:
|
|
249
|
+
return (3 * math.cos(theta) ** 2 - 1) ** 2 # dz2-type
|
|
250
|
+
return 1.0
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _sample_point(n, l, m, r_max):
|
|
254
|
+
"""Rejection-sample an (r, theta) pair from the real |psi|^2 density."""
|
|
255
|
+
peak = 0.0
|
|
256
|
+
for rr in [i * r_max / 60 for i in range(61)]:
|
|
257
|
+
for th in [j * math.pi / 20 for j in range(21)]:
|
|
258
|
+
v = _radial_density(n, l, rr) * _angular_density(l, m, th)
|
|
259
|
+
peak = max(peak, v)
|
|
260
|
+
peak = max(peak, 1e-9)
|
|
261
|
+
for _ in range(200):
|
|
262
|
+
r = random.uniform(0, r_max)
|
|
263
|
+
th = random.uniform(0, math.pi)
|
|
264
|
+
val = _radial_density(n, l, r) * _angular_density(l, m, th)
|
|
265
|
+
if random.uniform(0, peak) <= val:
|
|
266
|
+
phi = random.uniform(0, 2 * math.pi)
|
|
267
|
+
return r, th, phi
|
|
268
|
+
return None
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _snapshot_orbital(orbital_key, n, l, m, r_max):
|
|
272
|
+
"""Save a scientific-style probability-density point-cloud PNG
|
|
273
|
+
(density-colored magma scatter on black) via calc_terminal.scires.
|
|
274
|
+
`r_max` is accepted for backward compatibility with existing call
|
|
275
|
+
sites; scires picks its own r_max per n internally."""
|
|
276
|
+
return scires.render_orbital(orbital_key, n, l, m,
|
|
277
|
+
out_name=f"orbital_{orbital_key}_snapshot.png")
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def snapshot_orbital_grid():
|
|
281
|
+
"""Save a reference-chart-style grid of many hydrogen orbitals'
|
|
282
|
+
|psi|^2 (like the classic 'Hydrogen Wave Function' chart). Returns
|
|
283
|
+
the saved path, or None if matplotlib/numpy/scipy are unavailable."""
|
|
284
|
+
return scires.render_orbital_grid()
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def orbital_simulation(orbital_key, out=sys.stdout, max_points=2200, width=62, height=26):
|
|
288
|
+
"""Live Monte-Carlo build-up of a real quantum orbital's probability
|
|
289
|
+
cloud (the textbook 'electron cloud'), redrawn as it accumulates."""
|
|
290
|
+
if orbital_key not in ORBITALS:
|
|
291
|
+
print(theme.red(f" Unknown orbital '{orbital_key}'. Try 1s, 2s, 2p, 3s, 3p, 3d."))
|
|
292
|
+
return
|
|
293
|
+
n, l, m = ORBITALS[orbital_key]
|
|
294
|
+
r_max = {1: 6, 2: 14, 3: 24}[n]
|
|
295
|
+
|
|
296
|
+
grid = [[0 for _ in range(width)] for _ in range(height)]
|
|
297
|
+
cx, cy = width // 2, height // 2
|
|
298
|
+
shade = " .:-=+*#%@"
|
|
299
|
+
|
|
300
|
+
theme.hide_cursor()
|
|
301
|
+
placed = 0
|
|
302
|
+
paused = False
|
|
303
|
+
status_msg = ""
|
|
304
|
+
try:
|
|
305
|
+
theme.clear_screen()
|
|
306
|
+
while placed < max_points:
|
|
307
|
+
k = keys.read_key() if keys.key_available() else ""
|
|
308
|
+
if k == "q":
|
|
309
|
+
break
|
|
310
|
+
if k == " ":
|
|
311
|
+
paused = not paused
|
|
312
|
+
if k == "r":
|
|
313
|
+
grid = [[0 for _ in range(width)] for _ in range(height)]
|
|
314
|
+
placed = 0
|
|
315
|
+
if k == "s":
|
|
316
|
+
path = _snapshot_orbital(orbital_key, n, l, m, r_max)
|
|
317
|
+
status_msg = f"Saved: {path}" if path else "matplotlib not installed — snapshot skipped."
|
|
318
|
+
|
|
319
|
+
if not paused:
|
|
320
|
+
for _ in range(6):
|
|
321
|
+
pt = _sample_point(n, l, m, r_max)
|
|
322
|
+
if pt is None:
|
|
323
|
+
continue
|
|
324
|
+
r, th, phi = pt
|
|
325
|
+
# project onto the x-z plane (side-on cross-section)
|
|
326
|
+
x = r * math.sin(th) * math.cos(phi)
|
|
327
|
+
z_ = r * math.cos(th)
|
|
328
|
+
scale = (width / 2 - 2) / r_max
|
|
329
|
+
gx = int(round(cx + x * scale * 2))
|
|
330
|
+
gy = int(round(cy - z_ * scale))
|
|
331
|
+
if 0 <= gx < width and 0 <= gy < height:
|
|
332
|
+
grid[gy][gx] = min(len(shade) - 1, grid[gy][gx] + 1)
|
|
333
|
+
placed += 1
|
|
334
|
+
|
|
335
|
+
rows = []
|
|
336
|
+
for row in grid:
|
|
337
|
+
line = ""
|
|
338
|
+
for v in row:
|
|
339
|
+
ch = shade[min(v, len(shade) - 1)]
|
|
340
|
+
if v == 0:
|
|
341
|
+
line += " "
|
|
342
|
+
elif v < 3:
|
|
343
|
+
line += theme.fg(ch, theme.CYAN)
|
|
344
|
+
elif v < 6:
|
|
345
|
+
line += theme.fg(ch, theme.PURPLE, bold=True)
|
|
346
|
+
else:
|
|
347
|
+
line += theme.fg(ch, theme.TEXT, bold=True)
|
|
348
|
+
rows.append(line)
|
|
349
|
+
|
|
350
|
+
info = [
|
|
351
|
+
theme.purple(f"Orbital {orbital_key}", bold=True) +
|
|
352
|
+
theme.dim(f" n={n} l={l} m={m} (Monte-Carlo |\u03c8|\u00b2 sampling)"),
|
|
353
|
+
theme.dim(f"Points placed: {placed}/{max_points}" + (" (paused)" if paused else "")),
|
|
354
|
+
]
|
|
355
|
+
theme.cursor_home()
|
|
356
|
+
out.write(theme.panel(info + [""] + rows, title="orbital · live simulation",
|
|
357
|
+
color=theme.PURPLE, width=width + 8))
|
|
358
|
+
out.write("\n" + theme.faint(" [q] quit [space] pause [r] restart [s] snapshot") + "\n")
|
|
359
|
+
if status_msg:
|
|
360
|
+
out.write(" " + theme.green(status_msg) + "\n")
|
|
361
|
+
status_msg = ""
|
|
362
|
+
out.flush()
|
|
363
|
+
time.sleep(0.015)
|
|
364
|
+
except KeyboardInterrupt:
|
|
365
|
+
pass
|
|
366
|
+
finally:
|
|
367
|
+
theme.show_cursor()
|
|
368
|
+
print()
|