Dimensionally-inconsistent Calculations (Emperical formulae)#
Sometimes calculations and formulae are based on curve-fitting the results of various tests. The resulting formula from the curve-fitting may assume input units with a particular scaling and produce outputs assumed to be in a different scaling.
[24]:
import forallpeople as si
si.environment('default')
Dimensionally-inconsistent radicals#
Observed in many concrete design codes is a value expressed as \(\sqrt{f'_c}\) where \(f'_c\) is in scaled units of stress (e.g. MPa) and \(\sqrt{f'_c}\) is also in units of stress (MPa in this example).
The intention behind this particular expression is to compute the square-root of 35
and for that value to be in units of MPa
.
Strategy 1 - Manually add the units back on#
[25]:
import math
MPa = 1e6 * si.Pa
f_c = 35e6 * si.Pa
math.sqrt(f_c) * MPa
[25]:
Strategy 2 - Define a custom sqrt
function#
[26]:
import math
MPa = 1e6 * si.Pa
def sqrt(x):
MPa = 1e6 * si.Pa
if (
isinstance(x, si.Physical)
and x.dimensions == (1, -1, -2, 0, 0, 0, 0)
):
return math.sqrt(x) * MPa # Special case
else:
return x**(1/2) # General case
f_c = 35 * MPa # Example of special case
area = 0.0350 * si.m**2 # Example of general case
display(
f_c,
sqrt(f_c)
)
display(
area,
sqrt(area)
)
Strategy 3#
Continuing with the example above, a calculation may intend to compute the square root of 35e6
(instead of 35
) and apply the same units to that resulting value.
This strategy can be combined with Strategy 2 to define a custom sqrt
function for special cases.
[27]:
import math
MPa = 1e6 * si.Pa
f_c = 35 * MPa
value, unit = f_c.split()
math.sqrt(value) * unit
[27]:
Hidden units#
Another kind of seemingly dimensionally-inconsistent formula may just be a case where units are assumed within a numerical value but not communicated.
An example commonly used in Canadian flexural concrete design:
This formula for calculating the required area of flexural tension steel should result in values of area (say, in mm2). In its current form, however, it is dimensionally-inconsistent because the value of 0.0015
contains hidden units of 1 / MPa
.
[28]:
si.environment('default')
MPa = 1e6 * si.Pa
f_c = 35 * MPa
b = 0.30 * si.m
d = 0.60 * si.m
M_f = 200e3 * si.N * si.m
A_s = 0.0015 * f_c * b * (d - sqrt(d**2 - (3.85 * M_f)/(f_c * b)))
A_s # Resulting units are in N, which are not expected
[28]:
Here, we will manually add the units into the calculation as (0.0015 / MPa)
.
[30]:
A_s = (0.0015 / MPa) * f_c * b * (d - sqrt(d**2 - (3.85 * M_f)/(f_c * b)))
A_s # These are the correct dimensions
[30]:
Completely inconsistent formulae#
Last, there are times where the formula essentially serves as a numeric transformation and the units simply need to be manually applied.
An example from the Canadian wood design code:
This formula for calculating tension resistance in the parallel-to-grain direction of a bolted timber connection is based on empirically-measured fracture test results.
All symbols (t
, d_e
, and d
) are numbers, scaled to units of mm
, and the resulting value of QS_i
is a number in units of force, N
.
Because this formula is a strict numeric computation with no dimensional consistency, it is best to treat it as such by manually removing units from the inputs and adding the units to the output.
[31]:
si.environment('default')
import math
# Use .prefix to force the numerical value to scale in mm
t = (0.354 * si.m).prefix('m')
d = (0.620 * si.m).prefix('m')
d_e = (0.480 * si.m).prefix('m')
t = float(t)
d = float(d)
d_e = float(d_e)
QS_i = 14 * t * math.sqrt(d_e / (1 - d_e/d)) * si.N
QS_i
[31]: