# The method axmo-format-version: ed0892bbbdf4 Build a model in this order. Each step ends with something you can show the user, and the user's answer to it is worth more than any guess. ## 1. Purpose, grain, horizon, units Before anything else, write down in a few lines: - **the purpose** — the questions the model must answer (*"what does each stage cost us, by plant and quarter?"*); - **the grain** — the finest level of each dimension (product, not range; month, not quarter); - **the horizon** — the first and last period; - **the units** — of every input and result (units, minutes, kWh, EUR). ## 2. Study the model source Read the user's description and their data, and list: - the **target series** — what the user wants to see; - the **input series** — what is given; - the **intermediary series** — what is needed between them. For each, its **dimensionality**: the dimensions it varies over. A price varies over resource, country and month; it does not vary over product. Then the **input tables**: the user's, or sample tables you agree with the user. **Write a dimensionality matrix**, series down and dimensions across. Mark the combinations that never exist: a product that skips a stage, a resource a stage does not use. Axmo computes every combination of a calculated series, and an empty input counts as zero in a formula. So a combination that never exists computes to 0, which is right, as long as its input is left empty rather than filled. ## 3. Reconcile the sources The same data often arrives in differently labelled or differently shaped tables: - **A dimension under different labels:** `Month` in one table, `Period` in another, or months as column headers `2027-01, 2027-02, …`. - **One series from several tables:** each department's actuals in its own layout; actuals as a long table and the budget as a wide one. Decide, per table: - which **columns** map to which **dimensions**; - whether the table is **long** (one row per value) or **wide** (one dimension's elements across the columns); - which **Version**, if any, each table supplies. **Axmo matches labels exactly**, apart from case and surrounding spaces (inner spaces count); a number and its text, such as `2027` and `"2027"`, also match. It does **not** convert anything. `Jan-27`, `2027-1`, a date, `FY2027` or `0100` will not match `2027-01` or `100`. If the labels differ, reshape the source before loading, or add an Excel formula column that the input range reads, and say so to the user. The check tool does not calculate formulas written to cells, so to check the model, put the reshaped labels in its data. ## 4. Define the dimensions For each dimension: - **Its layers, top to bottom.** By convention the top layer is `Top_` and the root element is `All_`. **A layer may not have its dimension's name**: use a plural for the dimension and a singular for the layer (dimension `Products`, layer `Product`). - **Static or generated?** Write the tree in the file when it is known and stable. Generate it from data when the elements live in a table that changes, such as customers or cost centres ([recipe](04-recipes.md#a-dimension-built-from-data)). - **Time** is a sequential dimension, named for you ([02](02-model-file.md#dimensions)). ## 5. Define the input series For each input series: - **its dimensions**, from the matrix; - **how it totals up on each dimension** — its roll-up. Not everything sums ([03-formulas-and-totals.md](03-formulas-and-totals.md#how-a-series-totals-up)); - **whether it is entered above the grain**, and if so how it splits down: a price per country copied to plants, a target per quarter split to months; - **its loader:** which source, which columns, which fixed elements. ## 6. Define the calculated series Work from the intermediaries to the targets. For each: - **its dimensions** — the business situation it describes, not what its formula happens to produce; - **its formula**, on named series; - **how it totals up.** A sum of amounts sums. A ratio is recalculated from the totals (`FORMULA`). **Time behaviour needs its own thought:** - **balances** carry forward ([recipe](04-recipes.md#a-balance-carried-forward)); - **future-dependent values** look forward ([recipe](04-recipes.md#a-balance-from-the-future)); - **opening values** need a seed; - **stocks and flows** total differently over time: `LAST` for a stock, `SUM` for a flow. ## 7. Agree and create the outputs Agree with the user what they want to see, then create **output ranges**: - which dimensions go on the rows and which on the columns; - which totals to show; - the number format of each series. Every dimension of a series shown must be placed ([02-model-file.md](02-model-file.md#output-ranges)). ## 8. Verify Check the model by [the loop](README.md#the-loop-that-makes-the-result-reliable) until it reports `No issues.`. Then compare **two or three values with numbers you calculated by hand**, including one total. Check that totals reconcile: the regions add up to the whole, and the months to the quarter. Tell the user which values you checked, and what you assumed. ## Changing an existing model **Change an Axmo workbook through Axmo or through `apply`, never by saving it with openpyxl, pandas, ExcelJS or SheetJS**: a single load and save deletes the model and its stored values. Reading the cells without saving is harmless, but the model is not in the cells. **With the user's workbook and the ability to run code:** 1. `node tool/axmo-workbook.mjs extract book.xlsx --out work --depth complete` writes `work/model.yaml` (the model with a `data` section of the input cells as last saved, as Export at *Complete* would give it) and `work/dsdata.yaml` (every `DS.DATA` formula in the workbook). A `WORKBOOK_OBJECT_LEFT_OUT` line means the workbook holds a broken object, missing from `model.yaml`: stop, and have the user repair it in Excel first ([05](05-checking-and-fixing.md#the-workbook-tool)). 2. Edit `work/model.yaml`, and check it with `axmo-check --values` until it has no errors and the values are right. **A rename** must reach every formula, report and loader in the file; `apply` names the `DS.DATA` cells it breaks. 3. `node tool/axmo-workbook.mjs apply book.xlsx work/model.yaml -o book-v2.xlsx` writes a **new** workbook with the new model (`-o` must name a file that does not exist yet); the original is never changed. Read its lines ([05](05-checking-and-fixing.md#the-workbook-tool)): a `DS.DATA` cell to edit, old report cells to clear, data not applied. 4. Give the user `book-v2.xlsx`: they open it in Excel and press **Update**. Until then it shows the old numbers. **Otherwise** ask for the model as an export, *Plain YAML text* at `complete` (or `bindings`) depth — a `definition` export leaves generated dimensions empty (`All_Customers: null`) — and the user imports your result. **A new model** always goes this way: write it, check it, and the user imports it. **Input data changes only in Excel, or through Import at `complete`.** `apply` writes no cell. Either way: - **List the assumptions you find in it** (roll-ups, split-downs, names) before you change anything. - **Preserve what you did not create**: names, order, descriptions, reports. **Re-importing replaces the whole model**, and a `complete` file also replaces the input cells. Before it does, the Import dialog says how many input cells differ from the file, and the user chooses **Import anyway** or **Cancel**. Tell the user to expect it, and that **Import anyway** overwrites what they changed since the export.