jupytermind 0.3.0
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.
- package/.github/skills/ai-chemistry-scientist/SKILL.md +97 -0
- package/.github/skills/ai-chemistry-scientist/manifest.json +156 -0
- package/.github/skills/ai-data-scientist/SKILL.md +330 -0
- package/.github/skills/ai-genomics-scientist/SKILL.md +98 -0
- package/.github/skills/ai-genomics-scientist/manifest.json +93 -0
- package/.github/skills/ai-materials-scientist/SKILL.md +51 -0
- package/.github/skills/ai-materials-scientist/manifest.json +58 -0
- package/.github/skills/ai-scientist/SKILL.md +69 -0
- package/.github/skills/ai-scientist/manifest.json +61 -0
- package/.github/skills/ai-structural-biology-scientist/SKILL.md +67 -0
- package/.github/skills/ai-structural-biology-scientist/manifest.json +72 -0
- package/.github/skills/japanese-prose/NOTICE.md +17 -0
- package/.github/skills/japanese-prose/SKILL.md +111 -0
- package/.github/skills/japanese-prose/references/review-workflow.md +50 -0
- package/.github/skills/japanese-prose/references/scoring.md +24 -0
- package/.github/skills/japanese-prose/references/writing-guidelines.md +60 -0
- package/.github/skills/japanese-prose/scripts/core.py +192 -0
- package/.github/skills/japanese-prose/scripts/fixtures/natural.md +5 -0
- package/.github/skills/japanese-prose/scripts/fixtures/unnatural.md +5 -0
- package/.github/skills/japanese-prose/scripts/lint.py +378 -0
- package/.github/skills/japanese-prose/scripts/outline.py +68 -0
- package/.github/skills/japanese-prose/scripts/terms.py +112 -0
- package/.github/skills/japanese-prose/scripts/test_engine.py +117 -0
- package/.github/skills/presentation-planner/SKILL.md +257 -0
- package/.github/skills/presentation-planner/assets/design-templates/data-report.yaml +97 -0
- package/.github/skills/presentation-planner/assets/design-templates/executive-proposal.yaml +92 -0
- package/.github/skills/presentation-planner/assets/design-templates/technical-briefing.yaml +96 -0
- package/.github/skills/presentation-planner/assets/scenario-templates/data-report.md +47 -0
- package/.github/skills/presentation-planner/assets/scenario-templates/executive-decision.md +43 -0
- package/.github/skills/presentation-planner/assets/scenario-templates/technical-briefing.md +45 -0
- package/.github/skills/presentation-planner/references/customizing-design-templates.md +160 -0
- package/.github/skills/presentation-planner/references/design-spec-schema.md +72 -0
- package/.github/skills/presentation-planner/references/handoff-contract.md +49 -0
- package/.github/skills/presentation-planner/references/responsibility-boundary.md +32 -0
- package/.github/skills/presentation-planner/references/scenario-templates.md +55 -0
- package/.github/skills/tech-writer/SKILL.md +434 -0
- package/.github/skills/tech-writer/assets/templates/blueprint.md +187 -0
- package/.github/skills/tech-writer/assets/templates/design-doc.md +29 -0
- package/.github/skills/tech-writer/assets/templates/migration-plan.md +173 -0
- package/.github/skills/tech-writer/assets/templates/operations-runbook.md +202 -0
- package/.github/skills/tech-writer/assets/templates/pr-description.md +23 -0
- package/.github/skills/tech-writer/assets/templates/qiita.md +44 -0
- package/.github/skills/tech-writer/assets/templates/readme.md +38 -0
- package/.github/skills/tech-writer/assets/templates/requirements-definition.md +170 -0
- package/.github/skills/tech-writer/assets/templates/rfi.md +113 -0
- package/.github/skills/tech-writer/assets/templates/rfp.md +180 -0
- package/.github/skills/tech-writer/assets/templates/security-design.md +167 -0
- package/.github/skills/tech-writer/assets/templates/system-design.md +220 -0
- package/.github/skills/tech-writer/assets/templates/technical-proposal.md +112 -0
- package/.github/skills/tech-writer/assets/templates/test-plan.md +153 -0
- package/.github/skills/tech-writer/assets/templates/user-manual.md +22 -0
- package/.github/skills/tech-writer/assets/templates/white-paper.md +192 -0
- package/.github/skills/tech-writer/references/doctypes/api-docs.md +33 -0
- package/.github/skills/tech-writer/references/doctypes/blueprint.md +81 -0
- package/.github/skills/tech-writer/references/doctypes/code-comments.md +39 -0
- package/.github/skills/tech-writer/references/doctypes/design-doc.md +42 -0
- package/.github/skills/tech-writer/references/doctypes/migration-plan.md +63 -0
- package/.github/skills/tech-writer/references/doctypes/operations-runbook.md +63 -0
- package/.github/skills/tech-writer/references/doctypes/pr-commit.md +82 -0
- package/.github/skills/tech-writer/references/doctypes/qiita.md +75 -0
- package/.github/skills/tech-writer/references/doctypes/readme.md +43 -0
- package/.github/skills/tech-writer/references/doctypes/release-notes.md +30 -0
- package/.github/skills/tech-writer/references/doctypes/requirements-definition.md +61 -0
- package/.github/skills/tech-writer/references/doctypes/rfi.md +43 -0
- package/.github/skills/tech-writer/references/doctypes/rfp.md +46 -0
- package/.github/skills/tech-writer/references/doctypes/security-design.md +71 -0
- package/.github/skills/tech-writer/references/doctypes/system-design.md +74 -0
- package/.github/skills/tech-writer/references/doctypes/technical-proposal.md +49 -0
- package/.github/skills/tech-writer/references/doctypes/test-plan.md +67 -0
- package/.github/skills/tech-writer/references/doctypes/user-manual.md +58 -0
- package/.github/skills/tech-writer/references/doctypes/white-paper.md +84 -0
- package/.github/skills/tech-writer/references/doctypes/zenn.md +66 -0
- package/.github/skills/tech-writer/references/japanese-prose-optimization.md +110 -0
- package/.github/skills/tech-writer/references/style-constitution.md +104 -0
- package/.github/skills/tech-writer/scripts/lint.py +412 -0
- package/LICENSE +21 -0
- package/README.md +92 -0
- package/bin/ai-data-scientist.js +123 -0
- package/package.json +41 -0
- package/pyproject.toml +45 -0
- package/src/ai_chemistry_scientist/__init__.py +0 -0
- package/src/ai_chemistry_scientist/admet_prediction.py +71 -0
- package/src/ai_chemistry_scientist/bioactivity_classification.py +73 -0
- package/src/ai_chemistry_scientist/data/sample_molecules.csv +21 -0
- package/src/ai_chemistry_scientist/dispatch.py +369 -0
- package/src/ai_chemistry_scientist/docking_score.py +97 -0
- package/src/ai_chemistry_scientist/drug_likeness_rules.py +84 -0
- package/src/ai_chemistry_scientist/evidence.py +41 -0
- package/src/ai_chemistry_scientist/molecular_descriptors.py +97 -0
- package/src/ai_chemistry_scientist/molecular_formula_mass.py +40 -0
- package/src/ai_chemistry_scientist/molecular_similarity.py +78 -0
- package/src/ai_chemistry_scientist/qsar_modeling.py +105 -0
- package/src/ai_chemistry_scientist/salt_standardization.py +81 -0
- package/src/ai_chemistry_scientist/structural_alerts.py +76 -0
- package/src/ai_chemistry_scientist/structure_format_conversion.py +84 -0
- package/src/ai_chemistry_scientist/validation.py +70 -0
- package/src/ai_data_scientist/__init__.py +0 -0
- package/src/ai_data_scientist/analysis_assumptions.py +121 -0
- package/src/ai_data_scientist/anomaly_detection.py +39 -0
- package/src/ai_data_scientist/automl.py +109 -0
- package/src/ai_data_scientist/cleaning.py +56 -0
- package/src/ai_data_scientist/cli.py +90 -0
- package/src/ai_data_scientist/clustering.py +54 -0
- package/src/ai_data_scientist/dashboard.py +33 -0
- package/src/ai_data_scientist/data_definition.py +100 -0
- package/src/ai_data_scientist/data_quality.py +164 -0
- package/src/ai_data_scientist/dataset_validation.py +135 -0
- package/src/ai_data_scientist/dependency_pins.py +60 -0
- package/src/ai_data_scientist/eda.py +82 -0
- package/src/ai_data_scientist/experiment_evaluation.py +635 -0
- package/src/ai_data_scientist/explainability.py +340 -0
- package/src/ai_data_scientist/feature_engineering.py +163 -0
- package/src/ai_data_scientist/gate_config.py +32 -0
- package/src/ai_data_scientist/ingestion.py +127 -0
- package/src/ai_data_scientist/insight_engine.py +180 -0
- package/src/ai_data_scientist/japanese_nlp.py +43 -0
- package/src/ai_data_scientist/jupyter_launcher.py +137 -0
- package/src/ai_data_scientist/jupyter_mcp_client.py +94 -0
- package/src/ai_data_scientist/language_router.py +28 -0
- package/src/ai_data_scientist/lifecycle.py +221 -0
- package/src/ai_data_scientist/mcp_gateway.py +113 -0
- package/src/ai_data_scientist/mcp_runtime.py +194 -0
- package/src/ai_data_scientist/mcp_transport.py +53 -0
- package/src/ai_data_scientist/ml_modeling.py +451 -0
- package/src/ai_data_scientist/model_tuning.py +104 -0
- package/src/ai_data_scientist/notebook_audit.py +574 -0
- package/src/ai_data_scientist/project_manager.py +243 -0
- package/src/ai_data_scientist/report_export.py +73 -0
- package/src/ai_data_scientist/sensitivity.py +445 -0
- package/src/ai_data_scientist/signal_analysis.py +201 -0
- package/src/ai_data_scientist/skill_packaging.py +40 -0
- package/src/ai_data_scientist/stats_analysis.py +88 -0
- package/src/ai_data_scientist/text_nlp.py +44 -0
- package/src/ai_data_scientist/timeseries.py +68 -0
- package/src/ai_data_scientist/visualization.py +708 -0
- package/src/ai_genomics_scientist/__init__.py +1 -0
- package/src/ai_genomics_scientist/differential_expression.py +147 -0
- package/src/ai_genomics_scientist/dispatch.py +267 -0
- package/src/ai_genomics_scientist/evidence.py +45 -0
- package/src/ai_genomics_scientist/gene_set_enrichment.py +76 -0
- package/src/ai_genomics_scientist/sequence_alignment.py +97 -0
- package/src/ai_genomics_scientist/sequence_features.py +111 -0
- package/src/ai_genomics_scientist/splice_site_scoring.py +66 -0
- package/src/ai_genomics_scientist/validation.py +83 -0
- package/src/ai_genomics_scientist/variant_effect.py +147 -0
- package/src/ai_genomics_scientist/variant_pathogenicity.py +125 -0
- package/src/ai_materials_scientist/__init__.py +0 -0
- package/src/ai_materials_scientist/calphad.py +117 -0
- package/src/ai_materials_scientist/classical_monte_carlo.py +165 -0
- package/src/ai_materials_scientist/crystal_plasticity.py +184 -0
- package/src/ai_materials_scientist/dispatch.py +100 -0
- package/src/ai_materials_scientist/evidence.py +84 -0
- package/src/ai_materials_scientist/fem.py +279 -0
- package/src/ai_materials_scientist/kinetic_monte_carlo.py +145 -0
- package/src/ai_materials_scientist/molecular_dynamics.py +240 -0
- package/src/ai_materials_scientist/phase_field.py +167 -0
- package/src/ai_materials_scientist/validation.py +70 -0
- package/src/ai_scientist/__init__.py +1 -0
- package/src/ai_scientist/completion_gate.py +15 -0
- package/src/ai_scientist/data_analysis.py +46 -0
- package/src/ai_scientist/evidence_registry.py +99 -0
- package/src/ai_scientist/experimental_design.py +20 -0
- package/src/ai_scientist/language.py +14 -0
- package/src/ai_scientist/latex_renderer.py +41 -0
- package/src/ai_scientist/literature_review.py +37 -0
- package/src/ai_scientist/manifest.py +87 -0
- package/src/ai_scientist/manuscript.py +94 -0
- package/src/ai_scientist/mcp_config.py +76 -0
- package/src/ai_scientist/mcp_external.py +42 -0
- package/src/ai_scientist/mcp_failures.py +23 -0
- package/src/ai_scientist/mcp_gateway.py +38 -0
- package/src/ai_scientist/mcp_managed.py +180 -0
- package/src/ai_scientist/npm_packaging.py +49 -0
- package/src/ai_scientist/orchestrator.py +133 -0
- package/src/ai_scientist/peer_review.py +60 -0
- package/src/ai_scientist/phase_gate.py +74 -0
- package/src/ai_scientist/phase_state.py +230 -0
- package/src/ai_scientist/presentation.py +56 -0
- package/src/ai_scientist/project_config.py +31 -0
- package/src/ai_scientist/project_handle.py +74 -0
- package/src/ai_scientist/reproducibility.py +20 -0
- package/src/ai_scientist/research_planning.py +20 -0
- package/src/ai_scientist/skill_invocation.py +21 -0
- package/src/ai_scientist/tdd_gate.py +99 -0
- package/src/ai_structural_biology_scientist/__init__.py +0 -0
- package/src/ai_structural_biology_scientist/contact_map.py +87 -0
- package/src/ai_structural_biology_scientist/dispatch.py +269 -0
- package/src/ai_structural_biology_scientist/evidence.py +43 -0
- package/src/ai_structural_biology_scientist/hydrophobicity.py +101 -0
- package/src/ai_structural_biology_scientist/protein_docking_score.py +104 -0
- package/src/ai_structural_biology_scientist/secondary_structure.py +95 -0
- package/src/ai_structural_biology_scientist/structural_similarity.py +74 -0
- package/src/ai_structural_biology_scientist/validation.py +100 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Classical Monte Carlo lattice sampling module (DES-AIMS-030 / REQ-AIMS-030)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ai_materials_scientist.evidence import record_run
|
|
8
|
+
from ai_materials_scientist.validation import (
|
|
9
|
+
check_finite_array,
|
|
10
|
+
register_validator,
|
|
11
|
+
validate_parameters,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
_MODULE_NAME = "classical-monte-carlo"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _total_energy_per_site(spins: np.ndarray, J: float) -> float:
|
|
18
|
+
"""-J * sum over unique nearest-neighbor bonds, divided by N sites."""
|
|
19
|
+
n = spins.size
|
|
20
|
+
right = np.roll(spins, -1, axis=1)
|
|
21
|
+
down = np.roll(spins, -1, axis=0)
|
|
22
|
+
bond_sum = np.sum(spins * right) + np.sum(spins * down)
|
|
23
|
+
return float(-J * bond_sum / n)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _local_field(spins: np.ndarray, i: int, j: int, L: int) -> int:
|
|
27
|
+
return (
|
|
28
|
+
spins[(i + 1) % L, j]
|
|
29
|
+
+ spins[(i - 1) % L, j]
|
|
30
|
+
+ spins[i, (j + 1) % L]
|
|
31
|
+
+ spins[i, (j - 1) % L]
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _sweep(spins: np.ndarray, L: int, J: float, T: float, rng: np.random.Generator) -> None:
|
|
36
|
+
"""One raster-order full-lattice sweep of single-site Metropolis trial moves."""
|
|
37
|
+
random_values = rng.random((L, L))
|
|
38
|
+
for i in range(L):
|
|
39
|
+
for j in range(L):
|
|
40
|
+
s = spins[i, j]
|
|
41
|
+
neighbor_sum = _local_field(spins, i, j, L)
|
|
42
|
+
delta_e = 2.0 * J * s * neighbor_sum
|
|
43
|
+
if delta_e <= 0 or random_values[i, j] < np.exp(-delta_e / T):
|
|
44
|
+
spins[i, j] = -s
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _mc_validator(params: dict) -> dict:
|
|
48
|
+
"""DES-AIMS-002 registered validator for module_name='classical-monte-carlo'."""
|
|
49
|
+
if params["L"] <= 0:
|
|
50
|
+
return {"ok": False, "parameter": "L", "constraint": "L > 0"}
|
|
51
|
+
if params["J"] <= 0:
|
|
52
|
+
return {"ok": False, "parameter": "J", "constraint": "J > 0"}
|
|
53
|
+
if params["T"] <= 0:
|
|
54
|
+
return {"ok": False, "parameter": "T", "constraint": "T > 0"}
|
|
55
|
+
if params["equilibration_sweeps"] < 0:
|
|
56
|
+
return {
|
|
57
|
+
"ok": False,
|
|
58
|
+
"parameter": "equilibration_sweeps",
|
|
59
|
+
"constraint": "equilibration_sweeps >= 0",
|
|
60
|
+
}
|
|
61
|
+
if params["sampling_sweeps"] <= 0:
|
|
62
|
+
return {
|
|
63
|
+
"ok": False,
|
|
64
|
+
"parameter": "sampling_sweeps",
|
|
65
|
+
"constraint": "sampling_sweeps > 0",
|
|
66
|
+
}
|
|
67
|
+
initial_spins = params["initial_spins"]
|
|
68
|
+
finite_check = check_finite_array("initial_spins", initial_spins)
|
|
69
|
+
if not finite_check["ok"]:
|
|
70
|
+
return finite_check
|
|
71
|
+
if initial_spins.shape != (params["L"], params["L"]):
|
|
72
|
+
return {
|
|
73
|
+
"ok": False,
|
|
74
|
+
"parameter": "initial_spins",
|
|
75
|
+
"constraint": "initial_spins.shape == (L, L)",
|
|
76
|
+
}
|
|
77
|
+
if not np.all(np.isin(initial_spins, (-1, 1))):
|
|
78
|
+
return {
|
|
79
|
+
"ok": False,
|
|
80
|
+
"parameter": "initial_spins",
|
|
81
|
+
"constraint": "every spin must be +1 or -1",
|
|
82
|
+
}
|
|
83
|
+
return {"ok": True}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
register_validator(_MODULE_NAME, _mc_validator)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _validate(L, J, T, equilibration_sweeps, sampling_sweeps, initial_spins) -> None:
|
|
90
|
+
result = validate_parameters(
|
|
91
|
+
_MODULE_NAME,
|
|
92
|
+
{
|
|
93
|
+
"L": L,
|
|
94
|
+
"J": J,
|
|
95
|
+
"T": T,
|
|
96
|
+
"equilibration_sweeps": equilibration_sweeps,
|
|
97
|
+
"sampling_sweeps": sampling_sweeps,
|
|
98
|
+
"initial_spins": initial_spins,
|
|
99
|
+
},
|
|
100
|
+
)
|
|
101
|
+
if not result["ok"]:
|
|
102
|
+
raise ValueError(f"{result['parameter']}: {result['constraint']}")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# @id CODE-AIMS-030
|
|
106
|
+
# @implements REQ-AIMS-030 REQ-AIMS-003
|
|
107
|
+
# @design DES-AIMS-030
|
|
108
|
+
def run_classical_monte_carlo(
|
|
109
|
+
L: int,
|
|
110
|
+
J: float,
|
|
111
|
+
T: float,
|
|
112
|
+
equilibration_sweeps: int,
|
|
113
|
+
sampling_sweeps: int,
|
|
114
|
+
seed: int,
|
|
115
|
+
initial_spins: np.ndarray,
|
|
116
|
+
) -> dict:
|
|
117
|
+
"""Run Metropolis-criterion single-site Ising sweeps (REQ-AIMS-030).
|
|
118
|
+
|
|
119
|
+
Rejects any out-of-domain parameter (REQ-AIMS-003) before any spin-flip
|
|
120
|
+
trial move, and never mutates ``initial_spins``.
|
|
121
|
+
"""
|
|
122
|
+
_validate(L, J, T, equilibration_sweeps, sampling_sweeps, initial_spins)
|
|
123
|
+
|
|
124
|
+
spins = initial_spins.astype(np.int64).copy()
|
|
125
|
+
rng = np.random.default_rng(seed)
|
|
126
|
+
|
|
127
|
+
for _ in range(equilibration_sweeps):
|
|
128
|
+
_sweep(spins, L, J, T, rng)
|
|
129
|
+
|
|
130
|
+
history = []
|
|
131
|
+
for _ in range(sampling_sweeps):
|
|
132
|
+
_sweep(spins, L, J, T, rng)
|
|
133
|
+
energy_per_site = _total_energy_per_site(spins, J)
|
|
134
|
+
magnetization_per_site = float(np.sum(spins)) / spins.size
|
|
135
|
+
history.append(
|
|
136
|
+
{"energy_per_site": energy_per_site, "magnetization_per_site": magnetization_per_site}
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
mean_energy = float(np.mean([h["energy_per_site"] for h in history]))
|
|
140
|
+
mean_abs_magnetization = float(np.mean([abs(h["magnetization_per_site"]) for h in history]))
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
"mean_energy": mean_energy,
|
|
144
|
+
"mean_abs_magnetization": mean_abs_magnetization,
|
|
145
|
+
"history": history,
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# @id CODE-AIMS-901
|
|
150
|
+
# @implements REQ-AIMS-030 REQ-AIMS-004 REQ-AIMS-005
|
|
151
|
+
# @design DES-AIMS-030
|
|
152
|
+
def run_classical_monte_carlo_with_evidence(**kwargs) -> dict:
|
|
153
|
+
"""Run classical Monte Carlo and wrap the result as a reproducible RunRecord."""
|
|
154
|
+
result = run_classical_monte_carlo(**kwargs)
|
|
155
|
+
energies = np.array([h["energy_per_site"] for h in result["history"]], dtype=np.float64)
|
|
156
|
+
magnetizations = np.array(
|
|
157
|
+
[h["magnetization_per_site"] for h in result["history"]], dtype=np.float64
|
|
158
|
+
)
|
|
159
|
+
return record_run(
|
|
160
|
+
module_name=_MODULE_NAME,
|
|
161
|
+
unit_system="ising-reduced",
|
|
162
|
+
params={k: v for k, v in kwargs.items() if k != "initial_spins"},
|
|
163
|
+
arrays={"energy_history": energies, "magnetization_history": magnetizations},
|
|
164
|
+
seed=kwargs["seed"],
|
|
165
|
+
)
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""Single-point crystal plasticity slip activation module (DES-AIMS-050 / REQ-AIMS-050)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ai_materials_scientist.evidence import record_run
|
|
8
|
+
from ai_materials_scientist.validation import (
|
|
9
|
+
check_finite_array,
|
|
10
|
+
register_validator,
|
|
11
|
+
validate_parameters,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
_MODULE_NAME = "crystal-plasticity"
|
|
15
|
+
|
|
16
|
+
# Table CP-12: fixed ordered (plane normal, slip direction) pairs, crystal frame.
|
|
17
|
+
_SLIP_SYSTEMS = [
|
|
18
|
+
((1, 1, 1), (0, 1, -1)),
|
|
19
|
+
((1, 1, 1), (1, 0, -1)),
|
|
20
|
+
((1, 1, 1), (1, -1, 0)),
|
|
21
|
+
((1, 1, -1), (0, 1, 1)),
|
|
22
|
+
((1, 1, -1), (1, 0, 1)),
|
|
23
|
+
((1, 1, -1), (1, -1, 0)),
|
|
24
|
+
((1, -1, 1), (0, 1, 1)),
|
|
25
|
+
((1, -1, 1), (1, 0, -1)),
|
|
26
|
+
((1, -1, 1), (1, 1, 0)),
|
|
27
|
+
((-1, 1, 1), (0, 1, -1)),
|
|
28
|
+
((-1, 1, 1), (1, 0, 1)),
|
|
29
|
+
((-1, 1, 1), (1, 1, 0)),
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
_ORTHOGONALITY_TOL = 1e-6
|
|
33
|
+
_DETERMINANT_TOL = 1e-6
|
|
34
|
+
_SYMMETRY_TOL = 1e-6
|
|
35
|
+
_MIN_STRESS_NORM = 1e-12
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _cp_validator(params: dict) -> dict:
|
|
39
|
+
"""DES-AIMS-002 registered validator for module_name='crystal-plasticity'."""
|
|
40
|
+
q = params["orientation_q"]
|
|
41
|
+
stress = params["stress_tensor"]
|
|
42
|
+
crss = params["crss"]
|
|
43
|
+
gamma_dot_0 = params["gamma_dot_0"]
|
|
44
|
+
n = params["n"]
|
|
45
|
+
|
|
46
|
+
q_check = check_finite_array("orientation_q", q)
|
|
47
|
+
if not q_check["ok"]:
|
|
48
|
+
return q_check
|
|
49
|
+
if q.shape != (3, 3):
|
|
50
|
+
return {"ok": False, "parameter": "orientation_q", "constraint": "shape == (3, 3)"}
|
|
51
|
+
if np.max(np.abs(q.T @ q - np.eye(3))) > _ORTHOGONALITY_TOL:
|
|
52
|
+
return {
|
|
53
|
+
"ok": False,
|
|
54
|
+
"parameter": "orientation_q",
|
|
55
|
+
"constraint": "Q must be orthogonal (Q^T Q == I within 1e-6)",
|
|
56
|
+
}
|
|
57
|
+
if abs(np.linalg.det(q) - 1.0) > _DETERMINANT_TOL:
|
|
58
|
+
return {
|
|
59
|
+
"ok": False,
|
|
60
|
+
"parameter": "orientation_q",
|
|
61
|
+
"constraint": "det(Q) == 1 within 1e-6",
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
stress_check = check_finite_array("stress_tensor", stress)
|
|
65
|
+
if not stress_check["ok"]:
|
|
66
|
+
return stress_check
|
|
67
|
+
if stress.shape != (3, 3):
|
|
68
|
+
return {"ok": False, "parameter": "stress_tensor", "constraint": "shape == (3, 3)"}
|
|
69
|
+
if np.max(np.abs(stress - stress.T)) > _SYMMETRY_TOL:
|
|
70
|
+
return {
|
|
71
|
+
"ok": False,
|
|
72
|
+
"parameter": "stress_tensor",
|
|
73
|
+
"constraint": "stress_tensor must be symmetric within 1e-6",
|
|
74
|
+
}
|
|
75
|
+
if np.linalg.norm(stress) < _MIN_STRESS_NORM:
|
|
76
|
+
return {
|
|
77
|
+
"ok": False,
|
|
78
|
+
"parameter": "stress_tensor",
|
|
79
|
+
"constraint": "Frobenius norm must be >= 1e-12",
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if crss <= 0 or not np.isfinite(crss):
|
|
83
|
+
return {"ok": False, "parameter": "crss", "constraint": "crss > 0 and finite"}
|
|
84
|
+
if gamma_dot_0 <= 0 or not np.isfinite(gamma_dot_0):
|
|
85
|
+
return {
|
|
86
|
+
"ok": False,
|
|
87
|
+
"parameter": "gamma_dot_0",
|
|
88
|
+
"constraint": "gamma_dot_0 > 0 and finite",
|
|
89
|
+
}
|
|
90
|
+
if n <= 0 or not np.isfinite(n):
|
|
91
|
+
return {"ok": False, "parameter": "n", "constraint": "n > 0 and finite"}
|
|
92
|
+
return {"ok": True}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
register_validator(_MODULE_NAME, _cp_validator)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _validate(orientation_q, stress_tensor, crss, gamma_dot_0, n) -> None:
|
|
99
|
+
result = validate_parameters(
|
|
100
|
+
_MODULE_NAME,
|
|
101
|
+
{
|
|
102
|
+
"orientation_q": orientation_q,
|
|
103
|
+
"stress_tensor": stress_tensor,
|
|
104
|
+
"crss": crss,
|
|
105
|
+
"gamma_dot_0": gamma_dot_0,
|
|
106
|
+
"n": n,
|
|
107
|
+
},
|
|
108
|
+
)
|
|
109
|
+
if not result["ok"]:
|
|
110
|
+
raise ValueError(f"{result['parameter']}: {result['constraint']}")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# @id CODE-AIMS-050
|
|
114
|
+
# @implements REQ-AIMS-050 REQ-AIMS-003
|
|
115
|
+
# @design DES-AIMS-050
|
|
116
|
+
def run_crystal_plasticity(
|
|
117
|
+
orientation_q: np.ndarray,
|
|
118
|
+
stress_tensor: np.ndarray,
|
|
119
|
+
crss: float,
|
|
120
|
+
gamma_dot_0: float,
|
|
121
|
+
n: float,
|
|
122
|
+
) -> dict:
|
|
123
|
+
"""Evaluate Schmid factors, resolved shear stresses, and slip activation.
|
|
124
|
+
|
|
125
|
+
Rejects any out-of-domain parameter (REQ-AIMS-003) before any
|
|
126
|
+
Schmid-factor computation (REQ-AIMS-050).
|
|
127
|
+
"""
|
|
128
|
+
_validate(orientation_q, stress_tensor, crss, gamma_dot_0, n)
|
|
129
|
+
|
|
130
|
+
stress_norm = np.linalg.norm(stress_tensor)
|
|
131
|
+
stress_hat = stress_tensor / stress_norm
|
|
132
|
+
|
|
133
|
+
schmid_factors = []
|
|
134
|
+
resolved_shear_stresses = []
|
|
135
|
+
active_systems = []
|
|
136
|
+
shear_strain_rates = []
|
|
137
|
+
|
|
138
|
+
for plane_normal, slip_direction in _SLIP_SYSTEMS:
|
|
139
|
+
n_crystal = np.array(plane_normal, dtype=np.float64)
|
|
140
|
+
d_crystal = np.array(slip_direction, dtype=np.float64)
|
|
141
|
+
n_sample = orientation_q @ n_crystal
|
|
142
|
+
d_sample = orientation_q @ d_crystal
|
|
143
|
+
n_hat = n_sample / np.linalg.norm(n_sample)
|
|
144
|
+
d_hat = d_sample / np.linalg.norm(d_sample)
|
|
145
|
+
|
|
146
|
+
schmid_tensor = np.outer(n_hat, d_hat)
|
|
147
|
+
schmid_factor = float(np.sum(schmid_tensor * stress_hat))
|
|
148
|
+
tau = schmid_factor * stress_norm
|
|
149
|
+
|
|
150
|
+
is_active = bool(abs(tau) >= crss)
|
|
151
|
+
shear_rate = gamma_dot_0 * np.sign(tau) * abs(tau / crss) ** n if is_active else 0.0
|
|
152
|
+
|
|
153
|
+
schmid_factors.append(schmid_factor)
|
|
154
|
+
resolved_shear_stresses.append(tau)
|
|
155
|
+
active_systems.append(is_active)
|
|
156
|
+
shear_strain_rates.append(float(shear_rate))
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
"schmid_factors": schmid_factors,
|
|
160
|
+
"resolved_shear_stresses": resolved_shear_stresses,
|
|
161
|
+
"active_systems": active_systems,
|
|
162
|
+
"shear_strain_rates": shear_strain_rates,
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# @id CODE-AIMS-902
|
|
167
|
+
# @implements REQ-AIMS-050 REQ-AIMS-004 REQ-AIMS-005
|
|
168
|
+
# @design DES-AIMS-050
|
|
169
|
+
def run_crystal_plasticity_with_evidence(**kwargs) -> dict:
|
|
170
|
+
"""Run crystal plasticity and wrap the result as a reproducible RunRecord."""
|
|
171
|
+
result = run_crystal_plasticity(**kwargs)
|
|
172
|
+
return record_run(
|
|
173
|
+
module_name=_MODULE_NAME,
|
|
174
|
+
unit_system="stress-units-as-supplied",
|
|
175
|
+
params={k: v for k, v in kwargs.items() if k not in ("orientation_q", "stress_tensor")},
|
|
176
|
+
arrays={
|
|
177
|
+
"schmid_factors": np.array(result["schmid_factors"], dtype=np.float64),
|
|
178
|
+
"resolved_shear_stresses": np.array(
|
|
179
|
+
result["resolved_shear_stresses"], dtype=np.float64
|
|
180
|
+
),
|
|
181
|
+
"shear_strain_rates": np.array(result["shear_strain_rates"], dtype=np.float64),
|
|
182
|
+
},
|
|
183
|
+
seed=None,
|
|
184
|
+
)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""Request dispatcher for ai_materials_scientist (DES-AIMS-001)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from ai_data_scientist.language_router import detect_language as _detect_language
|
|
9
|
+
|
|
10
|
+
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
11
|
+
DEFAULT_MANIFEST_PATH = (
|
|
12
|
+
REPO_ROOT / ".github" / "skills" / "ai-materials-scientist" / "manifest.json"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def load_manifest(manifest_path: Path | None = None) -> dict:
|
|
17
|
+
"""Load the static method-name-to-module manifest (DES-AIMS-001)."""
|
|
18
|
+
path = manifest_path or DEFAULT_MANIFEST_PATH
|
|
19
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _matched_methods(request_text: str, manifest: dict) -> list[str]:
|
|
23
|
+
lowered = request_text.lower()
|
|
24
|
+
matched = []
|
|
25
|
+
for method, entry in manifest.items():
|
|
26
|
+
names = entry.get("names", {})
|
|
27
|
+
candidates = list(names.get("en", [])) + list(names.get("ja", []))
|
|
28
|
+
if any(
|
|
29
|
+
(candidate.lower() in lowered) if candidate.isascii() else (candidate in request_text)
|
|
30
|
+
for candidate in candidates
|
|
31
|
+
):
|
|
32
|
+
matched.append(method)
|
|
33
|
+
return matched
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# @id CODE-AIMS-001
|
|
37
|
+
# @implements REQ-AIMS-001 REQ-AIMS-002
|
|
38
|
+
# @design DES-AIMS-001
|
|
39
|
+
def dispatch(
|
|
40
|
+
request_text: str,
|
|
41
|
+
language: str | None = None,
|
|
42
|
+
manifest_path: Path | None = None,
|
|
43
|
+
) -> dict:
|
|
44
|
+
"""Classify ``request_text`` and dispatch to exactly one matched module.
|
|
45
|
+
|
|
46
|
+
``language`` may be supplied explicitly; otherwise it is detected from
|
|
47
|
+
``request_text`` (REQ-AIMS-001) and propagated into the result so every
|
|
48
|
+
downstream (module handler, clarification, rejection) path can render
|
|
49
|
+
its user-facing text in that language.
|
|
50
|
+
"""
|
|
51
|
+
if not isinstance(request_text, str):
|
|
52
|
+
raise ValueError("request_text: must be a str") # noqa: TRY004
|
|
53
|
+
if language is not None and language not in ("en", "ja"):
|
|
54
|
+
raise ValueError("language: must be 'en' or 'ja' when explicitly supplied")
|
|
55
|
+
detected_language = language or _detect_language(request_text)
|
|
56
|
+
manifest = load_manifest(manifest_path)
|
|
57
|
+
matched = _matched_methods(request_text, manifest)
|
|
58
|
+
|
|
59
|
+
if len(matched) == 1:
|
|
60
|
+
return {
|
|
61
|
+
"outcome": "dispatch",
|
|
62
|
+
"module": matched[0],
|
|
63
|
+
"language": detected_language,
|
|
64
|
+
# Populated once the matched module's handler is implemented and
|
|
65
|
+
# wired in (DES-AIMS-010..070); absent any handler yet, this is
|
|
66
|
+
# explicitly None rather than an omitted key, per DES-AIMS-001's
|
|
67
|
+
# DispatchResult {module, handler_result} contract.
|
|
68
|
+
"handler_result": None,
|
|
69
|
+
}
|
|
70
|
+
if len(matched) > 1:
|
|
71
|
+
return {
|
|
72
|
+
"outcome": "clarification",
|
|
73
|
+
"candidates": matched,
|
|
74
|
+
"language": detected_language,
|
|
75
|
+
"clarification_question": _render_clarification(matched, detected_language),
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
"outcome": "rejected",
|
|
79
|
+
"language": detected_language,
|
|
80
|
+
"rejected_method": _render_rejection(detected_language),
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _render_clarification(candidates: list[str], language: str) -> str:
|
|
85
|
+
"""Render a single-sentence clarification question in ``language``.
|
|
86
|
+
|
|
87
|
+
Method names (e.g. ``phase-field``) are the only permitted non-``language``
|
|
88
|
+
tokens, per REQ-AIMS-001's acceptance.
|
|
89
|
+
"""
|
|
90
|
+
names = "、".join(candidates) if language == "ja" else ", ".join(candidates)
|
|
91
|
+
if language == "ja":
|
|
92
|
+
return f"{names} のどちらを意図していますか。明確にしてください。"
|
|
93
|
+
return f"Did you mean {names}? Please clarify which method you want."
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _render_rejection(language: str) -> str:
|
|
97
|
+
"""Render a single-sentence rejection message in ``language``."""
|
|
98
|
+
if language == "ja":
|
|
99
|
+
return "対応するシミュレーション手法が要求から認識されませんでした。"
|
|
100
|
+
return "No supported simulation method was recognized in your request."
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Run evidence recording and JSON-safe codec (DES-AIMS-003 / REQ-AIMS-004/005)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
SCHEMA_VERSION = 1
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# @id CODE-AIMS-003
|
|
13
|
+
# @implements REQ-AIMS-004 REQ-AIMS-005
|
|
14
|
+
# @design DES-AIMS-003
|
|
15
|
+
def record_run(
|
|
16
|
+
module_name: str,
|
|
17
|
+
unit_system: str,
|
|
18
|
+
params: dict[str, Any],
|
|
19
|
+
arrays: dict[str, np.ndarray],
|
|
20
|
+
seed: int | None,
|
|
21
|
+
*,
|
|
22
|
+
allow_integer_arrays: frozenset[str] = frozenset(),
|
|
23
|
+
) -> dict:
|
|
24
|
+
"""Build a RunRecord with exactly `metadata`, `parameters`, `arrays`.
|
|
25
|
+
|
|
26
|
+
``seed`` is the explicit integer seed for a stochastic module, or
|
|
27
|
+
``None`` for a deterministic module (REQ-AIMS-004). Every array must be
|
|
28
|
+
``float64`` unless its name is listed in ``allow_integer_arrays`` (a
|
|
29
|
+
module's own requirement explicitly stating an integer array).
|
|
30
|
+
"""
|
|
31
|
+
for name, array in arrays.items():
|
|
32
|
+
if name in allow_integer_arrays:
|
|
33
|
+
continue
|
|
34
|
+
if array.dtype != np.float64:
|
|
35
|
+
raise ValueError(
|
|
36
|
+
f"array '{name}' must be float64 unless explicitly declared integer "
|
|
37
|
+
f"(REQ-AIMS-004), got dtype={array.dtype}"
|
|
38
|
+
)
|
|
39
|
+
return {
|
|
40
|
+
"metadata": {
|
|
41
|
+
"module": module_name,
|
|
42
|
+
"unit_system": unit_system,
|
|
43
|
+
"schema_version": SCHEMA_VERSION,
|
|
44
|
+
"seed": seed,
|
|
45
|
+
},
|
|
46
|
+
"parameters": dict(params),
|
|
47
|
+
"arrays": dict(arrays),
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# @id CODE-AIMS-903
|
|
52
|
+
# @implements REQ-AIMS-004
|
|
53
|
+
# @design DES-AIMS-003
|
|
54
|
+
def to_json(run_record: dict) -> dict:
|
|
55
|
+
"""Encode a RunRecord's `arrays` ndarrays as {dtype, shape, data}."""
|
|
56
|
+
encoded_arrays = {}
|
|
57
|
+
for name, array in run_record["arrays"].items():
|
|
58
|
+
encoded_arrays[name] = {
|
|
59
|
+
"dtype": str(array.dtype),
|
|
60
|
+
"shape": list(array.shape),
|
|
61
|
+
"data": array.tolist(),
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
"metadata": dict(run_record["metadata"]),
|
|
65
|
+
"parameters": dict(run_record["parameters"]),
|
|
66
|
+
"arrays": encoded_arrays,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# @id CODE-AIMS-904
|
|
71
|
+
# @implements REQ-AIMS-004
|
|
72
|
+
# @design DES-AIMS-003
|
|
73
|
+
def from_json(json_safe_record: dict) -> dict:
|
|
74
|
+
"""Reconstruct a RunRecord from its JSON-safe encoding (inverse of to_json)."""
|
|
75
|
+
decoded_arrays = {}
|
|
76
|
+
for name, encoded in json_safe_record["arrays"].items():
|
|
77
|
+
decoded_arrays[name] = np.array(encoded["data"], dtype=encoded["dtype"]).reshape(
|
|
78
|
+
encoded["shape"]
|
|
79
|
+
)
|
|
80
|
+
return {
|
|
81
|
+
"metadata": dict(json_safe_record["metadata"]),
|
|
82
|
+
"parameters": dict(json_safe_record["parameters"]),
|
|
83
|
+
"arrays": decoded_arrays,
|
|
84
|
+
}
|