Skip to content

Units ​

Culsma keeps a physical quantity's value and unit together. The same quantity can be written as a literal, calculated from other quantities, or passed into a protocol. A material can also have a declared identity whose quantity is not yet known; that case has a separate meaning from a numeric quantity.

Numbers and Quantities ​

10 and 12.5 are unitless numbers. 5mL, 37C, and 100000cells carry a physical unit. A leading minus sign is an operator, so -20C is a negated temperature quantity.

A quantity used for an initial load or quantified transfer must have a volume, mass, or count unit. Container capacity requires volume; duration requires time. A unitless dilution factor can participate in a calculation, but cannot itself specify how much material to load or transfer.

Unit Families ​

DimensionCanonical units
VolumeuL, mL, L
Massug, mg, g, kg
Countcells
Timems, s, min, h, day
TemperatureC, K
Electric potentialmV, V
Electric currentuA, mA, A
Rotation raterpm
Motion frequencyHz, cycle/min
Percent%

Use canonical spellings in new source. The legacy aliases ul, ml, sec, hr, and pct remain accepted where the corresponding unit is supported, with typecheck warnings.

Recognizing a suffix in the parser does not make it valid for arithmetic or an operation argument. Suffixes such as ng_per_uL, mM, rcf, and X are not additional convertible families in the quantity arithmetic described here.

Calculation and Conversion ​

Multiplying or dividing a quantity by a unitless number preserves its unit. Addition and subtraction between compatible quantities convert the right operand into the left operand's unit. Dividing compatible quantities produces a unitless ratio.

ExpressionResult
10mL / 10000.01mL, equivalent to 10uL
2 * 5uL10uL
1mL - 100uL0.9mL
100uL + 1mL1100uL
1mL / 100uL10

The result remains a quantity when used in material operations:

text
let final_volume = 10mL;
let dilution = 1000;
let concentrate_volume = final_volume / dilution;
let diluent_volume = final_volume - concentrate_volume;

Here the concentrate volume is 0.01mL and the diluent volume is 9.99mL. Both can be used in a constructor's load list or after the colon in a quantified transfer. See Protocols and Bindings for a complete preparation protocol using these expressions.

Calculations retain numerical precision for later operations; they do not round an aliquot to a display value. For example, 10mL / 3000 can be used in subsequent subtraction. Runtime material reports may normalize the result to uL or mg without changing the represented amount.

Conversions require compatible dimensions. 1mL + 1mg is invalid, as is adding a plain number to a volume. Compound units from quantity multiplication and inverse units from number/quantity division are outside this arithmetic model. Mixed C/K arithmetic needs explicit temperature conversion; g and rpm cannot be converted without rotor information. In a centrifugal setting, g denotes relative centrifugal force rather than ordinary mass.

Bindings and Protocol Arguments ​

A let captures its calculated value when that statement executes. Changing an input later does not recalculate the earlier binding:

text
let dilution = 1000;
let aliquot = 10mL / dilution;
dilution = 2000;
let next_aliquot = 10mL / dilution;

aliquot remains 0.01mL; next_aliquot is 0.005mL. Protocol parameters follow the same arithmetic rules. An explicit argument overrides its default, and an omitted argument uses the default. Type checking resolves known values and retains known dimensions when values must wait for call expansion or execution.

Materials with Unknown Quantity ​

A declared replacement product can use unknown(dimension = mass) when its identity is known but its yield has not been quantified. This form is currently limited to the material-replacement prototype; it is not a general value for constructor loads or transfer amounts.

Unknown mass is neither zero nor a number available for ordinary arithmetic. The material must remain free in the current prototype. Separation requires explicit authored fate fractions for its unknown-mass entries; changing their relationship is unsupported. The material can follow a volume aliquot when the carrier volume and distribution are defined. Runtime tracks the share of the original unknown amount. A request such as transferring 10ug still requires a known mass and fails with MAT_QUANTITY_UNKNOWN when that mass is unavailable. Known carrier volume remains usable.

Validation and Execution ​

Type checking reports errors that can be decided from the source and resolved bindings: missing or unknown units, incompatible dimensions, known division by zero, and non-finite calculations. An authored cell count must also be a non-negative integer, including when calculated by an expression.

Values that remain unresolved are checked when execution reaches them. Runtime also checks source availability, capacity, and whether the required material quantity is known. Deferring a value does not supply a unit, invent an amount, or make an invalid calculation executable.

For volume and mass, availability and capacity checks tolerate small floating-point representation differences after unit conversion. For example, a calculated 9999.999999999998uL can satisfy a 10000uL transfer. A request within this boundary tolerance consumes the actual remaining stock, leaving the source empty and recording the actual amount moved. This does not round the recipe or define an experimental tolerance: larger shortages still fail, and an empty source cannot supply a positive amount. Cell counts retain their integer rules.

Released under the Apache-2.0 license.