Catchment Simulation App

Submodules

views module

Views and helper functions for the main Django application.

class main.views.BodySizeLimitUploadHandler(request: HttpRequest, max_bytes: int)[source]

Bases: FileUploadHandler

Abort multipart parsing when streamed request body exceeds configured limit.

file_complete(file_size: int) None[source]

Signal that a file has completed. File size corresponds to the actual size accumulated by all the chunks.

Subclasses should return a valid UploadedFile object.

receive_data_chunk(raw_data: bytes, start: int) bytes[source]

Receive data from the streamed upload parser. start is the position in the file of the chunk.

exception main.views.InputValidationError[source]

Bases: ValueError

Raised for user-correctable input issues.

exception main.views.ResultPayloadTooLargeError[source]

Bases: ValueError

Raised when serialized result payload exceeds configured cache limit.

main.views.about(request: HttpRequest) HttpResponse[source]
main.views.ajax_login_required(view_func)[source]

Like @login_required but returns 401 JSON for AJAX requests.

main.views.calculations(request: HttpRequest) HttpResponse[source]

Run SWMM + ANN prediction and compare runoff volumes per subcatchment.

main.views.clear_session_variables(request: HttpRequest) None[source]

Purge all cached results and form state from the session.

main.views.contact(request: HttpRequest) HttpResponse[source]
main.views.download_simulation_results(request: HttpRequest) HttpResponse[source]

Download simulation results as an Excel file generated in memory.

main.views.download_timeseries_csv(request: HttpRequest) HttpResponse[source]

Download timeseries analysis results as CSV.

main.views.download_timeseries_results(request: HttpRequest) HttpResponse[source]

Download timeseries analysis results as an in-memory Excel file.

main.views.get_feature_name(method_name: str) str[source]

Map simulation method name (e.g. simulate_area) to INP column name.

main.views.get_session_variables(request: HttpRequest) dict[source]

Load simulation result context from cache for template rendering.

main.views.main_view(request: HttpRequest) HttpResponse[source]

Landing page with static slope/area/width charts.

main.views.simulation_view(request: HttpRequest) HttpResponse[source]

Run a subcatchment feature simulation and display results with charts.

main.views.subcatchments(request: HttpRequest) JsonResponse[source]

AJAX endpoint returning subcatchment IDs from the uploaded INP.

main.views.timeseries_view(request: HttpRequest) HttpResponse[source]

Timeseries analysis: single run with metrics or parameter sweep with overlaid hydrographs.

main.views.upload(request: HttpRequest) JsonResponse[source]

Accept a user-uploaded .inp file (via Dropzone.js) after size and content validation.

main.views.upload_clear(request: HttpRequest) JsonResponse[source]

Remove uploaded file from disk and clear related session state.

main.views.upload_sample(request: HttpRequest) JsonResponse[source]

Load bundled sample INP file into the current user session.

main.views.upload_status(request: HttpRequest) JsonResponse[source]

Return {has_file, filename, size} for the current session upload.

main.views.user_profile(request: HttpRequest, user_id: int) HttpResponse[source]

Display user profile; owners can edit, others get read-only view.

urls module

This module defines the URL patterns for the main app, including the main view, user profile, contact form, about page, simulation view, timeseries view, and file upload and download.

Django uses the urlpatterns list to match the requested URL with the corresponding view function.

predictor module

This module contains functions to predict runoff using a machine learning model.

The model weights are loaded from the ‘swmm_model’ directory. The predict_runoff function takes a SWMM model object as input and returns an array of predicted runoff values for each subcatchment.

This is a pure NumPy implementation - no TensorFlow/Keras required.

class main.predictor.SimpleMLPModel(weights_path: str)[source]

Bases: object

A simple MLP model for inference using pure NumPy.

Architecture:

Input (8) -> Normalization -> Dense(8, ReLU) -> Dense(8, ReLU) -> Dense(1, ReLU)

predict(x: ndarray) ndarray[source]

Run inference on input data.

Parameters

xnp.ndarray

Input array of shape (batch_size, 8).

Returns

np.ndarray

Predictions of shape (batch_size, 1).

main.predictor.predict_runoff(swmmio_model: Model) ndarray[source]

Predict runoff using a machine learning model.

Parameters

swmmio_modelswmmio.Model

A SWMM model object with subcatchment data.

Returns

np.ndarray

An array of predicted runoff values for each subcatchment.

Example

>>> swmm_model = swmmio.Model("example.inp")
>>> predict_runoff(swmm_model)
array([0.1, 0.2, 0.3, 0.4, 0.5])
main.predictor.preload_model() bool[source]

Eagerly load model weights into process memory.

Returns True when model was not loaded before this call.

models module

This module contains the UserProfile model for the web application.

The UserProfile model extends the default Django User model with additional fields, such as a biography.

class main.models.UserProfile(*args, **kwargs)[source]

Bases: Model

A model representing a user’s profile in the web application.

The UserProfile model is linked to the default Django User model through a OneToOneField relationship.

Attributes:

user: The related User object. bio: A text field for the user’s biography.

exception DoesNotExist

Bases: ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: MultipleObjectsReturned

bio

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

id

A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.

objects = <django.db.models.manager.Manager object>
user

Accessor to the related object on the forward side of a one-to-one relation.

In the example:

class Restaurant(Model):
    place = OneToOneField(Place, related_name='restaurant')

Restaurant.place is a ForwardOneToOneDescriptor instance.

user_id

forms module

This module contains form classes for the web application. It includes: 1. ContactForm - for sending messages through the contact page. 2. UserProfileForm - for updating user profile information. 3. SimulationForm - for selecting simulation parameters. 4. TimeseriesForm - for selecting timeseries analysis parameters.

Each form class is built with the help of the Django Forms library and the Crispy Forms package.

class main.forms.ContactForm(*args, **kwargs)[source]

Bases: Form

A form for sending messages through the contact page.

Attributes:

email: A field for the sender’s email address. title: A field for the message’s title. content: A field for the message’s content. send_to_me: A boolean field to indicate whether to send the message to the sender.

base_fields = {'content': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'send_to_me': <django.forms.fields.BooleanField object>, 'title': <django.forms.fields.CharField object>}
declared_fields = {'content': <django.forms.fields.CharField object>, 'email': <django.forms.fields.EmailField object>, 'send_to_me': <django.forms.fields.BooleanField object>, 'title': <django.forms.fields.CharField object>}
property media

Return all media required to render the widgets on this form.

class main.forms.SimulationForm(*args, catchment_choices=None, **kwargs)[source]

Bases: Form

A form for selecting simulation parameters.

Supports both range-based methods (requiring start/stop/step) and predefined methods (using literature values, no range parameters).

Attributes:

option: A choice field for selecting the parameter to simulate. start: An integer field for the starting value of the parameter range. stop: An integer field for the ending value of the parameter range. step: An integer field for the step size in the parameter range. catchment_name: A field for the name of the catchment.

MAX_SWEEP_STEPS = 100
OPTIONS = (('Range-based Parameters', (('simulate_percent_slope', 'Slope (%)'), ('simulate_area', 'Area (ha)'), ('simulate_width', 'Width (m)'), ('simulate_percent_impervious', 'Impervious (%)'), ('simulate_percent_zero_imperv', 'Zero-Imperv (%)'), ('simulate_curb_length', 'Curb Length (m)'))), ('Predefined Literature Values', (('simulate_n_imperv', "Manning's n - Impervious"), ('simulate_n_perv', "Manning's n - Pervious"), ('simulate_s_imperv', 'Depression Storage - Impervious'), ('simulate_s_perv', 'Depression Storage - Pervious'))))
PREDEFINED_METHODS = frozenset({'simulate_n_imperv', 'simulate_n_perv', 'simulate_s_imperv', 'simulate_s_perv'})
base_fields = {'catchment_name': <django.forms.fields.CharField object>, 'option': <django.forms.fields.ChoiceField object>, 'start': <django.forms.fields.IntegerField object>, 'step': <django.forms.fields.IntegerField object>, 'stop': <django.forms.fields.IntegerField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'catchment_name': <django.forms.fields.CharField object>, 'option': <django.forms.fields.ChoiceField object>, 'start': <django.forms.fields.IntegerField object>, 'step': <django.forms.fields.IntegerField object>, 'stop': <django.forms.fields.IntegerField object>}
property media

Return all media required to render the widgets on this form.

class main.forms.TimeseriesForm(*args, catchment_choices=None, **kwargs)[source]

Bases: Form

A form for timeseries analysis. Supports single-run and parameter sweep modes.

Attributes:

mode: Choice between single timeseries or parameter sweep. feature: The subcatchment feature to vary (sweep mode only). start: Start value for parameter sweep. stop: Stop value for parameter sweep. step: Step size for parameter sweep. catchment_name: The subcatchment identifier.

FEATURE_CHOICES = (('PercSlope', 'Slope (%)'), ('Area', 'Area (ha)'), ('Width', 'Width (m)'), ('PercImperv', 'Impervious (%)'), ('CurbLength', 'Curb Length (m)'))
MAX_SWEEP_STEPS = 100
MODE_CHOICES = (('single', 'Single Timeseries'), ('sweep', 'Parameter Sweep Timeseries'))
base_fields = {'catchment_name': <django.forms.fields.CharField object>, 'feature': <django.forms.fields.ChoiceField object>, 'mode': <django.forms.fields.ChoiceField object>, 'start': <django.forms.fields.FloatField object>, 'step': <django.forms.fields.FloatField object>, 'stop': <django.forms.fields.FloatField object>}
clean()[source]

Hook for doing any extra form-wide cleaning after Field.clean() has been called on every field. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field named ‘__all__’.

declared_fields = {'catchment_name': <django.forms.fields.CharField object>, 'feature': <django.forms.fields.ChoiceField object>, 'mode': <django.forms.fields.ChoiceField object>, 'start': <django.forms.fields.FloatField object>, 'step': <django.forms.fields.FloatField object>, 'stop': <django.forms.fields.FloatField object>}
property media

Return all media required to render the widgets on this form.

class main.forms.UserProfileForm(*args, **kwargs)[source]

Bases: ModelForm

A form for updating user profile information.

Attributes:

user: A field for the related user object. bio: A field for the user’s biography.

class Meta[source]

Bases: object

fields = ['user', 'bio']
model

alias of UserProfile

base_fields = {'bio': <django.forms.fields.CharField object>, 'user': <django.forms.models.ModelChoiceField object>}
declared_fields = {}
property media

Return all media required to render the widgets on this form.

Module contents