simudo.gui package¶
Subpackages¶
- simudo.gui.panels package
- Submodules
- simudo.gui.panels.bands module
- simudo.gui.panels.bcs module
- simudo.gui.panels.layers module
- simudo.gui.panels.mat_ast module
- simudo.gui.panels.materials module
- simudo.gui.panels.opt_fields module
- simudo.gui.panels.output module
- simudo.gui.panels.processes module
- simudo.gui.panels.shared module
- simudo.gui.panels.simulation module
- simudo.gui.panels.stub module
- Module contents
Submodules¶
simudo.gui.app module¶
Simudo GUI — main entry point.
- Run with:
panel serve app.py –show –port 5006
from this directory (containing app.py), in an environment where panel is installed.
The working directory matters: the panels below are imported by bare name
(from model import ...), so serving app.py from anywhere else fails on
import.
- class simudo.gui.app.SimudoApp[source]¶
Bases:
object- property bundled_lib_dir: str¶
- get_effective_execution_profile() ExecutionProfile[source]¶
Return the active execution profile: per-project override if set, else user default.
- get_execution_profile_for_type(type_str: str)[source]¶
Return the last-used ExecutionProfile for this type, or None.
- get_library_dirs() list[str][source]¶
Return valid library directories: user dir first (higher precedence).
- load_from_checkpoint(project_path: str, checkpoint_relpath: str)[source]¶
Start a new (already-open, already-saved) project resuming from checkpoint_relpath (e.g. “checkpoints/sim_V=0.4.yaml”) found under project_path’s configured output folder.
Loads the frozen device-definition YAML that the runner copies into the output folder for provenance – not project_path itself, which may have kept changing since that run – so the resumed project’s layers/materials/bands/etc. are guaranteed to match what actually produced the checkpoint. Saves in place inside that run folder (see gui/TODO.md “Checkpoint / Resume UX” for why).
- notify_run_output_dir(host_path: str)[source]¶
Store the output dir and update both panels that display it.
- refresh_layers_missing_params()[source]¶
Recompute and redisplay the missing-params section and badge.
- refresh_layers_panel()[source]¶
Full rebuild of the Layers panel (table, schematic, overlays, missing params).
Call this after any change that affects what layers can reference — e.g. when project materials are added or removed.
- save_execution_profile_for_type(type_str: str, profile: ExecutionProfile)[source]¶
Remember the profile for this type in memory and persist to config.
- save_yaml(path: str = None)[source]¶
Save project. If no path given and no filepath set, prompt with dialog.
- set_default_execution_profile(profile: ExecutionProfile)[source]¶
Persist profile as the user-level default in ~/.simudo_gui.yaml.
- set_last_run_output_dir(host_path: str)[source]¶
Called by the simulation panel once the runner’s output directory is known.
simudo.gui.batch module¶
Simudo GUI — batch parameter sweep.
Data model, sidecar I/O, sub-YAML generation, and parallel launcher for running a set of sub-simulations that vary one or more project parameters.
Sidecar file: <project_stem>.batch.yaml (next to the project YAML).
Sub-YAML layout:
<output_folder>/0/<project>.yaml (output.folder = ".")
<output_folder>/1/<project>.yaml
...
- class simudo.gui.batch.BatchLauncher[source]¶
Bases:
objectLaunches sub-runs in parallel, bounded by a semaphore.
- launch_all(sub_yaml_paths: List[str], spec: BatchSpec, backend, runner_host: str, lib_dirs: List[str], log_cb: Callable[[str], None], status_cb: Callable[[int, str], None] | None = None) None[source]¶
Start a background supervisor thread that manages all sub-runs.
status_cb(idx, status) is called from background threads whenever a run changes state. status is one of: “queued”, “running”, “done”, “failed”, “skipped”.
- class simudo.gui.batch.BatchSpec(mode: 'str' = 'zip', max_parallel: 'int' = 1, variations: 'List[BatchVariation]' = <factory>)[source]¶
Bases:
object- max_parallel: int = 1¶
- mode: str = 'zip'¶
- variations: List[BatchVariation]¶
- class simudo.gui.batch.BatchTarget(kind: str, container_name: str, key: str = '', unit: str = '')[source]¶
Bases:
objectIdentifies a single numeric parameter in the project YAML tree.
- container_name: str¶
- classmethod from_dict(d: dict) BatchTarget[source]¶
- key: str = ''¶
- kind: str¶
- unit: str = ''¶
- class simudo.gui.batch.BatchVariation(label: str, target: BatchTarget, values: List[float])[source]¶
Bases:
objectOne dimension of the parameter sweep: which parameter and what values.
- classmethod from_dict(d: dict) BatchVariation[source]¶
- label: str¶
- target: BatchTarget¶
- values: List[float]¶
- simudo.gui.batch.build_combinations(spec: BatchSpec) List[List[Tuple[BatchTarget, float]]][source]¶
Return one list of (target, value) pairs per sub-run.
- simudo.gui.batch.compact_param_label(target: BatchTarget, value: float) str[source]¶
Return a short ‘name=value’ string for a single (target, value) pair.
- simudo.gui.batch.ensure_new_dir(cur_dir: str) str[source]¶
Return cur_dir (or an incremented variant) that does not yet exist.
- simudo.gui.batch.enumerate_sweep_params(project) List[Tuple[str, BatchTarget]][source]¶
Return all numeric parameters in the project that can be swept.
Returns a list of (display_label, BatchTarget) pairs.
- simudo.gui.batch.generate_sub_yamls(project_yaml_path: str, spec: BatchSpec) List[str][source]¶
Create numbered sub-directories and write a modified project YAML into each.
Sub-YAMLs use output.folder = “.” so runner output goes alongside them. Returns the list of absolute sub-YAML paths.
- simudo.gui.batch.get_current_param_value(project, target: BatchTarget) str[source]¶
Return a human-readable ‘current value + unit’ string for a BatchTarget.
Returns an empty string if the parameter has no value set.
simudo.gui.fourlayer_reference module¶
Reference run of the fourlayer IB solar cell using the original fourlayer.py driver. Output goes to gui/out/reference/ (relative to the working directory, which in Docker is /home/user/simudo/code).
- Run from the Docker container:
python3 gui/fourlayer_reference.py
The output is used by gui/compare_jv.py to validate simudo_1d_runner.py against the original driver.
simudo.gui.model module¶
Simudo GUI — project data model.
Plain Python dataclasses that map 1-to-1 with the project YAML schema. No Panel / param dependencies here; this module must be importable without any GUI framework installed.
- class simudo.gui.model.Band(name: 'str' = 'CB', type: 'str' = 'nondegenerate', sign: 'int' = -1, extent: 'Any' = 'all', extent_boundary_bc_left: 'str' = 'zero_current', extent_boundary_bc_right: 'str' = 'zero_current')[source]¶
Bases:
object- extent: Any = 'all'¶
- extent_boundary_bc_left: str = 'zero_current'¶
- extent_boundary_bc_right: str = 'zero_current'¶
- name: str = 'CB'¶
- sign: int = -1¶
- type: str = 'nondegenerate'¶
- class simudo.gui.model.BlackbodyIntensity(T_source: 'float' = 6000.0, T_source_unit: 'str' = 'K', concentration: 'float' = 1.0, E_min: 'float' = 1.42, E_min_unit: 'str' = 'eV', E_max: 'Optional[float]' = None, E_max_unit: 'str' = 'eV')[source]¶
Bases:
object- E_max: float | None = None¶
- E_max_unit: str = 'eV'¶
- E_min: float = 1.42¶
- E_min_unit: str = 'eV'¶
- T_source: float = 6000.0¶
- T_source_unit: str = 'K'¶
- concentration: float = 1.0¶
- class simudo.gui.model.CallableTopHat(region: str = 'domain', E_low: float = 0.0, E_low_unit: str = 'eV', E_high: float | None = None, E_high_unit: str = 'eV', value: float = 0.0, unit: str = '1/cm')[source]¶
Bases:
objectOne top-hat callable spec attached to a Process for a given region.
regionis either'domain'or a layer name.E_low/E_highare stored as floats with explicit units;E_highofNonemeans +infinity. MultipleCallableTopHatrows for the same callable shorthand are allowed (one per region scope).- E_high: float | None = None¶
- E_high_unit: str = 'eV'¶
- E_low: float = 0.0¶
- E_low_unit: str = 'eV'¶
- region: str = 'domain'¶
- unit: str = '1/cm'¶
- value: float = 0.0¶
- class simudo.gui.model.CheckpointStageSettings(checkpoint_at_end: 'bool' = True, at_values: 'List[float]' = <factory>)[source]¶
Bases:
object- at_values: List[float]¶
- checkpoint_at_end: bool = True¶
- class simudo.gui.model.CheckpointsSettings(intensity_ramp: 'CheckpointStageSettings' = <factory>, voltage_sweep: 'CheckpointStageSettings' = <factory>, directory: 'str' = 'checkpoints')[source]¶
Bases:
object- directory: str = 'checkpoints'¶
- intensity_ramp: CheckpointStageSettings¶
- voltage_sweep: CheckpointStageSettings¶
- class simudo.gui.model.Contact(role: 'str' = 'reference', band_bcs: 'Dict[str, str]' = <factory>)[source]¶
Bases:
object- band_bcs: Dict[str, str]¶
- role: str = 'reference'¶
- class simudo.gui.model.ExecutionProfile(type: str = 'docker', docker_container: str = '', docker_host_root: str = '', docker_container_root: str = '', docker_simudo_path: str = '', ssh_host: str = '', ssh_user: str = '', ssh_identity_file: str = '', ssh_remote_work_dir: str = '~/simudo_runs', ssh_simudo_path: str = '', ssh_delete_remote_after_sync: bool = False, python_cmd: str = 'python3')[source]¶
Bases:
objectDescribes how to launch simudo_1d_runner.py.
type: “local” | “docker” | “ssh” | “ssh+docker”
The user-level default lives in ~/.simudo_gui.yaml under the key “execution”. A per-project override can be stored in the project YAML under the same key; it is merged on top of the default at runtime.
- docker_container: str = ''¶
- docker_container_root: str = ''¶
- docker_host_root: str = ''¶
- docker_simudo_path: str = ''¶
- python_cmd: str = 'python3'¶
- ssh_delete_remote_after_sync: bool = False¶
- ssh_host: str = ''¶
- ssh_identity_file: str = ''¶
- ssh_remote_work_dir: str = '~/simudo_runs'¶
- ssh_simudo_path: str = ''¶
- ssh_user: str = ''¶
- type: str = 'docker'¶
- class simudo.gui.model.ExplicitIntensity(value: 'float' = 100.0, unit: 'str' = 'mW/cm^2', input_type: 'str' = 'power_density')[source]¶
Bases:
object- input_type: str = 'power_density'¶
- unit: str = 'mW/cm^2'¶
- value: float = 100.0¶
- class simudo.gui.model.IntensityRampSettings(enabled: 'bool' = True, selfconsistent_optics: 'bool' = True, step_size: 'Optional[float]' = None)[source]¶
Bases:
object- enabled: bool = True¶
- selfconsistent_optics: bool = True¶
- step_size: float | None = None¶
- class simudo.gui.model.Interface(left: str = '', right: str = '', bcs: ~typing.List[~simudo.gui.model.InterfaceBCSpec] = <factory>)[source]¶
Bases:
objectInternal interface between two adjacent layers.
left and right are layer names (Python identifiers) matching the Simudo region attribute names: facet = R.<left>.boundary(R.<right>).
- bcs: List[InterfaceBCSpec]¶
- left: str = ''¶
- right: str = ''¶
- class simudo.gui.model.InterfaceBCSpec(type: str = 'ThermionicHeterojunction', bands: ~typing.List[str] = <factory>, HJBC_enhancement: ~typing.Dict[str, float] = <factory>)[source]¶
Bases:
objectOne BC type applied at an internal interface.
- HJBC_enhancement: Dict[str, float]¶
- bands: List[str]¶
- type: str = 'ThermionicHeterojunction'¶
- class simudo.gui.model.Layer(name: 'str' = 'layer', thickness: 'float' = 1.0, thickness_unit: 'str' = 'um', material: 'str' = '', properties: 'Dict[str, Any]' = <factory>, mesh: 'MeshParams' = <factory>, color: 'str' = '#4a9eff')[source]¶
Bases:
object- color: str = '#4a9eff'¶
- material: str = ''¶
- mesh: MeshParams¶
- name: str = 'layer'¶
- properties: Dict[str, Any]¶
- thickness: float = 1.0¶
- thickness_unit: str = 'um'¶
- class simudo.gui.model.Material(name: 'str' = 'material', source: 'Optional[str]' = None, properties: 'Dict[str, Any]' = <factory>)[source]¶
Bases:
object- name: str = 'material'¶
- properties: Dict[str, Any]¶
- source: str | None = None¶
- class simudo.gui.model.MeshParams(start: 'Optional[float]' = None, factor: 'Optional[float]' = None)[source]¶
Bases:
object- factor: float | None = None¶
- start: float | None = None¶
- class simudo.gui.model.OpticalField(name: 'str' = 'field', direction: 'str' = '+x', photon_energy: 'float' = 1.42, photon_energy_unit: 'str' = 'eV', intensity: 'Any' = <factory>)[source]¶
Bases:
object- direction: str = '+x'¶
- intensity: Any¶
- name: str = 'field'¶
- photon_energy: float = 1.42¶
- photon_energy_unit: str = 'eV'¶
- class simudo.gui.model.OpticalFieldSet(name_prefix: str = 'sun', direction: str = '+x', spectrum: str = 'am15g', N_bins: int = 5, E_min: float = 0.8, E_min_unit: str = 'eV', E_max: float = 4.0, E_max_unit: str = 'eV', concentration: float = 1.0, T_source: float = 6000.0, T_source_unit: str = 'K', bin_edges: str = 'equal_flux')[source]¶
Bases:
objectA set of N optical fields generated from a spectrum.
Persisted to / from the YAML
optical_field_sets:block; the runner expands it into N monochromatic fields at simulation time (item 7).- E_max: float = 4.0¶
- E_max_unit: str = 'eV'¶
- E_min: float = 0.8¶
- E_min_unit: str = 'eV'¶
- N_bins: int = 5¶
- T_source: float = 6000.0¶
- T_source_unit: str = 'K'¶
- bin_edges: str = 'equal_flux'¶
- concentration: float = 1.0¶
- direction: str = '+x'¶
- name_prefix: str = 'sun'¶
- spectrum: str = 'am15g'¶
- class simudo.gui.model.OutputSettings(xdmf_mesh: 'bool' = True, spatial_profiles: 'bool' = False)[source]¶
Bases:
object- spatial_profiles: bool = False¶
- xdmf_mesh: bool = True¶
- class simudo.gui.model.OverlayRegion(name: 'str' = 'overlay', start: 'Optional[float]' = None, end: 'Optional[float]' = None, extent_unit: 'str' = 'um', layer_names: 'List[str]' = <factory>, properties: 'Dict[str, Any]' = <factory>, is_domain: 'bool' = False)[source]¶
Bases:
object- end: float | None = None¶
- extent_unit: str = 'um'¶
- is_domain: bool = False¶
- layer_names: List[str]¶
- name: str = 'overlay'¶
- properties: Dict[str, Any]¶
- start: float | None = None¶
- class simudo.gui.model.PhysicsSettings(temperature: 'float' = 300.0, temperature_unit: 'str' = 'K')[source]¶
Bases:
object- temperature: float = 300.0¶
- temperature_unit: str = 'K'¶
- class simudo.gui.model.Process(name: 'str' = '', cls: 'str' = 'SRHRecombination', src_band: 'str' = 'VB', dst_band: 'str' = 'CB', trap_band: 'Optional[str]' = None, radiative_recombination: 'Optional[bool]' = None, svr_E_min: 'Optional[float]' = None, svr_E_min_unit: 'str' = 'eV', svr_E_max: 'Optional[float]' = None, svr_E_max_unit: 'str' = 'eV', callable_top_hats: 'Dict[str, List[CallableTopHat]]' = <factory>)[source]¶
Bases:
object- callable_top_hats: Dict[str, List[CallableTopHat]]¶
- cls: str = 'SRHRecombination'¶
- dst_band: str = 'CB'¶
- name: str = ''¶
- radiative_recombination: bool | None = None¶
- src_band: str = 'VB'¶
- svr_E_max: float | None = None¶
- svr_E_max_unit: str = 'eV'¶
- svr_E_min: float | None = None¶
- svr_E_min_unit: str = 'eV'¶
- trap_band: str | None = None¶
- class simudo.gui.model.Project(filepath: 'Optional[str]' = None, description: 'str' = '', layers: 'List[Layer]' = <factory>, overlay_regions: 'List[OverlayRegion]' = <factory>, bands: 'List[Band]' = <factory>, processes: 'List[Process]' = <factory>, optical_fields: 'List[OpticalField]' = <factory>, optical_field_sets: 'List[OpticalFieldSet]' = <factory>, contacts: 'Dict[str, Contact]' = <factory>, physics: 'PhysicsSettings' = <factory>, simulation: 'SimulationSettings' = <factory>, custom_eop_files: 'List[str]' = <factory>, output_folder: 'str' = <factory>, mesh_max_edge_length: 'float' = 0.02, mesh_dimension: 'int' = 1, materials: 'List[Material]' = <factory>, interfaces: 'List[Interface]' = <factory>, execution: 'Optional[ExecutionProfile]' = None)[source]¶
Bases:
object- property band_names: List[str]¶
- custom_eop_files: List[str]¶
- description: str = ''¶
- execution: ExecutionProfile | None = None¶
- filepath: str | None = None¶
- property layer_names: List[str]¶
- mesh_dimension: int = 1¶
- mesh_max_edge_length: float = 0.02¶
- optical_field_sets: List[OpticalFieldSet]¶
- optical_fields: List[OpticalField]¶
- output_folder: str¶
- overlay_regions: List[OverlayRegion]¶
- physics: PhysicsSettings¶
- simulation: SimulationSettings¶
- class simudo.gui.model.SimulationSettings(intensity_ramp: 'IntensityRampSettings' = <factory>, voltage_sweep: 'VoltageSweepSettings' = <factory>, output: 'OutputSettings' = <factory>, checkpoints: 'CheckpointsSettings' = <factory>, resume_from: 'Optional[str]' = None)[source]¶
Bases:
object- checkpoints: CheckpointsSettings¶
- intensity_ramp: IntensityRampSettings¶
- output: OutputSettings¶
- resume_from: str | None = None¶
- voltage_sweep: VoltageSweepSettings¶
- class simudo.gui.model.ValueUnit(value: 'float' = 0.0, unit: 'str' = '')[source]¶
Bases:
object- unit: str = ''¶
- value: float = 0.0¶
- class simudo.gui.model.VoltageSweepSettings(enabled: 'bool' = True, values: 'List[float]' = <factory>, selfconsistent_optics: 'bool' = True, step_size: 'Optional[float]' = None)[source]¶
Bases:
object- enabled: bool = True¶
- selfconsistent_optics: bool = True¶
- step_size: float | None = None¶
- values: List[float]¶
- simudo.gui.model.default_bands() List[Band][source]¶
Standard two-band semiconductor starting point.
- simudo.gui.model.make_domain_overlay() OverlayRegion[source]¶
simudo.gui.runner_backends module¶
Runner backend abstraction.
Each backend knows how to launch simudo_1d_runner.py in a particular execution environment (local subprocess, Docker, SSH, SSH+Docker) and stream its stdout back as a line iterator.
Adding a new backend only requires subclassing RunnerBackend and implementing launch(). The Simulation panel is backend-agnostic.
- class simudo.gui.runner_backends.DockerBackend(container: str, host_root: str, container_root: str, python_cmd: str = 'python3', container_simudo_path: str = '')[source]¶
Bases:
RunnerBackendRun the runner inside a local Docker container via
docker exec.A bind-mount must exist mapping
host_rooton the host tocontainer_rootinside the container. All host paths underhost_rootare translated to the equivalent container path automatically.Works on macOS, Linux, and Windows (with Docker Desktop). On Windows the host_root may be given as a Windows path (
C:\Users\...) or with forward slashes (C:/Users/...); both are normalised correctly. On Cygwin, use the native Cygwin path format (/cygdrive/c/...).Example
host_root = “/Users/you/Simudo” # Mac/Linux host_root = “C:/Users/you/Simudo” # Windows / Cygwin container_root = “/home/user/simudo” container = “container_name” python_cmd = “python3”
- get_core_count() int[source]¶
Return the number of available CPU cores in the execution environment.
- launch(runner_host_path, project_yaml_host_path, lib_dirs_host, extra_args) DockerRunHandle[source]¶
- launch_extractor(extractor_host_path, output_dir_host_path, extra_args=(), local_proj_dir=None) ExtractorHandle[source]¶
- class simudo.gui.runner_backends.DockerRunHandle(proc, cmd_str, host_root: str, container_root: str)[source]¶
Bases:
RunHandleRunHandle that translates Docker container paths back to host paths.
- class simudo.gui.runner_backends.ExtractorHandle(proc: Popen, cmd_str: str)[source]¶
Bases:
objectRunHandle variant for spatial_extractor: separate stdout and stderr.
- property returncode: int | None¶
- class simudo.gui.runner_backends.LocalBackend[source]¶
Bases:
RunnerBackendRun the runner directly as a subprocess using the current Python interpreter.
- get_core_count() int[source]¶
Return the number of available CPU cores in the execution environment.
- launch_extractor(extractor_host_path, output_dir_host_path, extra_args=(), local_proj_dir=None) ExtractorHandle[source]¶
- class simudo.gui.runner_backends.RunHandle(proc: Popen, cmd_str: str)[source]¶
Bases:
objectWraps an active subprocess. Subclasses override path-translation and post-run hooks for environment-specific behaviour (Docker, SSH, etc.).
- do_intermediate_sync() Iterator[str][source]¶
Perform one intermediate sync and yield log-line strings. Default: no-op (local and Docker runs need no file transfer).
- finalize_msgs() Iterator[str][source]¶
Post-run actions. Yields log-lines while executing (e.g. rsync). Default: nothing to do.
- initial_msgs() Iterator[str][source]¶
Messages to emit before stdout streaming starts (e.g. announce paths). Default: nothing.
- periodic_sync_interval: int = 0¶
Seconds between automatic intermediate syncs while the run is active. 0 means no periodic sync (default for local and Docker runs).
- property returncode: int | None¶
- class simudo.gui.runner_backends.RunnerBackend[source]¶
Bases:
objectAbstract base — subclasses implement launch().
- get_core_count() int[source]¶
Return the number of available CPU cores in the execution environment.
- launch(runner_host_path: str, project_yaml_host_path: str, lib_dirs_host: List[str], extra_args: List[str]) RunHandle[source]¶
- launch_extractor(extractor_host_path: str, output_dir_host_path: str, extra_args: List[str] = (), local_proj_dir: str | None = None) ExtractorHandle[source]¶
- class simudo.gui.runner_backends.SSHBackend(host: str, user: str = '', identity_file: str | None = None, remote_work_dir: str = '~/simudo_runs', python_cmd: str = 'python3', simudo_path: str = '', delete_remote: bool = False)[source]¶
Bases:
RunnerBackendRun the runner on a remote Linux machine via SSH.
- Launch workflow:
Create a unique run directory on the remote under remote_work_dir.
rsync the project YAML to that directory.
For each library dir: if it lives under the local simudo tree, translate to the corresponding remote path; otherwise rsync it to a .lib_cache sub-directory inside the run directory.
Launch: ssh <host> <python_cmd> -u <runner_path> <remote_yaml> [flags]
Stream stdout/stderr back in real time.
After the process exits (finalize_msgs): rsync the whole remote run directory back to local_proj_dir so output files appear locally.
- SSH authentication:
Preferred: configure the host in ~/.ssh/config (handles auth, port, etc.). Set ssh_host to the config alias; leave ssh_user and ssh_identity_file blank.
Alternative: set ssh_host to hostname/IP, ssh_user to your username, and optionally ssh_identity_file to a private key path.
Password authentication is not supported; set up key-based auth first.
- Remote runner discovery:
- Set ssh_simudo_path to the output of:
python3 -c “import simudo; print(simudo.__file__)”
- run on the remote machine. The runner path is derived as:
<simudo_pkg_parent>/gui/simudo_1d_runner.py
- get_core_count() int[source]¶
Return the number of available CPU cores in the execution environment.
- launch(runner_host_path: str, project_yaml_host_path: str, lib_dirs_host: List[str], extra_args: List[str]) SSHRunHandle[source]¶
- launch_extractor(extractor_host_path: str, output_dir_host_path: str, extra_args=(), local_proj_dir: str | None = None) SSHExtractorHandle[source]¶
Run the extractor on the remote host.
Always rsyncs the local output directory to a temporary directory on the remote before running the extractor, so the files are guaranteed to be present regardless of whether delete_remote was set or whether the run was done with a different backend. The temp directory is removed automatically when stdout_lines() drains.
- class simudo.gui.runner_backends.SSHDockerBackend[source]¶
Bases:
RunnerBackendSSH to a remote host, then docker exec inside a container there. Not yet implemented.
- launch_extractor(extractor_host_path, output_dir_host_path, extra_args=()) ExtractorHandle[source]¶
- class simudo.gui.runner_backends.SSHExtractorHandle(proc, cmd_str, cleanup_ssh_cmd: List[str])[source]¶
Bases:
ExtractorHandleExtractorHandle that removes the remote temp directory after extraction.
- class simudo.gui.runner_backends.SSHRunHandle(proc: Popen, cmd_str: str, host_spec: str, rsync_ssh_opts: List[str], remote_out_dir: str, local_out_dir: str, staging_dir: str, delete_remote: bool = False)[source]¶
Bases:
RunHandleRunHandle for SSH execution.
Tracks the negotiated remote and local output directories separately. Path translation maps remote_out_dir → local_out_dir. Post-run: rsyncs remote_out_dir back to local_out_dir, removes the hidden staging directory, and optionally deletes the remote output copy.
Periodic sync:
do_intermediate_sync()rsyncs the remote output directory to the local one without any cleanup, so partially-written output files (sim_V.csv, info.log, …) appear locally while the run is still active.periodic_sync_intervalis set to 120 s.- do_intermediate_sync() Iterator[str][source]¶
Rsync remote output dir → local output dir without any cleanup. Called periodically while the run is active.
- finalize_msgs() Iterator[str][source]¶
Post-run actions. Yields log-lines while executing (e.g. rsync). Default: nothing to do.
- initial_msgs() Iterator[str][source]¶
Messages to emit before stdout streaming starts (e.g. announce paths). Default: nothing.
- periodic_sync_interval: int = 120¶
Seconds between automatic intermediate syncs while the run is active. 0 means no periodic sync (default for local and Docker runs).
- simudo.gui.runner_backends.backend_from_profile(profile) RunnerBackend[source]¶
Build the appropriate RunnerBackend from an ExecutionProfile dataclass.
simudo.gui.simudo_1d_runner module¶
simudo_1d_runner.py¶
Generic runner that reads a Simudo project YAML file and executes a 1D layered-structure Poisson / drift-diffusion simulation.
Usage (inside the Docker container or environment with Simudo installed):
cd ~/simudo/code
python gui/simudo_1d_runner.py gui/fourlayer_example.yaml
The project YAML format is documented and exemplified in
gui/fourlayer_example.yaml.
The execution: section of the project YAML is consumed by the GUI
launcher layer (which decides whether to run locally, via docker exec,
or over SSH). This script always runs locally inside the target
environment and never reads the execution: key.
Design notes¶
Priority levels for spatial rules (lower number = higher priority; wins
via setdefault in get()):
PRIORITY_OVERLAY = 0 named overlay-region properties — highest priority
PRIORITY_LAYER = 5 layer-specific properties
PRIORITY_DOMAIN = 7 the `domain` overlay — a device-wide default
PRIORITY_MATERIAL = 10 material default properties — lowest priority
domain is deliberately below layers. It is how a user says “unless I say otherwise, this holds everywhere”, so a value set on a single layer has to be able to beat it; before this it shared PRIORITY_OVERLAY with named overlays and was registered first, which made every layer-level override silently inert.
Material properties are registered by calling
spatial.add_material_data directly with priority=PRIORITY_MATERIAL,
so that layer / overlay rules always beat material defaults regardless of
registration order.
Bidirectional voltage sweeps¶
Simudo’s Newton solver ramps the parameter (I or V) slowly from a known
solution. Thermal equilibrium gives the solution at I = V = 0. A
unidirectional sweep from 0 → +Voc is straightforward. voltage_sweep.values
is split around an initial_v – 0 for a fresh run, or the resumed checkpoint’s
own value (see below) – into an “up” group (values above initial_v) and a
“down” group (values below initial_v), each run against its own problem
instance sharing one seed state, so the (possibly expensive) state that
produced that initial_v point is only computed once.
Checkpoint resumption¶
simulation.resume_from (a checkpoint .yaml path relative to the
output folder) resumes a previous run instead of starting fresh. The stage
the checkpoint belongs to is inferred from its filename (..._V=<v>.yaml
or ..._I=<i>.yaml, written by
write_xdmf_checkpoint()):
An optical-ramp (
I) checkpoint continues the intensity ramp from that intensity (or, if it is already at I=1, is used directly) and then runs the voltage sweep(s) normally (initial_v = 0) from the resulting V=0 state — this is how a run can branch into a fresh voltage sweep without recomputing the optical ramp.A voltage checkpoint (
Vof either sign) resumes with initial_v = that checkpoint’s own value, and sweeps both directions from it as needed – e.g. resuming from V=0.4 with targets[0.3, 0.4, 0.5]computes both 0.3 and 0.5, each from its own copy of the loaded V=0.4 state. The optical ramp is skipped either way (the checkpoint already reflects its outcome).
Either way, any requested value already present in this output folder’s
sim_V.csv / sim_I.csv (from the run that produced the checkpoint) is
dropped rather than recomputed – see _already_computed_values().
See _parse_checkpoint_stage() and the “Stage 1/2/3” comments in
run() for the exact logic. Resuming still requires the project
YAML to describe an identically-constructed problem (same layers, bands,
processes, mesh) — the checkpoint only restores solution values, not the
problem structure.
- simudo.gui.simudo_1d_runner.DEFAULT_MESH_DIMENSION = 1¶
Default mesh dimension for the runner. 1 = true-1D interval mesh (new route, about half the degrees of freedom); 2 = the historical 2D strip (one cell layer of triangles between y=0 and y=1). Override with
mesh: {dimension: 2}in the project YAML, e.g. to compare the two.
- simudo.gui.simudo_1d_runner.DEFAULT_TEMPERATURE_K = 300.0¶
Temperature assumed when a project names none anywhere. Every material reads it during get_dict(), and an unset spatial key resolves to zero, so without a default a project that forgets it is solved at 0 K – which does not converge, and says nothing useful about why.
- class simudo.gui.simudo_1d_runner.ProblemBuilder(config, library_dir=None, setup_dolfin=True)[source]¶
Bases:
objectEverything a project config needs before solving: units, mesh, topology.
_create_problemdatatakes(config, R, F, U, mesh_data, ..., dark_mode=...)on every call, andrun()builds up to four problems from the same five objects. This class owns that bundle so it is constructed once, and so callers other thanrun()– notably the test suite – can build a problem without running a simulation.Constructing a builder has no side effects outside dolfin’s global parameters: it creates no directories, writes no files, configures no logging, and solves nothing.
- Parameters:
config (dict) – Parsed project YAML.
library_dir (str, Path, or list, optional) – Passed through to
library://material resolution.setup_dolfin (bool, optional) – Call
setup_dolfin_parameters(). On by default; passFalsewhen the caller has already configured dolfin.
Examples
Check that a configuration assembles, without solving it:
builder = ProblemBuilder(config, library_dir=materials) problem = builder.problem('full')
- simudo.gui.simudo_1d_runner.build_problems(config, library_dir=None, goals=('full',), V_ext=None)[source]¶
Build the problems named in goals without solving any of them.
Returns
(builder, {goal: problem}).This is the entry point for tests that need to know whether a configuration assembles – which is where a large class of runner bugs lives.
ThermionicHeterojunctionwas registered on every goal for months, and raisedAttributeErroron the'local charge neutrality'problem long before any solve; a construction-only check would have caught it in about a second.'thermal equilibrium'needs aphi_cnfrom the local-charge-neutrality problem. That is a dolfinFunctionwhich exists whether or not it has been solved for, so the dependency is satisfied here by building the LCN problem and handing over its (unsolved)phi. The resulting equilibrium problem is therefore well-formed but not physically meaningful – which is all a construction test needs.
- simudo.gui.simudo_1d_runner.ensure_new_dir(cur_dir)[source]¶
Return cur_dir (or an incremented variant) that does not yet exist.
- simudo.gui.simudo_1d_runner.parse_quantity(entry, U)[source]¶
Parse a YAML property value into a pint Quantity.
Accepted forms:
{value: X, unit: "cm^2"}— returnsX * U(unit)a bare scalar (int or float) — returned as-is (dimensionless)
True/False— returned as-is (Python bool)
Extra keys (such as
mode) are silently ignored, so a full intensity dict can be passed directly.
- simudo.gui.simudo_1d_runner.parse_spatial_quantity(entry, U)[source]¶
Like parse_quantity but wraps numeric magnitudes in dolfin.Constant.
Use for quantities going into spatial.add_rule / spatial.add_material_data. dolfin.Constant avoids FEniCS form recompilation when the value changes between runs.
- simudo.gui.simudo_1d_runner.run(yaml_path, library_dir=None, new_experiment=True)[source]¶
Read the project YAML at yaml_path and execute the simulation.
- Parameters:
yaml_path (str or Path) – Path to the project YAML file.
library_dir (str, Path, or list, optional) – Directory (or list of directories) containing Python Material subclasses for
library://material sources.new_experiment (bool, optional) – When
True(default), the output directory is checked for existence and incremented if necessary (ensure_new_dir), so that each new run gets its own folder. Set toFalsewhen continuing from a checkpoint so that output lands back in the same folder as the original run.
simudo.gui.spatial_extractor module¶
Spatial data extractor for Simudo output.
Runs inside the execution environment (Docker container or local) where
simudo and dolfin are installed. Delegates all XDMF reading and function
evaluation to simudo.example.fourlayer.sweep_extraction.SpatialXdmf.
- Usage:
python3 spatial_extractor.py <output_dir> [–n-points N]
- stdout protocol (one block per sweep point):
# BEGIN_POINT V=<v> I=<i> coord_x,field1,field2,… val,val,val,… … # END_POINT V=<v> I=<i>
V= files use I=0; I= files use V=0. Dolfin log messages and warnings go to stderr only.
simudo.gui.yaml_io module¶
Simudo GUI — YAML serialization / deserialization.
Converts between the Project data model and the YAML format consumed by simudo_1d_runner.py.
Module contents¶
Panel-based graphical interface for setting up and running Simudo problems.
Intentionally empty of imports: the GUI modules depend on panel/bokeh,
which are not required to use the rest of Simudo. Import the submodules
directly (e.g. simudo.gui.app) if you need them.