Hurmet Reference Manual

Introduction

Hurmet is a rich-text editor that gives you the ability to create high quality calculation documents using standard math notation.

Hurmet calculations are much easier to read and check than spreadsheet calculations. Hurmet does not hide the active expressions and intermediate values of a calculation. They’re all open for review in the displayed document.

You are welcome to use the Hurmet.org web page under terms of the MIT License. The source code is available in Hurmet’s GitHub repository.

Editor Basics

Hurmet provides rich-text editing capabilities. You can apply styles to a document range by selecting text, then clicking one of the menu bar buttons:

Navigate…

File▾
Open…, Save…, Save as…,
Create a permalink URL,
Import/Export to Markdown,
Take a snapshot, Show diff,
Set Page Size, Print

Doc▾
Set Decimal, Font size,
Draft Mode, Print header,
Delete all comments
recalc Recalculate all
undo  redoUndo, Redo
B  I  embed X2 X2 strikethrough  UCharacter styles:
Bold, Italic, Code, Subscript, Superscript, Strikethrough, Underline
link upload image footnote ToC C T scroll commentInsert:
Link…, Horizontal rule, Uploaded image…, Link to image…, Footnote, Table of Contents…, Calculation…, TeX…, Macro expansion, Comment…
embed H1 H2 list numbered list quotes Centered Indented Boxed Note Tip Important Warning ⬚Block styles:
Plain paragraph, Code block, Headings, List, Ordered list, Centered Indented Boxed Note Important Warning Select Parent
table insert-row insert-column delete-table delete-row delete-column merge table-caption align-left align-center align-right Tbl Style spreadsheetTable:
Insert table, Insert row, Insert column, Delete table, Delete row, Delete column, Toggle cell merge, Toggle table caption, Align left, Align center, Align right,  Set table style, Toggle spreadsheet
informationInformation

Save/Open

You can save your work using Ctrl-S or the save command in the File menu. Then reopen it using the File | Open… menu choice. In Chrome and Edge, the save button is smart enough to re-save your work to the same file you opened earlier. In Firefox and Safari, the save button always works like a Save As… button.

Tracking Changes

The File▾ menu contains commands that enable you to track changes:

Snapshots and diffs are displayed in Markdown format.

You can create a print header in any document by clicking the File | Print Header menu choice. Later, when you click the File | Print… menu choice, the header will be printed at the top of every page (except the cover page). The header is a table and it should remain a table. Otherwise, edit it any way you want.

If you write $PAGE into a print header, Hurmet will print page numbers at that location.

Macro Expansion

To expand a macro, (1) write the macro name in your document, put the selection point after the name, and then (2) hit the scroll button or type Alt+E. Hurmet will replace the macro name with the macro expansion.

To learn how to write macros or how to import macros, see the macros section, below.

Comments

The comment button enables you to write a comment into the document.

A command in the “Docs” menu will delete all comments in the document.


Table of Contents

The ToC button creates a Table of Contents at the selection point. The table will be built from Headings in your document. In the ToC dialog box, you can choose which heading levels to include.

Markdown

Hurmet documents are saved in Markdown, a lightweight, easy-to-read markup format. Hurmet's version of Markdown is extended to enable calculations, complex tables, and more.

Click for more…

Paragraphs are preceded by a blank line.
A newline is indicated by a backslash, \, at the end of a line.

Type… To get…
_Italic_Italic
**Bold**Bold
**_Bold Italic_**Bold Italic
~subscript~subscript
^superscript^superscript
~~strikethrough~~strikethrough
`inline code`inline code
¢` calcu = la/tion `
¢¢ "Display Calc" ¢¢
calcu=lation

Display Calc

$\TeX$ or $`\TeX`$
$$Display \TeX$$
TEX

DisplayTEX

# Heading 1

Heading 1

## Heading 2

Heading 2

[Link][link id]Link
![alt][id]id
!![image and caption][id]
id
image and caption
[id]: filepathpath to image or link
> Blockquote| Blockquote
* List
* List
* List
  • List

  • List

  • List

1. One
2. Two
3. Three
  1. One

  2. Two

  3. Three

a. Item a
b. Item b
c. Item c
  1. Item a

  2. Item b

  3. Item c

A. Item A
B. Item B
C. Item C
  1. Item A

  2. Item B

  3. Item C

```
#code block
print "Hi!"
```
# code block
print "Hi!"
---------
::: boxed
Block elements. The attribute
can be `indented`, `centered`,
`boxed`, or `header`.
:::

Block elements. The attribute can be indented, centered, boxed, or header.

> [!NOTE]
> Alerts. The attribute can be
> `NOTE`, `TIP`, `IMPORTANT`, or
> `WARNING`.

Alerts. The attribute can be NOTE, TIP, IMPORTANT, or WARNING.

Pipe Tables

| Head 1  |  Head 2  | Head 3  |
|:--------|:--------:|---------|
| datum 1 | datum 2  | datum 3 |
| datum 4 | datum 5  | datum 6 |

Grid tables

+-----------+-------------------------+
| Heading 1 |  Merged Heading         |
+:=========:+=========================+
| datum 1   | merged cell             |
+-----------+---------------+---------+
| merged\   | datum 3       | datum 4 |
| cell      +---------------+---------|
|           | datum 5       | datum 6 |
+-----------+---------------+---------+
| datum 7   | * cells can   | datum 8 |
|           | * contain     |         | 
|           | * block       |         |
|           | * elements    |         |
+-----------+---------------+---------+

Table in a Figure

: Write the caption just above the table, preceded by a :
| Head 1  |  Head 2  | Head 3  |
|:--------|:--------:|---------|
| datum 1 | datum 2  | datum 3 |
| datum 4 | datum 5  | datum 6 |
{.grid float=right}

Spreadsheet

: sheetName, then the caption
| Head 1  |  Head 2  | Head 3  |
|:--------|:--------:|---------|
| datum 1 | 2300     | =2*B1   |
| datum 4 | 4.3      | "       |
{#sheetname ."grid spreadsheet"}

TeX

Besides its calculation cells, Hurmet also has cells that emulate the math mode of TEX (pronounced tech). These cells display, but do not calculate, math. You can create a TeX cell by clicking the T button. Type Enter to save the cell.

To create a cell in TeX display mode, create the cell in a paragraph with no other contents, then set the paragraph justification to Centered.

For more information about TeX and LaTeX, good places to start are the Wikibooks pages for writing math and advanced math; and the Temml home page and supported-functions page.

Hurmet calculation cells use a different syntax than TeX. In calculation cells, the syntax is more akin to a programming language, yet it renders like mathematics.

And now, on to the main event, Hurmet’s calculations.

Calculation Tutorial

Create a cell

Hurmet calculation cells display math and perform numeric calculations. To create a calculation cell in Hurmet.org, select a spot in the document, then click the C button or type Alt c.

While in a cell,
      Enter will close and update the cell.
       Shift-Enter will create a newline inside the cell.
       Esc will close the cell without updating it.
      Clicking elsewhere will also close the cell.

Statements

Inside a calculation cell, we can write an statement and get a numeric result. In the demonstration box to the right, try replacing the text with 2 + 2 = ?. Hurmet will render the math and write the result where you place the ? mark.

Numbers

Numbers can be written as integers (33), decimals (2.45), or mixed fractions (3 ⁷⁄₈). There is a more detailed description below.

Arithmetic

The symbols: + - × / ^ √ are some of Hurmet’s arithmetic operators. Try an equation such as 2 × 4 + 3^2/7 = ?. Play with changes to the values and operators to see how they work. See here for more operators.

Multiplication

Hurmet accepts several multiplication syntaxes. If a=7.1, then the following all give the same result:

2×7.1
2*7.1
27.1
27.1
2a
(2)(7.1)

To obtain the character ×, type xx and hit the space bar. Auto-correct will give you an ×.

A space between variables acts as a multiplication operator.

Roots

Type sqrt and hit the spacebar to auto-correct into .
root 3 and root 4 will also auto-correct into roots.

Function

Hurmet treats a word as a function name if it is placed directly before an open parenthesis. Example: sin(π6)=0.5. Hurmet has many built-in functions.

Variables

L=3.1   ← That kind of statement will assign a value to a variable. Subsequent cells can then use the variable.
Example: 2 L = ? will result in: 2L=(2)(3.1)=6.2

A variable name must be a valid identifier.

An assignment statement can also contain a calculation expression. Example:
b = 2 L = ? will result in b=2L=(2)(3.1)=6.2

Subscripts

An underscore signals the beginning of a subscript. Examples: x_left and y_(i+1) result in xleft and yi+1.

Exponents

A carat signals the beginning of an exponent. Examples: x^23 and y^(i+1) result in x23 and yi+1

Greek letters

To write a Greek letter, write the name of the letter and hit the space bar. So, alpha ↦ α and beta ↦ β. More detail here.

Accents and Primes

To write an accent above a single-letter variable, write the accent name and hit the space bar for an auto-correction. Examples:

y bary
θ hatθ^
P vecP
x dotx˙

More detail here.

To write a prime, type two apostrophes (aka single quotation marks) and hit the space bar. So, f'' will result in f

Units

After a number, write a Hurmet unit directly after a number, with no intervening space, like this: 5meters, or between two single quotation marks, like this: 5 'meters'. Or, prepend a currency symbol to a number, e.g. $30.

Unit-Aware Calcs

Hurmet can automatically handle unit conversions of quantities. To call for a unit-aware calculations, write ?? instead of ? where you want the result to appear. Example:
2 × 3.1m = ?? ft results in 2×(3.1m)=13.1ft.

This is covered in more detail below.

Result Rounding

To specify how results are to be rounded, use the format statement. Examples:
format = "f2"   fixed to 2 places after decimal.
format = "r3"   rounded to 3 significant digits.
format = "h3"   like "r3", but doesn’t round integers.
More details below.

Display Mode

Display mode centers a calculation cell and enlarges summation symbols and integration symbols. To get display mode, first set a paragraph to centered, then create the cell.

Quick Reference

Markup

Input Renders as: Input Renders or
calculates as:
12/25.21225.2xx
(a + b)/ca+bclongVarNamelongVarName
a//bab"A string."A string.
a///ba/b5 'N.m/s2'5Nm/s2
x^23x23(a, b; c, d)(abcd)
x^(a+b)xa+b[a, b; c, d][abcd]
x_subscriptxsubscript{:a, b; c, d:}abcd
x_(a+b)xa+b[1:4] = ?[1234]
x′x[1:2:5] = ?[135]
|x|  ‖x‖|x|   x{a if b;
c otherwise}
{aifbcotherwise
A-->note BAnoteB``#size dia area
in in²
#3 0.375 0.11
#4 0.5 0.2 ``
sizediaareainin2#30.3750.11#40.5000.20
\red("ng")ng

Calculation cells also support many of the math-mode TeX functions supported by Temml. Put function arguments between parentheses, not braces, as in \cancel(5) instead of \cancel{5}.

TeX functions are provided for use in displaying math. Not all of them are valid in calculations.

A few color functions are valid in calculations, but only if their argument is a string. These are: \blue, \gray, \green, \orange, \pink, \purple, and \red.

Auto-correct

Auto-correct kicks in when you type a space inside a math zone.

Type Get Type Get Type Get Type Get
xx×sqrtGammaΓalphaα
.·root 3DeltaΔbetaβ
' 'x^2ThetaΘgammaγ
oobb M𝐌LambdaΛdeltaδ
ooo°bbb E𝔼XiΞepsilonε
///cc P𝒫PiΠzetaζ
<=\ceil⎾⏋SigmaΣetaη
>=\floor⎿⏌PhiΦthetaθ
<><<PsiΨiotaι
>>OmegaΩkappaκ
~=^^y barlambdaλ
~~vvθ hatθ^muμ
\invvvP vecPnuν
\notinnnP harpoonPxiξ
-=nnna dotpiπ
:=uua ddotrhoρ
-:÷uuua gravesigmaσ
+-±\checkmarka acutetauτ
-+\oøa tildeupsilonυ
->\not¬a ringphiϕ
<-\xorAAchiχ
<->\sumEEpsiψ
\circ\intCComegaω
|||¦\iintHH\hbar
\|ii-1NN\ell
/_OOOQQ\euro
\c¢RR\yen¥
ZZ

The font corrections, e.g., bb … work on any letter from A to Z or a to z. You can also make one those letters bold by typing it and then typing Ctrl+B.

-->, <--, and <--> will auto correct into extensible arrows, as in: AnoteB.

<space> auto-corrects to ˽ in the text editor, which renders as a space.

Display Selectors

Display selector Display Selector for Unit-Aware Calculation Displays:
???Entire calculation, including the result and a blue echo of the expression displaying the value plugged in to each variable.
%%%Omits blue echo.
@@@Displays only the result, like a spreadsheet cell.
!!!Omits the blue echo and the result.
Valid only when the result is a data frame.

Accessors

Data Type and Example Accessor Returns
string
s = "abcde"
s[2]
s[2:4]
s[3:end]
b
bce
cde
Vector
𝐕 = [12345]
𝐕[2]
𝐕[2:4]
𝐕[3:end]
2
[234]
[345]
Matrix
𝐌 = (123456789)
𝐌[2, 3]
𝐌[3,:]
𝐌[2:3, 1:2]
6
[789]
(4578)
Data Frame
DF=namewareainin2A410B622C959
DF.B
DF["B"]
DF.area
DF.B.area
DF.area.B
DF.area.end
DF["B", "area"]
DF.w[1]
DF[["A"; "C"], area]
An entire row
An entire row
Column vector
22
22
59
22
4
[10; 59]
sheet: Spreadsheet
Item
Amt
Dbl
1st
500
=2*B1
2nd
400
"
sheet.B2
sheet.B or
sheet.Amt
400
[500400]

Dot notation can be used only if the property name is a valid identifier.

Calculation Forms

Hurmet calculation cells don’t just display math; they compute numerical results.

It’s quite simple to assign a value to a variable:

Form Examples
assignmentx = 5
L = 3.1 m
w = 100 lbf/ft
name = "James"

To calulate an expression that contains a variable, a function, or an operator; write a ? or % or @ to indicate where the result should appear. Here are some examples:

Input Renders as:
2 + 2 = ?2+2=4
2 + 2 = @4
A = 2 × 4 = ?A=2×4=8
x = 2 A = ?x=2A=(2)(8)=16
x = 2 A = %x=2A=16
A = 2m × 4feet = ?? m²A=2m×4feet=2.4384m2

The statement form is more precisely defined as:

statement

At the beginning of the statement, you can write an optional variable name. The result of the calculation will be assigned to that variable. Expressions later in the document can call the variable. Variable names must qualify as valid identifiers. They are case-sensitive and bold-sensitive. A search for variable E will not find e. A search for M will not find M.

You can define a unit for the result with a leading currency symbol or a trailing unit name, but not both in the same statement.

You can also slip in a ; character just before the final = sign in a statement. That will create a multiple line statement, with aligned = signs.

Display Selector

Near the end of the statement is the display selector, i.e., ?, ??, etc. It determines how much of the calculation is displayed.

Display selector Display Selector for Unit-Aware Calculation Displays:
???Entire calculation, including the result and a blue echo of the expression displaying the value plugged in to each variable.
%%%Omits blue echo.
@@@Displays only the result, like a spreadsheet cell.
!!!Omits the blue echo and the result.
Valid only when the result is a data frame.

For an engineer like me, the most common display selector is ??. I almost always want to see the entire calculation. Seeing the expression and the plugged-in values helps me to avoid the kind of unseen errors that creep into spreadsheet calculations. And it makes the calculation reviewable by a second set of eyes.

A doubled selector will prompt a unit-aware calculation. After you try them, you may wonder how you ever did without them.

I use the ! selector mostly when I am assigning a chunk of data to a variable.

I try to resist the temptation to overuse the % selector. When I review work done by another engineer, I can do without the blue echo if variable values are assigned directly above the equation where they are used. Otherwise I get grumpy. You don’t want a grumpy reviewer.

One last variation is possible when assigning values from a single-row data frame. You can assign such values to more than one variable at a time, like this:

A, I, w_self = beam["A", "Ix", "weight"] = !!

Identifiers

Variable names and function names must be written in the form of a valid identifier.

The names of those accents are:

graveacutehattilde
barbrevedotddot
ringcheckulleftharpoon
harpoonleftvecvecleftrightvec

Hurmet’s auto-correct can help create identifiers.

To create: … do this and hit the space bar Example input Example result
Greek letterType the name of the letter.gammaγ
Capital Greek letterCapitalize the name’s first letter.GammaΓ
Bold letterType “bb”, then space, then the desired letter.bb M𝐌
Calligraphic capital letterType “cc”, then space, then the desired letter.cc P𝒫
AccentType the name of the accent.y bary
PrimeType two apostrophes.''

Hurmet will render single Latin letter variable names in italic. Function names and multi-letter variable names are rendered in upright font. As a convention, I personally use bold letters for variables that contain vectors or matrices.

Data Types

Boolean

true or false

String

A string literal is a string of text characters enclosed by a pair of straight double quotation marks. The string may include any Unicode character except a straight double quotation mark, a newline, or a carriage return.

"This is a string."

You can call a subset of any string with an index or range in brackets. Hurmet indices are one-based. Examples:

a = "abcdefg"
a[2]      # returns "b"
a[2:4]    # returns "bcd"
a[5:end]  # returns "efg"

Math String

Strings will be rendered as math if they are delimited with single backticks instead of double quotes. So somthing like `M_n` will return as Mn. This is useful mostly when a calculation checks a condition and reports whether some computed variable can be accepted.

Number

Enter as integers (33), decimals (2.45), percentages (3.2%), scientific notation (3.1e4), mixed fractions (3 ⁷⁄₈) or hexadecimal (0x2A).

integers, decimals, percentages, scientific notation, mixed fractions, or hexadecimal

Notice that a number literal must begin and end with a numeral, not a decimal symbol. Hurmet will not recognize 5. as a number.

Hurmet’s default decimal symbol is a dot. You can choose instead to enter numbers with a decimal comma via a drop-down menu in the Doc menu. Numbers are never entered with a thousands separator, but they can be displayed with one.

Hurmet always saves a decimal symbol as a dot. It’s only the display that changes.

While calculations are underway, Hurmet holds every number in memory in rational number format. The numerator and denominator are each integers of arbitrary length. So Hurmet can work precisely with numbers like 0.1 and 0¹⁄₃. Trignonometry and roots are done in double-precision floating point, good to about 15 significant digits.

Complex Number

One can write a complex number in two forms:

  • a±jb    The letter j is identical to -1 by Hurmet definition. Write a space after the j, as in 2 - j 3.

  • rθ    The characters /_ will auto-correct into ∠ and θ is in radians.

Also, the character ° is now a unit name. So one can also write a polar notation as rθ° and the phase angle will be unit-aware. The characters ooo will auto-correct into °

Examples:

z1=2+j3

z2=430°

z=z1+z2=(2+j3)+(430°)=5.46+j5

Unit

A Humet unit can be applied to a numeric value. There are four ways to write a Hurmet unit.

  1. A unit name written directly after a number, with no intervening space.

  2. A unit name between apostrophes, aka single straight quotation marks, written after a numeric value. A unit written this way can contain a space, like fluid ounce.

  3. A unit symbol written after a numeric value.

  4. A currency symbol written before a non-negative number.

Input Renders as
4.2meters4.2meters
4.2 'meters'4.2meters
30°30°
$25.10$25.10
10 'N·m/s'10Nm/s
[2.1; 15.3] 'feet'[2.115.3]feet

number or matrix or map apostrophe unit-name apostrophe

Hurmet treats the number and the unit together as a single quantity. Quantities are useful in unit-aware calculations which do automatic unit conversion and also check for unit compatibility.

Hurmet has many built-in unit definitions. You can write any one of them into a quantity. SI (metric) prefixes are valid on the appropriate unit names.

You can also create compound units on the fly. That is, you can raise any unit to a power, and these powers-of-units can be multiplied (or divided) together into products. Example:

Input Renders as
4 'kW.hr/m2'4kWhr/m2

Note that within the unit literal, it is not necessary to write ^ to indicate a numeric exponent. Also, a dot or a hyphen within a compound unit name will be rendered as a half-high dot.

Only one division solidus, /, may be written into a compound unit.

Matrix

A Hurmet matrix is a one or two dimensional arrangement of matrix elements. A Hurmet matrix element can be a number, a string, true, false, or an exprression that resolves to one of those simple types.s

A matrix literal is written between delimiters, either ( ) or [ ] or {: }. Matrix elements are horizontally separated by tabs or commas. Matrix rows are separated by semi-colons. So this: (1, 0; 0, 1) renders as (1001).

A Hurmet vector is a one dimensional array. Write a vector literal with values separated by commas or semi-colons, but not both.

Input Renders as
[2.1, -15.3][2.1-15.3]
[4; 5][45]
[][]


Another way to create a Hurmet column vector is to write a range of numbers between brackets; the form is [start:step:end]. A Hurmet calculation of that form will return a column vector with every number in the range. The step size is optional (default = 1). Examples:

Input Result
[2:5] = ?[2:5]=[2345]
[1:2:5] = ?[1:2:5]=[135]

You can call individual elements with index integers between brackets, as in 𝐕[5] or 𝐌[1, 3]. You can use a variable name for the index if the variable returns an integer. Hurmet indexes are one-based.

You can access a sub-matrix using the range operator, “:”, as in 𝐕[2:5] or 𝐕[2:end]. Entire rows or columns can be called, as in 𝐌[2,:] or 𝐌[:,1].

Matrix Operations

All the usual math operators can be applied to a numeric matrix. The operators mostly work in an element-wise fashion. If you add a scalar to a matrix, or pass a matrix to most functions, Hurmet will do an element-by-element calculation and return a matrix, as in:

𝐡=[51015]

𝐱=2𝐡+1=2[51015]+1=[112131]

Spreadsheet calculations can often be replaced by calulations using vectors, as above. When you really need to get things right, it’s great to be able to see the expression and all the plugged-in values.

Multiplication of two matrices is different than other operations. Mathematicians have several ways to multiply matrices. In Hurmet, you choose the type of multiplication by your choice of multiplication operator:

𝐀𝐁 ↦ element-wise product, (𝐀𝐁)ij=𝐀ij×𝐁ij

𝐀 𝐁 or 𝐀*𝐁matrix product, (𝐀𝐁)ij=k=1m𝐀i𝐁kj

𝐀×𝐁cross product of a pair of three-vectors     = |𝐀||𝐁|sin(θ)𝐧

𝐀𝐁 ↦ dot product = i=1n(𝐀i𝐁i)

Here are more of Hurmet’s matrix operations:

𝐀T ↦ a transposed matrix.

𝐀-1 ↦ an inverted matrix, if 𝐀 is square.

|𝐀|{determinantif𝐀 is squaremagnitudeotherwise

abs(𝐀) ↦ element-wise absolute values

𝐀{x12++xn2if𝐀 is a vectorijAij2if𝐀 is a matrix

𝐀&𝐁 or hcat(𝐀,𝐁) ↦ concatenate matrices 𝐀 and 𝐁 horizontally

vcat(𝐀,𝐁) ↦ concatenate 𝐀 and 𝐁 vertically

𝐀&e ↦ append an element to any vector

Functions will mostly work element-wise on an matrix. Exception: functions min() and max() will find the minimum or maximum of the elements in the matrix.

If you want to write a semi-colon inside parentheses and not create a matrix, use \;.

Data Frame

A data frame is a two dimensional data structure that can be accessed with row names and column names or by row indices and column indices.

Each datum can be a number, a string, true, or false. A missing item will be taken to be undefined. All data in a column must be of the same data type. A column of numbers can be assigned a unit of measure.

Data frame literals are written between double backtick delimiters. The text between the backticks must be written in TSV format. (tab-separated values)

Numbers must use a dot decimal. The second row may contain units of measure. Tabs and newlines are disallowed in data. Quotation marks, ", have no special significance.

Here’s an example of TSV input:

rebar = ``#size	diameter	area
 	in     	in²
#3	0.375  	0.11
#4	0.5    	0.2
#5	0.625  	0.31
#6	0.75   	0.44``

… which renders as:

rebar=sizediameterareainin2#30.3750.11#40.5000.20#50.6250.31#60.7500.44

Hurmet will use the first column as keys to the rest of each row if the content of the top left cell begins with a hash tag, #.

A dataframe literal can also show totals on the bottom line, via the sum(up) function. So this input:

roof = ``#Item             	weight
                           	psf
2 layers asphalt shingles  	8.0
1/2 inch plywood           	1.5
insulation, R19 fiberglass 	0.6
trusses at 16 inch o.c.    	2.5
5/8 inch gypsum board      	2.5
lights, HVAC, miscellaneous	1.5
total                      	=sum(up)``

will render like this:
roof=Itemweightpsf2 layers asphalt shingles8.01/2 inch plywood1.5insulation, R19 fiberglass0.6trusses at 16 inch o.c.2.55/8 inch gypsum board2.5lights, HVAC, miscellaneous1.5total16.6

Data frames can be quite large, so Hurmet has a fetch(url) function to load data from a remote TSV file into a data frame. Since Hurmet runs in a browser, the url must begin with http: or https:

A fetch example:

wideFlanges = fetch("https://hurmet.org/example.tsv") = !

That example loads in this data:

nameweightAdbftwIxSxlbf/ftin2inininin4in3W14X909026.5014.0014.500.440999.0143.00W12X656519.1012.1012.000.390533.087.90W10X494914.4010.0010.000.340272.054.60W8X31319.138.008.000.285110.027.50W8X18185.268.145.250.23061.915.20W6X15154.435.995.990.23029.19.72W4X13133.834.164.060.28011.35.46

As data frames go, that example is still pretty small. When I assign a data frame to a variable, I usually suppress its display by using the ! display selector.

I use a data frame most commonly by calling a row from it, like this:

beam = wideFlanges.W10X49 = !! or
beam = wideFlanges["W10X49"] = !!

That returns a single-row data frame. Then I can call individual properties, like this:

A = beam.A = ?? in2 or
A = beam["A"] = ?? in2 or
A = wideFlanges.W10X49.A = ?? in2

Hurmet will return a
{simple typeifyou call a single cell, as in df[1, 2]column vectorifyou call a column, as in df[,2]data frameotherwise

Dot notation, as in wideFlanges.W10X49, can be used only if the property name is a valid identifier.

Here are calls that can return multiple values:
    A, S_x = wideFlanges.W8X31["A", "Sx"] = !!, or
    A, S_x = wideFlanges["W8X31"]["A", "Sx"] = !! Multiple returns must use the !! display selector, for now.

If the data frame has only one row of data, a single accessor will call a datum.
Say the data frame is    aBar=sizediameterareainin2#40.50.2
Then one can call A=aBar.area=0.2in2

Numeric cata frames can be multiplied by a unit-less scalar. No other math operations are supported for data frames.

For structural engineers, I’ve put some useful data frames on GitHub. There are links below.

Map

A Hurmet map is unit-less data frame in which every value is the same data type, either boolean, string, or number. Maps can be the numeric part of a quantity.

w=deadlivesnow307040lbf/ft

You can do arithmetic on maps and run them through functions. The operation will be done on each value in the map. For instance, a beam calculation can break the loads down into dead load, live load, snow load, etc.:

M=18wL2= deadlivesnow0.3750.8750.5kft

Or, you could do your calculations in matrices and then annotate the matrix by converting it to a map:

P=(1021.215112514)kips

Pa=matrix2table(P,[DLS],[Col ACol B])=DLSCol A1021.115Col B112514kips

String Interpolation

Hurmet can do string interpolation, but only inside a data frame or a map, not inside other strings. So data frames can update automatically with values from variables defined elsewhere.

Use ${ before a variable name and } after. Hurmet will write the variable value into that spot in the data. The value will not be unit-aware. Here’s an example.

w_dead = 25 lbf/ft
w = ``dead	live	snow
${w_dead}	30	40`` 'lbf/ft' = %% lbf/ft

Note that you must do a calculation. It’s not reading a literal value.

Expressions

Hurmet calculations are meant to be recognizeable to anyone familiar with standard math notation. That is a broad statement. Here are many nuances:

Constants

π or pi

If you write π into an expression, Hurmet uses a value of 3.1415926535897932384626433832795028841971693993751.

e

Hurmet will treat e just like any other variable most of the time. But if e is the base of an exponent, for example: ex, then Hurmet will take e to mean 2.7182818284590452353602874713527.

j

j = -1. This value can be overwritten by a Hurmet assignment.

For ℏ, Hurmet uses a value of 1.054571817 × 10⁻³⁴ J·s.

Operators

Operator Example Description
=x = 15Assign a value to a variable.
xcosxAnonymous function. Used when a function is passed as an argument to another function.
auto-correct: ->
+2 + 2Addition
5 - 3Subtraction
--4Unary minus
*2*4Multiplication of numbers or matrices.\
"s1"*"s2"Concatenation of strings
×2 × 4Multiplication of numbers.
Cross product of three-vectors.
auto-correct: xx
·abMultiplication of numbers.
Dot product of vectors or matrices.
auto-correct: dot between two spaces.

(2)(4)Multiplication

a bMultiplication. (A space acts as an operator when between variables.)

2LNumber and unit (2 liters).
Not a multiplication if no space.

a2Not a multiplication if no space.
Hurmet reads “a2” as an identifier.

sin(2)Function

a (2)Multiplication if a space exists before the open paren.
/82Division
//82Case fraction
///8/2Division displayed inline
^32Exponent
&s1&s2Concatenate strings or horizontally concatenate vectors, or append numbers onto vectors, or variables into a map, or append a column vector to a data frame
Square root
auto-correct: sqrt
383nth-root
auto-correct: root n
||-4|Absolute value of a scalar, determinant of a matrix, or magnitude of a vector or a complex number.
\| \| xx12++xn2 if the argument is a vector of reals
ijAi,j2 if the argument is a 2-D matrix
⌊ ⌋4.5Floor. Always rounds down.
auto-correct: floor
⌈ ⌉4.5Ceiling. Always rounds up.
auto-correct: ceil
%10%Percent
% is not a remainder operator. If you need a remainder, use the rem() function.
10Per thousand
modulo5modulo4Modulo operator, always returns a positive result
!5!Factorial
precision = {100%ifn10015digitsotherwise
if!xLogical not if preceded by a space
5!!Double Factorial
(nk)(5 \atop 3)Binomial coefficient. (nk)=n!n!(n!k!)
==x15Equality comparison
≠ !=ifbcInequality comparison
auto-correct: <>
<

Less than comparison
>

Greater than comparison

auto-correct: <=

auto-correct: >=

in
cs
cins
Is an element of a matrix or
is a character of a string, or
is a property of a data frame.
auto-correct: \in
dpd has a property named y
auto-correct: owns
csIs not an element of
auto-correct: \notin
dpd does not have a property named y
csIs a subset of
auto-correct: \subset or contains
csIs not a subset of
auto-correct: \nsubset
and
&&
if a and b
if a && b
if ab
Logical and
or
||
if a or b
if a || b
if ab
Logical or

Logical xor
¬
!
if ¬ a
if !a
Logical not
:𝐕[2:3]
for i in 1:3
| Range separator

Functions

Hurmet treats an identifier as a function name if it is placed directly before an open parenthesis. So a term like sinh(x) is a function.

Functions can return multiple values if the return statement is written in the form: return a, b, c, …, z

Transcendental functions such as trigonometry or logarithms are done to 15 digits precision.

Hurmet’s built-in functions are described below. Unless noted otherwise, they can operate on any real or complex number or any matrix containing real numbers.


abs(z)

Absolute value of a real number. Magnitude of a complex number.

accumulate(𝐕)

Takes a vector, 𝐕, and returns a new vector whose elements are each the sum of the preceding elements in 𝐕.
Example: accumulate([241])=[267]

acos(z), asin(z), atan(z), asec(z), acsc(z), acot(z)

Inverse trigonometry functions. One can also call an inverse trigonometry function with a superscript, as in cos-1x.

atan(x, y)

When atan is called with two arguments, it returns an angle in the proper quadrant. Given a point defined by real coordinates x and y, atan returns the angle between that point and the positive x-axis of a plane. Real numbers only.

angle(z)

Phase angle of a complex number.

ceil(x)

Ceiling. Always rounds up. Real numbers only.

Char(n)

Takes an integer as a argument, treats it as a Unicode code point, and returns the corresponding string character.
Char(34) returns a double quotation mark.

conj(z)

Complex conjugate of a complex number.

cos(𝜃), sin(𝜃), tan(𝜃), sec(𝜃), csc(𝜃), cot(𝜃)

Trigonometry functions.

The trig functions listed above will assume that a real argument is in radians unless you tell it otherwise. You can tell it otherwise by just writing in a unit, as in: tan(45°) and running a unit-aware calculation.

Complex numbers are also valid arguments.

A positive integer written as a superscript after a trig function name will return the function result raised to a power.
So that: sin2θ=(sinθ)2.

A superscript -1 indicates an inverse function. In other words, cos-1x=acos(x).

Three functions: sin, cos, and tan, do not require parentheses around their arguments.

cosd(𝜃), sind(𝜃), tand(𝜃), secd(𝜃), cscd(𝜃), cotd(𝜃)

The trigonometry functions listed just above will assume that the argument is in degrees. Real numbers only. Hurmet will subscript the “d” for you.

cosh(z), sinh(z), tanh(z), sech(z), csch(z), coth(z)

Hyperbolic functions or real or complex numbers. Notation for inverse functions is similar to trigonometry.

count(str, pattern)

The number of times string pattern occurs in string str.

dataframe(a, b, …)

Takes vectors as arguments and returns a dataframe.

exp(z)

ez

fetch(url)

Fetches the contents of a remote file. It expects the file to be in TSV format (tab-separated values) and will return a data range. Fetch functions must be stand-alone expressions.

findfirst(searchstring, string)
findfirst(value, vector)
findfirst(booleanVector)

Searches the string (vector) and returns the index of the first occurence of searchstring (value).
If only one (vector) argment is provided, findfirst will return the index of the first true.

findmax(v)

Find the maximum numeric value of a vector. Returns the value and the index. So you would call it this way:
max, index = findmax(𝐕) = ?

floor(x)

floor. Always rounds down. Real numbers only.

gcd(m, n)

Greatest common divisor of two integers.

hcat(v, x)

Horizontal concatenation of: two strings, or two matrices, or an element onto a vector, or a variable onto a map, or a vector onto a data frame.

hypot(x, y)

x2+y2   …done in a way that avoids overflow. Real numbers only.

imag(z)

Imaginary part of a complex number.

isnan(x)

Indicates if the argument is not numeric.

length(a)

The length of a string or the number of elements in a matrix or vector.

lerp(X, Y, index)

Linear interplolation. Locates real index within the vector X and returns a real number interpolated from the vector Y. X must contain values in ascending order. Real numbers only.

log(z), ln(z)

Natural (base e) logarithm of real or complex number z.

log10(x)

Base 10 logarithm. Real numbers only. Hurmet will subscript the numerals for you.

log(b, x)

Base b logarithm. Real numbers only.

lfact(n)

Returns the natural logarithm of the factorial of the argument. Valid only for non-negative integers. Note that log(n!) is a valid alias for lfact(n). Real numbers only.

lgamma(x)

Returns the natural logarithm of the gamma function, Γ(x). For now, Hurmet's lgamma(x) function only works on positive rational numbers.

matrix2table(matrix, columnNames, rowNames)

Returns a map with the contents of the matrix. columnNames and the optional rowNames must each be a vector of strings.

min(a,b,c,),max(a,b,c,)

Minimum or maximum of a list or array. Real numbers only.

mod(x, y)

x modulo y. This functions divides x by y, and returns the absolute value of the remainder.

number(string)

Converts a string, such as "5" or "3.14" to a number.

ones(m, n)

Returns a m × n matrix filled with ones. Arguments must be integers.

rand(), rand(n), rand(m, n)

Pseudo-random number(s) in the range from 0 to 1 (inclusive of 0, but not 1). Good for Monte-Carlo modeling. Not sufficiently random for crypto.

The optional arguments are integers. rand with no arguments will return a single random number. If one or two arguments are provided, rand will return a matrix filled with random numbers.

real(z)

Real part of a complex number.

rem(x, y)

Remainder. This functions divides x by y, and returns the remainder.

round(x, spec)

Rounds a real number x.
To round to an integer, omit the spec.
To round to n significant digits, write the spec as "rn", e.g., "r3".
To round to n places after the decimal, write the spec as "fn".

sign(x)

Returns {1ifx>0-1ifx<00otherwise
Real numbers only.

string(x, spec)

Takes a number, x, and returns a string. spec is a rounding specification. It can round to a fixed number of digits after the decimal, e.g., "f2", or round to a specified number of digits, e.g., "r3".

sum(a, b, c, …), product(a, b, c, …), length(a, b, c, …), range(a, b, c, …), mean(a, b, c, …), variance(a, b, c, …), stddev(a, b, c, …)

Functions that accumulate a result from a list of arguments or a vector. Real numbers only.

sum(M, n)

Takes a matrix and sums either the rows or the columns.
sum(𝐌, 1) will sum the columns and return a row vector.
sum(𝐌, 2) will sum the rows and return a column vector.

transpose(M)

Transpose a matrix.

vcat(v, x)

Vertical concatenation of: two matrices, or an element onto a vertical vector.

zeros(m, n)

Returns a m × n matrix filled with zeros. Arguments must be integers.

Γ(z)

Gamma function
precision = {100%ifz is a positive integer ≤ 10015digitsotherwise

Operator Precedence

What is the result of the expression 3+4×2 ?

It depends on whether one does the addition first or the multiplication first. So the answer could be (3+4)(2)=14 or it could be 3+(4×2)=11.

To resolve this ambiguity, Hurmet performs operations with the following precedence:

! %Factorials and percents are done first.
^Then exponents, from right to left.
Roots
-Unary minus, for example: -4
To write a complex number in r∠θ notation.
× · /Multiplication or division, from left to right.
+ – & ∑Addition or subtraction or concatenation, from left to right. Also, summation.
< > ≤ ≥ = ≠Comparisons (for If Expressions)
∧ ∨ ¬ ⊻Logical operators (ditto)
:Separator for a range of integers, as in V[2:3].
, ;Argument separators or row separators for functions, matrices, dictionaries, or If Expressions.
( ) [ ]All conventions are over-ridden by parentheses or brackets.

Now let’s return to the question that opened this section. We now know that multiplication has a higher precedence than addition, so the answer to our question above is: 3+(4×2)=11

If Expressions

Hurmet If Expressions enable you to choose between expressions, based upon one or more conditions, as in:

β1={0.85iffc4,0000.65iffc8,0000.85fc4,00020,000otherwise

This sort of expression is written between the delimiters: { } The row separator symbol is ; Hurmet will automatically align the logic words if and otherwise. So the example above can be coded this way:

β_1 = {
    0.85                         if f_c′ ≤ 4000 ;
    0.65                         if f_c′ ≥ 8000 ;
    0.85 - (f_c′ - 4000)/20000   otherwise
}

The spaces in that code example are not significant. Hurmet always aligns the words if and otherwise. In fact, that example could also be coded all onto one line. To be precise, the form is:

expression if condition; expression otherwise

Conditions may contain logical operators:  and or not ∧  ∨  ¬  ⊻

x={2aifa<bandb=4a2otherwise

Chained comparisons are okay.

x={1.0ifa<b<5<d1.2otherwise

Summation

Hurmet can handle single-index summation terms. Like this one:
n=042n=20

You write the summation expression like this:
\sum_(n=0)^4 2 n = ?

The \sum and ^4 will auto-correct into more descriptive terms and the input text ends up like this:
∑_(n=0)⁴ 2 n = ?.

Overloading

Overloading summary. That is, Hurmet math operators and functions will work on all the data types tablulated below. They also work on a Hurmet quantity that takes any of these shapes:

scalar vector matrix map map with
vector values
scalar
vector
matrix
map
map with
vector values

Also, a unit-less number can be multiplied times a data frame that has numeric values.

Unit-Aware Calculations

Hurmet has a data type called a quantity that contains both a numeric magnitude and a unit of measure. In a Hurmet calculation editing box, you transform a number into a quantity literal by appending a unit name. Either omit any space before the unit name or write the unit name between single quotation marks. Examples:

4meters7.1 'ft3/s'11N·m

Hurmet has a unit-aware calculation mode that automatically handles unit conversions on quantities and also checks that the operands are unit-compatible. You specify unit-aware mode by writing two question marks instead of one in the place where you want a result to appear. So if you open a Hurmet calculation cell and write:

4ft + 3 'yards' = ?? m

… the result will render as:

4ft+3yards=3.9624m

You can create composite units on the fly and Hurmet will still convert them automatically.

3kWhr×(20min)800lbf×1h=1.0116402439486971731km

If you try to add quantities with non-compatible units, Hurmet will return an error message:

3m+2V=Error. Adding incompatible units.

If the calculated units are non-compatible with the units specified for the result display, Hurmet will return an error message:

3m+2ft=Error. Calculated units are not compatible with the desired result unit: ,V

If you assign a quantity to a variable, a unit-aware calculation will call the variable’s entire quantity, not just the numeric value.

L=3ft

L2=2L=2(3ft)=1.8288m

If you assign a quantity to a variable, you can still call the variable from a non-unit-aware calculation. Such a calculation will call the scalar value, not the quantity.

Lunaware=2L=2(3)=6

You’re welcome to view all of Hurmet’s built-in unit definitions.

Currencies

Currency exchange rates change, so Hurmet’s exchange rates are updated with data from the European Central Bank. That update occurs only once per week.

Traditional Units

Many traditional units have had more than one historical definition. Hurmet currently has the following default treatment of certain traditional units:

If you are curious about some of the more unusual units, such as “survey foot” or “nautical mile”, I recommend Russ Rowlett’s dictionary of units of measurement.

Spreadsheets

Sometimes vectors are just too awkward. For those times, Hurmet can include simple spreadsheets. The section below contains an example.

Vertical Distribution of Seismic Force

From earlier analysis

Vbase=400kips, base shear        T=0.75sec, fundamental period of the structure

From ASCE-16 section 12.8.3, Equivalent Lateral Procedure

k={1ifT0.52ifT2.51+T0.52otherwise=1.125

Cvs=w×hkΣ(w×hk), vertical distribution coefficient, Eq. 12.8-12

F=CvsVbase, local force, Eq. 12.8-11

dist: Vertical Distribution of Seismic Force
Floor Weight
kips
Height
ft
w × hk Cvs Force
kips
Shear
kips
roof95070113,1000.2899116.0116.0
fifth1,25056115,8000.2968118.7234.7
fourth1,2504283,7700.214785.90320.6
third1,2502853,0800.136154.44375.0
second1,2501424,3400.0624024.96400
total5,9500390,100

400400

Next, let’s look at the underlying formulas of that spreadsheet.

seis: Same table. Toggled to show formulas.
Floor Weight
kips
Height
ft
w × hk Cvs Force
kips
Shear
kips
roof95070=B1×C1^k=D1/D_end==E1× V_base=F1
fifth1,25056"""=G1+F2
fourth"42""""
third"28""""
second"14""""
total=sum(up)0=sum(up)

=sum(up)=F_end

This example illustrates several things about Hurmet spreadsheets.

  1. Spreadsheets start out as a Hurmet table.

  2. A spreadsheet must have a caption. The caption’s first word will be the spreadsheet’s name. Create a table caption by selecting a table and tapping the table-caption button.

  3. After all editing is complete, toggle the table into a spreadsheet by tapping the spreadsheet button. Hurmet spreadsheets toggle the entire table, not just one cell.

  4. No merged cells are allowed

  5. The top row contains headings, not formulas.

  6. A unit-of-measure can be assigned to a column. Type a newline (Shift-Enter) into a heading and write the unit’s name on the second line.

  7. Cells can contain data: numbers, strings, true, or false. Spreadsheet cells cannot contain matrices.

  8. Cells can also contain a formula.

    1. Formulas start with an = sign and can contain references to other cells or to variables in the Hurmet document.

    1. Refer to a cell with A1 format. No range names or R1C1 references. The row number is indexed so that number 1 refers to the first data row. A formula cannot refer to a heading.

    1. Refer to a column’s bottom cell with _end format. Example: B_end.

    1. To make a cell unit-aware, start the formula with a double == sign.

    1. A formula can contain the functions sum(up) or sum(left).

  9. A single " mark will be treated as a ditto instruction. Hurmet will treat that cell as a copy of the data or formula above it, with adjusted row numbers.

  10. Order of calculation is column-wise.

  11. Hurmet math zones outside the spreadsheet can refer to a spreadsheet cell with the sheet name, column heading, and row heading. An exterior cell that calls dist.Shear.total = ? would get 400 for a result.

Numeral display

There are two aspects to how numbers are displayed: (1) decimal separators, and (2) rounding format for results.

Decimal separator

In some countries, the usual decimal separator symbol is a dot. Other countries use a comma. Hurmet starts up with a decimal separator based upon the browser’s language setting. Hurmet also allows the reader (not the document author) to select which display they prefer. Just use the use the drop-down menu labeled Doc | Set Decimal.

The same menu choice also selects how Hurmet displays thousands separators.

This menu choice changes nothing internally. It changes only the display. All Hurmet documents are saved with numbers that have a dot decimal and no thousands separator.

Rounding of Results

Hurmet stores numbers internally as rational numbers in arbitrary precision, but its default result display is a decimal fraction with up to 15 significant digits. You can command Hurmet to display results differently. Just write a format statement into a Hurmet calculation cell. The specified format will apply to every calculation result below that statement (until another format statement). Here’s a format statement example:

format = "f2"

That statement specifies a fixed decimal format. Results after it will display exactly two digits after the decimal. If you would rather specify the number of significant digits, I suggest one of these statements:

format = "r3"
format = "h3"

"r3" will display a result rounded to exactly three significant digits. If your client freaks out because integer values have been rounded and look “wrong”, the "h3" format will round only the fractional part of a number.

That was the short explanation. Now the long one. The rounding format specification string must take the form: "TN∠", where:

Specification
Letter
Description Use one of: Default
TType of roundingbEefhkNnprSstx%h
NNumber of digits[0-9]+15
Optional polar∠ °

Type of rounding

Let N be the number of digits specified. Then:

Type Description Examples
Number Format spec Result display
bBinary5b0b101
e or EA programmer’s version of scientific notation. Rounds to N significant digits.22,000e32.20e4
E32.20E4
fRounds to exactly N places after the decimal.3.236f03
f23.24
f43.2360
hHurmet’s default format will round a decimal fraction to display N significant digits and omit trailing zeros, but it will not round an integer.31.345h331.3
65,809h365,809
1.1000h31.1
kAbbreviated and followed by a symbol from the SI prefixes. Rounds to N significant digits.22,000k322.0k
n or NEngineering notation, i.e. scientific notation with exponents that are even multiples of 3. Rounds to N significant digits.22,000n322.0·10³
N322.0×10³
rRounds to N significant digits.31.345r331.3
65,809r365,800
s or SScientific notation. Rounds to N significant digits.22,000s32.20·10⁴
S32.20×10⁴
p or %Percentage display.
“%” is fixed to exactly N places after the decimal.
“p” rounds to N significant digits.
0.2812%128.1%
1.28p2130%
tTruncates to a whole number.31.6t31
x or XHexadecimal62x0x3e
X0x3E
∠ or °Polar notation of complex numbers2 + j 3h32 + j 3
h3∠3.61∠0.983
h3°3.61∠56.3°

Numeric result display types f and % can be set to any non-negative integer. The significant digit display types are limited to no more than 15 significant digits.

Tests

Hurmet test statements will send an error message if a criterion is not met. For example, if you assign numeric values to two variables and then write:

@test P_u ≤ ϕR_n

The result will be one of these two messages:

PuϕRn,okPuϕRn, n.g.

If the test fails, the message is also written to the console. So you can run an entire document and get notifications in one place if something has gone wrong. (You can see a browser console by typing Ctrl-Shift-I.)

If you have previously assigned a string to the variable “assert”, a failing test message takes a more informative format:

assert=The column at location B2 should work.

The column at location B2 should work, but PuϕRn

A test statement takes this form:

@test value1 comparison operator value2

If you want a unit-aware comparison, write “@@test” instead of “@test”.

Drawings

Hurmet’s draw environment can plot functions and render simple sketches. For a sine wave, you can open a math zone and type the following code…

draw()
    title "sin x"
    frame 250, 150
    view -5, 5, -3
    axes 2, 1, "labels"
    strokewidth 2
    plot sin(x), 51
    text [1.6, 1.35], "sin x"
end

… which will result in this plot …

sin x

Always use x as the variable of a single function. For parametric plots, use t as the variable and put the two expressions into a row vector, like the code below.

draw()
   title "spiral" 
   frame 200, 200 
   view -8, 8 
   axes
   plot [t*cos(π t), t * sin(π t)], 251, 0, 8 
end

… which results in this plot …

spiral

You can pass variables into a draw environment. And a draw environment can execute the same statements as a user-defined function. So you can create drawings that change dynamically in reaction to the rest of your document.

I’ll write up an example next week.

Draw environment commands

In the following list, optional arguments are written in orange.

title "string"

Title of the drawing, for accessibility.

frame width, height, position

width and height, in px, define the size of the drawing in the document. position can be "inline", "left", or "right".
This command must come before anything is drawn.

view xmin, xmax, yₘᵢₙ, yₘₐₓ,

This command is usually written directly after frame. The arguments set the coordinate system. If ymin is omitted, the x-axis is placed in the middle of the picture. If ymax is omitted, the scales along the x-axis and y-axis are the same.

axes dx, dy, "labels"

Draws coordinate axes.

grid dx, dy, "labels"

Draws a background grid.

stroke "color"

Sets the default color for lines, paths, curves and outlines of solid figures. Can be any of the standard HTML predefined color names.

strokewidth pixelvalue

Sets the width of lines, paths, and shape outlines.

strokedasharray "dashpixel spacepixel"

Set a pattern of dashes and gaps for lines and paths. Default = null.

fill "color"

Sets the default color for filling in the inside of solid figures.

fontfamily "sansserif" | "serif" | "fixed" | "monotype"

Sets the font type.

fontsize pixelvalue

Sets the font size in px. Default = 13.33 (~10 pt).

marker "none" | "dot" | "arrow" | "arrowdot"

Sets the default marker symbol that is drawn at the endpoints of lines and paths. Dots are also set along the intermediate points of paths and curves.

line [x, y; u, v]

Draws a straight line from coordinate point x, y to coordinate point u, v.

path (x₁, y₁; x₂, y₂; …; xₙ, yₙ)       or
path (x₁, y₁, 0; x₂, y₂, r₂; …; xₙ, yₙ, rₙ)

Draws a path connecting all the points in the matrix.

Use the second form of the statement if the path contains any circular arcs. In that case, rₙ is the radius of the arc. Write a positive radius for arcs drawn counter-clockwise and write a negative radius for arcs drawn clockwise.

circle [x, y], r

Draws a circle of radius r, centered at point x, y.

dot [x, y], "open" | "closed", "label", position

Draws a dot with an optional appended label. position can be: "above"|"below"|"left"|"right"|"aboveleft"|"aboveright" |"belowleft"|"belowright"|null

ellipse [x, y], rx, ry

Draws an ellipse of radii rx and ry, centered at point x, y.

arc [x, y; u, v], r or [rx, ry]

Draws an arc in anticlockwise direction from point x, y to point u, v. It will be either a circular arc of radius r or an elliptical arc of radius [rx, ry].

rect [x, y; u, v], r

Draws a rectangle with corners at points x, y and u, v. The optional r argument defines the corner radius of a rounded rectangle.

text [x, y], "string", position

Writes the string at a point keyed to coordinates x, y.

position can be "above", "below", "middle", "left", "right", "aboveleft", "aboveright", "belowleft", or "belowright". The default is "middle".

The string can be styled with Markdown inline styles: _italic_, **bold**, `code`, ~subscript~, ^superscript^, and ~~strikethrough~~.

leader [x₁, y₁; x₂, y₂; x₃, y₃; etc], "note"

Writes a note with an arrow pointing to a location.

dimension [x₁, y₁; x₂, y₂; x₃, y₃; etc; xLabel, yLabel], "label" or ["label₁", "label₂", etc.]

Writes a string of dimensions. xLabel and yLabel locate the labels. The other points each define a witness line.

plot f or [g, h], 𝑛, xₘᵢₙ, xₘₐₓ

Plots a function or a pair of parametric equations. A single function f() should be written with x as its variable. A pair of parametric equations should be written with t as their variable.
Values will be plotted from xₘᵢₙ to xₘₐₓ. n determines the number of points to be plotted. (Default = 250)

User Defined Functions

If Hurmet’s built-in functions do not satisfy your needs, it is possible to write your own functions. Example:

function multiply(a, b)
   return a × b
end

Other Hurmet calculation cells can then call the function:

n=multiply(2,4)=8

Unlike other Hurmet assignments, user defined functions can be placed at the end of the document and still be called by other expressions.

The function can have any number of arguments, or none, separated by commas. The function name and each argument (if any) must be valid identifiers.

If any arguments are optional, write them after a semi-colon and provide a default value.

function Ms(section, Fy, Lb; Cb = 1, axis = "x")

Function statements end at a line ending, unless the last character is one of: ( [ { , ; + - or the following line begins with one of: } ] )

Comments can be written after #. A space must precede the #.

Variables created inside a user-defined function are local and their values will not be available outside the function. A user-defined function returns only the result of the expression in a return statement.

If you omit any arguments when you call a function, Hurmet will fill out the argument list with values of undefined when it executes the function.

Hurmet does not support function recursion.

Code Blocks

Inside a user-defined function, Hurmet supports code blocks and some additional control words. That is, words such as if and else can control execution of a block of statements, not just one expression. Statements between the if statement and an end statement are in the block. Example:

if a ≤ b
    x = a + b²
    y = 2 x
end

Indentation is not significant to the parser but is very useful to humans reading the code. I usually indent by four spaces.

if else

if​​…else control words make the execution of code blocks dependent on a condition. Example:

if a ≤ 4000
    b = 0.85
elseif a ≥ 8000
    b = 0.65
else
    b = 0.85 - (a - 4000)/20000
end
while

A while loop executes a code block repeatedly, as long as a condition holds true. Example:

while b ≠ 0
    h = b
    b = mod(a, b)
    a = h
end
for

A for loop iterates, executing a code block once with each element of a range or collection.

Examples:

sum = 0
for i in 1:10
    sum = sum + i
end
reverse = ""
for ch in "abcdef"
    reverse = ch & reverse
end

for index variable in range or matrix or string

The index variable of a for loop will iterate through each of the numbers in a range, the elements in a matrix, or the characters in a string.

break

A loop can be terminated early via the break keyword. Example:

for i in 1:1000000
    if i ≥ 2
        break
    end
end
return

A return statement terminates the function.

return optional expression

If the optional expression is present, the function will return its result. If not, the function will return undefined.

throw

A throw statement terminates the function and returns an optional error message.

throw optional string

print

A print statement writes a message to the browser’s console. You can type Ctrl Shift I to see it. Such a message can be very useful while debugging a function.

print string

one-liner

To make early returns less verbose, a one-liner if syntax is available:

one liner

startSvg

A user-defined function can also operate as a draw envronment. To initiate a draw environement, write the following line of code into a function:

svg = startSvg()

After that line is written, all the draw environment commands are valid.

Remote modules

If some Hurmet code is used repeatedly, it makes sense to write that code once and import it into other documents. Hurmet modules are text files that serve that purpose. Modules can contain functions and statements that assign literal values to a variable. Such a module would have text that might look like this:

E = 29000 'ksi'

v = [4, 6, 8]

function multiply(a, b)
    return a × b
end

A Hurmet document can load an entire module into one variable with a import statement. The following statement will import a file that contains the text above.

mod = import("https://hurmet.org/smallModule.txt") = !

After a module has been imported and loaded into a variable, its functions and values can be called by writing the module name and variable/function name in dot notation, as in:

E = mod.E = ?? psi

n = mod.multiply(2, 4) = ?

Imported Parameters

The Hurmet variable name importedParameters has a special purpose. It loads module values into multiple variables instead of into one variable. An example of such an import is:

importedParameters = import("https://hurmet.org/parent.txt") = !

That statement will render like this:

fcfcfyrβ1ρ0ρmaxEcGcEGncσaσasμsσppplρgCeIsVwECkztαzgSCSDSSD1IE=import(https://hurmet.org/parent.txt)

Such a statement is handy in a big project, where you break the calculations into several documents. Since any big project often has several common variables, you want a way to keep them synchronized. Put an importedParameters statement into each of the documents and you’re good. As an added benefit, a reviewer can see what you are doing.

Macros

A macro enables you to save typing. You type the macro name, hit Alt-E, and a larger section appears in your document. The macro name serves as an abbreviation for the macro expansion.

A Hurmet macro is written in a module. The macro expansion is a section of a Hurmet document, written in Markdown format. The expansion is contained within """…""" delimiters. Here’s an example:

ab = """¢` A_b = (π d_b^2) / 4 = ?? in² `, bolt area"""

As you can see, the macro expansion contains an equation to find the area of a bolt. That expression is written into a module. If you’re writing macros, you typically write several macros into each module.

A user can invoke the macro in two steps. First, import the module into a document, as in this example:

macros = import("https://gist.githubusercontent.com/ronkok/317f8ce0f706608fa9b3e3258ecea138/raw/csMacros.txt") = !

Then the user types the macro name, ab, and hits Alt-E. The macro expansion appears in the document.

It doesn’t really matter what you name the module. When a user invokes the Alt-E command, Hurmet will search all active variables to see if they contain the desired macro name.

Gists

Hurmet is a web app, so it can import text files only from addresses that begin with http or https. An easy way to create such a file is a Github Gist. I've written an example Gist for imported parameters:

https://gist.githubusercontent.com/ronkok/c6c564cf162008cccf03ab8afeb09a83/raw/ParentFileExample.txt

If you create your own Gists, you'll see that the addresses of the raw files are very long. If you want a permalink to your file, delete the 40 random characters after "/raw/". Github keeps a copy of every draft of your file and the random part after "/raw/" is the revision ID.

Batch Mode

Suppose you want to operate in batch mode and run the calculations on an entire document, or multiple documents, all at once. You can do that.

There is an altenate version of Hurmet that runs in Node.js from a command-line interface (CLI). It exposes one method, hurmet2html(), which takes Hurmet’s version of Markdown input and returns an HTML document. The code below shows how one might apply it in Node.js:

// Read a Markdown file, run the calcs, and write an HTML file.
const fs = require('fs')
const hurmet = require('filePath/hurmet.cjs')
const temml = require('filePath/temml.cjs') // Math rendering library
globalThis.temml = temml
const titleRegEx = /([^.\\/]+)\.md$/;  // A helper.

// The main function has to be async.
(async function main() {
  const inputPath = 'filePath/fileName.md'
  const title = titleRegEx.exec(inputPath)[1];
  const outputPath = `filePath/${title}.html`
  // Read the file.
  const md = fs.readFileSync(inputPath).toString('utf8')
  // Run the calculations and convert to HTML.
  const html = await hurmet.hurmet2html(md, title)
  fs.writeFileSync(outputPath, html)
})();

In the code above, you need to customize the filePath and fileName callouts.

The HTML file <head> contains references to a CSS (style) file and two fonts. You can get those files, and the hurmet.js file that runs all this, from Hurmet’s GitHub repository. Find the green button labeled “code” and get a zip file.

In that zip file, the preview folder contains the files: hurmet.js, styles.css, latinmodernmath.woff2, and Temml.woff2. The CSS and font files need to be copied to the same folder as your HTML files.

Troubleshooting

Typing lag

A big document with a lot of math may cause typing lag. You can regain speed by clicking on the Draft Mode toggle button at File | Draft mode. It will render math as plain text and omit the blue echos.

Matrix multiplication

To get element-wise multiplication of two matrices, the operator symbol must be explicitly written as or .*.

Offline

If Hurmet does not work offline, it may be because the browser is deleting cookies. If that is the case, whitelist "hurmet.org".

Gists

Hurmet can export or import a document in Markdown format. This is useful for collaboration.

Say that you have written a calculation. It’s awesome and you want to share it so that others can use it as a template. An easy way to share work is via a GitHub Gist. Then anyone can view it, download it, or comment on it. Here’s an example.

Hurmet’s version of Markdown adds some extensions that GitHub does not recognize, such as calculation cells, indented paragraphs, and merged cells in tables.

Coming Attractions

Other Resources

Civil and structural engineers may also find these items useful:

Credits

I’m Ron Kok and I created Hurmet because I want practicing engineers to have the tools they need to write calculations that are clear, complete, and reviewable.

Hurmet is built with the aid of several open source libraries and resources, for which I am very grateful.


Copyright © 2020-2024 Ron Kok. Released under the MIT License


format = ""

Give it a try. (It’s interactive.)