{ "cells": [ { "cell_type": "markdown", "id": "296a21c0-86b3-498a-af11-23041d306a1f", "metadata": {}, "source": [ "# Dimensionally-inconsistent Calculations (Emperical formulae)" ] }, { "cell_type": "markdown", "id": "82ccbff3-3f88-403e-a9e5-c99db53c998d", "metadata": {}, "source": [ "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. " ] }, { "cell_type": "code", "execution_count": 24, "id": "6c82f362-cec3-4682-a6fd-cdd7e74e9dcc", "metadata": {}, "outputs": [], "source": [ "import forallpeople as si\n", "si.environment('default')" ] }, { "cell_type": "markdown", "id": "a9a70767-f926-4e1e-9ff2-1cc6ac026957", "metadata": {}, "source": [ "## Dimensionally-inconsistent radicals" ] }, { "cell_type": "markdown", "id": "172026b3-8075-47e2-a952-c247d3a02198", "metadata": {}, "source": [ "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).\n", "\n", "The intention behind this particular expression is to compute the square-root of `35` and for that value to be in units of `MPa`." ] }, { "cell_type": "markdown", "id": "faa9f9f9-2501-455d-ae09-0e0a40c25732", "metadata": {}, "source": [ "### Strategy 1 - Manually add the units back on" ] }, { "cell_type": "code", "execution_count": 25, "id": "f6d455f2-7509-4302-b994-c2e70919024c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "5.916 MPa" ], "text/latex": [ "5.916\\ \\text{MPa}" ], "text/markdown": [ "5.916 MPa" ], "text/plain": [ "5.916 MPa" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import math\n", "MPa = 1e6 * si.Pa\n", "f_c = 35e6 * si.Pa\n", "\n", "math.sqrt(f_c) * MPa" ] }, { "cell_type": "markdown", "id": "2fa15a9f-a138-49f3-b700-99711a638a1f", "metadata": {}, "source": [ "### Strategy 2 - Define a custom `sqrt` function" ] }, { "cell_type": "code", "execution_count": 26, "id": "acb6a9a7-d51e-4be8-bde2-d624ddbae09c", "metadata": {}, "outputs": [ { "data": { "text/html": [ "35.000 MPa" ], "text/latex": [ "35.000\\ \\text{MPa}" ], "text/markdown": [ "35.000 MPa" ], "text/plain": [ "35.000 MPa" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "5.916 MPa" ], "text/latex": [ "5.916\\ \\text{MPa}" ], "text/markdown": [ "5.916 MPa" ], "text/plain": [ "5.916 MPa" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "35000.000 mm2" ], "text/latex": [ "35000.000\\ \\text{mm}^{2}" ], "text/markdown": [ "35000.000 mm2" ], "text/plain": [ "35000.000 mm²" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "187.083 mm" ], "text/latex": [ "187.083\\ \\text{mm}" ], "text/markdown": [ "187.083 mm" ], "text/plain": [ "187.083 mm" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import math\n", "MPa = 1e6 * si.Pa\n", "\n", "def sqrt(x):\n", " MPa = 1e6 * si.Pa\n", " if (\n", " isinstance(x, si.Physical) \n", " and x.dimensions == (1, -1, -2, 0, 0, 0, 0)\n", " ):\n", " return math.sqrt(x) * MPa # Special case\n", " else:\n", " return x**(1/2) # General case\n", " \n", "f_c = 35 * MPa # Example of special case\n", "area = 0.0350 * si.m**2 # Example of general case\n", "\n", "display(\n", " f_c, \n", " sqrt(f_c)\n", ")\n", "\n", "display(\n", " area, \n", " sqrt(area)\n", ")" ] }, { "cell_type": "markdown", "id": "cffbcf8d-5b2d-40bb-8087-13a8a10de7e1", "metadata": {}, "source": [] }, { "cell_type": "markdown", "id": "e9ab264c-aa09-4181-9ca7-a093503f1d54", "metadata": {}, "source": [ "### Strategy 3\n", "\n", "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.\n", "\n", "This strategy can be combined with **Strategy 2** to define a custom `sqrt` function for special cases." ] }, { "cell_type": "code", "execution_count": 27, "id": "c643c3ab-9a6d-408e-823d-7324717efa70", "metadata": {}, "outputs": [ { "data": { "text/html": [ "5.916 kPa" ], "text/latex": [ "5.916\\ \\text{kPa}" ], "text/markdown": [ "5.916 kPa" ], "text/plain": [ "5.916 kPa" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import math\n", "MPa = 1e6 * si.Pa\n", "f_c = 35 * MPa\n", "\n", "value, unit = f_c.split()\n", "math.sqrt(value) * unit" ] }, { "cell_type": "markdown", "id": "2c2b11a4-7024-4e99-8ab9-1105c6af2786", "metadata": {}, "source": [ "## Hidden units" ] }, { "cell_type": "markdown", "id": "a880206b-e4fa-420c-a9f7-316ca703d836", "metadata": {}, "source": [ "Another kind of _seemingly_ dimensionally-inconsistent formula may just be a case where units are assumed within a numerical value but not communicated.\n", "\n", "An example commonly used in Canadian flexural concrete design:\n", "\n", "$$A_s = 0.0015 (f'_c) (b) (d) - \\sqrt{d^2 - \\frac{3.85 M_f}{(f'_c) (b)}}$$\n", "\n", "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`." ] }, { "cell_type": "code", "execution_count": 28, "id": "a8b14951-5ee1-4983-ae58-cbf08f3b0260", "metadata": {}, "outputs": [ { "data": { "text/html": [ "1.017 kN" ], "text/latex": [ "1.017\\ \\text{kN}" ], "text/markdown": [ "1.017 kN" ], "text/plain": [ "1.017 kN" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "si.environment('default')\n", "MPa = 1e6 * si.Pa\n", "\n", "f_c = 35 * MPa\n", "b = 0.30 * si.m\n", "d = 0.60 * si.m\n", "M_f = 200e3 * si.N * si.m\n", "\n", "A_s = 0.0015 * f_c * b * (d - sqrt(d**2 - (3.85 * M_f)/(f_c * b)))\n", "A_s # Resulting units are in N, which are not expected" ] }, { "cell_type": "markdown", "id": "24123956-69ca-469c-b10e-c4ed46e1702a", "metadata": {}, "source": [ "Here, we will manually add the units into the calculation as `(0.0015 / MPa)`." ] }, { "cell_type": "code", "execution_count": 30, "id": "320e62c7-9dbd-495c-8cb2-8480ffcd1edd", "metadata": {}, "outputs": [ { "data": { "text/html": [ "1017.251 mm2" ], "text/latex": [ "1017.251\\ \\text{mm}^{2}" ], "text/markdown": [ "1017.251 mm2" ], "text/plain": [ "1017.251 mm²" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A_s = (0.0015 / MPa) * f_c * b * (d - sqrt(d**2 - (3.85 * M_f)/(f_c * b)))\n", "A_s # These are the correct dimensions " ] }, { "cell_type": "markdown", "id": "aa4417e0-8d47-41ab-9934-9d098eaa3029", "metadata": {}, "source": [ "## Completely inconsistent formulae" ] }, { "cell_type": "markdown", "id": "5bb56540-8b59-49c3-8589-af24cd66ff6f", "metadata": {}, "source": [ "Last, there are times where the formula essentially serves as a numeric transformation and the units simply need to be manually applied.\n", "\n", "An example from the Canadian wood design code:\n", "\n", "$$QS_i = 14t \\sqrt{\\frac{d_e}{1 - \\frac{d_e}{d}}}$$\n", "\n", "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.\n", "\n", "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`.\n", "\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." ] }, { "cell_type": "code", "execution_count": 31, "id": "4f6f4024-659f-4e00-afde-eca9a3f82416", "metadata": {}, "outputs": [ { "data": { "text/html": [ "228.499 kN" ], "text/latex": [ "228.499\\ \\text{kN}" ], "text/markdown": [ "228.499 kN" ], "text/plain": [ "228.499 kN" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "si.environment('default')\n", "import math\n", "\n", "# Use .prefix to force the numerical value to scale in mm\n", "t = (0.354 * si.m).prefix('m')\n", "d = (0.620 * si.m).prefix('m')\n", "d_e = (0.480 * si.m).prefix('m')\n", "\n", "t = float(t)\n", "d = float(d)\n", "d_e = float(d_e)\n", "\n", "QS_i = 14 * t * math.sqrt(d_e / (1 - d_e/d)) * si.N\n", "QS_i" ] } ], "metadata": { "kernelspec": { "display_name": "forallpeople", "language": "python", "name": "forallpeople" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.4" } }, "nbformat": 4, "nbformat_minor": 5 }