Skip to content

Core

Calculator

Core saponification calculator.

calculate(recipe, *, oil_weight=None, run_validation=True)

Calculate the soap recipe results, including lye, water, and additives.

This function performs the core saponification mathematics. It determines: 1. Lye Amount: Based on the SAP values of the oils and the selected lye type (NaOH, KOH, or Hybrid). 2. Liquids: Calculates water/liquid amount based on the specified mode (ratio, concentration, or % of oils). 3. Additives: Resolves additive amounts and any lye consumption (e.g., for citric acid). 4. Properties: Predicts soap characteristics (hardness, cleansing, etc.) based on fatty acid profiles.

Parameters:

Name Type Description Default
recipe Recipe

The completely defined soap recipe.

required
oil_weight float

An optional override for the total oil weight in grams. If provided, the recipe is scaled to this weight. Defaults to None.

None
run_validation bool

If True, runs the validate() function on the recipe and includes any warnings in the result. Defaults to True.

True

Returns:

Name Type Description
RecipeResult RecipeResult

A dataclass containing all calculation details, including: - lye: Breakdown of NaOH and KOH amounts. - total_liquid: Total grams of liquid to use. - total_batch_weight: The final weight of the soap batter. - properties: Predicted qualities of the cured soap. - warnings: A list of potential issues (safety or quality).

Examples:

>>> from soap_calc import SoapCalculator, Recipe
>>> recipe = Recipe.load("my_recipe.json")
>>> result = calculate(recipe)
>>> print(f"Lye needed: {result.lye.naoh_amount}g")

Models

Core data structures and types.

Additive

Bases: BaseModel

An additive ingredient in a recipe.

Attributes:

Name Type Description
name str

Display name of the additive.

amount Optional[float]

Absolute weight in grams (mutually exclusive with percentage).

percentage Optional[float]

Percentage of a base weight (see percent_base).

percent_base PercentBase

Which weight the percentage is relative to.

stage Stage

Production stage for this additive.

lye_adjustment Optional[float]

Manual override for lye consumption.

notes str

Optional notes.

AdditiveInfo

Bases: BaseModel

Database record for an additive with usage and stage info.

Attributes:

Name Type Description
name str

Display name of the additive.

category str

Category (e.g., "Exfoliant", "Colorant").

usage AdditiveUsage

Recommended usage range.

stage str

Production stage when the additive is added.

purpose str

Brief description of what the additive does.

lye_adjustment float

Extra lye consumed per unit (e.g., citric acid).

notes str

Optional notes.

normalize_stage(v) classmethod

Normalize free-text stage names to Stage enum values.

Parameters:

Name Type Description Default
v str

Raw stage string from JSON data.

required

Returns:

Type Description
str

Normalized stage string matching a Stage enum value.

AdditiveResult

Bases: BaseModel

Calculated result for a single additive, fragrance, or superfat oil.

Attributes:

Name Type Description
name str

Display name of the ingredient.

amount float

Calculated weight in grams.

stage Stage

Production stage for this ingredient.

lye_consumed float

Extra NaOH consumed by this ingredient (e.g., citric acid).

notes str

Optional notes.

AdditiveUsage

Bases: BaseModel

Recommended usage range for an additive.

Attributes:

Name Type Description
min float

Minimum recommended amount.

max float

Maximum recommended amount.

unit str

Unit of measurement (e.g., "tsp").

per str

Weight basis for the rate (e.g., "lb_oils").

FattyAcidProfile

Bases: BaseModel

The fatty acid composition of an oil or blend.

Attributes:

Name Type Description
lauric float

C12:0 — contributes to hardness, cleansing, bubbly lather.

myristic float

C14:0 — contributes to hardness, cleansing, bubbly lather.

palmitic float

C16:0 — contributes to hardness, stable creamy lather.

stearic float

C18:0 — contributes to hardness, stable creamy lather.

ricinoleic float

C18:1-OH — conditioning, bubbly, creamy (castor oil).

oleic float

C18:1 — conditioning.

linoleic float

C18:2 — conditioning.

linolenic float

C18:3 — conditioning.

bubbly property

Bubbly lather factor (lauric + myristic + ricinoleic).

cleansing property

Cleansing factor (lauric + myristic).

conditioning property

Conditioning factor (oleic + linoleic + linolenic + ricinoleic).

creamy property

Creamy lather factor (palmitic + stearic + ricinoleic).

hard property

Hardness factor (lauric + myristic + palmitic + stearic).

longevity property

Longevity factor (palmitic + stearic).

__add__(other)

Combine two fatty acid profiles by summing each acid.

Parameters:

Name Type Description Default
other 'FattyAcidProfile'

The fatty acid profile to add to this one.

required

Returns:

Type Description
'FattyAcidProfile'

A new FattyAcidProfile with summed values.

scale(factor)

Scale all fatty acids by a factor.

Parameters:

Name Type Description Default
factor float

Multiplicative factor (e.g., 0.5 for 50%).

required

Returns:

Type Description
'FattyAcidProfile'

A new FattyAcidProfile with scaled values.

Fragrance

Bases: BaseModel

A fragrance ingredient in a recipe.

Attributes:

Name Type Description
name str

Display name of the fragrance.

fragrance_type FragranceType

Essential oil or fragrance oil.

amount Optional[float]

Absolute weight in grams (mutually exclusive with percentage).

percentage Optional[float]

Percentage of oil weight.

max_safe_pct Optional[float]

IFRA safety limit override.

stage Stage

Production stage for this fragrance.

notes str

Optional notes.

Liquid

Bases: BaseModel

A liquid-phase ingredient (water, milk, tea, etc.).

Attributes:

Name Type Description
name str

Display name of the liquid.

percentage float

Share of the liquid phase (0-100).

handling_notes str

Optional preparation notes (e.g., "freeze first").

LiquidBreakdown

Bases: BaseModel

Weight breakdown for a single liquid ingredient.

Attributes:

Name Type Description
name str

Display name of the liquid.

amount float

Weight in grams.

handling_notes str

Preparation notes (e.g., "freeze first").

LyeResult

Bases: BaseModel

Calculated lye amounts for a recipe.

Attributes:

Name Type Description
naoh_amount float

Grams of NaOH required.

koh_amount float

Grams of KOH required.

total_weight property

Total combined lye weight in grams.

MoldSpec

Bases: BaseModel

Mold dimensions for batch sizing.

Attributes:

Name Type Description
length float

Interior length in centimeters.

width float

Interior width in centimeters.

height float

Interior height in centimeters.

fill_factor float

Fraction of mold volume to fill (0.0-1.0).

estimated_batch_weight property

Estimate total batch weight assuming oil is approx 65% of total.

volume property

Interior volume in cubic centimeters.

Oil

Bases: BaseModel

A saponifiable oil or fat with its SAP values and fatty acid profile.

Attributes:

Name Type Description
name str

Common name of the oil.

sap_naoh float

Grams of NaOH to saponify 1 g of this oil.

sap_koh float

Grams of KOH to saponify 1 g of this oil.

fatty_acids FattyAcidProfile

Fatty acid composition.

iodine float

Iodine value (measure of unsaturation).

ins float

INS value.

notes str

Optional notes.

OilEntry

Bases: BaseModel

An oil entry within a recipe, pairing an oil with its blend percentage.

Attributes:

Name Type Description
oil Annotated[Oil, WithJsonSchema({'type': 'string'})]

The resolved Oil object.

percentage float

Percentage of this oil in the blend (0-100).

PropertyRating

Bases: Enum

Rating for whether a soap property falls within its recommended range.

PropertyValue

Bases: BaseModel

A predicted soap property with its value and acceptable range.

Attributes:

Name Type Description
name str

Display name of the property.

value float

Predicted numeric value.

low float

Lower bound of the recommended range.

high float

Upper bound of the recommended range.

rating PropertyRating

Whether the value is below, within, or above range.

Recipe

Bases: BaseModel

A complete soap recipe definition.

Attributes:

Name Type Description
name str

Recipe name.

description str

Optional description.

lye_type LyeType

Alkali type (NaOH, KOH, or Dual).

naoh_ratio float

NaOH share for dual-lye recipes (0-100).

naoh_purity float

NaOH purity percentage.

koh_purity float

KOH purity percentage.

superfat_pct float

Lye discount or total superfat percentage.

water_mode WaterCalculationMode

How water amount is calculated.

water_value float

Numeric value for the chosen water mode.

liquid_discount_pct float

Percentage to reduce liquid (for additives that add moisture).

oils List[OilEntry]

List of base oils with blend percentages.

liquids List[Liquid]

Liquid-phase ingredients.

additives List[Additive]

Recipe additives.

fragrances List[Fragrance]

Fragrance ingredients.

superfat_oils List[OilEntry]

Post-cook superfat oils (HP soap).

total_oil_weight Optional[float]

Total oil weight in grams (base + superfat).

base_oil_weight Optional[float]

Base oil weight in grams (excludes superfat).

mold Optional[MoldSpec]

Optional mold dimensions for batch sizing.

ignore_warnings List[str]

Warning codes to suppress.

notes str

Free-text notes.

resolve_oil_weight(override=None)

Determine total oil weight from override, mold, base_oil_weight, or total_oil_weight.

Priority
  1. Explicit override argument (e.g. from CLI --oil-weight)
  2. Mold specification
  3. base_oil_weight — back-calculates total using superfat_pct
  4. total_oil_weight
  5. Fallback: 800 g

RecipeResult

Bases: BaseModel

Complete output of a soap recipe calculation.

Attributes:

Name Type Description
lye LyeResult

NaOH and KOH amounts.

total_liquid float

Total grams of liquid.

liquid_breakdown List[LiquidBreakdown]

Per-liquid weight breakdown.

total_oil_weight float

Total grams of oil (base + superfat).

total_batch_weight float

Final batter weight in grams.

fatty_acid_profile FattyAcidProfile

Blended fatty acid profile of the oil mix.

properties SoapProperties

Predicted soap quality properties.

additives List[AdditiveResult]

Calculated additive results.

fragrances List[AdditiveResult]

Calculated fragrance results.

superfat_oils List[AdditiveResult]

Calculated post-cook superfat oil results.

effective_superfat_pct float

Combined lye discount + superfat oils percentage.

superfat_analysis Optional[SkinFeel]

Skin-feel analysis of superfat oils.

warnings List[str]

Validation warnings.

ingredients_by_stage()

Group all ingredients by production stage for instructions.

Returns:

Type Description
Dict[Stage, List[str]]

Dictionary mapping each Stage to a list of formatted ingredient strings.

SkinFeel

Bases: BaseModel

Superfat character profile for post-cook oil blends in soap.

SoapProperties

Bases: BaseModel

Full set of predicted soap properties.

Attributes:

Name Type Description
hardness PropertyValue

Bar hardness prediction.

cleansing PropertyValue

Cleansing strength prediction.

conditioning PropertyValue

Skin conditioning prediction.

bubbly_lather PropertyValue

Bubbly (big bubble) lather prediction.

creamy_lather PropertyValue

Creamy (stable) lather prediction.

longevity PropertyValue

Bar longevity prediction.

iodine PropertyValue

Iodine value of the oil blend.

ins PropertyValue

INS value of the oil blend.