Skip to content

Commit 53261aa

Browse files
committed
Support unit prefixes
1 parent 54b4abb commit 53261aa

6 files changed

Lines changed: 159 additions & 46 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Convert units and quantities between standard [SysML v2](https://www.omg.org/sys
1111
- Get/set unit as `attribute` value, specified using Pint `Unit` objects
1212
- Supports numerical values, as well as `inf` (`*` in SysML v2) and `NaN` (set as `null` in SysML v2)
1313
- Supports compound units, for example `K·kg·s²/m³`
14+
- Supports unit prefixes (kilo, mega, milli, etc.)
1415
- Conversion functions between SysML v2 units and Pint `Unit`, and string parsing functions
1516
- Derive preferred units for a quantity type, for example `kg` for an `ISQ::mass` quantity
1617
- Syside Automator [`ReferencePrinter`](https://docs.sensmetry.com/python/latest/syside/ReferencePrinter.html) for

‎documentation.ipynb‎

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
"# Read SysML v2 textual notation using Syside Automator\n",
9696
"model, doc, elements = read_sysml(\"\"\"\n",
9797
"private import SI::*;\n",
98+
"private import SIPrefixes::*;\n",
9899
"package ThePackage {\n",
99100
" part def PartWithAttributes {\n",
100101
" \n",
@@ -110,11 +111,12 @@
110111
" attribute speed = 300 [m/s];\n",
111112
" attribute pressure = 101325 [N/m^2]; // Normally you would use [Pa]\n",
112113
" \n",
113-
" // Compound unit defined in standard lib\n",
114+
" // Compound units defined in standard lib\n",
114115
" attribute acceleration = 10.0 ['m⋅s⁻²'];\n",
115116
"\n",
116-
" // Compound unit not defined in the standard lib\n",
117+
" // Compound units not defined in the standard lib\n",
117118
" attribute crazyUnits = -3.14 [K*kg*s**2/m^3];\n",
119+
" attribute filesize = 42 [mega*byte]; // Megabyte itself is not defined as a unit\n",
118120
" \n",
119121
" // Temperature\n",
120122
" attribute absTemp = 15.0 ['°C_abs']; // = 288.15 K\n",
@@ -131,9 +133,9 @@
131133
"units_helper = SysMLUnitsHelper(model)\n",
132134
"\n",
133135
"# Get the attributes of the part\n",
134-
"part = elements[1].children.elements[0]\n",
136+
"part = elements[2].children.elements[0]\n",
135137
"assert part.name == 'PartWithAttributes'\n",
136-
"attrs = list(part.children.elements)"
138+
"attrs = {el.name: el for el in part.children.elements}"
137139
]
138140
},
139141
{
@@ -149,12 +151,12 @@
149151
"outputs": [],
150152
"source": [
151153
"# Read attribute value quantity\n",
152-
"q = units_helper.get_quantity(attrs[0])\n",
154+
"q = units_helper.get_quantity(attrs['length'])\n",
153155
"assert q.magnitude == 1000\n",
154156
"assert str(q.units) == 'meter'\n",
155157
"\n",
156158
"# Only read the unit\n",
157-
"units, m_unit_attr = units_helper.get_units(attrs[0])\n",
159+
"units, m_unit_attr = units_helper.get_units(attrs['length'])\n",
158160
"assert units == ureg.m\n",
159161
"assert str(units) == 'meter'\n",
160162
"\n",
@@ -195,6 +197,7 @@
195197
" pressure = 101325 N/m²\n",
196198
" acceleration = 10.0 m/s²\n",
197199
" crazyUnits = -3.14 K·kg·s²/m³\n",
200+
" filesize = 42 MB\n",
198201
" absTemp = 15.0 °C\n",
199202
" deltaTemp = 15.0 Δ°C\n",
200203
" density has no value\n",
@@ -213,7 +216,7 @@
213216
" print(f' {feature.name} has no value')\n",
214217
" \n",
215218
"print('Attribute quantities:')\n",
216-
"for attr in attrs:\n",
219+
"for attr in attrs.values():\n",
217220
" _read_print_quantity(attr)\n",
218221
"print('')"
219222
]
@@ -241,6 +244,7 @@
241244
" pressure = inf Pa\n",
242245
" acceleration = nan m/s²\n",
243246
" crazyUnits = -6.28 K·kg·s²/m³\n",
247+
" filesize = 42.0 GB\n",
244248
" absTemp = 288.15 K\n",
245249
" deltaTemp = 15.0 K\n",
246250
" density = 1.225 kg/m³\n",
@@ -250,41 +254,43 @@
250254
],
251255
"source": [
252256
"# Convert value to another unit (m --> km)\n",
253-
"q_m = units_helper.get_quantity(attrs[0])\n",
257+
"q_m = units_helper.get_quantity(attrs['length'])\n",
254258
"q_km = q_m.to(ureg.km)\n",
255-
"units_helper.set_quantity(attrs[0], q_km)\n",
259+
"units_helper.set_quantity(attrs['length'], q_km)\n",
256260
"\n",
257261
"# kg --> lbs\n",
258262
"units_helper.set_quantity(\n",
259-
" attrs[1], units_helper.get_quantity(\n",
260-
" attrs[1]).to(ureg.lbs))\n",
263+
" attrs['mass'], units_helper.get_quantity(\n",
264+
" attrs['mass']).to(ureg.lbs))\n",
261265
"\n",
262266
"# Temperature conversion\n",
263267
"units_helper.set_quantity(\n",
264-
" attrs[8], units_helper.get_quantity(attrs[8]).to(ureg.K))\n",
268+
" attrs['absTemp'], units_helper.get_quantity(attrs['absTemp']).to(ureg.K))\n",
265269
"units_helper.set_quantity(\n",
266-
" attrs[9], units_helper.get_quantity(attrs[9]).to(ureg.K))\n",
270+
" attrs['deltaTemp'], units_helper.get_quantity(attrs['deltaTemp']).to(ureg.K))\n",
267271
"\n",
268272
"# Set quantity: quantity constructor\n",
269273
"units_helper.set_quantity(\n",
270-
" attrs[2], units_helper.quantity(150, ureg.kJ))\n",
274+
" attrs['energy'], units_helper.quantity(150, ureg.kJ))\n",
271275
"\n",
272-
"units_helper.set_quantity(attrs[3], 3.14 * ureg.m)\n",
276+
"units_helper.set_quantity(attrs['diameter'], 3.14 * ureg.m)\n",
273277
"\n",
274278
"# Set quantity: value and parsed unit str\n",
275-
"units_helper.set_value_and_units(attrs[4], 42, 'km/h')\n",
279+
"units_helper.set_value_and_units(attrs['speed'], 42, 'km/h')\n",
276280
"\n",
277281
"# Set special values: inf and NaN\n",
278-
"units_helper.set_value_and_units(attrs[5], math.inf, 'Pa')\n",
279-
"units_helper.set_value_and_units(attrs[6], math.nan, 'm/s**2')\n",
282+
"units_helper.set_value_and_units(attrs['pressure'], math.inf, 'Pa')\n",
283+
"units_helper.set_value_and_units(attrs['acceleration'], math.nan, 'm/s**2')\n",
280284
"\n",
281285
"# Get and set compound units\n",
282-
"quantity = units_helper.get_quantity(attrs[7])\n",
286+
"quantity = units_helper.get_quantity(attrs['crazyUnits'])\n",
283287
"assert len(list(quantity.units._units.unit_items())) > 1\n",
284-
"units_helper.set_quantity(attrs[7], quantity*2)\n",
288+
"units_helper.set_quantity(attrs['crazyUnits'], quantity*2)\n",
289+
"\n",
290+
"units_helper.set_quantity(attrs['filesize'], 42*ureg['GB'])\n",
285291
"\n",
286292
"# Get preferred units of a quantity base type\n",
287-
"quantity_attr = attrs[10]\n",
293+
"quantity_attr = attrs['density']\n",
288294
"assert units_helper.is_typed_by_quantity_value(quantity_attr)\n",
289295
"units = units_helper.get_quantity_value_units(quantity_attr)\n",
290296
"assert units == ureg['kg/m**3']\n",
@@ -297,7 +303,7 @@
297303
"\n",
298304
"# Read and print all attribute values\n",
299305
"print('Modified attribute quantities:')\n",
300-
"for attr in attrs:\n",
306+
"for attr in attrs.values():\n",
301307
" _read_print_quantity(attr)\n",
302308
"print('')"
303309
]
@@ -318,6 +324,7 @@
318324
"output_type": "stream",
319325
"text": [
320326
"private import SI::*;\n",
327+
"private import SIPrefixes::*;\n",
321328
"package ThePackage {\n",
322329
" part def PartWithAttributes {\n",
323330
" attribute length = 1 [km];\n",
@@ -332,6 +339,7 @@
332339
" attribute acceleration = null ['m⋅s⁻²'];\n",
333340
"\n",
334341
" attribute crazyUnits = -6.28 [K * kg * s^2 * m^(-3)];\n",
342+
" attribute filesize = 42 [giga * B];\n",
335343
"\n",
336344
" attribute absTemp = 288.15 [K];\n",
337345
" attribute deltaTemp = 15 [K];\n",
@@ -681,8 +689,8 @@
681689
"42 meter / second\n",
682690
"attribute speed = 42 [SI::'m/s'];\n",
683691
"\n",
684-
"42 kelvin * kilogram / meter ** 3\n",
685-
"attribute valueWithCustomUnits = 42 [SI::K * SI::kg * SI::m^(-3)];\n",
692+
"42 kilogram * megakelvin / meter ** 3\n",
693+
"attribute valueWithCustomUnits = 42 [SIPrefixes::mega * (SI::kg * SI::K * SI::m^(-3))];\n",
686694
"\n"
687695
]
688696
}
@@ -699,8 +707,8 @@
699707
"units_helper.set_quantity(attr, quantity)\n",
700708
"print(units_helper.to_text(attr))\n",
701709
"\n",
702-
"# Compound units not available as a separate units attribute: K*kg/m**3\n",
703-
"model, _, elements = read_sysml(\"attribute valueWithCustomUnits = 42 [SI::K * SI::kg / SI::m^3];\")\n",
710+
"# Compound units not available as a separate units attribute: mega*K*kg/m**3\n",
711+
"model, _, elements = read_sysml(\"attribute valueWithCustomUnits = 42 [SIPrefixes::mega * SI::K * SI::kg / SI::m^3];\")\n",
704712
"units_helper = SysMLUnitsHelper(model)\n",
705713
"\n",
706714
"attr = elements[0]\n",
@@ -824,8 +832,7 @@
824832
"id": "1571c0b9-6fc5-4ca4-91e5-8a5cc5d12697",
825833
"metadata": {},
826834
"source": [
827-
"Sometimes units are converted to their base definitions, for example when prefixes (e.g. kilo, mega) are used.\n",
828-
"To support this, you can use the `scale` output of `set_units` to correct your value:"
835+
"Unit prefixes are automatically applied:"
829836
]
830837
},
831838
{
@@ -838,17 +845,16 @@
838845
"name": "stdout",
839846
"output_type": "stream",
840847
"text": [
841-
"attribute myAttribute = SI::W;\n",
848+
"attribute myAttribute = SIPrefixes::mega * SI::W;\n",
842849
"\n"
843850
]
844851
}
845852
],
846853
"source": [
847-
"scale = units_helper.set_units(attr, 'MW')\n",
848-
"assert scale == 1e6\n",
854+
"units_helper.set_units(attr, 'MW')\n",
849855
"\n",
850856
"units, _ = units_helper.get_units(attr)\n",
851-
"assert units == ureg.W\n",
857+
"assert units == ureg('MW').units\n",
852858
"print(units_helper.to_text(attr))"
853859
]
854860
},
@@ -870,17 +876,17 @@
870876
"name": "stdout",
871877
"output_type": "stream",
872878
"text": [
873-
"attribute myAttribute = SI::K * SI::kg * SI::m^(-1);\n",
879+
"attribute myAttribute = SIPrefixes::mega * (SI::K * SI::kg * SI::m^(-1));\n",
874880
"\n"
875881
]
876882
}
877883
],
878884
"source": [
879-
"units_helper.set_units(attr, 'K*kg/m')\n",
885+
"units_helper.set_units(attr, 'megaK*kg/m')\n",
880886
"print(units_helper.to_text(attr))\n",
881887
"\n",
882888
"units, units_attr = units_helper.get_units(attr)\n",
883-
"assert units == ureg('K*kg/m').units\n",
889+
"assert units == ureg('megaK*kg/m').units\n",
884890
"assert units_attr is None # There is no single units attribute that represents these compound units"
885891
]
886892
},
@@ -972,7 +978,8 @@
972978
"source": [
973979
"### Convert between Pint or str units and SysML units\n",
974980
"\n",
975-
"Note: this only works for non-compound units (working with SysML units expressions is only implemented for getting/setting units/quantities as feature values)!"
981+
"Note: this only works for non-compound units!\n",
982+
"Working with SysML units expressions is only implemented for getting/setting units/quantities as feature values."
976983
]
977984
},
978985
{
@@ -990,7 +997,7 @@
990997
"name": "stdout",
991998
"output_type": "stream",
992999
"text": [
993-
"Cannot map Pint units to SysML: kelvin * kilogram / meter\n"
1000+
"Could not convert pint units \"<K·kg/m> kelvin·kilogram/meter\" to SysML units\n"
9941001
]
9951002
}
9961003
],

0 commit comments

Comments
 (0)