Quick Start

This guide will get you up and running with Keecas in just a few minutes.

Your First Calculation

Let’s start with a simple engineering calculation - computing stress from force and area.

1. Import Keecas

from keecas import (
        show_eqn, # main function to generate expression block
        check, # main function for verification
        symbols, # to create symbols (from sympy)
        u, # unit registry (from pint)
        pc, # pipe commands
        generate_unique_label, # label generator
        config, # configuration options
    )

# Init the global dict
params = {}
eqn = {}

2. Define Symbols

Use LaTeX notation with subscripts for comprehensive display:

# Define symbols with LaTeX notation
F_d, A_load, sigma = symbols(r"F_{d}, A_{load}, \sigma")

3. Set Up Parameters

Define your parameters with units:

# Cell-local parameters
_p = {
    F_d: 10 * u.kN,      # Force in kilonewtons
    A_load: 50 * u.cm**2,   # Area in square centimeters
}
params.update(_p)

4. Define Expressions

Create symbolic expressions:

# Cell-local expressions
_e = {
    sigma: "F_d / A_load" | pc.parse_expr
}
eqn.update(_e)

5. Create Descriptions and Labels

Add descriptions for documentation and generate labels1 for cross-references:

# Descriptions
_d = {
    F_d: "design force",
    A_load: "loaded area",
    sigma: "normal stress",
}

# Labels (for Quarto cross-references)
_l = generate_unique_label(_d)

6. Evaluate and Display

Compute values and display the results:

# Evaluate expressions
_v = {
    k: v | pc.subs(eqn|params) | pc.convert_to([u.MPa]) | pc.N
    for k, v in _e.items()
}

# Display equations
show_eqn([_p | _e, _v, _d], label=_l)

\[\begin{align} F_{d} & = 10{\,}\text{kN} & & \quad\text{design force} \label{eq-1kv2lsa6} \\[8pt] A_{load} & = 50{\,}\text{cm}^{2} & & \quad\text{loaded area} \label{eq-1qnugots} \\[8pt] \sigma & = \dfrac{F_{d}}{A_{load}} & = 2.0{\,}\text{MPa} & \quad\text{normal stress} \label{eq-27myzkyp} \end{align}\]

This will produce beautiful LaTeX output showing both the symbolic equation and numerical result.

Understanding the Pattern

As convention Keecas uses dict prepended by _ as cell-local containers (e.g. _p), while not prepended as global containers (e.g. params) that carry across cells.

Using pc.subs is recommended to pass a dict as union of the global dicts (e.g. eqn|params), because it contains all the necessary values and expression defined in the notebook.

Dictionary Conventions

Dict Purpose Example
_p Cell-local parameters _p = {F_d: 10*u.kN}
_e Cell-local expressions _e = {sigma: "F_d/A_load" \| pc.parse_expr}
_v Cell-local values Evaluated results
_d Cell-local descriptions _d = {F_d: "design force"}
_l Cell-local labels _l = generate_unique_label(_d)

Pipe Operations

Keecas uses pipe operators (|) for functional composition:

# Chain operations together
result = expression | pc.subs(parameters) | pc.convert_to(units) | pc.N

Common pipe commands:

  • pc.parse_expr - Parse string expressions
  • pc.subs(dict) - Substitute values
  • pc.convert_to(units) - Convert units
  • pc.N - Numerical evaluation

Symbol Dependency Ordering

Keecas automatically handles out-of-order symbol definitions. You can define expressions before their dependencies:

a, b, intermediate, result = symbols(r"a, b, intermediate, result")

_e = {
    result: "sqrt(a^2 + b^2) / intermediate" | pc.parse_expr,  # Uses intermediate
    intermediate: "a * b" | pc.parse_expr,                     # Defined after result
}

_p = {a: 3, b: 4}

_v = {k: v | pc.subs(_e | _p) | pc.N for k, v in _e.items()}

show_eqn([_p | _e, _v])

\[\begin{align} a & = 3 & \\[8pt] b & = 4 & \\[8pt] result & = \dfrac{\sqrt{a^{2} + b^{2}}}{intermediate} & = 0.416666666666667 \\[8pt] intermediate & = a{\,}b & = 12.0 \end{align}\]

Keecas resolves dependencies automatically - no manual ordering required.

Common Pitfalls

WarningImportant Patterns to Know
  1. Use LaTeX notation for symbol definitions - Prefer symbols(r"\sigma_{Sd}") over symbols("sigma_Sd"). Symbols are compared by their string representation, so these create different objects:
# Two different symbols even though they render similarly
display(sigma_latex := symbols(r"\sigma_{Sd}"))
display(sigma_plain := symbols("sigma_Sd"))

\(\displaystyle \sigma_{Sd}\)

\(\displaystyle \sigma_{Sd}\)

# They are NOT equal
sigma_latex == sigma_plain  # False
False

Using LaTeX notation ensures proper rendering and avoids unexpected symbol mismatches.

  1. Be careful with vals dict in pc.subs - While maintaining a global vals dict for evaluated results can be useful, passing it to pc.subs will overwrite expressions with already evaluated values, preventing recalculation when parameters change.

Example showing the problem:

# Initial setup
x, y, z = symbols(r"x, y, z")

params = {}
eqn = {}
vals = {}

_p = {x: 2}
params.update(_p)

_e = {
    y: "x + 1" | pc.parse_expr,  # y depends on x
    z: "y^2" | pc.parse_expr,     # z depends on y (and indirectly on x)
}
eqn.update(_e)

_v = {k: v | pc.subs(eqn|params) for k, v in _e.items()}
vals.update(_v)

show_eqn([_p | _e, _v])

\[\begin{align} x & = 2 & \\[8pt] y & = x + 1 & = 3 \\[8pt] z & = y^{2} & = 9 \end{align}\]

# Update parameter and recalculate
_p = {x: 3}  # Changed value
params.update(_p)

expr_to_recalc = [y, z]

# INCORRECT: passing vals overwrites expressions with old evaluated values
_v_incorrect = {
    k: eqn[k] | pc.subs(eqn|params|vals) for k in expr_to_recalc
}

# CORRECT: don't pass vals
_v_correct = {
    k: eqn[k] | pc.subs(eqn|params) for k in expr_to_recalc
}

# Verify the difference using check()
from keecas import check
from sympy import Eq

_c = {
    k: check(_v_incorrect[k], _v_correct[k], Eq) for k in expr_to_recalc
}

show_eqn([_p | _e, _v_incorrect, _c])

\[\begin{align} x & = 3 & & \\[8pt] y & = x + 1 & = 4 & \quad\text{$\textcolor{green}{\left[=4\quad \textbf{VERIFIED}\right]}$} \\[8pt] z & = y^{2} & = 9 & \quad\text{$\textcolor{red}{\left[\neq16\quad \textbf{NOT VERIFIED}\right]}$} \end{align}\]

Only pass vals to pc.subs if you’re certain no dependent expressions need updating.

Configuration

Set up basic configuration for your document:

# Configuration for LaTeX output
config.display.katex = False             # KaTeX compatibility
config.latex.eq_prefix = "eq-PREFIX"     # Equation label prefix
config.language.language = 'en'          # Language/locale

Multi-Step Calculations

For complex calculations spanning multiple cells:

# Setup cell (run once)
params = {}  # Global parameters
eqn = {}     # Global expressions

# First calculation cell
F_d, A_load, sigma_d = symbols(r"F_{d}, A_{load}, \sigma_{d}")

_p = {
    F_d: 10 * u.kN,
    A_load: 5 * u.cm**2,
}
params.update(_p)  # Save to global

_e = {
    sigma_d: "F_d / A_load" | pc.parse_expr, 
}
eqn.update(_e)     # Save to global

_v = {
    k: v | pc.subs(eqn | params) | pc.convert_to([u.MPa]) | pc.N for k, v in _e.items()
}
show_eqn([_p | _e, _v])

\[\begin{align} F_{d} & = 10{\,}\text{kN} & \\[8pt] A_{load} & = 5{\,}\text{cm}^{2} & \\[8pt] \sigma_{d} & = \dfrac{F_{d}}{A_{load}} & = 20.0{\,}\text{MPa} \end{align}\]

# Second calculation cell (uses previous results)
sigma_Rk, sigma_Rd, gamma_M0 = symbols(r"\sigma_{Rk}, \sigma_{Rd}, \gamma_{M0}")

_p = {
    sigma_Rk: 275 * u.MPa,
    gamma_M0: 1.05, # Safety factor
}  
params.update(_p)

_e = {
    sigma_Rd: "sigma_Rk / gamma_M0" | pc.parse_expr,
}
eqn.update(_e)

_v = {
    k: v | pc.subs(eqn | params) | pc.convert_to([u.MPa]) | pc.N for k, v in _e.items()
}
show_eqn([_p | _e, _v], float_format=":.2f")

\[\begin{align} \sigma_{Rk} & = 275{\,}\text{MPa} & \\[8pt] \gamma_{M0} & = 1.05 & \\[8pt] \sigma_{Rd} & = \dfrac{\sigma_{Rk}}{\gamma_{M0}} & = 261.90{\,}\text{MPa} \end{align}\]

Verification and Checks

Check if calculated values meet criteria:

from keecas import check

# Check if stress is within allowable limits

# calculate the value
_v = {
    k: k | pc.subs(eqn|params) | pc.convert_to([u.N, u.mm]) | pc.N for k in [sigma_d/sigma_Rd]
}

# check is the expression is less than 1 (default)
_c = {
    k: check(v, 1) for k, v in _v.items()
}

show_eqn([_v, _c], float_format=":.3f")

\[\begin{align} \dfrac{\sigma_{d}}{\sigma_{Rd}} & = 0.076 & \quad\text{$\textcolor{green}{\left[\le1\quad \textbf{VERIFIED}\right]}$} \end{align}\]

CLI Quick Start

Use the Keecas CLI for quick setup:

# Create a temporary session 
keecas edit --temp

# Create a new notebook with template
keecas edit my_calculation.ipynb --template quickstart

# Launch JupyterLab in current directory
keecas edit --dir .

# Show available templates
keecas edit --list-templates

Complete Examples

For comprehensive real-world usage, check out the example notebooks:

Next Steps

Footnotes

  1. labels can be automatically generated, or manually specified↩︎