diff --git a/net_maestro/core/migrations/0011_alter_pholdsimulationconfig_lookahead.py b/net_maestro/core/migrations/0011_alter_pholdsimulationconfig_lookahead.py new file mode 100644 index 0000000..85ae55f --- /dev/null +++ b/net_maestro/core/migrations/0011_alter_pholdsimulationconfig_lookahead.py @@ -0,0 +1,25 @@ +# Generated by Django 6.0.6 on 2026-07-14 22:48 +from __future__ import annotations + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0010_alter_run_status_pholdsimulationconfig"), + ] + + operations = [ + migrations.AlterField( + model_name="pholdsimulationconfig", + name="lookahead", + field=models.FloatField( + default=1.0, + validators=[ + django.core.validators.MinValueValidator(0.1), + django.core.validators.MaxValueValidator(1.0), + ], + ), + ), + ] diff --git a/net_maestro/core/models/phold_simulation_config.py b/net_maestro/core/models/phold_simulation_config.py index c4af989..303ba4e 100644 --- a/net_maestro/core/models/phold_simulation_config.py +++ b/net_maestro/core/models/phold_simulation_config.py @@ -1,5 +1,6 @@ from __future__ import annotations +from django.core.exceptions import ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models @@ -41,7 +42,10 @@ class PHOLDSimulationConfig(models.Model): mult = models.FloatField( default=1.4, validators=[MinValueValidator(1.0)], verbose_name="Memory multiplier" ) - lookahead = models.FloatField(default=1.0, validators=[MinValueValidator(0.1)]) + # ROSS's PHOLD model hard-errors if lookahead exceeds 1.0 + lookahead = models.FloatField( + default=1.0, validators=[MinValueValidator(0.1), MaxValueValidator(1.0)] + ) start_events = models.IntegerField( default=1, validators=[MinValueValidator(1)], verbose_name="Start events per LP" ) @@ -52,3 +56,10 @@ class PHOLDSimulationConfig(models.Model): def __str__(self) -> str: return f"PHOLD config for Run {self.run_id}" + + def clean(self) -> None: + super().clean() + # PHOLD subtracts lookahead from mean before using it as the exponential distribution's + # rate parameter. A non-positive result produces invalid event timestamp offsets. + if self.mean is not None and self.lookahead is not None and self.mean <= self.lookahead: + raise ValidationError({"mean": "Mean timestamp must be greater than lookahead."}) diff --git a/net_maestro/core/templates/net_maestro/partials/new_simulation.html b/net_maestro/core/templates/net_maestro/partials/new_simulation.html index d685425..f45e985 100644 --- a/net_maestro/core/templates/net_maestro/partials/new_simulation.html +++ b/net_maestro/core/templates/net_maestro/partials/new_simulation.html @@ -57,6 +57,15 @@