From 7fcc8098521916b05cc867ddd282eadf75690044 Mon Sep 17 00:00:00 2001 From: Dominik Roth Date: Thu, 12 Mar 2026 17:16:25 +0100 Subject: [PATCH] Update README: valve API, cheat_mode, model learning overhaul Co-Authored-By: Claude Sonnet 4.6 --- README.md | 91 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index ac7d5d6..000b65a 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,10 @@ Parameter properties: - `nucon..value`: Get or set the current value of the parameter. Assigning a new value will write it to the game. - `nucon..param_type`: Get the type of the parameter - `nucon..is_writable`: Check if the parameter is writable +- `nucon..is_readable`: `False` for write-only parameters (e.g. VALVE_OPEN, CORE_SCRAM_BUTTON). Reading raises `AttributeError`. +- `nucon..is_cheat`: `True` for game-event triggers (all `FUN_*`). Writing raises `ValueError` unless `cheat_mode=True`. - `nucon..enum_type`: Get the enum type of the parameter if it's an enum, otherwise None +- `nucon..unit`: Unit string if defined (e.g. `'°C'`, `'bar'`, `'%'`) Parameter methods: - `nucon..read()`: Get the current value of the parameter (alias for `value`) @@ -80,14 +83,23 @@ Parameter methods: Class methods: - `nucon.get(parameter)`: Get the value of a specific parameter. Also accepts string parameter names. -- `nucon.set(parameter, value, force=False)`: Set the value of a specific parameter. Also accepts string parameter names. `force` will try to write even if the parameter is known as non-writable or out of known allowed range. -- `nucon.get_all_readable()`: Get a list of all readable parameters (which is all parameters) -- `nucon.get_all_writable()`: Get a list of all writable parameters -- `nucon.get_all()`: Get all parameter values as a dictionary -- `nucon.get_all_iter()`: Get all parameter values as a generator -- `nucon.get_multiple(params)`: Get values for multiple specified parameters -- `nucon.get_multiple_iter(params)`: Get values for multiple specified parameters as a generator -- `nucon.set_dummy_mode(dummy_mode)`: Enable or disable dummy mode for testing. In dummy mode we won't connect to the game and just return sensible values for all params and allow but ignore all writes to writable parameters. +- `nucon.set(parameter, value, force=False)`: Set the value of a specific parameter. Also accepts string parameter names. `force` bypasses writable/range/cheat checks. +- `nucon.get_all_readable()`: Get a dict of all readable parameters. +- `nucon.get_all_writable()`: Get a dict of all writable parameters (includes write-only params). +- `nucon.get_all()`: Get all readable parameter values as a dictionary. +- `nucon.get_all_iter()`: Get all readable parameter values as a generator. +- `nucon.get_multiple(params)`: Get values for multiple specified parameters. +- `nucon.get_multiple_iter(params)`: Get values for multiple specified parameters as a generator. +- `nucon.get_game_variable_names()`: Query the game for all exposed variable names (GET and POST), excluding special endpoints. +- `nucon.set_dummy_mode(dummy_mode)`: In dummy mode, returns sensible values without connecting to the game and silently ignores writes. +- `nucon.set_cheat_mode(cheat_mode)`: Enable writing to cheat parameters (`FUN_*` event triggers). Default `False`. + +Valve API (motorized actuators: OPEN/CLOSE powers the motor, OFF holds current position): +- `nucon.get_valve(name)`: Get state dict for a single valve (`Value`, `IsOpened`, `IsClosed`, `Stuck`, …). +- `nucon.get_valves()`: Get state dict for all 53 valves. +- `nucon.open_valve(name)` / `nucon.open_valves(names)`: Power actuator toward open. +- `nucon.close_valve(name)` / `nucon.close_valves(names)`: Power actuator toward closed. +- `nucon.off_valve(name)` / `nucon.off_valves(names)`: Cut actuator power, hold current position (normal resting state). Custom Enum Types: - `PumpStatus`: Enum for pump status (INACTIVE, ACTIVE_NO_SPEED_REACHED\*, ACTIVE_SPEED_REACHED\*, REQUIRES_MAINTENANCE, NOT_INSTALLED, INSUFFICIENT_ENERGY) @@ -234,41 +246,62 @@ But theres yet another problem: We do not know the exact simulation dynamics of ## Model Learning (Work in Progress) -To address the challenge of unknown game dynamics, NuCon provides tools for collecting data, creating datasets, and training models to learn the reactor dynamics. This approach allows for more accurate simulations and enables model-based control strategies. Key features include: +To address the challenge of unknown game dynamics, NuCon provides tools for collecting data, creating datasets, and training models to learn the reactor dynamics. Key features include: -- Data Collection: Supports gathering state transitions from both human play and automated agents. -- Dataset Management: Tools for saving, loading, and merging datasets. -- Model Training: Train neural network models to predict next states based on current states and time deltas. -- Dataset Refinement: Ability to refine datasets by focusing on more challenging or interesting data points. +- **Data Collection**: Gathers state transitions from human play or automated agents. `time_delta` is specified in game-time seconds; wall-clock sleep is automatically adjusted for `GAME_SIM_SPEED` so collected deltas are uniform regardless of simulation speed. +- **Automatic param filtering**: Junk params (GAME_VERSION, TIME, ALARMS_ACTIVE, …) and params from uninstalled subsystems (returns `None`) are automatically excluded from model inputs/outputs. +- **Two model backends**: Neural network (NN) or k-Nearest Neighbours with GP interpolation (kNN). +- **Uncertainty estimation**: The kNN backend returns a GP posterior standard deviation alongside each prediction — 0 means the query lies on known data, ~1 means it is out of distribution. +- **Dataset management**: Tools for saving, loading, merging, and pruning datasets. ### Additional Dependencies -To use you'll need to install `torch` and `numpy`. You can do so via - ```bash pip install -e '.[model]' ``` -### Usage: +### Usage ```python from nucon.model import NuconModelLearner -# Initialize the model learner -learner = NuconModelLearner() - -# Collect data by querying the game +# --- Data collection --- +learner = NuconModelLearner( + time_delta=10.0, # 10 game-seconds per step (wall sleep auto-scales with sim speed) + include_valve_states=False, # set True to include all 53 valve positions as model inputs +) learner.collect_data(num_steps=1000) - -# Train the model -learner.train_model(batch_size=32, num_epochs=10) - -# Refine the dataset -learner.refine_dataset(error_threshold=0.1) - -# Save the model and dataset -learner.save_model('reactor_model.pth') learner.save_dataset('reactor_dataset.pkl') + +# Merge datasets collected across multiple sessions +learner.merge_datasets('other_session.pkl') + +# --- Neural network backend --- +nn_learner = NuconModelLearner(model_type='nn', dataset_path='reactor_dataset.pkl') +nn_learner.train_model(batch_size=32, num_epochs=50) +# Drop samples the NN already predicts well (keep hard cases for further training) +nn_learner.drop_well_fitted(error_threshold=1.0) +nn_learner.save_model('reactor_nn.pth') + +# --- kNN + GP backend --- +knn_learner = NuconModelLearner(model_type='knn', knn_k=10, dataset_path='reactor_dataset.pkl') +# Drop near-duplicate samples before fitting (keeps diverse coverage). +# A sample is dropped only if BOTH its input state AND output transition +# are within the given distances of an already-kept sample. +knn_learner.drop_redundant(min_state_distance=0.1, min_output_distance=0.05) +knn_learner.fit_knn() + +# Point prediction +state = knn_learner._get_state() +pred = knn_learner.model.forward(state, time_delta=10.0) + +# Prediction with uncertainty +pred, uncertainty = knn_learner.predict_with_uncertainty(state, time_delta=10.0) +print(f"CORE_TEMP: {pred['CORE_TEMP']:.1f} ± {uncertainty:.3f} (std, GP posterior)") +# uncertainty ≈ 0: confident (query near known data) +# uncertainty ≈ 1: out of distribution + +knn_learner.save_model('reactor_knn.pkl') ``` The trained models can be integrated into the NuconSimulator to provide accurate dynamics based on real game data.