{"id":25456840,"url":"https://github.com/szaghi/fury","last_synced_at":"2026-02-25T02:31:36.064Z","repository":{"id":146096529,"uuid":"65200499","full_name":"szaghi/FURY","owner":"szaghi","description":"Fortran Units (environment) for Reliable phYsical math","archived":false,"fork":false,"pushed_at":"2023-04-04T07:07:31.000Z","size":16713,"stargazers_count":33,"open_issues_count":10,"forks_count":4,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-06-11T18:54:19.562Z","etag":null,"topics":["fortran","oop","reliability","unit-of-measure","uom"],"latest_commit_sha":null,"homepage":null,"language":"Fortran","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/szaghi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.bsd-2.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-08-08T11:56:10.000Z","updated_at":"2024-05-21T09:18:38.000Z","dependencies_parsed_at":"2023-04-17T22:16:15.115Z","dependency_job_id":null,"html_url":"https://github.com/szaghi/FURY","commit_stats":{"total_commits":102,"total_committers":2,"mean_commits":51.0,"dds":0.009803921568627416,"last_synced_commit":"ee00b79ba2000521c6e9bfc6f8abe00d8fcf1558"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szaghi%2FFURY","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szaghi%2FFURY/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szaghi%2FFURY/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/szaghi%2FFURY/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/szaghi","download_url":"https://codeload.github.com/szaghi/FURY/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239394683,"owners_count":19631122,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fortran","oop","reliability","unit-of-measure","uom"],"created_at":"2025-02-18T01:51:27.729Z","updated_at":"2025-11-02T10:30:33.074Z","avatar_url":"https://github.com/szaghi.png","language":"Fortran","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"top\"\u003e\u003c/a\u003e\n\n# FURY [![GitHub tag](https://img.shields.io/github/tag/szaghi/FURY.svg)]() [![Join the chat at https://gitter.im/szaghi/FURY](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/szaghi/FURY?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\n\u003e dedicated to [**W. Van Snyder**](https://science.jpl.nasa.gov/people/Snyder/)[[\u003csup\u003erg\u003c/sup\u003e]](https://www.researchgate.net/profile/W_Snyder)\n\n[![License](https://img.shields.io/badge/license-GNU%20GeneraL%20Public%20License%20v3,%20GPLv3-blue.svg)]()\n[![License](https://img.shields.io/badge/license-BSD2-red.svg)]()\n[![License](https://img.shields.io/badge/license-BSD3-red.svg)]()\n[![License](https://img.shields.io/badge/license-MIT-red.svg)]()\n\n[![Status](https://img.shields.io/badge/status-stable-green.svg)]()\n[![Build Status](https://travis-ci.org/szaghi/FURY.svg?branch=master)](https://travis-ci.org/szaghi/FURY)\n[![Build Status](https://api.shippable.com/projects/57dabe9156a1350f001d8ffc/badge?branch=master)]()\n[![Coverage Status](https://img.shields.io/codecov/c/github/szaghi/FURY.svg)](http://codecov.io/github/szaghi/FURY?branch=master)\n\n### FURY, Fortran Units (environment) for Reliable phYsical math\n\nA KISS pure Fortran Library for improving reliability of physical math computations by taking into account units of measure:\n\n- FURY is a pure Fortran (KISS) library for improving reliability of physical math computations;\n- FURY is a pure Fortran (KISS) library for symbolic algebra on units symbols;\n- FURY is Fortran 2003+ standard compliant;\n- FURY is OOP designed;\n- FURY is a Free, Open Source Project.\n\n#### A taste of FURY\n\n```fortran\nuse, intrinsic :: iso_fortran_env, only : real64\nuse fury\ntype(uom)   :: meter\ntype(uom)   :: second\ntype(qreal) :: distance_to_arrival\ntype(qreal) :: time_to_arrival\ntype(qreal) :: mean_velocity\n\nmeter = uom('m = meter = metre [length] {meter}')\nsecond = uom('s = sec = second [time] {second}')\n\ndistance_to_arrival = qreal(100._real64, meter)\ntime_to_arrival = qreal(9.58_real64, second)\n\nmean_velocity = distance_to_arrival / time_to_arrival\n\nprint \"(A)\", 'Bolt''s record speed: '//mean_velocity%stringify(with_dimensions=.true.)\n! print\n! Bolt's record speed: +0.104384133611691E+002 m.s-1 [length.time-1]\n```\n\n#### Issues\n\n[![GitHub issues](https://img.shields.io/github/issues/szaghi/FURY.svg)]()\n[![Ready in backlog](https://badge.waffle.io/szaghi/FURY.png?label=ready\u0026title=Ready)](https://waffle.io/szaghi/FURY)\n[![In Progress](https://badge.waffle.io/szaghi/FURY.png?label=in%20progress\u0026title=In%20Progress)](https://waffle.io/szaghi/FURY)\n[![Open bugs](https://badge.waffle.io/szaghi/FURY.png?label=bug\u0026title=Open%20Bugs)](https://waffle.io/szaghi/FURY)\n\n#### Compiler Support\n\n[![Compiler](https://img.shields.io/badge/GNU-v6.1.1+-brightgreen.svg)]()\n[![Compiler](https://img.shields.io/badge/Intel-v16.1+-brightgreen.svg)]()\n[![Compiler](https://img.shields.io/badge/IBM%20XL-not%20tested-yellow.svg)]()\n[![Compiler](https://img.shields.io/badge/g95-not%20tested-yellow.svg)]()\n[![Compiler](https://img.shields.io/badge/NAG-not%20tested-yellow.svg)]()\n[![Compiler](https://img.shields.io/badge/PGI-not%20tested-yellow.svg)]()\n\n---\n\n[What is FURY?](#what-is-fury) | [Main features](#main-features) | [Copyrights](#copyrights) | [Download](#download) | [Compilation](#compilation) | [Documentation](#documentation) | [References](#references)\n\n---\n\n## What is FURY?\n\nFURY is a *poor-by-blow* of *reliability* concept\n\n\u003e+ reliability is expression of the *consistency-of-a-set-of-measures*\n\u003e+ reliability measures successful probability, i.e. *1 - probability-of-failure*\n\u003e+ reliability (absence) played a role on the *Mars Climate Orbiter disaster*\u003csup\u003e[mco](#mco-disaster)\u003c/sup\u003e\n\u003e\n\u003e ergo **reliability counts**\n\nFURY project started to respond to two questions:\n\n1. is a *units-consistency-check* facility (UCCF) a desirable feature for a programming language?\n    + is useful? or\n    + is dangerous?\n1. how it can be implemented in Fortran?\n    + is feasible?\n\nThese questions are generated by an inspiring [Fortran Language Google Group discussion](https://groups.google.com/forum/#!topic/comp.lang.fortran/1TbfQlAmKx8) started by [**W. Van Snyder**](https://science.jpl.nasa.gov/people/Snyder/)[[\u003csup\u003erg\u003c/sup\u003e]](https://www.researchgate.net/profile/W_Snyder). They are really *controversial*: someone want UCCF to be a built-in feature in Fortran, others claim that such a feature is not useful at all or even dangerous just because it could add more space for errors than it could reduce (thus reducing the reliability).\n\n\u003e Starting from an *agnostic* point of view, the FURY case study conveys us to think that a UCCF is a desirable feature for the next Fortran standards.\n\nMoreover, the large experience borrowed from other programming languages, see [references](#references), proves that UCCF like features can be feasible in modern programming languages and they are of proved usefulness. As a consequence, FURY started to begin a fully featured, self-contained project that is presently usable for production-applications, even if the first comprehensive testing phase (of pre v1.0.0 bug-fix one) is still not completed.\n\nFURY is the result of the tentative to respond the above questions:\n\n\u003e FURY is a pure Fortran library providing a new set of types (the **quantities**) having a built-in units-consistency-check facility that is able to improve the reliability of physical computations.\n\u003e Moreover, FURY can perform symbolic math on units symbols.\n\nFURY can do reliable math computations, preserving quantities dimensionality, checking consistency and propagating multiplicative scaling factors. For example, if you want to know how fast is Bolt you can do it with FURY, in a reliable way :smile:\n\n```fortran\nuse, intrinsic :: iso_fortran_env, only : real64\nuse fury\ntype(uom)   :: meter\ntype(uom)   :: second\ntype(qreal) :: distance_to_arrival\ntype(qreal) :: time_to_arrival\ntype(qreal) :: mean_velocity\n\nmeter = uom('m = meter = metre [length] {meter}')\nsecond = uom('s = sec = second [time] {second}')\n\ndistance_to_arrival = qreal(100._real64, meter)\ntime_to_arrival = qreal(9.58_real64, second)\n\nmean_velocity = distance_to_arrival / time_to_arrival\n\nprint \"(A)\", 'Bolt''s record speed: '//mean_velocity%stringify(with_dimensions=.true.)\n! print\n! Bolt's record speed: +0.104384133611691E+002 m.s-1 [length.time-1]\n```\n\nFURY is based on a powerful parser of *unit-of-measure* (UOM) definitions: once a (set of) UOM is defined its scaling factor, symbol and dimensions are consistently checked, preserved and propagated in all computations. For set of UOMs with defined conversion-formulas FURY can check the consistency of all conversions. Eventually, if a quantity has a defined UOM, any tentative to assign it to another quantity with a different UOM will raise an error as well as for all inconsistent computations.\n\nGo to [Top](#top)\n\n## Main features\n\nFURY is inspired by the python great module [pint](https://github.com/hgrecco/pint), thus many features are taken from it. Here the main features are listed.\n\n* [x] User-friendly classes to add *units of measure* to numbers;\n* [x] errors trapping for invalid computations/assignments;\n* [x] unit parsing: prefixed forms of units are recognized without explicitly defining them, i.e. as the prefix kilo and the unit meter are defined, FURY understands kilometer;\n* [x] effortless conversion even for complex derived UOM;\n* [ ] standalone unit definitions: units definitions are loaded from simple and easy to edit text file;\n* [ ] advanced string parsing:\n    * [x] symbolic algebra on units symbols;\n    * [ ] Buckingham Pi Theorem;\n* [ ] replicate all the useful features of [pint](https://github.com/hgrecco/pint);\n* [x] Test Driven Developed (TDD);\n* [x] collaborative developed;\n* [x] well documented;\n* [x] free!\n\nAny feature request is welcome.\n\nGo to [Top](#top)\n\n## Copyrights\n\nFURY is an open source project, it is distributed under a multi-licensing system:\n\n+ for FOSS projects:\n  - [GPL v3](http://www.gnu.org/licenses/gpl-3.0.html);\n+ for closed source/commercial projects:\n  - [BSD 2-Clause](http://opensource.org/licenses/BSD-2-Clause);\n  - [BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause);\n  - [MIT](http://opensource.org/licenses/MIT).\n\nAnyone is interest to use, to develop or to contribute to FURY is welcome, feel free to select the license that best matches your soul!\n\nMore details can be found on [wiki](https://github.com/szaghi/FURY/wiki/Copyrights).\n\nGo to [Top](#top)\n\n## Download\n\nFURY home is at [https://github.com/szaghi/FURY](https://github.com/szaghi/FURY). To download all the source files you can:\n\n+ clone recursively this repository: `git clone --recursive https://github.com/szaghi/FURY`\n+ download the latest master-branch archive at [https://github.com/szaghi/FURY/archive/master.zip](https://github.com/szaghi/FURY/archive/master.zip)\n+ download a release archive at [https://github.com/szaghi/FURY/releases](https://github.com/szaghi/FURY/releases)\n\nGo to [Top](#top)\n\n## Compilation\n\nFURY is a modern Fortran project thus a modern Fortran compiler is need to compile the project.\n\nThe library is modular, namely it exploits Fortran modules. As a consequence, there is compilation-cascade hierarchy to build the library. To correctly build the library the following approaches are supported\n\n+ [Build by means of FoBiS](#build-by-means-of-fobis): full support;\n+ [Build by means of GNU Make](#build-by-means-of-gnu-make): to be implemented.\n+ [Build by means of CMake](#build-by-means-of-cmake): to be implemented.\n\nThe FoBiS building support is the most complete, as it is the one used for the developing FURY.\n\n### Build by means of FoBiS\n\nA `fobos` file is provided to build the library by means of the Fortran Building System [FoBiS](https://github.com/szaghi/FoBiS).\n\n#### Build all tests\n\nType\n\n```shell\nFoBiS.py build\n```\n\nAfter (a successful) building a directory `./exe` is created containing all the compiled tests that constitute the FURY *regression-tests-suite*, e.g.\n\n```bash\n→ FoBiS.py build\nBuilder options\nDirectories\n  Building directory: \"exe\"\n  Compiled-objects .o   directory: \"exe/obj\"\n  Compiled-objects .mod directory: \"exe/mod\"\nCompiler options\n  Vendor: \"gnu\"\n  Compiler command: \"gfortran\"\n  Module directory switch: \"-J\"\n  Compiling flags: \"-c -frealloc-lhs -std=f2008 -fall-intrinsics -O2 -Dr16p\"\n  Linking flags: \"-O2\"\n  Preprocessing flags: \"-Dr16p\"\n  Coverage: False\n  Profile: False\nPreForM.py used: False\nPreForM.py output directory: None\nPreForM.py extensions processed: []\n\nBuilding src/tests/basic_use.f90\nCompiling src/lib/penf.F90 serially\nCompiling src/lib/string_t.F90 serially\nCompiling src/lib/stringifor.F90 serially\nCompiling ...\nLinking exe/basic_use\nTarget src/tests/basic_use.f90 has been successfully built\n...\n\n→ tree -L 1 exe/\nexe/\n├── basic_use\n...\n```\n\n### Build by means of GNU Make\n\nTo be implemented.\n\n### Build by means of CMake\n\nTo be implemented.\n\nGo to [Top](#top)\n\n---\n\n## Documentation\n\nBesides this README file the FURY documentation is contained into its own [wiki](https://github.com/szaghi/FURY/wiki). Detailed documentation of the API is contained into the [GitHub Pages](http://szaghi.github.io/FURY/index.html) that can also be created locally by means of [ford tool](https://github.com/cmacmackin/ford).\n\n### The design\n\nFURY is designed upon a simple, yet powerful UOM grammar, for example the definition of the Pascal unit could be one the followings:\n\n+ `'Pa'`\n+ `'Pa [pressure]'`\n+ `'Pa [pressure] {pascal}'`\n+ `'kg.m-1.s-2'`\n+ `'kg.m-1.s-2 = Pa'`\n+ ...\n+ `'kg [mass].m-1 [length-1].s-2 [time-2] (Pa[pressure]) {pascal}'`\n\nwhere the first is the most basic definition defining only the main symbol while the others are definitions with increasing complexity where we are defining dimensions, symbol aliases, name, definition with respect other units... The flexibility left to the end user is really high. More in details, the UOM grammar is composed as following:\n\n+ `'kg [mass].m-1 = metre-1 = meter-1 [length-1].s-2 = seconds-2 = sec-2 [time-2] (Pa[pressure]) {pascal}'`\n\nwhere\n\n+ the terms `[...]` define the *dimensions* of each unit and are optional (the white spaces are ignored); moreover the exponents of dimensions can be omitted: in this case they are inferred from the symbol reference exponents; in the case they are explicitly written they must match the corresponding symbol ones or an error is raised;\n+ the term `(...)` defines a *main* unit *alias* that is optional and must come always after unit reference definition;\n+ the term `{...}` defines the unit name that is optional and must be always the last term.\n\nReference units used for the definition of another one are separated by the `.` symbol, thus the Pascal definition is `kg/(m * s^2)` is defined as `kg.m-1.s-2` to mimic the rules of [The Unified Code for Units of Measure](http://unitsofmeasure.org/trac): each *reference* unit is intended multiplied the subsequent with the proper exponent with sign. The FURY parser is designed on this grammar, thus each reference unit is tokenized with the `.` separator.\n\nSymbol aliases are used also for defining units conversion formulas, e.g.\n\n`'km = 1000 * m [length].h-1 = 3600 s-1 [time-1] (km/h[speed]) {km/h}'`\n\nThis is the base, more concise conversion formula grammar, but it could be unsafe if the conversion implies real-valued scaling factor, as it often happens. In this case, a more verbose but more safe grammar should be used, e.g.\n\n`'km\u003c = 1000._real64 * m \u003e [length].h-1\u003c = 3600._real64 s-1\u003e [time-1] (km/h[speed]) {km/h}'`\n\nwhere the conversion formulas are *protected* by the `\u003c\u003e` symbols. Defining a UOM with fury is simple as\n\n```fortran\nuse fury\ntype(uom) :: pascal\npascal = uom('kg [mass].m-1 [length-1].s-2 [time-2] (Pa[pressure]) {pascal}')\n```\n\nHaving a unit so defined, it is allowed to perform your reliable computations, namely all the symbolic computations necessary when dealing with units, e.g. computing the force from a pressure on a surface\n\n```fortran\nuse fury\ntype(uom) :: meter\ntype(uom) :: pascal\ntype(uom) :: newton\n\nmeter = uom(m [length] (meter[length]) {meter}')\npascal = uom('kg [mass].m-1 [length-1].s-2 [time-2] (Pa[pressure]) {pascal}')\n\nnewton = pascal * meter**2\nprint \"(A)\", ' newton: '//newton%stringify(with_dimensions=.true.)\n! output\n! newton: kg.m.s-2 [mass.length.time-2]\n```\n\nFor make easier the life of *snappy coders* a far complete SI system of predefined units is provided, as well an abstract class for defining new units systems.\n\n#### UOM grammar for reference unit\n\nWe indicate a UOM to be a *reference* unit when it is defined by only main symbol having exponent 1 and multiplicative factor 1. With this categorization the *base* units of SI are all reference units for us. Moreover, the user can define his/her own reference units, e.g. `apple [fruit] {not a pc}` is a valid UOM reference definition that can be used to define other (complex) units like `GNU\u003c = 1.e20 * apple\u003e [salad_of_fruits] {HPC}`. To define a reference UOM you need to specify just the main symbol, but other data can be optionally provided to cover more complex purposes. For example, defining a reference unit you can provide aliases defining conversion formulas to other UOM, you can provide the dimensions or UOM name useful to query systems of units.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e                                                   \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003erequired                  \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd colspan=\"6\"\u003e \u003csub\u003ealias formula(s), optional\u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional                  \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional                  \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional                  \u003c/sub\u003e \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd colspan=\"2\"\u003e                             \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional        \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003e=               \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional if == 1\u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eHz              \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional if == 1\u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional        \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd colspan=\"3\"\u003e                             \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e \u003csub\u003egrammar_element      \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003emain_symbol          \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e\u0026#60;                \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e=                    \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003emultiplicative_factor\u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003esymbol               \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003esymbol_exponent      \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e\u0026#62;                \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e[dimensions]         \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e(alias[dimensions])  \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e{unit_name}          \u003c/sub\u003e \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e \u003csub\u003eexample               \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003ekHz                   \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e\u0026#60;                 \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e=                     \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e1000. *               \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003eHz                    \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e1                     \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e\u0026#62;                 \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e[time-1]              \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e(kilohertz[frequency])\u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e{kilohertz}           \u003c/sub\u003e \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nExamples\n\n+ `kHz`, only the main symbol is strictly required;\n+ `kHz = 1000 * Hz`, one alias (for conversion formula);\n+ `kHz = 1000 * Hz = 1000 * s-1`, two aliases (for conversion formulas);\n+ `kHz\u003c = 1000. * Hz\u003e`, one alias protected (due to real factor);\n+ `kHz\u003c = 1000. * Hz = 1000. * s-1 \u003e`, two aliases protected;\n+ `kHz [time-1]`, dimensions specification;\n+ `kHz [time-1] (kilohertz[frequency])`, a main alias specification, useful for units like pressure:\n    + `kg.m-1.s-2 (Pa[pressure]) {pascal}`\n+ `kHz [time-1] (kilohertz[frequency]) {my kilohertz}`, unit name specification, useful for queries in units systems usage;\n+ `kHz\u003c = 1000. * Hz = 1000. * s-1 \u003e [frequency] (kilohertz[frequency]) {kilohertz}`\n\n#### UOM grammar for general complex unit\n\nIn the case you want to define a UOM with a respect a set of reference UOM, you can do using the `.` operator that mimics the definition of [The Unified Code for Units of Measure](http://unitsofmeasure.org/trac) group.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e                                                            \u003c/td\u003e\n    \u003ctd colspan=\"3\"\u003e \u003csub\u003erequired at least 2 UOM definitions\u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional                           \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e             \u003csub\u003eoptional                           \u003c/sub\u003e \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e \u003csub\u003egrammar_element     \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003eUOMreference        \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e.                   \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003eotherUOMreference   \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e(alias[dimensions]) \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e{unit_name}         \u003c/sub\u003e \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e \u003csub\u003eexample      \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003em [length]   \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e.            \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003es-1 [time-1] \u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e(m/s [speed])\u003c/sub\u003e \u003c/td\u003e\n    \u003ctd\u003e \u003csub\u003e{speed SI}   \u003c/sub\u003e \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nExamples\n\n+ `kg [mass].m [length].s-2 [time-2] (N[force]) {newton}`\n+ `kg [mass].m2 [length2].s-3 [time-3].A-2 [current-2]{ohm}`\n+ `kg [mass].m-1 [length-1].s-2 [time-2] (Pa[pressure]) {pascal}`\n\nIt worth to note that the user can always define a complex unit as a reference one, let us consider for example two possible definitions of the pressure:\n\n1. `kg [mass].m-1 [length-1].s-2 [time-2] (Pa[pressure]) {pascal_complex}`\n2. `Pa [pressure] {pascal_simple}`\n\nBoth are valid, but the first one provides much more *informations* thus resulting into a more powerful symbolic math. For example consider the following example where the above 2 definitions are used to define the Newton unit:\n\n```fortran\nuse fury\ntype(uom) :: meter\ntype(uom) :: pascal_complex\ntype(uom) :: pascal_simple\ntype(uom) :: newton\n\nmeter = uom('m [length] (meter[length]) {meter}')\npascal_complex = uom('kg [mass].m-1 [length-1].s-2 [time-2] (Pa[pressure]) {pascal}')\npascal_simple = uom('Pa[pressure] {pascal}')\n\nnewton = pascal_complex * meter**2\nprint \"(A)\", ' newton: '//newton%stringify(with_dimensions=.true.)\n! output\n! newton: kg.m.s-2 [mass.length.time-2]\n\ncall newton%unset\nnewton = pascal_simple * meter**2\nprint \"(A)\", ' newton: '//newton%stringify(with_dimensions=.true.)\n! output\n! newton: Pa.m2 [pressure.length2]\n```\n\nBoth results are correct, but the first is more *informative* if a consistent set of reference units has been defined, as it happens for the SI system.\n\n#### Physical Quantities\n\nFURY's quantities are built up upon the above UOM: a quantity is essentially a number (real or integer of any kind) with attached a UOM. When a quantity has a defined UOM all UOM's check are pushed to the quantity's magnitude computations, thus improving the math computations reliability.\n\nUnfortunately, we have not find a simple way *to attach* UOM to standard Fortran types, thus the end user must do reliable computations on a new set of types, namely `qreal` and `qinteger` (or their *kinded* version).\n\nLet us assume to consider the summation of 2 length, the first expressed in meters and the second in kilometers. With FURY this can be implemented as:\n\n```fortran\nuse fury\ntype(system_si) :: SI        ! SI system.\ntype(qreal)     :: q         ! A physical quantity.\ntype(qreal)     :: q1        ! A physical quantity.\ntype(qreal)     :: q2        ! A physical quantity.\ntype(uom)       :: kilometre ! The kilometre unit based on the metre unit.\n\n! initialize SI units system\ncall SI%initialize\n\n! define a new unit, i.e. the kilometre, that must\n! be compatible with SI's metre\nkilometre = uom('km = 1000 * m')\n\n! define 2 quantities\nq1 = qreal(magnitude=1._R_P, unit=SI%unit('metre'))\nq2 = qreal(magnitude=1._R_P, unit=kilometre)\n\n! try to blindly to sum them\nq = q1 + q2\n! error: cannot convert from \"metre [length]\" to \"km\"\n\n! a more conscious sum\nq = q1 + q2%to(SI%unit('metre'))\n! no error is raised\nprint \"(A)\", '1 m + 1 km = '//q%stringify(format='(F6.1)')\n! output \"1 m + 1 km = 1001.0 m\"\n\n```\n\n#### The minimal tutorial\n\nTo use FURY the minimal steps necessary are:\n\n##### 1. use FURY module\n\n```fortran\nuse fury\n```\n\n##### 2. define FURY quantities\n\n```fortran\ntype(qreal)    :: q1 ! A real physical quantity.\ntype(qinteger) :: q2 ! An integer physical quantity.\n```\n\n##### 3. (optional) define new FURY units\n\n```fortran\ntype(uom) :: centimetre ! The centimetre unit based on the metre unit.\ntype(uom) :: kilometre  ! The kilometre unit based on the metre unit.\ntype(uom) :: hour       ! The hour unit based on the second unit.\n\ncentimetre = uom('cm = 0.01 * m')\nkilometre = uom('km = 1000.0 * m')\nhour = uom('h = 3600.0 * s')\n```\n\n##### 4. (optional) initialize FURY units system(s)\n\n```fortran\ntype(system_si) :: SI ! SI system\n\ncall SI%initialize\n```\n\nNote that currently on the SI system is provided.\n\n##### 5. assign unit (and optionally magnitude) to FURY quantities\n\n```fortran\nq1 = qreal(magnitude=1._R_P, unit=kilometre)\nq2 = qinteger(magnitude=3, unit=hour)\n```\n\n##### 6. do your physical maths\n\nNow you can do your reliable physical computations :party:\n\nGo to [Top](#top)\n\n### References\n\nA non comprehensive references list of UCCF related contents.\n\n+ [The Unified Code for Units of Measure](http://unitsofmeasure.org/trac)\n+ [Meyers, Dimensional analysis. C++ Report](http://se.ethz.ch/~meyer/publications/OTHERS/scott_meyers/dimensions.pdf)\n+ [Petty, Automated computation and consistency checking of physical dimensions and units in scientific programs](http://onlinelibrary.wiley.com/doi/10.1002/spe.401/abstract)\n+ [Brown, Introduction to the SI Library of Unit-Based Computation](http://lss.fnal.gov/archive/1998/conf/Conf-98-328.pdf)\n+ [International System of Units](https://en.wikipedia.org/wiki/International_System_of_Units)\n\n##### Built-in in language\n\n+ [F#](https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure)\n\n##### Libraries\n\n+ .NET\n    + [UnitsNet](https://github.com/anjdreas/UnitsNet)\n+ Ada\n    + [Units](http://www.dmitry-kazakov.de/ada/units.htm)\n+ C#\n    + [QuantityTypes](https://github.com/objorke/QuantityTypes)\n+ C++\n    + [Boost.Units](http://www.boost.org/doc/libs/1_37_0/doc/html/boost_units.html)\n    + [PhysUnits C++11](https://github.com/martinmoene/PhysUnits-CT-Cpp11)\n+ Haskell\n    + [dimensional](http://hackage.haskell.org/package/dimensional)\n+ JavaScript\n    + [UCUM](https://github.com/jmandel/ucum.js)\n+ Julia\n    + [SIUnits](https://github.com/Keno/SIUnits.jl)\n    + [Unitful](https://github.com/ajkeller34/Unitful.jl)\n+ Python\n    + [quantities](https://github.com/python-quantities/python-quantities)\n    + [magnitude](https://github.com/juanre/magnitude)\n    + [buckingham](https://github.com/mdipierro/buckingham)\n    + [pint](https://github.com/hgrecco/pint)\n+ Ruby\n    + [unitwise](https://github.com/joshwlewis/unitwise)\n\n#### MCO disaster\n\nThe Mars Climate Orbiter (MCO) Mishap Investigation Board (MIB) has determined that the root cause for the loss of the MCO spacecraft was the failure to use **metric units** in the coding of a ground software file, “Small Forces” used in trajectory models, specifically:\n\n\u003e thruster performance data in **English units** instead of **metric units** was used in the software application code titled `SM_FORCES` (small forces).\n\nThe units mismatching generates an erroneous trajectory that was underestimated by a factor of 4.45, which is the required conversion factor from force in **pounds** to **Newtons**.\n\n\u003e if the software application `SM_FORCES` had been developed with a *units-consistency-check facility*, $300 million of spacecraft could be saved.\n\nGo to [Top](#top)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fszaghi%2Ffury","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fszaghi%2Ffury","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fszaghi%2Ffury/lists"}