Technical specification the calculator implements (JSON, with the site’s corrections)
{
"id": "mixing-calculator",
"version": 1,
"title": "Mixing calculator",
"purpose": "Convert a vial amount, a diluent volume and a chosen dose into a volume in mL and a reading on a U-100 insulin syringe. Arithmetic only; the tool never suggests or validates a dose.",
"disclaimer": "General information, not medical advice. This tool does arithmetic only. It cannot tell you whether a dose is safe or whether a vial contains what its label says. Approved drugs: follow your prescriber and the product's instructions for use.",
"constants": {
"mcg_per_mg": 1000,
"u100_units_per_ml": 100
},
"inputs": [
{
"id": "vial_amount",
"label": "Amount of substance in the vial",
"type": "number",
"units": [
"mg",
"mcg"
],
"default_unit": "mg",
"required": true,
"min_exclusive": 0,
"max_mg": 1000,
"help": "Read this from the vial label."
},
{
"id": "diluent_ml",
"label": "Diluent added",
"type": "number",
"units": [
"mL"
],
"default_unit": "mL",
"required": true,
"min": 0.1,
"max": 10,
"step": 0.1,
"help": "The total volume of liquid you put into the vial."
},
{
"id": "dose",
"label": "Dose you want to measure",
"type": "number",
"units": [
"mcg",
"mg"
],
"default_unit": "mcg",
"required": true,
"min_exclusive": 0,
"help": "Enter the dose and choose its unit. The tool does not suggest doses."
},
{
"id": "syringe",
"label": "Syringe size (U-100)",
"type": "select",
"required": true,
"default": "1.0",
"options": [
{
"value": "0.3",
"label": "0.3 mL (30 units)",
"capacity_units": 30,
"graduation_units": 1
},
{
"value": "0.5",
"label": "0.5 mL (50 units)",
"capacity_units": 50,
"graduation_units": 1
},
{
"value": "1.0",
"label": "1 mL (100 units)",
"capacity_units": 100,
"graduation_units": 2
}
],
"help": "Typical markings. Some 0.3 mL syringes have half-unit marks; check your own syringe."
}
],
"normalisation": [
"vial_mg = vial_amount if unit is mg, else vial_amount / 1000",
"dose_mg = dose if unit is mg, else dose / 1000"
],
"formulas": {
"concentration_mg_per_ml": "vial_mg / diluent_ml",
"volume_ml": "dose_mg / concentration_mg_per_ml",
"u100_units": "volume_ml * 100",
"doses_per_vial": "floor(vial_mg / dose_mg)",
"nearest_mark_below_units": "floor(u100_units / graduation_units) * graduation_units",
"nearest_mark_above_units": "ceil(u100_units / graduation_units) * graduation_units",
"dose_at_mark_mg": "mark_units / 100 * concentration_mg_per_ml"
},
"outputs": [
{
"id": "concentration",
"label": "Concentration",
"format": "{mg_per_ml} mg/mL ({mcg_per_ml} mcg/mL)",
"decimals": 2
},
{
"id": "volume_ml",
"label": "Volume to draw",
"format": "{value} mL",
"decimals": 3
},
{
"id": "u100_units",
"label": "U-100 syringe reading",
"format": "{value} units",
"decimals": 1,
"note": "Units are a volume mark (1 unit = 0.01 mL), not a dose."
},
{
"id": "doses_per_vial",
"label": "Whole doses in the vial",
"format": "{value}",
"decimals": 0
}
],
"precision": {
"internal": "Compute in decimal or integer micro-units (micrograms, microlitres) to avoid binary floating-point drift; compare thresholds after rounding to 6 decimal places.",
"display": "Round half up for display only; never round before applying a formula."
},
"validation": [
{
"id": "REQUIRED",
"level": "error",
"when": "any required input is empty or not a number",
"message": "Enter a number in every field."
},
{
"id": "NOT_POSITIVE",
"level": "error",
"when": "vial_mg <= 0 or dose_mg <= 0 or diluent_ml <= 0",
"message": "Amounts must be greater than zero."
},
{
"id": "DILUENT_OUT_OF_RANGE",
"level": "error",
"when": "diluent_ml < 0.1 or diluent_ml > 10",
"message": "Enter a diluent volume between 0.1 mL and 10 mL."
},
{
"id": "VIAL_OUT_OF_RANGE",
"level": "error",
"when": "vial_mg > 1000",
"message": "That vial amount is outside the range this tool handles. Check whether the label is in mg or mcg."
},
{
"id": "DOSE_EXCEEDS_VIAL",
"level": "error",
"when": "dose_mg > vial_mg",
"message": "The dose is larger than the whole vial. Check the units (mcg versus mg)."
}
],
"warnings": [
{
"id": "VOLUME_TOO_SMALL",
"level": "error",
"when": "u100_units < 2",
"message": "Less than 2 units (0.02 mL) cannot be measured reliably with a syringe. Do not try to estimate it."
},
{
"id": "VOLUME_SMALL",
"level": "caution",
"when": "u100_units >= 2 and u100_units < 5",
"message": "Small volume. Misreading by one mark on the syringe changes this dose by 20% or more (40% or more on syringes marked every 2 units). A more dilute mix gives a larger, easier-to-read volume for the same dose."
},
{
"id": "VOLUME_EXCEEDS_SYRINGE",
"level": "error",
"when": "u100_units > capacity_units",
"message": "This volume does not fit in the selected syringe."
},
{
"id": "VOLUME_TOO_LARGE",
"level": "error",
"when": "volume_ml > 1.0",
"message": "More than 1 mL cannot be measured in one U-100 syringe, and volumes around 1.5 mL are the conventional upper limit for a single injection under the skin. A result this large usually means a units mistake (mcg versus mg) or a very dilute mix; check the numbers."
},
{
"id": "NOT_ON_GRADUATION",
"level": "caution",
"when": "u100_units is not a whole multiple of graduation_units",
"message": "This reading falls between the marks on the selected syringe. Nearest marks: {below} units = {dose_below}, {above} units = {dose_above}.",
"show": [
"nearest_mark_below_units",
"nearest_mark_above_units",
"dose_at_mark_mg"
]
},
{
"id": "DOSE_LARGE_SHARE",
"level": "caution",
"when": "dose_mg >= 0.5 * vial_mg and dose_mg <= vial_mg",
"message": "This dose is half the vial or more. Check the units (mcg versus mg)."
},
{
"id": "UNITS_ARE_VOLUME",
"level": "info",
"when": "always",
"message": "Syringe units measure volume, not dose. The same number of units from a different mix is a different dose."
}
],
"behaviour": {
"on_validation_error": "Show the message next to the field and show no results.",
"on_warning_error": "Show the computed numbers greyed out with the error message above them; do not present them as a usable reading.",
"on_caution": "Show results with the caution directly beneath the syringe reading.",
"accessibility": "Every input has a visible label and unit; messages are announced with aria-live=polite; no information is conveyed by colour alone.",
"privacy": "All calculation happens in the browser. Nothing is stored or sent."
},
"test_vectors": [
{
"name": "Example A",
"input": {
"vial_amount": 10,
"vial_unit": "mg",
"diluent_ml": 2,
"dose": 250,
"dose_unit": "mcg",
"syringe": "0.5"
},
"expect": {
"concentration_mg_per_ml": 5,
"volume_ml": 0.05,
"u100_units": 5,
"doses_per_vial": 40,
"messages": [
"UNITS_ARE_VOLUME"
]
}
},
{
"name": "Example B",
"input": {
"vial_amount": 5,
"vial_unit": "mg",
"diluent_ml": 2.5,
"dose": 1,
"dose_unit": "mg",
"syringe": "0.5"
},
"expect": {
"concentration_mg_per_ml": 2,
"volume_ml": 0.5,
"u100_units": 50,
"doses_per_vial": 5,
"messages": [
"UNITS_ARE_VOLUME"
]
}
},
{
"name": "Example C (too small)",
"input": {
"vial_amount": 10,
"vial_unit": "mg",
"diluent_ml": 1,
"dose": 100,
"dose_unit": "mcg",
"syringe": "0.3"
},
"expect": {
"concentration_mg_per_ml": 10,
"volume_ml": 0.01,
"u100_units": 1,
"doses_per_vial": 100,
"messages": [
"VOLUME_TOO_SMALL",
"UNITS_ARE_VOLUME"
]
}
},
{
"name": "Example D (too large)",
"input": {
"vial_amount": 5,
"vial_unit": "mg",
"diluent_ml": 3,
"dose": 2.5,
"dose_unit": "mg",
"syringe": "1.0"
},
"expect": {
"concentration_mg_per_ml": 1.666667,
"volume_ml": 1.5,
"u100_units": 150,
"doses_per_vial": 2,
"messages": [
"VOLUME_EXCEEDS_SYRINGE",
"VOLUME_TOO_LARGE",
"DOSE_LARGE_SHARE",
"UNITS_ARE_VOLUME"
]
}
},
{
"name": "Example E (between marks)",
"input": {
"vial_amount": 10,
"vial_unit": "mg",
"diluent_ml": 3,
"dose": 300,
"dose_unit": "mcg",
"syringe": "1.0"
},
"expect": {
"concentration_mg_per_ml": 3.333333,
"volume_ml": 0.09,
"u100_units": 9,
"doses_per_vial": 33,
"nearest_mark_below_units": 8,
"nearest_mark_above_units": 10,
"dose_at_mark_below_mg": 0.266667,
"dose_at_mark_above_mg": 0.333333,
"messages": [
"NOT_ON_GRADUATION",
"UNITS_ARE_VOLUME"
]
}
},
{
"name": "Small volume caution",
"input": {
"vial_amount": 5,
"vial_unit": "mg",
"diluent_ml": 2,
"dose": 75,
"dose_unit": "mcg",
"syringe": "0.3"
},
"expect": {
"concentration_mg_per_ml": 2.5,
"volume_ml": 0.03,
"u100_units": 3,
"doses_per_vial": 66,
"messages": [
"VOLUME_SMALL",
"UNITS_ARE_VOLUME"
]
}
},
{
"name": "Dose larger than vial",
"input": {
"vial_amount": 2,
"vial_unit": "mg",
"diluent_ml": 2,
"dose": 5,
"dose_unit": "mg",
"syringe": "1.0"
},
"expect": {
"results": null,
"messages": [
"DOSE_EXCEEDS_VIAL"
]
}
},
{
"name": "Vial entered in mcg",
"input": {
"vial_amount": 5000,
"vial_unit": "mcg",
"diluent_ml": 2.5,
"dose": 0.5,
"dose_unit": "mg",
"syringe": "0.5"
},
"expect": {
"concentration_mg_per_ml": 2,
"volume_ml": 0.25,
"u100_units": 25,
"doses_per_vial": 10,
"messages": [
"UNITS_ARE_VOLUME"
]
}
}
]
}