simjecture 0.1.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.
- conjecture_solver/__init__.py +10 -0
- conjecture_solver/__main__.py +4 -0
- conjecture_solver/action_handlers.py +459 -0
- conjecture_solver/adapters/__init__.py +7 -0
- conjecture_solver/adapters/base.py +96 -0
- conjecture_solver/adapters/fake.py +155 -0
- conjecture_solver/adapters/pic.py +196 -0
- conjecture_solver/adapters/warpx.py +1375 -0
- conjecture_solver/autonomous_research.py +1071 -0
- conjecture_solver/benchmarks/__init__.py +6 -0
- conjecture_solver/benchmarks/electrostatic_pic.py +547 -0
- conjecture_solver/benchmarks/kinetic_sufficiency.py +318 -0
- conjecture_solver/builtin_skills/warpx/SKILL.md +151 -0
- conjecture_solver/builtin_skills/warpx/agents/openai.yaml +4 -0
- conjecture_solver/builtin_skills/warpx/examples/implicit_em_smoke.py +74 -0
- conjecture_solver/builtin_skills/warpx/examples/minimal_smoke.py +54 -0
- conjecture_solver/builtin_skills/warpx/examples/openpmd_field_smoke.py +87 -0
- conjecture_solver/builtin_skills/warpx/manifest.json +11 -0
- conjecture_solver/builtin_skills/warpx/references/2d-xz-commissioning.md +145 -0
- conjecture_solver/builtin_skills/warpx/references/cpu-launch-tuning.md +54 -0
- conjecture_solver/builtin_skills/warpx/references/diagnostics.md +139 -0
- conjecture_solver/builtin_skills/warpx/references/gpu-launch-tuning.md +79 -0
- conjecture_solver/builtin_skills/warpx/references/local-cuda-deployment.md +87 -0
- conjecture_solver/builtin_skills/warpx/references/numerical-risks.md +32 -0
- conjecture_solver/builtin_skills/warpx/references/picmi-interface.md +118 -0
- conjecture_solver/builtin_skills/warpx/references/resource-scaling.md +24 -0
- conjecture_solver/builtin_skills/warpx/references/time-integration.md +58 -0
- conjecture_solver/builtin_skills/warpx/scripts/benchmark_cpu_threads.py +207 -0
- conjecture_solver/builtin_skills/warpx/scripts/benchmark_gpu.py +242 -0
- conjecture_solver/builtin_skills/warpx/scripts/bootstrap_local_cuda.sh +82 -0
- conjecture_solver/builtin_skills/warpx/scripts/probe_local_cuda.py +110 -0
- conjecture_solver/builtin_skills/warpx/scripts/reduced_energy_budget.py +195 -0
- conjecture_solver/builtin_skills/warpx/scripts/run_local_cuda.sh +39 -0
- conjecture_solver/campaign.py +406 -0
- conjecture_solver/cli.py +963 -0
- conjecture_solver/confirmation.py +287 -0
- conjecture_solver/control.py +234 -0
- conjecture_solver/deployment.py +874 -0
- conjecture_solver/discovery.py +68 -0
- conjecture_solver/domains/__init__.py +40 -0
- conjecture_solver/domains/base.py +157 -0
- conjecture_solver/domains/kinetic_sufficiency.py +521 -0
- conjecture_solver/ledger.py +238 -0
- conjecture_solver/lifecycle.py +131 -0
- conjecture_solver/literature.py +494 -0
- conjecture_solver/llm.py +228 -0
- conjecture_solver/models.py +279 -0
- conjecture_solver/mvp_agent.py +3212 -0
- conjecture_solver/mvp_claims.py +1279 -0
- conjecture_solver/mvp_control.py +322 -0
- conjecture_solver/mvp_guidance.py +172 -0
- conjecture_solver/mvp_launch.py +1296 -0
- conjecture_solver/mvp_monitor.py +1487 -0
- conjecture_solver/mvp_skills.py +538 -0
- conjecture_solver/orchestration.py +578 -0
- conjecture_solver/outbox.py +526 -0
- conjecture_solver/parameters.py +394 -0
- conjecture_solver/proposals.py +427 -0
- conjecture_solver/research_tools.py +278 -0
- conjecture_solver/schema_export.py +246 -0
- conjecture_solver/search.py +1047 -0
- conjecture_solver/semantics.py +146 -0
- conjecture_solver/tui/__init__.py +7 -0
- conjecture_solver/tui/app.py +202 -0
- conjecture_solver/tui/claim_views.py +213 -0
- conjecture_solver/tui/screens.py +1014 -0
- conjecture_solver/warpx_analysis.py +184 -0
- conjecture_solver/warpx_campaign.py +148 -0
- conjecture_solver/warpx_confirmation.py +617 -0
- simjecture-0.1.0.dist-info/METADATA +400 -0
- simjecture-0.1.0.dist-info/RECORD +75 -0
- simjecture-0.1.0.dist-info/WHEEL +4 -0
- simjecture-0.1.0.dist-info/entry_points.txt +4 -0
- simjecture-0.1.0.dist-info/licenses/LICENSE +202 -0
- simjecture-0.1.0.dist-info/licenses/NOTICE +6 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Deterministic in-process adapter for the first physics benchmark."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
from ..benchmarks.kinetic_sufficiency import run_kinetic_sufficiency_benchmark
|
|
9
|
+
from ..models import ExperimentSpec
|
|
10
|
+
from .base import (
|
|
11
|
+
CapabilityManifest,
|
|
12
|
+
CostEstimate,
|
|
13
|
+
JobReference,
|
|
14
|
+
JobState,
|
|
15
|
+
JobStatus,
|
|
16
|
+
NormalizedResult,
|
|
17
|
+
RawResult,
|
|
18
|
+
RunPackage,
|
|
19
|
+
ValidationReport,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DeterministicKineticScheduler:
|
|
24
|
+
"""External-system stand-in whose state can outlive an adapter process."""
|
|
25
|
+
|
|
26
|
+
def __init__(self) -> None:
|
|
27
|
+
self.jobs: dict[str, RawResult] = {}
|
|
28
|
+
self.idempotency: dict[str, str] = {}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class DeterministicKineticAdapter:
|
|
32
|
+
def __init__(self, scheduler: DeterministicKineticScheduler | None = None) -> None:
|
|
33
|
+
self._scheduler = scheduler or DeterministicKineticScheduler()
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def submitted_job_count(self) -> int:
|
|
37
|
+
"""Count distinct external jobs, excluding idempotent reattachments."""
|
|
38
|
+
|
|
39
|
+
return len(self._scheduler.jobs)
|
|
40
|
+
|
|
41
|
+
def capabilities(self) -> CapabilityManifest:
|
|
42
|
+
return CapabilityManifest(
|
|
43
|
+
adapter_name="deterministic_kinetic",
|
|
44
|
+
adapter_version="0.1.0",
|
|
45
|
+
supported_actions=("kinetic_sufficiency",),
|
|
46
|
+
supported_models=("linearized_1d_electrostatic_vlasov_poisson",),
|
|
47
|
+
supported_diagnostics=("dominant_linear_mode", "distribution_moments"),
|
|
48
|
+
supported_coordinates=("density", "mean_velocity", "variance"),
|
|
49
|
+
supported_observable_kinds=("dominant_linear_growth_rate",),
|
|
50
|
+
supports_checkpoint=False,
|
|
51
|
+
deterministic=True,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def validate(self, experiment: ExperimentSpec) -> ValidationReport:
|
|
55
|
+
errors: list[str] = []
|
|
56
|
+
if experiment.action_type != "kinetic_sufficiency":
|
|
57
|
+
errors.append("unsupported action_type")
|
|
58
|
+
if experiment.physical_parameters.get("wavenumber") != 0.5:
|
|
59
|
+
errors.append("the planted benchmark is preregistered at wavenumber 0.5")
|
|
60
|
+
required = {"dominant_linear_mode", "distribution_moments"}
|
|
61
|
+
missing = required - set(experiment.required_diagnostics)
|
|
62
|
+
if missing:
|
|
63
|
+
errors.append(f"missing diagnostics: {sorted(missing)}")
|
|
64
|
+
return ValidationReport(valid=not errors, errors=tuple(errors))
|
|
65
|
+
|
|
66
|
+
def estimate_cost(self, experiment: ExperimentSpec) -> CostEstimate:
|
|
67
|
+
report = self.validate(experiment)
|
|
68
|
+
if not report.valid:
|
|
69
|
+
raise ValueError("; ".join(report.errors))
|
|
70
|
+
return CostEstimate(compute_units=0.001, wall_seconds=1.0, storage_bytes=20_000)
|
|
71
|
+
|
|
72
|
+
def compile_input(self, experiment: ExperimentSpec) -> RunPackage:
|
|
73
|
+
report = self.validate(experiment)
|
|
74
|
+
if not report.valid:
|
|
75
|
+
raise ValueError("; ".join(report.errors))
|
|
76
|
+
payload = {
|
|
77
|
+
"benchmark": "kinetic_sufficiency",
|
|
78
|
+
"wavenumber": experiment.physical_parameters["wavenumber"],
|
|
79
|
+
}
|
|
80
|
+
canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"))
|
|
81
|
+
return RunPackage(
|
|
82
|
+
experiment_id=experiment.id,
|
|
83
|
+
adapter_name="deterministic_kinetic",
|
|
84
|
+
payload=payload,
|
|
85
|
+
package_hash=hashlib.sha256(canonical.encode()).hexdigest(),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def submit(self, run: RunPackage, *, idempotency_key: str) -> JobReference:
|
|
89
|
+
if idempotency_key in self._scheduler.idempotency:
|
|
90
|
+
return JobReference(
|
|
91
|
+
job_id=self._scheduler.idempotency[idempotency_key],
|
|
92
|
+
experiment_id=run.experiment_id,
|
|
93
|
+
idempotency_key=idempotency_key,
|
|
94
|
+
)
|
|
95
|
+
job_identity = hashlib.sha256(
|
|
96
|
+
f"{run.package_hash}:{idempotency_key}".encode()
|
|
97
|
+
).hexdigest()
|
|
98
|
+
job_id = f"fake-{job_identity[:16]}"
|
|
99
|
+
benchmark = run_kinetic_sufficiency_benchmark(
|
|
100
|
+
wavenumber=float(run.payload["wavenumber"])
|
|
101
|
+
)
|
|
102
|
+
result_payload = {
|
|
103
|
+
"experiment_id": run.experiment_id,
|
|
104
|
+
"benchmark": benchmark.model_dump(mode="json"),
|
|
105
|
+
}
|
|
106
|
+
canonical_result = json.dumps(result_payload, sort_keys=True, separators=(",", ":"))
|
|
107
|
+
self._scheduler.jobs[job_id] = RawResult(
|
|
108
|
+
job_id=job_id,
|
|
109
|
+
payload=result_payload,
|
|
110
|
+
artifact_hashes=(hashlib.sha256(canonical_result.encode()).hexdigest(),),
|
|
111
|
+
)
|
|
112
|
+
self._scheduler.idempotency[idempotency_key] = job_id
|
|
113
|
+
return JobReference(
|
|
114
|
+
job_id=job_id,
|
|
115
|
+
experiment_id=run.experiment_id,
|
|
116
|
+
idempotency_key=idempotency_key,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def monitor(self, job: JobReference) -> JobStatus:
|
|
120
|
+
state = JobState.COMPLETED if job.job_id in self._scheduler.jobs else JobState.UNKNOWN
|
|
121
|
+
return JobStatus(job_id=job.job_id, state=state)
|
|
122
|
+
|
|
123
|
+
def retrieve(self, job: JobReference) -> RawResult:
|
|
124
|
+
try:
|
|
125
|
+
return self._scheduler.jobs[job.job_id]
|
|
126
|
+
except KeyError as error:
|
|
127
|
+
raise LookupError(f"unknown fake job {job.job_id}") from error
|
|
128
|
+
|
|
129
|
+
def normalize(self, result: RawResult) -> NormalizedResult:
|
|
130
|
+
payload = result.payload
|
|
131
|
+
benchmark = payload["benchmark"]
|
|
132
|
+
return NormalizedResult(
|
|
133
|
+
experiment_id=str(payload["experiment_id"]),
|
|
134
|
+
observables={
|
|
135
|
+
"maxwellian_growth_rate": float(
|
|
136
|
+
benchmark["maxwellian"]["mode"]["growth_rate"]
|
|
137
|
+
),
|
|
138
|
+
"two_stream_growth_rate": float(
|
|
139
|
+
benchmark["two_stream"]["mode"]["growth_rate"]
|
|
140
|
+
),
|
|
141
|
+
"moments_match": bool(benchmark["moments_match"]),
|
|
142
|
+
"hypothesis_falsified": bool(benchmark["witness"]["falsifies"]),
|
|
143
|
+
},
|
|
144
|
+
diagnostics=benchmark,
|
|
145
|
+
artifact_hashes=result.artifact_hashes,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
def cancel(self, job: JobReference) -> JobStatus:
|
|
149
|
+
if job.job_id in self._scheduler.jobs:
|
|
150
|
+
return JobStatus(
|
|
151
|
+
job_id=job.job_id,
|
|
152
|
+
state=JobState.COMPLETED,
|
|
153
|
+
detail="deterministic in-process jobs complete atomically",
|
|
154
|
+
)
|
|
155
|
+
return JobStatus(job_id=job.job_id, state=JobState.UNKNOWN)
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""In-process adapter for the independent electrostatic PIC benchmark."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
|
|
8
|
+
from ..benchmarks.electrostatic_pic import (
|
|
9
|
+
PICConfig,
|
|
10
|
+
PICSufficiencyResult,
|
|
11
|
+
run_pic_sufficiency_benchmark,
|
|
12
|
+
)
|
|
13
|
+
from ..models import ExperimentSpec
|
|
14
|
+
from .base import (
|
|
15
|
+
CapabilityManifest,
|
|
16
|
+
CostEstimate,
|
|
17
|
+
JobReference,
|
|
18
|
+
JobState,
|
|
19
|
+
JobStatus,
|
|
20
|
+
NormalizedResult,
|
|
21
|
+
RawResult,
|
|
22
|
+
RunPackage,
|
|
23
|
+
ValidationReport,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DeterministicPICScheduler:
|
|
28
|
+
"""External-scheduler stand-in shared across restarted adapter instances."""
|
|
29
|
+
|
|
30
|
+
def __init__(self) -> None:
|
|
31
|
+
self.jobs: dict[str, RawResult] = {}
|
|
32
|
+
self.idempotency: dict[str, str] = {}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ElectrostaticPICAdapter:
|
|
36
|
+
_NUMERICAL_KEYS = {
|
|
37
|
+
"grid_cells",
|
|
38
|
+
"velocity_beams",
|
|
39
|
+
"particles_per_beam",
|
|
40
|
+
"time_step",
|
|
41
|
+
"final_time",
|
|
42
|
+
"diagnostic_interval",
|
|
43
|
+
"seed",
|
|
44
|
+
}
|
|
45
|
+
_PHYSICAL_KEYS = {"wavenumber", "perturbation_amplitude", "stream_drift"}
|
|
46
|
+
|
|
47
|
+
def __init__(self, scheduler: DeterministicPICScheduler | None = None) -> None:
|
|
48
|
+
self._scheduler = scheduler or DeterministicPICScheduler()
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def submitted_job_count(self) -> int:
|
|
52
|
+
return len(self._scheduler.jobs)
|
|
53
|
+
|
|
54
|
+
def capabilities(self) -> CapabilityManifest:
|
|
55
|
+
return CapabilityManifest(
|
|
56
|
+
adapter_name="electrostatic_pic",
|
|
57
|
+
adapter_version="0.1.0",
|
|
58
|
+
supported_actions=("kinetic_sufficiency",),
|
|
59
|
+
supported_models=("electrostatic_1d_pic_vlasov_poisson",),
|
|
60
|
+
supported_diagnostics=(
|
|
61
|
+
"dominant_linear_mode",
|
|
62
|
+
"distribution_moments",
|
|
63
|
+
"energy_conservation",
|
|
64
|
+
"gauss_residual",
|
|
65
|
+
),
|
|
66
|
+
supported_coordinates=("density", "mean_velocity", "variance"),
|
|
67
|
+
supported_observable_kinds=("effective_fundamental_growth_rate",),
|
|
68
|
+
supports_checkpoint=False,
|
|
69
|
+
deterministic=True,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def _config(self, experiment: ExperimentSpec) -> PICConfig:
|
|
73
|
+
values = {
|
|
74
|
+
**experiment.physical_parameters,
|
|
75
|
+
**experiment.numerical_parameters,
|
|
76
|
+
}
|
|
77
|
+
return PICConfig.model_validate(values)
|
|
78
|
+
|
|
79
|
+
def validate(self, experiment: ExperimentSpec) -> ValidationReport:
|
|
80
|
+
errors: list[str] = []
|
|
81
|
+
warnings: list[str] = []
|
|
82
|
+
if experiment.action_type != "kinetic_sufficiency":
|
|
83
|
+
errors.append("unsupported action_type")
|
|
84
|
+
unknown_physical = set(experiment.physical_parameters) - self._PHYSICAL_KEYS
|
|
85
|
+
unknown_numerical = set(experiment.numerical_parameters) - self._NUMERICAL_KEYS
|
|
86
|
+
if unknown_physical:
|
|
87
|
+
errors.append(f"unknown physical parameters: {sorted(unknown_physical)}")
|
|
88
|
+
if unknown_numerical:
|
|
89
|
+
errors.append(f"unknown numerical parameters: {sorted(unknown_numerical)}")
|
|
90
|
+
missing_diagnostics = set(experiment.required_diagnostics) - set(
|
|
91
|
+
self.capabilities().supported_diagnostics
|
|
92
|
+
)
|
|
93
|
+
if missing_diagnostics:
|
|
94
|
+
errors.append(f"unsupported diagnostics: {sorted(missing_diagnostics)}")
|
|
95
|
+
if not errors:
|
|
96
|
+
try:
|
|
97
|
+
config = self._config(experiment)
|
|
98
|
+
except ValueError as error:
|
|
99
|
+
errors.append(f"invalid PIC configuration: {error}")
|
|
100
|
+
else:
|
|
101
|
+
particle_count = config.velocity_beams * config.particles_per_beam
|
|
102
|
+
if particle_count > 1_000_000:
|
|
103
|
+
warnings.append("PIC request contains more than one million particles")
|
|
104
|
+
return ValidationReport(valid=not errors, errors=tuple(errors), warnings=tuple(warnings))
|
|
105
|
+
|
|
106
|
+
def estimate_cost(self, experiment: ExperimentSpec) -> CostEstimate:
|
|
107
|
+
report = self.validate(experiment)
|
|
108
|
+
if not report.valid:
|
|
109
|
+
raise ValueError("; ".join(report.errors))
|
|
110
|
+
config = self._config(experiment)
|
|
111
|
+
particle_count = config.velocity_beams * config.particles_per_beam
|
|
112
|
+
step_count = round(config.final_time / config.time_step)
|
|
113
|
+
work = 2 * particle_count * step_count
|
|
114
|
+
return CostEstimate(
|
|
115
|
+
compute_units=work / 100_000_000,
|
|
116
|
+
wall_seconds=work / 20_000_000,
|
|
117
|
+
storage_bytes=(round(config.final_time / config.diagnostic_interval) + 1) * 128,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
def compile_input(self, experiment: ExperimentSpec) -> RunPackage:
|
|
121
|
+
report = self.validate(experiment)
|
|
122
|
+
if not report.valid:
|
|
123
|
+
raise ValueError("; ".join(report.errors))
|
|
124
|
+
payload = {
|
|
125
|
+
"benchmark": "electrostatic_pic_sufficiency",
|
|
126
|
+
"config": self._config(experiment).model_dump(mode="json"),
|
|
127
|
+
}
|
|
128
|
+
canonical = json.dumps(payload, sort_keys=True, separators=(",", ":"))
|
|
129
|
+
return RunPackage(
|
|
130
|
+
experiment_id=experiment.id,
|
|
131
|
+
adapter_name="electrostatic_pic",
|
|
132
|
+
payload=payload,
|
|
133
|
+
package_hash=hashlib.sha256(canonical.encode()).hexdigest(),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
def submit(self, run: RunPackage, *, idempotency_key: str) -> JobReference:
|
|
137
|
+
if idempotency_key in self._scheduler.idempotency:
|
|
138
|
+
return JobReference(
|
|
139
|
+
job_id=self._scheduler.idempotency[idempotency_key],
|
|
140
|
+
experiment_id=run.experiment_id,
|
|
141
|
+
idempotency_key=idempotency_key,
|
|
142
|
+
)
|
|
143
|
+
identity = hashlib.sha256(f"{run.package_hash}:{idempotency_key}".encode()).hexdigest()
|
|
144
|
+
job_id = f"pic-{identity[:16]}"
|
|
145
|
+
result = run_pic_sufficiency_benchmark(PICConfig.model_validate(run.payload["config"]))
|
|
146
|
+
result_payload = {
|
|
147
|
+
"experiment_id": run.experiment_id,
|
|
148
|
+
"benchmark": result.model_dump(mode="json"),
|
|
149
|
+
}
|
|
150
|
+
canonical = json.dumps(result_payload, sort_keys=True, separators=(",", ":"))
|
|
151
|
+
self._scheduler.jobs[job_id] = RawResult(
|
|
152
|
+
job_id=job_id,
|
|
153
|
+
payload=result_payload,
|
|
154
|
+
artifact_hashes=(hashlib.sha256(canonical.encode()).hexdigest(),),
|
|
155
|
+
)
|
|
156
|
+
self._scheduler.idempotency[idempotency_key] = job_id
|
|
157
|
+
return JobReference(
|
|
158
|
+
job_id=job_id,
|
|
159
|
+
experiment_id=run.experiment_id,
|
|
160
|
+
idempotency_key=idempotency_key,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def monitor(self, job: JobReference) -> JobStatus:
|
|
164
|
+
state = JobState.COMPLETED if job.job_id in self._scheduler.jobs else JobState.UNKNOWN
|
|
165
|
+
return JobStatus(job_id=job.job_id, state=state)
|
|
166
|
+
|
|
167
|
+
def retrieve(self, job: JobReference) -> RawResult:
|
|
168
|
+
try:
|
|
169
|
+
return self._scheduler.jobs[job.job_id]
|
|
170
|
+
except KeyError as error:
|
|
171
|
+
raise LookupError(f"unknown PIC job {job.job_id}") from error
|
|
172
|
+
|
|
173
|
+
def normalize(self, result: RawResult) -> NormalizedResult:
|
|
174
|
+
benchmark = PICSufficiencyResult.model_validate(result.payload["benchmark"])
|
|
175
|
+
if not benchmark.maxwellian.validity_passed or not benchmark.two_stream.validity_passed:
|
|
176
|
+
raise ValueError("PIC result failed numerical validity gates")
|
|
177
|
+
return NormalizedResult(
|
|
178
|
+
experiment_id=str(result.payload["experiment_id"]),
|
|
179
|
+
observables={
|
|
180
|
+
"maxwellian_growth_rate": benchmark.maxwellian.effective_growth_rate,
|
|
181
|
+
"two_stream_growth_rate": benchmark.two_stream.effective_growth_rate,
|
|
182
|
+
"moments_match": benchmark.moments_match,
|
|
183
|
+
"hypothesis_falsified": benchmark.hypothesis_falsified,
|
|
184
|
+
},
|
|
185
|
+
diagnostics=benchmark.model_dump(mode="json"),
|
|
186
|
+
artifact_hashes=result.artifact_hashes,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def cancel(self, job: JobReference) -> JobStatus:
|
|
190
|
+
if job.job_id in self._scheduler.jobs:
|
|
191
|
+
return JobStatus(
|
|
192
|
+
job_id=job.job_id,
|
|
193
|
+
state=JobState.COMPLETED,
|
|
194
|
+
detail="in-process PIC jobs complete synchronously",
|
|
195
|
+
)
|
|
196
|
+
return JobStatus(job_id=job.job_id, state=JobState.UNKNOWN)
|