8000 flahax mix: interactive batch planning for growers and agronomists, any material by formula or analysis by rafatahmed · Pull Request #94 · rafatahmed/Flahax · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
2b250de
Quote incidental nutrients from the weighed recipe in review reasons …
rafatahmed Oct 22, 2026
1fb7bf0
Judge the incidental-nutrient review on the weighed recipe in both di…
rafatahmed Oct 22, 2026
24867e0
Update water-share test for the weighed-recipe review (#91)
rafatahmed Oct 22, 2026
29b2a22
Two stock tanks: magnesium sulfate shares tank B with the phosphates …
rafatahmed Oct 22, 2026
6913a61
Accept supplier label grades in the chemistry and pH stages
rafatahmed Oct 22, 2026
7ef67d7
Model data-sheet compounds from their declared ions; plan no acid for…
rafatahmed Oct 22, 2026
38bddb6
Let declared compounds state chloride, name each unstated ion, and co…
rafatahmed Oct 22, 2026
a7c6aa6
Stock volumes for fill-full and one-irrigation modes
rafatahmed Oct 22, 2026
5f537af
Fill mode never prepares more than the smallest tank holds
rafatahmed Oct 22, 2026
87ecce7
One incidental assessment: keep recommend's ammonium allowance and na…
rafatahmed Oct 22, 2026
659cf46
Judge pH candidates against the same assessed limits, including the a…
rafatahmed Oct 22, 2026
6a11f9c
Check stock solubility at the entered temperature (data pending owner…
rafatahmed Oct 22, 2026
0f396e6
Add flahax mix: five-step interactive entry with saved waters, formul…
rafatahmed Oct 22, 2026
7cbe906
flahax mix: one prompt per lab ion, alkalinity asked at entry, micron…
rafatahmed Oct 22, 2026
e495b4c
Define materials by formula, ions or analysis instead of catalogue names
rafatahmed Oct 22, 2026
4fc02aa
Tank-card batch sheet, agronomist nutrient table and full report for …
rafatahmed Oct 22, 2026
49d6410
Document flahax mix for growers and agronomists
rafatahmed Oct 22, 2026
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Open FlahaX to growers and agronomists with `flahax mix`, an interactive five-step entry (specification, water analysis, crop formula, fertilizers available, pH requirement) that saves waters, formulas, product stores, acids and sessions under `$FLAHAX_HOME` (default `~/.flahax`) in the formats `flahax batch` reads, and writes a batch sheet at the chosen depth: grower (tank A and tank B cards with prepared litres and grams, the acid container, checks after mixing), agronomist (adds the nutrient table: target, from water, required, achieved, final, difference; limits; pH path) or developer and manager (adds the full report). Lab reports are typed in their own units (mg/L, meq/L, mmol/L, alkalinity as CaCO3, micronutrients in mg/L or µmol/L); Enter is not measured, 0 a measur 10000 ed zero, `<DL` below detection; missing alkalinity is flagged at entry. Stock volumes follow the fill mode: fill the tanks full (the smallest container sets the irrigation volume) or make one irrigation (`stock_volumes.prepare_stocks`, `tank_too_small`). Two concentrate tanks (owner decision 2026-10-22): magnesium sulfate shares tank B with the phosphates, a waiver of Yara p. 65 listed on the report; a compound containing phosphate goes to tank B; more than two tanks is refused (`too_many_tanks`). Supplier label grades enter the chemistry and pH stages (graded id `<catalogue id>+<grade_id>`; an inconsistent label is `identity_inconsistent`), and compounds are declared from their data sheet (`declared_ions`: nitrogen forms, oxides, micronutrients, chelating agent, optional Na and Cl; checked by implied protons per phosphate between HPO4 2- and H2PO4-; one flag per unstated ion; their chelate sodium counted in the Na row); a product that cannot be modelled is formulated but gets no pH plan (`ph_not_planned_for_product`). Stock solubility is checked per product at the entered temperature from sourced data (`stock_solubility.check_stock_solubility`); no data is packaged yet, so every product shows not checked until the owner approves the sourced table. The review reasons on every output now quote the recipe that is weighed (#91).
- A material is defined by what it puts in the water, not by its catalogue name (owner decision 2026-10-22). `material_chemistry(record)` resolves a compound from its stated `ions` (with `chelating_agent` for chelates) or its `formula` (fertilizer ion table plus hydrate water), and a blend from its analysis by nutrient form (declared-ions grade); a record with only a name stops with `material_undefined` and says what to give. The 32 catalogue products are pre-filled materials whose ions are their identities' `ion_forms`; counterions and ligands follow the ions, so the name-based special cases (potassium carbonate and bicarbonate, macro-salt formula counterions) are gone. `chemistry_for_product`, `PRODUCT_CHEMISTRY` and `convert_catalogue_product_dose` remain as views. Every catalogue product converts bit for bit as before at five doses, and the 26 packaged formulas in RO water give identical recipes, pH and reagent decisions; a material list that shares no names with the catalogue gives the same recipe, pH and acid dose as the catalogue. Urea's component list was a string (a missing tuple comma) and is now a tuple.
- Assess untargeted nutrients once, and name where each comes from (#92). `recommend` keeps its 10 % ammonium allowance (`ammoniumLimit`), but the workflow re-assessed the first fit against the caller's limits only, so ammonium within the allowance read 'no declared maximum' and made the formulation `requires_review` while the coupled pH refit rated it `within_limit`. The workflow now assesses against the caller's limits plus the allowance `recommend` applied (a declared N_NH4 maximum still wins; an explicit N_NH4 target is fitted as given), so first fit, refit and every later stage agree. Every incidental row carries `source`, the dosed products (or water) that supply it, e.g. N_NH4 from Calcium Nitrate (ag grade), and the summary's formulation rows for untargeted nutrients carry it too. Recipes are unchanged: the 26 packaged formulas in RO water give identical salts, first fit and refit.
- Draft the physical validation protocol (#41): what will be measured (acid dose to target pH, pH after the planned dose, stock-tank stability with a precipitating positive control, nutrient concentrations; unadjusted pH and EC reported only), a 2-water by 3-formula matrix with three independent preparations, predictions made from measured inputs and frozen by commit hash before any solution is prepared, proposed acceptance criteria, fixed exclusions, and the separation of implementation agreement, input uncertainty and measured agreement. No measurement has been made; reviewer, laboratory and budget are the owner's decisions.
- Benchmark the authors' Irriblend-DSW optimiser in the competitor comparison (#40). Its authors added the MIT licence on 2026-10-20 (commit a046d5c), so the formulation track now imports their unmodified `irriblend_dsw_funs.py` (SHA-256 checked) and calls `ferti_eco_min`; through the same calls it reproduces all 97 water blends of their two published case-study outputs exactly. The independent LP after their method stays beside it, and every engine is also scored on macronutrients only, because Irriblend-DSW models no micronutrients. New snapshot 2026-10-22-competitors-1ade5b6: on the benchmark's fixed inputs (equal prices, non-binding EC cap) the optimiser returns 30 of 52 recipes, meets N, P, K and S in every one, and overshoots Mg or Ca as its lower-bound constraints allow; the comparison page explains each result. All other accuracy figures are unchanged from the previous snapshot.
- Rewrite the growers page as a task path (#80): enter the water analysis (with unit conversions, measured zeros and detection limits), choose the formula, run `flahax batch`, read the batch sheet; then a worked tomato example on the station 104 well blended with RO water (8% passes the 3 mmol/L Na and Cl limits, 9% is blocked), what to measure after mixing and when to call an agronomist. A test reruns the example and checks the page's numbers. `flahax batch --water-share PERCENT` blends the analysed water with ion-free water: nutrients and limits scale the laboratory values and the chemistry dilutes the measured-pH record (#84). Formulation and pH stages that need review now say why (incidental nutrients without a declared maximum; the chosen reagent's review findings and missed targets) instead of an empty reason.
Expand Down
53 changes: 49 additions & 4 deletions docs/site/growers.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,48 @@ FlahaX plans a batch; it does not run pumps or dose anything. Its evidence is
computational: it has not been validated in the laboratory or in the field, so
every sheet ends with measurements you take after mixing.

## The quick way: `flahax mix`

`flahax mix` asks for the same five things in order and remembers your answers,
so the next batch is one command:

1. **Specification**: tank A, tank B and acid container sizes, the injection
ratio, the temperature, and whether you fill the tanks full (several
irrigations) or make just enough for one irrigation.
2. **Water analysis**: RO water, a saved analysis, or a new one typed from the
lab report in its own units (mg/L, meq/L or mmol/L; NO3 and SO4 as printed).
Enter means *not measured*, `0` a measured zero, and `<0.02` below detection,
as the lab prints it. The charge balance is shown at once.
3. **Crop formula**: a packaged formula, a saved one, or a packaged one changed
value by value.
4. **Fertilizers available**: the catalogue, a saved store, or ticking what you
have. A product you add is either a **chemical** (MKP, calcium nitrate) with
the label on your bag, or a **compound** (an NPK 20-20-20 + TE) typed from its
data sheet: the nitrogen forms, P2O5, K2O, the micronutrients and the
chelating agent. FlahaX checks that the label's charges balance; a compound
that does not balance is still used for nutrients, but no acid is planned for
that batch.
5. **pH requirement**: the target pH of the irrigation solution.

```bash
flahax mix # first time: answers the five steps
flahax mix sessions/tomato-ro # next time: no questions
```

At the end choose who the result is for. **Grower**: the batch sheet with tank
A and tank B (prepared litres and grams to weigh, with tick boxes), the acid
container and the checks after mixing. **Agronomist**: the same, plus the
nutrient table (target, from water, required, achieved, final, difference),
the limits and the pH path. **Developer or manager**: both, plus the full
report and `summary.json`. Tank A holds calcium and the micronutrients and never
takes acid; tank B holds the sulfates and phosphates, magnesium sulfate and any
phosphate compound included; acid has its own container and injector. A stock
that would not dissolve at your temperature blocks the sheet, and products
without sourced solubility data are listed as not checked.

The steps below do the same with `flahax batch`, one command with files, for
scripts and for checking a plan by hand.

## What you need before you start

| You need | Where it comes from |
Expand Down Expand Up @@ -120,7 +162,8 @@ Read it from top to bottom before you weigh anything.
injection ratio.
- Tank A holds the calcium products, micronutrients and chelates. Never put
acid into tank A.
- Keep the tanks apart as listed.
- Keep the two tanks apart. Magnesium sulfate shares tank B with the
phosphates by FlahaX's two-tank rule; the sheet lists each such pair.
- FlahaX does not check that each concentrate dissolves at that strength.
Check it with your supplier's solubility data.

Expand Down Expand Up @@ -166,10 +209,12 @@ value on the sheet rather than relying on this arithmetic alone.
| A | Sodium Molybdate (Dihydrate) | 0.1 | 0.01 |
| B | Potassium Sulfate | 501.7 | 50.17 |
| B | Magnesium Sulfate (Heptahydrate) | 423.3 | 42.33 |
| C | Potassium Monobasic Phosphate | 220.0 | 22.00 |
| B | Potassium Monobasic Phosphate | 220.0 | 22.00 |

- **Tanks.** Magnesium sulfate cannot share a concentrate with the phosphate
(Yara's compatibility table), so there are three tanks.
- **Tanks.** There are two tanks. By FlahaX's rule magnesium sulfate shares
tank B with the phosphate, although Yara's compatibility table says not to
mix them: keep tank B's strength within what your supplier says dissolves,
and check it for cloudiness.
- **Targets.** Every target is met within 1 %.
- **pH.** The blend mixes at pH 5.84, so only **1.5 mL** of 60 % nitric acid
per 1000 L brings it to 5.8.
Expand Down
29 changes: 26 additions & 3 deletions docs/site/guide/grower-outputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ and offline: the HTML has inline styles and charts, and no script, font or netwo
access. These are planning documents, not dosing instructions: measure EC and pH
after mixing.

## Interactive: `flahax mix`

`flahax mix` asks for the specification, water analysis, crop formula,
fertilizers and target pH, saves each answer under `$FLAHAX_HOME` (default
`~/.flahax`) in the same formats `flahax batch` reads, and writes the batch
sheet at the chosen depth: grower (tank cards, acid container, checks),
agronomist (adds the nutrient table, limits and pH path) or developer and
manager (adds `report.html`). `summary.json` is always written. In Python,
`grower_sheet.render_mix_sheet(summary, depth)` and
`grower_sheet.agronomist_rows(summary)` give the same from any
`batch_cli.run_batch` summary. See the [growers page](../growers.md).

## From the command line

```bash
Expand Down Expand Up @@ -82,13 +94,20 @@ warnings to read before mixing and blank lines for measured EC and pH.
The default grouping (`group_tanks`) follows Yara, *Fertilizantes para
fertirrigación*, page 65 mixing compatibility table, read with page 63. The
table's twelve "No" pairs are exactly three rules, applied to every product from
its elemental analysis:
its elemental analysis. FlahaX waives the last one (see below):

| Keep apart | Why |
|---|---|
| calcium and phosphate | calcium phosphate precipitates in a concentrate (pp. 63, 65) |
| calcium and sulfate | gypsum precipitates in a concentrate (pp. 63, 65) |
| magnesium and phosphate | magnesium phosphate precipitates in a concentrate (p. 65) |
| magnesium and phosphate | magnesium phosphate precipitates in a concentrate (p. 65); **waived** by the two-tank rule |

FlahaX rule (owner decision 2026-10-22): there are exactly **two** concentrate
tanks, A and B. Magnesium sulfate shares tank B with the phosphates, against
the magnesium-phosphate rule above. The report lists every pair this lets share
a tank (`TankGrouping.waived`), and check the strength of tank B against your
supplier's solubility data. Products that still need a third tank, for example
because of rules of your own, are refused with `too_many_tanks`.

FlahaX rule (owner decision, #79): micronutrients and chelates go to **tank A**
with the calcium products, because their doses are too small to precipitate
Expand All BD0 @@ -100,7 +119,11 @@ another tank. pH reagents always have their own channel.
The table states compatibility, not solubility. Check that every concentrate
dissolves at its strength and temperature; `plan_stocks` does this with your
sourced solubility limits, and `default_compatibility_rules(products)` gives it
the same rules as records. Your own `compatibilityRule` records (`--rules`, or
the same rules as records. `summarize_batch(..., temperature_c=25)` also lists
each concentrate against sourced single-salt solubility at that temperature
(`summary['solubility']`); a stock that does not dissolve blocks the batch. No
solubility data are packaged yet, so every product shows "not checked" until a
sourced table is approved. Your own `compatibilityRule` records (`--rules`, or
`rules=` in Python) separate further products and override the micronutrient
rule.

Expand Down
2 changes: 2 additions & 0 deletions src/flahax/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from .trace_equilibrium import ChMicroProductDose, ChMicroTotals, TraceEquilibrium, solve_ch_micro_equilibrium
from .catalogue_chemistry import ProductChemistry, assert_catalogue_coverage, chemistry_for_product
from .product_conversion import ProductAnalyticalTotals, convert_catalogue_product_dose, convert_product_dose, solve_catalogue_product_doses, catalogue_dose_totals, plan_catalogue_nitric_target
from .material_chemistry import material_chemistry
from .aqueous_model import AqueousResult, AcidResult
from .mixed_equilibrium import MixedFertilizerEquilibrium, solve_mixed_fertilizer_equilibrium

Expand Down Expand Up @@ -136,6 +137,7 @@
from .equilibrium_delivery import EquilibriumPhPlan, plan_equilibrium_delivery
__all__ += ["EquilibriumPhPlan", "plan_equilibrium_delivery"]
__all__ += ["AqueousResult", "AcidResult", "catalogue_dose_totals", "plan_catalogue_nitric_target"]
__all__ += ["material_chemistry"]
from .calculated_ph import calculate_equilibrium_ph
from .fertilizer_workflow import FertilizerWorkflow, WorkflowStage, plan_fertilizer_workflow
__all__ += ["calculate_equilibrium_ph", "FertilizerWorkflow", "WorkflowStage", "plan_fertilizer_workflow"]
Expand Down
7 changes: 5 additions & 2 deletions src/flahax/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ def main() -> int:
if sys.argv[1:2] == ['batch']:
from .batch_cli import main as batch
return batch(sys.argv[2:])
if sys.argv[1:2] == ['mix']:
from .mix_cli import main as mix
return mix(sys.argv[2:])
parser = argparse.ArgumentParser(description='FlahaX nutrient recommendation and site planning')
parser.add_argument('command', nargs='?', default='recommend', choices=('recommend', 'workflow', 'ec', 'size', 'batch'),
help='batch: report and batch sheet (flahax batch --help)')
parser.add_argument('command', nargs='?', default='recommend', choices=('recommend', 'workflow', 'ec', 'size', 'batch', 'mix'),
help='batch: report and batch sheet (flahax batch --help); mix: interactive five-step entry')
parser.add_argument('--interactive', action='store_true', help='Request site inputs (workflow, ec or size)')
args = parser.parse_args()
if args.command != 'recommend':
Expand Down
Loading
Loading
0