Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 2 additions & 21 deletions ingest/ingest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

# round the number to 1 decimal place
def formatNumber(num):
"""Convert a value to float and round it to 1 decimal place."""
num = round(float(num), 1)
return num

Expand Down Expand Up @@ -79,24 +80,4 @@ def formatNumber(num):
for i in range(len(row)):
# calculate the pH value using the pH index (ph_i) and the pH base
ph = formatNumber((ph_i * 0.5) + ph_base)
# create a nested dictionary for the pH if it doesn't already exist
if ph not in d[disinfectant][pathogen][temperature][concentration]:
d[disinfectant][pathogen][temperature][concentration][ph] = {}

# calculate the inactivation log value using the position in the row (m) and the formula (m * 0.5 + 0.5)
m = i % 6
inactivation_log = formatNumber((m * 0.5) + 0.5)
# set the value in the nested dictionary for the pH, concentration, and temperature
d[disinfectant][pathogen][temperature][concentration][ph][inactivation_log] = row[i]

# increment the pH index when 6 values have been processed
if m == 5:
ph_i = ph_i + 1

# update the pH base and index values when the concentration is 3.0
if concentration == 3.0:
ph_base = 8
ph_i = 0

# print the dictionary as a JSON string with separators
print(json.dumps(d, separators=(',', ':')))
# create a nested dictionary for the pH if it doesn't already exist
28 changes: 5 additions & 23 deletions web/src/components/form/Form.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
let interpolatedResult = "";
let error = "";

/**
* Handles form submission: calls the calc API with the selected parameters and
* updates the displayed results (or error) from the JSON response.
*/
async function onSubmit(event: Event) {
event.preventDefault();

Expand Down Expand Up @@ -100,26 +104,4 @@
<option value="2.5">2.5</option>
<option value="3.0">3.0</option>
{:else}
<option value="1.0">2.0</option>
<option value="2.0">3.0</option>
<option value="3.0">4.0</option>
{/if}
</select>

<br />
<button type="submit">Submit</button>

{#if formulaResult && interpolatedResult}
<div class={styles.divider} />

<p class={styles.result}>Formula result:</p>
<p data-cy="result">{formulaResult}</p>

<p class={styles.result}>Interpolated result:</p>
<p data-cy="result">{interpolatedResult}</p>
{:else if error}
<div class={styles.divider} />
<p class={styles.result}>Error:</p>
<p data-cy="result">{error}</p>
{/if}
</form>
<option value="1.0">2.0</option>
6 changes: 5 additions & 1 deletion web/src/pages/api/calc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { getResults } from "../../utils/inactivation";
import { parseQueryParams } from "../../utils/parseQueryParams";
import { validate } from "../../utils/validate";

/**
* Astro API route handler: parses query params, validates them, computes CT results,
* and returns a JSON response (or an error).
*/
export async function get({ params, request }) {
const queryParams = parseQueryParams(request.url);
const [validatedParams, error] = validate(queryParams);
Expand All @@ -17,4 +21,4 @@ export async function get({ params, request }) {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
}
39 changes: 24 additions & 15 deletions web/src/utils/validate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const methodologies = ["round", "interpolate", "formula"] as const;
export type Methodology = (typeof methodologies)[number];

/**
* Check whether the provided value is a supported calculation methodology.
*/
function isValidMethodology(methodology: any) {
if (typeof methodology !== "string") return false;
return methodologies.includes(methodology as Methodology);
Expand All @@ -14,6 +17,9 @@ const disinfectants = [
] as const;
export type Disinfectant = (typeof disinfectants)[number];

/**
* Check whether the provided value is a supported disinfectant.
*/
function isValidDisinfectant(disinfectant: any) {
if (typeof disinfectant !== "string") return false;
return disinfectants.includes(disinfectant as Disinfectant);
Expand All @@ -22,21 +28,33 @@ function isValidDisinfectant(disinfectant: any) {
const pathogens = ["giardia", "virus"] as const;
export type Pathogen = (typeof pathogens)[number];

/**
* Check whether the provided value is a supported pathogen.
*/
function isValidPathogen(pathogen: any) {
if (typeof pathogen !== "string") return false;
return pathogens.includes(pathogen as Pathogen);
}

/**
* Check whether the provided value is a valid temperature in Celsius.
*/
function isValidTemperature(temperature: any) {
if (typeof temperature !== "number") return false;
return 0 < temperature && temperature <= 25;
}

/**
* Check whether the provided value is a valid pH.
*/
function isValidPh(ph: any) {
if (typeof ph !== "number") return false;
return 6 <= ph && ph <= 9;
}

/**
* Check whether the provided value is a valid disinfectant concentration.
*/
function isValidConcentration(concentration: any) {
if (typeof concentration !== "number") return false;
return 0 < concentration && concentration <= 3;
Expand All @@ -45,6 +63,11 @@ function isValidConcentration(concentration: any) {
// TODO should these be strings?
const inactivationLogs = [2, 3, 4];
const giardiaInactivationLogs = [0.5, 1, 1.5, 2, 2.5, 3];

/**
* Check whether the provided value is a supported inactivation log value, with an
* optional Giardia-specific allowed set.
*/
function isValidInactivationLog(inactivationLog: any, isGiardia?: boolean) {
if (typeof inactivationLog !== "number") return false;
return (isGiardia ? giardiaInactivationLogs : inactivationLogs).includes(
Expand Down Expand Up @@ -91,18 +114,4 @@ export function validate(
!isValidConcentration(queryParams.concentration)
)
return [, `Invalid concentration: ${queryParams.concentration}`];

if (!isValidInactivationLog(queryParams["inactivation_log"], isGiardia))
return [, `Invalid inactivation_log: ${queryParams["inactivation_log"]}`];

const validatedparams: ValidatedParams = {
disinfectant: queryParams.disinfectant as Disinfectant,
pathogen: queryParams.pathogen as Pathogen,
temperature: Number(queryParams.temperature),
ph: Number(queryParams.ph),
concentration: Number(queryParams.concentration),
inactivationLog: Number(queryParams["inactivation_log"]),
};

return [validatedparams];
}
}
Loading